docs(skills): extract house recipes as Claude Code skills for SSP templating
8 template-generic skills in .claude/skills/ (new-feature, new-context, value-object, form-machine, bff-endpoint, mutation-command, ui-component, new-ssp), condensed from CLAUDE.md/ARCHITECTURE/fp-tea/ADRs and pointing at this repo's worked examples. CLAUDE.md gains a pointer. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
53
.claude/skills/ui-component/SKILL.md
Normal file
53
.claude/skills/ui-component/SKILL.md
Normal file
@@ -0,0 +1,53 @@
|
||||
---
|
||||
name: ui-component
|
||||
description: Add a shared UI building block (atom, molecule, organism) with its Storybook story. Use only after confirming no existing block in shared/ui fits — new blocks are the exception, composition is the default.
|
||||
---
|
||||
|
||||
# UI component (atom / molecule / organism)
|
||||
|
||||
First: check `shared/ui/` and `shared/layout/` — a new page should be composition of
|
||||
existing blocks. Only add a block when nothing fits.
|
||||
|
||||
## Rules
|
||||
|
||||
- **Folder = atomic layer**: `shared/ui/` atoms → molecules → organisms;
|
||||
`shared/layout/` templates. Each level only uses levels below.
|
||||
- Standalone component, **English name** (shared = language-agnostic), signal
|
||||
`input()`s only, `inject()` over constructor DI.
|
||||
- **Atoms are thin wrappers over CIBG Huisstijl (Bootstrap 5.2) classes** (`btn`,
|
||||
`form-control`, `card`, …) — you own a small typed `input()` API, the design system
|
||||
owns the visuals. No CIBG class for it? Hand-roll a small surface from the token
|
||||
bridge (ADR-0003, e.g. the `alert` atom).
|
||||
- **Tokens only** — `var(--rhc-*)` / `var(--app-*)`, never hardcoded colors
|
||||
(`npm run check:tokens` fails the build; escape hatch: `token-ok` marker + reason).
|
||||
- **No hardcoded Dutch** in shared components — expose copy as `input()`s with
|
||||
`$localize` defaults; the domain caller supplies the text (see `shared/ui/async`).
|
||||
- Components with content-projected slots export a spread constant so callers import
|
||||
one thing: `export const ASYNC = [AsyncComponent, AsyncLoadedDirective, …] as const;`
|
||||
|
||||
## Story (required — this is the component's test)
|
||||
|
||||
Co-located `<name>.stories.ts`, title prefixed with the layer:
|
||||
|
||||
```ts
|
||||
const meta: Meta<ButtonComponent> = { title: 'Atoms/Button', component: ButtonComponent };
|
||||
export const Primary: StoryObj<ButtonComponent> = { args: { variant: 'primary' } };
|
||||
```
|
||||
|
||||
One named export per meaningful state. CI runs axe on every story
|
||||
(`test-storybook:ci`) — a11y failures break the build. Machines/wizards mount
|
||||
specific states via the `Seed` message. No heavy component specs; Storybook is the
|
||||
UI test surface.
|
||||
|
||||
## Worked examples
|
||||
|
||||
- Atom: `src/app/shared/ui/button/` — typed variant API over `btn` classes.
|
||||
- Molecule: `src/app/shared/ui/async/` — slot directives, localizable input defaults, spread constant.
|
||||
- Template: `src/app/shared/layout/wizard-shell/` — the canonical wizard outline.
|
||||
|
||||
## Verify
|
||||
|
||||
```bash
|
||||
npm run lint && npm run check:tokens && npm run build
|
||||
npm run storybook # eyeball the story; CI will run axe
|
||||
```
|
||||
Reference in New Issue
Block a user