1+ "use client" ;
2+
3+ import { useTheme } from "next-themes" ;
4+ import { useEffect , useState } from "react" ;
5+
6+ interface ThemeButtonProps {
7+ themeName : string ;
8+ currentTheme : string | undefined ;
9+ onClick : ( ) => void ;
10+ label : string ;
11+ }
12+
13+ interface StaticThemeButtonProps {
14+ label : string ;
15+ }
16+
17+ const ThemeButton = ( {
18+ themeName,
19+ currentTheme,
20+ onClick,
21+ label,
22+ } : ThemeButtonProps ) => {
23+ return (
24+ < button
25+ onClick = { onClick }
26+ className = { `flex items-center cursor-pointer px-4 py-2 rounded-md transition-colors ${
27+ currentTheme === themeName
28+ ? "bg-blue-500 text-white"
29+ : "bg-gray-200 text-gray-800 hover:bg-gray-300 dark:bg-gray-700 dark:text-gray-200 dark:hover:bg-gray-600"
30+ } `}
31+ >
32+ { label }
33+ </ button >
34+ ) ;
35+ } ;
36+
37+ const StaticThemeButton = ( { label } : StaticThemeButtonProps ) => {
38+ return (
39+ < button className = "flex items-center cursor-pointer px-4 py-2 rounded-md bg-gray-200 text-gray-800 dark:bg-gray-700 dark:text-gray-200" >
40+ { label }
41+ </ button >
42+ ) ;
43+ } ;
44+
45+ export const ThemeButtons = ( ) => {
46+ const { theme, setTheme, resolvedTheme } = useTheme ( ) ;
47+ const [ mounted , setMounted ] = useState < boolean > ( false ) ;
48+
49+ interface ThemeOption {
50+ id : string ;
51+ label : string ;
52+ }
53+
54+ const themes : ThemeOption [ ] = [
55+ { id : "light" , label : "Light Mode" } ,
56+ { id : "dark" , label : "Dark Mode" } ,
57+ { id : "custom" , label : "Custom Mode" } ,
58+ { id : "pastel" , label : "Pastel Mode" } ,
59+ ] ;
60+
61+ useEffect ( ( ) => {
62+ setMounted ( true ) ;
63+ } , [ ] ) ;
64+
65+ useEffect ( ( ) => {
66+ if ( mounted && ! theme ) {
67+ const systemTheme =
68+ resolvedTheme ||
69+ ( window . matchMedia ( "(prefers-color-scheme: dark)" ) . matches
70+ ? "dark"
71+ : "light" ) ;
72+
73+ setTheme ( systemTheme ) ;
74+ }
75+ } , [ mounted , theme , resolvedTheme , setTheme ] ) ;
76+
77+ if ( ! mounted ) {
78+ return (
79+ < div className = "flex flex-col gap-4" >
80+ { themes . map ( ( themeOption : ThemeOption ) => (
81+ < StaticThemeButton key = { themeOption . id } label = { themeOption . label } />
82+ ) ) }
83+ </ div >
84+ ) ;
85+ }
86+
87+ const effectiveTheme = resolvedTheme || theme ;
88+
89+ return (
90+ < div className = "flex flex-col gap-4" >
91+ { themes . map ( ( themeOption : ThemeOption ) => (
92+ < ThemeButton
93+ key = { themeOption . id }
94+ themeName = { themeOption . id }
95+ currentTheme = { effectiveTheme }
96+ onClick = { ( ) => setTheme ( themeOption . id ) }
97+ label = { themeOption . label }
98+ />
99+ ) ) }
100+ </ div >
101+ ) ;
102+ } ;
0 commit comments