1"use client";
2
3import { createContext, useCallback, useContext, useEffect, useMemo, useState, type ReactNode } from "react";
4import { applyTheme, useSystemThemeSync, useUiStore, type Theme } from "@/stores/ui-store";
5
6interface ThemeContextValue {
7 theme: Theme;
8 setTheme: (theme: Theme) => void;
9 toggleTheme: () => void;
10}
11
12const ThemeContext = createContext<ThemeContextValue | null>(null);
13
14
18export function ThemeProvider({ children }: { children: ReactNode }) {
19 const theme = useUiStore((s) => s.theme);
20 const setTheme = useUiStore((s) => s.setTheme);
21 const [mounted, setMounted] = useState(false);
22
23 useEffect(() => {
24 applyTheme(theme);
25 setMounted(true);
26 }, [theme]);
27
28 useSystemThemeSync();
29
30 const toggleTheme = useCallback(() => {
31 const current = useUiStore.getState().theme;
32 const next: Theme =
33 current === "light" ? "dark" : current === "dark" ? "system" : "light";
34 useUiStore.getState().setTheme(next);
35 }, []);
36
37 const value = useMemo(
38 () => ({ theme: mounted ? theme : "light", setTheme, toggleTheme }),
39 [theme, setTheme, toggleTheme, mounted]
40 );
41
42 return <ThemeContext.Provider value={value}>{children}</ThemeContext.Provider>;
43}
44
45export function useTheme(): ThemeContextValue {
46 const ctx = useContext(ThemeContext);
47 if (!ctx) throw new Error("useTheme must be used within <ThemeProvider>");
48 return ctx;
49}
50