테마
라이트 · 다크 · 시스템 테마를 전환하는 Provider, 토글 버튼, 훅입니다. next-themes 가 html 에 class 를 붙입니다.
토큰이 .dark 에서 재정의되므로 컴포넌트에는 테마별 코드가 필요 없습니다. 그늘처럼 겹 값이 바뀌는 것도 토큰(--uyoo-shadow-*)이 다크 값을 따로 가집니다. BrandLogo 는 라이트 · 다크 로고를 모두 렌더링하고 CSS 로 전환하므로 테마가 확정되기 전에도 깜빡이지 않습니다.
- 쓰는 경우
- 앱 루트에 ThemeProvider 를 한 번 두고, 테마 전환이 필요한 곳(대시보드 상단 바)에 ThemeToggle 을 둡니다. 테마처럼 클라이언트에서만 확정되는 값을 그릴 때 useMounted 를 씁니다.
- 쓰지 않는 경우
- 토큰으로 해결되는 색 차이를 컴포넌트 안에서 테마별로 분기하지 않습니다.
ThemeProvider
루트 layout 에서 앱 전체를 감쌉니다.
import { ThemeProvider } from "@uyoolabs/ui/theme";
// class 기반 다크 모드. attribute="class" · defaultTheme="system" · enableSystem · disableTransitionOnChange.
// next-themes 가 첫 렌더링에서 html 의 class 를 바꾸므로 html 에 suppressHydrationWarning 을 둔다.
<html lang="ko" suppressHydrationWarning>
<body><ThemeProvider>{children}</ThemeProvider></body>
</html>ThemeToggle
눌러 보세요. 사이트 헤더에 있는 것과 같은 컴포넌트입니다.
useMounted
하이드레이션 불일치를 피할 때 쓰는 훅입니다. 이 용도의 훅은 이것 하나뿐입니다.
"use client";
import { useMounted } from "@uyoolabs/ui";
import { useTheme } from "next-themes";
// 테마처럼 클라이언트에서만 확정되는 값은 첫 렌더링에서 그리지 않는다.
const mounted = useMounted();
const { theme } = useTheme();
if (!mounted) return null;
return <span>{theme}</span>;dark: variant
토큰에 없는 값을 테마별로 지정할 때 Tailwind 의 dark: variant 를 씁니다.
/* 토큰은 .dark 에서 재정의된다. Tailwind 의 dark: variant 도 같은 .dark 클래스를 기준으로 한다. */
@custom-variant dark (&:is(.dark *));
<div className="bg-white/60 dark:bg-white/[0.07]">…</div>