theme-toggle.tsx 1.6 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061
  1. "use client";
  2. import { useTheme } from "next-themes";
  3. import { useEffect, useState } from "react";
  4. export function ThemeToggle() {
  5. const { theme, setTheme } = useTheme();
  6. const [mounted, setMounted] = useState(false);
  7. useEffect(() => {
  8. setMounted(true);
  9. }, []);
  10. if (!mounted) {
  11. return <div className="w-8 h-8" />;
  12. }
  13. return (
  14. <button
  15. onClick={() => setTheme(theme === "dark" ? "light" : "dark")}
  16. className="w-8 h-8 flex items-center justify-center rounded-md text-muted-foreground hover:text-foreground hover:bg-muted transition-colors"
  17. aria-label="Toggle theme"
  18. >
  19. {theme === "dark" ? (
  20. <svg
  21. width="16"
  22. height="16"
  23. viewBox="0 0 24 24"
  24. fill="none"
  25. stroke="currentColor"
  26. strokeWidth="2"
  27. strokeLinecap="round"
  28. strokeLinejoin="round"
  29. >
  30. <circle cx="12" cy="12" r="4" />
  31. <path d="M12 2v2" />
  32. <path d="M12 20v2" />
  33. <path d="m4.93 4.93 1.41 1.41" />
  34. <path d="m17.66 17.66 1.41 1.41" />
  35. <path d="M2 12h2" />
  36. <path d="M20 12h2" />
  37. <path d="m6.34 17.66-1.41 1.41" />
  38. <path d="m19.07 4.93-1.41 1.41" />
  39. </svg>
  40. ) : (
  41. <svg
  42. width="16"
  43. height="16"
  44. viewBox="0 0 24 24"
  45. fill="none"
  46. stroke="currentColor"
  47. strokeWidth="2"
  48. strokeLinecap="round"
  49. strokeLinejoin="round"
  50. >
  51. <path d="M12 3a6 6 0 0 0 9 9 9 9 0 1 1-9-9Z" />
  52. </svg>
  53. )}
  54. </button>
  55. );
  56. }