"use client";
import * as React from "react";
import { Moon, Sun, Monitor } from "lucide-react";
import { useTheme } from "next-themes";
import { Button } from "@/components/ui/button";
import { IconTooltip } from "@/components/ui/tooltip";
import {
DropdownMenu,
DropdownMenuContent,
DropdownMenuLabel,
DropdownMenuGroup,
DropdownMenuRadioGroup,
DropdownMenuRadioItem,
DropdownMenuTrigger,
} from "@/components/ui/dropdown-menu";
const ACTIVE_ICONS = {
light: Sun,
dark: Moon,
} as const;
// The theme choices, for dropping into whichever menu is showing them - the
// user menu when signed in, `ThemeToggle`'s own dropdown when signed out.
//
// Bound to `theme` rather than `resolvedTheme` so the selection shows what was
// actually chosen: "System" stays checked at night instead of reading as "Dark".
export function ThemeMenuItems() {
const { theme, setTheme } = useTheme();
const mounted = useMounted();
return (
Appearance
Light
Dark
System
);
}
// Standalone theme control, used where there's no user menu to hang the choices
// off - i.e. signed out.
export function ThemeToggle({ className }: { className?: string }) {
const { resolvedTheme } = useTheme();
const mounted = useMounted();
const ActiveIcon =
mounted && resolvedTheme && resolvedTheme in ACTIVE_ICONS
? ACTIVE_ICONS[resolvedTheme as keyof typeof ACTIVE_ICONS]
: Sun;
return (
}
>
);
}
// Avoid rendering theme-dependent UI until mounted, since the resolved theme
// isn't known on the server and would otherwise cause a hydration mismatch.
function useMounted() {
const [mounted, setMounted] = React.useState(false);
React.useEffect(() => {
// eslint-disable-next-line react-hooks/set-state-in-effect
setMounted(true);
}, []);
return mounted;
}