/**
* toast.js - Modularized Notification System for drawNET
*/
let toastContainer = null;
/**
* Ensures a singleton container for toasts exists in the DOM.
*/
function ensureContainer() {
if (toastContainer) return toastContainer;
toastContainer = document.createElement('div');
toastContainer.id = 'toast-container';
toastContainer.style.cssText = `
position: fixed;
bottom: 30px;
left: 50%;
transform: translateX(-50%);
display: flex;
flex-direction: column;
gap: 10px;
z-index: 10000;
pointer-events: none;
`;
document.body.appendChild(toastContainer);
return toastContainer;
}
/**
* showToast - Displays a stylish, non-blocking notification
* @param {string} message - Message to display
* @param {string} type - 'info', 'success', 'warning', 'error'
* @param {number} duration - MS to stay visible (default 3500)
*/
export function showToast(message, type = 'info', duration = 3500) {
const container = ensureContainer();
const toast = document.createElement('div');
toast.className = `toast-item ${type}`;
const colors = {
info: '#3b82f6',
success: '#10b981',
warning: '#f59e0b',
error: '#ef4444'
};
const icons = {
info: 'fa-info-circle',
success: 'fa-check-circle',
warning: 'fa-exclamation-triangle',
error: 'fa-times-circle'
};
toast.innerHTML = `
${message}
`;
toast.style.cssText = `
background: rgba(15, 23, 42, 0.9);
color: white;
padding: 12px 20px;
border-radius: 12px;
font-size: 13px;
font-weight: 600;
box-shadow: 0 10px 15px -3px rgba(0, 0, 0, 0.3);
display: flex;
align-items: center;
gap: 12px;
border-left: 4px solid ${colors[type]};
backdrop-filter: blur(8px);
pointer-events: auto;
animation: toastIn 0.4s cubic-bezier(0.175, 0.885, 0.32, 1.275) forwards;
min-width: 280px;
`;
// Add CSS Keyframes if not present
if (!document.getElementById('toast-styles')) {
const style = document.createElement('style');
style.id = 'toast-styles';
style.innerHTML = `
@keyframes toastIn {
from { opacity: 0; transform: translateY(20px); }
to { opacity: 1; transform: translateY(0); }
}
@keyframes toastOut {
from { opacity: 1; transform: translateY(0); }
to { opacity: 0; transform: translateY(-20px) scale(0.95); }
}
`;
document.head.appendChild(style);
}
container.appendChild(toast);
const dismiss = () => {
toast.style.animation = 'toastOut 0.3s ease-in forwards';
setTimeout(() => toast.remove(), 300);
};
setTimeout(dismiss, duration);
toast.onclick = dismiss;
}