/**
* 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 = `
${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');
});