70 lines
2.0 KiB
TypeScript
70 lines
2.0 KiB
TypeScript
'use client';
|
|
|
|
import { cn } from '@repo/shadcn/lib/utils';
|
|
import { Moon, Sun } from 'lucide-react';
|
|
import { useTheme } from 'next-themes';
|
|
import * as React from 'react';
|
|
import { useEffect, useState } from 'react';
|
|
|
|
export function ModeSwitcher() {
|
|
const { setTheme, resolvedTheme } = useTheme();
|
|
|
|
const isDark = resolvedTheme === 'dark';
|
|
|
|
const toggleTheme = React.useCallback(() => {
|
|
setTheme(resolvedTheme === 'dark' ? 'light' : 'dark');
|
|
}, [resolvedTheme, setTheme]);
|
|
const [mounted, setMounted] = useState(false);
|
|
|
|
// useEffect only runs on the client, so now we can safely show the UI
|
|
useEffect(() => {
|
|
setMounted(true);
|
|
}, []);
|
|
|
|
if (!mounted) {
|
|
return null;
|
|
}
|
|
return (
|
|
<div
|
|
className={cn(
|
|
'flex w-16 h-8 p-1 rounded-full cursor-pointer transition-all duration-300',
|
|
isDark
|
|
? 'bg-zinc-950 border border-zinc-800'
|
|
: 'bg-white border border-zinc-200',
|
|
)}
|
|
onClick={toggleTheme}
|
|
role="button"
|
|
tabIndex={0}
|
|
>
|
|
<div className="flex justify-between items-center w-full">
|
|
<div
|
|
className={cn(
|
|
'flex justify-center items-center w-6 h-6 rounded-full transition-transform duration-300',
|
|
isDark
|
|
? 'transform translate-x-0 bg-zinc-800'
|
|
: 'transform translate-x-8 bg-gray-200',
|
|
)}
|
|
>
|
|
{isDark ? (
|
|
<Moon className="w-4 h-4 text-white" strokeWidth={1.5} />
|
|
) : (
|
|
<Sun className="w-4 h-4 text-gray-700" strokeWidth={1.5} />
|
|
)}
|
|
</div>
|
|
<div
|
|
className={cn(
|
|
'flex justify-center items-center w-6 h-6 rounded-full transition-transform duration-300',
|
|
isDark ? 'bg-transparent' : 'transform -translate-x-8',
|
|
)}
|
|
>
|
|
{isDark ? (
|
|
<Sun className="w-4 h-4 text-gray-500" strokeWidth={1.5} />
|
|
) : (
|
|
<Moon className="w-4 h-4 text-black" strokeWidth={1.5} />
|
|
)}
|
|
</div>
|
|
</div>
|
|
</div>
|
|
);
|
|
}
|