diff --git a/web/src/main.tsx b/web/src/main.tsx index 8884e8495..038d4ee6c 100644 --- a/web/src/main.tsx +++ b/web/src/main.tsx @@ -8,8 +8,12 @@ import "./index.css"; import router from "./router"; import { initialUserStore } from "./store/user"; import { initialWorkspaceStore } from "./store/workspace"; +import { applyThemeEarly } from "./utils/theme"; import "leaflet/dist/leaflet.css"; +// Apply theme early to prevent flash of wrong theme +applyThemeEarly(); + const Main = observer(() => ( <> diff --git a/web/src/utils/theme.ts b/web/src/utils/theme.ts index 75570b0a6..83a8ffac7 100644 --- a/web/src/utils/theme.ts +++ b/web/src/utils/theme.ts @@ -16,6 +16,43 @@ const validateTheme = (theme: string): ValidTheme => { return VALID_THEMES.includes(theme as ValidTheme) ? (theme as ValidTheme) : "default"; }; +/** + * Detects system theme preference + */ +export const getSystemTheme = (): "default" | "default-dark" => { + if (typeof window !== "undefined" && window.matchMedia) { + return window.matchMedia("(prefers-color-scheme: dark)").matches ? "default-dark" : "default"; + } + return "default"; +}; + +/** + * Gets the theme that should be applied on initial load + * Priority: stored user preference -> system preference -> default + */ +export const getInitialTheme = (): ValidTheme => { + // Try to get stored theme from localStorage (where user settings might be cached) + try { + const storedTheme = localStorage.getItem("memos-theme"); + if (storedTheme && VALID_THEMES.includes(storedTheme as ValidTheme)) { + return storedTheme as ValidTheme; + } + } catch { + // localStorage might not be available + } + + // Fall back to system preference + return getSystemTheme(); +}; + +/** + * Applies the theme early to prevent flash of wrong theme + */ +export const applyThemeEarly = (): void => { + const theme = getInitialTheme(); + loadTheme(theme); +}; + export const loadTheme = (themeName: string): void => { const validTheme = validateTheme(themeName); @@ -35,4 +72,11 @@ export const loadTheme = (themeName: string): void => { // Set data attribute document.documentElement.setAttribute("data-theme", validTheme); + + // Store theme preference for future loads + try { + localStorage.setItem("memos-theme", validTheme); + } catch { + // localStorage might not be available + } };