the-grid-cc 1.4.0 → 1.6.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,287 +0,0 @@
1
- ---
2
- cluster: james-weatherhead-blog
3
- block: 04
4
- type: execute
5
- wave: 3
6
- depends_on: [02, 03]
7
- files_modified: [src/pages/index.astro, src/pages/blog/index.astro, src/pages/about.astro, src/pages/blog/tags/[tag].astro]
8
- autonomous: false
9
-
10
- must_haves:
11
- truths:
12
- - "Homepage displays recent blog posts"
13
- - "Blog index page lists all posts"
14
- - "About page contains author information"
15
- - "Tag pages filter posts by tag"
16
- artifacts:
17
- - path: "src/pages/index.astro"
18
- provides: "Homepage with recent posts"
19
- min_lines: 30
20
- - path: "src/pages/blog/index.astro"
21
- provides: "Complete blog post listing"
22
- min_lines: 25
23
- - path: "src/pages/about.astro"
24
- provides: "About page with author info"
25
- min_lines: 20
26
- - path: "src/pages/blog/tags/[tag].astro"
27
- provides: "Tag-filtered post listing"
28
- min_lines: 40
29
- key_links:
30
- - from: "index.astro"
31
- to: "getCollection('blog')"
32
- via: "fetch recent posts"
33
- pattern: "getCollection\\('blog'\\)"
34
- - from: "[tag].astro"
35
- to: "posts.filter"
36
- via: "tag filtering"
37
- pattern: "\\.filter.*tags\\.includes"
38
- ---
39
-
40
- <objective>
41
- Create static pages (homepage, blog index, about) and tag-based filtering functionality.
42
-
43
- Purpose: Connect layout system (Block 02) and content system (Block 03) into navigable pages with tag-based organization.
44
- Output: Complete page structure with homepage, blog listing, about page, and tag filtering.
45
- </objective>
46
-
47
- <context>
48
- Dependencies completed:
49
- - Block 02: Layout system (BaseLayout, Header, Footer, DarkModeToggle)
50
- - Block 03: Content system (blog collection, post template, PostList component)
51
-
52
- This block brings everything together into actual pages users will visit. Navigation links from Header (Home, Blog, About) now have destinations. Tag filtering enables content organization without complex search.
53
-
54
- This is where the blog becomes navigable and complete. After this block, users can:
55
- - Land on homepage and see recent posts
56
- - Browse all posts at /blog
57
- - Read about the author at /about
58
- - Filter posts by tag at /blog/tags/{tag}
59
- </context>
60
-
61
- <threads>
62
-
63
- <thread type="auto">
64
- <name>Thread 1: Build homepage and blog index</name>
65
- <files>src/pages/index.astro, src/pages/blog/index.astro</files>
66
- <action>
67
- Create homepage and blog listing pages:
68
-
69
- index.astro (Homepage):
70
- 1. Import BaseLayout, PostList, getCollection
71
- 2. Fetch recent posts:
72
- ```ts
73
- const allPosts = await getCollection('blog', ({ data }) => !data.draft);
74
- const recentPosts = allPosts
75
- .sort((a, b) => b.data.pubDate.valueOf() - a.data.pubDate.valueOf())
76
- .slice(0, 5); // Show 5 most recent
77
- ```
78
- 3. Hero section:
79
- - Site title: "James Weatherhead"
80
- - Subtitle/tagline (e.g., "Software Engineer & Technical Writer")
81
- - Brief intro paragraph (1-2 sentences)
82
- 4. Recent posts section:
83
- - Heading: "Recent Posts"
84
- - Use PostList component with recentPosts
85
- - Link to /blog: "View all posts →"
86
- 5. Minimal design: max-w-3xl container, generous whitespace
87
-
88
- blog/index.astro (Blog Index):
89
- 1. Import BaseLayout, PostList, getCollection
90
- 2. Fetch all posts (sorted by date descending)
91
- 3. Page title: "Blog"
92
- 4. Optional: display tag cloud (all unique tags)
93
- 5. Use PostList component with all posts
94
- 6. Style consistently with homepage
95
-
96
- AVOID: Do not add complex hero animations (keep minimal). Do not add featured posts section yet (YAGNI). WHY: Requirements specify "minimal design" - focus on content, not embellishments.
97
- </action>
98
- <verify>
99
- Run: npm run dev
100
- Visit: http://localhost:4321 (homepage)
101
- Check: Recent posts appear (up to 5)
102
- Visit: http://localhost:4321/blog (blog index)
103
- Check: All posts appear in list
104
- Check: Both pages use BaseLayout with header/footer
105
- </verify>
106
- <done>
107
- - index.astro displays hero section and 5 recent posts
108
- - blog/index.astro lists all non-draft posts
109
- - Both pages use consistent styling (max-w-3xl, Tailwind)
110
- - "View all posts" link navigates to /blog
111
- - Posts sorted by date descending
112
- </done>
113
- </thread>
114
-
115
- <thread type="auto">
116
- <name>Thread 2: Create About page</name>
117
- <files>src/pages/about.astro</files>
118
- <action>
119
- Create About page with author information:
120
-
121
- 1. Create src/pages/about.astro with BaseLayout
122
- 2. Page title: "About"
123
- 3. Content structure:
124
- - Heading: "About James Weatherhead"
125
- - Bio paragraphs (placeholder text for now - user will customize):
126
- * Professional background
127
- * Technical interests
128
- * Why they write (blog purpose)
129
- - Contact information (if provided)
130
- - Optional: Links to GitHub, LinkedIn, Twitter (if provided)
131
- 4. Style with prose typography: prose dark:prose-invert max-w-3xl
132
- 5. Consistent container width with other pages
133
-
134
- Placeholder content example:
135
- "I'm a software engineer passionate about web development, DevOps, and technical writing. This blog is where I share insights, tutorials, and lessons learned from building software."
136
-
137
- AVOID: Do not add contact form (YAGNI - add if requested). Do not add photo upload (user can add later). WHY: Keep initial version simple - user can customize content after deployment.
138
- </action>
139
- <verify>
140
- Visit: http://localhost:4321/about
141
- Check: Page renders with heading and bio content
142
- Check: Consistent styling with other pages (max-w-3xl, prose)
143
- Check: Dark mode works correctly on about page
144
- Check: Header navigation links to /about works
145
- </verify>
146
- <done>
147
- - about.astro created with BaseLayout
148
- - Page contains heading and placeholder bio content
149
- - Prose typography applied for readability
150
- - Consistent container width (max-w-3xl)
151
- - Navigation link from Header works
152
- </done>
153
- </thread>
154
-
155
- <thread type="auto">
156
- <name>Thread 3: Implement tag-based filtering</name>
157
- <files>src/pages/blog/tags/[tag].astro</files>
158
- <action>
159
- Create dynamic tag pages for filtering posts by tag:
160
-
161
- 1. Create src/pages/blog/tags/[tag].astro
162
-
163
- 2. Implement getStaticPaths to generate page for each unique tag:
164
- ```ts
165
- import { getCollection } from 'astro:content';
166
- export async function getStaticPaths() {
167
- const allPosts = await getCollection('blog', ({ data }) => !data.draft);
168
- const uniqueTags = [...new Set(allPosts.flatMap(post => post.data.tags))];
169
-
170
- return uniqueTags.map(tag => {
171
- const filteredPosts = allPosts.filter(post =>
172
- post.data.tags.includes(tag)
173
- );
174
- return {
175
- params: { tag },
176
- props: { posts: filteredPosts },
177
- };
178
- });
179
- }
180
- ```
181
-
182
- 3. Render tag page:
183
- - Page title: "Posts tagged with '{tag}'"
184
- - Display tag name prominently
185
- - Show post count: "X posts"
186
- - Use PostList component with filtered posts
187
- - Breadcrumb: "Blog / Tags / {tag}"
188
- - Link back to /blog
189
-
190
- 4. Update Tag component (from Block 03):
191
- - When variant='link', link to /blog/tags/{tag}
192
- - Ensure tags in PostList are clickable
193
-
194
- AVOID: Do not add tag description field (YAGNI - tags are self-explanatory). Do not add "related tags" section (over-engineering). WHY: Keep tag pages simple - they're for filtering, not complex taxonomy.
195
- </action>
196
- <verify>
197
- Run: npm run dev
198
- Visit: http://localhost:4321/blog/tags/javascript (or any tag from sample post)
199
- Check: Page shows only posts with that tag
200
- Check: Post count displays correctly
201
- Check: Tags in PostList are clickable and link to tag pages
202
- Check: Breadcrumb or back link to /blog exists
203
- Run: npm run build (should generate static page for each tag)
204
- </verify>
205
- <done>
206
- - [tag].astro implements getStaticPaths with unique tags
207
- - Filters posts by tag correctly
208
- - Displays tag name and post count
209
- - PostList shows filtered posts
210
- - Tag component links to tag pages (variant='link')
211
- - Build generates static page for each tag
212
- </done>
213
- </thread>
214
-
215
- <thread type="checkpoint:human-verify" gate="blocking">
216
- <what-built>
217
- Complete page structure:
218
- - Homepage (index.astro) with recent posts
219
- - Blog index (blog/index.astro) with all posts
220
- - About page (about.astro) with author info
221
- - Tag pages (blog/tags/[tag].astro) with filtered posts
222
- </what-built>
223
- <how-to-verify>
224
- 1. cd /Users/jacweath/grid/blog && npm run dev
225
-
226
- 2. Test Homepage (http://localhost:4321):
227
- - Hero section displays site title and intro
228
- - Recent posts section shows up to 5 posts
229
- - "View all posts" link navigates to /blog
230
- - Header navigation visible (Home, Blog, About)
231
-
232
- 3. Test Blog Index (http://localhost:4321/blog):
233
- - All blog posts listed
234
- - Posts sorted newest first
235
- - Tags visible and clickable
236
-
237
- 4. Test About Page (http://localhost:4321/about):
238
- - Page renders with author info
239
- - Consistent styling with other pages
240
- - Navigation link from Header works
241
-
242
- 5. Test Tag Filtering:
243
- - Click a tag from blog index or post page
244
- - Should navigate to /blog/tags/{tag}
245
- - Only posts with that tag appear
246
- - Post count displays correctly
247
-
248
- 6. Test Navigation:
249
- - Click each nav link (Home, Blog, About)
250
- - All pages load without errors
251
- - Dark mode toggle works on all pages
252
-
253
- 7. Run: npm run build
254
- - Build completes successfully
255
- - Check dist/ contains all static pages
256
- </how-to-verify>
257
- <resume-signal>Type "approved" if all pages work and navigation is functional, or describe issues (e.g., "tag filtering broken", "about page missing", "homepage posts not showing")</resume-signal>
258
- </thread>
259
-
260
- </threads>
261
-
262
- <verification>
263
- Complete verification checklist:
264
- 1. Homepage renders with hero and recent posts (max 5)
265
- 2. Blog index lists all non-draft posts sorted by date
266
- 3. About page displays author information
267
- 4. Tag pages filter posts correctly by tag
268
- 5. Navigation links work (Home, Blog, About)
269
- 6. Tags are clickable and link to tag pages
270
- 7. Dark mode works consistently across all pages
271
- 8. All pages use BaseLayout with header/footer
272
- 9. Responsive on mobile and desktop
273
- 10. npm run build generates all static pages
274
- 11. No console errors on any page
275
- 12. User approves page structure and navigation
276
- </verification>
277
-
278
- <success_criteria>
279
- - Homepage displays recent posts and hero content
280
- - Blog index shows complete post listing
281
- - About page contains author information
282
- - Tag filtering functional (click tag → see filtered posts)
283
- - All navigation links work correctly
284
- - Build generates all static pages
285
- - Consistent styling and dark mode across all pages
286
- - User approves overall page structure and UX
287
- </success_criteria>
@@ -1,235 +0,0 @@
1
- ---
2
- cluster: james-weatherhead-blog
3
- block: 05
4
- type: execute
5
- wave: 3
6
- depends_on: [01, 03]
7
- files_modified: [src/pages/rss.xml.ts, src/utils/rss.ts]
8
- autonomous: true
9
-
10
- must_haves:
11
- truths:
12
- - "RSS feed is accessible at /rss.xml"
13
- - "Feed contains all published blog posts"
14
- - "Feed validates against RSS 2.0 specification"
15
- artifacts:
16
- - path: "src/pages/rss.xml.ts"
17
- provides: "RSS feed endpoint"
18
- exports: ["GET"]
19
- - path: "src/utils/rss.ts"
20
- provides: "RSS generation utility functions"
21
- min_lines: 20
22
- key_links:
23
- - from: "rss.xml.ts"
24
- to: "@astrojs/rss"
25
- via: "rss() function import"
26
- pattern: "import.*@astrojs/rss"
27
- - from: "rss.xml.ts"
28
- to: "getCollection('blog')"
29
- via: "fetch posts for feed"
30
- pattern: "getCollection\\('blog'\\)"
31
- ---
32
-
33
- <objective>
34
- Implement RSS feed generation for blog posts using @astrojs/rss.
35
-
36
- Purpose: Provide RSS feed for readers who prefer feed readers (Feedly, NewsBlur, etc.).
37
- Output: Valid RSS 2.0 feed at /rss.xml with all published posts.
38
- </objective>
39
-
40
- <context>
41
- Dependencies:
42
- - Block 01: @astrojs/rss installed during project setup
43
- - Block 03: Blog content collection configured
44
-
45
- This block adds RSS feed support - a standard feature for technical blogs. Requirements explicitly mention "RSS feed" as a feature.
46
-
47
- RSS feeds are static XML files generated at build time. Astro's @astrojs/rss integration makes this straightforward - no complex logic needed.
48
-
49
- This block runs in parallel with Block 04 (wave 3) since there's no file overlap:
50
- - Block 04 modifies: pages (index, blog, about, tags)
51
- - Block 05 modifies: rss.xml.ts, utils/rss.ts
52
- </context>
53
-
54
- <threads>
55
-
56
- <thread type="auto">
57
- <name>Thread 1: Create RSS feed endpoint</name>
58
- <files>src/pages/rss.xml.ts</files>
59
- <action>
60
- Create RSS feed using @astrojs/rss integration:
61
-
62
- 1. Create src/pages/rss.xml.ts (note: .ts not .astro for API route)
63
-
64
- 2. Import dependencies:
65
- ```ts
66
- import rss from '@astrojs/rss';
67
- import { getCollection } from 'astro:content';
68
- import type { APIContext } from 'astro';
69
- ```
70
-
71
- 3. Export GET function:
72
- ```ts
73
- export async function GET(context: APIContext) {
74
- const posts = await getCollection('blog', ({ data }) => !data.draft);
75
- const sortedPosts = posts.sort(
76
- (a, b) => b.data.pubDate.valueOf() - a.data.pubDate.valueOf()
77
- );
78
-
79
- return rss({
80
- title: 'James Weatherhead Blog',
81
- description: 'Technical writing on web development, DevOps, and software engineering',
82
- site: context.site || 'https://jamesweatherhead.com',
83
- items: sortedPosts.map(post => ({
84
- title: post.data.title,
85
- description: post.data.description,
86
- pubDate: post.data.pubDate,
87
- link: `/blog/${post.slug}/`,
88
- categories: post.data.tags,
89
- })),
90
- customData: '<language>en-us</language>',
91
- });
92
- }
93
- ```
94
-
95
- 4. Ensure astro.config.mjs has site URL set (required for RSS):
96
- - If not set, use placeholder: https://jamesweatherhead.com
97
-
98
- AVOID: Do not add full content to RSS (use description only for preview). Do not add custom XML transformations (use @astrojs/rss defaults). WHY: Full content RSS increases bandwidth and complexity; previews encourage click-through to site.
99
- </action>
100
- <verify>
101
- Run: npm run build
102
- Check: dist/rss.xml exists
103
- Run: npm run preview
104
- Visit: http://localhost:4321/rss.xml
105
- Check: XML renders in browser with all posts
106
- Validate: Use https://validator.w3.org/feed/ or RSS validator
107
- </verify>
108
- <done>
109
- - rss.xml.ts exports GET function returning RSS feed
110
- - Feed includes all non-draft posts sorted by date
111
- - Each item has title, description, pubDate, link, categories (tags)
112
- - site URL configured in astro.config.mjs
113
- - RSS feed accessible at /rss.xml
114
- </done>
115
- </thread>
116
-
117
- <thread type="auto">
118
- <name>Thread 2: Create RSS utility functions (optional helpers)</name>
119
- <files>src/utils/rss.ts</files>
120
- <action>
121
- Create optional utility functions for RSS generation:
122
-
123
- 1. Create src/utils/rss.ts
124
-
125
- 2. Add helper functions:
126
- ```ts
127
- import type { CollectionEntry } from 'astro:content';
128
-
129
- export function formatPostForRSS(post: CollectionEntry<'blog'>) {
130
- return {
131
- title: post.data.title,
132
- description: post.data.description,
133
- pubDate: post.data.pubDate,
134
- link: `/blog/${post.slug}/`,
135
- categories: post.data.tags,
136
- };
137
- }
138
-
139
- export function sortPostsByDate(posts: CollectionEntry<'blog'>[]) {
140
- return posts.sort(
141
- (a, b) => b.data.pubDate.valueOf() - a.data.pubDate.valueOf()
142
- );
143
- }
144
- ```
145
-
146
- 3. Refactor rss.xml.ts to use these utilities (DRY principle)
147
-
148
- Note: This thread is optional but recommended for cleaner code. If time-constrained, inline logic in rss.xml.ts is acceptable.
149
-
150
- AVOID: Do not add XML parsing utilities (use @astrojs/rss). Do not add feed caching (Astro handles this). WHY: @astrojs/rss provides all RSS functionality; additional abstractions add unnecessary complexity.
151
- </action>
152
- <verify>
153
- Check: src/utils/rss.ts exports helper functions
154
- Check: rss.xml.ts imports and uses utilities
155
- Run: npm run build (should succeed)
156
- Check: dist/rss.xml unchanged (same output, cleaner code)
157
- </verify>
158
- <done>
159
- - src/utils/rss.ts created with helper functions
160
- - formatPostForRSS converts post to RSS item format
161
- - sortPostsByDate sorts posts by date descending
162
- - rss.xml.ts refactored to use utilities
163
- - Build output identical (cleaner code, same result)
164
- </done>
165
- </thread>
166
-
167
- <thread type="auto">
168
- <name>Thread 3: Add RSS autodiscovery link</name>
169
- <files>src/layouts/BaseLayout.astro</files>
170
- <action>
171
- Add RSS feed autodiscovery to site header:
172
-
173
- 1. Open src/layouts/BaseLayout.astro (created in Block 02)
174
-
175
- 2. In the <head> section, add autodiscovery link:
176
- ```html
177
- <link
178
- rel="alternate"
179
- type="application/rss+xml"
180
- title="James Weatherhead Blog"
181
- href="/rss.xml"
182
- />
183
- ```
184
-
185
- 3. This allows:
186
- - Browsers to detect RSS feed (shows RSS icon in address bar)
187
- - Feed readers to auto-discover feed
188
- - Standard SEO best practice for blogs
189
-
190
- 4. Optional: Add visible RSS link in Footer component:
191
- - Icon or text link: "RSS Feed"
192
- - Links to /rss.xml
193
-
194
- AVOID: Do not add Atom feed (RSS 2.0 sufficient). Do not add JSON Feed (RSS standard more widely supported). WHY: RSS 2.0 is universal standard; additional feed formats add maintenance overhead without significant benefit.
195
- </action>
196
- <verify>
197
- Run: npm run dev
198
- Visit: http://localhost:4321
199
- Check: View page source - <link rel="alternate" type="application/rss+xml"> in <head>
200
- Check: Browser RSS icon appears (if browser supports)
201
- Check: Footer has RSS link (if added)
202
- </verify>
203
- <done>
204
- - BaseLayout.astro has RSS autodiscovery link in <head>
205
- - RSS feed detectable by browsers and feed readers
206
- - Optional: Footer contains visible RSS link
207
- - Feed properly advertised to users
208
- </done>
209
- </thread>
210
-
211
- </threads>
212
-
213
- <verification>
214
- Complete verification checklist:
215
- 1. src/pages/rss.xml.ts exports GET function
216
- 2. RSS feed includes all non-draft posts
217
- 3. Posts sorted by date descending (newest first)
218
- 4. Each item has title, description, pubDate, link, categories
219
- 5. Feed validates against RSS 2.0 spec (use validator)
220
- 6. /rss.xml accessible after build
221
- 7. BaseLayout.astro has autodiscovery link in <head>
222
- 8. Optional: Footer has visible RSS link
223
- 9. npm run build generates dist/rss.xml
224
- 10. Feed loads in feed reader (test with Feedly or similar)
225
- </verification>
226
-
227
- <success_criteria>
228
- - RSS feed accessible at /rss.xml
229
- - Feed contains all published blog posts
230
- - Feed validates against RSS 2.0 specification
231
- - Autodiscovery link present in site <head>
232
- - Feed items have complete metadata (title, description, date, link, tags)
233
- - Build generates static RSS XML file
234
- - Feed works in standard feed readers
235
- </success_criteria>