Skip to content

Add a theme choice to Settings - #58

Merged
malinfossum merged 1 commit into
mainfrom
feat/theme-switcher
Aug 21, 2026
Merged

Add a theme choice to Settings#58
malinfossum merged 1 commit into
mainfrom
feat/theme-switcher

Conversation

@malinfossum

Copy link
Copy Markdown
Member

Dark by default, light available — Malin's request. Based on main, independent of the auth stack (#54#55#56).

Most of this already existed

Wend simply never exposed it:

  • tokens/colors.css carries a full :root[data-theme="light"] block
  • tokens/palettes/wend.css carries [data-theme="light"][data-palette="wend"], so the brand survives the switch
  • index.html has had the anti-flash init script since Slice 1

The only missing piece was a control. No new CSS colours, no design-system/ edit.

Decisions

A native <select>, not a switch or a pair of radios: two options today, more when a palette picker lands, and the design system's .select already carries the 44px floor (measured 47px).

Stored under the design system's own theme key, not inside wend.prefs. The inline script in index.html reads it before any module loads — that script is what stops a dark-mode user seeing a flash of light on first paint, and it cannot wait for an import. Unknown or hand-edited values fall back to dark, the same way setPref ignores unknown keys.

The controller writes data-theme onto <html>, not the view. No view owns that element — it sits above every view root. index.html sets it on load; the controller sets it on change.

Verification

Against the running app, driving the real view/model/controller:

before after choosing Light
<html data-theme> dark light
localStorage.theme (unset → dark) light
body background #0d1117 #f6f8fa
body text #10161d
auth input background #ffffff

It also announces "Light theme.", returns focus to the select, and re-renders with the new value selected. Choosing Dark puts everything back.

dotnet test255 passed, 0 failed. Frontend only.

Not in scope — the palette picker

Five brand palettes ship in the bundle (wend, gold, daily, ignite, plus the shared _oled foundation), but three of them are other projects' brands. Which ones a Wend user should see, and what they should be called in the UI, is a branding decision rather than a wiring one. index.html stays pinned to data-palette="wend".

What to check

  • The storage key. Putting the theme in wend.prefs would look tidier and would reintroduce the flash — the comment in prefs.js says so, but it is the kind of tidy-up worth guarding against.
  • Whether <select> is the right control for two options, or whether you would rather have a toggle now and a select later when palettes arrive.

Malin asked for dark by default with light available. Almost all of it
already existed upstream and Wend simply never exposed it: colors.css
carries a full :root[data-theme="light"] block, and wend.css carries a
[data-theme="light"][data-palette="wend"] block, so the brand survives the
switch. index.html has had the anti-flash init script since Slice 1. The
only thing missing was a control.

A native <select> in Settings, not a switch or a pair of radios: there are
two options today and more when a palette picker lands, and the design
system's .select already carries the 44px floor. Measured 47px.

The theme is stored under the design system's own "theme" key rather than
inside wend.prefs, because the inline script in index.html reads it before
any module loads - that script is what stops a dark-mode user seeing a
flash of light on first paint, and it cannot wait for an import. Unknown or
hand-edited values fall back to dark, the same way setPref ignores unknown
keys.

The controller, not the view, writes data-theme onto <html>. No view owns
that element: it sits above every view root, index.html sets it on load,
and this sets it on change.

Verified against the running app: choosing Light flips data-theme, persists
it, announces "Light theme.", returns focus to the select, and the page
really changes - body background #0d1117 to #f6f8fa, text to #10161d, the
auth input to white. Choosing Dark puts it all back.

Not in scope: the palette picker. Five brand palettes ship in the bundle,
but three of them are other projects' brands, so which ones a Wend user
should see - and what they should be called - is a branding decision rather
than a wiring one. index.html stays pinned to data-palette="wend".

255/255 green; frontend only.
@malinfossum
malinfossum merged commit 85d9fcc into main Aug 21, 2026
1 check passed
@malinfossum
malinfossum deleted the feat/theme-switcher branch August 21, 2026 13:27
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.

1 participant