From 1a9ec9d0e4fbb092ca9ad55307b962426ccfb8b5 Mon Sep 17 00:00:00 2001 From: Yusuf Suleman Date: Mon, 30 Mar 2026 21:10:07 -0500 Subject: [PATCH] wip: bento card layout + zinc/emerald tokens (in progress) Co-Authored-By: Claude Opus 4.6 (1M context) --- frontend-v2/src/app.css | 94 +++++---- frontend-v2/src/app.html | 2 +- .../components/dashboard/BudgetModule.svelte | 22 ++- .../dashboard/DashboardActionCard.svelte | 186 +++++++++--------- .../src/lib/components/layout/Navbar.svelte | 27 ++- frontend-v2/src/routes/(app)/+page.svelte | 51 ++--- 6 files changed, 188 insertions(+), 194 deletions(-) diff --git a/frontend-v2/src/app.css b/frontend-v2/src/app.css index 809cc72..da5f984 100644 --- a/frontend-v2/src/app.css +++ b/frontend-v2/src/app.css @@ -16,7 +16,7 @@ body { padding-top: env(safe-area-inset-top); padding-bottom: env(safe-area-inset-bottom); } :root { /* ── Fonts ── */ - --font: 'DM Sans', -apple-system, system-ui, sans-serif; + --font: 'Outfit', -apple-system, system-ui, sans-serif; --mono: 'JetBrains Mono', ui-monospace, monospace; --transition: 150ms ease; @@ -56,8 +56,8 @@ --radius-xs: 4px; --radius-sm: 6px; --radius-md: 8px; - --radius: 12px; - --radius-lg: 16px; + --radius: 16px; + --radius-lg: 20px; --radius-full: 9999px; /* ── Elevation scale ── @@ -67,11 +67,12 @@ * lg: elevated (dropdowns, popovers, hero cards) * xl: overlay (modals, slide-out panels) */ - --shadow-xs: 0 1px 2px rgba(0,0,0,0.03); - --shadow-sm: 0 1px 3px rgba(0,0,0,0.04), 0 4px 12px rgba(0,0,0,0.04); - --shadow-md: 0 2px 6px rgba(0,0,0,0.04), 0 8px 24px rgba(0,0,0,0.06); - --shadow-lg: 0 4px 12px rgba(0,0,0,0.06), 0 16px 40px rgba(0,0,0,0.1); - --shadow-xl: 0 8px 24px rgba(0,0,0,0.08), 0 24px 60px rgba(0,0,0,0.15); + /* Zinc-tinted shadows */ + --shadow-xs: 0 1px 2px rgba(24,24,27,0.04); + --shadow-sm: 0 1px 2px rgba(24,24,27,0.04), 0 4px 8px rgba(24,24,27,0.02); + --shadow-md: 0 2px 8px rgba(24,24,27,0.05), 0 12px 24px rgba(24,24,27,0.04); + --shadow-lg: 0 4px 16px rgba(24,24,27,0.06), 0 24px 48px rgba(24,24,27,0.06); + --shadow-xl: 0 8px 24px rgba(24,24,27,0.08), 0 32px 64px rgba(24,24,27,0.1); /* Legacy aliases */ --card-shadow: var(--shadow-md); --card-shadow-sm: var(--shadow-sm); @@ -103,75 +104,68 @@ --leading-loose: 1.8; } - /* ── LIGHT MODE ── */ + /* ── LIGHT MODE — Zinc + Emerald ── */ :root { - /* Surface hierarchy: canvas (page bg) → surface (sidebars, panels) → card (content containers) */ - --canvas: #F3F4F6; + --canvas: #FAFAFA; --surface: #FFFFFF; - --surface-secondary: #F7F8FA; + --surface-secondary: #F4F4F5; --card: #FFFFFF; - --card-secondary: #F7F8FA; - --card-hover: #EDEEF2; + --card-secondary: #F4F4F5; + --card-hover: #F0F0F2; - /* Borders */ --border: rgba(0,0,0,0.06); --border-strong: rgba(0,0,0,0.10); - /* Text hierarchy: 1 (headings/names) → 2 (body) → 3 (labels/meta) → 4 (placeholder/disabled) */ - --text-1: #111118; - --text-2: #3d3d4a; - --text-3: #6b6b78; - --text-4: #a8a8b3; + --text-1: #18181B; + --text-2: #3F3F46; + --text-3: #71717A; + --text-4: #A1A1AA; - /* Accent — deep indigo */ - --accent: #4338CA; - --accent-bg: #EEF2FF; - --accent-dim: rgba(67,56,202,0.06); - --accent-border: rgba(67,56,202,0.12); - --accent-focus: rgba(67,56,202,0.14); + /* Accent — Emerald (single, desaturated) */ + --accent: #059669; + --accent-bg: #ECFDF5; + --accent-dim: rgba(5,150,105,0.07); + --accent-border: rgba(5,150,105,0.14); + --accent-focus: rgba(5,150,105,0.16); - /* Semantic: success */ --success: #059669; --success-bg: #ECFDF5; --success-dim: rgba(5,150,105,0.07); - /* Semantic: error */ --error: #DC2626; --error-bg: #FEF2F2; --error-dim: rgba(220,38,38,0.06); - /* Semantic: warning */ --warning: #D97706; --warning-bg: rgba(217,119,6,0.07); - /* Overlay */ - --overlay: rgba(0,0,0,0.25); - --overlay-strong: rgba(0,0,0,0.45); - --nav-bg: rgba(255,255,255,0.92); + --overlay: rgba(0,0,0,0.2); + --overlay-strong: rgba(0,0,0,0.4); + --nav-bg: rgba(250,250,250,0.8); } - /* ── DARK MODE ── */ + /* ── DARK MODE — Zinc + Emerald ── */ .dark { - --canvas: #0a0a0c; - --surface: #111114; - --surface-secondary: #141417; - --card: #18181c; - --card-secondary: #141417; - --card-hover: #1f1f24; + --canvas: #09090B; + --surface: #111113; + --surface-secondary: #18181B; + --card: #1C1C1F; + --card-secondary: #18181B; + --card-hover: #232326; --border: rgba(255,255,255,0.07); --border-strong: rgba(255,255,255,0.12); - --text-1: #f4f4f5; - --text-2: #a1a1aa; - --text-3: #71717a; - --text-4: #3f3f46; + --text-1: #FAFAFA; + --text-2: #A1A1AA; + --text-3: #71717A; + --text-4: #3F3F46; - --accent: #6366F1; - --accent-bg: rgba(99,102,241,0.1); - --accent-dim: rgba(99,102,241,0.08); - --accent-border: rgba(99,102,241,0.14); - --accent-focus: rgba(99,102,241,0.16); + --accent: #34D399; + --accent-bg: rgba(52,211,153,0.1); + --accent-dim: rgba(52,211,153,0.08); + --accent-border: rgba(52,211,153,0.14); + --accent-focus: rgba(52,211,153,0.16); --success: #22c55e; --success-bg: rgba(34,197,94,0.1); @@ -487,7 +481,7 @@ /* ── App surface (centered container) ── */ .app-surface { - max-width: 1200px; + max-width: 1280px; width: 100%; margin: 0 auto; padding: 0 var(--sp-6); diff --git a/frontend-v2/src/app.html b/frontend-v2/src/app.html index 6b07520..bd524fe 100644 --- a/frontend-v2/src/app.html +++ b/frontend-v2/src/app.html @@ -5,7 +5,7 @@ - + %sveltekit.head% diff --git a/frontend-v2/src/lib/components/dashboard/BudgetModule.svelte b/frontend-v2/src/lib/components/dashboard/BudgetModule.svelte index 2067a15..60bde42 100644 --- a/frontend-v2/src/lib/components/dashboard/BudgetModule.svelte +++ b/frontend-v2/src/lib/components/dashboard/BudgetModule.svelte @@ -61,17 +61,18 @@ } .budget-amount { - font-size: var(--text-3xl); - font-weight: 500; + font-size: 36px; + font-weight: 800; font-family: var(--mono); + letter-spacing: -0.04em; color: var(--text-1); line-height: 1; } .budget-label { - font-size: var(--text-base); - color: var(--text-3); - margin-top: var(--sp-1.5); + font-size: 12px; + color: var(--text-4); + margin-top: 4px; } .budget-rows { @@ -92,18 +93,19 @@ } .budget-row-name { - font-size: var(--text-base); - color: var(--text-2); + font-size: 13px; + color: var(--text-3); } .budget-row-amount { - font-size: var(--text-base); + font-size: 12px; font-family: var(--mono); - color: var(--text-1); + font-weight: 500; + color: var(--text-2); } .budget-row-amount.income { - color: var(--success); + color: var(--accent); } @media (max-width: 768px) { diff --git a/frontend-v2/src/lib/components/dashboard/DashboardActionCard.svelte b/frontend-v2/src/lib/components/dashboard/DashboardActionCard.svelte index ade52d5..6c39b5c 100644 --- a/frontend-v2/src/lib/components/dashboard/DashboardActionCard.svelte +++ b/frontend-v2/src/lib/components/dashboard/DashboardActionCard.svelte @@ -14,147 +14,139 @@ size?: 'primary' | 'secondary'; href: string; } = $props(); + + // Extract the number from title (e.g. "78 uncategorized..." → "78") + function extractNumber(t: string): { num: string; rest: string } { + const match = t.match(/^([\d,\.]+)\s+(.*)$/); + if (match) return { num: match[1], rest: match[2] }; + return { num: '', rest: t }; + } + + const parsed = $derived(extractNumber(title)); - -
-
+ +
+ + {#if variant === 'budget'}Budget{:else if variant === 'inventory'}Inventory{:else}Calories{/if} + +
{#if variant === 'budget'} - + {:else if variant === 'inventory'} - - {:else if variant === 'fitness'} - + + {:else} + {/if}
-
-
{title}
-
{description}
-
-
+ + {#if parsed.num} +
{parsed.num}
+
{parsed.rest}
{description}
+ {:else} +
{title}
{description}
+ {/if} + +
{action} - +
diff --git a/frontend-v2/src/lib/components/layout/Navbar.svelte b/frontend-v2/src/lib/components/layout/Navbar.svelte index d915805..f623210 100644 --- a/frontend-v2/src/lib/components/layout/Navbar.svelte +++ b/frontend-v2/src/lib/components/layout/Navbar.svelte @@ -97,25 +97,25 @@ -webkit-backdrop-filter: blur(20px) saturate(1.4); } .navbar-inner { - max-width: 1400px; + max-width: 1280px; margin: 0 auto; display: flex; align-items: center; - height: 52px; + height: 48px; padding: 0 var(--sp-6); - gap: var(--sp-5); + gap: var(--sp-6); } .navbar-logo { font-weight: 700; - font-size: var(--text-md); + font-size: 14px; display: flex; align-items: center; - gap: var(--sp-2); + gap: 7px; color: var(--text-1); flex-shrink: 0; - letter-spacing: -0.02em; + letter-spacing: -0.04em; } - .navbar-logo svg { width: 18px; height: 18px; color: var(--accent); } + .navbar-logo svg { width: 16px; height: 16px; color: var(--accent); } .navbar-links { display: flex; @@ -124,19 +124,18 @@ flex: 1; } .navbar-link { - padding: 5px var(--sp-3); - border-radius: var(--radius-md); - font-size: var(--text-sm); + padding: 4px 12px; + border-radius: 6px; + font-size: 13px; font-weight: 500; - color: var(--text-3); - transition: all 0.15s ease; + color: var(--text-4); + transition: all 0.2s cubic-bezier(0.16,1,0.3,1); background: none; border: none; position: relative; text-decoration: none; - letter-spacing: 0.01em; } - .navbar-link:hover { color: var(--text-1); background: var(--card-hover); } + .navbar-link:hover { color: var(--text-2); background: rgba(0,0,0,0.03); } .navbar-link.active { color: var(--accent); background: var(--accent-dim); diff --git a/frontend-v2/src/routes/(app)/+page.svelte b/frontend-v2/src/routes/(app)/+page.svelte index 92c80da..6943042 100644 --- a/frontend-v2/src/routes/(app)/+page.svelte +++ b/frontend-v2/src/routes/(app)/+page.svelte @@ -157,8 +157,8 @@ { taskPanelOpen = false; loadTasks(); }} /> - -
+ +
+
+ + +
+
- +
-
- - -
+
@@ -310,28 +312,29 @@ color: var(--accent); } - /* ── Action cards ── */ - .action-cards { - display: flex; - flex-direction: column; - gap: var(--sp-2); - margin-bottom: var(--section-gap); + /* ── Bento grids ── */ + .bento-row { + display: grid; + grid-template-columns: 2fr 1fr; + gap: 10px; + margin-bottom: 10px; + } + + .bento-row-2 { + display: grid; + grid-template-columns: 1fr 1fr; + gap: 10px; + margin-bottom: 10px; } /* ── Modules grid ── */ .modules-grid { display: grid; - grid-template-columns: 1.3fr 0.7fr; - gap: var(--module-gap); + grid-template-columns: 7fr 3fr; + gap: 10px; align-items: start; } - .right-stack { - display: flex; - flex-direction: column; - gap: var(--module-gap); - } - /* ── Mobile ── */ @media (max-width: 900px) { .dash-header { @@ -348,9 +351,13 @@ } @media (max-width: 768px) { + .bento-row, + .bento-row-2, .modules-grid { grid-template-columns: 1fr; } + .bento-row > :global(*), + .bento-row-2 > :global(*), .modules-grid > :global(*) { min-width: 0; max-width: 100%;