// App-wide notices — Svelte 5 rune store (.svelte.ts). Rendered globally by // in the root layout. export type NoticeType = 'info' | 'success' | 'warning' | 'error'; export interface Notice { id: string; type: NoticeType; title: string; message?: string; action?: { label: string; href: string }; dismissible: boolean; } let idCounter = 0; class NoticeStore { list = $state([]); add(notice: Omit): string { const id = `notice-${Date.now()}-${idCounter++}`; this.list.push({ ...notice, id }); return id; } remove(id: string) { this.list = this.list.filter((n) => n.id !== id); } clear() { this.list = []; } success(title: string, message?: string, action?: Notice['action']) { return this.add({ type: 'success', title, message, action, dismissible: true }); } info(title: string, message?: string, action?: Notice['action']) { return this.add({ type: 'info', title, message, action, dismissible: true }); } warning(title: string, message?: string, action?: Notice['action']) { return this.add({ type: 'warning', title, message, action, dismissible: true }); } error(title: string, message?: string, action?: Notice['action']) { return this.add({ type: 'error', title, message, action, dismissible: true }); } } export const notices = new NoticeStore(); // Fire-and-forget helper — auto-dismisses after `duration` ms. export function addAutoDismissNotice(notice: Omit, duration = 5000): string { const id = notices.add({ ...notice, dismissible: true }); setTimeout(() => notices.remove(id), duration); return id; }