export type ToastLevel = "info" | "warn" | "error"; export type Toast = { id: number; level: ToastLevel; message: string; detail?: string; expiresAt?: number; }; const listeners = new Set<(toasts: Toast[]) => void>(); const queue: Toast[] = []; let nextId = 1; const MAX_TOASTS = 4; function emitUpdate() { listeners.forEach((fn) => fn([...queue])); } export function pushToast(toast: Omit) { const entry: Toast = { id: nextId++, ...toast, }; queue.push(entry); if (queue.length > MAX_TOASTS) queue.shift(); emitUpdate(); } export function dismissToast(id: number) { const idx = queue.findIndex((t) => t.id === id); if (idx >= 0) { queue.splice(idx, 1); emitUpdate(); } } export function subscribeToasts(fn: (toasts: Toast[]) => void) { listeners.add(fn); fn([...queue]); return () => { listeners.delete(fn); }; } export function toastError(message: string, detail?: string) { const expiresAt = Date.now() + 7000; pushToast({ level: "error", message, detail, expiresAt }); } export function toastInfo(message: string, detail?: string) { const expiresAt = Date.now() + 4000; pushToast({ level: "info", message, detail, expiresAt }); }