fix(ui): prevent light-theme flash during dark and system-mode startup - #55
Merged
Merged
Conversation
Proxicon
marked this pull request as ready for review
September 16, 2026 14:12
This was referenced Sep 16, 2026
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.
Closes #54
Implementation commit:
f90a2f0fe82891da4c93490abaa66d3627b6e9d9Cause and correction
The existing synchronous head script set
data-helpdesk-theme, but the firstMudThemeProviderrender still emitted its light CSS variables. The body, paper/card, text, app bar, drawer, and input surfaces consume those variables, so a dark document attribute alone could still visibly render a light application palette before interactivity completed.This change adds a tiny synchronous bootstrap before stylesheet links. It normalizes the existing preference contract, safely falls back to system preference if storage or
matchMediais unavailable, and sets the document attribute pluscolor-scheme.RatelDeskPrepaintThemederives all prepaint palette variables fromRatelDeskTheme; selector specificity keeps that resolved palette authoritative while MudBlazor hydrates. The original footer helper is removed so there is one browser preference implementation. The provider also prevents an in-flight initial storage read from overwriting a newer explicit selection.Startup behavior preserved
The public root remains server-rendered and retains its existing Blazor/Mud scripts and interactive functionality. No eager circuit, runtime dependency, loading gate, or extra fetched asset was added. The previous 561-byte
js/theme-preference.jsrequest is removed; the replacement bootstrap and palette are inline in the existing HTML head, so there is no new network request.Regression evidence
tests/ux/theme-first-paint.spec.tsseeds only the preference and OS emulation, holds the noncritical Blazor runtime request behind an explicit gate, and captures animation-frame computed colors from visible prerendered body, portal card, and heading before and after release. It covers normalized System+dark, explicit Dark+light, and explicit Light+dark cases.Validation
dotnet restore Helpdesk.slndotnet build Helpdesk.sln --configuration Release --no-restoredotnet test Helpdesk.sln --configuration Release --no-build— 1,135 passed, 6 existing skipsdotnet publish src/HelpDesk.NewWeb/HelpDesk.NewWeb.csproj --configuration Release --no-restore --no-build --output /tmp/rateldesk-theme-first-paint-publishHELPDESK_E2E_AUTH_MODE=development tools/ci/run-ux-local.sh --grep 'persists manual light and dark choices|keeps the (dark|light) palette'— 4 passed, plus setup validationportrait tablet uses an aligned two-column catalogue and mobile drawer lifecyclefailed its existing tablet-catalogue geometry assertion. Theme-specific cases and the existing manual preference regression passed. This PR remains draft pending owner disposition of that unrelated failure.Owner verification
In a fresh profile, verify System+dark first arrival and refresh, explicit Dark refresh, public portal navigation, authenticated refresh, explicit Light on a dark OS, System mode switching after an OS change, and a throttled/delayed-runtime refresh while content remains visible. No merge, release, or deployment is included.