the-grid-cc 1.5.0 → 1.7.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,180 +0,0 @@
1
- ---
2
- cluster: james-weatherhead-blog
3
- block: 01
4
- type: execute
5
- wave: 1
6
- depends_on: []
7
- files_modified: [package.json, astro.config.mjs, tsconfig.json, .gitignore, tailwind.config.mjs, vercel.json]
8
- autonomous: true
9
-
10
- must_haves:
11
- truths:
12
- - "Project runs locally with npm run dev"
13
- - "Tailwind CSS styles are processed correctly"
14
- - "Vercel adapter is configured for deployment"
15
- artifacts:
16
- - path: "package.json"
17
- provides: "Project dependencies and scripts"
18
- min_lines: 20
19
- - path: "astro.config.mjs"
20
- provides: "Astro configuration with Vercel adapter and Tailwind"
21
- exports: ["default"]
22
- - path: "tailwind.config.mjs"
23
- provides: "Tailwind configuration with dark mode"
24
- exports: ["default"]
25
- key_links:
26
- - from: "astro.config.mjs"
27
- to: "@astrojs/vercel/serverless"
28
- via: "adapter import"
29
- pattern: "import.*@astrojs/vercel"
30
- - from: "astro.config.mjs"
31
- to: "@astrojs/tailwind"
32
- via: "integration"
33
- pattern: "tailwind\\(\\)"
34
- ---
35
-
36
- <objective>
37
- Initialize Astro project with Tailwind CSS and Vercel deployment configuration.
38
-
39
- Purpose: Establish the foundational project structure with all necessary dependencies and configuration for a modern, deployable blog.
40
- Output: Fully configured Astro project ready for local development and Vercel deployment.
41
- </objective>
42
-
43
- <context>
44
- This is a greenfield blog project for James Weatherhead. Requirements specify:
45
- - Astro framework (latest version)
46
- - Tailwind CSS for styling
47
- - Dark mode support
48
- - Vercel hosting
49
- - Minimal design aesthetic
50
-
51
- This block establishes the technical foundation. No prior work exists. Subsequent blocks will build the layout system, content structure, and features on top of this base.
52
- </context>
53
-
54
- <threads>
55
-
56
- <thread type="auto">
57
- <name>Thread 1: Initialize Astro project with dependencies</name>
58
- <files>package.json, astro.config.mjs, tsconfig.json, .gitignore</files>
59
- <action>
60
- Create new Astro project from scratch in /Users/jacweath/grid/blog directory:
61
-
62
- 1. Run: npm create astro@latest blog -- --template minimal --no-install --no-git --typescript strict
63
- 2. cd blog && npm install
64
- 3. Add Tailwind: npx astro add tailwind --yes
65
- 4. Add Vercel adapter: npx astro add vercel --yes
66
- 5. Add RSS integration: npm install @astrojs/rss
67
- 6. Add syntax highlighting: npm install @astrojs/shiki
68
-
69
- Configure astro.config.mjs:
70
- - Import vercel adapter
71
- - Import tailwind integration
72
- - Set site URL: https://jamesweatherhead.com (placeholder)
73
- - Enable markdown code highlighting with shiki
74
-
75
- Update package.json scripts:
76
- - "dev": "astro dev"
77
- - "build": "astro check && astro build"
78
- - "preview": "astro preview"
79
- - "astro": "astro"
80
-
81
- AVOID: Do not use SSR features unless needed (keep it static for performance). Do not add unnecessary dependencies (keep bundle small per minimal design requirement).
82
- </action>
83
- <verify>
84
- Run: cd /Users/jacweath/grid/blog && npm run dev
85
- Check: Server starts on localhost:4321 without errors
86
- Check: npm run build completes successfully
87
- </verify>
88
- <done>
89
- - package.json exists with all required dependencies (astro, @astrojs/vercel, @astrojs/tailwind, @astrojs/rss, @astrojs/shiki)
90
- - astro.config.mjs exports valid configuration with vercel adapter and tailwind integration
91
- - npm run dev starts server without errors
92
- - npm run build completes successfully
93
- </done>
94
- </thread>
95
-
96
- <thread type="auto">
97
- <name>Thread 2: Configure Tailwind with dark mode</name>
98
- <files>tailwind.config.mjs</files>
99
- <action>
100
- Configure Tailwind for dark mode and minimal design aesthetic:
101
-
102
- 1. Set darkMode: 'class' (allow manual toggle, not media query)
103
- 2. Extend theme with custom colors:
104
- - Background colors: bg-gray-50 (light), bg-gray-900 (dark)
105
- - Text colors: text-gray-900 (light), text-gray-100 (dark)
106
- - Accent color: text-blue-600 (light), text-blue-400 (dark)
107
- 3. Configure content paths: ['./src/**/*.{astro,html,js,jsx,md,mdx,svelte,ts,tsx,vue}']
108
- 4. Add typography plugin if needed for markdown styling: npm install -D @tailwindcss/typography
109
-
110
- AVOID: Do not add excessive color variants (keep minimal). Do not use CSS-in-JS patterns (use Tailwind utilities). WHY: Requirements specify "minimal design" - extra variants add complexity and bundle size.
111
- </action>
112
- <verify>
113
- Check: tailwind.config.mjs exports config with darkMode: 'class'
114
- Check: Content paths include all Astro file types
115
- Run: npm run build to ensure Tailwind processes correctly
116
- </verify>
117
- <done>
118
- - tailwind.config.mjs has darkMode: 'class' configured
119
- - Custom theme colors defined for dark/light modes
120
- - @tailwindcss/typography plugin installed and configured
121
- - Build completes with Tailwind processing styles
122
- </done>
123
- </thread>
124
-
125
- <thread type="auto">
126
- <name>Thread 3: Add Vercel deployment configuration</name>
127
- <files>vercel.json</files>
128
- <action>
129
- Create vercel.json for deployment configuration:
130
-
131
- 1. Create vercel.json in project root
132
- 2. Configure build settings:
133
- {
134
- "buildCommand": "npm run build",
135
- "devCommand": "npm run dev",
136
- "installCommand": "npm install",
137
- "framework": "astro",
138
- "outputDirectory": "dist"
139
- }
140
- 3. Ensure .gitignore includes:
141
- - node_modules/
142
- - dist/
143
- - .vercel/
144
- - .astro/
145
-
146
- AVOID: Do not add environment variables yet (none needed for static blog). Do not add redirects/rewrites yet (add when needed). WHY: Keep configuration minimal until features require it.
147
- </action>
148
- <verify>
149
- Check: vercel.json exists with correct build configuration
150
- Check: .gitignore includes all build artifacts
151
- Run: npm run build && ls dist/ to verify output directory
152
- </verify>
153
- <done>
154
- - vercel.json exists with framework set to "astro"
155
- - Build command and output directory configured correctly
156
- - .gitignore excludes all build artifacts and dependencies
157
- - dist/ directory created successfully after build
158
- </done>
159
- </thread>
160
-
161
- </threads>
162
-
163
- <verification>
164
- Run the following to verify block completion:
165
- 1. cd /Users/jacweath/grid/blog
166
- 2. npm run dev (server starts on port 4321)
167
- 3. npm run build (completes without errors)
168
- 4. ls dist/ (contains built files)
169
- 5. Check astro.config.mjs imports vercel adapter and tailwind
170
- 6. Check tailwind.config.mjs has darkMode: 'class'
171
- 7. Check vercel.json exists with correct framework setting
172
- </verification>
173
-
174
- <success_criteria>
175
- - Project initializes and runs locally at localhost:4321
176
- - Tailwind CSS processes styles correctly
177
- - Build completes successfully with Vercel adapter
178
- - All configuration files present and valid
179
- - Ready for layout development in next block
180
- </success_criteria>
@@ -1,229 +0,0 @@
1
- ---
2
- cluster: james-weatherhead-blog
3
- block: 02
4
- type: execute
5
- wave: 2
6
- depends_on: [01]
7
- files_modified: [src/layouts/BaseLayout.astro, src/components/Header.astro, src/components/Footer.astro, src/components/DarkModeToggle.astro, src/styles/global.css]
8
- autonomous: false
9
-
10
- must_haves:
11
- truths:
12
- - "Dark mode toggles between light and dark themes"
13
- - "Navigation links are visible and functional"
14
- - "Layout is responsive on mobile and desktop"
15
- artifacts:
16
- - path: "src/layouts/BaseLayout.astro"
17
- provides: "Base HTML structure with dark mode support"
18
- min_lines: 40
19
- - path: "src/components/Header.astro"
20
- provides: "Site navigation with logo/title and links"
21
- min_lines: 20
22
- - path: "src/components/DarkModeToggle.astro"
23
- provides: "Interactive dark mode toggle button"
24
- min_lines: 30
25
- key_links:
26
- - from: "DarkModeToggle.astro"
27
- to: "document.documentElement"
28
- via: "classList.toggle('dark')"
29
- pattern: "classList\\.toggle\\('dark'\\)"
30
- - from: "BaseLayout.astro"
31
- to: "localStorage"
32
- via: "theme persistence script"
33
- pattern: "localStorage\\.getItem\\('theme'\\)"
34
- ---
35
-
36
- <objective>
37
- Build the layout system with base layout, header, footer, and dark mode functionality.
38
-
39
- Purpose: Create reusable layout components that provide consistent structure, navigation, and theming across all pages.
40
- Output: Responsive layout with working dark mode toggle, navigation header, and footer.
41
- </objective>
42
-
43
- <context>
44
- Block 01 completed: Astro project initialized with Tailwind (darkMode: 'class') and Vercel adapter.
45
-
46
- This block builds the visual foundation. The layout system must:
47
- - Support dark mode toggle (class-based, not media query)
48
- - Be minimal and clean (per requirements)
49
- - Work on mobile and desktop
50
- - Include header with site title and nav links
51
- - Include footer with copyright/contact info
52
-
53
- No blog content yet - that comes in Block 03. This focuses purely on structure and theming.
54
- </context>
55
-
56
- <threads>
57
-
58
- <thread type="auto">
59
- <name>Thread 1: Create base layout with dark mode persistence</name>
60
- <files>src/layouts/BaseLayout.astro, src/styles/global.css</files>
61
- <action>
62
- Create BaseLayout.astro as the foundational layout component:
63
-
64
- 1. Create src/layouts/BaseLayout.astro with props interface:
65
- - title: string
66
- - description?: string
67
- - ogImage?: string
68
-
69
- 2. Structure:
70
- - HTML doctype and head with meta tags (viewport, charset, description)
71
- - SEO meta tags (og:title, og:description, twitter:card)
72
- - Link to global.css
73
- - Inline script in head (before body renders) to prevent flash:
74
- ```js
75
- const theme = localStorage.getItem('theme') || 'dark'; // default dark per minimal aesthetic
76
- if (theme === 'dark') document.documentElement.classList.add('dark');
77
- ```
78
- - Body with dark:bg-gray-900 bg-gray-50 dark:text-gray-100 text-gray-900
79
- - Slot for page content
80
-
81
- 3. Create src/styles/global.css:
82
- - @tailwind base/components/utilities
83
- - Custom font stack: system-ui, -apple-system, sans-serif
84
- - Smooth scroll behavior
85
- - Focus styles for accessibility
86
-
87
- AVOID: Do not use media query dark mode (requirements specify toggle, not auto). Do not add analytics scripts yet (keep minimal). WHY: User wants control over theme, not automatic switching based on system preference.
88
- </action>
89
- <verify>
90
- Check: src/layouts/BaseLayout.astro exists with inline theme script
91
- Check: localStorage persistence script runs before body render
92
- Check: global.css imports Tailwind directives
93
- Run: grep -r "localStorage.getItem" src/layouts/BaseLayout.astro
94
- </verify>
95
- <done>
96
- - BaseLayout.astro exports layout with title, description props
97
- - Inline script prevents FOUC (flash of unstyled content)
98
- - Dark mode classes applied to html element
99
- - global.css configures Tailwind and typography
100
- </done>
101
- </thread>
102
-
103
- <thread type="auto">
104
- <name>Thread 2: Build Header and Footer components</name>
105
- <files>src/components/Header.astro, src/components/Footer.astro</files>
106
- <action>
107
- Create navigation header and footer components:
108
-
109
- Header.astro:
110
- 1. Create header element with container max-w-3xl mx-auto px-4 py-8
111
- 2. Site title "James Weatherhead" as h1 or logo
112
- 3. Navigation links: Home (/) | Blog (/blog) | About (/about)
113
- 4. Include DarkModeToggle component (will create in next thread)
114
- 5. Make responsive: stack on mobile, horizontal on desktop (md:flex)
115
- 6. Style links with hover:text-blue-600 dark:hover:text-blue-400
116
-
117
- Footer.astro:
118
- 1. Create footer element with border-t border-gray-200 dark:border-gray-800
119
- 2. Container max-w-3xl mx-auto px-4 py-8
120
- 3. Copyright text: © 2024 James Weatherhead
121
- 4. Optional: Contact links or social media (GitHub, Twitter) if provided
122
- 5. Small text size: text-sm text-gray-600 dark:text-gray-400
123
-
124
- AVOID: Do not add complex navigation menus (keep minimal - 3 links max). Do not add social media icons unless assets provided. WHY: Requirements specify "minimal design" - extra navigation adds visual clutter.
125
- </action>
126
- <verify>
127
- Check: src/components/Header.astro exists with nav links
128
- Check: src/components/Footer.astro exists with copyright
129
- Check: Both use max-w-3xl for content width consistency
130
- Run: grep -r "max-w-3xl" src/components/
131
- </verify>
132
- <done>
133
- - Header.astro contains site title and 3 navigation links
134
- - Footer.astro contains copyright and minimal info
135
- - Both components use consistent container width (max-w-3xl)
136
- - Responsive styles applied with Tailwind breakpoints
137
- </done>
138
- </thread>
139
-
140
- <thread type="auto">
141
- <name>Thread 3: Implement dark mode toggle component</name>
142
- <files>src/components/DarkModeToggle.astro</files>
143
- <action>
144
- Create interactive dark mode toggle button:
145
-
146
- 1. Create DarkModeToggle.astro with client:load directive (needs JS)
147
- 2. Button element with aria-label="Toggle dark mode" for accessibility
148
- 3. Icon: Use Unicode characters (☀️ sun / 🌙 moon) or SVG for sun/moon icons
149
- 4. Client-side script:
150
- ```js
151
- const toggle = document.querySelector('#dark-mode-toggle');
152
- toggle.addEventListener('click', () => {
153
- const isDark = document.documentElement.classList.toggle('dark');
154
- localStorage.setItem('theme', isDark ? 'dark' : 'light');
155
- });
156
- ```
157
- 5. Style: rounded-full p-2 hover:bg-gray-200 dark:hover:bg-gray-800 transition
158
- 6. Position in Header component (top-right corner)
159
-
160
- AVOID: Do not use React or Vue (keep Astro-native for simplicity). Do not add animations beyond simple transition. WHY: Requirements don't specify framework components, and excessive animations conflict with minimal aesthetic.
161
- </action>
162
- <verify>
163
- Check: DarkModeToggle.astro exists with client:load directive
164
- Check: Toggle button has click handler that updates localStorage
165
- Check: classList.toggle('dark') targets documentElement
166
- Run: grep -r "client:load" src/components/DarkModeToggle.astro
167
- </verify>
168
- <done>
169
- - DarkModeToggle.astro component created with interactive button
170
- - Click handler toggles 'dark' class on html element
171
- - Theme preference persists in localStorage
172
- - Accessible with aria-label
173
- </done>
174
- </thread>
175
-
176
- <thread type="checkpoint:human-verify" gate="blocking">
177
- <what-built>
178
- Complete layout system with:
179
- - BaseLayout.astro (theme persistence, no FOUC)
180
- - Header.astro (navigation: Home, Blog, About)
181
- - Footer.astro (copyright, minimal info)
182
- - DarkModeToggle.astro (interactive toggle with localStorage)
183
- - global.css (Tailwind config, typography)
184
- </what-built>
185
- <how-to-verify>
186
- 1. cd /Users/jacweath/grid/blog && npm run dev
187
- 2. Create test page at src/pages/index.astro using BaseLayout
188
- 3. Visit http://localhost:4321
189
- 4. Check:
190
- - Header appears with "James Weatherhead" title and nav links
191
- - Footer appears with copyright
192
- - Dark mode toggle button visible (sun/moon icon)
193
- 5. Click dark mode toggle:
194
- - Background switches from light to dark (or vice versa)
195
- - Text color changes appropriately
196
- - Refresh page - theme persists
197
- 6. Test responsive:
198
- - Resize browser to mobile width
199
- - Header should stack vertically or remain readable
200
- 7. Check browser console for errors (should be none)
201
- </how-to-verify>
202
- <resume-signal>Type "approved" if layout and dark mode work correctly, or describe any issues (e.g., "toggle not working", "colors wrong")</resume-signal>
203
- </thread>
204
-
205
- </threads>
206
-
207
- <verification>
208
- Complete verification checklist:
209
- 1. BaseLayout.astro exists with theme persistence script
210
- 2. Header.astro has navigation links (/, /blog, /about)
211
- 3. Footer.astro has copyright text
212
- 4. DarkModeToggle.astro has client:load and click handler
213
- 5. global.css imports Tailwind directives
214
- 6. Dark mode toggle switches theme without page reload
215
- 7. Theme persists across page refresh (localStorage)
216
- 8. Layout is responsive on mobile and desktop
217
- 9. No FOUC (flash of unstyled content) on page load
218
- 10. Browser console has no errors
219
- </verification>
220
-
221
- <success_criteria>
222
- - Layout system renders correctly in browser
223
- - Dark mode toggle switches between light and dark themes
224
- - Theme preference persists in localStorage
225
- - Navigation links are visible and clickable
226
- - Responsive on mobile and desktop
227
- - No console errors
228
- - User approves visual appearance and functionality
229
- </success_criteria>
@@ -1,253 +0,0 @@
1
- ---
2
- cluster: james-weatherhead-blog
3
- block: 03
4
- type: execute
5
- wave: 2
6
- depends_on: [01]
7
- files_modified: [src/content/config.ts, src/content/blog/sample-post.md, src/pages/blog/[...slug].astro, src/components/PostList.astro, src/components/Tag.astro]
8
- autonomous: false
9
-
10
- must_haves:
11
- truths:
12
- - "Blog posts are defined as content collection with schema"
13
- - "Individual blog posts render with frontmatter data"
14
- - "Tags are extracted and displayed for each post"
15
- artifacts:
16
- - path: "src/content/config.ts"
17
- provides: "Content collection schema for blog posts"
18
- exports: ["collections"]
19
- - path: "src/pages/blog/[...slug].astro"
20
- provides: "Dynamic blog post page template"
21
- min_lines: 50
22
- - path: "src/components/PostList.astro"
23
- provides: "Reusable component for listing blog posts"
24
- min_lines: 30
25
- key_links:
26
- - from: "src/pages/blog/[...slug].astro"
27
- to: "getCollection('blog')"
28
- via: "Astro content collections API"
29
- pattern: "getCollection\\('blog'\\)"
30
- - from: "src/content/config.ts"
31
- to: "zod schema"
32
- via: "defineCollection"
33
- pattern: "defineCollection"
34
- ---
35
-
36
- <objective>
37
- Implement blog content structure using Astro Content Collections with markdown posts, frontmatter validation, and tag support.
38
-
39
- Purpose: Create the core blog functionality - content schema, post rendering, and listing capabilities.
40
- Output: Content collection configured, sample post created, dynamic post template working.
41
- </objective>
42
-
43
- <context>
44
- Block 01 completed: Astro project initialized with Tailwind and Vercel adapter.
45
- Block 02 in progress: Layout system (runs parallel with this block).
46
-
47
- This block focuses on the content layer using Astro's Content Collections API. Requirements specify:
48
- - Markdown-based posts
49
- - Tags for organization
50
- - Syntax highlighting (shiki installed in Block 01)
51
-
52
- Content Collections provide type-safe frontmatter, automatic routing, and built-in markdown processing. This is the canonical Astro approach for blog content.
53
-
54
- Block 02 (layouts) and Block 03 (content) can run in parallel since they modify different files with no overlap.
55
- </context>
56
-
57
- <threads>
58
-
59
- <thread type="auto">
60
- <name>Thread 1: Configure content collection schema</name>
61
- <files>src/content/config.ts, src/content/blog/sample-post.md</files>
62
- <action>
63
- Set up Astro Content Collections for blog posts:
64
-
65
- 1. Create src/content/config.ts with zod schema:
66
- ```ts
67
- import { defineCollection, z } from 'astro:content';
68
-
69
- const blog = defineCollection({
70
- type: 'content',
71
- schema: z.object({
72
- title: z.string(),
73
- description: z.string(),
74
- pubDate: z.coerce.date(),
75
- updatedDate: z.coerce.date().optional(),
76
- tags: z.array(z.string()).default([]),
77
- draft: z.boolean().default(false),
78
- }),
79
- });
80
-
81
- export const collections = { blog };
82
- ```
83
-
84
- 2. Create src/content/blog/ directory
85
-
86
- 3. Create sample post: src/content/blog/sample-post.md
87
- - Frontmatter with all required fields (title, description, pubDate, tags)
88
- - Markdown content with headings, paragraphs, code blocks
89
- - Use tags: ["javascript", "astro", "web-development"]
90
- - Include code block to test syntax highlighting
91
-
92
- AVOID: Do not add complex media fields yet (images come later if needed). Do not add author field unless multi-author (single author blog). WHY: Keep schema minimal - only add fields when content requires them.
93
- </action>
94
- <verify>
95
- Run: npm run build (should succeed with no schema errors)
96
- Check: src/content/config.ts exports 'collections' with 'blog'
97
- Check: sample-post.md exists with valid frontmatter
98
- Run: npx astro check (validates content schema)
99
- </verify>
100
- <done>
101
- - src/content/config.ts defines blog collection with zod schema
102
- - Schema includes: title, description, pubDate, updatedDate, tags, draft
103
- - sample-post.md created with valid frontmatter
104
- - Build completes without content validation errors
105
- </done>
106
- </thread>
107
-
108
- <thread type="auto">
109
- <name>Thread 2: Create dynamic blog post template</name>
110
- <files>src/pages/blog/[...slug].astro</files>
111
- <action>
112
- Create dynamic route for individual blog posts:
113
-
114
- 1. Create src/pages/blog/[...slug].astro
115
-
116
- 2. Implement getStaticPaths():
117
- ```ts
118
- import { getCollection } from 'astro:content';
119
- export async function getStaticPaths() {
120
- const posts = await getCollection('blog', ({ data }) => !data.draft);
121
- return posts.map(post => ({
122
- params: { slug: post.slug },
123
- props: post,
124
- }));
125
- }
126
- ```
127
-
128
- 3. Destructure props: const { data, render } = Astro.props;
129
- 4. Render post with BaseLayout:
130
- - Pass title and description to layout
131
- - Render metadata: title, date, tags
132
- - Render content: const { Content } = await render();
133
- - Style with Tailwind typography: prose dark:prose-invert max-w-3xl
134
-
135
- 5. Date formatting: use Intl.DateTimeFormat or date-fns
136
- 6. Tags: render as badges with Tag component (create in next thread)
137
-
138
- AVOID: Do not add comments (requirements say "none"). Do not add related posts sidebar (keep minimal). WHY: Feature requirements explicitly exclude comments; related posts adds complexity without requirement.
139
- </action>
140
- <verify>
141
- Run: npm run dev
142
- Visit: http://localhost:4321/blog/sample-post
143
- Check: Post renders with title, date, tags, and content
144
- Check: Code blocks have syntax highlighting
145
- Check: Prose typography applied correctly
146
- </verify>
147
- <done>
148
- - [slug].astro implements getStaticPaths with getCollection
149
- - Filters out draft posts (data.draft === false)
150
- - Renders post content with proper typography
151
- - Displays frontmatter data (title, date, tags)
152
- - Syntax highlighting works in code blocks
153
- </done>
154
- </thread>
155
-
156
- <thread type="auto">
157
- <name>Thread 3: Build post list and tag components</name>
158
- <files>src/components/PostList.astro, src/components/Tag.astro</files>
159
- <action>
160
- Create reusable components for displaying posts and tags:
161
-
162
- PostList.astro:
163
- 1. Props interface: posts (array of blog collection entries)
164
- 2. Map over posts and display:
165
- - Title (link to /blog/{slug})
166
- - Description
167
- - Date (formatted)
168
- - Tags (using Tag component)
169
- 3. Sort by pubDate descending (newest first)
170
- 4. Style: space-y-8 for vertical spacing, hover states on titles
171
- 5. No pagination yet (add later if needed)
172
-
173
- Tag.astro:
174
- 1. Props: tag (string), variant?: 'link' | 'badge'
175
- 2. If variant === 'link': render as link to /blog/tags/{tag}
176
- 3. If variant === 'badge': render as span with badge styles
177
- 4. Style: rounded-full px-3 py-1 text-sm bg-gray-200 dark:bg-gray-800
178
-
179
- AVOID: Do not add filter/search UI (add later if needed). Do not add pagination yet (YAGNI - wait until many posts exist). WHY: Premature optimization - start simple, add features when content volume requires it.
180
- </action>
181
- <verify>
182
- Check: PostList.astro accepts posts prop and maps over entries
183
- Check: Tag.astro handles both 'link' and 'badge' variants
184
- Check: Tags are clickable links (variant='link') or static badges
185
- Run: grep -r "variant=" src/components/Tag.astro
186
- </verify>
187
- <done>
188
- - PostList.astro displays posts with title, description, date, tags
189
- - Posts sorted by date descending (newest first)
190
- - Tag.astro renders tags as links or badges based on variant prop
191
- - Hover states applied to post titles
192
- </done>
193
- </thread>
194
-
195
- <thread type="checkpoint:human-verify" gate="blocking">
196
- <what-built>
197
- Complete blog content system with:
198
- - Content collection schema (src/content/config.ts)
199
- - Sample blog post (src/content/blog/sample-post.md)
200
- - Dynamic post template ([slug].astro)
201
- - PostList component (reusable post listing)
202
- - Tag component (link and badge variants)
203
- </what-built>
204
- <how-to-verify>
205
- 1. cd /Users/jacweath/grid/blog && npm run dev
206
- 2. Visit http://localhost:4321/blog/sample-post
207
- 3. Check post page:
208
- - Title displays correctly
209
- - Date shows formatted (e.g., "January 23, 2024")
210
- - Tags appear as badges or links
211
- - Markdown content renders properly
212
- - Code blocks have syntax highlighting (colors visible)
213
- - Dark mode: check prose-invert class applies (text readable on dark bg)
214
- 4. Check browser console for errors (should be none)
215
- 5. Run: npm run build
216
- - Build should complete successfully
217
- - Check: npx astro check (no content schema errors)
218
- 6. Create test listing page:
219
- - Add src/pages/blog/index.astro using PostList component
220
- - Visit http://localhost:4321/blog
221
- - Sample post appears in list
222
- </how-to-verify>
223
- <resume-signal>Type "approved" if content renders correctly and schema validates, or describe issues (e.g., "highlighting broken", "schema error", "tags not visible")</resume-signal>
224
- </thread>
225
-
226
- </threads>
227
-
228
- <verification>
229
- Complete verification checklist:
230
- 1. src/content/config.ts defines blog collection with zod schema
231
- 2. Schema includes all required fields (title, description, pubDate, tags, draft)
232
- 3. src/content/blog/sample-post.md exists with valid frontmatter
233
- 4. src/pages/blog/[slug].astro implements getStaticPaths correctly
234
- 5. Dynamic route filters out draft posts
235
- 6. Post template renders content with prose typography
236
- 7. Syntax highlighting works in code blocks
237
- 8. PostList.astro sorts posts by date (newest first)
238
- 9. Tag.astro supports 'link' and 'badge' variants
239
- 10. npm run build completes successfully
240
- 11. npx astro check passes with no errors
241
- 12. User approves content rendering and functionality
242
- </verification>
243
-
244
- <success_criteria>
245
- - Content collection configured with type-safe schema
246
- - Sample blog post renders at /blog/sample-post
247
- - Frontmatter data displays correctly (title, date, tags)
248
- - Markdown content styled with typography plugin
249
- - Syntax highlighting functional
250
- - PostList and Tag components work correctly
251
- - Build succeeds with no content validation errors
252
- - User approves rendering and functionality
253
- </success_criteria>