feat: redesign site as personal page with Catppuccin theme
Enterprise AI Code Review / ai-review (pull_request) Successful in 44s

- Switch to Catppuccin Mocha color palette
- Add monospace font (JetBrains Mono/Fira Code)
- Create minimalist layout with centered card design
- Add subtle animated grid background
- Update content to personal info (Latte)
- Include projects, games, and crypto donation addresses
- Update 404 page to match new style
This commit is contained in:
2026-01-03 13:00:17 +01:00
parent f36f65733e
commit a21e512bbe
3 changed files with 349 additions and 255 deletions
+267 -151
View File
@@ -1,203 +1,319 @@
---
import BaseLayout from "../layouts/BaseLayout.astro";
import Card from "../components/Card.astro";
import Section from "../components/Section.astro";
import ServiceItem from "../components/ServiceItem.astro";
---
<BaseLayout
title="Hidden Den Cafe - Cozy Self-Hosted Services"
description="Welcome to Hidden Den Cafe - a warm, self-hosted space where technology meets comfort. Privacy-focused, furry-friendly, and built with love by Latte."
title="Hidden Den Cafe"
description="Latte's cozy corner of the internet. Gay furry wizard, IT enthusiast, and self-hosting advocate."
>
<main id="main-content">
<!-- Hero Section -->
<section class="hero" aria-labelledby="hero-title">
<div class="container">
<div class="hero-content fade-in">
<h1 id="hero-title" class="hero-title">Hidden Den Cafe</h1>
<p class="hero-subtitle">A cozy corner of the internet</p>
<div class="matrix-bg" aria-hidden="true"></div>
<main class="main">
<div class="container">
<!-- Header -->
<header class="header fade-in">
<h1 class="title">Hidden Den Cafe</h1>
<div class="divider">══════════════════════════════</div>
</header>
<!-- About -->
<section class="section fade-in">
<p class="intro">
Hey, I'm <span class="highlight">Latte</span> (he/him).
</p>
<p class="tagline">gay furry wizard</p>
<p class="desc">
IT wizard with a homelab. I believe in self-hosting, privacy,
and keeping control of my own data. Companies don't get to sell
or misuse what's mine.
</p>
</section>
<div class="divider">══════════════════════════════</div>
<!-- Games -->
<section class="section fade-in">
<h2>Games</h2>
<p class="games">
Minecraft, No Man's Sky, Warframe, Cyberpunk 2077
</p>
</section>
<div class="divider">══════════════════════════════</div>
<!-- Projects -->
<section class="section fade-in">
<h2>Projects</h2>
<div class="project">
<h3><a href="https://git.hiddenden.cafe/Hiddenden/openrabbit" target="_blank" rel="noopener noreferrer">OpenRabbit</a></h3>
<p>AI code review system for Gitea with automated PR review, issue triage, interactive chat, and codebase analysis.</p>
</div>
</div>
</section>
<p class="note">More projects coming soon...</p>
</section>
<!-- About Hidden Den 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>
<div class="divider">══════════════════════════════</div>
<!-- About Latte 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>
<!-- Links -->
<section class="section fade-in">
<h2>Links</h2>
<ul class="links">
<li><a href="https://git.hiddenden.cafe" target="_blank" rel="noopener noreferrer">Gitea</a> — Self-hosted git server</li>
</ul>
</section>
<!-- Services Section -->
<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="divider">══════════════════════════════</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}
/>
<!-- Donate -->
<section class="section fade-in">
<h2>Support</h2>
<div class="donate">
<div class="crypto">
<span class="crypto-label">[XMR]</span>
<code class="crypto-addr">41uiUeBru8jhtzjQz3M5CKV1uFpern7juStdfveNQS52LQ9aw3mNkdbc8akM81YnxuE2RT9K2Cmyp9cfyi1osrbVBjBbzQ3</code>
</div>
<div class="crypto">
<span class="crypto-label">[ETH]</span>
<code class="crypto-addr">0x3Dfc92458267b91BFa6bF8f6c86bAE809Ab76Cb4</code>
</div>
</div>
</Card>
</Section>
</section>
<!-- Footer -->
<footer class="footer" role="contentinfo">
<div class="container">
<!-- Footer -->
<footer class="footer fade-in">
<div class="divider">══════════════════════════════</div>
<p>Made with love by Latte</p>
<nav aria-label="Footer navigation">
<p class="footer-links">
<a
href="https://git.hiddenden.cafe"
target="_blank"
rel="noopener noreferrer">Gitea</a
>
</p>
</nav>
</div>
</footer>
</footer>
</div>
</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>
main {
display: flex;
flex-direction: column;
/* Matrix-style animated background */
.matrix-bg {
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 100%;
z-index: -1;
opacity: 0.03;
background:
linear-gradient(var(--color-accent) 1px, transparent 1px),
linear-gradient(90deg, var(--color-accent) 1px, transparent 1px);
background-size: 50px 50px;
animation: grid-move 20s linear infinite;
}
@keyframes grid-move {
0% { transform: translate(0, 0); }
100% { transform: translate(50px, 50px); }
}
.main {
min-height: 100vh;
display: flex;
align-items: center;
justify-content: center;
padding: var(--space-lg) var(--space-md);
}
.container {
max-width: 800px;
margin: 0 auto;
padding: 0 var(--space-md);
max-width: 700px;
width: 100%;
background: rgba(30, 30, 46, 0.8);
backdrop-filter: blur(10px);
border: 1px solid var(--color-surface);
border-radius: 8px;
padding: var(--space-xl);
}
/* Hero Section */
.hero {
padding: var(--space-xl) 0;
.header {
text-align: center;
background: linear-gradient(
135deg,
var(--color-bg) 0%,
var(--color-bg-light) 100%
);
margin-bottom: var(--space-lg);
}
.hero-title {
font-size: 3rem;
.title {
font-size: 2rem;
font-weight: 700;
letter-spacing: 2px;
}
.divider {
color: var(--color-surface);
text-align: center;
font-size: 0.75rem;
margin: var(--space-md) 0;
user-select: none;
}
.section {
margin: var(--space-md) 0;
}
.section h2 {
font-size: 1rem;
text-transform: uppercase;
letter-spacing: 2px;
margin-bottom: var(--space-sm);
text-shadow: 2px 2px 4px rgba(0, 0, 0, 0.3);
color: var(--color-accent);
}
.hero-subtitle {
font-size: 1.25rem;
.intro {
font-size: 1.1rem;
margin-bottom: var(--space-xs);
}
.highlight {
color: var(--color-accent-bright);
font-weight: 700;
}
.tagline {
color: var(--color-accent);
font-style: italic;
margin-bottom: var(--space-sm);
}
.desc {
color: var(--color-text-dim);
line-height: 1.7;
}
.games {
color: var(--color-text-dim);
}
/* Service List */
.service-list {
margin-top: var(--space-md);
display: flex;
flex-direction: column;
gap: var(--space-md);
.project {
margin-bottom: var(--space-sm);
}
.project h3 {
font-size: 1rem;
margin-bottom: var(--space-xs);
}
.project h3 a {
color: var(--color-blue);
}
.project h3 a:hover {
color: var(--color-accent-bright);
}
.project p {
color: var(--color-text-dim);
font-size: 0.9rem;
}
.note {
color: var(--color-surface);
font-style: italic;
font-size: 0.85rem;
}
.links {
list-style: none;
}
.links li {
margin-bottom: var(--space-xs);
color: var(--color-text-dim);
}
.links a {
color: var(--color-blue);
}
.links a:hover {
color: var(--color-accent-bright);
}
.donate {
display: flex;
flex-direction: column;
gap: var(--space-sm);
}
.crypto {
display: flex;
flex-wrap: wrap;
align-items: baseline;
gap: var(--space-xs);
}
.crypto-label {
color: var(--color-peach);
font-weight: 700;
font-size: 0.85rem;
}
.crypto-addr {
font-size: 0.7rem;
color: var(--color-text-dim);
word-break: break-all;
background: var(--color-bg);
padding: 2px 6px;
border-radius: 4px;
}
/* Footer */
.footer {
margin-top: auto;
padding: var(--space-lg) 0;
margin-top: var(--space-lg);
text-align: center;
border-top: 1px solid rgba(212, 165, 116, 0.2);
background: var(--color-bg-light);
}
.footer p {
color: var(--color-text-dim);
margin-bottom: var(--space-xs);
font-size: 0.85rem;
}
.footer-links {
display: flex;
justify-content: center;
align-items: center;
gap: var(--space-sm);
/* Animations */
.fade-in {
animation: fadeIn 0.6s ease-out forwards;
opacity: 0;
}
.fade-in:nth-child(1) { animation-delay: 0.1s; }
.fade-in:nth-child(2) { animation-delay: 0.2s; }
.fade-in:nth-child(3) { animation-delay: 0.3s; }
.fade-in:nth-child(4) { animation-delay: 0.4s; }
.fade-in:nth-child(5) { animation-delay: 0.5s; }
.fade-in:nth-child(6) { animation-delay: 0.6s; }
.fade-in:nth-child(7) { animation-delay: 0.7s; }
@keyframes fadeIn {
from {
opacity: 0;
transform: translateY(10px);
}
to {
opacity: 1;
transform: translateY(0);
}
}
/* Responsive */
@media (max-width: 768px) {
.hero-title {
font-size: 2rem;
@media (max-width: 600px) {
.container {
padding: var(--space-md);
}
.hero-subtitle {
font-size: 1rem;
.title {
font-size: 1.5rem;
}
.divider {
font-size: 0.6rem;
}
}
@media (prefers-reduced-motion: reduce) {
.matrix-bg {
animation: none;
}
.fade-in {
animation: none;
opacity: 1;
}
}
</style>