diff --git a/docs/frontend-design-cookbook.md b/docs/frontend-design-cookbook.md new file mode 100644 index 0000000..e916f3d --- /dev/null +++ b/docs/frontend-design-cookbook.md @@ -0,0 +1,189 @@ +# Frontend Design Cookbook + +This cookbook defines the visual system for the frontend so every new change extends the existing style instead of inventing a new one. + +## Design intent + +- Core tone: light editorial, calm and information-first. +- Product feel: premium personal logbook, not generic SaaS dashboard. +- Contrast model: neutral paper and ink do most of the work; accents are restrained. + +## Non-negotiables + +- Keep layouts readable first. Aesthetic details support hierarchy, not the other way around. +- Use one visual language across the app shell, cards, forms, tables, and actions. +- Prefer subtle depth (borders, layered paper, soft shadows) over loud gradients. +- Keep motion purposeful and short; always preserve `prefers-reduced-motion` behavior. + +## Typography + +- Display/headings: `Cormorant Infant`. +- Body/UI text: `Manrope`. +- Use display typography for page titles and section heads only. +- Keep paragraph text in body font for legibility. + +## Color system + +Global neutrals are defined in `frontend/src/app.css` using CSS variables. + +- `--background`, `--card`, `--foreground`, `--muted-foreground`, `--border` +- `--page-accent` drives route-level emphasis. +- `--page-accent-soft` is the low-contrast companion tint. + +### Domain accents (muted and professional) + +- Dashboard: `--accent-dashboard` +- Products: `--accent-products` +- Routines: `--accent-routines` +- Skin: `--accent-skin` +- Health labs: `--accent-health-labs` +- Health medications: `--accent-health-meds` + +The app shell assigns a domain class per route and maps it to `--page-accent`. + +## Where to use accent color + +Use accent for: + +- active navigation state +- important buttons and key badges +- focus ring tint and hover border tint +- section separators and small status markers + +Do not use accent for: + +- full-page backgrounds +- body text +- large surfaces that reduce readability + +Guideline: accent should occupy roughly 10-15% of visual area per screen. + +## Layout rules + +- Use the app shell spacing rhythm from `app.css` (`.app-main`, editorial cards). +- Keep max content width constrained for readability. +- Prefer asymmetry in hero/summary areas, but keep forms and dense data grids regular. + +### Shared page wrappers + +Use these wrappers before introducing route-specific structure: + +- `editorial-page`: standard constrained content width for route pages. +- `editorial-hero`: top summary strip for title, subtitle, and primary actions. +- `editorial-panel`: primary surface for forms, tables, and ledgers. +- `editorial-toolbar`: compact action row under hero copy. +- `editorial-backlink`: standard top-left back navigation style. +- `editorial-alert`, `editorial-alert--error`, `editorial-alert--success`: feedback banners. + +## Component rules + +- Reuse UI primitives under `frontend/src/lib/components/ui/*`. +- Keep primitive APIs stable when changing visual treatment. +- Style via tokens and shared classes, not one-off hardcoded colors. +- New variants must be documented in this file. + +### Existing shared utility patterns + +These classes are already in use and should be reused: + +- Lists and ledgers: `routine-ledger-row`, `products-mobile-card`, `health-entry-row` +- Group headers: `products-section-title` +- Table shell: `products-table-shell` +- Tabs shell: `products-tabs`, `editorial-tabs` +- Health semantic pills: `health-kind-pill*`, `health-flag-pill*` + +## Forms and data views + +- Inputs should remain high-contrast and calm. +- Validation/error states should be explicit and never color-only. +- Tables and dense lists should prioritize scanning: spacing, row separators, concise metadata. + +### DRY form primitives + +- Use shared form components for repeated native select markup: + - `frontend/src/lib/components/forms/SimpleSelect.svelte` + - `frontend/src/lib/components/forms/GroupedSelect.svelte` +- Use shared checkbox helper for repeated label+hint toggles: + - `frontend/src/lib/components/forms/HintCheckbox.svelte` +- Use shared input field helper for repeated label+input rows: + - `frontend/src/lib/components/forms/LabeledInputField.svelte` +- Use shared section card helper for repeated titled form panels: + - `frontend/src/lib/components/forms/FormSectionCard.svelte` +- Use shared class tokens from: + - `frontend/src/lib/components/forms/form-classes.ts` +- Prefer passing option labels from route files via `m.*` to keep i18n explicit. + +### Select policy (performance + maintainability) + +- Default to native ` - {#if aiError} -

{aiError}

- {/if} -
- - -
- - - + {#await import('$lib/components/ProductFormAiModal.svelte') then mod} + {@const AiModal = mod.default} + + {/await} {/if} - - - {m["productForm_basicInfo"]()} - -
-
- - -
-
- - -
-
-
-
- - -
-
- - -
-
-
-
- - -
-
- - -
-
-
-
+{#await import('$lib/components/product-form/ProductFormBasicSection.svelte') then mod} + {@const BasicSection = mod.default} + +{/await} - - - {m["productForm_classification"]()} - -
-
- - - -
- -
- - - -
- -
- - - -
- -
- - - -
- -
- - - -
-
-
-
+{#await import('$lib/components/product-form/ProductFormClassificationSection.svelte') then mod} + {@const ClassificationSection = mod.default} + +{/await} @@ -651,7 +544,7 @@
- {#each skinTypes as st} + {#each skinTypes as st (st)}