vignette/apps/web/src/pages/settings/useTheme.ts
2026-06-27 18:09:48 +09:00

36 lines
1.4 KiB
TypeScript

/* =====================================================================
useTheme — 라이트/다크 토글 상태.
Topbar 와 동일한 lib/theme 단일 경로를 사용한다.
===================================================================== */
import { useCallback, useEffect, useState } from "react";
import { applyTheme, readInitialTheme } from "../../lib/theme";
/** [dark, setDark] — Topbar 토글과 같은 키/속성을 사용. */
export function useTheme(): [boolean, (next: boolean) => void] {
const [dark, setDark] = useState<boolean>(() => {
if (typeof document !== "undefined") {
const attr = document.documentElement.getAttribute("data-theme");
if (attr === "dark") return true;
if (attr === "light") return false;
}
return readInitialTheme() === "dark";
});
useEffect(() => {
applyTheme(dark ? "dark" : "light");
}, [dark]);
// 다른 곳(Topbar)에서 속성을 바꾸면 따라잡기 위해 마운트 시 1회 동기화
useEffect(() => {
const root = document.documentElement;
const observer = new MutationObserver(() => {
const isDark = root.getAttribute("data-theme") === "dark";
setDark((prev) => (prev === isDark ? prev : isDark));
});
observer.observe(root, { attributes: true, attributeFilter: ["data-theme"] });
return () => observer.disconnect();
}, []);
const set = useCallback((next: boolean) => setDark(next), []);
return [dark, set];
}