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.

Emacs 29.3 (Org mode 9.6.15)