refactor: enhance theme switch component with loading state and improved animations
This commit is contained in:
parent
b786d7741c
commit
affc441cfc
1 changed files with 31 additions and 2 deletions
|
|
@ -1,9 +1,30 @@
|
||||||
import { motion, type Transition } from "framer-motion";
|
import { motion, type Transition } from "framer-motion";
|
||||||
import { Moon, Sun } from "lucide-react";
|
import { Moon, Sun } from "lucide-react";
|
||||||
import { useTheme } from "next-themes";
|
import { useTheme } from "next-themes";
|
||||||
|
import { useEffect, useState } from "react";
|
||||||
import { cn } from "~/lib/utils";
|
import { cn } from "~/lib/utils";
|
||||||
|
|
||||||
export const ThemeSwitch = () => {
|
export const ThemeSwitch = () => {
|
||||||
|
const [mounted, setMounted] = useState(false);
|
||||||
|
useEffect(() => {
|
||||||
|
setMounted(true);
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
if (!mounted) {
|
||||||
|
return <ThemeSwitchSkeleton />;
|
||||||
|
}
|
||||||
|
|
||||||
|
return <ThemeSwitchContent />;
|
||||||
|
};
|
||||||
|
|
||||||
|
const ThemeSwitchSkeleton = () => (
|
||||||
|
<div
|
||||||
|
aria-hidden="true"
|
||||||
|
className="h-9 w-16 animate-pulse rounded-full bg-muted p-[5px] shadow-inner"
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
|
||||||
|
const ThemeSwitchContent = () => {
|
||||||
const { theme, setTheme } = useTheme();
|
const { theme, setTheme } = useTheme();
|
||||||
|
|
||||||
const spring: Transition = {
|
const spring: Transition = {
|
||||||
|
|
@ -25,14 +46,22 @@ export const ThemeSwitch = () => {
|
||||||
type="button"
|
type="button"
|
||||||
>
|
>
|
||||||
<motion.div
|
<motion.div
|
||||||
|
animate={{ opacity: 1 }}
|
||||||
className={cn(
|
className={cn(
|
||||||
"flex size-7 items-center justify-center rounded-full bg-black",
|
"flex size-7 items-center justify-center rounded-full bg-black",
|
||||||
theme === "light" ? "bg-yellow-300" : "bg-gray-800/60",
|
theme === "light" ? "bg-yellow-300" : "bg-gray-800/60",
|
||||||
)}
|
)}
|
||||||
|
initial={{ opacity: 0 }}
|
||||||
layout
|
layout
|
||||||
transition={spring}
|
transition={{
|
||||||
|
opacity: { duration: 0.1, ease: "easeInOut", delay: 0.5 }, // Fast fade in
|
||||||
|
layout: spring, // Spring for position change
|
||||||
|
}}
|
||||||
>
|
>
|
||||||
<motion.div whileTap={{ rotate: 360 }}>
|
<motion.div
|
||||||
|
animate={{ rotate: theme === "light" ? 180 : 0 }}
|
||||||
|
transition={spring}
|
||||||
|
>
|
||||||
{theme === "light" ? (
|
{theme === "light" ? (
|
||||||
<Sun className="size-5 fill-yellow-500 stroke-yellow-500" />
|
<Sun className="size-5 fill-yellow-500 stroke-yellow-500" />
|
||||||
) : (
|
) : (
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue