1<script lang="ts">
2 import Toast from './Toast.svelte';
3
4 interface ToastData {
5 id: number;
6 message: string;
7 duration?: number;
8 type?: 'info' | 'success' | 'error';
9 }
10
11 // Svelte 5 rune for reactive state
12 let toasts = $state<ToastData[]>([]);
13 let counter = $state(0);
14 let zoomToastId = $state<number | null>(null);
15 let zoomDebounceTimer: number | undefined = undefined;
16
17 function addToast(message: string, duration = 2500, type: 'info' | 'success' | 'error' = 'info'): number {
18 const id = ++counter;
19 const toast: ToastData = { id, message, duration, type };
20
21 toasts.push(toast);
22 console.log('📋 Toast:', message);
23 return id;
24 }
25
26 function dismissToast(id: number) {
27 console.log(`[ToastContainer] Dismissing toast with id: ${id}`);
28 const index = toasts.findIndex(t => t.id === id);
29 if (index === -1) {
30 console.log(`[ToastContainer] Toast with id ${id} not found in array`);
31 return;
32 }
33
34 // Clear zoom toast tracking if this is the zoom toast
35 if (zoomToastId === id) {
36 console.log(`[ToastContainer] Clearing zoom toast tracking for id: ${id}`);
37 zoomToastId = null;
38 }
39
40 console.log(`[ToastContainer] Removing toast at index ${index}, remaining: ${toasts.length - 1}`);
41 toasts.splice(index, 1);
42 }
43
44 function clearAllToasts() {
45 toasts = [];
46 zoomToastId = null;
47 if (zoomDebounceTimer) {
48 window.clearTimeout(zoomDebounceTimer);
49 zoomDebounceTimer = undefined;
50 }
51 }
52
53 function showZoomToast(zoomLevel: number) {
54 console.log('[dumber] showZoomToast called with level:', zoomLevel);
55
56 // Debug: Check if toast container exists in DOM
57 const container = document.querySelector('.toast-container');
58 const browserRoot = document.querySelector('.browser-component-root');
59 console.log('[dumber] DOM check - container exists:', !!container, 'browser-root exists:', !!browserRoot, 'toasts array length:', toasts.length);
60
61 // Clear existing debounce timer
62 if (zoomDebounceTimer) {
63 window.clearTimeout(zoomDebounceTimer);
64 }
65
66 // Remove existing zoom toasts immediately (no animation needed for replacement)
67 toasts = toasts.filter(toast => {
68 const isZoomToast = toast.message.includes('Zoom level:') || toast.id === zoomToastId;
69 return !isZoomToast;
70 });
71
72 // Show new zoom toast
73 const percentage = Math.round(zoomLevel * 100);
74 const message = `Zoom level: ${percentage}%`;
75 const id = addToast(message, 1500, 'info');
76 zoomToastId = id;
77
78 console.log('[dumber] Added zoom toast - id:', id, 'current toasts count:', toasts.length);
79
80 // Debounced cleanup for rapid zoom changes
81 zoomDebounceTimer = window.setTimeout(() => {
82 zoomToastId = null;
83 zoomDebounceTimer = undefined;
84 }, 1500);
85 }
86
87 // Expose API to global window for Go integration immediately
88 // This must happen outside onMount to ensure functions are available immediately
89 if (typeof window !== 'undefined') {
90 window.__dumber_showToast = addToast;
91 window.__dumber_dismissToast = dismissToast;
92 window.__dumber_clearToasts = clearAllToasts;
93 window.__dumber_showZoomToast = showZoomToast;
94 console.log('✅ Toast functions exposed to window:', {
95 showToast: typeof window.__dumber_showToast,
96 dismissToast: typeof window.__dumber_dismissToast,
97 clearToasts: typeof window.__dumber_clearToasts,
98 showZoomToast: typeof window.__dumber_showZoomToast
99 });
100 }
101
102 // Effect that runs when toasts array changes
103 $effect(() => {
104 const container = document.querySelector('.toast-container');
105 const browserRoot = document.querySelector('.browser-component-root');
106 console.log('[dumber] Toast state changed - container:', !!container, 'browser-root:', !!browserRoot, 'toasts:', toasts.length, 'toasts:', toasts.map(t => t.message));
107 });
108
109 // One-time setup effect
110 $effect(() => {
111 console.log('🔄 ToastContainer initialized, functions exposed');
112
113 // Monitor container periodically for debugging
114 const monitorInterval = setInterval(() => {
115 const container = document.querySelector('.toast-container');
116 const browserRoot = document.querySelector('.browser-component-root');
117 console.log('[dumber] Periodic check - container:', !!container, 'browser-root:', !!browserRoot, 'toasts:', toasts.length);
118 }, 5000);
119
120 return () => {
121 clearInterval(monitorInterval);
122 console.log('🗑️ ToastContainer cleanup');
123 };
124 });
125</script>
126
127<div class="browser-component-root toast-container">
128 {#each toasts as toast (toast.id)}
129 <Toast
130 id={toast.id}
131 message={toast.message}
132 duration={toast.duration}
133 type={toast.type}
134 onDismiss={dismissToast}
135 />
136 {/each}
137</div>
138
139<style>
140 .toast-container {
141 display: flex;
142 flex-direction: column;
143 gap: 0.5rem;
144 left: 0.5rem;
145 max-width: 20rem;
146 pointer-events: none;
147 position: fixed;
148 top: 0.5rem;
149 z-index: 2147483647;
150 }
151</style>