PyRunner / static /js /toast.js
Akoda35's picture
Upload toast.js
42bc952 verified
Raw
History Blame Contribute Delete
3.81 kB
/**
* PyRunner Toast Notification System
*/
const PyRunnerToast = {
container: null,
defaults: {
duration: 5000,
maxToasts: 5
},
init() {
if (!this.container) {
this.container = document.createElement('div');
this.container.id = 'toast-container';
this.container.className = 'fixed flex flex-col gap-3 pointer-events-none';
this.container.style.cssText = 'top: 5rem; right: 1rem; z-index: 9999;';
document.body.appendChild(this.container);
}
},
show(message, type = 'info', duration = this.defaults.duration) {
this.init();
const toast = document.createElement('div');
toast.className = this.getToastClasses(type);
toast.innerHTML = this.getToastHTML(message, type);
toast.style.animation = 'toastSlideIn 0.3s ease-out';
const closeBtn = toast.querySelector('[data-toast-close]');
if (closeBtn) {
closeBtn.addEventListener('click', () => this.dismiss(toast));
}
while (this.container.children.length >= this.defaults.maxToasts) {
this.dismiss(this.container.firstChild);
}
this.container.appendChild(toast);
if (duration > 0) {
setTimeout(() => this.dismiss(toast), duration);
}
return toast;
},
dismiss(toast) {
if (!toast || !toast.parentNode) return;
toast.style.animation = 'toastSlideOut 0.2s ease-in forwards';
setTimeout(() => toast.remove(), 200);
},
getToastClasses(type) {
const base = 'pointer-events-auto max-w-sm w-full p-4 rounded-lg border shadow-lg flex items-start gap-3';
const types = {
success: 'bg-code-surface border-code-green/30 text-code-green',
error: 'bg-code-surface border-code-red/30 text-code-red',
warning: 'bg-code-surface border-code-yellow/30 text-code-yellow',
info: 'bg-code-surface border-code-accent/30 text-code-accent'
};
return `${base} ${types[type] || types.info}`;
},
getToastHTML(message, type) {
const icons = {
success: '<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M5 13l4 4L19 7"/>',
error: '<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M6 18L18 6M6 6l12 12"/>',
warning: '<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 9v2m0 4h.01m-6.938 4h13.856c1.54 0 2.502-1.667 1.732-3L13.732 4c-.77-1.333-2.694-1.333-3.464 0L3.34 16c-.77 1.333.192 3 1.732 3z"/>',
info: '<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M13 16h-1v-4h-1m1-4h.01M21 12a9 9 0 11-18 0 9 9 0 0118 0z"/>'
};
return `
<svg class="w-5 h-5 flex-shrink-0 mt-0.5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
${icons[type] || icons.info}
</svg>
<p class="flex-1 text-sm text-code-text">${message}</p>
<button data-toast-close class="flex-shrink-0 text-code-muted hover:text-code-text transition-colors">
<svg class="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M6 18L18 6M6 6l12 12"/>
</svg>
</button>
`;
},
success(message, duration) { return this.show(message, 'success', duration); },
error(message, duration) { return this.show(message, 'error', duration); },
warning(message, duration) { return this.show(message, 'warning', duration); },
info(message, duration) { return this.show(message, 'info', duration); }
};
window.Toast = PyRunnerToast;