"use client"; import { useStatusBlocksLabels } from "@openstatus/ui/components/blocks/status-i18n"; import { THEME_VALUES, type ThemeValue, } from "@openstatus/ui/components/blocks/status.types"; import { Button } from "@openstatus/ui/components/ui/button"; import { DropdownMenu, DropdownMenuContent, DropdownMenuItem, DropdownMenuTrigger, } from "@openstatus/ui/components/ui/dropdown-menu"; import { Skeleton } from "@openstatus/ui/components/ui/skeleton"; import { cn } from "@openstatus/ui/lib/utils"; import { Laptop, Moon, Sun } from "lucide-react"; export type { ThemeValue }; function ThemeIcon({ value, className, }: { value: ThemeValue; className?: string; }) { const Icon = value === "light" ? Sun : value === "dark" ? Moon : Laptop; return ; } /** * StatusThemeSwitcher — agnostic light/dark/system switcher. * * Pure presentation: caller owns the value and onValueChange wiring (next-themes, * form state, etc.). The block does no hydration handling — render a Skeleton * yourself before the active theme is known. */ export function StatusThemeSwitcher({ value, onValueChange, className, ...props }: Omit< React.ComponentProps, "value" | "onValueChange" > & { value: ThemeValue; onValueChange: (value: ThemeValue) => void; }) { const labels = useStatusBlocksLabels(); return ( {THEME_VALUES.map((v) => { const isActive = v === value; return ( onValueChange(v)} > {labels.themeNames[v]} ); })} ); } /** * StatusThemeSwitcherSkeleton — same footprint as the trigger button. * Render while the active theme isn't known yet (e.g. before next-themes * hydrates) so the surrounding layout doesn't shift. */ export function StatusThemeSwitcherSkeleton({ className, ...props }: React.ComponentProps) { return ( ); }