Add .gitignore, robots.txt, and sitemap integration

Move and restructure BaseLayout to src/layouts with SEO meta tags Add
404 page with accessibility improvements Restructure pages to src/pages
This commit is contained in:
2025-12-24 16:45:35 +01:00
parent e888478c23
commit f318a6bdaf
9 changed files with 439 additions and 135 deletions
+174
View File
@@ -0,0 +1,174 @@
---
interface Props {
title: string;
description?: string;
ogImage?: string;
canonicalURL?: string;
}
const {
title,
description = "Hidden Den Cafe - A cozy, self-hosted corner of the internet. Privacy-focused, furry-friendly, and built with love.",
ogImage = "/og-image.png",
canonicalURL = Astro.url.pathname
} = Astro.props;
const fullCanonicalURL = new URL(canonicalURL, Astro.site).href;
const fullOgImage = new URL(ogImage, Astro.site).href;
---
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<meta name="generator" content={Astro.generator} />
<!-- Primary Meta Tags -->
<title>{title}</title>
<meta name="title" content={title} />
<meta name="description" content={description} />
<link rel="canonical" href={fullCanonicalURL} />
<!-- Open Graph / Facebook -->
<meta property="og:type" content="website" />
<meta property="og:url" content={fullCanonicalURL} />
<meta property="og:title" content={title} />
<meta property="og:description" content={description} />
<meta property="og:image" content={fullOgImage} />
<meta property="og:site_name" content="Hidden Den Cafe" />
<meta property="og:locale" content="en_US" />
<!-- Twitter Card -->
<meta name="twitter:card" content="summary_large_image" />
<meta name="twitter:url" content={fullCanonicalURL} />
<meta name="twitter:title" content={title} />
<meta name="twitter:description" content={description} />
<meta name="twitter:image" content={fullOgImage} />
<!-- Additional Meta Tags -->
<meta name="author" content="Latte" />
<meta name="keywords" content="self-hosted, privacy, open-source, furry, developer, cozy, hidden den" />
<meta name="theme-color" content="#d4a574" />
<meta name="color-scheme" content="dark" />
<!-- Favicon -->
<link rel="icon" type="image/svg+xml" href="/favicon.svg" />
<link rel="apple-touch-icon" href="/favicon.svg" />
<!-- Preconnect for performance (if needed for future external resources) -->
<!-- <link rel="preconnect" href="https://example.com" crossorigin /> -->
</head>
<body>
<slot />
</body>
</html>
<style is:global>
:root {
/* Cozy Den Color Palette */
--color-bg: #1a1410;
--color-bg-light: #2a1f18;
--color-text: #f4e9d8;
--color-text-dim: #c4b5a0;
--color-accent: #d4a574;
--color-accent-bright: #e8bf8e;
--color-warm: #8b6f47;
/* Spacing */
--space-xs: 0.5rem;
--space-sm: 1rem;
--space-md: 1.5rem;
--space-lg: 2rem;
--space-xl: 3rem;
/* Typography */
--font-body: system-ui, -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
}
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
html {
font-family: var(--font-body);
background: var(--color-bg);
color: var(--color-text);
scroll-behavior: smooth;
}
body {
min-height: 100vh;
line-height: 1.6;
}
h1, h2, h3, h4, h5, h6 {
color: var(--color-accent-bright);
line-height: 1.2;
}
a {
color: var(--color-accent-bright);
text-decoration: none;
transition: color 0.2s ease;
}
a:hover {
color: var(--color-accent);
}
a:focus-visible {
outline: 2px solid var(--color-accent);
outline-offset: 2px;
border-radius: 2px;
}
/* Smooth animations */
@keyframes fadeIn {
from {
opacity: 0;
transform: translateY(20px);
}
to {
opacity: 1;
transform: translateY(0);
}
}
.fade-in {
animation: fadeIn 0.6s ease-out;
}
/* Respect user's motion preferences */
@media (prefers-reduced-motion: reduce) {
*,
*::before,
*::after {
animation-duration: 0.01ms !important;
animation-iteration-count: 1 !important;
transition-duration: 0.01ms !important;
scroll-behavior: auto !important;
}
}
/* Improve focus visibility for keyboard navigation */
*:focus-visible {
outline: 2px solid var(--color-accent);
outline-offset: 2px;
}
/* Screen reader only content */
.sr-only {
position: absolute;
width: 1px;
height: 1px;
padding: 0;
margin: -1px;
overflow: hidden;
clip: rect(0, 0, 0, 0);
white-space: nowrap;
border-width: 0;
}
</style>
+150
View File
@@ -0,0 +1,150 @@
---
import BaseLayout from '../layouts/BaseLayout.astro';
---
<BaseLayout
title="404 - Page Not Found | Hidden Den Cafe"
description="This page doesn't exist in the Hidden Den. Let's get you back to somewhere cozy."
>
<main class="not-found-page">
<div class="container">
<div class="card fade-in">
<div class="not-found-content">
<h1 class="error-code">404</h1>
<h2 class="error-title">Lost in the Den?</h2>
<p class="error-message">
Oops! This cozy corner doesn't seem to exist. Maybe it's still being built,
or perhaps you've wandered into a part of the den that hasn't been opened yet.
</p>
<div class="actions">
<a href="/" class="btn-primary">
<span aria-hidden="true">🏡</span> Back to Home
</a>
<a href="https://git.hiddenden.cafe" class="btn-secondary" target="_blank" rel="noopener noreferrer">
<span aria-hidden="true">📦</span> Visit Gitea
</a>
</div>
</div>
</div>
</div>
</main>
</BaseLayout>
<style>
.not-found-page {
display: flex;
align-items: center;
justify-content: center;
min-height: 100vh;
padding: var(--space-md);
}
.container {
max-width: 600px;
width: 100%;
}
.card {
background: var(--color-bg-light);
border-radius: 12px;
padding: var(--space-xl);
box-shadow: 0 4px 6px rgba(0, 0, 0, 0.3);
border: 1px solid rgba(212, 165, 116, 0.1);
text-align: center;
}
.not-found-content {
display: flex;
flex-direction: column;
gap: var(--space-md);
}
.error-code {
font-size: 6rem;
font-weight: bold;
color: var(--color-accent);
line-height: 1;
margin: 0;
text-shadow: 2px 2px 4px rgba(0, 0, 0, 0.3);
}
.error-title {
font-size: 2rem;
margin: 0;
color: var(--color-accent-bright);
}
.error-message {
font-size: 1.1rem;
color: var(--color-text-dim);
line-height: 1.6;
margin: 0;
}
.actions {
display: flex;
gap: var(--space-md);
justify-content: center;
flex-wrap: wrap;
margin-top: var(--space-md);
}
.btn-primary,
.btn-secondary {
display: inline-flex;
align-items: center;
gap: var(--space-xs);
padding: var(--space-sm) var(--space-lg);
border-radius: 8px;
font-weight: 500;
transition: all 0.2s ease;
text-decoration: none;
}
.btn-primary {
background: var(--color-accent);
color: var(--color-bg);
}
.btn-primary:hover {
background: var(--color-accent-bright);
transform: translateY(-2px);
box-shadow: 0 4px 8px rgba(212, 165, 116, 0.3);
}
.btn-secondary {
background: transparent;
color: var(--color-accent-bright);
border: 2px solid var(--color-accent);
}
.btn-secondary:hover {
background: rgba(212, 165, 116, 0.1);
border-color: var(--color-accent-bright);
transform: translateY(-2px);
}
@media (max-width: 768px) {
.error-code {
font-size: 4rem;
}
.error-title {
font-size: 1.5rem;
}
.error-message {
font-size: 1rem;
}
.actions {
flex-direction: column;
}
.btn-primary,
.btn-secondary {
width: 100%;
justify-content: center;
}
}
</style>
+301
View File
@@ -0,0 +1,301 @@
---
import BaseLayout from '../layouts/BaseLayout.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."
>
<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">
<span aria-hidden="true">🏡</span> Hidden Den Cafe
</h1>
<p class="hero-subtitle">A cozy corner of the internet</p>
</div>
</div>
</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"><span aria-hidden="true">☕</span> 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>
<!-- 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"><span aria-hidden="true">🦊</span> 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>
<!-- Services Section -->
<section class="section services" aria-labelledby="services-heading">
<div class="container">
<div class="card fade-in">
<h2 id="services-heading"><span aria-hidden="true">🛠️</span> 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">
<span aria-hidden="true">📦</span> 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><span aria-hidden="true">🔜</span> 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>
</div>
</section>
<!-- Support Section -->
<section class="section support" aria-labelledby="support-heading">
<div class="container">
<div class="card fade-in">
<h2 id="support-heading"><span aria-hidden="true">💝</span> 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><span aria-hidden="true">🌟</span> Share & Spread the Word</h3>
<p>Tell others about the projects and services hosted here!</p>
</div>
<div class="support-item" role="listitem">
<h3><span aria-hidden="true">🐛</span> Report Issues</h3>
<p>Found a bug or have a suggestion? Let me know!</p>
</div>
<div class="support-item" role="listitem">
<h3><span aria-hidden="true">☕</span> 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><span aria-hidden="true">🤝</span> Contribute</h3>
<p>Check out the projects on Gitea - contributions are always welcome!</p>
</div>
</div>
</div>
</div>
</section>
<!-- Footer -->
<footer class="footer" role="contentinfo">
<div class="container">
<p>Made with <span aria-hidden="true">💖</span><span class="sr-only">love</span> 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>
<span class="separator" aria-hidden="true">•</span>
<a href="https://dmush.cloud" target="_blank" rel="noopener noreferrer">dmush.cloud</a>
</p>
</nav>
</div>
</footer>
</main>
</BaseLayout>
<style>
main {
display: flex;
flex-direction: column;
min-height: 100vh;
}
.container {
max-width: 800px;
margin: 0 auto;
padding: 0 var(--space-md);
width: 100%;
}
/* Hero Section */
.hero {
padding: var(--space-xl) 0;
text-align: center;
background: linear-gradient(135deg, var(--color-bg) 0%, var(--color-bg-light) 100%);
}
.hero-title {
font-size: 3rem;
margin-bottom: var(--space-sm);
text-shadow: 2px 2px 4px rgba(0, 0, 0, 0.3);
}
.hero-subtitle {
font-size: 1.25rem;
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 {
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;
padding: var(--space-lg) 0;
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);
}
.footer-links {
display: flex;
justify-content: center;
align-items: center;
gap: var(--space-sm);
}
.separator {
color: var(--color-warm);
}
/* Responsive */
@media (max-width: 768px) {
.hero-title {
font-size: 2rem;
}
.hero-subtitle {
font-size: 1rem;
}
.card h2 {
font-size: 1.5rem;
}
}
</style>