Repository navigation
feat(portal): light / system / dark theme switch; language selector on its own row (#17) - #21
Merged
Merged
Conversation
…n its own row The sidebar footer put the theme button and the language selector side by side in a 192px sidebar. They did not fit: the selector spilled past the edge (visible in every README screenshot) and "Light theme" wrapped. The theme was also only light or dark, and a first visit always got dark. The theme is now a three-position switch with icons, in the same visual language as the Dashboard admission switch: light, system, dark. System follows the operating system and changes live when it does, and it is the default for anyone who never chose; a saved light or dark is kept. The switch is a radiogroup: arrow keys move the selection and only the selected option is in the Tab order. The mobile header gets the same switch, compact. The language selector stays a list, since more languages are expected, on its own row as wide as the sidebar. <html data-theme> still holds the resolved light/dark, so the CSS and the chart colours did not change. The pre-paint script in index.html mirrors the new lib/theme.ts. Closes #17
The first version was a rectangular segmented control with a solid blue fill on the selected option. It worked but looked heavy next to the rest of the sidebar. The switch is now a small rounded pill with a knob in the brand emerald that slides to the chosen option, the selected icon white and the others muted. Theme and language sit on two rows, label on the left in the same small caps as the Dashboard "Admission" label, control on the right; the language list is a pill too and truncates instead of pushing past the sidebar edge. The mobile header uses the same pill. The selected icon uses a literal white: the light theme remaps text-white to near-black, which would have put a dark icon on the knob.
…heme The Dashboard admission switch (Full auto / Flex) and the per-Node SG / Manual switch were the rectangular segmented controls the theme switch started from. They now use the same pill, through a shared PillSwitch: equal-width options, a knob that slides one slot per position, emerald, or amber while a Node is in Manual. The read-only badges shown without nodes:operation-mode are pills too. The theme switch is now PillSwitch with icons, and the arrow-key logic moved to lib/pill-switch.ts so every switch shares it.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What was wrong / what was missing
The sidebar footer put the theme button and the language selector side by side in a 192px sidebar. They did not fit: the selector spilled past the sidebar edge — visible in every README screenshot — and Light theme wrapped onto two lines. The theme was also only light or dark, and a first visit always got dark, whatever the operating system preferred.
What this changes
prefers-color-schemeand changes live when the operating system does. It is the default for anyone who never chose; a savedlightordarkis kept.radiogroup/radiowitharia-checked, arrow keys move the selection (rovingtabindex), focus ring on the whole pill, translated labels and tooltips.PillSwitchwith equal-width options; the knob turns amber while a Node is in Manual. The read-only badges are pills too.<html data-theme>still holds the resolvedlight/dark, so the CSS and the chart colours (useTheme) are untouched. The pre-paint script inindex.htmlmirrors the newsrc/lib/theme.ts.sg-themevalues.README screenshots are retaken in a follow-up, once this is merged.
How it was verified
src/lib/theme.test.ts(saved choice, default, blocked storage, resolution),src/lib/pill-switch.test.ts(keyboard wrap-around),src/components/PillSwitch.test.tsx(radiogroup, knob slot and tone, only the selected option checked and tabbable, busy) andsrc/components/ThemeSwitch.test.tsx(order, labels, language).node:22container:tsc --noEmit,vitest(733 passing),npm run build; the no-literals guard covers the new component.Checklist
CHANGELOG.mdupdated under[Unreleased], if users will notice the changeCloses #17
🤖 Generated with Claude Code
https://claude.ai/code/session_01Tk9HuwXZP8CdJu5vRLaoBq