Files
koko_blog/TODO.md
T
2026-04-30 19:44:13 +02:00

35 KiB

Koko Blog - TODO List

Detailed task breakdown with sub-steps for systematic implementation.


Phase 0: Project Initialization (Critical)

0. Initialize Astro Project

Priority: Critical | Status: Pending

  • Astro 5.x scaffold with output: 'static' and Dracula/Shiki
  • TypeScript strict mode via astro/tsconfigs/strict
  • Path aliases (@/*, @components/*, @layouts/*, @styles/*, @utils/*)
  • src/content/config.ts — Zod schema for blog posts (title, slug, excerpt, publishedAt, category, tags, image, draft)
  • src/env.d.ts with Astro client types
  • pnpm build passes cleanly

Phase 1: Complete Synthwave Theme Implementation (src/styles/)

Priority: Critical | Status: Pending

STACK ENFORCEMENT (NON-NEGOTIABLE):

  • Framework: Pure CSS in .css files
  • Forbidden: CSS-in-JS, styled-components, Tailwind classes in TS
  • Required patterns: CSS custom properties, Astro-native styling
  • Verification: Check no import styles from... patterns

NON-FUNCTIONAL REQUIREMENTS:

  • Bundle size: CSS must be < 20KB total
  • Performance: No render-blocking CSS (use media queries)
  • Security: No user input in CSS (static only)

Implementation Checklist:

  • Define complete color palette

    • Primary purple (#6a1b9a) with all variations (main, dark, light)
    • Secondary blue (#000080) with all variations
    • Background colors (default black #000, paper #121212)
    • Accent colors for highlights (magenta variations)
    • Opacity variations for dark mode (0%, 5%, 10%, 20% opacity layers)
    • Verify: All hex codes match PLAN.md exactly
  • Implement gradient system

    • Default gradient: 135deg from black through purple to black
    • Gradient 1: 135deg with full opacity at 100%
    • Gradient 2: Repeating gradient for shimmer effect
    • Gradient transitions with CSS custom properties
    • Verify: Gradients render correctly in dev and build
  • Build shimmer effects

    • Background shimmer overlay (90deg, transparent through purple to transparent)
    • Floating glass effect with 45deg overlay
    • Low opacity layers for depth perception
    • CSS animation for subtle movement (optional)
    • Verify: Animations respect prefers-reduced-motion
  • Create typography scale

    • Headline: 2.5rem (mobile) to 3rem (desktop), weight 800
    • HeadlineMedium: 2rem to 2.5rem, weight 600
    • Title: 1.8rem, weight 700
    • Subtitle: 1.2rem, color #aaa
    • Body: 1rem, color #eee
    • Meta text: 0.9rem, color #888
  • Define transition timings

    • Shimmer-in easing: cubic-bezier(0.4, 0, 0.6, 1)
    • Gradient-in easing: cubic-bezier(0.53, 0.55, 0.55, 1)
    • Duration variants: short (0.3s), medium (0.5s), long (0.8s)

Review Checklist for Loki:

  • Build passes: pnpm build exits 0
  • No React imports in any file
  • CSS file size < 20KB
  • All colors match hex codes in PLAN.md
  • Typography scale implemented correctly

2. Build Responsive Layout with Collapsible Sidebar (Layout.astro, Header.astro, Sidebar.astro, Footer.astro)

Priority: Critical | Status: Pending

STACK ENFORCEMENT (NON-NEGOTIABLE):

  • Framework: Astro .astro components ONLY
  • Forbidden: React, JSX, React hooks (useState, useEffect, etc.), react-router-dom
  • Forbidden: Vue, Svelte, or any other framework
  • Required patterns: Astro frontmatter, <script> tags for vanilla JS, CSS <style> blocks
  • Verification: grep -r "from 'react'" src/components/ must return NOTHING

NON-FUNCTIONAL REQUIREMENTS:

  • Bundle size: Each component < 15KB, total layout < 50KB
  • Performance: No render-blocking JS, minimal client-side JS
  • Accessibility: ARIA labels, keyboard navigation, focus management

Pre-Implementation (Thor must do before dispatching Odin):

  • Read existing src/content/config.ts to understand data types
  • Read src/styles/synthwave.css to understand theme integration
  • Verify Astro version and capabilities

Implementation Checklist:

Layout.astro (Base Structure)

  • Create base Layout.astro structure
    • Main container with full viewport height
    • Flexbox column layout
    • Theme gradient background integration (import from synthwave.css)
    • Transition effects for all interactive elements
    • Props via const { title } = Astro.props in frontmatter
    • Import and use Header, Sidebar, Footer components
    • <slot /> for main content
    • Code pattern to follow:
      ---
      const { title } = Astro.props;
      import Header from './Header.astro';
      import Sidebar from './Sidebar.astro';
      import Footer from './Footer.astro';
      ---
      
    • Verify: No React imports, no JSX, no export default

Header.astro

  • Implement Header.astro component
    • Fixed position at top (z-index: 100)
    • Logo/branding area (left side)
    • Mobile menu toggle button (right side, visible only on mobile via CSS)
    • Desktop navigation links (optional)
    • Z-index layering for overlay elements
    • Verify: Uses CSS for responsive visibility, not JS

Sidebar.astro

  • Build Sidebar.astro component
    • Fixed position, left side
    • 300px width
    • Synthwave gradient background
    • Shadow: 3px 0 20px rgba(106, 27, 154, 0.3)
    • Navigation list with hover effects
    • Social media links section
    • Verify: Uses CSS for positioning, not JS

Mobile Menu Logic

  • Implement mobile menu behavior in Layout.astro
    • Add <script> tag at bottom of Layout.astro for vanilla JS
    • Hamburger icon rotation animation (180deg) via CSS transitions
    • Sidebar slide-in from left (translateX animation via CSS)
    • Animation duration: 0.5s exactly with cubic-bezier(0.4, 0, 0.6, 1)
    • Click-outside detection to close on mobile (JS event listener)
    • Pointer-events management when closed (CSS)
    • Code pattern:
      <script>
        document.addEventListener('DOMContentLoaded', () => {
          const menuBtn = document.querySelector('.menu-toggle');
          const sidebar = document.querySelector('.sidebar');
          // Toggle classes for CSS animations
        });
      </script>
      
    • Verify: No useState, no React hooks, vanilla JS only

Main Content Area

  • Create Main Content area in Layout.astro
    • Dynamic padding-left based on sidebar state (CSS class toggle)
    • Responsive max-width (1400px)
    • Padding for all viewports (2rem desktop, 1rem mobile)
    • Transition on sidebar state change (CSS transition property)

Footer.astro

  • Implement Footer.astro component
    • Paper background color (#121212)
    • Copyright text (centered)
    • Footer link group (centered)
    • Top border (1px solid #333)
    • Hover effects on links (CSS :hover)
    • Verify: No interactive JS needed, pure CSS

Responsive Behavior

  • Screen size detection
    • Window resize event listener in <script> tag
    • Breakpoint detection (768px mobile threshold)
    • CSS class toggling for layout state
    • Verify: CSS media queries for layout changes, JS only for menu toggle

Review Checklist for Loki:

  • Build passes: pnpm build exits 0
  • Check for forbidden imports: grep -r "from 'react'" src/components/ returns nothing
  • Check for JSX: No .tsx files in components directory
  • Verify vanilla JS: All <script> tags use standard DOM API, no React
  • Bundle check: du -sh dist/assets/* shows minimal JS
  • Responsive test: Resize browser, layout adapts correctly
  • Mobile menu: Opens/closes smoothly in 0.5s

Priority: High | Status: Pending

STACK ENFORCEMENT (NON-NEGOTIABLE):

  • Framework: Astro .astro component
  • Forbidden: React hooks, Vue, Svelte, jQuery plugins
  • Forbidden: External carousel libraries (Swiper, Slick, etc.)
  • Required patterns: Vanilla JS in <script> tag, CSS animations
  • Verification: Check no external carousel dependencies

NON-FUNCTIONAL REQUIREMENTS:

  • Performance: Carousel must use CSS transforms, not layout-triggering properties
  • Accessibility: Pause button for auto-rotation, keyboard navigation
  • Bundle size: Hero component must be <20KB including images

Pre-Implementation (Thor must verify):

  • Read src/styles/synthwave.css to extract color variables
  • Confirm public/images/sliders/ directory exists with hero images
  • Check existing Image component usage in other .astro files

Implementation Checklist:

Hero.astro Structure

  • Create Hero.astro section container
    • Full viewport height (100vh desktop, 80vh mobile)
    • Center content vertically and horizontally with flexbox
    • Gradient background integration (use CSS variables from synthwave.css)
    • Dark overlay for text contrast (rgba(0,0,0,0.5))
    • Code pattern:
      ---
      interface Props {
        slides: Array<{
          image: string;
          title: string;
          subtitle: string;
        }>;
      }
      const { slides } = Astro.props;
      ---
      
  • Build carousel structure in Astro template (static HTML)
    • Array of slider items defined in frontmatter or passed as props
    • Create 3-5 slides with sample data
    • Each slide contains: image, title, subtitle, button label
    • Use <Image /> from astro:assets for slide images
    • Absolute positioning for slides with CSS
    • Verify: No dynamic imports, all images resolved at build time

Auto-Rotation Logic

  • Implement auto-rotation via <script> tag
    • 5 second interval between slides (setInterval)
    • DOM-based state using data attributes (e.g., data-slide="0")
    • Pause on hover (mouseenter/mouseleave events)
    • Reset rotation timer on manual change
    • Code pattern:
      <script>
        let currentSlide = 0;
        const slides = document.querySelectorAll('.hero-slide');
        let intervalId;
      
        function rotateSlide() {
          currentSlide = (currentSlide + 1) % slides.length;
          updateSlideVisibility();
        }
      
        intervalId = setInterval(rotateSlide, 5000);
      </script>
      
    • Verify: Uses vanilla JS only, no React hooks

Slide Transitions

  • Create slide transitions with CSS
    • Opacity fade (0.8s duration)
    • Transform translateX for directional movement (optional)
    • Active slide: opacity 1, z-index 2, display: flex
    • Inactive slides: opacity 0, z-index 1, display: none
    • Performance: Use transform and opacity only (GPU accelerated)

Visual Effects

  • Build title with synthwave effects

    • Gradient text using primary purple (#6a1b9a)
    • Webkit background clip for gradient text effect
    • Responsive font sizing (mobile-first)
    • Text shadow for glow effect (optional)
  • Implement action buttons

    • Primary button: filled purple (#6a1b9a), white text
    • Secondary button: transparent, purple outline
    • Hover effects: transform scale(1.02), box-shadow
    • Active state: darker purple background
  • Create carousel controls via vanilla JS
    • Navigation dots at bottom-right (8px circles)
    • Active dot: purple (#6a1b9a), scale(1.2)
    • Inactive dots: gray (#333), transparent
    • Previous/Next arrow buttons (bottom-center, 40px)
    • Click handlers update current slide index
    • Verify: All interactions work without page reload

Review Checklist for Loki:

  • Build passes: pnpm build exits 0
  • No external carousel libraries in package.json
  • Check bundle size: du -sh dist/assets/* - Hero JS < 5KB
  • Carousel auto-rotates every 5 seconds
  • Manual controls work (dots and arrows)
  • Hover pauses rotation
  • All hex codes match PLAN.md (#6a1b9a for purple)
  • Responsive: Looks good on mobile (<768px) and desktop (>1024px)
  • Accessibility: Can navigate with keyboard (Tab, Enter, Arrow keys)

4. Create Post Card Component (PostCard.astro)

Priority: High | Status: Pending

STACK ENFORCEMENT (NON-NEGOTIABLE):

  • Framework: Astro .astro component
  • Forbidden: React hooks, state management, event handlers in JSX
  • Required patterns: Astro props interface, CSS :hover effects
  • Data source: Content Collections via getCollection('blog')
  • Verification: Component receives data via props, not API calls

NON-FUNCTIONAL REQUIREMENTS:

  • Performance: CSS-only hover effects (no JS for interactions)
  • Accessibility: Proper heading hierarchy, alt text for images
  • Bundle size: Component < 10KB

Pre-Implementation (Thor must verify):

  • Read src/content/config.ts to understand BlogPost type
  • Read src/styles/synthwave.css for color/variable reference
  • Check sample post data exists in src/content/blog/

Implementation Checklist:

Component Structure

  • Design PostCard.astro with proper typing
    • Create Props interface extending Content Collection entry
    • Props via const { post } = Astro.props with TypeScript type
    • Container styling from synthwave.css
    • Code pattern:
      ---
      import type { CollectionEntry } from 'astro:content';
      interface Props {
        post: CollectionEntry<'blog'>;
      }
      const { post } = Astro.props;
      const { title, excerpt, publishedAt, category, image } = post.data;
      ---
      

Styling

  • Container styling

    • Semi-transparent background (rgba(255,255,255,0.05))
    • 20px border-radius
    • 2rem padding (1.5rem mobile via media query)
    • Position relative for overlays
    • Verify: Uses CSS variables from synthwave.css
  • Implement hover effects (CSS-only)

    • Transform: translateY(-5px) on hover
    • Box-shadow: 0 15px 40px rgba(106, 27, 154, 0.3) on hover
    • Background lightening (increase opacity by 0.05)
    • Transition: all 0.3s cubic-bezier(0.4, 0, 0.6, 1)
    • Important: CSS :hover only, no JavaScript
    • Code pattern:
      .post-card {
        transition: all 0.3s cubic-bezier(0.4, 0, 0.6, 1);
      }
      .post-card:hover {
        transform: translateY(-5px);
        box-shadow: 0 15px 40px rgba(106, 27, 154, 0.3);
      }
      

Card Header

  • Build card header section
    • Category tag (pill-shaped, purple background #6a1b9a)
    • Publication date formatted (e.g., "Mar 1, 2026")
    • Tags displayed as comma-separated list
    • Flex layout with justify-between
    • Verify: Date formatting happens at build time, not client-side

Title Element

  • Create title with styling
    • Hover color change (#fff to #eee) via CSS
    • Left border accent (purple #6a1b9a, 4px wide)
    • Standard anchor link: <a href={/posts/${post.slug}}>
    • Heading element (h2 or h3 based on context)
    • Accessibility: Semantic heading, not just styled div

Content Area

  • Implement excerpt display

    • Truncated text (150-200 characters)
    • Ellipsis for overflow (text-overflow: ellipsis)
    • Line-height: 1.8 for readability
    • Color: #eee (from synthwave.css variables)
    • Note: Truncation at build time, not via CSS
  • Add image preview

    • Use <Image /> from astro:assets
    • Import: import { Image } from 'astro:assets'
    • Full-width responsive image with defined width/height
    • Border-radius: 12px
    • Aspect ratio preservation via props
    • loading="lazy" for performance
    • Code pattern:
      <Image 
        src={post.data.image} 
        alt={post.data.title}
        width={800}
        height={450}
        loading="lazy"
      />
      

Call to Action

  • Create "Read More" link
    • Standard anchor tag: <a href={/posts/${post.slug}}>
    • Purple background button styling (#6a1b9a)
    • Hover: darker purple (#510ca9) with lift effect
    • Text: "Read More →" or similar
    • Verify: No JavaScript event handlers, standard link behavior

Review Checklist for Loki:

  • Build passes: pnpm build exits 0
  • Component file ends with .astro, not .tsx
  • No React imports or hooks
  • Uses astro:assets Image component
  • Props properly typed with CollectionEntry
  • All hex codes match (#6a1b9a for purple)
  • Hover effects work with CSS only (check in browser)
  • Responsive: Card stacks properly on mobile
  • Accessibility: Images have alt text, semantic headings

5. Set Up Astro Content Collections (src/content/)

Priority: Critical | Status: Pending

STACK ENFORCEMENT (NON-NEGOTIABLE):

  • Framework: Astro Content Collections API
  • Forbidden: marked.js, highlight.js, manual Markdown parsing
  • Forbidden: Runtime Markdown rendering (everything at build time)
  • Required patterns: Zod validation, getCollection(), getStaticPaths()
  • Verification: Check no manual markdown libraries in package.json

NON-FUNCTIONAL REQUIREMENTS:

  • Performance: All Markdown rendered at build time (zero runtime cost)
  • Type Safety: Full TypeScript inference from Zod schema
  • Bundle size: Content collections add ~0KB to client bundle (server-side only)

Pre-Implementation (Thor must verify):

  • Confirm src/content/config.ts already exists from Phase 0
  • Verify Zod schema matches PLAN.md requirements
  • Check sample posts exist in src/content/blog/

Implementation Checklist:

Schema Verification

  • Verify src/content/config.ts exists with correct Zod schema:
    import { defineCollection, z } from 'astro:content';
    
    const blog = defineCollection({
      type: 'content',
      schema: z.object({
        title: z.string(),
        slug: z.string(),
        excerpt: z.string(),
        publishedAt: z.string(),
        category: z.string(),
        tags: z.array(z.string()).default([]),
        image: z.string().optional(),
        draft: z.boolean().default(false),
      }),
    });
    
    export const collections = { blog };
    
    • Verify: Schema matches PLAN.md exactly
    • Verify: TypeScript types are generated (check .astro/types.d.ts)

Post Files

  • Organize post files correctly
    • Location: src/content/blog/*.md (one file per post)
    • Filename format: [slug].md (e.g., hello-world.md)
    • Frontmatter structure matches schema
    • Sample post structure:
      ---
      title: "Hello World"
      slug: "hello-world"
      excerpt: "First post on the blog"
      publishedAt: "2026-03-01"
      category: "General"
      tags: ["intro", "welcome"]
      image: "/images/posts/hello.jpg"
      draft: false
      ---
      
      # Hello World
      
      This is the content...
      

Post Page Implementation ([slug].astro)

  • Create src/pages/posts/[slug].astro with static path generation:

    ---
    import { getCollection } from 'astro:content';
    import Layout from '../../components/Layout.astro';
    
    export async function getStaticPaths() {
      const posts = await getCollection('blog');
      return posts.map(entry => ({
        params: { slug: entry.slug },
        props: { entry },
      }));
    }
    
    const { entry } = Astro.props;
    const { Content, headings } = await entry.render();
    ---
    
    • Critical: Must use getStaticPaths() for static generation
    • Verify: getCollection('blog') returns typed entries
    • Verify: entry.slug matches filename
  • Render post content:

    • Use <Content /> component for body
    • No HTML sanitization needed (Astro handles this)
    • Access frontmatter via entry.data
    • Code pattern:
      <Layout title={entry.data.title}>
        <article>
          <h1>{entry.data.title}</h1>
          <time>{entry.data.publishedAt}</time>
          <Content />
        </article>
      </Layout>
      

Syntax Highlighting

  • Verify Shiki configuration in astro.config.mjs:

    markdown: {
      shikiConfig: {
        theme: 'dracula',
      },
    }
    
    • Note: Shiki runs at build time, no client JS needed
    • Theme: Dracula (already configured in Phase 0)
  • Style code blocks via CSS:

    • Target Shiki output classes (.shiki, .line, etc.)
    • Dark background: #1a1a2e
    • Light text: #f8f8f2
    • Padding: 1.5rem
    • Border-radius: 10px
    • Overflow-x: auto (horizontal scroll for long lines)
    • Verify: Check built HTML has syntax highlighting
  • Style inline code:

    • Background: #2d313e
    • Monospace font family
    • Padding: 0.2em 0.4em
    • Border-radius: 4px
  • Remove forbidden libraries:

    • Check package.json for marked, highlight.js
    • If present, run: pnpm remove marked highlight.js
    • Verify: grep -r "marked\|highlight.js" src/ returns nothing

Review Checklist for Loki:

  • Build passes: pnpm build exits 0
  • TypeScript check passes: pnpm astro check exits 0
  • No marked.js or highlight.js in dependencies
  • Create test post, verify it renders at /posts/[slug]
  • Code blocks have syntax highlighting (check built HTML)
  • All post frontmatter is accessible
  • Draft posts are excluded from collection (check Zod schema)

6. Image Handling with Astro + Sharp

Priority: High | Status: Pending

STACK ENFORCEMENT (NON-NEGOTIABLE):

  • Framework: Astro Assets (astro:assets) with Sharp
  • Forbidden: JSDOM runtime image processing, manual image manipulation
  • Forbidden: External image CDNs (Cloudinary, Imgix, etc.)
  • Required patterns: <Image /> component, build-time optimization
  • Verification: All images processed at build time

NON-FUNCTIONAL REQUIREMENTS:

  • Performance: Images converted to WebP at build time
  • Bundle size: Zero runtime image processing code
  • Accessibility: All images have alt text
  • Format: WebP with JPEG/PNG fallback for older browsers

Pre-Implementation (Thor must verify):

  • Check astro.config.mjs has Sharp service configured
  • Verify sharp is in dependencies (not devDependencies)
  • Confirm sample images exist in public/images/posts/

Implementation Checklist:

Astro Configuration

  • Verify astro.config.mjs has image service:
    import { defineConfig } from 'astro/config';
    
    export default defineConfig({
      output: 'static',
      image: {
        service: {
          entrypoint: 'astro/assets/services/sharp',
        },
      },
    });
    
    • Verify: Sharp service is configured
    • Verify: No external image services

Pre-Build Optimization (Optional)

  • Create scripts/optimize-images.js for pre-processing (if needed):
    • Read originals from public/images/posts/
    • Resize to max 800px wide, maintain aspect ratio
    • Output WebP to public/images/previews/
    • Add to package.json scripts: "prebuild": "node scripts/optimize-images.js"
    • Note: Astro's <Image /> component handles most optimization automatically
    • Only add if: You need specific custom optimizations

Image Component Usage

  • In .astro components, use <Image /> from astro:assets:

    ---
    import { Image } from 'astro:assets';
    import myImage from '../assets/my-image.jpg';
    ---
    
    <Image 
      src={myImage} 
      alt="Description"
      width={800}
      height={450}
      loading="lazy"
    />
    
    • Critical: Must import image to get processed
    • Critical: Must specify width and height (prevents CLS)
    • Verify: Image component auto-generates WebP
    • Verify: loading="lazy" handled automatically
  • For public directory images:

    <Image 
      src="/images/posts/my-image.jpg"
      alt="Description"
      width={800}
      height={450}
      inferSize
    />
    
    • Note: Use inferSize for public images to auto-detect dimensions

Critical Images (Hero, Above Fold)

  • Use loading="eager" for hero images (above the fold):
    <Image 
      src={heroImage}
      alt="Hero"
      width={1920}
      height={1080}
      loading="eager"
      priority
    />
    
    • Verify: These images preload, not lazy loaded
    • Performance: Improves LCP (Largest Contentful Paint)

Remove Forbidden Patterns

  • Delete any JSDOM runtime image processing
  • Remove manual image src updates in <script> tags
  • No new Image() JavaScript objects for layout
  • Verify: All image handling is declarative in .astro templates

Review Checklist for Loki:

  • Build passes: pnpm build exits 0

  • Check dist/ directory: Images are WebP format

  • Check HTML: Images have width/height attributes (no CLS)

  • All images have alt text (accessibility)

  • Hero images use loading="eager"

  • No JSDOM or runtime image processing code

  • Bundle size check: Image optimization adds minimal JS

    • Output WebP to public/images/previews/
    • Run before build: add to prebuild script in package.json
  • In .astro components: use <Image /> from astro:assets

    • <Image src={...} alt={...} width={800} height={450} />
    • <Image /> auto-generates WebP, adds width/height (prevents CLS)
    • loading="lazy" is handled automatically by <Image />
    • No JSDOM needed — image src is updated at build time, not runtime
  • Critical images (hero slides): use loading="eager" to preload

  • Remove: JSDOM runtime image processing (replaced by Astro's build-time handling)


Phase 2: Content & Navigation (Critical)

7. File-Based Routing (src/pages/)

Priority: Critical | Status: Pending

  • Create src/pages/index.astro → routes to /

    • Import and use Layout.astro, Hero.astro, PostGrid.astro
    • Fetch posts at build time: const posts = await getCollection('blog')
  • Create src/pages/posts/[slug].astro → routes to /posts/[slug]

    • Export getStaticPaths() to generate all post pages at build time
    • Astro.params.slug for post lookup
  • Create src/pages/404.astro → routes to /404

    • Synthwave-styled error page
    • "Return to Homepage" link (<a href="/">)
  • Navigation between pages: standard <a href="/posts/my-post"> links

    • No useNavigate, no BrowserRouter, no route library
  • Remove: react-router-dom from dependencies entirely


8. Create Full Post Page (src/pages/posts/[slug].astro)

Priority: High | Status: Pending

  • Export getStaticPaths():

    export async function getStaticPaths() {
      const posts = await getCollection('blog');
      return posts.map(entry => ({ params: { slug: entry.slug }, props: { entry } }));
    }
    
  • Destructure const { entry } = Astro.props

  • Call const { Content, headings } = await entry.render()

  • Build post page layout

    • Reuse <Layout> component
    • Full-width content area, max-width 800px for readability
  • Implement post header

    • Title (larger font, centered)
    • Metadata bar (date, category, tags)
    • Featured image via <Image />
  • Render post body

    • Use <Content /> component — Markdown is pre-rendered, no manual HTML sanitization
    • Syntax highlighting automatic via Shiki
    • Style headings, tables, blockquotes via CSS in <style> block
  • Build navigation footer

    • Previous/Next post links (standard <a> tags)
    • Back to home <a href="/">
  • Optional: build TOC from headings array returned by entry.render()


9. Build 404 Error Page

Priority: Medium | Status: Pending

  • Create error page layout

    • Full viewport height
    • Centered content
    • Synthwave gradient background
  • Design error display

    • Large "404" text (8rem desktop, 4rem mobile)
    • Gradient text effect
    • Rotation animation (10deg, subtle pulse)
    • Error message text
    • Path display (if available)
  • Implement action buttons

    • "Return to Homepage" primary button
    • "Contact Us" secondary button (outline)
    • Navigation handlers
  • Add decorative elements

    • Synthwave card styling
    • Hover effects
    • Subtle animations

Phase 3: Content Management (Medium)

10. Build Post Grid with Category Filtering

Priority: Medium | Status: Pending

  • Create grid layout system

    • CSS Grid or Flexbox
    • Responsive columns (1 mobile, 2 tablet, 3 desktop)
    • Gap spacing (1.5rem)
    • Auto-rows for variable height cards
  • Implement category filtering

    • Filter state management
    • Category buttons/tags
    • Active filter highlighting
    • Clear filter option
  • Add sorting options

    • Date (newest first, default)
    • Title (alphabetical)
    • Category
  • Build pagination (optional)

    • Page size (9-12 posts)
    • Page navigation
    • "Load more" button alternative

Priority: Medium | Status: Pending

  • Create horizontal scroll container

    • Overflow-x: auto
    • Hide scrollbar (custom styling)
    • Snap scrolling (optional)
  • Design category cards

    • Icon or image for each category
    • Category name
    • Post count badge
    • Hover lift effect
  • Add navigation arrows

    • Left/right scroll buttons
    • Show/hide based on scroll position
    • Smooth scroll behavior

12. Integrate Subscription Form

Priority: Low | Status: Pending

  • Create form component

    • Email input field
    • Submit button
    • Validation
  • Style with synthwave theme

    • Purple accent on focus
    • Rounded inputs
    • Hover effects
  • Handle form submission

    • Client-side validation
    • Success message
    • Error handling
    • Integration with email service (optional)

Phase 4: Build & Deployment (Critical)

13. Configure Astro Build (astro.config.mjs)

Priority: Critical | Status: Pending

  • Set output: 'static' for pure static HTML output
  • Set compressHTML: true for HTML minification
  • Configure Shiki theme:
    markdown: { shikiConfig: { theme: 'dracula' } }
    
  • Set image service to sharp:
    image: { service: { entrypoint: 'astro/assets/services/sharp' } }
    
  • Set site: URL for canonical link generation
  • Verify build: pnpm builddist/ contains static HTML files
  • Check dist/ sizes: du -sh dist/assets/*
    • Total JS should be < 50KB (most pages: 0KB if no client:* directives used)
  • Remove: separate vite.config.ts (not needed — Astro wraps Vite internally)

14. Configure TypeScript Strict Mode

Priority: High | Status: Pending

  • Update tsconfig.json with strict settings:

    • strict: true
    • noImplicitAny: true
    • strictNullChecks: true
    • noUnusedLocals: true
    • noUnusedParameters: true
    • noImplicitReturns: true
    • noFallthroughCasesInSwitch: true
  • Set up path aliases in tsconfig.json (Astro reads this natively):

    • @/*./src/*
    • @components/*./src/components/*
    • @utils/*./src/utils/*
    • @styles/*./src/styles/*
    • @pages/*./src/pages/*
  • Create src/env.d.ts:

    • /// <reference types="astro/client" />
  • Remove: vite-env.d.ts (replaced by env.d.ts)

  • Remove: separate Vite resolve aliases (tsconfig paths work natively in Astro)

  • Run type checking: pnpm astro check instead of tsc --noEmit


15. Write Documentation

Priority: Medium | Status: Pending

  • Create README.md

    • Project description
    • Installation instructions
    • Development workflow
    • Build commands
    • Deployment guide
  • Write CHANGELOG.md

    • Version numbering (SemVer)
    • Feature list per version
    • Breaking changes documentation
  • Create CONTRIBUTING.md (optional)

    • Code style guidelines
    • PR process
    • Issue reporting

Phase 5: Testing & Polish (High)

16. Performance Testing and Optimization

Priority: High | Status: Pending

  • Build and preview: pnpm build && pnpm preview

  • Inspect dist/: confirm pre-rendered HTML files (not a JS bundle)

  • Check bundle size: du -sh dist/assets/*

    • Total JS < 50KB (pages with no client:* directives: 0KB JS)
  • Add a test post src/content/blog/test.md, confirm it appears at /posts/test

  • Syntax highlighting test: add a fenced code block, confirm colors render in build

  • Run Lighthouse audit against pnpm preview server

    • Performance score >90
    • Accessibility score >90
    • Best Practices >90
    • SEO score >90
  • Measure load times

    • First Contentful Paint < 50ms
    • Largest Contentful Paint < 1s
    • Cumulative Layout Shift < 0.1
  • Optimize critical resources

    • Inline critical CSS
    • Use loading="eager" on hero images (already preloaded)
    • Font loading optimization
    • Verify no client:* directives on non-interactive components

17. Cross-Browser Testing

Priority: Medium | Status: Pending

  • Test on Chrome

    • Latest version
    • Performance metrics
    • Feature parity
  • Test on Firefox

    • Latest version
    • CSS compatibility
    • Animation performance
  • Test on Safari

    • macOS version
    • iOS version (mobile)
    • Webkit-specific issues
  • Test on Edge

    • Chromium version
    • Windows compatibility

18. Accessibility Audit (WCAG 2.1 AA)

Priority: Medium | Status: Pending

  • Keyboard navigation

    • Tab order logical
    • Focus indicators visible
    • Skip links provided
  • Screen reader testing

    • Alt text for images
    • ARIA labels where needed
    • Heading structure (h1-h6)
    • Landmark regions
  • Color contrast

    • Text contrast ratio ≥4.5:1
    • Large text contrast ≥3:1
    • UI component contrast
  • Motion and animation

    • Respect prefers-reduced-motion
    • No auto-playing content without pause
    • Animation duration reasonable

Phase 6: Future Enhancements (Low Priority)

19. Optional: Docker Setup

Priority: Low | Status: Pending

  • Create Dockerfile

    • Multi-stage build
    • Node.js base image
    • pnpm installation
    • Build stage
    • Nginx production stage
  • Write docker-compose.yml

    • Volume mounting
    • Port mapping (80:80)
    • Environment variables
  • Create deployment scripts

    • Build script
    • Deploy script
    • Environment setup

Quick Reference

Color Palette

Use Case Hex Code Notes
Primary #6a1b9a Main purple
Primary Dark #510ca9 Hover states
Primary Light #935edb Highlights
Secondary #000080 Indie blue
Background #000 True black
Paper #121212 Slightly lighter
Text Primary #fff Headings
Text Secondary #eee Body text
Text Muted #888 Meta text
Text Tertiary #aaa Subtitles

Breakpoints

Name Width Target
Mobile < 768px Phones
Tablet 768px - 1024px Tablets
Desktop > 1024px Laptops/Desktops

Performance Budget

Metric Target
Load Time < 100ms
Bundle Size < 200KB gzipped
FCP < 50ms
LCP < 1s
TTI < 2s
CLS < 0.1

Last Updated: 2026-02-28

Next Review: After Phase 1 completion