|
import { create } from "zustand"; |
|
import { createJSONStorage, persist } from "zustand/middleware"; |
|
|
|
export type ThemeMode = "dark" | "light"; |
|
export type UserThemeMode = ThemeMode | "system"; |
|
|
|
export type ThemeStore = { |
|
userPreference: UserThemeMode; |
|
systemPreference: ThemeMode; |
|
setPreference: (preference: UserThemeMode) => void; |
|
getTheme: () => ThemeMode; |
|
}; |
|
|
|
const systemDarkMode = window.matchMedia("(prefers-color-scheme: dark)"); |
|
|
|
export const useThemeStore = create<ThemeStore>()( |
|
persist( |
|
(set, get): ThemeStore => ({ |
|
userPreference: "system", |
|
systemPreference: systemDarkMode.matches ? "dark" : "light", |
|
getTheme: (): ThemeMode => { |
|
const { userPreference, systemPreference } = get(); |
|
|
|
if (userPreference === "system") { |
|
return systemPreference; |
|
} else { |
|
return userPreference; |
|
} |
|
}, |
|
setPreference: (preference): void => set({ userPreference: preference }), |
|
}), |
|
{ |
|
name: "app-theme", |
|
storage: createJSONStorage(() => localStorage), |
|
}, |
|
), |
|
); |
|
|
|
function setRootClass(theme: ThemeMode): void { |
|
const root = window.document.documentElement; |
|
|
|
root.classList.remove("light", "dark"); |
|
root.classList.add(theme); |
|
} |
|
|
|
// Ensures the root class is set on initial page load |
|
setRootClass(useThemeStore.getState().getTheme()); |
|
|
|
useThemeStore.subscribe((store) => { |
|
setRootClass(store.getTheme()); |
|
}); |
|
|
|
systemDarkMode.addEventListener("change", (event) => { |
|
useThemeStore.setState({ |
|
systemPreference: event.matches ? "dark" : "light", |
|
}); |
|
}); |