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

3.2 KiB

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.