Press n or j to go to the next uncovered block, b, p or k for the previous block.
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 | 1x 1x 3x 3x 5x 5x 2x 5x 2x 5x 5x 5x 5x 5x 5x | "use client";
import {
createContext,
useCallback,
useContext,
useMemo,
useSyncExternalStore,
type ReactNode,
} from "react";
// Constants
import {
DEFAULT_THEME,
THEME_CHANGE_EVENT,
isDarkTheme,
ThemeMode,
type Theme,
} from "@/constants/theme";
// Libs
import { getThemeFromDocument, persistTheme } from "@/lib/theme";
// Types
type ThemeContextValue = {
theme: Theme;
setTheme: (theme: Theme) => void;
toggleTheme: () => void;
};
const ThemeContext = createContext<ThemeContextValue | null>(null);
function subscribe(listener: () => void) {
window.addEventListener(THEME_CHANGE_EVENT, listener);
return () => window.removeEventListener(THEME_CHANGE_EVENT, listener);
}
export function ThemeProvider({ children }: { children: ReactNode }) {
const theme = useSyncExternalStore(
subscribe,
getThemeFromDocument,
() => DEFAULT_THEME,
);
const setTheme = useCallback((next: Theme) => {
persistTheme(next);
}, []);
const toggleTheme = useCallback(() => {
setTheme(isDarkTheme(theme) ? ThemeMode.Light : ThemeMode.Dark);
}, [setTheme, theme]);
const value = useMemo(
() => ({ theme, setTheme, toggleTheme }),
[theme, setTheme, toggleTheme],
);
return <ThemeContext.Provider value={value}>{children}</ThemeContext.Provider>;
}
export function useTheme() {
const context = useContext(ThemeContext);
Iif (!context) {
throw new Error("useTheme must be used within ThemeProvider");
}
return context;
}
|