feat: M2 — light/dark theme toggle + persistence#96
Merged
Conversation
Adds <se-theme-toggle id="theme_toggle"> to the MainMenu top bar as a
sibling of the main_button menu. The component wires to the svgedit-
themechange event for live icon sync (sun↔moon), toggleTheme() for
apply+announce, and bubbles toggle-theme so MainMenu can persist the
choice via configObj.pref('theme'). E2e test verified on chromium+firefox
(explicit LS+cookie write needed to exercise loadContentAndPrefs gate in
headless Playwright — see DONE_WITH_CONCERNS note).
…okens - server.ts: swap import from legacy embed/theme.js to editor/styles/theme.js applyTheme()/resolveInitialTheme(); params.theme and __setTheme now set html[data-theme] instead of adding theme-* CSS classes to body - Delete src/embed/theme.ts (legacy class-based module, now unreferenced) - Delete tests/unit/embed-theme.test.ts (tested only the retired module) - Update embed-server tests: assert html[data-theme] attribute instead of body.classList theme-* checks; add data-theme cleanup in beforeEach - tsconfig.embed.json: widen rootDir from src/embed to src so server.ts may import from src/editor/styles/theme.ts without TS6059 error
Follow-up to the embed __setTheme/?theme= reroute (217af95): the embed theme reroute now sets html[data-theme] inside the iframe instead of adding body.classList theme-* classes, so these two e2e assertions were left failing. Update them to read frame :root [data-theme]; await the setTheme round-trip via expect.poll. Echo-loop-prevention test unchanged (asserts event emission).
… module) — restores dist/embed/index.js
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.
M2 — Theme Toggle + Persistence
User-facing light/dark theming on top of M1's tokens. Implements
docs/.../specs/2026-06-02-svgedit-theme-toggle-design.md.Commits
theme.tsextended —getCurrentTheme/toggleTheme/resolveInitialTheme+applyThemedispatches asvgedit-themechangeCustomEvent.themepref + startup — apply persisted theme afterconfigObj.load()(stored choice wins over OS; no FOUC).se-theme-toggle— top-bar sun/moon icon (token chrome +currentColorSVG); click toggles + persists viaConfigObj.pref('theme')→ ext-storage/localStorage.__setTheme/?theme=rerouted from the legacy class-basedsrc/embed/theme.ts(retired) to M1'shtml[data-theme]tokens; embed unit + e2e tests updated to assertdata-theme.?theme=standalone — honored at startup (URL > stored pref > system).--se-text(probe element) + redraw onsvgedit-themechange. Closes the M1 follow-up (rulers were stuck black in dark mode).Verified locally:
npm run buildgreen;npx vitest run733 (738 −5 retired legacy embed-theme unit tests);npm run lintgreen (enforcing hex-guard — toggle uses tokens + currentColor); e2e green (chromium): theme toggle+persist,?theme=dark, ruler ink follows theme, embeddata-theme. Full cross-browser e2e on CI.Behavior: persistence is gated on the user's storage opt-in (consistent with how svgedit persists all prefs). Base = master (incl. M1). Second item of the UI-Modernization program.