1210 lines
45 KiB
JavaScript
1210 lines
45 KiB
JavaScript
/**
|
|
* Zentrales Glassmorphism-Benachrichtigungssystem für MYP Platform
|
|
* Vereinheitlicht alle Notification-Typen mit modernem Design
|
|
*/
|
|
|
|
class GlassmorphismNotificationSystem {
|
|
constructor() {
|
|
this.notifications = new Map();
|
|
this.toastCounter = 0;
|
|
this.soundEnabled = localStorage.getItem('myp-notification-sound') !== 'false';
|
|
this.animationsEnabled = !window.matchMedia('(prefers-reduced-motion: reduce)').matches;
|
|
|
|
this.init();
|
|
this.setupGlobalFunctions();
|
|
this.injectStyles();
|
|
}
|
|
|
|
init() {
|
|
// Container für Toasts erstellen
|
|
this.createToastContainer();
|
|
|
|
// Event-Listener für Einstellungen
|
|
this.setupEventListeners();
|
|
|
|
console.log('🎨 Glassmorphism Notification System initialisiert');
|
|
}
|
|
|
|
createToastContainer() {
|
|
if (!document.getElementById('glassmorphism-toast-container')) {
|
|
const container = document.createElement('div');
|
|
container.id = 'glassmorphism-toast-container';
|
|
container.className = 'notifications-container';
|
|
document.body.appendChild(container);
|
|
}
|
|
}
|
|
|
|
setupGlobalFunctions() {
|
|
// Globale Funktionen überschreiben für einheitliches Design
|
|
window.showFlashMessage = this.showToast.bind(this);
|
|
window.showToast = this.showToast.bind(this);
|
|
window.showNotification = this.showToast.bind(this);
|
|
window.showSuccessMessage = (msg, duration) => this.showToast(msg, 'success', duration);
|
|
window.showErrorMessage = (msg, duration) => this.showToast(msg, 'error', duration);
|
|
window.showWarningMessage = (msg, duration) => this.showToast(msg, 'warning', duration);
|
|
window.showInfoMessage = (msg, duration) => this.showToast(msg, 'info', duration);
|
|
window.showSuccessNotification = (msg) => this.showToast(msg, 'success');
|
|
|
|
// Spezielle Funktionen
|
|
window.showPersistentAlert = this.showPersistentAlert.bind(this);
|
|
window.showConfirmationToast = this.showConfirmationToast.bind(this);
|
|
window.showProgressToast = this.showProgressToast.bind(this);
|
|
}
|
|
|
|
setupEventListeners() {
|
|
// Keyboard Shortcuts
|
|
document.addEventListener('keydown', (e) => {
|
|
// ESC schließt alle Toasts
|
|
if (e.key === 'Escape') {
|
|
this.closeAllToasts();
|
|
}
|
|
// Ctrl/Cmd + Shift + N öffnet Benachrichtigungseinstellungen
|
|
if ((e.ctrlKey || e.metaKey) && e.shiftKey && e.key === 'N') {
|
|
this.showNotificationSettings();
|
|
}
|
|
});
|
|
|
|
// Geräte-Rotation
|
|
window.addEventListener('orientationchange', () => {
|
|
setTimeout(() => this.repositionAllToasts(), 200);
|
|
});
|
|
}
|
|
|
|
/**
|
|
* Zeigt eine Glassmorphism-Toast-Benachrichtigung
|
|
*/
|
|
showToast(message, type = 'info', duration = 5000, options = {}) {
|
|
// DND-Check
|
|
if (window.dndManager?.isEnabled) {
|
|
window.dndManager.suppressNotification(message, type);
|
|
return null;
|
|
}
|
|
|
|
const toastId = `glass-toast-${++this.toastCounter}`;
|
|
const toast = this.createToastElement(toastId, message, type, duration, options);
|
|
|
|
this.addToContainer(toast);
|
|
this.animateIn(toast);
|
|
this.scheduleRemoval(toastId, duration, options.persistent);
|
|
|
|
// Sound abspielen
|
|
if (this.soundEnabled && options.playSound !== false) {
|
|
this.playNotificationSound(type);
|
|
}
|
|
|
|
// Browser-Notification (optional)
|
|
if (options.browserNotification && 'Notification' in window) {
|
|
this.showBrowserNotification(message, type, options);
|
|
}
|
|
|
|
return toastId;
|
|
}
|
|
|
|
createToastElement(toastId, message, type, duration, options) {
|
|
const toast = document.createElement('div');
|
|
toast.id = toastId;
|
|
toast.className = `glassmorphism-toast notification notification-${type}`;
|
|
|
|
// Accessibility
|
|
toast.setAttribute('role', 'alert');
|
|
toast.setAttribute('aria-live', 'polite');
|
|
toast.setAttribute('aria-atomic', 'true');
|
|
|
|
const iconSvg = this.getIconSvg(type);
|
|
const progressBar = duration > 0 && !options.persistent ? this.createProgressBar(duration) : '';
|
|
|
|
toast.innerHTML = `
|
|
<div class="toast-content">
|
|
<div class="toast-header">
|
|
<div class="toast-icon">
|
|
${iconSvg}
|
|
</div>
|
|
<div class="toast-body">
|
|
${options.title ? `<div class="toast-title">${options.title}</div>` : ''}
|
|
<div class="toast-message">${message}</div>
|
|
</div>
|
|
<div class="toast-actions">
|
|
${options.actions ? this.createActionButtons(options.actions, toastId) : ''}
|
|
<button class="toast-close" onclick="glassNotificationSystem.closeToast('${toastId}')"
|
|
aria-label="Benachrichtigung schließen" title="Schließen">
|
|
<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>
|
|
</div>
|
|
</div>
|
|
${progressBar}
|
|
</div>
|
|
`;
|
|
|
|
// Hover-Events für Auto-Close-Pausierung
|
|
if (duration > 0 && !options.persistent) {
|
|
this.setupHoverEvents(toast, toastId);
|
|
}
|
|
|
|
this.notifications.set(toastId, {
|
|
element: toast,
|
|
type,
|
|
message,
|
|
timestamp: Date.now(),
|
|
options
|
|
});
|
|
|
|
return toast;
|
|
}
|
|
|
|
createProgressBar(duration) {
|
|
return `
|
|
<div class="toast-progress">
|
|
<div class="toast-progress-bar" style="animation: toast-progress ${duration}ms linear forwards;"></div>
|
|
</div>
|
|
`;
|
|
}
|
|
|
|
createActionButtons(actions, toastId) {
|
|
return actions.map(action => `
|
|
<button class="toast-action-btn toast-action-${action.type || 'secondary'}"
|
|
onclick="${action.onClick}; ${action.closeAfter !== false ? `glassNotificationSystem.closeToast('${toastId}')` : ''}"
|
|
title="${action.title || action.text}">
|
|
${action.icon ? `<svg class="w-4 h-4">${action.icon}</svg>` : ''}
|
|
${action.text}
|
|
</button>
|
|
`).join('');
|
|
}
|
|
|
|
getIconSvg(type) {
|
|
const icons = {
|
|
success: `<svg class="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
|
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M5 13l4 4L19 7"/>
|
|
</svg>`,
|
|
error: `<svg class="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
|
<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-2.5L13.732 4c-.77-.833-1.964-.833-2.732 0L3.732 16.5c-.77.833.192 2.5 1.732 2.5z"/>
|
|
</svg>`,
|
|
warning: `<svg class="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
|
<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-2.5L13.732 4c-.77-.833-1.964-.833-2.732 0L3.732 16.5c-.77.833.192 2.5 1.732 2.5z"/>
|
|
</svg>`,
|
|
info: `<svg class="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
|
<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"/>
|
|
</svg>`,
|
|
loading: `<svg class="w-5 h-5 animate-spin" fill="none" viewBox="0 0 24 24">
|
|
<circle cx="12" cy="12" r="10" stroke="currentColor" stroke-width="4" class="opacity-25"></circle>
|
|
<path fill="currentColor" d="M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4zm2 5.291A7.962 7.962 0 014 12H0c0 3.042 1.135 5.824 3 7.938l3-2.647z" class="opacity-75"></path>
|
|
</svg>`
|
|
};
|
|
return icons[type] || icons.info;
|
|
}
|
|
|
|
addToContainer(toast) {
|
|
const container = document.getElementById('glassmorphism-toast-container');
|
|
if (container) {
|
|
container.appendChild(toast);
|
|
this.repositionAllToasts();
|
|
}
|
|
}
|
|
|
|
animateIn(toast) {
|
|
if (!this.animationsEnabled) {
|
|
toast.classList.add('show');
|
|
return;
|
|
}
|
|
|
|
// Erweiterte Premium-Eingangsanimation mit Glassmorphism-Morphing
|
|
toast.style.transform = 'translateX(140%) scale(0.7) rotateY(25deg) rotateX(10deg)';
|
|
toast.style.opacity = '0';
|
|
toast.style.filter = 'blur(12px) brightness(0.5) saturate(2)';
|
|
toast.style.clipPath = 'polygon(0 0, 0 0, 0 100%, 0 100%)';
|
|
|
|
// Trigger premium morphing animation
|
|
requestAnimationFrame(() => {
|
|
toast.style.transition = 'all 1s cubic-bezier(0.23, 1, 0.32, 1)';
|
|
toast.style.transform = 'translateX(0) scale(1) rotateY(0deg) rotateX(0deg)';
|
|
toast.style.opacity = '1';
|
|
toast.style.filter = 'blur(0px) brightness(1) saturate(1)';
|
|
toast.style.clipPath = 'polygon(0 0, 100% 0, 100% 100%, 0 100%)';
|
|
toast.classList.add('show');
|
|
|
|
// Partikel-Effekt nach Animation
|
|
setTimeout(() => this.createEntryParticles(toast), 800);
|
|
});
|
|
}
|
|
|
|
/**
|
|
* Erstellt schöne Partikel-Effekte beim Eingang
|
|
*/
|
|
createEntryParticles(toast) {
|
|
const particleCount = 8;
|
|
const toastRect = toast.getBoundingClientRect();
|
|
|
|
for (let i = 0; i < particleCount; i++) {
|
|
const particle = document.createElement('div');
|
|
particle.className = 'notification-particle';
|
|
particle.style.cssText = `
|
|
position: fixed;
|
|
width: 4px;
|
|
height: 4px;
|
|
background: radial-gradient(circle, rgba(255,255,255,0.8) 0%, transparent 70%);
|
|
border-radius: 50%;
|
|
pointer-events: none;
|
|
z-index: 1001;
|
|
left: ${toastRect.right + Math.random() * 20}px;
|
|
top: ${toastRect.top + toastRect.height * Math.random()}px;
|
|
animation: particle-drift 2s ease-out forwards;
|
|
animation-delay: ${i * 0.1}s;
|
|
`;
|
|
|
|
document.body.appendChild(particle);
|
|
|
|
// Partikel nach Animation entfernen
|
|
setTimeout(() => {
|
|
if (particle.parentNode) {
|
|
particle.parentNode.removeChild(particle);
|
|
}
|
|
}, 2200);
|
|
}
|
|
}
|
|
|
|
setupHoverEvents(toast, toastId) {
|
|
let timeoutId;
|
|
let isPaused = false;
|
|
|
|
const notification = this.notifications.get(toastId);
|
|
if (!notification) return;
|
|
|
|
const pauseTimer = () => {
|
|
isPaused = true;
|
|
clearTimeout(timeoutId);
|
|
const progressBar = toast.querySelector('.toast-progress-bar');
|
|
if (progressBar) {
|
|
progressBar.style.animationPlayState = 'paused';
|
|
}
|
|
|
|
// Erweiterte Premium-Hover-Effekte
|
|
toast.style.transform = 'translateY(-8px) scale(1.05) rotateY(2deg)';
|
|
toast.style.filter = 'brightness(1.15) saturate(1.2) drop-shadow(0 20px 40px rgba(0,0,0,0.15))';
|
|
toast.style.zIndex = '1100';
|
|
|
|
// Magisches Glühen beim Hover
|
|
this.createHoverGlow(toast);
|
|
};
|
|
|
|
const resumeTimer = () => {
|
|
isPaused = false;
|
|
const progressBar = toast.querySelector('.toast-progress-bar');
|
|
if (progressBar) {
|
|
progressBar.style.animationPlayState = 'running';
|
|
}
|
|
|
|
// Sanfter Rückgang der Hover-Effekte
|
|
toast.style.transform = 'translateY(0) scale(1) rotateY(0deg)';
|
|
toast.style.filter = 'brightness(1) saturate(1) drop-shadow(none)';
|
|
toast.style.zIndex = '';
|
|
|
|
// Glühen entfernen
|
|
this.removeHoverGlow(toast);
|
|
};
|
|
|
|
toast.addEventListener('mouseenter', pauseTimer);
|
|
toast.addEventListener('mouseleave', resumeTimer);
|
|
toast.addEventListener('focus', pauseTimer);
|
|
toast.addEventListener('blur', resumeTimer);
|
|
}
|
|
|
|
/**
|
|
* Erstellt magisches Glühen beim Hover
|
|
*/
|
|
createHoverGlow(toast) {
|
|
const existingGlow = toast.querySelector('.hover-glow');
|
|
if (existingGlow) return;
|
|
|
|
const glow = document.createElement('div');
|
|
glow.className = 'hover-glow';
|
|
glow.style.cssText = `
|
|
position: absolute;
|
|
top: -2px;
|
|
left: -2px;
|
|
right: -2px;
|
|
bottom: -2px;
|
|
background: linear-gradient(45deg,
|
|
rgba(255,255,255,0.3) 0%,
|
|
rgba(255,255,255,0.1) 25%,
|
|
rgba(255,255,255,0.3) 50%,
|
|
rgba(255,255,255,0.1) 75%,
|
|
rgba(255,255,255,0.3) 100%);
|
|
border-radius: 1.5rem;
|
|
filter: blur(3px);
|
|
opacity: 0;
|
|
pointer-events: none;
|
|
z-index: -1;
|
|
animation: glow-pulse 1.5s ease-in-out infinite alternate;
|
|
`;
|
|
|
|
toast.style.position = 'relative';
|
|
toast.appendChild(glow);
|
|
|
|
// Fade in
|
|
requestAnimationFrame(() => {
|
|
glow.style.transition = 'opacity 0.3s ease';
|
|
glow.style.opacity = '1';
|
|
});
|
|
}
|
|
|
|
/**
|
|
* Entfernt das Hover-Glühen
|
|
*/
|
|
removeHoverGlow(toast) {
|
|
const glow = toast.querySelector('.hover-glow');
|
|
if (glow) {
|
|
glow.style.transition = 'opacity 0.3s ease';
|
|
glow.style.opacity = '0';
|
|
|
|
setTimeout(() => {
|
|
if (glow.parentNode) {
|
|
glow.parentNode.removeChild(glow);
|
|
}
|
|
}, 300);
|
|
}
|
|
}
|
|
|
|
scheduleRemoval(toastId, duration, persistent = false) {
|
|
if (persistent || duration <= 0) return;
|
|
|
|
setTimeout(() => {
|
|
this.closeToast(toastId);
|
|
}, duration);
|
|
}
|
|
|
|
closeToast(toastId) {
|
|
const notification = this.notifications.get(toastId);
|
|
if (!notification) return;
|
|
|
|
const toast = notification.element;
|
|
|
|
if (this.animationsEnabled) {
|
|
// Premium-Ausgangsanimation mit Morphing
|
|
toast.style.transition = 'all 0.8s cubic-bezier(0.68, -0.55, 0.265, 1.55)';
|
|
toast.style.transform = 'translateX(140%) scale(0.6) rotateY(-30deg) rotateZ(5deg)';
|
|
toast.style.opacity = '0';
|
|
toast.style.filter = 'blur(8px) brightness(0.3)';
|
|
toast.style.clipPath = 'polygon(100% 0, 100% 0, 100% 100%, 100% 100%)';
|
|
|
|
// Ausgangs-Partikel-Effekt
|
|
this.createExitParticles(toast);
|
|
|
|
setTimeout(() => {
|
|
this.removeToast(toastId);
|
|
}, 800);
|
|
} else {
|
|
this.removeToast(toastId);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Erstellt Partikel-Effekte beim Ausgang
|
|
*/
|
|
createExitParticles(toast) {
|
|
const particleCount = 6;
|
|
const toastRect = toast.getBoundingClientRect();
|
|
|
|
for (let i = 0; i < particleCount; i++) {
|
|
const particle = document.createElement('div');
|
|
particle.className = 'notification-exit-particle';
|
|
particle.style.cssText = `
|
|
position: fixed;
|
|
width: 3px;
|
|
height: 3px;
|
|
background: radial-gradient(circle, rgba(255,255,255,0.6) 0%, transparent 70%);
|
|
border-radius: 50%;
|
|
pointer-events: none;
|
|
z-index: 1001;
|
|
left: ${toastRect.left + toastRect.width * Math.random()}px;
|
|
top: ${toastRect.top + toastRect.height * Math.random()}px;
|
|
animation: particle-disperse 1s ease-out forwards;
|
|
animation-delay: ${i * 0.05}s;
|
|
`;
|
|
|
|
document.body.appendChild(particle);
|
|
|
|
setTimeout(() => {
|
|
if (particle.parentNode) {
|
|
particle.parentNode.removeChild(particle);
|
|
}
|
|
}, 1100);
|
|
}
|
|
}
|
|
|
|
removeToast(toastId) {
|
|
const notification = this.notifications.get(toastId);
|
|
if (!notification) return;
|
|
|
|
if (notification.element.parentNode) {
|
|
notification.element.parentNode.removeChild(notification.element);
|
|
}
|
|
|
|
this.notifications.delete(toastId);
|
|
this.repositionAllToasts();
|
|
}
|
|
|
|
repositionAllToasts() {
|
|
const container = document.getElementById('glassmorphism-toast-container');
|
|
if (!container) return;
|
|
|
|
const toasts = Array.from(container.children);
|
|
toasts.forEach((toast, index) => {
|
|
// Intelligente gestaffelte Positionierung mit Wellenbewegung
|
|
const baseOffset = 1 + index * 4.2;
|
|
const waveOffset = Math.sin(index * 0.5) * 0.3;
|
|
|
|
toast.style.top = `${baseOffset + waveOffset}rem`;
|
|
toast.style.zIndex = 1000 - index;
|
|
|
|
// Sanfte Tiefenstaffelung mit eleganten Übergängen
|
|
if (index > 0) {
|
|
const scaleReduction = 1 - index * 0.015;
|
|
const opacityReduction = 1 - index * 0.08;
|
|
const blurAmount = index * 0.5;
|
|
|
|
toast.style.transform = `scale(${scaleReduction}) translateX(${index * 2}px)`;
|
|
toast.style.opacity = `${Math.max(0.4, opacityReduction)}`;
|
|
toast.style.filter = `blur(${blurAmount}px)`;
|
|
toast.style.transition = 'all 0.4s cubic-bezier(0.25, 0.46, 0.45, 0.94)';
|
|
} else {
|
|
// Erstes Toast bleibt vollständig sichtbar
|
|
toast.style.transform = 'scale(1) translateX(0px)';
|
|
toast.style.opacity = '1';
|
|
toast.style.filter = 'blur(0px)';
|
|
}
|
|
});
|
|
}
|
|
|
|
closeAllToasts() {
|
|
const toastIds = Array.from(this.notifications.keys());
|
|
|
|
// Elegante Schließung mit Welleneffekt
|
|
toastIds.forEach((id, index) => {
|
|
setTimeout(() => {
|
|
const notification = this.notifications.get(id);
|
|
if (notification) {
|
|
// Spezielle Wellenanimation für Masse-Schließung
|
|
const toast = notification.element;
|
|
toast.style.transition = 'all 0.6s cubic-bezier(0.25, 0.46, 0.45, 0.94)';
|
|
toast.style.transform = `translateX(150%) scale(0.7) rotateY(20deg)`;
|
|
toast.style.opacity = '0';
|
|
|
|
setTimeout(() => this.removeToast(id), 600);
|
|
}
|
|
}, index * 120); // Gestaffelte Schließung
|
|
});
|
|
}
|
|
|
|
/**
|
|
* Spezielle Toast-Typen
|
|
*/
|
|
showConfirmationToast(message, onConfirm, onCancel = null, options = {}) {
|
|
return this.showToast(message, 'warning', 0, {
|
|
persistent: true,
|
|
title: options.title || 'Bestätigung erforderlich',
|
|
actions: [
|
|
{
|
|
text: options.confirmText || 'Bestätigen',
|
|
type: 'primary',
|
|
onClick: `(${onConfirm.toString()})()`
|
|
},
|
|
{
|
|
text: options.cancelText || 'Abbrechen',
|
|
type: 'secondary',
|
|
onClick: onCancel ? `(${onCancel.toString()})()` : ''
|
|
}
|
|
],
|
|
...options
|
|
});
|
|
}
|
|
|
|
showProgressToast(message, type = 'info', options = {}) {
|
|
const toastId = this.showToast(message, 'loading', 0, {
|
|
persistent: true,
|
|
title: options.title || 'Verarbeitung...',
|
|
...options
|
|
});
|
|
|
|
return {
|
|
id: toastId,
|
|
updateProgress: (percent) => this.updateProgressToast(toastId, percent),
|
|
updateMessage: (newMessage) => this.updateToastMessage(toastId, newMessage),
|
|
complete: (finalMessage, finalType = 'success') => {
|
|
this.closeToast(toastId);
|
|
if (finalMessage) {
|
|
this.showToast(finalMessage, finalType, 3000);
|
|
}
|
|
}
|
|
};
|
|
}
|
|
|
|
updateProgressToast(toastId, percent) {
|
|
const notification = this.notifications.get(toastId);
|
|
if (!notification) return;
|
|
|
|
let progressBar = notification.element.querySelector('.toast-progress-bar');
|
|
if (!progressBar) {
|
|
const progressContainer = document.createElement('div');
|
|
progressContainer.className = 'toast-progress';
|
|
progressContainer.innerHTML = `<div class="toast-progress-bar"></div>`;
|
|
notification.element.querySelector('.toast-content').appendChild(progressContainer);
|
|
progressBar = progressContainer.querySelector('.toast-progress-bar');
|
|
}
|
|
|
|
progressBar.style.width = `${Math.min(100, Math.max(0, percent))}%`;
|
|
}
|
|
|
|
updateToastMessage(toastId, newMessage) {
|
|
const notification = this.notifications.get(toastId);
|
|
if (!notification) return;
|
|
|
|
const messageEl = notification.element.querySelector('.toast-message');
|
|
if (messageEl) {
|
|
messageEl.textContent = newMessage;
|
|
}
|
|
}
|
|
|
|
showPersistentAlert(message, type = 'warning', options = {}) {
|
|
return this.showToast(message, type, 0, {
|
|
persistent: true,
|
|
title: options.title || 'Wichtiger Hinweis',
|
|
actions: [{
|
|
text: 'Verstanden',
|
|
type: 'primary',
|
|
onClick: ''
|
|
}],
|
|
...options
|
|
});
|
|
}
|
|
|
|
/**
|
|
* Browser-Benachrichtigungen
|
|
*/
|
|
async showBrowserNotification(message, type, options = {}) {
|
|
if (!('Notification' in window)) return null;
|
|
|
|
if (Notification.permission === 'granted') {
|
|
return new Notification(options.title || 'MYP Platform', {
|
|
body: message,
|
|
icon: '/static/icons/notification-icon.png',
|
|
badge: '/static/icons/badge-icon.png',
|
|
tag: `myp-${type}`,
|
|
...options.browserOptions
|
|
});
|
|
} else if (Notification.permission === 'default') {
|
|
const permission = await Notification.requestPermission();
|
|
if (permission === 'granted') {
|
|
return this.showBrowserNotification(message, type, options);
|
|
}
|
|
}
|
|
return null;
|
|
}
|
|
|
|
/**
|
|
* Sound-System
|
|
*/
|
|
playNotificationSound(type) {
|
|
if (!this.soundEnabled) return;
|
|
|
|
try {
|
|
const audioContext = new (window.AudioContext || window.webkitAudioContext)();
|
|
|
|
const frequencies = {
|
|
success: [523.25, 659.25, 783.99], // C-E-G Akkord
|
|
error: [440, 415.3, 370], // A-Ab-F# (dissonant)
|
|
warning: [493.88, 523.25], // B-C
|
|
info: [523.25], // C
|
|
loading: [392, 440, 493.88] // G-A-B (aufsteigend)
|
|
};
|
|
|
|
const freq = frequencies[type] || frequencies.info;
|
|
|
|
freq.forEach((f, i) => {
|
|
setTimeout(() => {
|
|
const oscillator = audioContext.createOscillator();
|
|
const gainNode = audioContext.createGain();
|
|
|
|
oscillator.connect(gainNode);
|
|
gainNode.connect(audioContext.destination);
|
|
|
|
oscillator.frequency.setValueAtTime(f, audioContext.currentTime);
|
|
oscillator.type = type === 'error' ? 'sawtooth' : 'sine';
|
|
|
|
gainNode.gain.setValueAtTime(0.1, audioContext.currentTime);
|
|
gainNode.gain.exponentialRampToValueAtTime(0.01, audioContext.currentTime + 0.2);
|
|
|
|
oscillator.start(audioContext.currentTime);
|
|
oscillator.stop(audioContext.currentTime + 0.2);
|
|
}, i * 150);
|
|
});
|
|
} catch (error) {
|
|
// Silent fail
|
|
}
|
|
}
|
|
|
|
toggleSound() {
|
|
this.soundEnabled = !this.soundEnabled;
|
|
localStorage.setItem('myp-notification-sound', this.soundEnabled.toString());
|
|
this.showToast(
|
|
`Benachrichtigungstöne ${this.soundEnabled ? 'aktiviert' : 'deaktiviert'}`,
|
|
'info',
|
|
2000
|
|
);
|
|
}
|
|
|
|
/**
|
|
* Einstellungen
|
|
*/
|
|
showNotificationSettings() {
|
|
const settingsHTML = `
|
|
<div class="notification-settings">
|
|
<h3>Benachrichtigungseinstellungen</h3>
|
|
<label class="setting-item">
|
|
<input type="checkbox" ${this.soundEnabled ? 'checked' : ''}
|
|
onchange="glassNotificationSystem.toggleSound()">
|
|
<span>Benachrichtigungstöne</span>
|
|
</label>
|
|
<label class="setting-item">
|
|
<input type="checkbox" ${this.animationsEnabled ? 'checked' : ''}
|
|
onchange="glassNotificationSystem.toggleAnimations()">
|
|
<span>Animationen</span>
|
|
</label>
|
|
</div>
|
|
`;
|
|
|
|
this.showToast(settingsHTML, 'info', 0, {
|
|
persistent: true,
|
|
title: 'Einstellungen',
|
|
actions: [{
|
|
text: 'Schließen',
|
|
type: 'secondary',
|
|
onClick: ''
|
|
}]
|
|
});
|
|
}
|
|
|
|
toggleAnimations() {
|
|
this.animationsEnabled = !this.animationsEnabled;
|
|
this.showToast(
|
|
`Animationen ${this.animationsEnabled ? 'aktiviert' : 'deaktiviert'}`,
|
|
'info',
|
|
2000
|
|
);
|
|
}
|
|
|
|
/**
|
|
* CSS-Styles einbetten
|
|
*/
|
|
injectStyles() {
|
|
if (document.getElementById('glassmorphism-notification-styles')) return;
|
|
|
|
const styles = document.createElement('style');
|
|
styles.id = 'glassmorphism-notification-styles';
|
|
styles.textContent = `
|
|
/* Premium Glassmorphism Toast Container */
|
|
.glassmorphism-toast {
|
|
margin-bottom: 0.75rem;
|
|
transform: translateX(100%);
|
|
opacity: 0;
|
|
transition: all 1s cubic-bezier(0.23, 1, 0.32, 1);
|
|
will-change: transform, opacity, filter, clip-path;
|
|
|
|
/* Ultra-Premium Glassmorphism */
|
|
backdrop-filter: blur(60px) saturate(220%) brightness(125%) contrast(115%);
|
|
-webkit-backdrop-filter: blur(60px) saturate(220%) brightness(125%) contrast(115%);
|
|
box-shadow:
|
|
0 40px 80px rgba(0, 0, 0, 0.25),
|
|
0 20px 40px rgba(0, 0, 0, 0.15),
|
|
0 10px 20px rgba(0, 0, 0, 0.1),
|
|
inset 0 3px 0 rgba(255, 255, 255, 0.5),
|
|
inset 0 1px 0 rgba(255, 255, 255, 0.7),
|
|
0 0 0 1px rgba(255, 255, 255, 0.2),
|
|
0 0 40px rgba(255, 255, 255, 0.1);
|
|
border-radius: 1.75rem;
|
|
overflow: hidden;
|
|
position: relative;
|
|
|
|
/* Morphing-Unterstützung */
|
|
clip-path: polygon(0 0, 100% 0, 100% 100%, 0 100%);
|
|
|
|
/* Erweiterte Premium-Eigenschaften */
|
|
background: linear-gradient(135deg,
|
|
rgba(255, 255, 255, 0.15) 0%,
|
|
rgba(255, 255, 255, 0.08) 30%,
|
|
rgba(255, 255, 255, 0.12) 70%,
|
|
rgba(255, 255, 255, 0.06) 100%);
|
|
}
|
|
|
|
/* Premium-Hintergrund-Glanz */
|
|
.glassmorphism-toast::before {
|
|
content: '';
|
|
position: absolute;
|
|
top: 0;
|
|
left: 0;
|
|
right: 0;
|
|
bottom: 0;
|
|
background:
|
|
radial-gradient(circle at 30% 20%, rgba(255, 255, 255, 0.2) 0%, transparent 40%),
|
|
radial-gradient(circle at 70% 80%, rgba(255, 255, 255, 0.15) 0%, transparent 40%),
|
|
radial-gradient(circle at 20% 60%, rgba(255, 255, 255, 0.1) 0%, transparent 35%),
|
|
linear-gradient(135deg, rgba(255, 255, 255, 0.12) 0%, transparent 60%),
|
|
conic-gradient(from 45deg at 50% 50%,
|
|
rgba(255, 255, 255, 0.05) 0deg,
|
|
rgba(255, 255, 255, 0.15) 90deg,
|
|
rgba(255, 255, 255, 0.05) 180deg,
|
|
rgba(255, 255, 255, 0.1) 270deg,
|
|
rgba(255, 255, 255, 0.05) 360deg);
|
|
pointer-events: none;
|
|
opacity: 0;
|
|
transition: opacity 0.4s ease;
|
|
animation: shimmer 3s ease-in-out infinite;
|
|
}
|
|
|
|
/* Aktive Shimmer-Animation */
|
|
@keyframes shimmer {
|
|
0%, 100% { opacity: 0.3; }
|
|
50% { opacity: 0.7; }
|
|
}
|
|
|
|
.glassmorphism-toast:hover::before {
|
|
opacity: 1;
|
|
animation-duration: 1.5s;
|
|
}
|
|
|
|
/* Premium Border-Gradient */
|
|
.glassmorphism-toast::after {
|
|
content: '';
|
|
position: absolute;
|
|
top: 0;
|
|
left: 0;
|
|
right: 0;
|
|
bottom: 0;
|
|
background: linear-gradient(135deg,
|
|
rgba(255, 255, 255, 0.4) 0%,
|
|
transparent 20%,
|
|
transparent 80%,
|
|
rgba(255, 255, 255, 0.3) 100%);
|
|
border-radius: inherit;
|
|
pointer-events: none;
|
|
opacity: 0;
|
|
transition: opacity 0.3s ease;
|
|
mask: linear-gradient(#fff 0 0) content-box, linear-gradient(#fff 0 0);
|
|
mask-composite: exclude;
|
|
-webkit-mask: linear-gradient(#fff 0 0) content-box, linear-gradient(#fff 0 0);
|
|
-webkit-mask-composite: xor;
|
|
padding: 1px;
|
|
}
|
|
|
|
.glassmorphism-toast:hover::after {
|
|
opacity: 1;
|
|
}
|
|
|
|
.glassmorphism-toast.show {
|
|
transform: translateX(0);
|
|
opacity: 1;
|
|
}
|
|
|
|
/* Typ-spezifische Ultra-Premium-Glassmorphism-Effekte */
|
|
.glassmorphism-toast.notification-success {
|
|
background: linear-gradient(135deg,
|
|
rgba(34, 197, 94, 0.3) 0%,
|
|
rgba(134, 239, 172, 0.18) 25%,
|
|
rgba(34, 197, 94, 0.12) 60%,
|
|
rgba(16, 185, 129, 0.08) 85%,
|
|
rgba(34, 197, 94, 0.15) 100%);
|
|
border: 1px solid rgba(34, 197, 94, 0.5);
|
|
box-shadow:
|
|
0 40px 80px rgba(34, 197, 94, 0.25),
|
|
0 20px 40px rgba(34, 197, 94, 0.15),
|
|
0 8px 16px rgba(34, 197, 94, 0.1),
|
|
inset 0 3px 0 rgba(255, 255, 255, 0.5),
|
|
inset 0 1px 0 rgba(255, 255, 255, 0.7),
|
|
0 0 0 1px rgba(34, 197, 94, 0.4),
|
|
0 0 40px rgba(34, 197, 94, 0.2);
|
|
}
|
|
|
|
.glassmorphism-toast.notification-error {
|
|
background: linear-gradient(135deg,
|
|
rgba(239, 68, 68, 0.3) 0%,
|
|
rgba(252, 165, 165, 0.18) 25%,
|
|
rgba(239, 68, 68, 0.12) 60%,
|
|
rgba(220, 38, 38, 0.08) 85%,
|
|
rgba(239, 68, 68, 0.15) 100%);
|
|
border: 1px solid rgba(239, 68, 68, 0.5);
|
|
box-shadow:
|
|
0 40px 80px rgba(239, 68, 68, 0.25),
|
|
0 20px 40px rgba(239, 68, 68, 0.15),
|
|
0 8px 16px rgba(239, 68, 68, 0.1),
|
|
inset 0 3px 0 rgba(255, 255, 255, 0.5),
|
|
inset 0 1px 0 rgba(255, 255, 255, 0.7),
|
|
0 0 0 1px rgba(239, 68, 68, 0.4),
|
|
0 0 40px rgba(239, 68, 68, 0.2);
|
|
}
|
|
|
|
.glassmorphism-toast.notification-warning {
|
|
background: linear-gradient(135deg,
|
|
rgba(245, 158, 11, 0.3) 0%,
|
|
rgba(252, 211, 77, 0.18) 25%,
|
|
rgba(245, 158, 11, 0.12) 60%,
|
|
rgba(217, 119, 6, 0.08) 85%,
|
|
rgba(245, 158, 11, 0.15) 100%);
|
|
border: 1px solid rgba(245, 158, 11, 0.5);
|
|
box-shadow:
|
|
0 40px 80px rgba(245, 158, 11, 0.25),
|
|
0 20px 40px rgba(245, 158, 11, 0.15),
|
|
0 8px 16px rgba(245, 158, 11, 0.1),
|
|
inset 0 3px 0 rgba(255, 255, 255, 0.5),
|
|
inset 0 1px 0 rgba(255, 255, 255, 0.7),
|
|
0 0 0 1px rgba(245, 158, 11, 0.4),
|
|
0 0 40px rgba(245, 158, 11, 0.2);
|
|
}
|
|
|
|
.glassmorphism-toast.notification-info {
|
|
background: linear-gradient(135deg,
|
|
rgba(59, 130, 246, 0.3) 0%,
|
|
rgba(147, 197, 253, 0.18) 25%,
|
|
rgba(59, 130, 246, 0.12) 60%,
|
|
rgba(37, 99, 235, 0.08) 85%,
|
|
rgba(59, 130, 246, 0.15) 100%);
|
|
border: 1px solid rgba(59, 130, 246, 0.5);
|
|
box-shadow:
|
|
0 40px 80px rgba(59, 130, 246, 0.25),
|
|
0 20px 40px rgba(59, 130, 246, 0.15),
|
|
0 8px 16px rgba(59, 130, 246, 0.1),
|
|
inset 0 3px 0 rgba(255, 255, 255, 0.5),
|
|
inset 0 1px 0 rgba(255, 255, 255, 0.7),
|
|
0 0 0 1px rgba(59, 130, 246, 0.4),
|
|
0 0 40px rgba(59, 130, 246, 0.2);
|
|
}
|
|
|
|
.glassmorphism-toast.notification-loading {
|
|
background: linear-gradient(135deg,
|
|
rgba(99, 102, 241, 0.3) 0%,
|
|
rgba(165, 180, 252, 0.18) 25%,
|
|
rgba(99, 102, 241, 0.12) 60%,
|
|
rgba(79, 70, 229, 0.08) 85%,
|
|
rgba(99, 102, 241, 0.15) 100%);
|
|
border: 1px solid rgba(99, 102, 241, 0.5);
|
|
box-shadow:
|
|
0 40px 80px rgba(99, 102, 241, 0.25),
|
|
0 20px 40px rgba(99, 102, 241, 0.15),
|
|
0 8px 16px rgba(99, 102, 241, 0.1),
|
|
inset 0 3px 0 rgba(255, 255, 255, 0.5),
|
|
inset 0 1px 0 rgba(255, 255, 255, 0.7),
|
|
0 0 0 1px rgba(99, 102, 241, 0.4),
|
|
0 0 40px rgba(99, 102, 241, 0.2);
|
|
}
|
|
|
|
/* Dark Mode Ultra-Premium Anpassungen */
|
|
.dark .glassmorphism-toast {
|
|
backdrop-filter: blur(80px) saturate(200%) brightness(115%) contrast(130%);
|
|
-webkit-backdrop-filter: blur(80px) saturate(200%) brightness(115%) contrast(130%);
|
|
background: linear-gradient(135deg,
|
|
rgba(0, 0, 0, 0.4) 0%,
|
|
rgba(0, 0, 0, 0.2) 30%,
|
|
rgba(0, 0, 0, 0.35) 70%,
|
|
rgba(0, 0, 0, 0.15) 100%);
|
|
box-shadow:
|
|
0 40px 80px rgba(0, 0, 0, 0.7),
|
|
0 20px 40px rgba(0, 0, 0, 0.5),
|
|
0 10px 20px rgba(0, 0, 0, 0.4),
|
|
inset 0 3px 0 rgba(255, 255, 255, 0.25),
|
|
inset 0 1px 0 rgba(255, 255, 255, 0.35),
|
|
0 0 0 1px rgba(255, 255, 255, 0.15),
|
|
0 0 40px rgba(255, 255, 255, 0.05);
|
|
}
|
|
|
|
/* Premium Partikel-Animationen */
|
|
@keyframes particle-drift {
|
|
0% {
|
|
opacity: 1;
|
|
transform: translate(0, 0) scale(1);
|
|
}
|
|
50% {
|
|
opacity: 0.8;
|
|
transform: translate(-30px, -20px) scale(1.2);
|
|
}
|
|
100% {
|
|
opacity: 0;
|
|
transform: translate(-60px, -40px) scale(0.5);
|
|
}
|
|
}
|
|
|
|
@keyframes particle-disperse {
|
|
0% {
|
|
opacity: 1;
|
|
transform: translate(0, 0) scale(1);
|
|
}
|
|
100% {
|
|
opacity: 0;
|
|
transform: translate(40px, -30px) scale(0.3);
|
|
}
|
|
}
|
|
|
|
@keyframes glow-pulse {
|
|
0% { opacity: 0.5; transform: scale(1); }
|
|
100% { opacity: 1; transform: scale(1.05); }
|
|
}
|
|
|
|
/* Toast Content mit erweiterten Effekten */
|
|
.toast-content {
|
|
position: relative;
|
|
overflow: hidden;
|
|
padding: 1.5rem;
|
|
backdrop-filter: blur(10px);
|
|
-webkit-backdrop-filter: blur(10px);
|
|
}
|
|
|
|
.toast-header {
|
|
display: flex;
|
|
align-items: flex-start;
|
|
gap: 1.2rem;
|
|
}
|
|
|
|
/* Premium Icon-Container */
|
|
.toast-icon {
|
|
flex-shrink: 0;
|
|
width: 3rem;
|
|
height: 3rem;
|
|
display: flex;
|
|
align-items: center;
|
|
justify-content: center;
|
|
border-radius: 50%;
|
|
background: linear-gradient(135deg,
|
|
rgba(255, 255, 255, 0.3) 0%,
|
|
rgba(255, 255, 255, 0.15) 100%);
|
|
backdrop-filter: blur(20px);
|
|
-webkit-backdrop-filter: blur(20px);
|
|
border: 1px solid rgba(255, 255, 255, 0.5);
|
|
box-shadow:
|
|
0 10px 20px rgba(0, 0, 0, 0.15),
|
|
0 4px 8px rgba(0, 0, 0, 0.1),
|
|
inset 0 2px 0 rgba(255, 255, 255, 0.6),
|
|
inset 0 -1px 0 rgba(0, 0, 0, 0.1);
|
|
transition: all 0.4s cubic-bezier(0.25, 0.46, 0.45, 0.94);
|
|
position: relative;
|
|
overflow: hidden;
|
|
}
|
|
|
|
/* Icon Shimmer-Effekt */
|
|
.toast-icon::before {
|
|
content: '';
|
|
position: absolute;
|
|
top: -50%;
|
|
left: -50%;
|
|
width: 200%;
|
|
height: 200%;
|
|
background: conic-gradient(from 0deg,
|
|
transparent 0deg,
|
|
rgba(255, 255, 255, 0.3) 60deg,
|
|
transparent 120deg);
|
|
animation: icon-shimmer 3s linear infinite;
|
|
opacity: 0;
|
|
transition: opacity 0.3s ease;
|
|
}
|
|
|
|
.toast-icon:hover::before {
|
|
opacity: 1;
|
|
}
|
|
|
|
@keyframes icon-shimmer {
|
|
0% { transform: rotate(0deg); }
|
|
100% { transform: rotate(360deg); }
|
|
}
|
|
|
|
.toast-icon:hover {
|
|
transform: scale(1.15) rotate(5deg);
|
|
box-shadow:
|
|
0 15px 30px rgba(0, 0, 0, 0.2),
|
|
0 6px 12px rgba(0, 0, 0, 0.15),
|
|
inset 0 2px 0 rgba(255, 255, 255, 0.7),
|
|
0 0 20px rgba(255, 255, 255, 0.3);
|
|
}
|
|
|
|
.dark .toast-icon {
|
|
background: linear-gradient(135deg,
|
|
rgba(0, 0, 0, 0.4) 0%,
|
|
rgba(0, 0, 0, 0.2) 100%);
|
|
border: 1px solid rgba(255, 255, 255, 0.25);
|
|
box-shadow:
|
|
0 10px 20px rgba(0, 0, 0, 0.4),
|
|
0 4px 8px rgba(0, 0, 0, 0.3),
|
|
inset 0 2px 0 rgba(255, 255, 255, 0.2),
|
|
inset 0 -1px 0 rgba(0, 0, 0, 0.3);
|
|
}
|
|
|
|
.toast-body {
|
|
flex: 1;
|
|
min-width: 0;
|
|
}
|
|
|
|
.toast-title {
|
|
font-weight: 700;
|
|
font-size: 1rem;
|
|
margin-bottom: 0.5rem;
|
|
line-height: 1.3;
|
|
letter-spacing: 0.02em;
|
|
text-shadow: 0 1px 3px rgba(0, 0, 0, 0.1);
|
|
background: linear-gradient(135deg,
|
|
currentColor 0%,
|
|
rgba(255, 255, 255, 0.9) 100%);
|
|
-webkit-background-clip: text;
|
|
background-clip: text;
|
|
}
|
|
|
|
.toast-message {
|
|
font-size: 0.9rem;
|
|
line-height: 1.6;
|
|
opacity: 0.95;
|
|
font-weight: 500;
|
|
text-shadow: 0 1px 2px rgba(0, 0, 0, 0.08);
|
|
}
|
|
|
|
/* Premium Progress Bar */
|
|
.toast-progress {
|
|
position: absolute;
|
|
bottom: 0;
|
|
left: 0;
|
|
right: 0;
|
|
height: 5px;
|
|
background: linear-gradient(90deg,
|
|
rgba(255, 255, 255, 0.2) 0%,
|
|
rgba(255, 255, 255, 0.1) 100%);
|
|
overflow: hidden;
|
|
border-radius: 0 0 1.75rem 1.75rem;
|
|
}
|
|
|
|
.toast-progress-bar {
|
|
height: 100%;
|
|
background: linear-gradient(90deg,
|
|
rgba(255, 255, 255, 0.8) 0%,
|
|
rgba(255, 255, 255, 1) 30%,
|
|
rgba(255, 255, 255, 0.9) 70%,
|
|
rgba(255, 255, 255, 0.8) 100%);
|
|
width: 0%;
|
|
transition: width 0.3s ease;
|
|
position: relative;
|
|
border-radius: inherit;
|
|
box-shadow:
|
|
0 0 12px rgba(255, 255, 255, 0.6),
|
|
inset 0 1px 0 rgba(255, 255, 255, 0.9),
|
|
inset 0 -1px 0 rgba(0, 0, 0, 0.1);
|
|
overflow: hidden;
|
|
}
|
|
|
|
/* Premium Shimmer für Progress Bar */
|
|
.toast-progress-bar::after {
|
|
content: '';
|
|
position: absolute;
|
|
top: 0;
|
|
left: 0;
|
|
right: 0;
|
|
bottom: 0;
|
|
background: linear-gradient(90deg,
|
|
transparent 0%,
|
|
rgba(255, 255, 255, 0.6) 30%,
|
|
rgba(255, 255, 255, 0.8) 50%,
|
|
rgba(255, 255, 255, 0.6) 70%,
|
|
transparent 100%);
|
|
animation: progress-shimmer 2.5s ease-in-out infinite;
|
|
}
|
|
|
|
@keyframes progress-shimmer {
|
|
0% { transform: translateX(-150%); }
|
|
100% { transform: translateX(250%); }
|
|
}
|
|
|
|
@keyframes toast-progress {
|
|
from { width: 100%; }
|
|
to { width: 0%; }
|
|
}
|
|
|
|
/* Responsive Design mit erweiterten Breakpoints */
|
|
@media (max-width: 640px) {
|
|
.glassmorphism-toast {
|
|
margin-bottom: 0.5rem;
|
|
border-radius: 1.5rem;
|
|
}
|
|
|
|
.toast-content {
|
|
padding: 1.25rem;
|
|
}
|
|
|
|
.toast-icon {
|
|
width: 2.5rem;
|
|
height: 2.5rem;
|
|
}
|
|
}
|
|
|
|
@media (max-width: 480px) {
|
|
.toast-content {
|
|
padding: 1rem;
|
|
}
|
|
|
|
.toast-header {
|
|
gap: 1rem;
|
|
}
|
|
|
|
.toast-icon {
|
|
width: 2.25rem;
|
|
height: 2.25rem;
|
|
}
|
|
}
|
|
|
|
/* Ultra High-DPI Display Optimierungen */
|
|
@media (-webkit-min-device-pixel-ratio: 2), (min-resolution: 192dpi) {
|
|
.glassmorphism-toast {
|
|
backdrop-filter: blur(80px) saturate(250%) brightness(130%) contrast(120%);
|
|
-webkit-backdrop-filter: blur(80px) saturate(250%) brightness(130%) contrast(120%);
|
|
}
|
|
}
|
|
|
|
/* High Contrast Mode Verbesserungen */
|
|
@media (prefers-contrast: high) {
|
|
.glassmorphism-toast {
|
|
border: 3px solid currentColor;
|
|
backdrop-filter: none;
|
|
-webkit-backdrop-filter: none;
|
|
background: rgba(255, 255, 255, 0.98);
|
|
box-shadow: 0 10px 25px rgba(0, 0, 0, 0.3);
|
|
}
|
|
|
|
.dark .glassmorphism-toast {
|
|
background: rgba(0, 0, 0, 0.98);
|
|
}
|
|
}
|
|
|
|
/* Reduced Motion Anpassungen */
|
|
@media (prefers-reduced-motion: reduce) {
|
|
.glassmorphism-toast,
|
|
.toast-icon,
|
|
.toast-progress-bar,
|
|
.toast-progress-bar::after {
|
|
transition: none !important;
|
|
animation: none !important;
|
|
}
|
|
|
|
.glassmorphism-toast:hover {
|
|
transform: none !important;
|
|
}
|
|
}
|
|
`;
|
|
|
|
document.head.appendChild(styles);
|
|
}
|
|
}
|
|
|
|
// Globale Instanz erstellen
|
|
const glassNotificationSystem = new GlassmorphismNotificationSystem();
|
|
|
|
// Für Rückwärtskompatibilität
|
|
if (typeof window !== 'undefined') {
|
|
window.glassNotificationSystem = glassNotificationSystem;
|
|
window.GlassmorphismNotificationSystem = GlassmorphismNotificationSystem;
|
|
}
|
|
|
|
// Event für DOM-ready ohne Test-Benachrichtigung
|
|
document.addEventListener('DOMContentLoaded', () => {
|
|
console.log('🎨 Glassmorphism Notification System bereit');
|
|
});
|