From 2a7c4f969874b850e30170f3aef5b578677220b0 Mon Sep 17 00:00:00 2001 From: Martin Kagamino Lehoux Date: Sat, 12 Sep 2026 22:26:09 +0200 Subject: Scope badges, titles, and one-off styles; add Button outline ScoreBadge/StatusBadge carry their own color scales, no bg-*/text-* globals. SectionTitle unifies category-name and section-title dupes (h2/h3 via level prop). Grocery add-bar buttons use Button, new outline variant for the secondary action. save-status moves into its only page. Delete dead globals and page overrides. --- src/app.css | 76 ---------------------- src/lib/components/Button.svelte | 23 ++++++- src/lib/components/ScoreBadge.svelte | 35 +++++++--- src/lib/components/SectionTitle.svelte | 23 +++++++ src/lib/components/StatusBadge.svelte | 48 ++++++++++---- src/routes/groceries/+page.svelte | 58 ++++------------- src/routes/groceries/catalog/+page.svelte | 3 +- src/routes/grocery/[id]/+page.svelte | 15 +++++ src/routes/projects/[id]/+page.svelte | 14 +--- .../[projectId]/routine/[routineId]/+page.svelte | 16 +---- 10 files changed, 144 insertions(+), 167 deletions(-) create mode 100644 src/lib/components/SectionTitle.svelte (limited to 'src') diff --git a/src/app.css b/src/app.css index daeffd7..0f25b28 100644 --- a/src/app.css +++ b/src/app.css @@ -15,18 +15,6 @@ gap: 0.5rem; } -/* Category heading */ -.category-name { - font-size: 0.75rem; - font-weight: 700; - text-transform: uppercase; - letter-spacing: 0.08em; - color: var(--accent); - margin: 1.25rem 0 0.5rem; - padding-left: 0.5rem; - border-left: 3px solid var(--accent); -} - /* Empty state */ .empty { color: var(--text-secondary); @@ -99,41 +87,6 @@ box-shadow: 0 0 0 3px var(--shadow-accent-focus); } -.score { - flex-shrink: 0; - min-width: 2.75rem; - padding: 0.25rem 0.5rem; - border-radius: 9999px; - text-align: center; - font-size: 0.875rem; - font-weight: 700; - color: var(--white); -} - -.bg-success { - background: var(--success); -} - -.bg-accent { - background: var(--accent); -} - -.bg-danger { - background: var(--danger); -} - -.bg-accent-soft { - background: var(--shadow-accent); -} - -.text-accent { - color: var(--accent); -} - -.text-white { - color: var(--white); -} - .add-bar { display: flex; gap: 0.5rem; @@ -146,19 +99,6 @@ min-width: 0; } -.status { - flex-shrink: 0; - display: inline-flex; - align-items: center; - justify-content: center; - width: 1.5rem; - height: 1.5rem; - border-radius: 0.375rem; - font-size: 0.875rem; - font-weight: 700; - line-height: 1; -} - /* Shared route scaffolding */ .page-header { display: flex; @@ -186,19 +126,3 @@ .input-invalid { border-color: var(--danger); } - -.save-status { - font-size: 0.875rem; - color: var(--success); - font-weight: 500; - margin-top: -0.25rem; - visibility: hidden; - opacity: 0; - transition: opacity 0.2s ease; - min-height: 1.25rem; -} - -.save-status.visible { - visibility: visible; - opacity: 1; -} diff --git a/src/lib/components/Button.svelte b/src/lib/components/Button.svelte index 30e9fc2..27b9b7f 100644 --- a/src/lib/components/Button.svelte +++ b/src/lib/components/Button.svelte @@ -15,7 +15,7 @@ onclick, children, }: { - variant?: 'primary' | 'accent' | 'ghost' | 'done'; + variant?: 'primary' | 'accent' | 'ghost' | 'done' | 'outline'; type?: 'button' | 'submit' | 'reset'; disabled?: boolean; name?: string; @@ -143,6 +143,27 @@ font-size: 0.9375rem; } + .outline { + width: 3rem; + height: 3rem; + flex-shrink: 0; + padding: 0; + border-radius: 0.75rem; + background: var(--surface); + color: var(--text-secondary); + border: 1.5px solid var(--border); + font-size: 1.25rem; + font-weight: 500; + display: flex; + align-items: center; + justify-content: center; + } + + .outline:hover:not(:disabled) { + border-color: var(--accent); + color: var(--text); + } + .block { align-self: stretch; width: 100%; diff --git a/src/lib/components/ScoreBadge.svelte b/src/lib/components/ScoreBadge.svelte index 6384667..ae11918 100644 --- a/src/lib/components/ScoreBadge.svelte +++ b/src/lib/components/ScoreBadge.svelte @@ -1,13 +1,32 @@ -{score} +{score} + + diff --git a/src/lib/components/SectionTitle.svelte b/src/lib/components/SectionTitle.svelte new file mode 100644 index 0000000..be77a46 --- /dev/null +++ b/src/lib/components/SectionTitle.svelte @@ -0,0 +1,23 @@ + + + + {@render children()} + + + diff --git a/src/lib/components/StatusBadge.svelte b/src/lib/components/StatusBadge.svelte index 4c149d2..2bbdf5a 100644 --- a/src/lib/components/StatusBadge.svelte +++ b/src/lib/components/StatusBadge.svelte @@ -9,16 +9,6 @@ overdueDays = 0, }: { status: RoutineStatus; overdueDays?: number } = $props(); - const className = $derived( - status === 'ok' - ? 'status bg-success text-white' - : status === 'due' - ? 'status bg-accent-soft text-accent' - : status === 'late' - ? 'status bg-accent text-white' - : 'status bg-danger text-white', - ); - const icon = $derived( status === 'ok' ? '✓' @@ -36,5 +26,41 @@ ); -{icon}{icon} + + diff --git a/src/routes/groceries/+page.svelte b/src/routes/groceries/+page.svelte index b134da7..5d88e49 100644 --- a/src/routes/groceries/+page.svelte +++ b/src/routes/groceries/+page.svelte @@ -4,7 +4,9 @@ import { enhance } from '$app/forms'; import FuzzyAutocomplete from '$lib/components/FuzzyAutocomplete.svelte'; import GroceryRow from '$lib/components/GroceryRow.svelte'; + import Button from '$lib/components/Button.svelte'; import { groupByCategory } from '$lib/shared/group-by-category'; + import SectionTitle from '$lib/components/SectionTitle.svelte'; import type { EnrichedGrocery } from '$lib/server/services/groceries'; let { data, form } = $props(); @@ -75,11 +77,17 @@ handleAdd(false); }} /> - handleAdd(false)}>+ - handleAdd(true)}>→ @@ -93,7 +101,7 @@ {:else}
{#each groupByCategory(localItems, data.categories) as [cat, items] (cat)} -

{cat}

+ {cat}