Skip to content

Auto dark mode#179

Merged
grische merged 5 commits intomainfrom
auto-dark-mode
Apr 19, 2026
Merged

Auto dark mode#179
grische merged 5 commits intomainfrom
auto-dark-mode

Conversation

@grische
Copy link
Copy Markdown

@grische grische commented Apr 18, 2026

See upstream PR freifunk#346

grische and others added 5 commits April 18, 2026 22:59
Adds button.theme.{light,dark,auto} across en/de/fr/cz/ru/tr. Each
label names the current theme and, in parentheses, the theme the
next click will switch to ("Light (next: dark)"), giving both
sighted and screen-reader users the same state-plus-action signal
in a single short string. Polyglot is configured with
allowMissing: true, so all locales need the keys to avoid rendering
raw dotted strings to non-English users.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
New standalone module lib/theme.ts owns theme state, storage, DOM
class mutation, and matchMedia subscription. Exposes initTheme,
getTheme, resolveTheme, cycleTheme, and themeIconSVG.

Persists the user's choice in localStorage under meshviewer.theme
(greenfield key — no prior storage usage in repo). All localStorage
access is wrapped in try/catch so sandboxed iframes, Safari private
mode, and file:// contexts fall back to in-memory state.

On apply, toggles the existing theme_night class on <html> and
dispatches a "themechange" CustomEvent on document.documentElement
so other modules (the map's label canvas) can react without
creating a direct dependency on this module.

Auto mode subscribes to prefers-color-scheme changes so the UI
flips live without a reload. Icons are inline SVG rather than
font glyphs because the bundled meshviewer.woff2 is a 24-glyph
subset of Ionicons and does not contain sun/moon/auto symbols.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Removes the theme_* class manipulation from the baselayerchange
handler. The theme is now a user preference owned by lib/theme.ts
and no longer implicitly tied to tile-layer config.

The label canvas renders colors derived from getComputedStyle on
the body (lib/map/labellayer.js), so it still needs to refresh
when the theme changes. LabelLayer subscribes to the themechange
CustomEvent in its own onAdd / onRemove Leaflet lifecycle hooks,
which ties the listener's lifetime to the layer and guarantees
teardown when the layer is removed — map.ts keeps no theme-related
code at all.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Adds a button that cycles light -> dark -> auto. The button icon
shows the current theme (sun / moon / half-circle) and the
aria-label carries the short "Light (next: dark)" string from the
locale file, so screen-reader users get the same state-plus-action
signal the icon conveys visually.

The same aria-label is the source for the button's hover tooltip
via the existing CSS rule (::after { content: attr(aria-label) }
on .content button), so no title attribute is set — that would
produce a duplicate native browser tooltip on top of the styled
one.

Calls initTheme() just before the button is rendered so the
matchMedia listener and storage state are active before any
click.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Reads the stored theme preference synchronously in the document
head and sets theme_night on <html> before any CSS resolves, so
dark-mode users don't see a light-theme flash while Vite loads
the main bundle. Read-only and wrapped in try/catch; the full
theme module still owns writes and listeners.

If localStorage access throws (sandboxed iframes, storage disabled,
some file:// contexts), a nested try/catch still applies
theme_night based on prefers-color-scheme alone, so OS-dark users
also get the correct first paint without a late flip when
lib/theme.ts boots.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@grische grische requested a review from a team as a code owner April 18, 2026 21:44
@grische grische merged commit dead7cf into main Apr 19, 2026
5 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants