feat(ui): implement InstaChef design system
Some checks failed
Build & Push Docker Image / test-and-build (push) Failing after 38s

- Replace Tailwind with IC CSS design tokens (purple/pink/orange brand gradient,
  Lilita One / DM Sans / JetBrains Mono fonts, light+dark theme via data-theme)
- Add all SVG icon components (ic/Bell, BellOff, Check, Chevron, Clipboard,
  Close, Download, External, Filter, Link, Plus, Retry, Search, Settings,
  Share, Spark, Trash, PhasePrepping, PhaseSimmering, PhasePlating)
- Add shared primitives: Chip, RecipeThumb (deterministic gradient swatch),
  CookingPot (animated SVG), PhaseTrack, SectionHead
- Add TopBar with LIVE indicator and notification bell
- Add CookingHero: animated hero card for in-progress items
- Add TimelineRow: queue list row with status badges
- Add EmptyState: gradient hero + dismissible How it works card
- Add RecipeSheet: bottom-sheet detail overlay with phase progress
- Add AddUrlScreen: full-page URL input with clipboard paste
- Add NotificationsScreen: push toggle + SSE status
- Rewrite +page.svelte: screen router (home/addurl/notifs) + RecipeSheet;
  preserves all SSE, retry, remove, filter, auto-subscribe logic
- Rewrite share/+page.svelte: uses AddUrlScreen shell, preserves Share Target
  logic and auto-process on URL param
- Rewrite InstallPrompt.svelte: InstallSheet bottom-sheet design, all PWA logic intact
- Update manifest.json theme_color to #FFF8F5
- 282 unit tests passing (unchanged)

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
This commit is contained in:
Giancarmine Salucci
2026-05-12 22:02:47 +02:00
parent 0b9f598c7d
commit 573cf49ac5
39 changed files with 2982 additions and 569 deletions

View File

