Task: Put the theme and the language in the header
Table of Contents
This page documents a task in the Switch the interface between light and dark, and choose the language from the header story. It captures the goal, current status, acceptance, and any notes or results.
1. Goal
The header offers both settings, and the palette they set survives a reload.
2. Status
| Field | Value |
|---|---|
| State | DONE |
| Parent story | Switch the interface between light and dark, and choose the language from the header |
| Now | Nothing. |
| Waiting on | Nothing. |
| Next | Nothing. |
| Last touched | 2026-10-31 |
3. Acceptance
- A light palette states every role token the dark one does
- The theme toggle shows the palette it will switch to and survives a reload
- The language menu opens from the header and marks the language in use
- The account menu no longer carries a language select
4. Plan
The palette is a second block of the same role tokens, selected on an attribute of the document, so no screen learns that a second palette exists: every utility already reads a role, and the block says what that role is in the light one.
The choice is kept in the module that owns it rather than in a React context.
The attribute on the document is the one place the palette is in force, and a
context would be a second copy that could disagree with it; a control subscribes
to the module with useSyncExternalStore instead, and a screen that never asks
for the palette pays nothing.
The language menu leaves the account menu for the header and reuses the
language label the header already carried. The document's lang attribute
follows the choice, so a screen reader and a browser's dictionary agree with the
menu.
5. Measurements
Every number this task claims about a tree, with the command that produced it
and the commit it was measured at. A number without both is not a measurement,
because a clean-up record describes a tree and trunk moves under a branch: a
consumer count, a gate's component count and a suite's size all change with no
code changing, and the reader of a bare number cannot tell which tree it came
from. Where the raw output matters, put it in an evidence/ file beside the
task and name that file in the Command column.
| What | Value | Command | Commit |
|---|---|---|---|
| web gate | pass (typecheck, format, tests) | compass check --exclude-heavy |
branch head |
| web package suite | 2341 tests in 187 files | npx vitest run in packages/web |
branch head |
| production bundle | builds | npm run build in projects/ores.web |
branch head |
| theme module | 8 tests | npx vitest run src/theme/theme.test.ts |
branch head |
6. Notes
7. Test Scenarios
Manual QA scenarios (scaffolded via compass add test_scenario)
that verify this task. Link
new ones here as they're created; the scenario doc itself links back
via its "Verifies task" field.
| Scenario | State | Notes |
|---|---|---|
8. PRs
| PR | Title |
|---|---|
| #4241 | [web] Switch the palette and the language from the header |
9. Review
| Comment summary | File | Decision | Notes |
|---|---|---|---|
10. Result
The header carries the palette switch and the language menu beside the bell, and the account menu keeps only the person's own pages. The palette survives a reload, applies before the first paint, and the language sets the document's own language with it.
The two icons are vendored from the Fluent set and recorded in the icon guide, as the guide asks of a new icon.