From 3e7de787211a0582d0032446491e9dd710e21bef Mon Sep 17 00:00:00 2001 From: Richie Date: Thu, 21 May 2026 14:05:36 +1000 Subject: [PATCH] Remove internal project files from tracking and update .gitignore MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Stop tracking .claude/, CLAUDE.md, ARCHITECTURE.md, and plans/ — these are local-only working files for Claude Code and should not be on the shared Gitea remote. Files remain on disk, only removed from git index. Co-Authored-By: Claude Opus 4.6 --- .claude/settings.json | 67 ------- .claude/skills/component-rules/SKILL.md | 71 ------- .claude/skills/figma-preflight/SKILL.md | 117 ------------ .claude/skills/figma-style-binding/SKILL.md | 137 -------------- .claude/skills/reference-interpreter/SKILL.md | 88 --------- .gitignore | 6 + ARCHITECTURE.md | 148 --------------- CLAUDE.md | 169 ----------------- plans/brand-colours.md | 73 -------- plans/button.md | 68 ------- plans/input.md | 55 ------ plans/penpot-to-figma.md | 49 ----- plans/project-setup.md | 177 ------------------ plans/toggle-controls.md | 90 --------- plans/typography.md | 74 -------- plans/workflow.md | 115 ------------ 16 files changed, 6 insertions(+), 1498 deletions(-) delete mode 100644 .claude/settings.json delete mode 100644 .claude/skills/component-rules/SKILL.md delete mode 100644 .claude/skills/figma-preflight/SKILL.md delete mode 100644 .claude/skills/figma-style-binding/SKILL.md delete mode 100644 .claude/skills/reference-interpreter/SKILL.md delete mode 100644 ARCHITECTURE.md delete mode 100644 CLAUDE.md delete mode 100644 plans/brand-colours.md delete mode 100644 plans/button.md delete mode 100644 plans/input.md delete mode 100644 plans/penpot-to-figma.md delete mode 100644 plans/project-setup.md delete mode 100644 plans/toggle-controls.md delete mode 100644 plans/typography.md delete mode 100644 plans/workflow.md diff --git a/.claude/settings.json b/.claude/settings.json deleted file mode 100644 index 18b25a1..0000000 --- a/.claude/settings.json +++ /dev/null @@ -1,67 +0,0 @@ -{ - "permissions": { - "allow": [ - "Bash(npm run dev)", - "Bash(npm run build)", - "Bash(npm run storybook)", - "Bash(npm run lint)", - "Bash(npx tsc --noEmit)", - "Bash(npx storybook *)", - "Bash(npx prettier *)", - "Bash(npx vitest *)", - "Bash(node --check *)", - "Bash(npm install *)", - "Bash(npm list *)", - "Bash(npm outdated *)", - "Bash(git status *)", - "Bash(git log *)", - "Bash(git diff *)", - "Bash(git add *)", - "Bash(git commit *)", - "Bash(git branch *)", - "Bash(git checkout *)", - "Bash(git push *)", - "Bash(git pull *)", - "Bash(git remote *)", - "Bash(kill %*)", - "Bash(lsof -i *)", - "WebSearch", - "WebFetch(domain:storybook.js.org)", - "WebFetch(domain:tailwindcss.com)", - "WebFetch(domain:react.dev)", - "WebFetch(domain:vitejs.dev)", - "WebFetch(domain:vite.dev)", - "WebFetch(domain:github.com)", - "WebFetch(domain:npmjs.com)", - "WebFetch(domain:figma.com)", - "WebFetch(domain:help.figma.com)", - "WebFetch(domain:developers.figma.com)", - "WebFetch(domain:developer.mozilla.org)", - "mcp__figma__whoami", - "mcp__figma__get_metadata", - "mcp__figma__get_libraries", - "mcp__figma__use_figma", - "mcp__figma__get_screenshot", - "mcp__figma__search_design_system", - "mcp__figma__get_variable_defs", - "mcp__figma__get_design_context", - "mcp__figma__get_code_connect_map", - "mcp__figma__add_code_connect_map", - "mcp__figma__get_code_connect_suggestions", - "mcp__figma__send_code_connect_mappings" - ] - }, - "hooks": { - "PostToolUse": [ - { - "matcher": "mcp__figma__use_figma", - "hooks": [ - { - "type": "command", - "command": "echo 'QA: Verify style/variable bindings on all returned node IDs.'" - } - ] - } - ] - } -} diff --git a/.claude/skills/component-rules/SKILL.md b/.claude/skills/component-rules/SKILL.md deleted file mode 100644 index 2724609..0000000 --- a/.claude/skills/component-rules/SKILL.md +++ /dev/null @@ -1,71 +0,0 @@ ---- -name: component-rules -description: "Triggers when building any UI element in Figma — 'create a card', 'build a nav', 'add a section', 'make a component'. Enforces library-first component lookup, correct Auto Layout structure, and semantic node naming. For visual property binding (colors, text styles, spacing values), defer to figma-style-binding." -disable-model-invocation: false ---- - -# Component Rules - -Governs how Claude constructs UI in Figma. Supplements `figma-generate-design`. For visual property binding, defer to `figma-style-binding`. - ---- - -## Rule 1 — Library-first hierarchy - -Before building anything, resolve the component source in this order: - -``` -1. search_design_system → importComponentByKeyAsync → createInstance() -2. Local file scan → createInstance() -3. Build from scratch — ONLY if nothing matches -``` - -Never rebuild primitives the DS provides: Button, Input, Checkbox, Toggle, Badge, Tag, Avatar, Icon, Tab, Breadcrumb, Toast, Alert, Spinner. - -```js -// Library import -const comp = await figma.importComponentByKeyAsync("key_from_search"); -const instance = comp.createInstance(); -parent.appendChild(instance); - -// For component sets (variants) -const set = await figma.importComponentSetByKeyAsync("key"); -const instance = set.defaultVariant.createInstance(); -``` - ---- - -## Rule 2 — Auto Layout - -Every container must use Auto Layout. Property order matters: - -1. Set `layoutMode` FIRST (`"VERTICAL"` or `"HORIZONTAL"`) -2. Set `layoutSizingHorizontal` / `layoutSizingVertical` AFTER `appendChild` -3. Set `layoutMode` BEFORE any `setBoundVariable` call - -| Goal | primaryAxisSizing | counterAxisSizing | layoutSizingH | layoutSizingV | -|---|---|---|---|---| -| Hug both | AUTO | AUTO | HUG | HUG | -| Fixed card | FIXED | FIXED | FIXED | FIXED | -| Full-width section | AUTO | FIXED | FILL | HUG | - ---- - -## Rule 3 — Node naming - -Name every node semantically with slash hierarchy. Never leave defaults. - -``` -Card / Container Card / Title Card / Body Card / Action Row -Hero / Background Nav / Link Group Button / Primary -``` - ---- - -## Rule 4 — Incremental building - -One section per `use_figma` call. Validate via screenshot after each step. Return all created/mutated node IDs: - -```js -return { created: { card: card.id, title: title.id } }; -``` diff --git a/.claude/skills/figma-preflight/SKILL.md b/.claude/skills/figma-preflight/SKILL.md deleted file mode 100644 index 607d615..0000000 --- a/.claude/skills/figma-preflight/SKILL.md +++ /dev/null @@ -1,117 +0,0 @@ ---- -name: figma-preflight -description: "Triggers on 'let's start', 'begin', 'preflight', 'start the session', or when a Figma file URL is first shared. Verifies MCP connection, reads CLAUDE.md, audits connected libraries, and loads a Token Map of all Styles and Variables — required before any design work." -disable-model-invocation: false ---- - -# Figma Preflight - -Run at the start of every design session. Do NOT start design work until all steps pass. - -**Prerequisite:** Load `figma-use` skill before any `use_figma` call. - ---- - -## Step A — Connection + Config (parallel) - -Run these two in parallel: - -1. **MCP Connection:** Call `mcp__figma__whoami`. Must return user email and plan. Fail → stop, re-authenticate. -2. **CLAUDE.md:** Read CLAUDE.md. Extract Figma file URL (required — stop if missing), font families, session goal. If fonts field is a placeholder, auto-populate after Step C using STRING variables starting with "Family". - ---- - -## Step B — File + Libraries (parallel) - -Parse `fileKey` from the Figma URL, then run in parallel: - -1. **File Access:** Call `get_metadata` with extracted nodeId and fileKey. Must return file name and pages. -2. **Libraries:** Call `get_libraries` with fileKey. Store subscribed libraries as **Library Registry** (name, libraryKey, description). These enable `search_design_system` to find library styles and components during design work. - ---- - -## Step C — Styles + Variables + Components (single use_figma call) - -Combine all three inventories in one script: - -```javascript -const textStyles = await figma.getLocalTextStylesAsync(); -const paintStyles = await figma.getLocalPaintStylesAsync(); -const collections = await figma.variables.getLocalVariableCollectionsAsync(); -const variables = await figma.variables.getLocalVariablesAsync(); - -const grouped = {}; -for (const v of variables) { - const key = v.resolvedType; - if (!grouped[key]) grouped[key] = []; - grouped[key].push({ name: v.name, scopes: v.scopes }); -} - -const components = {}; -for (const page of figma.root.children) { - await figma.setCurrentPageAsync(page); - const sets = page.findAll(n => n.type === "COMPONENT_SET"); - const solos = page.findAll(n => n.type === "COMPONENT" && n.parent.type !== "COMPONENT_SET"); - if (sets.length > 0 || solos.length > 0) { - components[page.name] = { - sets: sets.map(c => c.name), - solos: solos.map(c => c.name).slice(0, 15), - }; - } -} - -return { - textStyles: textStyles.map(s => s.name), - paintStyles: paintStyles.map(s => s.name), - collections: collections.map(c => c.name), - variableCount: variables.length, - byType: Object.fromEntries( - Object.entries(grouped).map(([type, vars]) => [type, vars.map(v => v.name)]) - ), - components -}; -``` - -Store **names only** in context. IDs are looked up on-demand during design work. Library styles/variables are discovered via `search_design_system`. - ---- - -## Token Map - -After Step C, derive a semantic index from variables grouped by `scopes`: - -| Role | Scope | Example names | -|---|---|---| -| Background fill | `FRAME_FILL`, `SHAPE_FILL` | `background/surface`, `color/neutral-100` | -| Text color | `TEXT_FILL` | `text/primary`, `color/neutral-900` | -| Border / stroke | `STROKE_COLOR` | `border/default`, `color/neutral-300` | -| Gap | `GAP` | `gap/sm`, `spacing/xxs` | -| Padding | `PADDING` | `padding/md`, `spacing/section-xl` | -| Border radius | `CORNER_RADIUS` | `radius/sm`, `radius/full` | - ---- - -## Status Report - -``` -✅ MCP Connection — [name] ([email]) · [plan] -✅ CLAUDE.md — Font: [primary] / [code] · Goal: [goal] -✅ Figma File — [file name] · [N] pages -✅ Libraries — [N] connected: [names] -✅ Styles — [N] text + [N] paint -✅ Variables — [N] across [N] collections -✅ Components — [N] sets across [N] pages - -── Token Map ────────────────────────────── -Background : [names] -Text : [names] -Border : [names] -Gap : [names] -Padding : [names] -Radius : [names] -──────────────────────────────────────────── - -Ready to design. -``` - -If any step fails, output ❌ with error and stop. diff --git a/.claude/skills/figma-style-binding/SKILL.md b/.claude/skills/figma-style-binding/SKILL.md deleted file mode 100644 index 8bd5227..0000000 --- a/.claude/skills/figma-style-binding/SKILL.md +++ /dev/null @@ -1,137 +0,0 @@ ---- -name: figma-style-binding -description: "Triggers on any visual property change in Figma — creating text, setting colors, adjusting spacing/padding/gap/radius. Enforces that ALL values bind to Figma Styles or Variables, never hardcoded. Includes post-write QA verification." -disable-model-invocation: false ---- - -# Style Binding + QA - -Every visual value must come from the design system. Supplements `figma-generate-design`. Prerequisite: `figma-preflight` must have run this session. - ---- - -## Binding Hierarchy - -For any visual property, follow this order. Stop at the first match. - -``` -1. Connected Library → search_design_system → import → apply -2. Local Style → Style Registry → apply by ID -3. Local Variable → Variable Registry → apply by ID -4. Gap found → Report to user, wait for decision -``` - ---- - -## Text - -Every text node must use `textStyleId`. Individual font properties (`fontSize`, `fontFamily`, etc.) are forbidden. - -```js -const style = await figma.getStyleByIdAsync(""); -await figma.loadFontAsync(style.fontName); -node.textStyleId = ""; -``` - -If no local style matches, search libraries via `search_design_system`. If no match anywhere: -``` -⚠️ Text style gap: no style for "[role]". Available: [top 5]. Use closest, or add missing style? -``` - ---- - -## Color Fills - -Every fill/stroke must bind to a COLOR Variable (preferred, supports theming) or Paint Style. - -```js -// Variable binding (preferred) -const variable = await figma.variables.getVariableByIdAsync(""); -const fill = { type: "SOLID", color: { r: 0, g: 0, b: 0 } }; -node.fills = [figma.variables.setBoundVariableForPaint(fill, "color", variable)]; - -// Paint Style binding -node.fillStyleId = ""; -``` - -Never use raw `{ r, g, b }` without a binding. - ---- - -## Spacing, Padding, Gap, Radius - -Bind to FLOAT Variables. `layoutMode` must be set BEFORE `setBoundVariable`. - -```js -node.setBoundVariable("paddingTop", spacingVar); -node.setBoundVariable("paddingBottom", spacingVar); -node.setBoundVariable("paddingLeft", spacingVar); -node.setBoundVariable("paddingRight", spacingVar); -node.setBoundVariable("itemSpacing", spacingVar); -node.setBoundVariable("cornerRadius", radiusVar); -``` - -Spacing can fall back to raw values temporarily with user confirmation. Color and text cannot. - ---- - -## Forbidden / Required - -| Forbidden | Required | -|---|---| -| `node.fontSize = 24` | `node.textStyleId = id` | -| `node.fills = [{ type: "SOLID", color: { r: .2, g: .4, b: 1 } }]` | Variable or Style binding | -| `node.paddingLeft = 16` | `node.setBoundVariable("paddingLeft", var)` | -| `node.cornerRadius = 8` | `node.setBoundVariable("cornerRadius", var)` | -| Creating a Button from scratch | `importComponentByKeyAsync` from library | - ---- - -## QA Verification - -After every `use_figma` call that creates or modifies nodes, run this verification on the returned node IDs: - -```javascript -const nodeIdsToAudit = [/* paste returned IDs */]; -const results = []; - -for (const id of nodeIdsToAudit) { - const node = await figma.getNodeByIdAsync(id); - if (!node) { results.push({ id, status: "NOT_FOUND" }); continue; } - - const checks = []; - - if (node.type === "TEXT") { - checks.push({ prop: "textStyleId", bound: !!node.textStyleId }); - } - - if ("fills" in node && Array.isArray(node.fills) && node.fills.length > 0) { - const bound = !!node.fillStyleId || (node.boundVariables?.fills?.length > 0); - checks.push({ prop: "fills", bound }); - } - - if ("layoutMode" in node && node.layoutMode !== "NONE") { - for (const p of ["paddingLeft","paddingRight","paddingTop","paddingBottom","itemSpacing"]) { - if (p in node) checks.push({ prop: p, bound: !!(node.boundVariables && p in node.boundVariables) }); - } - } - - if ("cornerRadius" in node && node.cornerRadius > 0) { - checks.push({ prop: "cornerRadius", bound: !!(node.boundVariables && "cornerRadius" in node.boundVariables) }); - } - - const failed = checks.filter(c => !c.bound); - results.push({ id, name: node.name, type: node.type, status: failed.length === 0 ? "PASS" : "FAIL", failed: failed.map(c => c.prop) }); -} - -return { auditResults: results }; -``` - -**If FAIL:** Fix each unbound property using the binding rules above, then re-audit. Do not proceed to the next design step until all pass. - -**Report format:** -``` -✅ All [N] nodes passed. -// or -❌ FAIL "Card" (FRAME) — paddingTop, cornerRadius unbound. Fixing... -``` diff --git a/.claude/skills/reference-interpreter/SKILL.md b/.claude/skills/reference-interpreter/SKILL.md deleted file mode 100644 index d48daa8..0000000 --- a/.claude/skills/reference-interpreter/SKILL.md +++ /dev/null @@ -1,88 +0,0 @@ ---- -name: reference-interpreter -description: "Triggers when user shares a screenshot, image, URL, or design description — or says 'analyze this', 'make a brief', 'interpret this reference'. Outputs a structured Design Brief mapping visual intent to design system tokens. Waits for 'confirmed' before designing." -disable-model-invocation: false ---- - -# Reference Interpreter - -Analyze a reference (screenshot, URL, or description) and produce a **Design Brief** that maps visual observations to design system tokens. Output the Brief, then **stop and wait for user confirmation** before building anything. - -Prerequisite: `figma-preflight` should have run so the Token Map and Style Registry are available. - ---- - -## Phase 1 — Analyze - -Examine the reference across these dimensions: - -1. **Layout** — structure, columns, section heights, grid width, alignment -2. **Typography** — heading/body hierarchy, weight contrast, tracking -3. **Color** — dark/light sections, accent usage, neutral dominance -4. **Spacing** — generous vs compact, section padding, internal gap -5. **Visual Anchor** — what draws the eye: large type, hero image, illustration -6. **Components** — what UI elements are visible: cards, buttons, forms, nav - ---- - -## Phase 2 — Map to Design System - -For each observation, identify the specific Token or Style from the session's Token Map: - -``` -"Large dark headline" → Text Style: heading/h1 · Color: text/primary -"Neutral section bg" → Variable: background/surface-2 -"Tight card spacing" → Gap: gap/xs · Padding: padding/sm -``` - -If no token exists, flag it: -``` -⚠️ Gap: [observation] — no matching token. Options: (a) nearest match: [name], (b) add token first. -``` - ---- - -## Phase 3 — Output the Design Brief - -``` -## Design Brief - -**Reference**: [source] -**Section**: [what this covers] -**Aesthetic**: [3-5 keywords] - -### Layout -[structure, height, alignment] - -### Typography -- Heading: [Style name] — [why] -- Body: [Style name] - -### Colors -- Background: [Variable] — [context] -- Text: [Variable] -- Accent: [Variable] — [used for] - -### Spacing -- Section padding: [Variable] -- Internal gap: [Variable] - -### Components needed -- [Name]: [from library? source] - -### Gaps -- [Gap description] — awaiting decision -- (none) [if all mapped] -``` - ---- - -## Phase 4 — Wait - -Output exactly: - -``` -Brief complete. Type `confirmed` to begin building, or tell me what to adjust. -``` - -Do NOT call `use_figma` or place any nodes until user types `confirmed`. diff --git a/.gitignore b/.gitignore index f52343a..f1ebd5f 100644 --- a/.gitignore +++ b/.gitignore @@ -25,3 +25,9 @@ dist-ssr *storybook.log storybook-static + +# Claude Code (local-only project files) +.claude/ +CLAUDE.md +ARCHITECTURE.md +plans/ diff --git a/ARCHITECTURE.md b/ARCHITECTURE.md deleted file mode 100644 index 246f683..0000000 --- a/ARCHITECTURE.md +++ /dev/null @@ -1,148 +0,0 @@ -# ARCHITECTURE.md — SDC-Frontend - -This is the living architecture document for the SDC-Frontend design system. All structural decisions are recorded here. Update this document when the architecture evolves — never let the codebase and this document drift apart. - ---- - -## 1. Overview - -SDC-Frontend is a React component library and design system that will serve as the frontend for the Research Synthesiser. It is built in phases: - -1. **Design system** — tokens, primitives, composite components -2. **Application screens** — the synthesiser UI rebuilt on top of the design system - ---- - -## 2. Token Pipeline - -``` -Figma (design tool) - ↓ Figma MCP / get_variable_defs -src/tokens/tokens.css (@theme block) - ↓ Tailwind CSS v4 reads @theme - ↓ Generates utility classes + CSS custom properties -Components (use Tailwind utilities or var() references) - ↓ Rendered in -Storybook (visual verification) -``` - -### Token Layers -Tokens are structured in three layers: - -1. **Palette** — raw colour values (`--color-blue-01`, `--color-grey-03`). Not used directly in components. -2. **Semantic** — purpose-based aliases (`--color-primary`, `--color-error`, `--color-text`). General UI usage. -3. **Form control** — shared interactive-state tokens for all form components (`--color-control-border`, `--color-control-checked`, `--color-control-label`, etc.). Ensures consistent styling across Input, Checkbox, Radio, Switch, Select, and future form primitives. - -### Token Categories -- **Palette colours**: `--color-{palette}-{shade}` (e.g., `--color-blue-01`, `--color-grey-03`) -- **Semantic colours**: `--color-{purpose}` (e.g., `--color-primary`, `--color-error`, `--color-text`) -- **Form control colours**: `--color-control-{role}` (e.g., `--color-control-border`, `--color-control-checked`) -- **Radii**: `--radius-*` (sm, default, lg, full) -- **Shadows**: `--shadow-*` (default, md) - -### How Tailwind v4 @theme Works -Declaring `--color-primary: #2563eb` inside `@theme` in `tokens.css` automatically generates utilities like `bg-primary`, `text-primary`, `border-primary`. No JavaScript config file needed — the CSS file is the config. - ---- - -## 3. Component Taxonomy - -### `src/components/ui/` — Primitives -Atomic, reusable building blocks. Each is self-contained with no domain logic. -- Button, Input, Checkbox, Radio/RadioGroup, Switch -- Textarea, Select -- Card, Badge, Tag -- Dialog, Tooltip, Popover - -### `src/components/composite/` — Composed Components -Built from primitives, may carry light domain semantics. -- StatusMessage (success/error/warning/info) -- TabBar, TabPanel -- ThemeCard (maps to synthesiser's theme display) - -### `src/components/layout/` — Layout -Page-level structural components. -- AppShell (header + sidebar + content area) -- PageHeader - -### Which Tier Does a Component Belong To? - -| Question | If yes → | -|---|---| -| Does it wrap a single native element or a single interaction pattern (button, input, toggle)? | **ui/** (primitive) | -| Does it compose 2+ primitives into a reusable unit (e.g., a search bar = Input + Button)? | **composite/** | -| Does it carry domain-specific naming or logic (e.g., ThemeCard, ParticipantRow)? | **composite/** | -| Does it define a page-level region or shell (header, sidebar, content area)? | **layout/** | - -When in doubt: start in `ui/`. Promote to `composite/` when a component begins importing other `ui/` components. If the `composite/` directory grows beyond ~15 components, consider splitting it into `molecules/` (generic compositions) and `organisms/` (domain-aware compositions). - ---- - -## 4. Styling Approach - -- **Primary**: Tailwind utility classes -- **Conditional classes**: `cn()` from `@/lib/utils` (clsx + tailwind-merge) -- **Token values**: Always from `src/tokens/tokens.css`, never hardcoded -- **Token discipline**: Components reference semantic or form-control tokens, not palette tokens. If the needed semantic token doesn't exist, add it to `tokens.css` before using a raw palette value. -- **No CSS modules, no styled-components, no inline styles** (except truly dynamic values) -- **Class ordering**: Enforced by `prettier-plugin-tailwindcss` - ---- - -## 5. Storybook Conventions - -- Every component has a co-located `.stories.tsx` file -- All stories use `tags: ['autodocs']` for auto-generated docs -- Stories cover: default state, all variants, edge cases, disabled/error states -- A11y addon runs on all stories — violations should be addressed -- MCP addon enabled at `localhost:6006/mcp` for AI-assisted development - ---- - -## 6. Project Structure - -``` -src/ -├── components/ -│ ├── ui/ # Primitives -│ ├── composite/ # Composed components -│ └── layout/ # Layout components -├── tokens/ -│ └── tokens.css # Design tokens (@theme block) -├── styles/ -│ └── global.css # Tailwind imports + base styles -├── lib/ -│ └── utils.ts # cn() utility -├── hooks/ # Custom React hooks -├── pages/ # App screens (Phase 2) -├── App.tsx # Root component -└── main.tsx # Vite entry point -``` - ---- - -## 7. Design Tool Integration - -### Figma -- Project file: https://www.figma.com/design/mrabO6AtxN3ektGiTk0I9c/ResearchInsights (file key: `mrabO6AtxN3ektGiTk0I9c`) -- MCP server: Official Figma Remote MCP at `https://mcp.figma.com/mcp` (HTTP transport, OAuth auth) -- Key tools: `get_design_context`, `get_variable_defs`, `get_screenshot`, `search_design_system`, `use_figma` -- Design tokens extracted via `get_variable_defs` → mapped to `@theme` values in `tokens.css` - -### Code Connect -- Links Figma components to their React implementations -- Once linked, `get_design_context` returns actual component code instead of generic markup -- Mapped as we build each component via `add_code_connect_map` (label: "React") - -### Storybook MCP -- Available at `localhost:6006/mcp` when Storybook dev server is running -- Provides: component listing, documentation retrieval, story generation, a11y testing -- `@storybook/addon-designs` embeds Figma frames in the story panel for side-by-side comparison -- `@storybook/addon-mcp` serves the MCP endpoint - -### claude2figma Skills -- 4 skills in `.claude/skills/` that enforce design system compliance when writing to Figma -- **figma-preflight**: Validates MCP connection, audits libraries, builds a Token Map of all styles/variables -- **component-rules**: Library-first lookup, Auto Layout conventions, semantic node naming -- **figma-style-binding**: All visual values must bind to Figma Styles or Variables, never hardcoded; includes post-write QA -- **reference-interpreter**: Converts screenshots/references into structured Design Briefs mapped to design tokens diff --git a/CLAUDE.md b/CLAUDE.md deleted file mode 100644 index 8b6f2d7..0000000 --- a/CLAUDE.md +++ /dev/null @@ -1,169 +0,0 @@ -# CLAUDE.md — SDC-Frontend Design System - -You are the lead engineer on **SDC-Frontend**, a React component library and design system for the Research Synthesiser, built for UX researchers at the NSW Department of Education. - ---- - -## How I Want You to Work - -These are non-negotiable working principles for this project. - -### Plan Before You Build -Before beginning any significant piece of work, write a plan as a markdown file in `plans/`. Include what you're building, why, how it connects to the architecture, key decisions, and anything you need my input on. Share it with me before starting. Small, well-defined tasks don't need a plan — use your judgment on the threshold. - -### Evaluate Before You Commit -Before choosing a library, pattern, or approach: identify your options, research the latest documentation (don't rely on training knowledge for version-specific details), verify it works within the project constraints, and state your reasoning — especially when you considered and rejected alternatives. - -### Ask, Don't Assume -If you need information you don't have — about infrastructure, the team's workflow, the Figma setup, design intent, or anything unclear — ask me. Do not fill gaps with assumptions. A question costs a moment; a wrong assumption costs hours. - -### Architecture Governance -`ARCHITECTURE.md` is the living contract for this project. Before starting any task, re-read the relevant section. If you need to deviate, propose the change to me first, then update the document. If you discover something new, add it. Never let the codebase and architecture drift apart. - -### Fail Gracefully, Build Honestly -Test components with realistic props and edge cases, not only happy-path defaults. When something breaks, surface clear errors. This is a design system — correctness and consistency matter more than speed. - ---- - -## Technical Stack - -| Tool | Version | Notes | -|---|---|---| -| React | 19.x | Function components, hooks only | -| Vite | latest | Dev server + build | -| TypeScript | strict mode | All components must have typed props | -| Tailwind CSS | v4.3+ | CSS-first config via `@theme` in `src/tokens/tokens.css` | -| Storybook | 10.x | Component dev, docs, visual testing, MCP addon | -| clsx + tailwind-merge | latest | Combined as `cn()` in `src/lib/utils.ts` | -| ESLint + Prettier | latest | With `prettier-plugin-tailwindcss` for class ordering | - ---- - -## Design Tokens - -All design tokens live in `src/tokens/tokens.css` as a `@theme` block. This is the **single source of truth**. Do not hardcode colour values, radii, or shadows anywhere else. - -Use Tailwind utilities (`bg-primary`, `text-error`, `rounded-default`, etc.) or CSS variables (`var(--color-primary)`) when utilities don't cover the case. - -### Token Layers - -Tokens are organised in three layers, from raw to consumable: - -1. **Palette** — raw colour values: `--color-blue-01`, `--color-grey-03`, etc. Never reference these directly in components. -2. **Semantic** — purpose-based aliases: `--color-primary`, `--color-error`, `--color-text`, etc. Use these for general UI. -3. **Form control** — shared interactive-state tokens for all form components (Input, Checkbox, Radio, Switch, Select, etc.): - - `--color-control-border` / `--color-control-border-hover` - - `--color-control-checked` / `--color-control-checked-hover` - - `--color-control-focus-ring` - - `--color-control-label` / `--color-control-description` / `--color-control-error` - - `--color-control-bg` / `--color-control-bg-readonly` - -**Rule**: Components must reference semantic or form-control tokens, not palette tokens. If you need a colour that has no semantic token, add one — don't reach for the palette directly. - -### Token Naming Convention -- Colours: `--color-{name}` (e.g., `--color-primary`, `--color-text-secondary`) -- Form controls: `--color-control-{role}` (e.g., `--color-control-border`, `--color-control-checked`) -- Radii: `--radius-{size}` (e.g., `--radius-default`, `--radius-lg`) -- Shadows: `--shadow-{size}` (e.g., `--shadow-default`, `--shadow-md`) - ---- - -## Component Conventions - -### File Structure -Each component lives in its own directory: -``` -src/components/ui/Button/ - Button.tsx — Component implementation - Button.stories.tsx — Storybook stories - index.ts — Barrel export -``` - -### Component Taxonomy -- `src/components/ui/` — Primitive components (Button, Input, Card, Badge) -- `src/components/composite/` — Composed components (StatusMessage, TabBar) -- `src/components/layout/` — Layout components (AppShell, Sidebar) - -### TypeScript -- Export a named props interface: `ButtonProps`, `CardProps`, etc. -- Use `React.forwardRef` for components that wrap native elements. -- Extend native element props where appropriate (e.g., `ButtonHTMLAttributes`). - -### Styling -- Use Tailwind utility classes as the primary styling method. -- Use the `cn()` utility from `@/lib/utils` for conditional classes. -- Never use inline styles except for truly dynamic values. -- Never use CSS modules or styled-components. -- **Token discipline**: Reference semantic or form-control tokens (`text-control-label`, `border-control-border`), never palette tokens (`text-blue-01`, `border-grey-03`) in component code. If the right semantic token doesn't exist, add one to `tokens.css` first. - -### Stories -- Every component MUST have a Storybook story file. -- Include at minimum: a `Default` story, and stories for each significant variant/state. -- Use Storybook Controls for interactive prop exploration. -- Use `tags: ['autodocs']` for automatic documentation generation. - -### Accessibility -- All interactive components must be keyboard-navigable. -- Use semantic HTML elements (`