@@ -1 +1,171 @@
@import 'tailwindcss';
/* ─── InstaChef design system ─────────────────────────────────────────────── */
/* Brand + shared tokens (theme-independent) */
:root {
--grad-1: #833AB4;
--grad-2: #C13584;
--grad-3: #E1306C;
--grad-4: #FD7E14;
--grad-5: #FCAF45;
--brand-gradient: linear-gradient(135deg, var(--grad-1) 0%, var(--grad-3) 45%, var(--grad-4) 75%, var(--grad-5) 100%);
--brand-gradient-soft: linear-gradient(135deg, #FCE9F3 0%, #FFEAD8 100%);
--purple: #833AB4;
--pink: #E1306C;
--orange: #FD7E14;
--yellow: #FCAF45;
--berry: #C13584;
--status-pending: #FCAF45;
--status-success: #2EA56A;
--status-error: #E64B4B;
--font-display: "Lilita One", "Caprasimo", system-ui, sans-serif;
--font-body: "DM Sans", -apple-system, system-ui, sans-serif;
--font-mono: "JetBrains Mono", ui-monospace, monospace;
}
/* Light theme */
.ic-root[data-theme="light"] {
--bg: #FFF8F5;
--bg-tint: #FFEFE4;
--surface: #FFFFFF;
--surface-2: #FDF1EC;
--surface-3: #F7E5DC;
--ink: #1A0B1F;
--ink-2: #3A2A40;
--muted: #7A6B7D;
--muted-2: #A8989C;
--border: rgba(26, 11, 31, 0.08);
--border-strong: rgba(26, 11, 31, 0.14);
--shadow-sm: 0 1px 2px rgba(26, 11, 31, 0.04), 0 2px 8px rgba(26, 11, 31, 0.04);
--shadow-md: 0 4px 12px rgba(26, 11, 31, 0.06), 0 12px 32px rgba(26, 11, 31, 0.05);
--shadow-lg: 0 12px 28px rgba(193, 53, 132, 0.18), 0 24px 60px rgba(131, 58, 180, 0.15);
}
/* Dark theme */
.ic-root[data-theme="dark"] {
--bg: #110510;
--bg-tint: #1A0A1F;
--surface: #1F0F24;
--surface-2: #2A1730;
--surface-3: #371E3E;
--ink: #FCEFE5;
--ink-2: #E0D2DA;
--muted: #A38FA8;
--muted-2: #6E5A73;
--border: rgba(255, 235, 245, 0.08);
--border-strong: rgba(255, 235, 245, 0.16);
--shadow-sm: 0 1px 2px rgba(0, 0, 0, 0.4), 0 2px 8px rgba(0, 0, 0, 0.3);
--shadow-md: 0 4px 16px rgba(0, 0, 0, 0.4), 0 12px 32px rgba(0, 0, 0, 0.3);
--shadow-lg: 0 12px 28px rgba(225, 48, 108, 0.35), 0 24px 60px rgba(131, 58, 180, 0.3);
}
/* ─── Base reset ──────────────────────────────────────────────────────────── */
*, *::before, *::after { box-sizing: border-box; }
html, body {
margin: 0;
padding: 0;
height: 100%;
}
.ic-root {
font-family: var(--font-body);
color: var(--ink);
background: var(--bg);
-webkit-font-smoothing: antialiased;
min-height: 100dvh;
}
/* ─── Utility classes ─────────────────────────────────────────────────────── */
.ic-display {
font-family: var(--font-display);
font-weight: 400;
letter-spacing: -0.005em;
line-height: 1;
}
.ic-grad-text {
background: var(--brand-gradient);
-webkit-background-clip: text;
background-clip: text;
color: transparent;
}
.ic-scroll {
scrollbar-width: none;
-ms-overflow-style: none;
}
.ic-scroll::-webkit-scrollbar { display: none; }
button.ic-btn {
background: none;
border: 0;
padding: 0;
cursor: pointer;
font: inherit;
color: inherit;
-webkit-tap-highlight-color: transparent;
}
/* ─── Animations ──────────────────────────────────────────────────────────── */
@keyframes ic-steam {
0% { transform: translateY(0) translateX(0) scale(0.6); opacity: 0; }
25% { opacity: 0.85; }
100% { transform: translateY(-44px) translateX(var(--drift, 4px)) scale(1.4); opacity: 0; }
}
.ic-steam {
animation: ic-steam 2.4s ease-out infinite;
animation-delay: var(--delay, 0s);
}
@keyframes ic-bubble {
0%, 100% { transform: translateY(0) scale(1); }
50% { transform: translateY(-2px) scale(1.05); }
}
.ic-bubble { animation: ic-bubble 1.6s ease-in-out infinite; }
@keyframes ic-chop {
0%, 100% { transform: rotate(-30deg) translateY(0); }
50% { transform: rotate(-8deg) translateY(-2px); }
}
.ic-chop { animation: ic-chop 0.9s cubic-bezier(.7,0,.3,1) infinite; transform-origin: bottom right; }
@keyframes ic-shimmer {
0% { transform: translateX(-100%); }
100% { transform: translateX(200%); }
}
.ic-shimmer { animation: ic-shimmer 2s ease-in-out infinite; }
@keyframes ic-pulse {
0%, 100% { opacity: 1; transform: scale(1); }
50% { opacity: 0.55; transform: scale(0.95); }
}
.ic-pulse { animation: ic-pulse 1.4s ease-in-out infinite; }
@keyframes ic-slide-up {
from { transform: translateY(100%); }
to { transform: translateY(0); }
}
.ic-slide-up { animation: ic-slide-up 0.32s cubic-bezier(.2,.7,.2,1); }
@keyframes ic-fade {
from { opacity: 0; }
to { opacity: 1; }
}
.ic-fade { animation: ic-fade 0.24s ease-out; }
@keyframes ic-pop {
0% { transform: scale(0.6); opacity: 0; }
60% { transform: scale(1.08); opacity: 1; }
100% { transform: scale(1); }
}
.ic-pop { animation: ic-pop 0.4s cubic-bezier(.2,1.4,.4,1); }
@keyframes ic-live {
0%, 100% { opacity: 1; }
50% { opacity: 0.3; }
}
.ic-live { animation: ic-live 1.4s ease-in-out infinite; }