/** * 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 = `
${iconSvg}
${options.title ? `
${options.title}
` : ''}
${message}
${options.actions ? this.createActionButtons(options.actions, toastId) : ''}
${progressBar}
`; // 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 `
`; } createActionButtons(actions, toastId) { return actions.map(action => ` `).join(''); } getIconSvg(type) { const icons = { success: ` `, error: ` `, warning: ` `, info: ` `, loading: ` ` }; 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 = `
`; 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 = `

Benachrichtigungseinstellungen

`; 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'); });