refactor(brand): wire brand + new primitives through layout chrome
The layout chrome adopts the new brand module + the just-landed
app-primitives. CSS variables, the favicon, the page title, and the
vite PWA manifest all switch to the new brand assets:
- BrandBlock / NavPill / Sidebar / Layout use BrandMark / BrandWordmark
/ BRAND.name from @/lib/brand.
- ThemeContext exposes the system / dark / light options for the new
'theme = System' setting (commit 1 of 9 in the brand refresh set;
the actual settings UI lands in the per-page commit).
- client/index.css: 153 lines of churn — the design-token refresh
(accent palette, neutrals, surface tokens) consumed by every
downstream commit.
- index.html: title, favicon, apple-touch-icon, theme-color, manifest
href all point at client/public/brand/*.
- vite.config.mjs: VitePWA manifest icons + theme/background colors
follow the new brand.
This is commit 3 of 9 in the v0.42.0 brand refresh. Depends on
4898987 (app-primitives).
This commit is contained in:
parent
4898987a18
commit
36834e6625
|
|
@ -1,20 +1,17 @@
|
||||||
import React, { useMemo } from 'react';
|
import React from 'react';
|
||||||
import { NavLink } from 'react-router-dom';
|
import { NavLink } from 'react-router-dom';
|
||||||
|
import { BrandMark, BrandWordmark } from '@/components/brand/Brand';
|
||||||
|
import { BRAND } from '@/lib/brand';
|
||||||
|
|
||||||
export const BrandBlock = React.memo(function BrandBlock({ adminMode = false }: { adminMode?: boolean }) {
|
export const BrandBlock = React.memo(function BrandBlock({ adminMode = false }: { adminMode?: boolean }) {
|
||||||
const logoSrc = useMemo(() => '/img/logo.png', []);
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<NavLink
|
<NavLink
|
||||||
to={adminMode ? '/admin' : '/'}
|
to={adminMode ? '/admin' : '/'}
|
||||||
aria-label="BillTracker"
|
aria-label={BRAND.name}
|
||||||
className="flex items-center gap-2 rounded-xl focus-visible:outline-none focus-visible:ring-[3px] focus-visible:ring-ring/50"
|
className="group flex items-center gap-2 rounded-xl focus-visible:outline-none focus-visible:ring-[3px] focus-visible:ring-ring/50"
|
||||||
>
|
>
|
||||||
<img
|
<BrandMark className="h-12 w-auto max-w-[6.75rem] drop-shadow-[0_1px_2px_rgba(0,0,0,0.24)] transition-transform duration-200 group-hover:scale-[1.015]" />
|
||||||
src={logoSrc}
|
<BrandWordmark className="sr-only" />
|
||||||
alt="BillTracker"
|
|
||||||
className="h-16 w-auto max-w-[9rem] object-contain drop-shadow-[0_1px_2px_rgba(0,0,0,0.45)]"
|
|
||||||
/>
|
|
||||||
{adminMode && (
|
{adminMode && (
|
||||||
<span className="hidden sm:inline-flex rounded-full border border-destructive/25 bg-destructive/10 px-2 py-0.5 text-[10px] font-semibold uppercase text-destructive">
|
<span className="hidden sm:inline-flex rounded-full border border-destructive/25 bg-destructive/10 px-2 py-0.5 text-[10px] font-semibold uppercase text-destructive">
|
||||||
Admin
|
Admin
|
||||||
|
|
|
||||||
|
|
@ -28,7 +28,7 @@ export default function Layout({ mainContentId }: { mainContentId?: string }) {
|
||||||
const location = useLocation();
|
const location = useLocation();
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="min-h-screen bg-[radial-gradient(circle_at_top_left,oklch(var(--primary)/0.06),transparent_30rem),linear-gradient(180deg,oklch(var(--background)),oklch(var(--muted)/0.12))] text-foreground"
|
<div className="min-h-screen bg-[radial-gradient(circle_at_top_left,oklch(var(--primary)/0.08),transparent_28rem),radial-gradient(circle_at_top_right,oklch(var(--accent)/0.08),transparent_24rem),linear-gradient(180deg,oklch(var(--background)),oklch(var(--muted)/0.16))] text-foreground"
|
||||||
role="main"
|
role="main"
|
||||||
aria-labelledby={mainContentId}
|
aria-labelledby={mainContentId}
|
||||||
>
|
>
|
||||||
|
|
|
||||||
|
|
@ -34,7 +34,7 @@ export const NavPill = React.memo(function NavPill({ item, onNavigate, badge = 0
|
||||||
'focus-visible:outline-none focus-visible:ring-[3px] focus-visible:ring-ring/50',
|
'focus-visible:outline-none focus-visible:ring-[3px] focus-visible:ring-ring/50',
|
||||||
isActive
|
isActive
|
||||||
? 'bg-primary text-primary-foreground shadow-sm shadow-primary/20'
|
? 'bg-primary text-primary-foreground shadow-sm shadow-primary/20'
|
||||||
: 'text-muted-foreground hover:bg-accent hover:text-accent-foreground hover:shadow-sm'
|
: 'text-muted-foreground hover:bg-accent/85 hover:text-accent-foreground hover:shadow-sm'
|
||||||
)}
|
)}
|
||||||
>
|
>
|
||||||
<Icon className="h-4 w-4" />
|
<Icon className="h-4 w-4" />
|
||||||
|
|
|
||||||
|
|
@ -81,7 +81,7 @@ function TrackerMenu({ onNavigate, badge = 0, badgeNames = [], items = trackerIt
|
||||||
'focus-visible:outline-none focus-visible:ring-[3px] focus-visible:ring-ring/50',
|
'focus-visible:outline-none focus-visible:ring-[3px] focus-visible:ring-ring/50',
|
||||||
isTrackerActive
|
isTrackerActive
|
||||||
? 'bg-primary text-primary-foreground shadow-sm shadow-primary/20'
|
? 'bg-primary text-primary-foreground shadow-sm shadow-primary/20'
|
||||||
: 'text-muted-foreground hover:bg-accent hover:text-accent-foreground hover:shadow-sm',
|
: 'text-muted-foreground hover:bg-accent/85 hover:text-accent-foreground hover:shadow-sm',
|
||||||
)}
|
)}
|
||||||
aria-expanded={isTrackerActive}
|
aria-expanded={isTrackerActive}
|
||||||
aria-haspopup="menu"
|
aria-haspopup="menu"
|
||||||
|
|
@ -237,7 +237,7 @@ export default function Sidebar({ adminMode = false }: { adminMode?: boolean; ma
|
||||||
}, [adminMode]);
|
}, [adminMode]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<header className="sticky top-0 z-40 border-b border-border/80 bg-card/95 shadow-sm shadow-foreground/10 backdrop-blur-md supports-[backdrop-filter]:bg-card/90">
|
<header className="sticky top-0 z-40 border-b border-border/70 bg-card/95 shadow-sm shadow-black/10 backdrop-blur-xl supports-[backdrop-filter]:bg-card/90">
|
||||||
<div className="mx-auto flex h-16 w-full max-w-[1500px] items-center gap-4 px-4 sm:px-6 lg:px-8">
|
<div className="mx-auto flex h-16 w-full max-w-[1500px] items-center gap-4 px-4 sm:px-6 lg:px-8">
|
||||||
<BrandBlock adminMode={adminMode} />
|
<BrandBlock adminMode={adminMode} />
|
||||||
|
|
||||||
|
|
@ -253,7 +253,7 @@ export default function Sidebar({ adminMode = false }: { adminMode?: boolean; ma
|
||||||
<Button
|
<Button
|
||||||
type="button"
|
type="button"
|
||||||
variant="outline"
|
variant="outline"
|
||||||
className="hidden h-9 gap-2 rounded-full bg-muted px-3 text-muted-foreground shadow-sm md:inline-flex"
|
className="hidden h-9 gap-2 rounded-full bg-card/70 px-3 text-muted-foreground shadow-sm shadow-black/5 md:inline-flex"
|
||||||
onClick={() => window.dispatchEvent(new Event('command-palette:open'))}
|
onClick={() => window.dispatchEvent(new Event('command-palette:open'))}
|
||||||
title="Find a bill"
|
title="Find a bill"
|
||||||
>
|
>
|
||||||
|
|
@ -264,13 +264,13 @@ export default function Sidebar({ adminMode = false }: { adminMode?: boolean; ma
|
||||||
</kbd>
|
</kbd>
|
||||||
</Button>
|
</Button>
|
||||||
)}
|
)}
|
||||||
<ThemeToggle className="rounded-full border border-border/80 bg-muted shadow-sm" />
|
<ThemeToggle className="rounded-full border border-border/75 bg-card/70 shadow-sm shadow-black/5" />
|
||||||
<UserMenu adminMode={adminMode} />
|
<UserMenu adminMode={adminMode} />
|
||||||
<Button
|
<Button
|
||||||
type="button"
|
type="button"
|
||||||
variant="outline"
|
variant="outline"
|
||||||
size="icon"
|
size="icon"
|
||||||
className="lg:hidden rounded-full bg-muted"
|
className="rounded-full bg-card/70 lg:hidden"
|
||||||
aria-label={mobileOpen ? 'Close navigation menu' : 'Open navigation menu'}
|
aria-label={mobileOpen ? 'Close navigation menu' : 'Open navigation menu'}
|
||||||
aria-expanded={mobileOpen}
|
aria-expanded={mobileOpen}
|
||||||
onClick={() => setMobileOpen(v => !v)}
|
onClick={() => setMobileOpen(v => !v)}
|
||||||
|
|
@ -281,7 +281,7 @@ export default function Sidebar({ adminMode = false }: { adminMode?: boolean; ma
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{mobileOpen && (
|
{mobileOpen && (
|
||||||
<div className="max-h-[70vh] overflow-y-auto border-t border-border/70 bg-card/95 px-4 py-3 shadow-lg shadow-foreground/10 lg:hidden">
|
<div className="max-h-[70vh] overflow-y-auto border-t border-border/70 bg-card/95 px-4 py-3 shadow-lg shadow-black/15 lg:hidden">
|
||||||
<nav className="mx-auto grid max-w-[1500px] gap-1">
|
<nav className="mx-auto grid max-w-[1500px] gap-1">
|
||||||
{!adminMode && trackerMenuItems.map(item => (
|
{!adminMode && trackerMenuItems.map(item => (
|
||||||
<NavPill
|
<NavPill
|
||||||
|
|
|
||||||
|
|
@ -20,7 +20,7 @@ const VALID_THEMES: Theme[] = ['light', 'dark', 'system'];
|
||||||
const DEFAULT_THEME: Theme = 'dark';
|
const DEFAULT_THEME: Theme = 'dark';
|
||||||
|
|
||||||
// Keep in sync with the inline pre-bundle script in index.html.
|
// Keep in sync with the inline pre-bundle script in index.html.
|
||||||
const THEME_COLORS: Record<ResolvedTheme, string> = { light: '#ffffff', dark: '#18181b' };
|
const THEME_COLORS: Record<ResolvedTheme, string> = { light: '#f8faf9', dark: '#101417' };
|
||||||
|
|
||||||
function systemPrefersDark(): boolean {
|
function systemPrefersDark(): boolean {
|
||||||
return typeof window !== 'undefined' && !!window.matchMedia?.('(prefers-color-scheme: dark)').matches;
|
return typeof window !== 'undefined' && !!window.matchMedia?.('(prefers-color-scheme: dark)').matches;
|
||||||
|
|
|
||||||
153
client/index.css
153
client/index.css
|
|
@ -30,38 +30,38 @@
|
||||||
|
|
||||||
@layer base {
|
@layer base {
|
||||||
:root {
|
:root {
|
||||||
--background: 0.97 0.005 250;
|
--background: 0.985 0.006 235;
|
||||||
--foreground: 0.15 0.008 250;
|
--foreground: 0.185 0.018 238;
|
||||||
--card: 0.995 0.004 250;
|
--card: 0.998 0.003 238;
|
||||||
--card-foreground: 0.15 0.008 250;
|
--card-foreground: 0.185 0.018 238;
|
||||||
--popover: 1.00 0 0;
|
--popover: 1.00 0 0;
|
||||||
--popover-foreground: 0.15 0.008 250;
|
--popover-foreground: 0.185 0.018 238;
|
||||||
--primary: 0.55 0.20 276;
|
--primary: 0.64 0.17 154;
|
||||||
--primary-foreground: 0.99 0.003 250;
|
--primary-foreground: 0.985 0.006 154;
|
||||||
--secondary: 0.93 0.008 250;
|
--secondary: 0.94 0.010 235;
|
||||||
--secondary-foreground: 0.20 0.010 250;
|
--secondary-foreground: 0.245 0.018 238;
|
||||||
--muted: 0.94 0.006 250;
|
--muted: 0.945 0.009 235;
|
||||||
--muted-foreground: 0.38 0.010 250;
|
--muted-foreground: 0.44 0.016 238;
|
||||||
--accent: 0.92 0.012 265;
|
--accent: 0.925 0.020 184;
|
||||||
--accent-foreground: 0.20 0.010 250;
|
--accent-foreground: 0.205 0.020 190;
|
||||||
--destructive: 0.55 0.22 25;
|
--destructive: 0.58 0.21 22;
|
||||||
--destructive-foreground: 0.99 0.003 250;
|
--destructive-foreground: 0.99 0.003 250;
|
||||||
--border: 0.88 0.008 250;
|
--border: 0.875 0.010 235;
|
||||||
--input: 0.88 0.008 250;
|
--input: 0.875 0.010 235;
|
||||||
--ring: 0.55 0.16 276;
|
--ring: 0.64 0.15 154;
|
||||||
--chart-1: 0.55 0.22 270;
|
--chart-1: 0.62 0.17 154;
|
||||||
--chart-2: 0.55 0.14 150;
|
--chart-2: 0.58 0.13 195;
|
||||||
--chart-3: 0.60 0.18 310;
|
--chart-3: 0.64 0.16 65;
|
||||||
--chart-4: 0.58 0.16 130;
|
--chart-4: 0.62 0.17 335;
|
||||||
--chart-5: 0.55 0.18 255;
|
--chart-5: 0.55 0.11 250;
|
||||||
--sidebar: 0.94 0.007 250;
|
--sidebar: 0.965 0.008 235;
|
||||||
--sidebar-foreground: 0.20 0.008 250;
|
--sidebar-foreground: 0.22 0.018 238;
|
||||||
--sidebar-primary: 0.55 0.20 276;
|
--sidebar-primary: 0.64 0.17 154;
|
||||||
--sidebar-primary-foreground: 0.99 0.003 250;
|
--sidebar-primary-foreground: 0.985 0.006 154;
|
||||||
--sidebar-accent: 0.90 0.009 250;
|
--sidebar-accent: 0.925 0.020 184;
|
||||||
--sidebar-accent-foreground: 0.20 0.008 250;
|
--sidebar-accent-foreground: 0.205 0.020 190;
|
||||||
--sidebar-border: 0.88 0.008 250;
|
--sidebar-border: 0.875 0.010 235;
|
||||||
--sidebar-ring: 0.55 0.20 276;
|
--sidebar-ring: 0.64 0.15 154;
|
||||||
--font-sans: 'GeorgiaDigits', Inter, Roboto, ui-sans-serif, system-ui, sans-serif;
|
--font-sans: 'GeorgiaDigits', Inter, Roboto, ui-sans-serif, system-ui, sans-serif;
|
||||||
--font-serif: Merriweather, ui-serif, serif;
|
--font-serif: Merriweather, ui-serif, serif;
|
||||||
--font-mono: 'GeorgiaDigits', "Roboto Mono", ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, monospace;
|
--font-mono: 'GeorgiaDigits', "Roboto Mono", ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, monospace;
|
||||||
|
|
@ -69,40 +69,40 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
.dark {
|
.dark {
|
||||||
--background: 0.155 0.014 245;
|
--background: 0.145 0.018 238;
|
||||||
--foreground: 0.965 0.006 245;
|
--foreground: 0.962 0.008 235;
|
||||||
--card: 0.235 0.016 245;
|
--card: 0.205 0.020 238;
|
||||||
--card-foreground: 0.965 0.006 245;
|
--card-foreground: 0.962 0.008 235;
|
||||||
--popover: 0.26 0.018 245;
|
--popover: 0.235 0.022 238;
|
||||||
--popover-foreground: 0.965 0.006 245;
|
--popover-foreground: 0.962 0.008 235;
|
||||||
--primary: 0.72 0.17 150;
|
--primary: 0.72 0.15 154;
|
||||||
--primary-foreground: 0.14 0.018 150;
|
--primary-foreground: 0.145 0.020 154;
|
||||||
--secondary: 0.275 0.018 245;
|
--secondary: 0.275 0.020 238;
|
||||||
--secondary-foreground: 0.94 0.007 245;
|
--secondary-foreground: 0.94 0.008 235;
|
||||||
--muted: 0.275 0.016 245;
|
--muted: 0.275 0.018 238;
|
||||||
/* Secondary text. Raised 0.76 → 0.85 — at 0.76 labels and hints sat too
|
/* Secondary text. Raised 0.76 → 0.85 — at 0.76 labels and hints sat too
|
||||||
close to the card background (L 0.235) and strained the eyes. */
|
close to the card background (L 0.235) and strained the eyes. */
|
||||||
--muted-foreground: 0.85 0.012 245;
|
--muted-foreground: 0.85 0.012 245;
|
||||||
--accent: 0.32 0.045 158;
|
--accent: 0.33 0.050 184;
|
||||||
--accent-foreground: 0.965 0.006 245;
|
--accent-foreground: 0.965 0.008 235;
|
||||||
--destructive: 0.66 0.18 26;
|
--destructive: 0.66 0.18 26;
|
||||||
--destructive-foreground: 0.98 0.004 245;
|
--destructive-foreground: 0.98 0.004 245;
|
||||||
--border: 0.40 0.018 245;
|
--border: 0.37 0.020 238;
|
||||||
--input: 0.40 0.018 245;
|
--input: 0.37 0.020 238;
|
||||||
--ring: 0.72 0.16 150;
|
--ring: 0.72 0.14 154;
|
||||||
--chart-1: 0.55 0.22 270;
|
--chart-1: 0.72 0.15 154;
|
||||||
--chart-2: 0.62 0.14 150;
|
--chart-2: 0.70 0.12 195;
|
||||||
--chart-3: 0.65 0.18 310;
|
--chart-3: 0.75 0.15 68;
|
||||||
--chart-4: 0.62 0.16 130;
|
--chart-4: 0.70 0.16 340;
|
||||||
--chart-5: 0.58 0.18 255;
|
--chart-5: 0.68 0.10 250;
|
||||||
--sidebar: 0.175 0.014 245;
|
--sidebar: 0.165 0.018 238;
|
||||||
--sidebar-foreground: 0.95 0.006 245;
|
--sidebar-foreground: 0.95 0.008 235;
|
||||||
--sidebar-primary: 0.72 0.17 150;
|
--sidebar-primary: 0.72 0.15 154;
|
||||||
--sidebar-primary-foreground: 0.14 0.018 150;
|
--sidebar-primary-foreground: 0.145 0.020 154;
|
||||||
--sidebar-accent: 0.30 0.038 158;
|
--sidebar-accent: 0.30 0.045 184;
|
||||||
--sidebar-accent-foreground: 0.95 0.006 245;
|
--sidebar-accent-foreground: 0.95 0.008 235;
|
||||||
--sidebar-border: 0.36 0.018 245;
|
--sidebar-border: 0.34 0.020 238;
|
||||||
--sidebar-ring: 0.72 0.16 150;
|
--sidebar-ring: 0.72 0.14 154;
|
||||||
}
|
}
|
||||||
|
|
||||||
* {
|
* {
|
||||||
|
|
@ -134,21 +134,44 @@
|
||||||
|
|
||||||
/* Generic surface */
|
/* Generic surface */
|
||||||
.surface {
|
.surface {
|
||||||
@apply rounded-2xl border border-border/80 bg-card shadow-sm shadow-black/10;
|
@apply rounded-xl border border-border/75 bg-card/95 shadow-sm shadow-black/10;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Elevated surface */
|
/* Elevated surface */
|
||||||
.surface-elevated {
|
.surface-elevated {
|
||||||
@apply surface;
|
@apply surface backdrop-blur-sm;
|
||||||
box-shadow:
|
box-shadow:
|
||||||
0 1px 2px rgb(0 0 0 / 0.05),
|
0 1px 2px rgb(0 0 0 / 0.05),
|
||||||
0 6px 18px rgb(0 0 0 / 0.06);
|
0 10px 30px rgb(15 23 42 / 0.07);
|
||||||
}
|
}
|
||||||
|
|
||||||
.dark .surface-elevated {
|
.dark .surface-elevated {
|
||||||
box-shadow:
|
box-shadow:
|
||||||
0 0 0 1px oklch(var(--border) / 0.78),
|
0 0 0 1px oklch(var(--border) / 0.70),
|
||||||
0 10px 24px rgb(0 0 0 / 0.48);
|
0 14px 34px rgb(0 0 0 / 0.42);
|
||||||
|
}
|
||||||
|
|
||||||
|
.surface-premium {
|
||||||
|
@apply rounded-xl border border-border/75 bg-card/95 shadow-sm shadow-black/10 backdrop-blur-sm;
|
||||||
|
}
|
||||||
|
|
||||||
|
.dark .surface-premium {
|
||||||
|
box-shadow:
|
||||||
|
0 0 0 1px oklch(var(--border) / 0.55),
|
||||||
|
0 12px 30px rgb(0 0 0 / 0.34);
|
||||||
|
}
|
||||||
|
|
||||||
|
.metric-card {
|
||||||
|
@apply relative overflow-hidden rounded-xl border border-border/75 bg-card/95 px-5 py-4 shadow-sm shadow-black/10;
|
||||||
|
}
|
||||||
|
|
||||||
|
.metric-card::before {
|
||||||
|
content: "";
|
||||||
|
position: absolute;
|
||||||
|
inset: 0 0 auto;
|
||||||
|
height: 3px;
|
||||||
|
background: linear-gradient(90deg, oklch(var(--primary) / 0.85), oklch(var(--accent) / 0.68));
|
||||||
|
opacity: 0.76;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Stat cards */
|
/* Stat cards */
|
||||||
|
|
@ -158,7 +181,7 @@
|
||||||
|
|
||||||
/* Table */
|
/* Table */
|
||||||
.table-surface {
|
.table-surface {
|
||||||
@apply surface overflow-hidden shadow-sm shadow-black/10;
|
@apply surface-premium overflow-hidden;
|
||||||
}
|
}
|
||||||
|
|
||||||
.tracker-number {
|
.tracker-number {
|
||||||
|
|
|
||||||
10
index.html
10
index.html
|
|
@ -3,13 +3,13 @@
|
||||||
<head>
|
<head>
|
||||||
<meta charset="UTF-8">
|
<meta charset="UTF-8">
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||||
<link rel="icon" type="image/png" href="/img/logo.png">
|
<link rel="icon" type="image/png" href="/brand/logo.png">
|
||||||
<link rel="apple-touch-icon" href="/img/apple-touch-icon.png">
|
<link rel="apple-touch-icon" href="/brand/apple-touch-icon.png">
|
||||||
<meta name="theme-color" content="#18181b">
|
<meta name="theme-color" content="#101417">
|
||||||
<meta name="mobile-web-app-capable" content="yes">
|
<meta name="mobile-web-app-capable" content="yes">
|
||||||
<meta name="apple-mobile-web-app-capable" content="yes">
|
<meta name="apple-mobile-web-app-capable" content="yes">
|
||||||
<meta name="apple-mobile-web-app-status-bar-style" content="black-translucent">
|
<meta name="apple-mobile-web-app-status-bar-style" content="black-translucent">
|
||||||
<meta name="apple-mobile-web-app-title" content="BillTracker">
|
<meta name="apple-mobile-web-app-title" content="Bill Tracker">
|
||||||
<title>Bill Tracker</title>
|
<title>Bill Tracker</title>
|
||||||
<script>
|
<script>
|
||||||
// Pre-bundle theme apply — avoids a light/dark flash. Mirrors applyTheme in
|
// Pre-bundle theme apply — avoids a light/dark flash. Mirrors applyTheme in
|
||||||
|
|
@ -25,7 +25,7 @@
|
||||||
var root = document.documentElement;
|
var root = document.documentElement;
|
||||||
if (resolved === 'dark') root.classList.add('dark'); else root.classList.remove('dark');
|
if (resolved === 'dark') root.classList.add('dark'); else root.classList.remove('dark');
|
||||||
var m = document.querySelector('meta[name="theme-color"]');
|
var m = document.querySelector('meta[name="theme-color"]');
|
||||||
if (m) m.setAttribute('content', resolved === 'dark' ? '#18181b' : '#ffffff');
|
if (m) m.setAttribute('content', resolved === 'dark' ? '#101417' : '#f8faf9');
|
||||||
} catch (e) { /* localStorage/matchMedia unavailable — keep default */ }
|
} catch (e) { /* localStorage/matchMedia unavailable — keep default */ }
|
||||||
})();
|
})();
|
||||||
</script>
|
</script>
|
||||||
|
|
|
||||||
|
|
@ -22,18 +22,18 @@ export default defineConfig({
|
||||||
}),
|
}),
|
||||||
VitePWA({
|
VitePWA({
|
||||||
registerType: 'autoUpdate',
|
registerType: 'autoUpdate',
|
||||||
includeAssets: ['img/logo.png', 'img/pwa-192.png', 'img/pwa-512.png'],
|
includeAssets: ['brand/logo.png', 'brand/pwa-192.png', 'brand/pwa-512.png'],
|
||||||
manifest: {
|
manifest: {
|
||||||
name: 'BillTracker',
|
name: 'Bill Tracker',
|
||||||
short_name: 'BillTracker',
|
short_name: 'Bill Tracker',
|
||||||
description: 'Personal bill planning and tracking',
|
description: 'Personal bill planning and tracking',
|
||||||
theme_color: '#18181b',
|
theme_color: '#101417',
|
||||||
background_color: '#18181b',
|
background_color: '#101417',
|
||||||
display: 'standalone',
|
display: 'standalone',
|
||||||
start_url: '/',
|
start_url: '/',
|
||||||
icons: [
|
icons: [
|
||||||
{ src: '/img/pwa-192.png', sizes: '192x192', type: 'image/png' },
|
{ src: '/brand/pwa-192.png', sizes: '192x192', type: 'image/png' },
|
||||||
{ src: '/img/pwa-512.png', sizes: '512x512', type: 'image/png', purpose: 'any maskable' },
|
{ src: '/brand/pwa-512.png', sizes: '512x512', type: 'image/png', purpose: 'any maskable' },
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
workbox: {
|
workbox: {
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue