diff --git a/.planning/STATE.md b/.planning/STATE.md index d39babb..8b49117 100644 --- a/.planning/STATE.md +++ b/.planning/STATE.md @@ -3,8 +3,8 @@ gsd_state_version: 1.0 milestone: v1.0 milestone_name: milestone status: Context gathered — ready for /gsd-plan-phase 6 -last_updated: "2026-04-21T23:11:57.514Z" -last_activity: 2026-04-21 +last_updated: "2026-04-22T06:55:05.535Z" +last_activity: 2026-04-22 progress: total_phases: 8 completed_phases: 3 @@ -26,7 +26,7 @@ progress: Phase: Phase 6 — Blog Pages Plan: — Status: Context gathered — ready for /gsd-plan-phase 6 -Last activity: 2026-04-21 +Last activity: 2026-04-22 Resume file: .planning/phases/06-blog-pages/06-UI-SPEC.md ## Accumulated Context diff --git a/server/plugins/reading-time.ts b/server/plugins/reading-time.ts new file mode 100644 index 0000000..1dea82e --- /dev/null +++ b/server/plugins/reading-time.ts @@ -0,0 +1,23 @@ +import { countWordsInMinimalBody } from '~/utils/countWords' + +/** + * Nitro plugin: compute reading time for every markdown content file at parse time. + * + * Injects `wordCount` (number) and `minutes` (number, min 1) on the content object. + * Values are persisted in the @nuxt/content SQLite DB and queryable via queryCollection + * thanks to the matching Zod schema fields in content.config.ts (per D-18 + D-19). + * + * Hook reference: https://content.nuxt.com/docs/advanced/hooks + */ +export default defineNitroPlugin((nitroApp) => { + nitroApp.hooks.hook('content:file:afterParse', (ctx) => { + const { file, content } = ctx + + // Only process markdown files (defensive — hook fires on all sources) + if (!file.id?.endsWith('.md')) return + + const wordCount = countWordsInMinimalBody(content.body) + content.wordCount = wordCount + content.minutes = Math.max(1, Math.ceil(wordCount / 200)) // D-19: 200 wpm, floor 1 min + }) +})