recipe-manager/.harness/docs/ui-primitive-contract.md

92 lines
3.2 KiB
Markdown

# T03 — UI Primitive Contract (Recipe Manager UI Kit)
Date: 2026-03-27
Scope: `recipe-manager/frontend`
## Goal
Stabilize core UI primitives so pages stop re-implementing button/card/chip/layout class strings.
This is a **low-risk contract layer**, not a redesign system.
---
## Contract surface (v1)
Implemented in:
- `frontend/src/components/ui/cn.ts`
- `frontend/src/components/ui/primitives.tsx`
### `cn(...values)`
- Lightweight class composer used by primitives and page-level variant helpers.
- Avoids repetitive template-string class logic.
### `UiPage`
- Canonical page shell wrapper (`ui-page` + optional additions).
- Use for top-level layout regions (header container, footer container, page root if needed).
### `UiSection`
- Canonical section shell (`ui-section`) with controlled padding options:
- `padding="md"` (default)
- `padding="lg"`
- `padding="none"`
- Use for grouped content blocks and major page sections.
### `UiCard`
- Canonical card surface (`ui-card`) with optional tone:
- `tone="default"`
- `tone="muted"`
- Use for repeatable content cards and skeleton containers.
### `UiButton`
- Canonical button primitive (`ui-btn` + variant mapping):
- `variant="primary"`
- `variant="secondary"` (default)
- Use for interactive `<button>` actions.
### `UiLinkButton`
- Anchor-style button for actual links (kept for future use where semantic `<a>` is needed).
### `UiChip` / `UiBadge`
- Canonical chip and badge wrappers around `ui-chip` / `ui-badge`.
- Use for compact status pills/filter tokens.
---
## Representative adoption in T03
### 1) App shell (`src/App.tsx`)
- Header and footer wrappers now use `UiPage`.
- Navigation active/inactive styles now use a `cn(...)` helper contract rather than bespoke duplicated class strings.
- Shell color treatment shifted to tokenized variables (`var(--...)`) instead of slate/blue freelancing.
### 2) Mission Control (`src/components/MissionControlPanel.tsx`)
- Converted from gray utility block to tokenized contract primitives:
- `UiSection` for panel shell
- `UiChip` for status pills
- Removes bespoke gray class styling drift from this shared panel.
### 3) Recipe list page (`src/pages/RecipeListPage.tsx`)
- Core repeated shells now use primitives:
- hero wrapper and filter blocks via `UiSection`
- feature cards and loading skeleton via `UiCard`
- key actions (`Search`, `Load More`, `Clear all filters`) via `UiButton`
- This proves the contract on a high-traffic page without broad redesign.
---
## Usage guidance for follow-on tasks
1. Prefer `UiSection`/`UiCard`/`UiButton` before writing new utility-heavy class blocks.
2. Use tokenized vars (`var(--...)`) for one-off values; avoid raw palette classes in shared surfaces.
3. Keep inline `style={{ ... }}` for runtime values only (e.g., tag color from data), not static radius/shadow/colors.
4. When classes need conditional composition, use `cn(...)` in one helper instead of many inlined strings.
---
## Intentionally deferred (not in T03)
- Broad conversion of `CookModePage`, `ImportUrlPage`, and full `RecipeDetailPage`.
- Full button/link semantic normalization (e.g., dedicated router-aware LinkButton primitive).
- Removal of all legacy one-off class usage in older components.
These are better handled in T04/T05 to keep T03 low-risk.