Context
skills/[id].astro is 913 lines handling two completely unrelated page types in one file — category landing pages (SSR, static content) and skill detail pages (client-side fetch). This is the SMI-3018 route-collision workaround. The file also has a 350-line is:inline script block that can be extracted once the React hooks from #1378 exist.
Depends on: #1376 (types + shared utilities), #1378 (hooks)
Work
src/pages/skills/_components/CategoryPage.astro
Receives categoryMeta: CategoryMeta and categorySkills: SkillItem[] as props. Contains all the category landing page HTML currently at [id].astro:199–297 (~100 lines of markup + breadcrumb + CTA + skill grid + about section).
src/pages/skills/_components/SkillDetailPage.tsx
React component (client island) for the skill detail view. Replaces the 350-line is:inline script + the static HTML shell at [id].astro:299–561. Uses useAuth from #1378, calls skills-get directly, renders via typed DOM updates → proper JSX instead.
Key sections:
- Breadcrumb (dynamic name after fetch)
- Loading / error states
- Skill header (name, author, trust badge, quality tier)
- Description block
- README section (shown when
skill.content present)
- Installation commands × 3 (npx / CLI / assistant) with copy buttons
- Details + Tags grid
- "Users also installed" + Related skills
skills/[id].astro after:
---
import BaseLayout from '../../layouts/BaseLayout.astro'
import CategoryPage from './_components/CategoryPage.astro'
import { SkillDetailPage } from './_components/SkillDetailPage'
import { CATEGORIES } from '../../data/categories'
const { id } = Astro.params
const categoryMeta = CATEGORIES.find(c => c.slug === id)
// ... SSR fetch for category skills (unchanged logic, ~15 lines)
---
{categoryMeta
? <CategoryPage categoryMeta={categoryMeta} categorySkills={categorySkills} />
: <SkillDetailPage client:load skillId={id} apiBase={apiBase} />
}
Target: [id].astro ≤ 80 lines.
Acceptance criteria
Context
skills/[id].astrois 913 lines handling two completely unrelated page types in one file — category landing pages (SSR, static content) and skill detail pages (client-side fetch). This is the SMI-3018 route-collision workaround. The file also has a 350-lineis:inlinescript block that can be extracted once the React hooks from #1378 exist.Depends on: #1376 (types + shared utilities), #1378 (hooks)
Work
src/pages/skills/_components/CategoryPage.astroReceives
categoryMeta: CategoryMetaandcategorySkills: SkillItem[]as props. Contains all the category landing page HTML currently at[id].astro:199–297(~100 lines of markup + breadcrumb + CTA + skill grid + about section).src/pages/skills/_components/SkillDetailPage.tsxReact component (client island) for the skill detail view. Replaces the 350-line
is:inlinescript + the static HTML shell at[id].astro:299–561. UsesuseAuthfrom #1378, callsskills-getdirectly, renders via typed DOM updates → proper JSX instead.Key sections:
skill.contentpresent)skills/[id].astroafter:Target:
[id].astro≤ 80 lines.Acceptance criteria
[id].astrois under 500 lines (audit:standardspasses)repo_urlalso_installedandrelated_skillssections appear when data is presentnpm run typecheck+npm run lintpasss-maxage=300) still set for category pages