// assets/js/toast.js // Shows toast in the TOP LAYER: if a exists, append inside it. // Otherwise append to . Default type = success (green). window.Toast = (function () { // create (or reuse) a toast root inside a given container function ensureRoot(container) { // Find last (topmost) open dialog if not explicitly passed const host = container || (() => { const dialogs = Array.from(document.querySelectorAll('dialog[open]')); return dialogs.length ? dialogs[dialogs.length - 1] : document.body; })(); // Root per container (class-based to allow multiple roots) let root = host.querySelector(':scope > .toast-root'); if (!root) { root = document.createElement('div'); root.className = 'toast-root'; host.appendChild(root); } return root; } function render(msg, type, duration, container) { const root = ensureRoot(container); const n = document.createElement('div'); n.className = 'toast' + (type === 'error' ? ' error' : ' success'); n.innerHTML = ` ${type === 'error' ? '⚠️' : '✅'} ${msg || ''} `; root.appendChild(n); const close = () => { try { n.remove(); } catch {} }; n.querySelector('.close')?.addEventListener('click', close); const t = setTimeout(close, Number(duration) || 2200); // clean timer if user closes early n.addEventListener('remove', () => clearTimeout(t), { once:true }); } // API function show(msg, opt) { opt = opt || {}; render( msg, opt.type === 'error' ? 'error' : 'success', opt.duration, opt.container // optional: pass a specific container ); } return { show }; })();