Skip to content

fix(ui): persist theme selection across page reloads - #33

Open
CatJuly wants to merge 1 commit into
HKUDS:mainfrom
CatJuly:fix/persist-theme-selection
Open

fix(ui): persist theme selection across page reloads#33
CatJuly wants to merge 1 commit into
HKUDS:mainfrom
CatJuly:fix/persist-theme-selection

Conversation

@CatJuly

@CatJuly CatJuly commented Aug 8, 2026

Copy link
Copy Markdown
Contributor

Summary

The theme selected in the top-bar picker does not survive a page reload — every refresh resets the UI to the default openopc theme, forcing users to re-select their preference each time.

Repro: switch to any non-default theme (e.g. Paper) → press F5 → the UI is back to the default theme.

Root cause

App.tsx keeps the theme in plain React state with a hardcoded initial value:

const [theme, setTheme] = useState<ThemeName>('openopc')

Nothing ever writes the choice anywhere, so each page load re-initializes from the literal. Notably the neighbouring preferences — locale (openopc_locale), sidebar collapse (opc_office_sidebar_collapsed), and the outdoor-lighting override (opc_outdoor_override) — all already persist through localStorage; the theme was the one preference that never did.

Fix

Follow the file's own persistence conventions:

  • Lazy-initialize the state from opc_office_theme, validating the stored value against the known theme names so a stale or tampered entry falls back to the default instead of producing a broken class name.
  • Write the key on every picker change.
  • Both sides wrapped in try/catch like the neighbouring preferences, so private-browsing modes degrade gracefully to the old in-memory behaviour.

Testing

  • npm run typecheck — clean
  • npm run build — clean; rebuilt frontend_dist bundle included
  • Manual: switched to Paper → hard refresh → Paper restored; repeated across other themes and a tab close/reopen; seeded an invalid value into opc_office_theme and confirmed fallback to the default

Scope

Frontend only (App.tsx + rebuilt dist). Independent of my other open PRs — no shared files.

The theme picker kept its value in plain React state, so every page
refresh reset the UI to the default `openopc` theme and the user had to
re-select their preference each time. Locale, sidebar collapse, and the
outdoor-lighting override already survive reloads through localStorage;
the theme was the one preference that never did.

Initialize the theme state lazily from `opc_office_theme` (validated
against the known theme names so a stale or tampered value falls back
to the default) and write the key on every change, wrapped in
try/catch like the neighbouring preferences so private browsing modes
degrade gracefully.

Verified with `npm run typecheck` and `npm run build`; manually
switched to the paper theme, hard-refreshed, and the paper theme was
restored; an invalid stored value falls back to the default.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant