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 // Listen for toast events from main world bridge
88 if (typeof document !== 'undefined') {
89 // Listen for general toast requests
90 document.addEventListener('dumber:toast', ((event: CustomEvent) => {
91 const { message, duration, type } = event.detail;
92 console.log('[ToastContainer] Received toast event:', { message, duration, type });
93 addToast(message, duration, type);
94 }) as EventListener);
95
96 // Listen for zoom toast requests
97 document.addEventListener('dumber:toast:zoom', ((event: CustomEvent) => {
98 const { level } = event.detail;
99 console.log('[ToastContainer] Received zoom toast event:', level);
100 showZoomToast(level);
101 }) as EventListener);
102
103 console.log('✅ Toast event listeners set up for CustomEvents');
104 }
105
106 // Effect that runs when toasts array changes
107 $effect(() => {
108 const container = document.querySelector('.toast-container');
109 const browserRoot = document.querySelector('.browser-component-root');
110 console.log('[dumber] Toast state changed - container:', !!container, 'browser-root:', !!browserRoot, 'toasts:', toasts.length, 'toasts:', toasts.map(t => t.message));
111 });
112
113 // One-time setup effect
114 $effect(() => {
115 console.log('🔄 ToastContainer initialized, functions exposed');
116
117 // Monitor container periodically for debugging (disabled)
118 // const monitorInterval = setInterval(() => {
119 // const container = document.querySelector('.toast-container');
120 // const browserRoot = document.querySelector('.browser-component-root');
121 // console.log('[dumber] Periodic check - container:', !!container, 'browser-root:', !!browserRoot, 'toasts:', toasts.length);
122 // }, 5000);
123
124 return () => {
125 // clearInterval(monitorInterval);
126 console.log('🗑️ ToastContainer cleanup');
127 };
128 });
129</script>
130
131<div class="browser-component-root toast-container">
132 {#each toasts as toast (toast.id)}
133 <Toast
134 id={toast.id}
135 message={toast.message}
136 duration={toast.duration}
137 type={toast.type}
138 onDismiss={dismissToast}
139 />
140 {/each}
141</div>
142
143<style>
144 .toast-container {
145 display: flex;
146 flex-direction: column;
147 gap: 0.5rem;
148 left: 0.5rem;
149 max-width: 20rem;
150 pointer-events: none;
151 position: fixed;
152 top: 0.5rem;
153 z-index: 2147483647;
154 }
155</style>