1591 lines
61 KiB
JavaScript
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');
|
|
});
|