1//go:build webkit_cgo
2
3package webkit
4
5// getToastScript returns the injected toast notification component script.
6// Provides a reusable toast system that can display messages across all pages.
7func getToastScript() string {
8 return `(() => {
9 try {
10 if (window.__dumber_toast_loaded) return; // idempotent
11 window.__dumber_toast_loaded = true;
12
13 const T = {
14 container: null,
15 toasts: [], // {id, element, timeout}
16 counter: 0,
17
18 init() {
19 if (T.container) return;
20
21 // Create toast container
22 const container = document.createElement('div');
23 container.id = 'dumber-toast-container';
24 container.style.cssText = 'position:fixed;bottom:20px;right:20px;z-index:2147483646;pointer-events:none;';
25 document.documentElement.appendChild(container);
26 T.container = container;
27
28 // Add CSS styles
29 const style = document.createElement('style');
30 style.textContent = ` +
31"`" + `
32 .dumber-toast {
33 background: rgba(18, 18, 18, 0.95);
34 color: #eee;
35 padding: 12px 16px;
36 border-radius: 8px;
37 border: 1px solid #444;
38 box-shadow: 0 4px 12px rgba(0, 0, 0, 0.4);
39 font-family: system-ui, -apple-system, Segoe UI, Roboto, Ubuntu, "Helvetica Neue", Arial, sans-serif;
40 font-size: 14px;
41 line-height: 1.4;
42 margin-bottom: 8px;
43 max-width: 320px;
44 word-wrap: break-word;
45 backdrop-filter: blur(8px);
46 -webkit-backdrop-filter: blur(8px);
47 pointer-events: auto;
48 cursor: default;
49 transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
50 transform: translateX(100%);
51 opacity: 0;
52 }
53
54 .dumber-toast.show {
55 transform: translateX(0);
56 opacity: 1;
57 }
58
59 .dumber-toast:hover {
60 background: rgba(27, 27, 27, 0.95);
61 border-color: #555;
62 }
63 ` + "`" + `;
64 document.documentElement.appendChild(style);
65 },
66
67 show(message, duration = 2500) {
68 T.init();
69
70 const id = ++T.counter;
71 const toast = document.createElement('div');
72 toast.className = 'dumber-toast';
73 toast.textContent = message || 'Notification';
74 toast.setAttribute('data-toast-id', id);
75
76 // Click to dismiss
77 toast.addEventListener('click', () => T.dismiss(id));
78
79 T.container.appendChild(toast);
80
81 // Trigger show animation
82 requestAnimationFrame(() => {
83 toast.classList.add('show');
84 });
85
86 // Auto-dismiss
87 const timeout = setTimeout(() => T.dismiss(id), duration);
88
89 T.toasts.push({ id, element: toast, timeout });
90
91 console.log('📋 Toast:', message);
92 return id;
93 },
94
95 dismiss(id) {
96 const toastIndex = T.toasts.findIndex(t => t.id === id);
97 if (toastIndex === -1) return;
98
99 const toast = T.toasts[toastIndex];
100 clearTimeout(toast.timeout);
101
102 // Animate out
103 toast.element.style.transform = 'translateX(100%)';
104 toast.element.style.opacity = '0';
105
106 setTimeout(() => {
107 if (toast.element && toast.element.parentNode) {
108 toast.element.parentNode.removeChild(toast.element);
109 }
110 T.toasts.splice(toastIndex, 1);
111 }, 300);
112 },
113
114 clear() {
115 T.toasts.forEach(toast => {
116 clearTimeout(toast.timeout);
117 if (toast.element && toast.element.parentNode) {
118 toast.element.parentNode.removeChild(toast.element);
119 }
120 });
121 T.toasts = [];
122 }
123 };
124
125 // Public API for native integration
126 window.__dumber_showToast = (message, duration) => T.show(message, duration);
127 window.__dumber_dismissToast = (id) => T.dismiss(id);
128 window.__dumber_clearToasts = () => T.clear();
129
130 console.log('✅ Dumber Browser toast system loaded');
131
132 } catch (e) {
133 console.error('❌ Failed to initialize Dumber toast system:', e);
134 }
135})();`
136}