From 27c690285ac45e4a1d62f3da15f6a57808c4d941 Mon Sep 17 00:00:00 2001 From: BOHA Date: Sun, 7 Jun 2026 18:12:20 +0200 Subject: [PATCH] fix(theme): white icon glyphs on solid tiles + single theme storage key MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Two issues: 1. Icon badges read as a coloured glyph on a same-hue LIGHT tile (bgcolor X.light + color X.main) — low contrast, "badly visible". The AttendanceHistory month tile and the Dashboard 2FA-banner icon now use a SOLID tile (X.main) + white glyph, matching the StatCard badge convention. Readable in both schemes (verified: info.main #1d4ed8 light / #3b82f6 dark, error.main, white glyph). 2. Theme reverted to light on F5 while the toggle still showed dark. Cause: two independent stores — our ThemeContext key (boha-theme) and MUI's own cssVariables mode key (mui-mode). The toggle only wrote boha-theme, so on mount MUI restored its stale mui-mode and overrode data-theme. Collapsed to a SINGLE source of truth: ThemeContext now reads/writes MUI's `mui-mode` key directly (with a one-time migration from the legacy boha-theme, which is then removed). Verified: toggle dark -> F5 -> stays dark; only `mui-mode` remains in localStorage. tsc -b --noEmit, npm run build, vitest 152/152 clean. Co-Authored-By: Claude Opus 4.8 (1M context) --- src/admin/pages/AttendanceHistory.tsx | 4 ++-- src/admin/pages/Dashboard.tsx | 4 ++-- src/context/ThemeContext.tsx | 15 ++++++++++----- 3 files changed, 14 insertions(+), 9 deletions(-) diff --git a/src/admin/pages/AttendanceHistory.tsx b/src/admin/pages/AttendanceHistory.tsx index e093d1b..5c43b2f 100644 --- a/src/admin/pages/AttendanceHistory.tsx +++ b/src/admin/pages/AttendanceHistory.tsx @@ -540,8 +540,8 @@ export default function AttendanceHistory() { width: 44, height: 44, borderRadius: 2, - bgcolor: "info.light", - color: "info.main", + bgcolor: "info.main", + color: "#fff", flexShrink: 0, }} > diff --git a/src/admin/pages/Dashboard.tsx b/src/admin/pages/Dashboard.tsx index 2cea3f5..8aecf37 100644 --- a/src/admin/pages/Dashboard.tsx +++ b/src/admin/pages/Dashboard.tsx @@ -260,8 +260,8 @@ export default function Dashboard() { display: "flex", alignItems: "center", justifyContent: "center", - bgcolor: "error.light", - color: "error.main", + bgcolor: "error.main", + color: "#fff", flexShrink: 0, }} > diff --git a/src/context/ThemeContext.tsx b/src/context/ThemeContext.tsx index b0872a3..3eb910f 100644 --- a/src/context/ThemeContext.tsx +++ b/src/context/ThemeContext.tsx @@ -20,10 +20,14 @@ type ViewTransitionDocument = Document & { export function ThemeProvider({ children }: { children: ReactNode }) { const [theme, setTheme] = useState(() => { - if (typeof window !== "undefined") { - return localStorage.getItem("boha-theme") || "dark"; - } - return "dark"; + if (typeof window === "undefined") return "dark"; + // Single source of truth = MUI's own mode key. MUI's cssVariables provider + // reads `mui-mode` on mount and sets `data-theme` from it, so we read/write + // that SAME key (no separate boha-theme) — page and toggle stay in sync + // across reloads. Fall back to the legacy key for pre-existing sessions. + const stored = + localStorage.getItem("mui-mode") || localStorage.getItem("boha-theme"); + return stored === "light" || stored === "dark" ? stored : "dark"; }); // Apply synchronously (layout effect) so the `data-theme` attribute flips @@ -31,7 +35,8 @@ export function ThemeProvider({ children }: { children: ReactNode }) { // the "after" snapshot and cross-fade to it. useLayoutEffect(() => { document.documentElement.setAttribute("data-theme", theme); - localStorage.setItem("boha-theme", theme); + localStorage.setItem("mui-mode", theme); + localStorage.removeItem("boha-theme"); // retire the duplicate legacy key const themeColor = theme === "dark" ? "#12121a" : "#ffffff"; document .querySelector('meta[name="theme-color"]')