@@ -17,6 +17,7 @@ const DARK_MODE_SCALE = 0.5;
1717export const ThemeToggle = ( { className = "" } : { className ?: string } ) => {
1818 const { theme, setTheme } = useTheme ( ) ;
1919 const [ mounted , setMounted ] = useState ( false ) ;
20+ const [ hasInteracted , setHasInteracted ] = useState ( false ) ;
2021
2122 // useEffect only runs on the client, so now we can safely show the UI
2223 useEffect ( ( ) => {
@@ -48,14 +49,19 @@ export const ThemeToggle = ({ className = "" }: { className?: string }) => {
4849
4950 const isDark = theme === "dark" ;
5051
52+ const handleClick = ( ) => {
53+ setHasInteracted ( true ) ;
54+ setTheme ( isDark ? "light" : "dark" ) ;
55+ } ;
56+
5157 return (
5258 < button
5359 aria-label = { `Switch to ${ isDark ? "light" : "dark" } mode` }
5460 className = { cn (
5561 "cursor-pointer rounded-full transition-all duration-300 active:scale-95" ,
5662 className
5763 ) }
58- onClick = { ( ) => setTheme ( isDark ? "light" : "dark" ) }
64+ onClick = { handleClick }
5965 type = "button"
6066 >
6167 < svg
@@ -72,15 +78,23 @@ export const ThemeToggle = ({ className = "" }: { className?: string }) => {
7278 x : isDark ? DARK_MODE_CLIP_X : 0 ,
7379 } }
7480 d = "M0-5h30a1 1 0 0 0 9 13v24H0Z"
75- transition = { { ease : "easeInOut" , duration : 0.35 } }
81+ transition = {
82+ hasInteracted
83+ ? { ease : "easeInOut" , duration : 0.35 }
84+ : { duration : 0 }
85+ }
7686 />
7787 </ clipPath >
7888 < g clipPath = "url(#skiper-btn-2)" >
7989 < motion . circle
8090 animate = { { r : isDark ? DARK_MODE_RADIUS : LIGHT_MODE_RADIUS } }
8191 cx = "16"
8292 cy = "16"
83- transition = { { ease : "easeInOut" , duration : 0.35 } }
93+ transition = {
94+ hasInteracted
95+ ? { ease : "easeInOut" , duration : 0.35 }
96+ : { duration : 0 }
97+ }
8498 />
8599 < motion . g
86100 animate = { {
@@ -90,7 +104,11 @@ export const ThemeToggle = ({ className = "" }: { className?: string }) => {
90104 } }
91105 stroke = "currentColor"
92106 strokeWidth = "1.5"
93- transition = { { ease : "easeInOut" , duration : 0.35 } }
107+ transition = {
108+ hasInteracted
109+ ? { ease : "easeInOut" , duration : 0.35 }
110+ : { duration : 0 }
111+ }
94112 >
95113 < path d = "M16 5.5v-4" />
96114 < path d = "M16 30.5v-4" />
@@ -106,11 +124,3 @@ export const ThemeToggle = ({ className = "" }: { className?: string }) => {
106124 </ button >
107125 ) ;
108126} ;
109-
110- /**
111- * Theme Toggle Animation — React + Framer Motion Recreation
112- * Inspired by and adapted from https://toggles.dev/ (Open Source CSS Theme Toggles by Alfie Jones)
113- * This implementation is rebuilt in React and Framer Motion, avoiding external toggle packages.
114- *
115- * Attribution: https://toggles.dev/
116- */
0 commit comments