diff --git a/docs/visual-audit/visual-style-guide.md b/docs/visual-audit/visual-style-guide.md new file mode 100644 index 0000000..9326251 --- /dev/null +++ b/docs/visual-audit/visual-style-guide.md @@ -0,0 +1,139 @@ +# Visual Style Guide (T02) + +## Purpose +This document defines the Recipe Manager visual design tokens and how to apply them consistently across pages/components. + +Primary source of truth: +- `frontend/src/theme.ts` +- `frontend/src/index.css` (CSS custom properties) +- `frontend/tailwind.config.js` (Tailwind token mapping) + +--- + +## 1) Color Tokens + +### Brand + Semantic +- `colors.primary`: `#2563eb` +- `colors.primaryDark`: `#1d4ed8` +- `colors.primaryLight`: `#dbeafe` +- `colors.accent`: `#9333ea` +- `colors.success`: `#15803d` +- `colors.warning`: `#ca8a04` +- `colors.error`: `#dc2626` + +### Surfaces + Text +- `colors.bg`: `#f4f7fb` +- `colors.bgAlt`: `#edf2f7` +- `colors.surface`: `#ffffff` +- `colors.surfaceMuted`: `#f8fafc` +- `colors.border`: `#dbe3ef` +- `colors.text`: `#1f2937` +- `colors.textHeading`: `#0f172a` +- `colors.textDim`: `#64748b` + +### Usage +- Primary actions: `primary` / `primaryDark` for hover. +- Validation or status badges/alerts: `success`, `warning`, `error` with light backgrounds where needed. +- Use `surface` + `border` for cards/forms. +- Use `textHeading` for section/page headings and `text`/`textDim` for body/supporting copy. + +--- + +## 2) Typography Tokens + +### Families +- Sans: `typography.fontFamily.sans` +- Heading: `typography.fontFamily.heading` +- Mono: `typography.fontFamily.mono` + +### Scale +- `xs` 0.75rem +- `sm` 0.875rem +- `base` 1rem +- `lg` 1.125rem +- `xl` 1.25rem +- `2xl` 1.5rem +- `3xl` 1.875rem +- `4xl` 2.25rem + +### Guidance +- Page titles: `3xl–4xl` +- Section titles: `xl–2xl` +- Body text: `base` +- Helper/meta text: `sm` + +--- + +## 3) Spacing Tokens + +- `xxs` 0.25rem +- `xs` 0.5rem +- `sm` 0.75rem +- `md` 1rem +- `lg` 1.5rem +- `xl` 2rem +- `2xl` 2.5rem +- `3xl` 3rem + +### Guidance +- Tight control spacing (chips/icons): `xxs–xs` +- Form controls/content clusters: `sm–md` +- Section/page spacing: `lg–2xl` + +--- + +## 4) Radius Tokens + +- `xs` 0.375rem +- `sm` 0.5rem +- `md` 0.75rem +- `lg` 1rem +- `xl` 1.25rem +- `full` 9999px + +### Guidance +- Inputs/buttons: `md` +- Cards/containers: `lg` +- Pills/tags: `full` + +--- + +## 5) Shadow Tokens + +- `shadows.subtle`: low emphasis hover/elevation +- `shadows.card`: default card elevation +- `shadows.hover`: raised interactive state +- `shadows.focus`: focus ring treatment + +### Guidance +- Prefer `card` for panels/surfaces. +- Use `subtle` for lightweight interactive surfaces. +- Keep `hover` limited to strong CTAs/cards. + +--- + +## 6) Tailwind Mapping + +Tailwind config maps tokenized CSS variables for: +- `colors` (`primary`, `accent`, `success`, `warning`, `error`, `surface`, `muted`, `border`) +- `fontFamily` +- `fontSize` +- `spacing` +- `borderRadius` +- `boxShadow` + +This keeps utility classes aligned with global tokens and avoids hardcoding values in component markup. + +--- + +## 7) Implementation Notes (T02) + +Updated to consume tokens where practical: +- `frontend/src/theme.ts`: expanded token definitions and shared `designTokens` export. +- `frontend/src/index.css`: added token-backed CSS variables (colors, type scale, spacing, radius, shadows). +- `frontend/tailwind.config.js`: switched extension values to CSS-variable/token-backed mappings. +- `frontend/src/components/Toast.tsx`: semantic status colors + radius/shadow from tokens. +- `frontend/src/components/RecipeCard.tsx`: recipe accent palette sourced from tokens. +- `frontend/src/components/TagSelector.tsx`: default tag color sourced from tokens. + +Scope intentionally kept minimal/non-breaking to support upcoming visual tasks (T04–T07). diff --git a/frontend/src/components/RecipeCard.tsx b/frontend/src/components/RecipeCard.tsx index bc179ef..a43a023 100644 --- a/frontend/src/components/RecipeCard.tsx +++ b/frontend/src/components/RecipeCard.tsx @@ -1,6 +1,6 @@ import { Link } from 'react-router-dom'; import type { Recipe, Tag } from '../types/recipe'; -import { colors, radius, shadows } from '../theme'; +import { colors, radius, recipeAccentPalette, shadows, typography } from '../theme'; interface RecipeCardProps { recipe: Recipe; @@ -25,8 +25,7 @@ function formatDate(timestamp?: number): string { function accentForRecipe(recipe: Recipe, tags: Tag[]) { if (tags[0]?.color) return tags[0].color; - const palette = ['#f97316', '#ef4444', '#22c55e', '#06b6d4', '#3b82f6', '#a855f7']; - return palette[recipe.id % palette.length]; + return recipeAccentPalette[recipe.id % recipeAccentPalette.length]; } function emojiForRecipe(recipe: Recipe) { @@ -68,7 +67,12 @@ export function RecipeCard({ recipe, tags = [] }: RecipeCardProps) {
{recipe.description}
diff --git a/frontend/src/components/TagSelector.tsx b/frontend/src/components/TagSelector.tsx index 94824f4..701b6a4 100644 --- a/frontend/src/components/TagSelector.tsx +++ b/frontend/src/components/TagSelector.tsx @@ -5,6 +5,7 @@ import { useState } from 'react'; import { useTags } from '../hooks/useTags'; import { useToastContext } from '../App'; +import { colors } from '../theme'; import type { Tag } from '../types/recipe'; interface TagSelectorProps { @@ -17,14 +18,14 @@ export function TagSelector({ selectedTags, onTagsChange }: TagSelectorProps) { const toast = useToastContext(); const [showNewTagForm, setShowNewTagForm] = useState(false); const [newTagName, setNewTagName] = useState(''); - const [newTagColor, setNewTagColor] = useState('#3B82F6'); + const [newTagColor, setNewTagColor] = useStateError loading tags: {error}
+Error loading tags: {error}