Newer
Older
client_dwatch / components / theme / ThemeProvider.tsx
"use client";

import {
  createContext,
  useCallback,
  useContext,
  useEffect,
  useMemo,
  useState,
} from "react";
import { translate, type Lang } from "@/lib/i18n";
import type { ThemeName } from "@/lib/theme";

interface ThemeContextValue {
  theme: ThemeName;
  lang: Lang;
  toggleTheme: () => void;
  toggleLang: () => void;
  t: (text: string) => string;
}

const ThemeContext = createContext<ThemeContextValue | null>(null);

export function ThemeProvider({ children }: { children: React.ReactNode }) {
  const [theme, setTheme] = useState<ThemeName>("dark");
  const [lang, setLang] = useState<Lang>("ja");

  useEffect(() => {
    document.documentElement.dataset.theme = theme;
    document.documentElement.lang = lang === "ja" ? "ja" : "en";
  }, [theme, lang]);

  const toggleTheme = useCallback(() => {
    setTheme((prev) => (prev === "dark" ? "light" : "dark"));
  }, []);

  const toggleLang = useCallback(() => {
    setLang((prev) => (prev === "ja" ? "en" : "ja"));
  }, []);

  const t = useCallback((text: string) => translate(lang, text), [lang]);

  const value = useMemo(
    () => ({ theme, lang, toggleTheme, toggleLang, t }),
    [theme, lang, toggleTheme, toggleLang, t]
  );

  return (
    <ThemeContext.Provider value={value}>{children}</ThemeContext.Provider>
  );
}

export function useTheme(): ThemeContextValue {
  const ctx = useContext(ThemeContext);
  if (!ctx) {
    throw new Error("useTheme must be used within ThemeProvider");
  }
  return ctx;
}