feat: Implement Phase 1 enhancements - components and animations
Enterprise AI Code Review / ai-review (pull_request) Successful in 19s

Components:
- Extract ServiceItem component with hover effects
- Extract SupportItem component with hover animations
- Extract Card component with scroll animations
- Extract Section component for consistent layout

Enhancements:
- Add Intersection Observer for scroll-triggered animations
- Implement hover effects on cards, services, and support items
- Add PWA manifest (site.webmanifest)
- Create SVG OG image placeholder for social sharing
- Add comprehensive favicon meta tags (16x16, 32x32, apple-touch-icon)
- Respect prefers-reduced-motion for accessibility

Files modified:
- src/pages/index.astro - Refactored to use new components
- src/layouts/BaseLayout.astro - Enhanced favicon and meta tags

Files created:
- src/components/Card.astro
- src/components/Section.astro
- src/components/ServiceItem.astro
- src/components/SupportItem.astro
- public/og-image.svg
- public/site.webmanifest
- public/FAVICON_INSTRUCTIONS.md

Note: PNG favicon variants still need to be generated (see FAVICON_INSTRUCTIONS.md)
This commit is contained in:
2025-12-31 18:12:11 +00:00
parent 51db744cc1
commit 6ed0eee514
9 changed files with 622 additions and 351 deletions
+112 -208
View File
@@ -1,5 +1,9 @@
---
import BaseLayout from "../layouts/BaseLayout.astro";
import Card from "../components/Card.astro";
import Section from "../components/Section.astro";
import ServiceItem from "../components/ServiceItem.astro";
import SupportItem from "../components/SupportItem.astro";
---
<BaseLayout
@@ -18,137 +22,95 @@ import BaseLayout from "../layouts/BaseLayout.astro";
</section>
<!-- About Hidden Den Section -->
<section class="section about-den" aria-labelledby="about-den-heading">
<div class="container">
<div class="card fade-in">
<h2 id="about-den-heading">About Hidden Den</h2>
<p>
Welcome to Hidden Den Cafe - a warm, self-hosted space
where technology meets comfort. This is a personal
corner of the internet built with love, care, and a
strong belief in privacy and open-source values.
</p>
<p>
Everything here runs on self-hosted infrastructure,
giving complete control over data and services. No cloud
dependencies, no tracking, just a cozy digital home.
</p>
</div>
</div>
</section>
<Section class="about-den" ariaLabelledby="about-den-heading">
<Card>
<h2 id="about-den-heading">About Hidden Den</h2>
<p>
Welcome to Hidden Den Cafe - a warm, self-hosted space where
technology meets comfort. This is a personal corner of the
internet built with love, care, and a strong belief in
privacy and open-source values.
</p>
<p>
Everything here runs on self-hosted infrastructure, giving
complete control over data and services. No cloud
dependencies, no tracking, just a cozy digital home.
</p>
</Card>
</Section>
<!-- About Latte Section -->
<section class="section about-me" aria-labelledby="about-me-heading">
<div class="container">
<div class="card fade-in">
<h2 id="about-me-heading">About Me</h2>
<p>
Hey there! I'm Latte, a gay furry developer who loves
building things and being part of the warm, welcoming
furry community. I'm passionate about self-hosting,
open-source software, and creating cozy spaces both
online and off.
</p>
<p>
I work primarily with Python and Flask, though I'm
always learning new things (currently exploring
JavaScript and the C stack). When I get those surges of
creative energy, I love diving into new projects - from
Reddit downloaders to Telegram sticker tools, and
everything in between.
</p>
<p>
Coffee enthusiast • Linux lover • Self-hosting advocate
</p>
</div>
</div>
</section>
<Section class="about-me" ariaLabelledby="about-me-heading">
<Card>
<h2 id="about-me-heading">About Me</h2>
<p>
Hey there! I'm Latte, a gay furry developer who loves
building things and being part of the warm, welcoming furry
community. I'm passionate about self-hosting, open-source
software, and creating cozy spaces both online and off.
</p>
<p>
I work primarily with Python and Flask, though I'm always
learning new things (currently exploring JavaScript and the
C stack). When I get those surges of creative energy, I love
diving into new projects - from Reddit downloaders to
Telegram sticker tools, and everything in between.
</p>
<p>Coffee enthusiast • Linux lover • Self-hosting advocate</p>
</Card>
</Section>
<!-- Services Section -->
<section class="section services" aria-labelledby="services-heading">
<div class="container">
<div class="card fade-in">
<h2 id="services-heading">Services</h2>
<p>Here are the services currently running in the den:</p>
<Section class="services" ariaLabelledby="services-heading">
<Card>
<h2 id="services-heading">Services</h2>
<p>Here are the services currently running in the den:</p>
<div class="service-list" role="list">
<div class="service-item" role="listitem">
<h3>
<a
href="https://git.hiddenden.cafe"
target="_blank"
rel="noopener noreferrer"
aria-label="Visit Gitea - Self-hosted Git service"
>
Gitea
</a>
</h3>
<p>
Self-hosted Git service for all my projects and
code repositories.
</p>
</div>
<div class="service-item coming-soon" role="listitem">
<h3>More Coming Soon</h3>
<p>
The den is always growing! More services will be
added as they're developed and deployed.
</p>
</div>
</div>
<div class="service-list" role="list">
<ServiceItem
title="Gitea"
description="Self-hosted Git service for all my projects and code repositories."
url="https://git.hiddenden.cafe"
/>
<ServiceItem
title="More Coming Soon"
description="The den is always growing! More services will be added as they're developed and deployed."
comingSoon={true}
/>
</div>
</div>
</section>
</Card>
</Section>
<!-- Support Section -->
<section class="section support" aria-labelledby="support-heading">
<div class="container">
<div class="card fade-in">
<h2 id="support-heading">How to Help Out</h2>
<p>
If you'd like to support the Hidden Den and help keep
the lights on, here are some ways you can contribute:
</p>
<Section class="support" ariaLabelledby="support-heading">
<Card>
<h2 id="support-heading">How to Help Out</h2>
<p>
If you'd like to support the Hidden Den and help keep the
lights on, here are some ways you can contribute:
</p>
<div class="support-list" role="list">
<div class="support-item" role="listitem">
<h3>Share & Spread the Word</h3>
<p>
Tell others about the projects and services
hosted here!
</p>
</div>
<div class="support-item" role="listitem">
<h3>Report Issues</h3>
<p>
Found a bug or have a suggestion? Let me know!
</p>
</div>
<div class="support-item" role="listitem">
<h3>Buy Me a Coffee</h3>
<p>
Donations help cover server costs and keep the
den cozy.
<span class="coming-soon-text"
>(Payment links coming soon!)</span
>
</p>
</div>
<div class="support-item" role="listitem">
<h3>Contribute</h3>
<p>
Check out the projects on Gitea - contributions
are always welcome!
</p>
</div>
</div>
<div class="support-list" role="list">
<SupportItem
title="Share & Spread the Word"
description="Tell others about the projects and services hosted here!"
/>
<SupportItem
title="Report Issues"
description="Found a bug or have a suggestion? Let me know!"
/>
<SupportItem
title="Buy Me a Coffee"
description="Donations help cover server costs and keep the den cozy."
comingSoonNote="Payment links coming soon!"
/>
<SupportItem
title="Contribute"
description="Check out the projects on Gitea - contributions are always welcome!"
/>
</div>
</div>
</section>
</Card>
</Section>
<!-- Footer -->
<footer class="footer" role="contentinfo">
@@ -166,6 +128,32 @@ import BaseLayout from "../layouts/BaseLayout.astro";
</div>
</footer>
</main>
<!-- Scroll Animation Script -->
<script>
// Intersection Observer for scroll animations
const observerOptions = {
threshold: 0.1,
rootMargin: "0px 0px -50px 0px",
};
const observer = new IntersectionObserver((entries) => {
entries.forEach((entry) => {
if (entry.isIntersecting) {
entry.target.classList.add("visible");
// Optionally unobserve after animation
observer.unobserve(entry.target);
}
});
}, observerOptions);
// Observe all elements with scroll-animate class
document.addEventListener("DOMContentLoaded", () => {
const animateElements =
document.querySelectorAll(".scroll-animate");
animateElements.forEach((el) => observer.observe(el));
});
</script>
</BaseLayout>
<style>
@@ -204,91 +192,15 @@ import BaseLayout from "../layouts/BaseLayout.astro";
color: var(--color-text-dim);
}
/* Sections */
.section {
padding: var(--space-lg) 0;
}
.card {
background: var(--color-bg-light);
border-radius: 12px;
padding: var(--space-lg);
box-shadow: 0 4px 6px rgba(0, 0, 0, 0.3);
border: 1px solid rgba(212, 165, 116, 0.1);
}
.card h2 {
font-size: 2rem;
margin-bottom: var(--space-md);
}
.card p {
margin-bottom: var(--space-md);
color: var(--color-text);
}
.card p:last-child {
margin-bottom: 0;
}
/* Services Section */
.service-list {
/* Service and Support Lists */
.service-list,
.support-list {
margin-top: var(--space-md);
display: flex;
flex-direction: column;
gap: var(--space-md);
}
.service-item {
background: var(--color-bg);
padding: var(--space-md);
border-radius: 8px;
border-left: 4px solid var(--color-accent);
}
.service-item h3 {
margin-bottom: var(--space-xs);
font-size: 1.25rem;
}
.service-item p {
color: var(--color-text-dim);
margin: 0;
}
.service-item.coming-soon {
border-left-color: var(--color-warm);
opacity: 0.8;
}
/* Support Section */
.support-list {
margin-top: var(--space-md);
display: grid;
gap: var(--space-md);
}
.support-item {
background: var(--color-bg);
padding: var(--space-md);
border-radius: 8px;
}
.support-item h3 {
margin-bottom: var(--space-xs);
font-size: 1.25rem;
}
.support-item p {
color: var(--color-text-dim);
margin: 0;
}
.coming-soon-text {
font-style: italic;
color: var(--color-warm);
}
/* Footer */
.footer {
margin-top: auto;
@@ -310,10 +222,6 @@ import BaseLayout from "../layouts/BaseLayout.astro";
gap: var(--space-sm);
}
.separator {
color: var(--color-warm);
}
/* Responsive */
@media (max-width: 768px) {
.hero-title {
@@ -323,9 +231,5 @@ import BaseLayout from "../layouts/BaseLayout.astro";
.hero-subtitle {
font-size: 1rem;
}
.card h2 {
font-size: 1.5rem;
}
}
</style>