2025-11-26 15:25:23 +07:00
|
|
|
import { FC } from 'react';
|
|
|
|
|
import { useTheme } from './theme-provider';
|
|
|
|
|
|
|
|
|
|
interface ThemeToggleProps {
|
|
|
|
|
className?: string;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Sun icon for light mode
|
|
|
|
|
const SunIcon = () => (
|
2025-11-27 15:12:45 +07:00
|
|
|
<svg
|
|
|
|
|
className="w-5 h-5"
|
|
|
|
|
fill="none"
|
|
|
|
|
viewBox="0 0 24 24"
|
|
|
|
|
stroke="currentColor"
|
|
|
|
|
>
|
|
|
|
|
<path
|
|
|
|
|
strokeLinecap="round"
|
|
|
|
|
strokeLinejoin="round"
|
|
|
|
|
strokeWidth={2}
|
|
|
|
|
d="M12 3v1m0 16v1m9-9h-1M4 12H3m15.364 6.364l-.707-.707M6.343 6.343l-.707-.707m12.728 0l-.707.707M6.343 17.657l-.707.707M16 12a4 4 0 11-8 0 4 4 0 018 0z"
|
|
|
|
|
/>
|
2025-11-26 15:25:23 +07:00
|
|
|
</svg>
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
// Moon icon for dark mode
|
|
|
|
|
const MoonIcon = () => (
|
2025-11-27 15:12:45 +07:00
|
|
|
<svg
|
|
|
|
|
className="w-5 h-5"
|
|
|
|
|
fill="none"
|
|
|
|
|
viewBox="0 0 24 24"
|
|
|
|
|
stroke="currentColor"
|
|
|
|
|
>
|
|
|
|
|
<path
|
|
|
|
|
strokeLinecap="round"
|
|
|
|
|
strokeLinejoin="round"
|
|
|
|
|
strokeWidth={2}
|
|
|
|
|
d="M20.354 15.354A9 9 0 018.646 3.646 9.003 9.003 0 0012 21a9.003 9.003 0 008.354-5.646z"
|
|
|
|
|
/>
|
2025-11-26 15:25:23 +07:00
|
|
|
</svg>
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
// System icon (monitor)
|
|
|
|
|
const SystemIcon = () => (
|
2025-11-27 15:12:45 +07:00
|
|
|
<svg
|
|
|
|
|
className="w-5 h-5"
|
|
|
|
|
fill="none"
|
|
|
|
|
viewBox="0 0 24 24"
|
|
|
|
|
stroke="currentColor"
|
|
|
|
|
>
|
|
|
|
|
<path
|
|
|
|
|
strokeLinecap="round"
|
|
|
|
|
strokeLinejoin="round"
|
|
|
|
|
strokeWidth={2}
|
|
|
|
|
d="M9.75 17L9 20l-1 1h8l-1-1-.75-3M3 13h18M5 17h14a2 2 0 002-2V5a2 2 0 00-2-2H5a2 2 0 00-2 2v10a2 2 0 002 2z"
|
|
|
|
|
/>
|
2025-11-26 15:25:23 +07:00
|
|
|
</svg>
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
export const ThemeToggle: FC<ThemeToggleProps> = ({ className = '' }) => {
|
|
|
|
|
const { theme, setTheme, resolvedTheme } = useTheme();
|
|
|
|
|
|
|
|
|
|
const cycleTheme = () => {
|
|
|
|
|
if (theme === 'light') setTheme('dark');
|
|
|
|
|
else if (theme === 'dark') setTheme('system');
|
|
|
|
|
else setTheme('light');
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
const getThemeLabel = () => {
|
|
|
|
|
if (theme === 'system') return 'System';
|
|
|
|
|
return theme === 'dark' ? 'Dark' : 'Light';
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
const renderIcon = () => {
|
|
|
|
|
if (theme === 'system') {
|
|
|
|
|
return <SystemIcon />;
|
|
|
|
|
}
|
|
|
|
|
return resolvedTheme === 'dark' ? <MoonIcon /> : <SunIcon />;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
return (
|
|
|
|
|
<button
|
|
|
|
|
type="button"
|
|
|
|
|
onClick={cycleTheme}
|
2025-11-27 15:12:45 +07:00
|
|
|
className={`p-2 rounded-lg hover:bg-gray-100 dark:hover:bg-neutral-800 transition-colors cursor-pointer text-gray-600 dark:text-neutral-200 ${className}`}
|
2025-11-26 15:25:23 +07:00
|
|
|
title={`Theme: ${getThemeLabel()}`}
|
|
|
|
|
aria-label={`Current theme: ${getThemeLabel()}. Click to change.`}
|
|
|
|
|
>
|
|
|
|
|
{renderIcon()}
|
|
|
|
|
</button>
|
|
|
|
|
);
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
export default ThemeToggle;
|