fix(desktop): restore dark mode in the desktop shell - #109
Merged
Conversation
The desktop shell embeds six full HTML pages as Rust string literals in `desktop/src-tauri/src/*.rs`, plus a custom titlebar injected into the SPA's own document. None of it is `.css`/`.tsx`, so when dark mode shipped it was left behind entirely and still renders hardcoded light. What users hit: - On macOS the whole main window is forced back to light. `MAC_OFFSET_SPA` sets `background:…#FFFFFF…,#F5F6F7!important` — with `!important`, so the app's own dark background cannot win. That strip was copied from the sidebar's old blue recipe, and the sidebar has since been tokenised to `color-mix(in srgb, var(--color-bg-gray) 72%, transparent)`, so it had also drifted out of sync in light mode. - On Windows/Linux the titlebar is a solid `#F7F8FA` bar above a dark app, with `#fff` dropdown menus. - The login, first-run, local-setup, close-confirm and server-address pages are all light. Login and close-confirm are hit daily. The titlebar and offset styles are injected into the SPA's own document, so `<html data-theme>` already applies to them: they now reference the app's tokens and follow both themes with no extra dark block. The macOS strip mirrors `.jx-sider`'s current recipe again, so future sidebar changes only need editing `sidebar.css`. The five shell pages are separate documents with no access to that attribute. They are served same-origin by the local proxy, so a new `THEME_BOOT_JS` reads the same `hugagent_theme_mode` key using rules identical to the anti-flicker script in `index.html` — meaning "manually chose dark while the OS is light" is honoured too. `prefers-color-scheme` cannot do that; it only follows the OS and fights the manual three-way toggle. The one exception is the updater progress window: it loads from a `data:text/html` URL — an opaque origin that cannot read localStorage — so it keeps the media query, with the reason and trade-off documented in place. Tests: two new cases alongside the existing 41, all green — `injected_shell_styles_carry_no_hardcoded_colors` (styles injected into the SPA must carry no colour literals) and `every_shell_page_boots_and_defines_both_themes` (every shell page needs the theme bootstrap *before* its `<style>`, a dark override block, and no `prefers-color-scheme`).
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.
The desktop shell embeds six full HTML pages as Rust string literals in
desktop/src-tauri/src/*.rs, plus a custom titlebar injected into the SPA's own document. None of it is.css/.tsx, so when dark mode shipped it was left behind entirely and still renders hardcoded light.What users hit
MAC_OFFSET_SPAsetsbackground:…#FFFFFF…,#F5F6F7!important— with!important, so the app's own dark background cannot win. That strip was copied from the sidebar's old blue recipe, and the sidebar has since been tokenised tocolor-mix(in srgb, var(--color-bg-gray) 72%, transparent), so it had also drifted out of sync in light mode.#F7F8FAbar above a dark app, with#fffdropdown menus.Approach
The titlebar and offset styles are injected into the SPA's own document, so
<html data-theme>already applies to them: they now reference the app's tokens and follow both themes with no extra dark block. The macOS strip mirrors.jx-sider's current recipe again, so future sidebar changes only need editingsidebar.css.The five shell pages are separate documents with no access to that attribute. They are served same-origin by the local proxy, so a new
THEME_BOOT_JSreads the samehugagent_theme_modekey using rules identical to the anti-flicker script inindex.html— meaning "manually chose dark while the OS is light" is honoured too.prefers-color-schemecannot do that; it only follows the OS and fights the manual three-way toggle.The one exception is the updater progress window: it loads from a
data:text/htmlURL — an opaque origin that cannot readlocalStorage— so it keeps the media query, with the reason and trade-off documented in place.Tests
Two new cases alongside the existing 41, all green:
injected_shell_styles_carry_no_hardcoded_colors— styles injected into the SPA must carry no colour literals (the Windows close-button red is the one documented exemption).every_shell_page_boots_and_defines_both_themes— every shell page needs the theme bootstrap before its<style>(otherwise dark users get a white flash), a dark override block, and noprefers-color-scheme.Follow-up
This repo has no dark-mode build gate, so nothing stops the next shell page from being written light again. A separate PR adds that feedback loop.