Communitygithub.com

khaym/stitch-to-astro

Procedure for creating pages using Astro Content Collections with dynamic routing from Stitch designs

O que é stitch-to-astro?

stitch-to-astro is a Claude Code agent skill that procedure for creating pages using Astro Content Collections with dynamic routing from Stitch designs.

Funciona com~Claude Code~Codex CLI~Cursor
npx skills add https://github.com/khaym/stitch-to-astro/tree/HEAD/.claude/skills/page-procedure

Perguntar na sua IA favorita

Abre um novo chat com esta habilidade de agente já pré-carregada.

Documentação

Content Page Procedure

Step-by-step procedure for creating content-driven pages using Astro Content Collections (Content Layer API) with dynamic routing.

Prerequisites

  • src/styles/global.css exists with design tokens (created by css-procedure)
  • docs/stitch/reference.md exists (field information from Stitch screens)

Input / Output

[Input]                                   [Output]
docs/stitch/reference.md  ──┐
  (Screen field info)        │
progress.md notes  ──────────┼──→  src/content/config.ts (schema)
  (Section structure,        │     src/content/<collection>/<slug>/index.mdx (data)
   design decisions)         │     src/pages/<collection>/[...slug].astro (routing)
                             │     src/components/*.astro (section components)

Steps

Step 1: Schema Definition (src/content/config.ts)

Astro 5 Content Layer API uses the glob loader.

1-1. Define Collection

import { defineCollection, z } from "astro:content";
import { glob } from "astro/loaders";

const myCollection = defineCollection({
  loader: glob({ pattern: "**/index.mdx", base: "./src/content/my-collection" }),
  schema: ({ image }) =>
    z.object({
      title: z.string(),
      // ... define fields
      heroImage: image(),  // Use image() helper for images
    }),
});

export const collections = { myCollection };

1-2. Schema Design Guidelines

  • Start minimal, extend incrementally. Define only fields needed for current page rendering; add more when implementing components
  • Use image() helper for image fields to enable build-time path validation and optimization
  • Use .optional() for fields not required in every entry
  • Use optional arrays for section-level data to control section visibility per page:
    // Schema
    moments: z.array(z.object({ title: z.string(), ... })).optional()
    
    <!-- Page template: conditional rendering -->
    {data.moments && <MomentsSection moments={data.moments} />}
    

1-3. YAML Frontmatter Pitfalls

  • Month names (March, May, etc.) and Yes/No are auto-converted by YAML. Quote them if they should be strings: date: "March"
  • Image paths are relative to the MDX file: heroImage: ./hero.jpg

Step 2: Create Content Data

2-1. Directory Structure

src/content/<collection>/<slug>/
├── index.mdx      # frontmatter + MDX body
├── hero.jpg        # Images co-located with content
└── ...

2-2. MDX File Structure

---
title: "Page Title"
heroImage: ./hero.jpg
description: "Description text"
---

## MDX Body

Body content is retrieved via `render()` and rendered as `<Content />`.

2-3. Image Management

  • Store images inside src/content/ co-located with their content (not in public/)
  • Resize images larger than 2560px before committing
  • When using image() helper in schema, frontmatter image paths resolve to ImageMetadata type. Use ImageMetadata in component Props as well

Step 3: Dynamic Routing Page

Create src/pages/<collection>/[...slug].astro:

---
import type { GetStaticPaths } from "astro";
import { getCollection, render } from "astro:content";

export const getStaticPaths = (async () => {
  const items = await getCollection("myCollection");
  return items.map((item) => ({
    params: { slug: item.id },
    props: { item },
  }));
}) satisfies GetStaticPaths;

const { item } = Astro.props;
const { Content } = await render(item);
---

Key Points

  • getCollection() fetches all entries; getStaticPaths generates static paths
  • render() returns MDX body as a Content component
  • item.data provides type-safe access to frontmatter fields
  • Conditional rendering for optional fields: {data.field && <Component ... />}

Step 4: Page Data Files (src/data/<page>.md)

User-editable content (text, labels, URLs) for each page should be defined in Markdown files with YAML frontmatter under src/data/. This keeps the format consistent with Content Collections and makes it easy for users to find and edit their content.

Note: The src/data/ directory is not created by the scaffold skill. Create it in this step.

4-1. Create a data file for each page

src/data/
├── index.md      # Works (top) page content
├── about.md      # About Me page content
└── skills.md     # Skills page content

4-2. Define editable content as YAML frontmatter

---
# ==============================
# Works Page Content
# Edit this file to customize your page.
# ==============================

hero:
  headingPrefix: "Hi, I'm a"
  highlightedText: "Web Developer."
  description: "I build scalable, user-centric applications..."
  badgeText: "Available for new projects"

cta:
  heading: "Ready to build something together?"
  description: "I'm currently open to freelance opportunities..."
  buttons:
    - label: "Get in Touch"
      href: "mailto:[email protected]"
      variant: "primary"
    - label: "Download CV"
      href: "#"
      variant: "secondary"
---
  • Put only user-editable text in the YAML (strings, labels, URLs, arrays of text)
  • Keep non-editable data (SVG icon paths, etc.) as TypeScript constants in the .astro page file

4-3. Import data in the page

Use import.meta.glob() to load the frontmatter:

---
const content = Object.values(
  import.meta.glob("../data/index.md", { eager: true })
)[0] as { frontmatter: Record<string, unknown> };
const { hero, cta } = content.frontmatter;
---

Step 5: Section Component Implementation

Create each section (hero, moments, etc.) as an independent component in src/components/. Follow develop-guideline for component structure and CSS rules.

Image Display: <Picture> vs <img>

MethodWhen to useExample
<Picture>Static images known at build timeHero backgrounds, entry images
<img>Images dynamically swapped by client JSModal gallery slideshows

<Picture> renders at build time, so it cannot be used when src is swapped by client JS.

Client-Side JavaScript

<script> tags in Astro components run as client JS. Interactive features can be built without frameworks (React, etc.).

Data passing pattern: Use data-* attributes to pass frontmatter data to client JS. <script> cannot directly reference frontmatter variables.

Accessibility: Modal / Overlay

Checklist for modal dialog implementation:

RequirementImplementation
Semanticsrole="dialog" + aria-modal="true" + aria-label
Open/closeToggle hidden attribute + CSS opacity transition
Scroll lockOpen: document.body.style.overflow = "hidden" / Close: restore to ""
KeyboardEscape to close, arrow keys for navigation
Focus trapTab/Shift+Tab cycles through buttons within modal
Focus restorefocus() trigger element on close
Backdrop closeClose when click target is not an interactive element
z-indexHigher than existing fixed elements (e.g., header 50 → modal 60)

Step 6: Build Verification

npm run build

Content Collections schema validation errors surface at build time with clear messages.

Common Errors

ErrorCauseFix
Expected type "string", received "object"YAML auto-converted a value (month name → Date, etc.)Quote the value
Could not find imageIncorrect image pathVerify relative path from MDX file
does not match collection schemaMissing field or type mismatch in frontmatterCheck against config.ts schema

Step 7: Dev Server Verification

npm run dev
  • Schema changes may require dev server restart (content store clearing)
  • If errors persist after restart, delete .astro/ directory and restart

Checklist

  • src/content/config.ts has schema defined
  • MDX frontmatter conforms to schema
  • Images are inside src/content/ and resized to ≤2560px
  • [...slug].astro returns all entries from getStaticPaths
  • Optional field sections use conditional rendering
  • npm run build succeeds
  • Visual confirmation in browser for all sections (including mobile width)

Habilidades Relacionadas