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.tswith Astro client typespnpm buildpasses cleanly
Phase 1: Complete Synthwave Theme Implementation (src/styles/)
Priority: Critical | Status: Pending
STACK ENFORCEMENT (NON-NEGOTIABLE):
- Framework: Pure CSS in
.cssfiles - 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 buildexits 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
.astrocomponents 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.tsto understand data types - Read
src/styles/synthwave.cssto understand theme integration - Verify Astro version and capabilities
Implementation Checklist:
Layout.astro (Base Structure)
- Create base
Layout.astrostructure- 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.propsin 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.astrocomponent- 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.astrocomponent- 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
- Add
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.astrocomponent- 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
- Window resize event listener in
Review Checklist for Loki:
- Build passes:
pnpm buildexits 0 - Check for forbidden imports:
grep -r "from 'react'" src/components/returns nothing - Check for JSX: No
.tsxfiles 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
3. Implement Homepage Hero with Carousel (Hero.astro)
Priority: High | Status: Pending
STACK ENFORCEMENT (NON-NEGOTIABLE):
- Framework: Astro
.astrocomponent - 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.cssto 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.astrosection 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; ---
Carousel Structure
- 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 />fromastro:assetsfor 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
transformandopacityonly (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
Carousel Controls
- 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 buildexits 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
.astrocomponent - 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.tsto understand BlogPost type - Read
src/styles/synthwave.cssfor color/variable reference - Check sample post data exists in
src/content/blog/
Implementation Checklist:
Component Structure
- Design
PostCard.astrowith proper typing- Create Props interface extending Content Collection entry
- Props via
const { post } = Astro.propswith 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
:hoveronly, 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 />fromastro: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" />
- Use
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
- Standard anchor tag:
Review Checklist for Loki:
- Build passes:
pnpm buildexits 0 - Component file ends with
.astro, not.tsx - No React imports or hooks
- Uses
astro:assetsImage 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.tsalready 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.tsexists 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...
- Location:
Post Page Implementation ([slug].astro)
-
Create
src/pages/posts/[slug].astrowith 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.slugmatches filename
- Critical: Must use
-
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>
- Use
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
- Target Shiki output classes (
-
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
- Check package.json for
Review Checklist for Loki:
- Build passes:
pnpm buildexits 0 - TypeScript check passes:
pnpm astro checkexits 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.mjshas Sharp service configured - Verify
sharpis in dependencies (not devDependencies) - Confirm sample images exist in
public/images/posts/
Implementation Checklist:
Astro Configuration
- Verify
astro.config.mjshas 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.jsfor 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.jsonscripts:"prebuild": "node scripts/optimize-images.js" - Note: Astro's
<Image />component handles most optimization automatically - Only add if: You need specific custom optimizations
- Read originals from
Image Component Usage
-
In
.astrocomponents, use<Image />fromastro: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
inferSizefor public images to auto-detect dimensions
- Note: Use
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
.astrotemplates
Review Checklist for Loki:
-
Build passes:
pnpm buildexits 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
prebuildscript inpackage.json
- Output WebP to
-
In
.astrocomponents: use<Image />fromastro: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')
- Import and use
-
Create
src/pages/posts/[slug].astro→ routes to/posts/[slug]- Export
getStaticPaths()to generate all post pages at build time Astro.params.slugfor post lookup
- Export
-
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, noBrowserRouter, no route library
- No
-
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
- Reuse
-
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
- Use
-
Build navigation footer
- Previous/Next post links (standard
<a>tags) - Back to home
<a href="/">
- Previous/Next post links (standard
-
Optional: build TOC from
headingsarray returned byentry.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
11. Implement Category Carousel
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: truefor 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 build→dist/contains static HTML files - Check
dist/sizes:du -sh dist/assets/*- Total JS should be < 50KB (most pages: 0KB if no
client:*directives used)
- Total JS should be < 50KB (most pages: 0KB if no
- Remove: separate
vite.config.ts(not needed — Astro wraps Vite internally)
14. Configure TypeScript Strict Mode
Priority: High | Status: Pending
-
Update
tsconfig.jsonwith strict settings:strict: truenoImplicitAny: truestrictNullChecks: truenoUnusedLocals: truenoUnusedParameters: truenoImplicitReturns: truenoFallthroughCasesInSwitch: 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 byenv.d.ts) -
Remove: separate Vite resolve aliases (tsconfig paths work natively in Astro)
-
Run type checking:
pnpm astro checkinstead oftsc --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)
- Total JS < 50KB (pages with no
-
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 previewserver- 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