Files
SkyArtShop/website/public/assets/js/notifications.js
Local Server 1919f6f8bb updateweb
2026-01-01 22:24:30 -06:00

225 lines
5.4 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
/**
* Notification System
* Accessible toast notifications
*/
(function () {
"use strict";
class NotificationManager {
constructor() {
this.container = null;
this.notifications = new Map();
this.init();
}
init() {
if (document.readyState === "loading") {
document.addEventListener("DOMContentLoaded", () =>
this.createContainer()
);
} else {
this.createContainer();
}
}
createContainer() {
if (!document.body || this.container) return;
this.container = document.createElement("div");
this.container.id = "notification-container";
this.container.setAttribute("aria-live", "polite");
this.container.setAttribute("aria-atomic", "true");
this.container.className = "notification-container";
const style = document.createElement("style");
style.textContent = `
.notification-container {
position: fixed;
top: 80px;
right: 20px;
z-index: 10000;
display: flex;
flex-direction: column;
gap: 10px;
max-width: 400px;
pointer-events: none;
}
.notification {
padding: 12px 20px;
border-radius: 8px;
box-shadow: 0 4px 12px rgba(0,0,0,0.15);
display: flex;
align-items: center;
gap: 12px;
color: white;
font-size: 14px;
font-weight: 500;
pointer-events: auto;
animation: slideInRight 0.3s ease;
min-width: 250px;
}
.notification.removing {
animation: slideOutRight 0.3s ease;
}
.notification-success {
background: #10b981;
}
.notification-error {
background: #ef4444;
}
.notification-info {
background: #3b82f6;
}
.notification-warning {
background: #f59e0b;
}
.notification-icon {
font-size: 18px;
flex-shrink: 0;
}
.notification-message {
flex: 1;
}
.notification-close {
background: transparent;
border: none;
color: white;
cursor: pointer;
padding: 4px;
opacity: 0.8;
transition: opacity 0.2s;
}
.notification-close:hover {
opacity: 1;
}
@keyframes slideInRight {
from {
transform: translateX(400px);
opacity: 0;
}
to {
transform: translateX(0);
opacity: 1;
}
}
@keyframes slideOutRight {
from {
transform: translateX(0);
opacity: 1;
}
to {
transform: translateX(400px);
opacity: 0;
}
}
@media (max-width: 640px) {
.notification-container {
right: 10px;
left: 10px;
max-width: none;
}
.notification {
min-width: auto;
}
}
`;
document.head.appendChild(style);
document.body.appendChild(this.container);
}
show(message, type = "info", duration = 3000) {
if (!this.container) this.createContainer();
if (!this.container) return;
const id = Date.now() + Math.random();
const notification = document.createElement("div");
notification.className = `notification notification-${type}`;
notification.setAttribute("role", "alert");
const icons = {
success: "✓",
error: "✕",
info: "",
warning: "⚠",
};
notification.innerHTML = `
<span class="notification-icon">${icons[type] || icons.info}</span>
<span class="notification-message">${this.escapeHtml(message)}</span>
<button class="notification-close" aria-label="Close notification">×</button>
`;
const closeBtn = notification.querySelector(".notification-close");
closeBtn.addEventListener("click", () => this.remove(id));
this.container.appendChild(notification);
this.notifications.set(id, notification);
if (duration > 0) {
setTimeout(() => this.remove(id), duration);
}
return id;
}
remove(id) {
const notification = this.notifications.get(id);
if (!notification) return;
notification.classList.add("removing");
setTimeout(() => {
if (notification.parentNode) {
notification.parentNode.removeChild(notification);
}
this.notifications.delete(id);
}, 300);
}
escapeHtml(text) {
const div = document.createElement("div");
div.textContent = text;
return div.innerHTML;
}
success(message, duration) {
return this.show(message, "success", duration);
}
error(message, duration) {
return this.show(message, "error", duration);
}
info(message, duration) {
return this.show(message, "info", duration);
}
warning(message, duration) {
return this.show(message, "warning", duration);
}
}
// Create global instance
window.Notifications = window.Notifications || new NotificationManager();
// Legacy compatibility
window.showNotification = function (message, type = "info") {
window.Notifications.show(message, type);
};
})();