Introduce blog support: content collection schema, listing and post routes, and a sample Markdown post. Update docs and TODO; add blog assets dir and adjust color variables in docs. Also set absolute_redirect off in nginx.conf for container routing.
9.2 KiB
Cozy Den - Developer Documentation
Project Overview
Cozy Den is a landing page for hiddenden.cafe built with Astro. The site features a warm, cozy aesthetic inspired by coffee shops and hidden dens, representing values of privacy, self-hosting, and open-source software.
Tech Stack:
- Astro 4.x (Static Site Generator)
- TypeScript (strict mode)
- Vanilla CSS with CSS Custom Properties
- Docker + Nginx for deployment
- Node.js 18+
Project Structure
cozy-den/
├── src/
│ ├── content/
│ │ ├── config.ts # Content collection schema
│ │ └── blog/
│ │ └── *.md # Blog posts (Markdown)
│ ├── layouts/
│ │ └── BaseLayout.astro # Base HTML layout with global styles
│ ├── pages/
│ │ ├── index.astro # Main landing page
│ │ ├── 404.astro # Custom 404 error page
│ │ └── blog/
│ │ ├── index.astro # Blog listing page (/blog)
│ │ └── [...slug].astro # Individual post pages (/blog/<slug>)
├── public/
│ ├── favicon.svg # Site favicon (coffee emoji)
│ ├── robots.txt # Search engine directives
│ └── blog/ # Blog post images (per-post subdirectory)
├── astro.config.mjs # Astro configuration with sitemap
├── package.json # Node dependencies
├── tsconfig.json # TypeScript configuration
├── Dockerfile # Multi-stage Docker build
├── docker-compose.yml # Docker Compose setup
├── nginx.conf # Nginx configuration for production
├── .gitignore # Git ignore rules
└── README.md # User-facing documentation
Color Palette
The site uses CSS custom properties for theming. All colors are defined in src/layouts/BaseLayout.astro:
--color-bg: #1e1e2e /* Dark background (Catppuccin Mocha base) */
--color-text: #cdd6f4 /* Light text */
--color-text-dim: #a6adc8 /* Dimmed text for less emphasis */
--color-accent: #cba6f7 /* Mauve accent */
--color-accent-bright: #f5c2e7 /* Pink accent for highlights */
--color-surface: #313244 /* Surface color for borders/cards */
--color-blue: #89b4fa /* Blue for links */
--color-green: #a6e3a1 /* Green for code */
--color-peach: #fab387 /* Peach for labels */
Component Architecture
BaseLayout.astro
The base layout provides:
- HTML structure and meta tags
- Global CSS reset and typography
- CSS custom properties for theming
- Global animations (fadeIn)
index.astro
The main page includes these sections:
- Header - Title
- About - Introduction, age, status
- Cryptographic Keys - PGP fingerprint and SSH public key
- Games - Games Latte plays
- Socials - Links to social platforms
- Services - Self-hosted services
- Support - Crypto donation addresses
- Blog - Link to
/blog - Footer - Credits
blog/index.astro
Blog listing page at /blog. Fetches all non-draft posts from the blog content collection, sorted by date descending.
blog/[...slug].astro
Individual blog post page. Renders Markdown content using Astro's <Content /> component. Styles for prose content (headings, paragraphs, code blocks, images, etc.) are scoped within .content :global(...).
src/content/config.ts
Defines the blog content collection schema:
title(string) — post titledate(date) — publish date, used for sortingdescription(string) — shown on the listing pagedraft(boolean, optional) — set totrueto hide from listing
404.astro
Custom error page with:
- Themed styling matching the cozy aesthetic
- Clear error message ("Lost in the Den?")
- Action buttons to return home or visit Gitea
- Responsive design for all devices
Development Workflow
Local Development
- Install dependencies:
npm install
- Start dev server (with hot reload):
npm run dev
Server runs at http://localhost:4321
- Build for production:
npm run build
Output goes to dist/ directory
- Preview production build:
npm run preview
Making Changes
Adding a new section:
- Edit
src/pages/index.astro - Add a new
<section class="section new-section">block - Style it in the
<style>tag at the bottom - Use the
.cardclass for consistent styling
Changing colors:
- Edit CSS custom properties in
src/layouts/BaseLayout.astro - All components will automatically update
Adding a service:
- Add a new
.service-itemdiv in the Services section - Follow the existing structure with h3 link and description
Adding images:
- Place images in
public/blog/<post-slug>/directory - Reference in Markdown with
/blog/<post-slug>/image.jpg - They'll be served as static assets by nginx
Adding a blog post:
- Create
src/content/blog/my-post-slug.md - Add frontmatter:
title,date,description(and optionallydraft: true) - Write content in Markdown below the frontmatter
- The post appears automatically at
/blog/my-post-slug
Docker Deployment
Building the Image
The Dockerfile uses a multi-stage build:
- Stage 1: Node builder (builds Astro site)
- Stage 2: Nginx server (serves static files)
docker build -t cozy-den .
Running Locally
docker run -d -p 3000:80 --name cozy-den cozy-den
Access at http://localhost:3000
Using Docker Compose
# Start
docker-compose up -d
# Stop
docker-compose down
# View logs
docker-compose logs -f
Deploying to Gitea Registry
# Tag for Gitea registry
docker tag cozy-den git.hiddenden.cafe/mats/cozy-den:latest
# Login to Gitea
docker login git.hiddenden.cafe
# Push
docker push git.hiddenden.cafe/mats/cozy-den:latest
Astro-Specific Information
File Extensions
.astro- Astro components (HTML-like syntax with embedded JS).mjs- ES module JavaScript files
Frontmatter
Code between --- at the top of .astro files runs at build time:
---
// This runs at build time (server-side)
const title = "My Page";
---
<h1>{title}</h1>
Styling
<style>tags in .astro files are scoped by default- Use
<style is:global>for global styles - CSS is processed and optimized automatically
Static Generation
Astro generates static HTML at build time. No JavaScript runtime needed for this site (pure HTML/CSS output).
Common Tasks
Task: Add a new page
- Create
src/pages/newpage.astro - Import BaseLayout
- Add content
- Page will be available at
/newpage
Example:
---
import BaseLayout from '../layouts/BaseLayout.astro';
---
<BaseLayout title="New Page">
<div class="container">
<h1>New Page</h1>
</div>
</BaseLayout>
Task: Add a new section to homepage
- Open
src/pages/index.astro - Add new section before footer:
<section class="section my-section">
<div class="container">
<div class="card fade-in">
<h2>My Section</h2>
<p>Content here</p>
</div>
</div>
</section>
- Add styles in the
<style>tag if needed
Task: Change the accent color
- Open
src/layouts/BaseLayout.astro - Modify
--color-accentand--color-accent-bright - Site updates automatically
Task: Add animation to new element
- Add
fade-inclass to element - Or create new animation in BaseLayout.astro:
@keyframes slideIn {
from { transform: translateX(-20px); opacity: 0; }
to { transform: translateX(0); opacity: 1; }
}
.slide-in { animation: slideIn 0.6s ease-out; }
Troubleshooting
Build fails with TypeScript errors
- Check
tsconfig.jsonextends correct config - Ensure all props are properly typed in components
Styles not applying
- Check if you need
is:globalon style tag - Verify CSS custom properties are defined in BaseLayout
Docker build fails
- Ensure
package.jsonandpackage-lock.jsonare present - Check Node version compatibility (needs 18+)
Changes not showing in dev
- Hard refresh browser (Ctrl+Shift+R)
- Restart dev server
- Clear
.astrocache directory
Future Enhancements
Ideas for future development:
- Add blog section using Astro's content collections
- Create custom 404 page
- Add RSS feed for blog
- Create reusable components for service items
- Add more animations and transitions
- Integrate with analytics (privacy-friendly, self-hosted)
Resources
Notes for AI Assistants
When working with this project:
- Maintain the cozy aesthetic (warm colors, soft animations)
- Keep the site lightweight and fast (static HTML/CSS)
- Follow the existing component structure
- Use CSS custom properties for theming
- Ensure responsive design for mobile
- Add appropriate TypeScript types when needed
- Test both dev and production builds
- Verify Docker build works after changes