185 lines
7.2 KiB
Markdown
185 lines
7.2 KiB
Markdown
# T01 — Styling Inventory + Drift Map
|
|
|
|
Date: 2026-03-27
|
|
Project: `recipe-manager/frontend`
|
|
Task: **T01 — Styling Inventory + Drift Map**
|
|
|
|
## Scope audited
|
|
- Token sources: `src/styles/tokens.css`, `src/theme.ts`, `frontend/tailwind.config.js`
|
|
- Shared styling layer: `src/index.css` (`ui-*` primitives)
|
|
- Legacy stylesheet: `src/App.css`
|
|
- App shell + representative screens/components:
|
|
- `src/App.tsx`
|
|
- `src/pages/RecipeListPage.tsx`
|
|
- `src/pages/RecipeDetailPage.tsx`
|
|
- `src/pages/CookModePage.tsx`
|
|
- `src/pages/ImportUrlPage.tsx`
|
|
- `src/pages/NotFoundPage.tsx`
|
|
- `src/components/RecipeCard.tsx`
|
|
- `src/components/RecipeForm.tsx`
|
|
- `src/components/TagSelector.tsx`
|
|
- `src/components/Toast.tsx`
|
|
- `src/components/MissionControlPanel.tsx`
|
|
- `src/components/ErrorBoundary.tsx`
|
|
|
|
---
|
|
|
|
## 1) Where styling primitives currently live
|
|
|
|
### Canonical CSS token surface (already strong)
|
|
- **`src/styles/tokens.css`**
|
|
- semantic color, typography, spacing, radius, shadow, focus, gradients
|
|
- includes dark-mode token overrides
|
|
|
|
### Utility-class primitives (already present)
|
|
- **`src/index.css` @layer components** defines:
|
|
- `.ui-page`, `.ui-section`, `.ui-card`
|
|
- `.ui-btn`, `.ui-btn-primary`, `.ui-btn-secondary`
|
|
- `.ui-input`, `.ui-textarea`, `.ui-select`
|
|
- `.ui-chip`, `.ui-badge`
|
|
- Also contains global focus-visible behavior and utility legacy classes (`.card`, `.shadow-card`, `animate-slide-in`)
|
|
|
|
### Tailwind token mapping
|
|
- **`frontend/tailwind.config.js`** maps many Tailwind theme keys to CSS vars (good bridge)
|
|
|
|
### Parallel TS token layer (drift risk)
|
|
- **`src/theme.ts`** duplicates many token values from `tokens.css`
|
|
- `colors`, `typography`, `spacing`, `radius`, `shadows`, `componentStyles`
|
|
|
|
### Legacy stylesheet
|
|
- **`src/App.css`** contains Vite/demo-era nested selectors (`#next-steps`, `.hero`, `.counter`, etc.)
|
|
- not imported by `main.tsx` or other src files in current app
|
|
|
|
---
|
|
|
|
## 2) Systems currently being mixed
|
|
|
|
1. **UI primitives + token vars** (`ui-*`, `var(--...)`)
|
|
2. **Raw Tailwind palette utilities** (`bg-blue-*`, `text-slate-*`, `border-gray-*`, etc.)
|
|
3. **Inline style objects via `theme.ts`** (`style={{ borderRadius: radius.lg }}`, `boxShadow: shadows.card`)
|
|
4. **One-off arbitrary values** (`hover:[box-shadow:var(--shadow-hover)]`, `shadow-[...]`)
|
|
5. **Legacy class debt** (`App.css`, and old helper classes in `index.css`)
|
|
|
|
Result: there is no enforced single styling path; authors can pick multiple parallel approaches in the same file.
|
|
|
|
---
|
|
|
|
## 3) Inventory by file (top-level pages + shared components)
|
|
|
|
Legend:
|
|
- **A** = ui-* primitives + var tokens (preferred direction)
|
|
- **B** = raw Tailwind palette utilities (non-tokenized drift)
|
|
- **C** = inline `theme.ts` style objects
|
|
- **D** = legacy/older pattern
|
|
|
|
### App shell
|
|
- `src/App.tsx` → **B-heavy**
|
|
- Header/nav/footer use many `blue/slate/gray` classes and custom focus ring colors
|
|
- Does not use `ui-page`, `ui-section`, `ui-btn` contract
|
|
|
|
### Pages
|
|
- `src/pages/RecipeListPage.tsx` → **A + C mix (plus some B)**
|
|
- strong `ui-*` adoption
|
|
- frequent inline radius/style injections from `theme.ts`
|
|
- `src/pages/RecipeDetailPage.tsx` → **A + B + C mixed**
|
|
- uses many `ui-*` classes but also many non-token Tailwind palette classes and inline styles
|
|
- `src/pages/CookModePage.tsx` → **B-only (high drift)**
|
|
- almost entirely gray/blue/green/red Tailwind palette utilities
|
|
- no `ui-*` shell/primitives
|
|
- `src/pages/ImportUrlPage.tsx` → **B + C (high drift)**
|
|
- heavily uses slate/blue/indigo/green palette classes
|
|
- inline radius/progress width styles
|
|
- `src/pages/NotFoundPage.tsx` → **B-only**
|
|
|
|
### Shared components
|
|
- `src/components/RecipeForm.tsx` → **A-dominant**
|
|
- `src/components/TagSelector.tsx` → **A-dominant + tiny C**
|
|
- `src/components/RecipeCard.tsx` → **A + C mixed**
|
|
- `src/components/Toast.tsx` → **C-dominant**
|
|
- visual appearance mostly from `theme.ts` inline styles
|
|
- `src/components/MissionControlPanel.tsx` → **B-only**
|
|
- `src/components/ErrorBoundary.tsx` → **B-only**
|
|
|
|
### Approximate drift signal (quick scan)
|
|
- Highest raw palette concentration: `CookModePage`, `ImportUrlPage`, `App.tsx`, `RecipeDetailPage`
|
|
- Highest inline-style concentration: `RecipeListPage`, `RecipeCard`, `Toast`
|
|
|
|
---
|
|
|
|
## 4) Representative drift hotspots
|
|
|
|
1. **`App.tsx` (app shell)**
|
|
- Entire global frame (header/nav/footer) is on blue/slate palette utilities
|
|
- creates visual disconnect from tokenized warm palette used in recipe surfaces
|
|
|
|
2. **`CookModePage.tsx`**
|
|
- Separate visual language (blue/gray success/error blocks) and no `ui-*` primitives
|
|
- likely to regress independently if token theme changes
|
|
|
|
3. **`ImportUrlPage.tsx`**
|
|
- Similar drift pattern to CookModePage; raw utility palette + custom gradients
|
|
|
|
4. **`RecipeDetailPage.tsx`**
|
|
- Mixed approach in same component: token vars + ui-* + raw palette + inline styles
|
|
- hard to predict and maintain consistency
|
|
|
|
5. **`Toast.tsx` + `theme.ts` coupling**
|
|
- toast visuals encoded in TS style objects instead of ui primitives/token classes
|
|
|
|
6. **`App.css` + legacy selectors in `index.css`**
|
|
- `App.css` appears unused yet present
|
|
- `.card` / `.shadow-card` coexist with `ui-card`, increasing ambiguity
|
|
|
|
---
|
|
|
|
## 5) Highest-risk problem areas
|
|
|
|
- **Token drift risk**: same values duplicated in `tokens.css` and `theme.ts`.
|
|
- **App-shell inconsistency risk**: `App.tsx` not on design-system primitives.
|
|
- **Page-level divergence risk**: CookMode/Import URL/NotFound/MissionControl use different style dialect than core recipe pages.
|
|
- **Maintainability risk**: inline style overrides (`borderRadius`, `boxShadow`) bypass primitive contract and encourage per-component customization.
|
|
- **Regression risk**: no guardrails prevent new raw palette utilities in future UI work.
|
|
|
|
---
|
|
|
|
## 6) First conversion targets (for stabilization wave)
|
|
|
|
1. `src/App.tsx` (global shell contract)
|
|
2. `src/components/MissionControlPanel.tsx` (small, easy, high-visibility drift)
|
|
3. `src/pages/CookModePage.tsx` (largest isolated drift surface)
|
|
4. `src/pages/ImportUrlPage.tsx` (same drift pattern as CookMode)
|
|
5. `src/components/Toast.tsx` (inline-style dependency cleanup)
|
|
|
|
---
|
|
|
|
## 7) Acceptance criteria for stabilization work (T02+)
|
|
|
|
A stabilization pass is accepted when all are true:
|
|
|
|
1. **Single token authority**
|
|
- CSS vars in `tokens.css` are canonical.
|
|
- `theme.ts` no longer independently defines conflicting visual token values.
|
|
|
|
2. **Primitive contract adoption**
|
|
- app shell + major pages use shared `ui-*` primitives (or wrapper components built from them).
|
|
- new features avoid ad-hoc color utilities outside tokenized scheme.
|
|
|
|
3. **Inline-style reduction**
|
|
- no routine radius/shadow/color inline overrides where equivalent primitive/token class exists.
|
|
|
|
4. **Legacy debt disposition**
|
|
- `App.css` removed or explicitly retained with documented rationale.
|
|
- overlapping legacy helpers (`.card`, `.shadow-card`) either standardized or deprecated.
|
|
|
|
5. **Governance check**
|
|
- lightweight styling checklist/doc exists and is referenced in workflow.
|
|
|
|
---
|
|
|
|
## 8) Suggested next task after T01
|
|
|
|
**T02 — Canonical Token Source Lock**
|
|
- lock CSS tokens as source of truth
|
|
- redefine `theme.ts` as typed accessor only (or trim to non-visual helpers)
|
|
- document token contract before broad conversion starts
|