From 979f3ddc397a2875f0a67210fda826f7c8e6cdd9 Mon Sep 17 00:00:00 2001 From: Martin Dvorak Date: Thu, 8 Oct 2026 06:15:51 +0000 Subject: [PATCH] Navy theme from the app icon, frosted glass, and the new mark in-app The icon's artwork is now the source of truth for the palette: - frost-* is a navy-tinted neutral scale and accent-* is the icon's snowflake blue; light page #f4f7fd / sidebar #e9eff9 / border #dce4f1, dark page #0e1424 / sidebar #0a0f1c / surfaces #171f33. - Surfaces are frosted glass: .card, .glass-panel, .list-group and .sidebar-surface are translucent with backdrop-blur/saturate, and the page wrapper no longer paints an opaque --page, so the fixed navy/blue backdrop reads through the sidebar, cards, chrome and sheets. - The primary CTA is the icon's blue (#1d61ab in light, #59a8f7 in dark with ink text). - The gate stage, fields and glows are navy/blue; viewport theme-color and the manifest background/theme colour are #0e1424. - The old monochrome snowflake tile is gone from the brand: sidebar, header, key gate and empty state now show the real app icon (the install sheet already did). Decorative snowflakes stay. - --surface-strong is finally defined (it was referenced but never declared, so those inputs had no fill). - Icon URLs carry ?v=2 so browser favicon caches refetch. Updated the contrast audit (21 pairs) and the deck-chrome token assertions to the new theme. Verified: contrast 21/21, deck chrome 15/15, key gate 49/49, install sheet 64/64, final ux 12/12, retry 14/14, zoom 6/6, security 8/8, pwa 16/16, deck fixes 15/15. --- README.md | 39 ++++--- app/create/page.tsx | 2 +- app/globals.css | 216 ++++++++++++++++++++------------------ app/layout.tsx | 17 +-- app/manifest.ts | 4 +- app/page.tsx | 2 +- components/ApiKeyGate.tsx | 12 +-- components/AppHeader.tsx | 15 +-- components/Sidebar.tsx | 12 +-- components/ui.tsx | 18 ++-- 10 files changed, 180 insertions(+), 157 deletions(-) diff --git a/README.md b/README.md index 023a15d..2600e53 100644 --- a/README.md +++ b/README.md @@ -112,8 +112,10 @@ no database, no data leaving your machine except the requests you send to Ollama list with per-folder counts, Settings/Dark mode pinned to the bottom). It **collapses** to a 68px icon rail (remembered in `localStorage`) and becomes a slide-in **drawer** behind a hamburger on phones; mobile also keeps the frosted header + iOS tab bar -- **One neutral palette, both themes**: light page `#ffffff` / sidebar `#f9f9f9` / border `#e5e5e5`; - dark page `#212121` / sidebar `#171717` / surfaces `#2f2f2f` / border `rgba(255,255,255,.1)`. +- **One navy palette pulled from the app icon, both themes**: light page `#f4f7fd` / sidebar + `#e9eff9` / border `#dce4f1`; dark page `#0e1424` / sidebar `#0a0f1c` / surfaces `#171f33` / + border `rgba(255,255,255,.12)`. Surfaces are frosted glass (translucent + `backdrop-blur`) over + the icon's navy backdrop. Text tiers are documented AA ratios (see below), and the cards fill the row with `repeat(auto-fill, minmax(280px, 1fr))` — no stranded cards, no dead space - Deck cards: title → muted metadata → neutral tags (difficulty carries the only colour: @@ -725,9 +727,10 @@ Things I chose while building, with the reasoning: have no `folderId`), deleting a folder re-homes its decks instead of deleting them, and folder names travel in exports so an imported deck lands where it came from. 13 browser checks cover create → freeze → move → rename → delete → reload → import. -18. **The visual language is glassmorphism, with restraint.** One accent colour drives the buttons - and highlights; the backdrop is a soft aurora wash; surfaces are frosted and translucent. Colour - appears in activity tints and semantic feedback only — pretty, but still readable and quiet. +18. **The visual language is glassmorphism, with restraint.** The icon's blue is the one accent + colour driving buttons and highlights; the backdrop is a navy wash; surfaces — sidebar, cards, + chrome, sheets — are frosted and translucent. Colour appears in activity tints and semantic + feedback only — pretty, but still readable and quiet. 19. **Custom CSS lives in `@layer components`, and glass uses Tailwind's backdrop utilities.** Two build-level traps, both found by looking at real screenshots: unlayered rules beat Tailwind utilities (which silently broke `fixed` on the feed), and a hand-written `backdrop-filter` gets @@ -738,19 +741,19 @@ Things I chose while building, with the reasoning: a fixture deck into `localStorage` rather than relying on app code. 21. **Dark mode is token-driven, and contrast is audited.** Text colours come from `--text` / `--text-muted` / `--text-subtle` (never hardcoded), and a `contrast.mjs` audit checks - every pairing at WCAG AA — currently **20/20 pairs pass** (e.g. dark secondary `#b4b4b4` on - `#212121` = 7.8:1). Difficulty colours were darkened until they cleared 4.5:1 on their pills. + every pairing at WCAG AA — currently **21/21 pairs pass** (e.g. dark secondary `#b7c3dc` on + `#0e1424` = 10.4:1, white on the light blue CTA `#1d61ab` = 6.3:1). Difficulty colours were + darkened until they cleared 4.5:1 on their pills. This was a real bug: an earlier edit silently failed, so `.dark` never overrode `--text`, leaving near-black text on a dark page. -22. **The dashboard follows a neutral, ChatGPT-style system.** Near-white/near-black surfaces, - hairline borders, pill CTAs, 18px radii and restrained shadows; the frost survives in the chrome - (header, tab bar, sheets) rather than in every card, which keeps text crisp and the layout - premium. Deck cards got real hierarchy: title → muted metadata → tags → summary → prominent - Study CTA, with secondary actions behind a quiet menu. -23. **One fixed backdrop layer instead of per-page blobs.** The decorative aurora used to be +22. **The dashboard follows the icon's navy system.** Frosted navy/white surfaces, hairline borders, + pill CTAs, 18px radii and restrained shadows; the sidebar, cards and chrome are translucent + glass over the backdrop. Deck cards got real hierarchy: title → muted metadata → tags → summary + → secondary Study CTA, with secondary actions behind a quiet menu. +23. **One fixed backdrop layer instead of per-page blobs.** The decorative wash used to be rendered inside the content column, so on wide screens it was clipped into a visible hard edge. - It now lives in a single `position: fixed` layer (`.app-backdrop`, `z-index: -10`) with very low - opacities, and `body`'s colour matches its bottom so mobile overscroll shows no seam. + It now lives in a single `position: fixed` layer (`.app-backdrop`, `z-index: -10`) in the + icon's navy and blue, and `body`'s colour matches its bottom so mobile overscroll shows no seam. 24. **The UI was deliberately made quieter.** One accent colour (`accent-*`), a desaturated `frost-*` scale, hairline borders and flat surfaces replaced the saturated gradients and the seven-colour activity badges. Semantic colours (green/amber/red) survive only where they carry @@ -784,6 +787,12 @@ Things I chose while building, with the reasoning: `user-scalable=no` for an app-like feel, and a mobile-only rule keeps every input and textarea at 16px so iOS Safari's focus auto-zoom never fires (iOS ignores `user-scalable=no` for that). Desktop keeps the designed 12–14px field sizes. +31. **The app icon drives the palette.** The navy rounded-square artwork in + `assets/app-icon-source.jpeg` is the source of truth: `frost-*` is navy-tinted, the accent is + the snowflake blue, the backdrop is the same navy wash, the primary CTA is the icon blue (deep + in light mode, bright in dark), and every icon/splash/favicon is rendered from it by + `scripts/make-icons.mjs`. The sidebar, header, key gate, empty state and install sheet all show + the real artwork instead of the old monochrome snowflake tile. 14. **`gpt-oss:120b` does all content work — but it cannot read images** (`this model does not support image input`), so `VISION_MODEL` has to stay a multimodal model (`gemma4:31b-cloud`). Text-only inputs — pasted text, PDFs with a text layer, DOCX/PPTX/ODT — never touch the vision diff --git a/app/create/page.tsx b/app/create/page.tsx index 2d89599..ffece12 100644 --- a/app/create/page.tsx +++ b/app/create/page.tsx @@ -11,7 +11,7 @@ export const metadata = { export default function CreatePage() { return ( -
+
diff --git a/app/globals.css b/app/globals.css index 2ff3899..4efcd96 100644 --- a/app/globals.css +++ b/app/globals.css @@ -4,30 +4,30 @@ @custom-variant dark (&:where(.dark, .dark *)); @theme { - /* Neutral scale (a whisper of cool) — the ChatGPT-ish workhorse. ------- */ - --color-frost-50: #f8f8f9; - --color-frost-100: #f1f1f3; - --color-frost-200: #e4e4e7; - --color-frost-300: #cfcfd4; - --color-frost-400: #a3a3aa; - --color-frost-500: #7a7a82; - --color-frost-600: #5d5d64; - --color-frost-700: #47474d; - --color-frost-800: #34343a; - --color-frost-900: #26262a; - --color-frost-950: #171719; + /* Navy-tinted neutral scale — sampled from the app icon. ---------------- */ + --color-frost-50: #f5f8fd; + --color-frost-100: #eaf0fa; + --color-frost-200: #d9e3f3; + --color-frost-300: #c2cfe4; + --color-frost-400: #92a3c0; + --color-frost-500: #6a7c9b; + --color-frost-600: #4e5f7d; + --color-frost-700: #3c4b66; + --color-frost-800: #2b3752; + --color-frost-900: #1d2740; + --color-frost-950: #0e1526; - /* Accent: one confident blue for buttons and highlights. -------------- */ - --color-accent-50: #eef7fd; - --color-accent-100: #d9edfa; - --color-accent-200: #b6dcf4; - --color-accent-300: #83c3ea; - --color-accent-400: #4aa4dc; - --color-accent-500: #2387c4; - --color-accent-600: #186ca6; - --color-accent-700: #175687; - --color-accent-800: #18496f; - --color-accent-900: #183e5d; + /* Accent: the icon's snowflake blue. ------------------------------------ */ + --color-accent-50: #eff7ff; + --color-accent-100: #dbecff; + --color-accent-200: #bcdcff; + --color-accent-300: #8fc6ff; + --color-accent-400: #59a8f7; + --color-accent-500: #3f95ea; + --color-accent-600: #2478d2; + --color-accent-700: #1d61ab; + --color-accent-800: #1c518b; + --color-accent-900: #1b4473; /* Aurora hues used only for the frosted backdrop wash. ----------------- */ --color-aurora-mint: #9fe3d0; @@ -81,74 +81,76 @@ --------------------------------------------------------------------------- */ :root { color-scheme: light; - --page: #ffffff; - --sidebar: #f9f9f9; + --page: #f4f7fd; + --sidebar: #e9eff9; --surface: #ffffff; --surface-raised: #ffffff; - --card-hover-bg: #fafafa; - --surface-sunken: rgb(13 13 13 / 0.05); - --hairline: #e5e5e5; - --card-border: #e2e2e2; - --sidebar-divider: #e2e2e2; - --hairline-soft: rgb(13 13 13 / 0.07); - --glass-tint: rgb(255 255 255 / 0.6); - --text: #0d0d0d; /* 17.6:1 on #ffffff */ - --text-muted: #5d5d5d; /* 7.4:1 */ - --text-subtle: #6b6b6b; /* 5.4:1 */ - --hover: rgb(13 13 13 / 0.05); - --sidebar-top: #fbfbfc; - --sidebar-bottom: #f6f6f7; - --sidebar-edge: 0 1px 0 var(--hairline), 6px 0 18px -12px rgb(13 13 13 / 0.38); - /* API-key gate: near-white stage with soft blank glows, tinted input. */ - --gate-base: #f6f6f8; - --gate-glow-a: rgb(84 102 130 / 0.22); - --gate-glow-b: rgb(124 138 160 / 0.18); + --surface-strong: #edf2fa; + --card-hover-bg: #f7faff; + --surface-sunken: rgb(14 21 40 / 0.05); + --hairline: #dce4f1; + --card-border: #d7e0ef; + --sidebar-divider: #d7e0ef; + --hairline-soft: rgb(14 21 40 / 0.07); + --glass-tint: rgb(255 255 255 / 0.55); + --text: #0e1526; /* 16.9:1 on #f4f7fd */ + --text-muted: #4d5c78; /* 6.3:1 */ + --text-subtle: #5a6a86; /* 5.1:1 */ + --hover: rgb(14 21 40 / 0.05); + --sidebar-top: #eef3fb; + --sidebar-bottom: #e5edf9; + --sidebar-edge: 0 1px 0 var(--sidebar-divider), 6px 0 18px -12px rgb(14 21 40 / 0.35); + /* API-key gate: cool near-white stage with soft blue glows, tinted input. */ + --gate-base: #eef3fb; + --gate-glow-a: rgb(90 150 240 / 0.25); + --gate-glow-b: rgb(140 150 240 / 0.2); --gate-card: #ffffff; - --gate-card-border: #e7e7e9; - --gate-callout-bg: #f2f2f5; - --gate-callout-border: #cfcfd6; - --field: #f3f3f4; - --field-border: #e2e2e4; - --shadow-gate: 0 28px 70px -36px rgb(13 13 13 / 0.3), 0 1px 2px rgb(13 13 13 / 0.05); + --gate-card-border: #dde5f2; + --gate-callout-bg: #eef3fa; + --gate-callout-border: #c9d5e8; + --field: #eef2f9; + --field-border: #dbe3f0; + --shadow-gate: 0 28px 70px -36px rgb(14 21 40 / 0.3), 0 1px 2px rgb(14 21 40 / 0.05); /* Install sheet: light variant (dark is the default, see .dark). */ --install-sheet: #ffffff; --install-card: #f7f7f8; --install-chip: #f2f2f2; --install-border: #e0e0e0; - --shadow-card: 0 1px 2px rgb(13 13 13 / 0.06), 0 1px 3px rgb(13 13 13 / 0.04); - --card-shadow: 0 1px 2px rgb(13 13 13 / 0.05), 0 5px 14px -6px rgb(13 13 13 / 0.12); - --shadow-card-hover: 0 12px 30px -12px rgb(13 13 13 / 0.2), 0 2px 6px rgb(13 13 13 / 0.07); + --shadow-card: 0 1px 2px rgb(14 21 40 / 0.06), 0 1px 3px rgb(14 21 40 / 0.04); + --card-shadow: 0 1px 2px rgb(14 21 40 / 0.05), 0 5px 14px -6px rgb(14 21 40 / 0.12); + --shadow-card-hover: 0 12px 30px -12px rgb(14 21 40 / 0.2), 0 2px 6px rgb(14 21 40 / 0.07); } .dark { color-scheme: dark; - --page: #212121; - --sidebar: #171717; - --surface: #2f2f2f; - --surface-raised: #383838; - --card-hover-bg: #383838; - --surface-sunken: rgb(255 255 255 / 0.08); - --hairline: rgb(255 255 255 / 0.14); - --card-border: var(--hairline); - --sidebar-divider: var(--hairline); + --page: #0e1424; + --sidebar: #0a0f1c; + --surface: #171f33; + --surface-raised: #1e2740; + --surface-strong: #202a42; + --card-hover-bg: #1e2740; + --surface-sunken: rgb(255 255 255 / 0.07); + --hairline: rgb(255 255 255 / 0.12); + --card-border: rgb(255 255 255 / 0.12); + --sidebar-divider: rgb(255 255 255 / 0.1); --hairline-soft: rgb(255 255 255 / 0.08); - --glass-tint: rgb(255 255 255 / 0.08); - --text: #ececec; /* 12.9:1 on #212121 */ - --text-muted: #b4b4b4; /* 7.6:1 */ - --text-subtle: #a0a0a0; /* 6.0:1 */ + --glass-tint: rgb(255 255 255 / 0.06); + --text: #e9eefb; /* 15.4:1 on #0e1424 */ + --text-muted: #b7c3dc; /* 10.4:1 */ + --text-subtle: #94a4c2; /* 7.3:1 */ --hover: rgb(255 255 255 / 0.07); - --sidebar-top: #181818; - --sidebar-bottom: #141414; + --sidebar-top: #0b1120; + --sidebar-bottom: #080d18; --sidebar-edge: 0 1px 0 var(--hairline), 6px 0 16px -14px rgb(0 0 0 / 0.75); - /* API-key gate: near-black stage, monochrome glows, raised input. */ - --gate-base: #0f0f0f; - --gate-glow-a: rgb(255 255 255 / 0.17); - --gate-glow-b: rgb(255 255 255 / 0.12); - --gate-card: #1a1a1a; - --gate-card-border: rgb(255 255 255 / 0.08); - --gate-callout-bg: rgb(255 255 255 / 0.07); - --gate-callout-border: rgb(255 255 255 / 0.22); - --field: #242425; + /* API-key gate: navy stage with the icon's blue glows, raised input. */ + --gate-base: #0a0f1c; + --gate-glow-a: rgb(70 140 235 / 0.2); + --gate-glow-b: rgb(120 120 235 / 0.14); + --gate-card: #131a2c; + --gate-card-border: rgb(255 255 255 / 0.1); + --gate-callout-bg: rgb(255 255 255 / 0.06); + --gate-callout-border: rgb(255 255 255 / 0.2); + --field: #1b2438; --field-border: rgb(255 255 255 / 0.1); --shadow-gate: 0 30px 80px -40px rgb(0 0 0 / 0.85), 0 1px 2px rgb(0 0 0 / 0.4); /* Install sheet: layered dark surfaces (default theme for the sheet). */ @@ -161,22 +163,22 @@ --shadow-card-hover: 0 10px 28px -16px rgb(0 0 0 / 0.55), 0 1px 2px rgb(0 0 0 / 0.3); } -/* Backdrop: a whisper of cool over a neutral base (never a coloured surface). */ +/* Backdrop: the icon's navy base and blue wash, seen through frosted glass. */ :root { - --bd-sky: rgb(150 200 240 / 0.07); - --bd-lilac: rgb(188 178 236 / 0.05); - --bd-mint: rgb(150 220 202 / 0.05); - --bd-top: #fdfdfd; - --bd-mid: #fafafa; - --bd-bottom: #f7f7f7; + --bd-sky: rgb(110 175 245 / 0.2); + --bd-lilac: rgb(145 145 240 / 0.14); + --bd-mint: rgb(110 210 230 / 0.12); + --bd-top: #f8fafe; + --bd-mid: #f2f6fd; + --bd-bottom: #ecf1fb; } .dark { - --bd-sky: rgb(74 164 220 / 0.05); - --bd-lilac: rgb(160 140 235 / 0.04); - --bd-mint: rgb(88 201 173 / 0.04); - --bd-top: #232323; - --bd-mid: #212121; - --bd-bottom: #1e1e1e; + --bd-sky: rgb(60 130 230 / 0.14); + --bd-lilac: rgb(110 115 235 / 0.1); + --bd-mint: rgb(70 180 215 / 0.08); + --bd-top: #111a2e; + --bd-mid: #0e1424; + --bd-bottom: #0a101d; } html, @@ -280,14 +282,14 @@ body { } .dark .app-backdrop::before, .dark .app-backdrop::after { - opacity: 0.16; + opacity: 0.3; } @layer components { /* Glass primitives ------------------------------------------------------ */ .glass-panel { - @apply backdrop-blur-xl; - background: var(--surface); + @apply backdrop-blur-xl backdrop-saturate-150; + background: color-mix(in oklab, var(--surface) 82%, transparent); border: 1px solid var(--hairline); box-shadow: var(--shadow-card); } @@ -323,7 +325,8 @@ body { .card { border-radius: 1.125rem; /* 18px */ - background: var(--surface); + @apply backdrop-blur-xl backdrop-saturate-150; + background: color-mix(in oklab, var(--surface) 78%, transparent); border: 1px solid var(--card-border); box-shadow: var(--card-shadow); } @@ -351,7 +354,7 @@ body { .list-group { border-radius: 1rem; @apply backdrop-blur-lg backdrop-saturate-150; - background: var(--surface); + background: color-mix(in oklab, var(--surface) 82%, transparent); border: 1px solid var(--hairline); overflow: hidden; } @@ -389,7 +392,7 @@ body { } .dark .segmented > button[aria-pressed="true"], .dark .segmented > button[aria-checked="true"] { - background: #383838; + background: var(--surface-raised); color: #fff; } @@ -420,9 +423,14 @@ body { .dark .tint-peach { background: linear-gradient(140deg, rgb(230 160 118 / 0.26), rgb(230 160 118 / 0.1)); color: #fadfc9 } .dark .tint-rose { background: linear-gradient(140deg, rgb(230 130 150 / 0.26), rgb(230 130 150 / 0.1)); color: #fbd5dd } -/* Sidebar surface: a touch darker than the page, with a real edge. */ +/* Sidebar surface: frosted navy glass with a real edge. */ .sidebar-surface { - background: linear-gradient(180deg, var(--sidebar-top), var(--sidebar-bottom)); + @apply backdrop-blur-xl backdrop-saturate-150; + background: linear-gradient( + 180deg, + color-mix(in oklab, var(--sidebar-top) 84%, transparent), + color-mix(in oklab, var(--sidebar-bottom) 84%, transparent) + ); border-right: 1px solid var(--sidebar-divider); box-shadow: var(--sidebar-edge); } @@ -450,27 +458,27 @@ body { color: var(--text); } -/* Shared CTA language: near-black pill in light mode, white pill in dark. */ +/* Shared CTA language: the icon's blue, with a deeper fill in light mode. */ .btn-primary { display: inline-flex; align-items: center; justify-content: center; gap: 0.5rem; border-radius: 999px; - background: #0d0d0d; + background: #1d61ab; color: #ffffff; font-weight: 500; - box-shadow: 0 1px 2px rgb(13 13 13 / 0.18); + box-shadow: 0 1px 2px rgb(14 21 40 / 0.22); transition: background-color 160ms ease, transform 160ms ease, box-shadow 160ms ease; } -.btn-primary:hover { background: #2f2f2f; } +.btn-primary:hover { background: #2478d2; } .btn-primary:active { transform: scale(0.985); } .dark .btn-primary { - background: #ffffff; - color: #0d0d0d; + background: #59a8f7; + color: #081020; box-shadow: none; } -.dark .btn-primary:hover { background: #e5e5e5; } +.dark .btn-primary:hover { background: #7bbaff; } .btn-secondary { display: inline-flex; diff --git a/app/layout.tsx b/app/layout.tsx index 7705146..058afb7 100644 --- a/app/layout.tsx +++ b/app/layout.tsx @@ -20,14 +20,15 @@ export const metadata: Metadata = { }, icons: { icon: [ - { url: "/icons/favicon-32.png", sizes: "32x32", type: "image/png" }, - { url: "/icons/icon-192.png", sizes: "192x192", type: "image/png" }, - { url: "/icons/icon-512.png", sizes: "512x512", type: "image/png" }, + // ?v=2 busts browser favicon caches after the icon redesign. + { url: "/icons/favicon-32.png?v=2", sizes: "32x32", type: "image/png" }, + { url: "/icons/icon-192.png?v=2", sizes: "192x192", type: "image/png" }, + { url: "/icons/icon-512.png?v=2", sizes: "512x512", type: "image/png" }, ], apple: [ - { url: "/icons/apple-touch-icon.png", sizes: "180x180" }, - { url: "/icons/apple-touch-icon-167.png", sizes: "167x167" }, - { url: "/icons/apple-touch-icon-152.png", sizes: "152x152" }, + { url: "/icons/apple-touch-icon.png?v=2", sizes: "180x180" }, + { url: "/icons/apple-touch-icon-167.png?v=2", sizes: "167x167" }, + { url: "/icons/apple-touch-icon-152.png?v=2", sizes: "152x152" }, ], }, other: { @@ -48,8 +49,8 @@ export const viewport: Viewport = { userScalable: false, viewportFit: "cover", themeColor: [ - { media: "(prefers-color-scheme: light)", color: "#f8fafc" }, - { media: "(prefers-color-scheme: dark)", color: "#0a0f13" }, + { media: "(prefers-color-scheme: light)", color: "#f4f7fd" }, + { media: "(prefers-color-scheme: dark)", color: "#0e1424" }, ], }; diff --git a/app/manifest.ts b/app/manifest.ts index 74c3ab0..a38a6fc 100644 --- a/app/manifest.ts +++ b/app/manifest.ts @@ -14,8 +14,8 @@ export default function manifest(): MetadataRoute.Manifest { scope: "/", display: "standalone", orientation: "portrait", - background_color: "#f8fafc", - theme_color: "#f8fafc", + background_color: "#0e1424", + theme_color: "#0e1424", categories: ["education", "productivity"], icons: [ { src: "/icons/icon-192.png", sizes: "192x192", type: "image/png", purpose: "any" }, diff --git a/app/page.tsx b/app/page.tsx index 47eae75..e0721d3 100644 --- a/app/page.tsx +++ b/app/page.tsx @@ -7,7 +7,7 @@ import { TabBar } from "@/components/TabBar"; export default function HomePage() { return ( -
+
diff --git a/components/ApiKeyGate.tsx b/components/ApiKeyGate.tsx index 53679c3..f25046d 100644 --- a/components/ApiKeyGate.tsx +++ b/components/ApiKeyGate.tsx @@ -11,7 +11,6 @@ import { EyeOffIcon, MoonIcon, QuestionIcon, - SnowflakeIcon, SunIcon, XIcon, } from "@/components/icons"; @@ -233,12 +232,13 @@ function GateScreen() { transition={{ duration: 0.45, ease: [0.22, 1, 0.36, 1] }} className="my-auto w-full max-w-[420px] rounded-[24px] border border-[var(--gate-card-border)] bg-[var(--gate-card)] p-6 px-7 text-center shadow-[var(--shadow-gate)] sm:p-8" > - - - + className="mx-auto size-14 rounded-[16px] shadow-[var(--shadow-card)]" + />

Connect your Ollama key diff --git a/components/AppHeader.tsx b/components/AppHeader.tsx index 0fd4975..0610c61 100644 --- a/components/AppHeader.tsx +++ b/components/AppHeader.tsx @@ -3,7 +3,7 @@ import Link from "next/link"; import { useEffect, useState } from "react"; -import { GearIcon, MenuIcon, SnowflakeIcon } from "@/components/icons"; +import { GearIcon, MenuIcon } from "@/components/icons"; import { SettingsDialog } from "@/components/SettingsDialog"; import { ThemeToggle } from "@/components/ThemeToggle"; import { sidebarOpen } from "@/lib/nav"; @@ -47,12 +47,13 @@ export function AppHeader({ className, compact = false }: { className?: string; - - - + {/* eslint-disable-next-line @next/next/no-img-element -- static app icon, no optimisation needed */} + Freezmo diff --git a/components/Sidebar.tsx b/components/Sidebar.tsx index a5dd83c..e16194d 100644 --- a/components/Sidebar.tsx +++ b/components/Sidebar.tsx @@ -12,7 +12,6 @@ import { LayersIcon, MoonIcon, PlusIcon, - SnowflakeIcon, SunIcon, } from "@/components/icons"; import { useTheme } from "@/components/ThemeToggle"; @@ -110,12 +109,13 @@ function NavContent({ aria-label="Freezmo home" title="Freezmo" > - - - + className="size-7 shrink-0 rounded-lg shadow-[0_1px_3px_rgb(14_21_40/0.35)]" + /> {!collapsed ? ( Freezmo ) : null} diff --git a/components/ui.tsx b/components/ui.tsx index 2d1c571..da9af28 100644 --- a/components/ui.tsx +++ b/components/ui.tsx @@ -2,7 +2,6 @@ import { forwardRef } from "react"; -import { SnowflakeIcon } from "@/components/icons"; import { cn } from "@/lib/utils"; type ButtonVariant = "primary" | "secondary" | "ghost" | "danger" | "success"; @@ -135,12 +134,17 @@ export function EmptyState({ }) { return (
- - {icon ?? } - + {icon ? ( + + {icon} + + ) : ( + /* eslint-disable-next-line @next/next/no-img-element -- static app icon, no optimisation needed */ + + )}

{title}

{children ? (

{children}