"use client"; import { CheckIcon, ChevronRightIcon, LogOutIcon, type LucideIcon, MonitorIcon, MoonIcon, SunIcon, } from "lucide-react"; import { AnimatePresence, motion, useReducedMotion } from "motion/react"; import { type KeyboardEvent, useEffect, useId, useRef, useState } from "react"; import { Kbd } from "@/components/ui/kbd"; import { SegmentedControl, SegmentedControlItem } from "@/components/ui/segmented-control"; import { cn } from "@/lib/utils"; export type ThemeChoice = "light" | "dark" | "system"; export interface AccountCardItem { id: string; label: string; icon: LucideIcon; shortcut?: string; meta?: string; } export interface AccountCardStep { id: string; label: string; done?: boolean; } export interface AccountCardProps { user: { name: string; email: string; initials: string; plan?: string }; items: AccountCardItem[]; steps?: AccountCardStep[]; theme?: ThemeChoice; onThemeChange?: (theme: ThemeChoice) => void; onSelect?: (id: string) => void; onSignOut?: () => void; className?: string; } const spring = { type: "spring", stiffness: 420, damping: 34 } as const; function Rolling({ value }: { value: number }) { const reduce = useReducedMotion(); const prev = useRef(value); const dir = value >= prev.current ? 1 : -1; useEffect(() => { prev.current = value; }, [value]); return ( {value} ); } const THEMES: { value: ThemeChoice; icon: LucideIcon; label: string }[] = [ { value: "light", icon: SunIcon, label: "Light" }, { value: "dark", icon: MoonIcon, label: "Dark" }, { value: "system", icon: MonitorIcon, label: "System" }, ]; function ThemeSwitch({ value, onChange }: { value: ThemeChoice; onChange: (t: ThemeChoice) => void }) { const refs = useRef<(HTMLButtonElement | null)[]>([]); const index = THEMES.findIndex((t) => t.value === value); const onKeyDown = (e: KeyboardEvent) => { if (e.key !== "ArrowRight" && e.key !== "ArrowLeft") return; e.preventDefault(); const next = (index + (e.key === "ArrowRight" ? 1 : -1) + THEMES.length) % THEMES.length; onChange(THEMES[next].value); refs.current[next]?.focus(); }; return ( {THEMES.map((t, i) => { const active = t.value === value; const Icon = t.icon; return ( onChange(t.value)} ref={(el: HTMLButtonElement | null) => { refs.current[i] = el; }} role="radio" tabIndex={active ? 0 : -1} title={t.label} > ); })} ); } export function AccountCard({ user, items, steps: initialSteps = [], theme: themeProp, onThemeChange, onSelect, onSignOut, className, }: AccountCardProps) { const reduce = useReducedMotion(); const hoverId = useId(); const [steps, setSteps] = useState(initialSteps); const [themeState, setThemeState] = useState(themeProp ?? "system"); const [hover, setHover] = useState(null); const theme = themeProp ?? themeState; const doneCount = steps.filter((s) => s.done).length; const pct = steps.length ? Math.round((doneCount / steps.length) * 100) : 100; const next = steps.find((s) => !s.done); const r = 25; const c = 2 * Math.PI * r; const setTheme = (t: ThemeChoice) => { setThemeState(t); onThemeChange?.(t); }; return (
{user.initials} {pct === 100 && ( )}

{user.name}

{user.plan && ( {user.plan} )}

{user.email}

{steps.length > 0 && (
Profile setup %
{next ? ( setSteps((s) => s.map((x) => (x.id === next.id ? { ...x, done: true } : x)))} transition={spring} type="button" > Next: {next.label} ) : ( All set – your profile is complete )}
)}
Theme
); }