"use client"; import { useEffect, useState } from "react"; import { CheckCircle2, Info, TriangleAlert, X } from "lucide-react"; import { cn } from "@/lib/utils"; import { useUiStore, type Toast } from "@/stores/ui-store"; const KIND_STYLES: Record = { success: { icon: CheckCircle2, classes: "border-green-600/30 text-foreground [&_svg]:text-green-600" }, error: { icon: TriangleAlert, classes: "border-red-600/40 text-foreground [&_svg]:text-red-600" }, info: { icon: Info, classes: "border-border text-foreground [&_svg]:text-muted-foreground" } }; function ToastItem({ toast, onDismiss }: { toast: Toast; onDismiss: (id: string) => void }) { const [visible, setVisible] = useState(false); useEffect(() => { const raf = requestAnimationFrame(() => setVisible(true)); const timer = setTimeout(() => onDismiss(toast.id), toast.duration); return () => { cancelAnimationFrame(raf); clearTimeout(timer); }; // eslint-disable-next-line react-hooks/exhaustive-deps }, [toast.id]); const { icon: Icon, classes } = KIND_STYLES[toast.kind]; return (

{toast.title}

{toast.description ? (

{toast.description}

) : null}
); } /** * Toast viewport — renders the zustand toast list (push/remove from * `useUiStore` or the imperative `toast()` helper). Fixed bottom-right. */ export function Toaster() { const toasts = useUiStore((s) => s.toasts); const removeToast = useUiStore((s) => s.removeToast); return (
{toasts.map((t) => ( ))}
); }