ThemeToggle.tsx 2.1 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162
  1. import { useTheme, Theme } from '../contexts/ThemeContext';
  2. function SunIcon({ className }: { className?: string }) {
  3. return (
  4. <svg className={className} fill="none" viewBox="0 0 24 24" stroke="currentColor" strokeWidth={2}>
  5. <path strokeLinecap="round" strokeLinejoin="round" 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" />
  6. </svg>
  7. );
  8. }
  9. function MoonIcon({ className }: { className?: string }) {
  10. return (
  11. <svg className={className} fill="none" viewBox="0 0 24 24" stroke="currentColor" strokeWidth={2}>
  12. <path strokeLinecap="round" strokeLinejoin="round" 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" />
  13. </svg>
  14. );
  15. }
  16. function SystemIcon({ className }: { className?: string }) {
  17. return (
  18. <svg className={className} fill="none" viewBox="0 0 24 24" stroke="currentColor" strokeWidth={2}>
  19. <path strokeLinecap="round" strokeLinejoin="round" 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" />
  20. </svg>
  21. );
  22. }
  23. const themeOrder: Theme[] = ['light', 'dark', 'system'];
  24. const themeLabels: Record<Theme, string> = {
  25. light: 'Light mode',
  26. dark: 'Dark mode',
  27. system: 'System theme',
  28. };
  29. export default function ThemeToggle() {
  30. const { theme, resolvedTheme, setTheme } = useTheme();
  31. const cycleTheme = () => {
  32. const currentIndex = themeOrder.indexOf(theme);
  33. const nextTheme = themeOrder[(currentIndex + 1) % themeOrder.length];
  34. setTheme(nextTheme);
  35. };
  36. const getIcon = () => {
  37. if (theme === 'system') {
  38. return <SystemIcon className="h-5 w-5" />;
  39. }
  40. return resolvedTheme === 'dark'
  41. ? <MoonIcon className="h-5 w-5" />
  42. : <SunIcon className="h-5 w-5" />;
  43. };
  44. return (
  45. <button
  46. onClick={cycleTheme}
  47. className="p-2 rounded-lg transition-colors duration-200 text-[var(--text-secondary)] hover:text-[var(--text-primary)] hover:bg-[var(--bg-tertiary)]"
  48. title={themeLabels[theme]}
  49. aria-label={themeLabels[theme]}
  50. >
  51. {getIcon()}
  52. </button>
  53. );
  54. }