22
33import { useTheme } from "next-themes" ;
44import { useEffect , useState } from "react" ;
5- // eslint-disable-next-line @typescript-eslint/no-unused-vars
65import { Sun , Moon , Palette } from "lucide-react" ;
76
87const themes = [
9- { id : "light" , label : "Light Mode" , icon : < Sun size = { 20 } /> } ,
10- { id : "dark" , label : "Dark Mode" , icon : < Moon size = { 20 } /> } ,
11- { id : "pastel" , label : "Pastel Mode" , icon : < Palette size = { 20 } /> } ,
8+ { id : "light" , label : "Light Mode" , icon : < Sun size = { 20 } /> } ,
9+ { id : "dark" , label : "Dark Mode" , icon : < Moon size = { 20 } /> } ,
10+ { id : "pastel" , label : "Pastel Mode" , icon : < Palette size = { 20 } /> } ,
1211] ;
1312
1413export const ChangeThemeButton = ( ) => {
15- const { theme, setTheme, resolvedTheme } = useTheme ( ) ;
16- const [ mounted , setMounted ] = useState ( false ) ;
14+ const { theme, setTheme, resolvedTheme } = useTheme ( ) ;
15+ const [ mounted , setMounted ] = useState ( false ) ;
1716
18- useEffect ( ( ) => {
19- setMounted ( true ) ;
20- } , [ ] ) ;
17+ useEffect ( ( ) => {
18+ setMounted ( true ) ;
19+ } , [ ] ) ;
2120
22- useEffect ( ( ) => {
23- if ( mounted && ! theme ) {
24- const systemTheme =
25- resolvedTheme ||
26- ( window . matchMedia ( "(prefers-color-scheme: dark)" ) . matches
27- ? "dark"
28- : "light" ) ;
29- setTheme ( systemTheme ) ;
30- }
31- } , [ mounted , theme , resolvedTheme , setTheme ] ) ;
21+ useEffect ( ( ) => {
22+ if ( mounted && ! theme ) {
23+ const systemTheme =
24+ resolvedTheme ||
25+ ( window . matchMedia ( "(prefers-color-scheme: dark)" ) . matches
26+ ? "dark"
27+ : "light" ) ;
28+ setTheme ( systemTheme ) ;
29+ }
30+ if ( mounted ) {
31+ // So that we have transition but not on page load
32+ document . documentElement . classList . add ( "theme-transition" ) ;
33+ }
34+ } , [ mounted , theme , resolvedTheme , setTheme ] ) ;
3235
33- if ( ! mounted ) {
34- return (
35- < button
36- className = "flex items-center justify-center w-10 h-10 rounded-md bg-gray-200 text-gray-800 dark:bg-gray-700 dark:text-gray-200"
37- aria-label = "Loading Theme..."
38- >
39- ...
40- </ button >
41- ) ;
42- }
36+ if ( ! mounted ) {
37+ return (
38+ < button
39+ className = "flex items-center justify-center w-10 h-10 rounded-md bg-gray-200 text-gray-800 dark:bg-gray-700 dark:text-gray-200"
40+ aria-label = "Loading Theme..."
41+ >
42+
43+ </ button >
44+ ) ;
45+ }
4346
44- const effectiveTheme = resolvedTheme || theme ;
45- const currentIndex = themes . findIndex ( ( t ) => t . id === effectiveTheme ) ;
46- const currentTheme = themes [ currentIndex ] || themes [ 0 ] ;
47- const nextIndex = ( currentIndex + 1 ) % themes . length ;
48- const nextTheme = themes [ nextIndex ] ;
47+ const effectiveTheme = resolvedTheme || theme ;
48+ const currentIndex = themes . findIndex ( ( t ) => t . id === effectiveTheme ) ;
49+ const currentTheme = themes [ currentIndex ] || themes [ 0 ] ;
50+ const nextIndex = ( currentIndex + 1 ) % themes . length ;
51+ const nextTheme = themes [ nextIndex ] ;
4952
50- const handleClick = ( ) => {
51- setTheme ( nextTheme . id ) ;
52- } ;
53+ const handleClick = ( ) => {
54+ setTheme ( nextTheme . id ) ;
55+ } ;
5356
54- return (
55- < button
56- onClick = { handleClick }
57- className = { `flex items-center justify-center w-10 h-10 rounded-md transition-colors
57+ return (
58+ < button
59+ onClick = { handleClick }
60+ className = { `flex items-center justify-center w-10 h-10 rounded-md transition-colors
5861 bg-gray-200 text-gray-800 hover:bg-gray-300
5962 dark:bg-gray-700 dark:text-gray-200 dark:hover:bg-gray-600` }
60- aria-label = { `Switch to ${ nextTheme . label } ` }
61- title = { currentTheme . label }
62- >
63- { currentTheme . icon }
64- </ button >
65- ) ;
63+ aria-label = { `Switch to ${ nextTheme . label } ` }
64+ title = { currentTheme . label }
65+ >
66+ { currentTheme . icon }
67+ </ button >
68+ ) ;
6669} ;
0 commit comments