Press n or j to go to the next uncovered block, b, p or k for the previous block.
| 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 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 | 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 45x 45x 45x 45x 45x 45x 45x 45x 45x 45x 45x 45x 45x 45x | import { createContext, useContext, useState, useCallback, type ReactNode } from 'react';
import { CheckCircle, XCircle, AlertCircle, Info, X } from 'lucide-react';
type ToastType = 'success' | 'error' | 'warning' | 'info';
interface Toast {
id: string;
message: string;
type: ToastType;
}
interface ToastContextType {
showToast: (message: string, type?: ToastType) => void;
}
const ToastContext = createContext<ToastContextType | undefined>(undefined);
export function useToast() {
const context = useContext(ToastContext);
if (!context) {
throw new Error('useToast must be used within a ToastProvider');
}
return context;
}
const icons = {
success: <CheckCircle className="w-5 h-5 text-green-400" />,
error: <XCircle className="w-5 h-5 text-red-400" />,
warning: <AlertCircle className="w-5 h-5 text-yellow-400" />,
info: <Info className="w-5 h-5 text-blue-400" />,
};
const bgColors = {
success: 'bg-green-500/10 border-green-500/30',
error: 'bg-red-500/10 border-red-500/30',
warning: 'bg-yellow-500/10 border-yellow-500/30',
info: 'bg-blue-500/10 border-blue-500/30',
};
export function ToastProvider({ children }: { children: ReactNode }) {
const [toasts, setToasts] = useState<Toast[]>([]);
const showToast = useCallback((message: string, type: ToastType = 'success') => {
const id = Math.random().toString(36).substr(2, 9);
setToasts((prev) => [...prev, { id, message, type }]);
// Auto-dismiss after 3 seconds
setTimeout(() => {
setToasts((prev) => prev.filter((t) => t.id !== id));
}, 3000);
}, []);
const dismissToast = useCallback((id: string) => {
setToasts((prev) => prev.filter((t) => t.id !== id));
}, []);
return (
<ToastContext.Provider value={{ showToast }}>
{children}
{/* Toast Container */}
<div className="fixed bottom-4 right-4 z-50 flex flex-col gap-2">
{toasts.map((toast) => (
<div
key={toast.id}
className={`flex items-center gap-3 px-4 py-3 rounded-lg border shadow-lg backdrop-blur-sm animate-slide-in ${bgColors[toast.type]}`}
>
{icons[toast.type]}
<span className="text-white text-sm">{toast.message}</span>
<button
onClick={() => dismissToast(toast.id)}
className="ml-2 text-bambu-gray hover:text-white transition-colors"
>
<X className="w-4 h-4" />
</button>
</div>
))}
</div>
</ToastContext.Provider>
);
}
|