Add a dark/light theme switcher to the navbar
The palette already lived in CSS custom properties, so dark mode is a token-override block in the new theme.css, applied via data-theme on the document element. A moon/sun toggle sits top right in the navbar; an explicit choice persists in localStorage, otherwise the app follows the OS preference live. An inline head script applies the theme before first paint so a dark reload never flashes light. Token hygiene sweep alongside: literal colours that broke under a dark palette (timeline chip text, color-mix against white, calendar stripes and bands, warning banners, nav background) moved into ten new tokens with light-mode values unchanged. The flip clock keeps its fixed dark look by design; the map keeps standard light tiles in both themes.
This commit is contained in:
+10
@@ -402,6 +402,16 @@ Proxies `https://nominatim.openstreetmap.org/search?format=jsonv2&limit=5&accept
|
||||
|
||||
- SPA served from `public/`; all non-`/api` GETs fall back to `public/index.html` is NOT required — a single `index.html` with hash-based routing (`#/login`, `#/trips`, `#/trip/:id[/:tab]`) is the expected design, so no server-side fallback is needed.
|
||||
|
||||
### Theme switcher (dark/light, frontend-only)
|
||||
|
||||
The palette already lives in CSS custom properties on `:root` (light). Dark mode is a token override, not a parallel stylesheet.
|
||||
|
||||
- **Mechanism**: `document.documentElement` carries `data-theme="dark"` or `data-theme="light"`. `public/css/theme.css` (new, linked in index.html after styles.css) defines the complete dark palette under `[data-theme="dark"]` — every colour token `:root` defines (brand/bg/surface/border/text/danger/success/warn soft variants, shadows) gets a dark value; nothing may be defined only in the dark block.
|
||||
- **Resolution order**: `localStorage.theme` (`"light"`/`"dark"`) if set, else the OS preference via `prefers-color-scheme` (followed LIVE through a `matchMedia` change listener until the user explicitly chooses). A tiny inline `<script>` in `index.html`'s `<head>` applies the attribute BEFORE the stylesheets paint (no flash of wrong theme). `localStorage` access wrapped in try/catch (privacy modes throw).
|
||||
- **Toggle**: an icon button at the TOP RIGHT of the navbar (in `.nav-right`, before the user area) — shows 🌙 when light (click → dark) and ☀️ when dark (click → light), `aria-label` "Switch to dark/light theme". Clicking stores the explicit choice and swaps the attribute; no page reload.
|
||||
- **Token hygiene sweep** (required, same commit): hard-coded colours that break under a dark palette move to tokens — `timeline.css` chip/block text `#334155` → a new `--chip-text` token and its `color-mix(… , white)` backgrounds → `color-mix(… , var(--surface))`; any equivalent literals in `styles.css` likewise. The flip-clock stays dark by design (its own fixed colours are the aesthetic, both themes). The Leaflet map keeps standard light tiles in both themes (out of scope); its container chrome uses tokens like everything else. Entry/type accent colours from `format.js` (`--chip` inline vars) are theme-neutral and unchanged.
|
||||
- styles.css is at its 500-line cap: the dark palette, the toggle button styles, and any new tokens' *dark* values live in `theme.css`; edits to styles.css are replacements only (introducing a new token's light value in `:root` is allowed, growth beyond the cap is not).
|
||||
|
||||
### Trip page tabs & compact nav header (frontend-only)
|
||||
|
||||
The trip page is split into three tabs, and the old full-width trip-header card is REMOVED — its contents move into the top navbar so the page starts with actual content.
|
||||
|
||||
Reference in New Issue
Block a user