3.2 KiB
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.tsfrontend/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:
UiSectionfor panel shellUiChipfor 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) viaUiButton
- hero wrapper and filter blocks via
- This proves the contract on a high-traffic page without broad redesign.
Usage guidance for follow-on tasks
- Prefer
UiSection/UiCard/UiButtonbefore writing new utility-heavy class blocks. - Use tokenized vars (
var(--...)) for one-off values; avoid raw palette classes in shared surfaces. - Keep inline
style={{ ... }}for runtime values only (e.g., tag color from data), not static radius/shadow/colors. - 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 fullRecipeDetailPage. - 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.