D3: Dark mode toggle (Phase 3 stretch)#3
Merged
Merged
Conversation
Implements the D3 desired item from the RFP — operator-selectable theme,
targeted at low-light warehouse stations per the proposal. Built on a
separate feat/dark-mode branch via git worktree so the main PR stays focused
on R1-R4 and this can be reviewed (or shelved) independently.
Architecture
- useTheme composable persists the choice in localStorage and applies a
data-theme="dark" attribute to <html>.
- App.vue's <style> (intentionally non-scoped) hosts the CSS-variable
palette: :root for light, :root[data-theme="dark"] for dark. Per-component
scoped styles still apply on top — overrides cover only the high-traffic
surfaces (banner, filter bar, cards, tables, badges, page headers).
- ThemeToggle.vue is a small banner button with a sun/moon icon swap.
- color-scheme set to match so native form controls (selects, scrollbars)
follow.
Coverage
- High-traffic surfaces flip cleanly.
- Long-tail per-view scoped styles remain on the original light palette in
dark mode and are tracked as Phase-3 polish follow-on (see PR description).
Tests
- tests/e2e/specs/09-dark-mode.spec.js — 5 specs covering toggle visibility,
default light, click → dark with localStorage persistence and luminance
check, click again → light, full-reload persistence.
- Test note: localStorage seed must be done via page.evaluate AFTER goto
(not addInitScript) so a later page.reload() doesn't re-clear the value.
Body has a 0.2s background-color transition; tests poll until the colour
settles.
Verification
- 53/53 Playwright tests pass on this branch (was 48; +5 for Flow lindsey-anthropic#9).
- Manual probe via Playwright MCP: toggle flips data-theme, body bg switches
from rgb(248,250,252) to rgb(11,17,32), preference survives reload.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Initial dark mode (commit 09bbbe5 on this branch — wait, prior commit on this branch) covered the global surfaces but missed several view-scoped classes whose CSS specificity ties with our globals and whose stylesheet is loaded after App.vue. Surfaced visually as white islands on the dashboard: - Dashboard `.kpi-card` (the five Key Performance Indicator cards) - FilterBar `.filter-select` and `.filters-bar` - LanguageSwitcher `.language-button` - ProfileMenu `.profile-button` - FilterBar `.reset-filters-btn` - Dashboard `.h-bar-container` and `.task-item:hover` - `.clickable-row:hover` (Dashboard had `!important` on light hover) Approach - Add `:root[data-theme="dark"]` selectors with `!important` for the specific class names. The trade-off (using !important) is bounded to the dark-mode override block; light mode is unaffected. - Cover dropdown menus too (LanguageSwitcher dropdown, ProfileMenu items) so the click states stay coherent. This is still a prototype; full per-view refactor of every scoped style to use the CSS variables would be the production-grade path. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Two issues spotted in the profile-menu popover:
1. Dropdown header banner (.dropdown-header), user name/email, divider, and
logout item still rendered with their light-mode component-scoped styles.
Added overrides under :root[data-theme="dark"] for:
.dropdown-header, .user-name, .user-email, .profile-name,
.dropdown-divider, .dropdown-item.logout (+ hover), .task-badge
2. composables/useAuth.js still hardcoded john.doe@catalystcomponents.com —
the previous brand-correction pass (lindsey-anthropic#15) only caught the H1 in the locale
files. This is the email field shown inside the dropdown header. Renamed
to john.doe@meridiancomponents.example to match the brand.
Verified via Playwright MCP:
- All dropdown surfaces resolve to dark tokens
- Email text in DOM now reads "john.doe@meridiancomponents.example"
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
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.
Summary
D3 desired item from the RFP — operator-selectable theme for low-light warehouse stations. Three commits, cherry-picked off the original PR #2 onto main after PR #1 squash-merged.
What's in this PR
Composable + component
Theming
Bonus brand fix
Tests
Test plan
History note
Original PR #2 (now closed) had base on `phase-1-m1-stabilize-document`. After PR #1 squash-merged, that branch was deleted and the rebase produced too many conflicts with the squashed history. Cleaner to cherry-pick the 3 dark-mode commits onto fresh main:
🤖 Generated with Claude Code