manage-your-printer/static/js/glassmorphism-notifications.js
2025-06-04 10:03:22 +02:00

1591 lines
61 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;
// Callback-Registry für Actions hinzufügen
this.actionCallbacks = new Map();
this.callbackCounter = 0;
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);
// Globale Callback-Ausführungsfunktion
window.executeNotificationCallback = this.executeCallback.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 => {
// Callback in Registry speichern falls vorhanden
let callbackId = '';
if (action.callback && typeof action.callback === 'function') {
callbackId = `callback-${++this.callbackCounter}`;
this.actionCallbacks.set(callbackId, action.callback);
}
return `
<button class="toast-action-btn toast-action-${action.type || 'secondary'}"
onclick="glassNotificationSystem.handleActionClick('${callbackId}', '${toastId}', ${action.closeAfter !== false})"
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 Eingangsanimation mit Glassmorphism-Effekten
toast.style.transform = 'translateX(120%) scale(0.8) rotateY(15deg)';
toast.style.opacity = '0';
toast.style.filter = 'blur(8px)';
// Trigger animation
requestAnimationFrame(() => {
toast.style.transition = 'all 0.8s cubic-bezier(0.34, 1.56, 0.64, 1)';
toast.style.transform = 'translateX(0) scale(1) rotateY(0deg)';
toast.style.opacity = '1';
toast.style.filter = 'blur(0px)';
toast.classList.add('show');
});
}
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';
}
// Hover-Effekt verstärken
toast.style.transform = 'translateY(-4px) scale(1.03)';
toast.style.filter = 'brightness(1.1) saturate(1.1)';
};
const resumeTimer = () => {
isPaused = false;
const progressBar = toast.querySelector('.toast-progress-bar');
if (progressBar) {
progressBar.style.animationPlayState = 'running';
}
// Hover-Effekt zurücksetzen
toast.style.transform = 'translateY(0) scale(1)';
toast.style.filter = 'brightness(1) saturate(1)';
};
toast.addEventListener('mouseenter', pauseTimer);
toast.addEventListener('mouseleave', resumeTimer);
toast.addEventListener('focus', pauseTimer);
toast.addEventListener('blur', resumeTimer);
}
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) {
// Verbesserte Ausgangsanimation
toast.style.transition = 'all 0.6s cubic-bezier(0.4, 0, 1, 1)';
toast.style.transform = 'translateX(120%) scale(0.8) rotateY(-15deg)';
toast.style.opacity = '0';
toast.style.filter = 'blur(4px)';
setTimeout(() => {
this.removeToast(toastId);
}, 600);
} else {
this.removeToast(toastId);
}
}
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);
// Alle zugehörigen Callbacks löschen
this.actionCallbacks.forEach((callback, callbackId) => {
if (callbackId.includes(toastId)) {
this.actionCallbacks.delete(callbackId);
}
});
this.repositionAllToasts();
}
repositionAllToasts() {
const container = document.getElementById('glassmorphism-toast-container');
if (!container) return;
const toasts = Array.from(container.children);
toasts.forEach((toast, index) => {
// Gestaffelte Positionierung mit smooth transition
toast.style.top = `${1 + index * 3.75}rem`;
toast.style.zIndex = 1000 - index;
// Leichter Versatz für Tiefeneffekt
if (index > 0) {
toast.style.transform = `scale(${1 - index * 0.015})`;
toast.style.opacity = `${1 - index * 0.08}`;
}
});
}
closeAllToasts() {
const toastIds = Array.from(this.notifications.keys());
toastIds.forEach((id, index) => {
setTimeout(() => this.closeToast(id), index * 100);
});
}
/**
* Spezielle Toast-Typen
*/
showConfirmationToast(message, onConfirm, onCancel = null, options = {}) {
const confirmCallback = () => {
if (typeof onConfirm === 'function') {
try {
onConfirm();
} catch (error) {
console.error('Fehler beim Ausführen der Bestätigungslogik:', error);
}
}
};
const cancelCallback = () => {
if (typeof onCancel === 'function') {
try {
onCancel();
} catch (error) {
console.error('Fehler beim Ausführen der Abbruchlogik:', error);
}
}
};
const actions = [
{
text: options.confirmText || 'Bestätigen',
type: 'primary',
callback: confirmCallback,
closeAfter: true
}
];
// Cancel-Button nur hinzufügen wenn Callback vorhanden ist
if (onCancel || options.cancelText) {
actions.push({
text: options.cancelText || 'Abbrechen',
type: 'secondary',
callback: cancelCallback,
closeAfter: true
});
}
return this.showToast(message, 'warning', 0, {
persistent: true,
title: options.title || 'Bestätigung erforderlich',
actions: actions,
...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)();
// Verfeinerte und melodiösere Frequenzen
const frequencies = {
success: [523.25, 659.25, 783.99, 880], // C-E-G-A (Dur-Akkord mit Terz)
error: [440, 370, 311], // A-F#-D# (dissonanter Moll-Akkord)
warning: [493.88, 587.33, 659.25], // B-D-E (warnendes Motiv)
info: [523.25, 659.25], // C-E (freundlich)
loading: [392, 440, 493.88, 523.25] // G-A-B-C (aufsteigende Melodie)
};
const freq = frequencies[type] || frequencies.info;
freq.forEach((f, i) => {
setTimeout(() => {
const oscillator = audioContext.createOscillator();
const gainNode = audioContext.createGain();
const filterNode = audioContext.createBiquadFilter();
// Sanfterer Sound mit Filter
oscillator.connect(filterNode);
filterNode.connect(gainNode);
gainNode.connect(audioContext.destination);
// Filtereinstellungen für weicheren Klang
filterNode.type = 'lowpass';
filterNode.frequency.setValueAtTime(2000, audioContext.currentTime);
filterNode.Q.setValueAtTime(1, audioContext.currentTime);
oscillator.frequency.setValueAtTime(f, audioContext.currentTime);
// Sanftere Wellenformen je nach Typ
oscillator.type = type === 'error' ? 'triangle' : 'sine';
// Dezentere Lautstärke und sanftere Envelope
const baseVolume = type === 'error' ? 0.06 : 0.08;
gainNode.gain.setValueAtTime(0, audioContext.currentTime);
gainNode.gain.linearRampToValueAtTime(baseVolume, audioContext.currentTime + 0.1);
gainNode.gain.exponentialRampToValueAtTime(0.001, audioContext.currentTime + 0.3);
oscillator.start(audioContext.currentTime);
oscillator.stop(audioContext.currentTime + 0.3);
}, i * 120); // Langsamere Abfolge für melodiöseren Effekt
});
// Zusätzlicher subtiler Reverb-Effekt für Success
if (type === 'success') {
setTimeout(() => {
const reverb = audioContext.createConvolver();
const impulse = audioContext.createBuffer(2, audioContext.sampleRate * 0.5, audioContext.sampleRate);
for (let channel = 0; channel < impulse.numberOfChannels; channel++) {
const channelData = impulse.getChannelData(channel);
for (let i = 0; i < channelData.length; i++) {
channelData[i] = (Math.random() * 2 - 1) * Math.pow(1 - i / channelData.length, 2);
}
}
reverb.buffer = impulse;
const finalOsc = audioContext.createOscillator();
const finalGain = audioContext.createGain();
finalOsc.connect(reverb);
reverb.connect(finalGain);
finalGain.connect(audioContext.destination);
finalOsc.frequency.setValueAtTime(1046.5, audioContext.currentTime); // Hohe C
finalOsc.type = 'sine';
finalGain.gain.setValueAtTime(0, audioContext.currentTime);
finalGain.gain.linearRampToValueAtTime(0.03, audioContext.currentTime + 0.1);
finalGain.gain.exponentialRampToValueAtTime(0.001, audioContext.currentTime + 0.8);
finalOsc.start(audioContext.currentTime);
finalOsc.stop(audioContext.currentTime + 0.8);
}, freq.length * 120);
}
} 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 = `
.glassmorphism-toast {
margin-bottom: 0.625rem;
transform: translateX(100%);
opacity: 0;
transition: all 0.7s cubic-bezier(0.34, 1.56, 0.64, 1);
will-change: transform, opacity, filter;
/* Erweiterte Premium Glassmorphism-Eigenschaften */
backdrop-filter: blur(50px) saturate(200%) brightness(120%) contrast(110%);
-webkit-backdrop-filter: blur(50px) saturate(200%) brightness(120%) contrast(110%);
box-shadow:
0 32px 64px rgba(0, 0, 0, 0.1),
0 16px 32px rgba(0, 0, 0, 0.06),
0 6px 12px rgba(0, 0, 0, 0.05),
inset 0 2px 0 rgba(255, 255, 255, 0.4),
inset 0 1px 2px rgba(255, 255, 255, 0.7),
0 0 0 1px rgba(255, 255, 255, 0.18);
border-radius: 1.5rem;
overflow: hidden;
position: relative;
/* Subtile Farbverläufe */
background: linear-gradient(145deg,
rgba(255, 255, 255, 0.12) 0%,
rgba(255, 255, 255, 0.06) 25%,
rgba(255, 255, 255, 0.1) 50%,
rgba(255, 255, 255, 0.05) 75%,
rgba(255, 255, 255, 0.08) 100%);
}
/* Erweiterte Glassmorphism-Overlay-Effekte */
.glassmorphism-toast::before {
content: '';
position: absolute;
top: 0;
left: 0;
right: 0;
bottom: 0;
background:
radial-gradient(circle at 25% 25%, rgba(255, 255, 255, 0.25) 0%, transparent 35%),
radial-gradient(circle at 75% 75%, rgba(255, 255, 255, 0.15) 0%, transparent 35%),
radial-gradient(circle at 50% 10%, rgba(255, 255, 255, 0.1) 0%, transparent 40%),
linear-gradient(135deg, rgba(255, 255, 255, 0.15) 0%, transparent 60%),
conic-gradient(from 180deg at 50% 50%,
rgba(255, 255, 255, 0.05) 0deg,
rgba(255, 255, 255, 0.1) 45deg,
rgba(255, 255, 255, 0.05) 90deg,
rgba(255, 255, 255, 0.08) 135deg,
rgba(255, 255, 255, 0.05) 180deg,
rgba(255, 255, 255, 0.12) 225deg,
rgba(255, 255, 255, 0.05) 270deg,
rgba(255, 255, 255, 0.08) 315deg,
rgba(255, 255, 255, 0.05) 360deg);
pointer-events: none;
opacity: 0;
transition: opacity 0.4s cubic-bezier(0.4, 0, 0.2, 1);
animation: subtle-shimmer 8s ease-in-out infinite;
}
/* Elegante Shimmer-Animation */
@keyframes subtle-shimmer {
0%, 100% { opacity: 0; transform: scale(1) rotate(0deg); }
25% { opacity: 0.3; transform: scale(1.01) rotate(1deg); }
50% { opacity: 0.6; transform: scale(1.02) rotate(0deg); }
75% { opacity: 0.3; transform: scale(1.01) rotate(-1deg); }
}
.glassmorphism-toast:hover::before {
opacity: 1;
animation-play-state: paused;
}
/* Floating-Partikel-Effekt bei Hover */
.glassmorphism-toast::after {
content: '';
position: absolute;
top: -50%;
left: -50%;
width: 200%;
height: 200%;
background:
radial-gradient(circle at 20% 20%, rgba(255, 255, 255, 0.3) 1px, transparent 1px),
radial-gradient(circle at 60% 80%, rgba(255, 255, 255, 0.2) 1px, transparent 1px),
radial-gradient(circle at 80% 30%, rgba(255, 255, 255, 0.25) 1px, transparent 1px),
radial-gradient(circle at 30% 70%, rgba(255, 255, 255, 0.15) 1px, transparent 1px);
opacity: 0;
transition: opacity 0.6s ease;
animation: floating-particles 12s linear infinite;
pointer-events: none;
}
@keyframes floating-particles {
0% { transform: translate(0, 0) rotate(0deg); }
25% { transform: translate(-10px, -10px) rotate(90deg); }
50% { transform: translate(0, -20px) rotate(180deg); }
75% { transform: translate(10px, -10px) rotate(270deg); }
100% { transform: translate(0, 0) rotate(360deg); }
}
.glassmorphism-toast:hover::after {
opacity: 1;
}
.glassmorphism-toast.show {
transform: translateX(0);
opacity: 1;
}
/* Typ-spezifische erweiterte Premium Glassmorphism-Effekte */
.glassmorphism-toast.notification-success {
background: linear-gradient(145deg,
rgba(34, 197, 94, 0.18) 0%,
rgba(134, 239, 172, 0.12) 20%,
rgba(16, 185, 129, 0.15) 40%,
rgba(34, 197, 94, 0.08) 60%,
rgba(134, 239, 172, 0.1) 80%,
rgba(16, 185, 129, 0.06) 100%);
border: 1px solid rgba(34, 197, 94, 0.3);
box-shadow:
0 40px 80px rgba(34, 197, 94, 0.15),
0 20px 40px rgba(34, 197, 94, 0.08),
0 8px 16px rgba(16, 185, 129, 0.1),
inset 0 3px 0 rgba(255, 255, 255, 0.6),
inset 0 1px 2px rgba(134, 239, 172, 0.4),
0 0 0 1px rgba(34, 197, 94, 0.2);
color: rgba(5, 95, 70, 0.95);
}
.dark .glassmorphism-toast.notification-success {
color: rgba(134, 239, 172, 0.95);
background: linear-gradient(145deg,
rgba(34, 197, 94, 0.25) 0%,
rgba(134, 239, 172, 0.15) 30%,
rgba(34, 197, 94, 0.12) 70%,
rgba(16, 185, 129, 0.08) 100%);
}
.glassmorphism-toast.notification-error {
background: linear-gradient(145deg,
rgba(239, 68, 68, 0.18) 0%,
rgba(252, 165, 165, 0.12) 20%,
rgba(220, 38, 38, 0.15) 40%,
rgba(239, 68, 68, 0.08) 60%,
rgba(252, 165, 165, 0.1) 80%,
rgba(220, 38, 38, 0.06) 100%);
border: 1px solid rgba(239, 68, 68, 0.3);
box-shadow:
0 40px 80px rgba(239, 68, 68, 0.15),
0 20px 40px rgba(239, 68, 68, 0.08),
0 8px 16px rgba(220, 38, 38, 0.1),
inset 0 3px 0 rgba(255, 255, 255, 0.6),
inset 0 1px 2px rgba(252, 165, 165, 0.4),
0 0 0 1px rgba(239, 68, 68, 0.2);
color: rgba(153, 27, 27, 0.95);
}
.dark .glassmorphism-toast.notification-error {
color: rgba(252, 165, 165, 0.95);
background: linear-gradient(145deg,
rgba(239, 68, 68, 0.25) 0%,
rgba(252, 165, 165, 0.15) 30%,
rgba(239, 68, 68, 0.12) 70%,
rgba(220, 38, 38, 0.08) 100%);
}
.glassmorphism-toast.notification-warning {
background: linear-gradient(145deg,
rgba(245, 158, 11, 0.18) 0%,
rgba(252, 211, 77, 0.12) 20%,
rgba(217, 119, 6, 0.15) 40%,
rgba(245, 158, 11, 0.08) 60%,
rgba(252, 211, 77, 0.1) 80%,
rgba(217, 119, 6, 0.06) 100%);
border: 1px solid rgba(245, 158, 11, 0.3);
box-shadow:
0 40px 80px rgba(245, 158, 11, 0.15),
0 20px 40px rgba(245, 158, 11, 0.08),
0 8px 16px rgba(217, 119, 6, 0.1),
inset 0 3px 0 rgba(255, 255, 255, 0.6),
inset 0 1px 2px rgba(252, 211, 77, 0.4),
0 0 0 1px rgba(245, 158, 11, 0.2);
color: rgba(146, 64, 14, 0.95);
}
.dark .glassmorphism-toast.notification-warning {
color: rgba(252, 211, 77, 0.95);
background: linear-gradient(145deg,
rgba(245, 158, 11, 0.25) 0%,
rgba(252, 211, 77, 0.15) 30%,
rgba(245, 158, 11, 0.12) 70%,
rgba(217, 119, 6, 0.08) 100%);
}
.glassmorphism-toast.notification-info {
background: linear-gradient(145deg,
rgba(59, 130, 246, 0.18) 0%,
rgba(147, 197, 253, 0.12) 20%,
rgba(37, 99, 235, 0.15) 40%,
rgba(59, 130, 246, 0.08) 60%,
rgba(147, 197, 253, 0.1) 80%,
rgba(37, 99, 235, 0.06) 100%);
border: 1px solid rgba(59, 130, 246, 0.3);
box-shadow:
0 40px 80px rgba(59, 130, 246, 0.15),
0 20px 40px rgba(59, 130, 246, 0.08),
0 8px 16px rgba(37, 99, 235, 0.1),
inset 0 3px 0 rgba(255, 255, 255, 0.6),
inset 0 1px 2px rgba(147, 197, 253, 0.4),
0 0 0 1px rgba(59, 130, 246, 0.2);
color: rgba(30, 64, 175, 0.95);
}
.dark .glassmorphism-toast.notification-info {
color: rgba(147, 197, 253, 0.95);
background: linear-gradient(145deg,
rgba(59, 130, 246, 0.25) 0%,
rgba(147, 197, 253, 0.15) 30%,
rgba(59, 130, 246, 0.12) 70%,
rgba(37, 99, 235, 0.08) 100%);
}
.glassmorphism-toast.notification-loading {
background: linear-gradient(145deg,
rgba(99, 102, 241, 0.18) 0%,
rgba(165, 180, 252, 0.12) 20%,
rgba(79, 70, 229, 0.15) 40%,
rgba(99, 102, 241, 0.08) 60%,
rgba(165, 180, 252, 0.1) 80%,
rgba(79, 70, 229, 0.06) 100%);
border: 1px solid rgba(99, 102, 241, 0.3);
box-shadow:
0 40px 80px rgba(99, 102, 241, 0.15),
0 20px 40px rgba(99, 102, 241, 0.08),
0 8px 16px rgba(79, 70, 229, 0.1),
inset 0 3px 0 rgba(255, 255, 255, 0.6),
inset 0 1px 2px rgba(165, 180, 252, 0.4),
0 0 0 1px rgba(99, 102, 241, 0.2);
color: rgba(55, 48, 163, 0.95);
}
.dark .glassmorphism-toast.notification-loading {
color: rgba(165, 180, 252, 0.95);
background: linear-gradient(145deg,
rgba(99, 102, 241, 0.25) 0%,
rgba(165, 180, 252, 0.15) 30%,
rgba(99, 102, 241, 0.12) 70%,
rgba(79, 70, 229, 0.08) 100%);
}
/* Dark Mode Premium Anpassungen */
.dark .glassmorphism-toast {
backdrop-filter: blur(80px) saturate(200%) brightness(115%) contrast(125%);
-webkit-backdrop-filter: blur(80px) saturate(200%) brightness(115%) contrast(125%);
box-shadow:
0 40px 80px rgba(0, 0, 0, 0.4),
0 20px 40px rgba(0, 0, 0, 0.3),
0 8px 16px rgba(0, 0, 0, 0.2),
inset 0 3px 0 rgba(255, 255, 255, 0.15),
inset 0 1px 2px rgba(255, 255, 255, 0.25),
0 0 0 1px rgba(255, 255, 255, 0.08);
background: linear-gradient(145deg,
rgba(0, 0, 0, 0.25) 0%,
rgba(15, 15, 15, 0.18) 25%,
rgba(0, 0, 0, 0.22) 50%,
rgba(10, 10, 10, 0.15) 75%,
rgba(0, 0, 0, 0.2) 100%);
}
.dark .glassmorphism-toast::before {
background:
radial-gradient(circle at 25% 25%, rgba(255, 255, 255, 0.12) 0%, transparent 35%),
radial-gradient(circle at 75% 75%, rgba(255, 255, 255, 0.08) 0%, transparent 35%),
radial-gradient(circle at 50% 10%, rgba(255, 255, 255, 0.06) 0%, transparent 40%),
linear-gradient(135deg, rgba(255, 255, 255, 0.08) 0%, transparent 60%),
conic-gradient(from 180deg at 50% 50%,
rgba(255, 255, 255, 0.03) 0deg,
rgba(255, 255, 255, 0.06) 45deg,
rgba(255, 255, 255, 0.03) 90deg,
rgba(255, 255, 255, 0.05) 135deg,
rgba(255, 255, 255, 0.03) 180deg,
rgba(255, 255, 255, 0.07) 225deg,
rgba(255, 255, 255, 0.03) 270deg,
rgba(255, 255, 255, 0.05) 315deg,
rgba(255, 255, 255, 0.03) 360deg);
}
.dark .glassmorphism-toast::after {
background:
radial-gradient(circle at 20% 20%, rgba(255, 255, 255, 0.15) 1px, transparent 1px),
radial-gradient(circle at 60% 80%, rgba(255, 255, 255, 0.1) 1px, transparent 1px),
radial-gradient(circle at 80% 30%, rgba(255, 255, 255, 0.12) 1px, transparent 1px),
radial-gradient(circle at 30% 70%, rgba(255, 255, 255, 0.08) 1px, transparent 1px);
}
.toast-content {
position: relative;
overflow: hidden;
padding: 1rem;
border-radius: inherit;
}
.toast-header {
display: flex;
align-items: flex-start;
gap: 0.875rem;
}
.toast-icon {
flex-shrink: 0;
width: 2.25rem;
height: 2.25rem;
display: flex;
align-items: center;
justify-content: center;
border-radius: 50%;
background: linear-gradient(145deg,
rgba(255, 255, 255, 0.35) 0%,
rgba(255, 255, 255, 0.2) 50%,
rgba(255, 255, 255, 0.3) 100%);
backdrop-filter: blur(16px) saturate(140%);
-webkit-backdrop-filter: blur(16px) saturate(140%);
border: 1px solid rgba(255, 255, 255, 0.4);
box-shadow:
0 8px 16px rgba(0, 0, 0, 0.06),
0 2px 4px rgba(0, 0, 0, 0.04),
inset 0 1px 0 rgba(255, 255, 255, 0.6),
inset 0 -1px 0 rgba(0, 0, 0, 0.03);
transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
position: relative;
overflow: hidden;
}
/* Icon-Glow-Effekt */
.toast-icon::before {
content: '';
position: absolute;
top: -50%;
left: -50%;
width: 200%;
height: 200%;
background: radial-gradient(circle, rgba(255, 255, 255, 0.25) 0%, transparent 70%);
opacity: 0;
transition: opacity 0.3s ease;
animation: icon-pulse 3s ease-in-out infinite;
}
@keyframes icon-pulse {
0%, 100% { opacity: 0; transform: scale(0.8); }
50% { opacity: 0.4; transform: scale(1.1); }
}
.toast-icon:hover::before {
opacity: 1;
animation-play-state: paused;
}
.toast-icon:hover {
transform: scale(1.08) rotate(8deg);
box-shadow:
0 12px 24px rgba(0, 0, 0, 0.08),
0 4px 8px rgba(0, 0, 0, 0.06),
inset 0 1px 0 rgba(255, 255, 255, 0.7),
inset 0 -1px 0 rgba(0, 0, 0, 0.05);
}
.dark .toast-icon {
background: linear-gradient(145deg,
rgba(0, 0, 0, 0.35) 0%,
rgba(15, 15, 15, 0.25) 50%,
rgba(0, 0, 0, 0.3) 100%);
border: 1px solid rgba(255, 255, 255, 0.12);
box-shadow:
0 8px 16px rgba(0, 0, 0, 0.25),
0 2px 4px rgba(0, 0, 0, 0.15),
inset 0 1px 0 rgba(255, 255, 255, 0.12),
inset 0 -1px 0 rgba(255, 255, 255, 0.03);
}
.dark .toast-icon::before {
background: radial-gradient(circle, rgba(255, 255, 255, 0.12) 0%, transparent 70%);
}
.toast-body {
flex: 1;
min-width: 0;
}
.toast-title {
font-weight: 600;
font-size: 0.875rem;
margin-bottom: 0.375rem;
line-height: 1.3;
letter-spacing: 0.01em;
text-shadow: 0 1px 2px rgba(0, 0, 0, 0.06);
background: linear-gradient(135deg, currentColor 0%, currentColor 100%);
-webkit-background-clip: text;
background-clip: text;
}
.toast-message {
font-size: 0.8125rem;
line-height: 1.4;
opacity: 0.9;
font-weight: 450;
text-shadow: 0 1px 2px rgba(0, 0, 0, 0.04);
}
.toast-actions {
display: flex;
gap: 0.5rem;
align-items: flex-start;
flex-shrink: 0;
}
.toast-action-btn {
padding: 0.5rem 0.875rem;
border-radius: 0.75rem;
font-size: 0.75rem;
font-weight: 500;
border: none;
cursor: pointer;
transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
display: flex;
align-items: center;
gap: 0.375rem;
background: linear-gradient(145deg,
rgba(255, 255, 255, 0.25) 0%,
rgba(255, 255, 255, 0.12) 50%,
rgba(255, 255, 255, 0.2) 100%);
color: inherit;
backdrop-filter: blur(16px) saturate(130%);
-webkit-backdrop-filter: blur(16px) saturate(130%);
border: 1px solid rgba(255, 255, 255, 0.3);
box-shadow:
0 4px 8px rgba(0, 0, 0, 0.06),
0 1px 2px rgba(0, 0, 0, 0.04),
inset 0 1px 0 rgba(255, 255, 255, 0.5);
text-shadow: 0 1px 2px rgba(0, 0, 0, 0.06);
position: relative;
overflow: hidden;
}
/* Button-Shimmer-Effekt */
.toast-action-btn::before {
content: '';
position: absolute;
top: 0;
left: -100%;
width: 100%;
height: 100%;
background: linear-gradient(90deg,
transparent 0%,
rgba(255, 255, 255, 0.3) 50%,
transparent 100%);
transition: left 0.4s cubic-bezier(0.4, 0, 0.2, 1);
}
.toast-action-btn:hover::before {
left: 100%;
}
.toast-action-btn:hover {
background: linear-gradient(145deg,
rgba(255, 255, 255, 0.35) 0%,
rgba(255, 255, 255, 0.2) 50%,
rgba(255, 255, 255, 0.3) 100%);
transform: translateY(-2px) scale(1.04);
box-shadow:
0 8px 16px rgba(0, 0, 0, 0.08),
0 2px 4px rgba(0, 0, 0, 0.06),
inset 0 1px 0 rgba(255, 255, 255, 0.6);
border-color: rgba(255, 255, 255, 0.5);
}
.toast-action-btn:active {
transform: translateY(-1px) scale(1.02);
transition: transform 0.1s ease;
}
.toast-action-primary {
background: linear-gradient(145deg,
rgba(59, 130, 246, 0.8) 0%,
rgba(37, 99, 235, 0.85) 50%,
rgba(59, 130, 246, 0.75) 100%);
color: white;
border-color: rgba(59, 130, 246, 0.6);
box-shadow:
0 4px 12px rgba(59, 130, 246, 0.2),
0 1px 3px rgba(59, 130, 246, 0.12),
inset 0 1px 0 rgba(255, 255, 255, 0.25);
text-shadow: 0 1px 2px rgba(0, 0, 0, 0.15);
}
.toast-action-primary::before {
background: linear-gradient(90deg,
transparent 0%,
rgba(255, 255, 255, 0.25) 50%,
transparent 100%);
}
.toast-action-primary:hover {
background: linear-gradient(145deg,
rgba(59, 130, 246, 0.9) 0%,
rgba(37, 99, 235, 0.95) 50%,
rgba(59, 130, 246, 0.85) 100%);
box-shadow:
0 8px 20px rgba(59, 130, 246, 0.25),
0 2px 6px rgba(59, 130, 246, 0.18),
inset 0 1px 0 rgba(255, 255, 255, 0.3);
}
.dark .toast-action-btn {
background: linear-gradient(145deg,
rgba(0, 0, 0, 0.35) 0%,
rgba(15, 15, 15, 0.25) 50%,
rgba(0, 0, 0, 0.3) 100%);
border: 1px solid rgba(255, 255, 255, 0.12);
box-shadow:
0 4px 8px rgba(0, 0, 0, 0.15),
0 1px 2px rgba(0, 0, 0, 0.12),
inset 0 1px 0 rgba(255, 255, 255, 0.08);
}
.dark .toast-action-btn:hover {
background: linear-gradient(145deg,
rgba(0, 0, 0, 0.45) 0%,
rgba(15, 15, 15, 0.35) 50%,
rgba(0, 0, 0, 0.4) 100%);
box-shadow:
0 8px 16px rgba(0, 0, 0, 0.2),
0 2px 4px rgba(0, 0, 0, 0.15),
inset 0 1px 0 rgba(255, 255, 255, 0.12);
}
.toast-close {
padding: 0.375rem;
border-radius: 0.625rem;
border: none;
background: linear-gradient(145deg,
rgba(255, 255, 255, 0.18) 0%,
rgba(255, 255, 255, 0.08) 50%,
rgba(255, 255, 255, 0.12) 100%);
color: inherit;
cursor: pointer;
opacity: 0.75;
transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
display: flex;
align-items: center;
justify-content: center;
backdrop-filter: blur(16px) saturate(110%);
-webkit-backdrop-filter: blur(16px) saturate(110%);
border: 1px solid rgba(255, 255, 255, 0.2);
box-shadow:
0 2px 4px rgba(0, 0, 0, 0.06),
0 1px 2px rgba(0, 0, 0, 0.04),
inset 0 1px 0 rgba(255, 255, 255, 0.3);
position: relative;
overflow: hidden;
}
/* Close-Button-Ripple-Effekt */
.toast-close::after {
content: '';
position: absolute;
top: 50%;
left: 50%;
width: 0;
height: 0;
border-radius: 50%;
background: rgba(255, 255, 255, 0.3);
transform: translate(-50%, -50%);
transition: width 0.25s ease, height 0.25s ease;
}
.toast-close:hover::after {
width: 100%;
height: 100%;
}
.toast-close:hover {
opacity: 1;
background: linear-gradient(145deg,
rgba(255, 255, 255, 0.28) 0%,
rgba(255, 255, 255, 0.15) 50%,
rgba(255, 255, 255, 0.22) 100%);
transform: scale(1.1) rotate(90deg);
box-shadow:
0 4px 8px rgba(0, 0, 0, 0.08),
0 1px 2px rgba(0, 0, 0, 0.06),
inset 0 1px 0 rgba(255, 255, 255, 0.5);
}
.toast-close:active {
transform: scale(1.05) rotate(90deg);
transition: transform 0.1s ease;
}
.dark .toast-close {
background: linear-gradient(145deg,
rgba(0, 0, 0, 0.25) 0%,
rgba(15, 15, 15, 0.15) 50%,
rgba(0, 0, 0, 0.2) 100%);
border: 1px solid rgba(255, 255, 255, 0.08);
box-shadow:
0 2px 4px rgba(0, 0, 0, 0.15),
0 1px 2px rgba(0, 0, 0, 0.12),
inset 0 1px 0 rgba(255, 255, 255, 0.06);
}
.dark .toast-close::after {
background: rgba(255, 255, 255, 0.15);
}
.dark .toast-close:hover {
background: linear-gradient(145deg,
rgba(0, 0, 0, 0.35) 0%,
rgba(15, 15, 15, 0.25) 50%,
rgba(0, 0, 0, 0.4) 100%);
box-shadow:
0 4px 8px rgba(0, 0, 0, 0.25),
0 1px 2px rgba(0, 0, 0, 0.18),
inset 0 1px 0 rgba(255, 255, 255, 0.1);
}
.toast-progress {
position: absolute;
bottom: 0;
left: 0;
right: 0;
height: 3px;
background: linear-gradient(90deg,
rgba(255, 255, 255, 0.08) 0%,
rgba(255, 255, 255, 0.04) 50%,
rgba(255, 255, 255, 0.08) 100%);
overflow: hidden;
border-radius: 0 0 1.75rem 1.75rem;
backdrop-filter: blur(8px);
-webkit-backdrop-filter: blur(8px);
}
.toast-progress-bar {
height: 100%;
background: linear-gradient(90deg,
rgba(255, 255, 255, 0.6) 0%,
rgba(255, 255, 255, 0.8) 25%,
rgba(255, 255, 255, 0.9) 50%,
rgba(255, 255, 255, 0.8) 75%,
rgba(255, 255, 255, 0.6) 100%);
width: 0%;
transition: width 0.25s ease;
position: relative;
border-radius: inherit;
box-shadow:
0 0 8px rgba(255, 255, 255, 0.4),
0 0 4px rgba(255, 255, 255, 0.3),
inset 0 1px 0 rgba(255, 255, 255, 0.7);
overflow: hidden;
}
/* Progress-Bar-Animationen */
.toast-progress-bar::before {
content: '';
position: absolute;
top: 0;
left: 0;
right: 0;
bottom: 0;
background: linear-gradient(90deg,
transparent 0%,
rgba(255, 255, 255, 0.4) 25%,
rgba(255, 255, 255, 0.6) 50%,
rgba(255, 255, 255, 0.4) 75%,
transparent 100%);
animation: progress-shimmer 2s ease-in-out infinite;
}
.toast-progress-bar::after {
content: '';
position: absolute;
top: 0;
left: 0;
right: 0;
bottom: 0;
background: linear-gradient(45deg,
transparent 25%,
rgba(255, 255, 255, 0.2) 25%,
rgba(255, 255, 255, 0.2) 50%,
transparent 50%,
transparent 75%,
rgba(255, 255, 255, 0.2) 75%);
background-size: 12px 12px;
animation: progress-stripes 0.8s linear infinite;
}
@keyframes progress-shimmer {
0% { transform: translateX(-100%); }
100% { transform: translateX(100%); }
}
@keyframes progress-stripes {
0% { background-position: 0 0; }
100% { background-position: 12px 0; }
}
@keyframes toast-progress {
from { width: 100%; }
to { width: 0%; }
}
.notification-settings {
max-width: 320px;
padding: 0.875rem;
background: linear-gradient(145deg,
rgba(255, 255, 255, 0.12) 0%,
rgba(255, 255, 255, 0.06) 50%,
rgba(255, 255, 255, 0.1) 100%);
border-radius: 1.25rem;
backdrop-filter: blur(24px) saturate(140%);
-webkit-backdrop-filter: blur(24px) saturate(140%);
border: 1px solid rgba(255, 255, 255, 0.25);
box-shadow:
0 16px 32px rgba(0, 0, 0, 0.08),
0 6px 12px rgba(0, 0, 0, 0.04),
inset 0 1px 0 rgba(255, 255, 255, 0.4);
}
.dark .notification-settings {
background: linear-gradient(145deg,
rgba(0, 0, 0, 0.35) 0%,
rgba(15, 15, 15, 0.25) 50%,
rgba(0, 0, 0, 0.3) 100%);
border: 1px solid rgba(255, 255, 255, 0.08);
box-shadow:
0 16px 32px rgba(0, 0, 0, 0.25),
0 6px 12px rgba(0, 0, 0, 0.15),
inset 0 1px 0 rgba(255, 255, 255, 0.06);
}
.notification-settings h3 {
margin-bottom: 1rem;
font-size: 1rem;
font-weight: 600;
color: inherit;
text-align: center;
background: linear-gradient(135deg, currentColor 0%, currentColor 100%);
-webkit-background-clip: text;
background-clip: text;
text-shadow: 0 1px 2px rgba(0, 0, 0, 0.08);
}
.setting-item {
display: flex;
align-items: center;
gap: 0.75rem;
margin: 1rem 0;
cursor: pointer;
font-size: 0.875rem;
font-weight: 450;
padding: 0.75rem;
border-radius: 0.875rem;
transition: all 0.25s cubic-bezier(0.4, 0, 0.2, 1);
background: linear-gradient(145deg,
rgba(255, 255, 255, 0.08) 0%,
rgba(255, 255, 255, 0.04) 100%);
border: 1px solid rgba(255, 255, 255, 0.12);
backdrop-filter: blur(12px);
-webkit-backdrop-filter: blur(12px);
position: relative;
overflow: hidden;
}
/* Setting-Item-Hover-Effekt */
.setting-item::before {
content: '';
position: absolute;
top: 0;
left: -100%;
width: 100%;
height: 100%;
background: linear-gradient(90deg,
transparent 0%,
rgba(255, 255, 255, 0.08) 50%,
transparent 100%);
transition: left 0.3s ease;
}
.setting-item:hover::before {
left: 100%;
}
.setting-item:hover {
background: linear-gradient(145deg,
rgba(255, 255, 255, 0.16) 0%,
rgba(255, 255, 255, 0.08) 100%);
transform: translateX(6px) scale(1.01);
box-shadow:
0 6px 12px rgba(0, 0, 0, 0.06),
0 1px 2px rgba(0, 0, 0, 0.04),
inset 0 1px 0 rgba(255, 255, 255, 0.25);
}
.dark .setting-item {
background: linear-gradient(145deg,
rgba(0, 0, 0, 0.18) 0%,
rgba(15, 15, 15, 0.12) 100%);
border: 1px solid rgba(255, 255, 255, 0.06);
}
.dark .setting-item:hover {
background: linear-gradient(145deg,
rgba(0, 0, 0, 0.25) 0%,
rgba(15, 15, 15, 0.18) 100%);
box-shadow:
0 6px 12px rgba(0, 0, 0, 0.15),
0 1px 2px rgba(0, 0, 0, 0.12),
inset 0 1px 0 rgba(255, 255, 255, 0.08);
}
.setting-item input[type="checkbox"] {
margin: 0;
width: 1.25rem;
height: 1.25rem;
accent-color: currentColor;
cursor: pointer;
border-radius: 0.3rem;
transition: all 0.2s ease;
}
.setting-item input[type="checkbox"]:checked {
transform: scale(1.05);
box-shadow: 0 0 6px rgba(59, 130, 246, 0.3);
}
/* Responsive Design */
@media (max-width: 640px) {
.notifications-container {
left: 0.5rem;
right: 0.5rem;
top: 0.5rem;
}
.glassmorphism-toast {
margin-bottom: 0.5rem;
border-radius: 1.25rem;
}
.toast-content {
padding: 0.875rem;
}
.toast-header {
gap: 0.75rem;
}
.toast-icon {
width: 2rem;
height: 2rem;
}
.toast-title {
font-size: 0.8125rem;
}
.toast-message {
font-size: 0.75rem;
}
.toast-action-btn {
padding: 0.4rem 0.7rem;
font-size: 0.7rem;
}
.toast-close {
padding: 0.3rem;
}
}
/* High Contrast Mode */
@media (prefers-contrast: high) {
.glassmorphism-toast {
border: 2px solid currentColor;
backdrop-filter: none;
-webkit-backdrop-filter: none;
background: rgba(255, 255, 255, 0.95);
}
.dark .glassmorphism-toast {
background: rgba(0, 0, 0, 0.95);
}
}
/* Reduced Motion */
@media (prefers-reduced-motion: reduce) {
.glassmorphism-toast,
.toast-icon,
.toast-action-btn,
.toast-close {
transition: none !important;
animation: none !important;
}
.glassmorphism-toast:hover {
transform: none !important;
}
}
`;
document.head.appendChild(styles);
}
/**
* Behandelt Action-Button-Klicks
*/
handleActionClick(callbackId, toastId, shouldClose = true) {
// Callback ausführen falls vorhanden
if (callbackId && this.actionCallbacks.has(callbackId)) {
const callback = this.actionCallbacks.get(callbackId);
try {
callback();
} catch (error) {
console.error('Fehler beim Ausführen des Action-Callbacks:', error);
}
// Callback nach Ausführung löschen
this.actionCallbacks.delete(callbackId);
}
// Toast schließen falls gewünscht
if (shouldClose) {
this.closeToast(toastId);
}
}
/**
* Für Rückwärtskompatibilität - führt Callback-Funktionen aus
*/
executeCallback(callbackId) {
if (this.actionCallbacks.has(callbackId)) {
const callback = this.actionCallbacks.get(callbackId);
try {
callback();
} catch (error) {
console.error('Fehler beim Ausführen des Callbacks:', error);
}
this.actionCallbacks.delete(callbackId);
}
}
}
// 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');
});