fix(webui): persist theme to server so it survives restarts/browsers - #634
fix(webui): persist theme to server so it survives restarts/browsers#634HerryOS wants to merge 1 commit into
Conversation
Theme was stored only in browser localStorage (key: flocks_theme), which is scoped to a single origin and lost when the browser clears site data, the user switches devices, or the app is served from a different port. Unlike display-name and favicon which are persisted server-side via /api/config/ui, theme had no server-side durability at all. Changes: - Server: add theme field to UIConfig model (config.py) and expose it through the existing UIDisplayResponse / UIConfigUpdateRequest in the /api/config/ui PATCH + /api/config/ui-display GET endpoints. - Client: ThemeProvider fetches the server-stored theme on mount and uses it as the source of truth (localStorage falls back when the server is unreachable). Every theme change is persisted to both localStorage (fast, synchronous, used by index.html anti-flash script) and the server API (durable across origins/devices). - Fix getInitialTheme() to respect prefers-color-scheme:dark as a fallback, matching the index.html inline script behavior and eliminating the flash of wrong theme on first load. - Fix index.html inline script to also remove the dark class in the else branch, guarding against BFCache restoring stale DOM state. - Add try/catch around all localStorage operations so that restricted storage contexts (private browsing, quota exceeded) don't crash the app and the theme silently falls back to the default. - Update ThemeContext, Settings, and WebUIContractWorkspaceHost tests to mock uiConfigApi and cover the new server-persistence flows. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
|
[P1] Partial UI updates delete fields that were not provided [P2] A delayed bootstrap request can overwrite a newer user selection Additional integration notes: |
Problem
Theme settings (light/dark) did not persist across restarts. The theme was stored only in browser
localStorage(key:flocks_theme), which is scoped to a single origin and lost when:Unlike display name and favicon — which are persisted server-side via
/api/config/ui— theme had no server-side durability.Changes
Server-side
themefield (Optional[Literal["light", "dark"]]) toUIConfigmodel inflocks/config/config.pythemethrough the existingUIDisplayResponseandUIConfigUpdateRequestin/api/config/uiendpointsPATCH /api/config/uinow accepts and persiststhemeGET /api/config/ui-displaynow returnsthemeClient-side
index.htmlanti-flash) and the server API (durable across origins)getInitialTheme()to respectprefers-color-scheme: darkas a fallback, matching theindex.htmlinline script behavior (eliminates flash of wrong theme on first load)index.htmlinline script to also remove thedarkclass in the else branch, guarding against BFCache restoring stale DOM stateTests
ThemeContext.test.tsxwith 10 tests covering server persistence, system preference fallback, localStorage unavailability, and server failureuiConfigApimocks toSettingsandWebUIContractWorkspaceHosttestsTest Results
🤖 Generated with Claude Code