File size: 1,844 Bytes
6dd9bad
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
import { useContext } from 'react';
import { CheckCircle2, XCircle, Info, AlertTriangle, X } from 'lucide-react';
import { ToastContext, Toast, ToastType } from '@/hooks/useToast';

const ICONS: Record<ToastType, React.ReactNode> = {
    success: <CheckCircle2 className="w-5 h-5 text-emerald-500 flex-shrink-0" />,
    error: <XCircle className="w-5 h-5 text-red-500 flex-shrink-0" />,
    info: <Info className="w-5 h-5 text-blue-500 flex-shrink-0" />,
    warning: <AlertTriangle className="w-5 h-5 text-amber-500 flex-shrink-0" />,
};

const BG: Record<ToastType, string> = {
    success: 'border-emerald-100 bg-white',
    error: 'border-red-100 bg-white',
    info: 'border-blue-100 bg-white',
    warning: 'border-amber-100 bg-white',
};

function ToastItem({ toast, onRemove }: { toast: Toast; onRemove: () => void }) {
    return (
        <div className={`flex items-start gap-3 px-4 py-3 rounded-xl border shadow-lg text-sm font-medium text-slate-800 min-w-[280px] max-w-[400px] animate-[fadeSlideIn_0.2s_ease] ${BG[toast.type]}`}>
            {ICONS[toast.type]}
            <span className="flex-1 leading-snug">{toast.message}</span>
            <button onClick={onRemove} className="text-slate-300 hover:text-slate-500 transition-colors flex-shrink-0 mt-0.5">
                <X className="w-4 h-4" />
            </button>
        </div>
    );
}

export function Toaster() {
    const { toasts, removeToast } = useContext(ToastContext);

    if (toasts.length === 0) return null;

    return (
        <div className="fixed top-5 right-5 z-[9999] flex flex-col gap-2 pointer-events-none">
            {toasts.map(t => (
                <div key={t.id} className="pointer-events-auto">
                    <ToastItem toast={t} onRemove={() => removeToast(t.id)} />
                </div>
            ))}
        </div>
    );
}