| 1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283 |
- 'use client';
- import { createContext, useContext, useEffect, useState, useCallback } from 'react';
- type Theme = 'light'|'dark';
- type Density = 'compact'|'normal'|'expanded';
- const THEME_KEY = 'az-theme';
- const LEGACY_THEME_KEY = 'bitforum-theme'; // 구 키 마이그레이션용
- const DENSITY_KEY = 'az-density';
- const ThemeContext = createContext<{
- theme: Theme;
- toggleTheme: () => void;
- density: Density;
- setDensity: (density: Density) => void;
- }>({
- theme: 'dark',
- toggleTheme: () => {},
- density: 'normal',
- setDensity: () => {},
- });
- export function useThemeContext() {
- return useContext(ThemeContext);
- }
- // html 루트에 테마 반영 — .dark/.light 클래스(tailwind dark: variant 용) + data-theme(토큰 스위칭 용)
- function applyTheme(theme: Theme) {
- const root = document.documentElement;
- root.classList.toggle('dark', theme === 'dark');
- root.classList.toggle('light', theme === 'light');
- root.dataset.theme = theme;
- }
- export function ThemeProvider({ children }: { children: React.ReactNode }) {
- // 기본 다크 (D6 확정) — 첫 페인트는 app/layout.tsx 의 인라인 스크립트가 결정 (FOUC 방지)
- const [theme, setTheme] = useState<Theme>('dark');
- const [density, setDensityState] = useState<Density>('normal');
- const [mounted, setMounted] = useState(false);
- useEffect(() => {
- const stored = localStorage.getItem(THEME_KEY) ?? localStorage.getItem(LEGACY_THEME_KEY);
- const initial: Theme = stored === 'light' ? 'light' : 'dark';
- if (!localStorage.getItem(THEME_KEY) && stored) {
- localStorage.setItem(THEME_KEY, initial);
- }
- const storedDensity = localStorage.getItem(DENSITY_KEY);
- const initialDensity: Density = storedDensity === 'compact' || storedDensity === 'expanded' ? storedDensity : 'normal';
- setTheme(initial);
- setDensityState(initialDensity);
- applyTheme(initial);
- document.documentElement.dataset.density = initialDensity;
- setMounted(true);
- }, []);
- const toggleTheme = useCallback(() => {
- setTheme((prev) => {
- const next = prev === 'light' ? 'dark' : 'light';
- localStorage.setItem(THEME_KEY, next);
- applyTheme(next);
- return next;
- });
- }, []);
- const setDensity = useCallback((next: Density) => {
- setDensityState(next);
- localStorage.setItem(DENSITY_KEY, next);
- document.documentElement.dataset.density = next;
- }, []);
- if (!mounted) {
- return <>{children}</>;
- }
- return (
- <ThemeContext.Provider value={{ theme, toggleTheme, density, setDensity }}>
- {children}
- </ThemeContext.Provider>
- );
- }
|