Replace ad-hoc Tailwind strings with design tokens

Define .field, .field-lg, .select, .select-lg, .btn-primary,
.btn-secondary, and .btn-danger-link in app.css as @layer components.
The .select tokens use appearance-none + an inline SVG chevron so
all dropdowns look identical to text inputs (no OS-level gray gradient).

Apply tokens across every in-app form: QuantityInput, shopping list
add form and item rows, recipe new/edit pages, recipe detail, stores,
and lists create form. Drop the STYLE_GUIDE.md doc in favour of the
tokens themselves as the source of truth, and update CLAUDE.md to
document the token names and usage rules.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
Josh Rogers
2026-05-14 20:25:57 -05:00
parent a398f8cf44
commit bf01063c3a
10 changed files with 90 additions and 102 deletions
+6 -1
View File
@@ -88,7 +88,12 @@ When adding a feature: create `Features/<Name>/<Name>Endpoints.cs` with a `Map<N
### Frontend — SvelteKit with runes
**UI consistency:** all form controls, buttons, colors, icons, spacing, and text casing are governed by `src/frontend/STYLE_GUIDE.md`. Read it before adding or modifying any UI component — deviating without a documented reason is a bug.
**UI tokens:** form controls, buttons, and select elements use named CSS component classes defined in `src/frontend/src/app.css`. Always use these instead of raw Tailwind strings:
- Inputs / textareas: `.field` (standard, `py-2 text-sm`) or `.field-lg` (prominent, `py-2.5 text-base`)
- Selects: `.select` or `.select-lg` — these add `appearance-none` + a consistent chevron so dropdowns look identical to text inputs
- Buttons: `.btn-primary`, `.btn-secondary`, `.btn-danger-link`
- Width, margin, and flex utilities are added alongside the token class (e.g. `class="field w-full"`)
- Never hardcode the border, background, padding, or focus ring on a new control — always start from a token
- `svelte.config.js` forces `runes: true` for all non-`node_modules` files. Use Svelte 5 runes (`$state`, `$derived`, `$effect`); do not use legacy reactive `$:` syntax.
- `src/lib/api.ts``api<T>(path, opts)` helper. Stores the JWT in `localStorage` under `token`, attaches `Authorization: Bearer …`, and on 401 it clears the token and `goto('/login')`.