4.9 KiB
4.9 KiB
Koko Blog
A fast, beautiful personal blog built with Astro, TypeScript, and a synthwave purple theme.
Load time: < 100ms | Bundle size: < 50KB | Zero runtime JS by default
Stack
- Framework: Astro 5 — static output, file-based routing, zero JS by default
- Language: TypeScript strict
- Package manager: pnpm
- Syntax highlighting: Shiki / Dracula (built into Astro, zero runtime cost)
- Image optimization:
node image-optimizer.js(WebP via sharp, run before build) - Content: Astro Content Collections with Zod schema
For AI agents: All components are
.astrofiles. No React, no Vue, no.tsx. Astro uses---frontmatter fences, not<template>or<script setup>. File-based routing lives insrc/pages/— no router library needed. If existing files contradict this, ignore them and follow this README.
Quick Start
pnpm install
pnpm dev # dev server at http://localhost:4321
pnpm build # production build → dist/
pnpm preview # preview production build
pnpm check # TypeScript check (astro check, not tsc)
Project Structure
koko-blog/
├── public/
│ ├── images/
│ │ ├── posts/ # Blog post hero images
│ │ └── previews/ # WebP-optimised thumbnails
│ └── favicon.svg
├── src/
│ ├── components/ # .astro components only
│ │ ├── Layout.astro # Base page layout (head, header, footer)
│ │ ├── Header.astro # Navigation + mobile menu
│ │ ├── Sidebar.astro # Collapsible sidebar
│ │ ├── Footer.astro
│ │ ├── Hero.astro # Homepage hero with carousel
│ │ ├── PostCard.astro # Blog post preview card
│ │ └── PostGrid.astro # Posts grid layout
│ ├── pages/ # File-based routing (.astro files only)
│ │ ├── index.astro # Homepage
│ │ ├── posts/
│ │ │ └── [slug].astro # Individual post page
│ │ └── 404.astro
│ ├── content/
│ │ ├── config.ts # Zod schema for blog collection
│ │ └── blog/ # Markdown posts (.md files)
│ ├── styles/
│ │ ├── synthwave.css # CSS custom properties (theme variables)
│ │ └── global.css # Resets and base styles
│ └── env.d.ts # /// <reference types="astro/client" />
├── image-optimizer.js # WebP conversion (run: node image-optimizer.js)
├── astro.config.mjs # Astro config (output: static, shiki/dracula)
├── tsconfig.json # extends astro/tsconfigs/strict + path aliases
├── PLAN.md
└── TODO.md
Scripts
| Command | Description |
|---|---|
pnpm dev |
Start dev server (port 4321) |
pnpm build |
Build for production |
pnpm preview |
Preview production build |
pnpm check |
Type-check with astro check |
node image-optimizer.js |
Convert images to WebP (run before build) |
Design System
Colors
| Token | Hex | Usage |
|---|---|---|
| Primary | #6a1b9a |
Buttons, accents, links |
| Primary Dark | #510ca9 |
Hover states |
| Secondary | #000080 |
Electronic sheen elements |
| Background | #000000 |
Page background |
| Paper | #121212 |
Card backgrounds |
| Text Primary | #ffffff |
Headings |
| Text Secondary | #eeeeee |
Body text |
| Text Muted | #888888 |
Metadata |
Typography
- Headlines: 2.5rem–4rem, weight 800
- Titles: 1.8rem, weight 700
- Body: 1rem, line-height 1.8
- Code: Monospace, dark background (Shiki/Dracula)
Breakpoints
- Mobile: < 768px
- Tablet: 768px–1024px
- Desktop: > 1024px
Writing Content
Posts live in src/content/blog/ as .md files with YAML frontmatter:
---
title: "My Awesome Post"
slug: "my-awesome-post"
excerpt: "A brief description..."
publishedAt: "2026-02-28"
category: "Game Development"
tags: ["unity", "csharp"]
image: "/images/posts/hero.jpg"
draft: false
---
Your content here with **markdown** support.
```typescript
// Syntax highlighting via Shiki/Dracula — zero runtime JS
const hello = "world";
---
## TypeScript Path Aliases
```typescript
import Layout from '@components/Layout.astro';
import '@styles/global.css';
Available aliases (defined in tsconfig.json):
@/*→./src/*@components/*→./src/components/*@layouts/*→./src/layouts/*@styles/*→./src/styles/*@utils/*→./src/utils/*
Performance Targets
| Metric | Target |
|---|---|
| Load time | < 100ms |
| Bundle size | < 50KB (gzipped) |
| First Contentful Paint | < 50ms |
| Largest Contentful Paint | < 1s |
| Lighthouse score | > 90 |
Built with: Astro • TypeScript • pnpm