11'use client' ;
22
3- import { useEffect , useState } from 'react ' ;
3+ import { useTheme } from 'next-themes ' ;
44import { MonitorIcon , MoonIcon , SunIcon } from '@phosphor-icons/react' ;
5- import { THEME_MEDIA_QUERY , THEME_STORAGE_KEY , cn } from '@/lib/utils' ;
6-
7- const THEME_SCRIPT = `
8- const doc = document.documentElement;
9- const theme = localStorage.getItem("${ THEME_STORAGE_KEY } ") ?? "system";
10-
11- if (theme === "system") {
12- if (window.matchMedia("${ THEME_MEDIA_QUERY } ").matches) {
13- doc.classList.add("dark");
14- } else {
15- doc.classList.add("light");
16- }
17- } else {
18- doc.classList.add(theme);
19- }
20- `
21- . trim ( )
22- . replace ( / \n / g, '' )
23- . replace ( / \s + / g, ' ' ) ;
24-
25- export type ThemeMode = 'dark' | 'light' | 'system' ;
26-
27- function applyTheme ( theme : ThemeMode ) {
28- const doc = document . documentElement ;
29-
30- doc . classList . remove ( 'dark' , 'light' ) ;
31- localStorage . setItem ( THEME_STORAGE_KEY , theme ) ;
32-
33- if ( theme === 'system' ) {
34- if ( window . matchMedia ( THEME_MEDIA_QUERY ) . matches ) {
35- doc . classList . add ( 'dark' ) ;
36- } else {
37- doc . classList . add ( 'light' ) ;
38- }
39- } else {
40- doc . classList . add ( theme ) ;
41- }
42- }
5+ import { cn } from '@/lib/utils' ;
436
447interface ThemeToggleProps {
458 className ?: string ;
469}
4710
48- export function ApplyThemeScript ( ) {
49- return < script id = "theme-script" > { THEME_SCRIPT } </ script > ;
50- }
51-
5211export function ThemeToggle ( { className } : ThemeToggleProps ) {
53- const [ theme , setTheme ] = useState < ThemeMode | undefined > ( undefined ) ;
54-
55- useEffect ( ( ) => {
56- const storedTheme = ( localStorage . getItem ( THEME_STORAGE_KEY ) as ThemeMode ) ?? 'system' ;
57-
58- setTheme ( storedTheme ) ;
59- } , [ ] ) ;
60-
61- function handleThemeChange ( theme : ThemeMode ) {
62- applyTheme ( theme ) ;
63- setTheme ( theme ) ;
64- }
12+ const { theme, setTheme } = useTheme ( ) ;
6513
6614 return (
6715 < div
@@ -71,29 +19,40 @@ export function ThemeToggle({ className }: ThemeToggleProps) {
7119 ) }
7220 >
7321 < span className = "sr-only" > Color scheme toggle</ span >
74- < button
75- type = "button"
76- onClick = { ( ) => handleThemeChange ( 'dark' ) }
77- className = "cursor-pointer p-1 pl-1.5"
78- >
22+ < button type = "button" onClick = { ( ) => setTheme ( 'dark' ) } className = "cursor-pointer p-1 pl-1.5" >
7923 < span className = "sr-only" > Enable dark color scheme</ span >
80- < MoonIcon size = { 16 } weight = "bold" className = { cn ( theme !== 'dark' && 'opacity-25' ) } />
24+ < MoonIcon
25+ suppressHydrationWarning
26+ size = { 16 }
27+ weight = "bold"
28+ className = { cn ( theme !== 'dark' && 'opacity-25' ) }
29+ />
8130 </ button >
8231 < button
8332 type = "button"
84- onClick = { ( ) => handleThemeChange ( 'light' ) }
33+ onClick = { ( ) => setTheme ( 'light' ) }
8534 className = "cursor-pointer px-1.5 py-1"
8635 >
8736 < span className = "sr-only" > Enable light color scheme</ span >
88- < SunIcon size = { 16 } weight = "bold" className = { cn ( theme !== 'light' && 'opacity-25' ) } />
37+ < SunIcon
38+ suppressHydrationWarning
39+ size = { 16 }
40+ weight = "bold"
41+ className = { cn ( theme !== 'light' && 'opacity-25' ) }
42+ />
8943 </ button >
9044 < button
9145 type = "button"
92- onClick = { ( ) => handleThemeChange ( 'system' ) }
46+ onClick = { ( ) => setTheme ( 'system' ) }
9347 className = "cursor-pointer p-1 pr-1.5"
9448 >
9549 < span className = "sr-only" > Enable system color scheme</ span >
96- < MonitorIcon size = { 16 } weight = "bold" className = { cn ( theme !== 'system' && 'opacity-25' ) } />
50+ < MonitorIcon
51+ suppressHydrationWarning
52+ size = { 16 }
53+ weight = "bold"
54+ className = { cn ( theme !== 'system' && 'opacity-25' ) }
55+ />
9756 </ button >
9857 </ div >
9958 ) ;
0 commit comments