📝 🚀 "Refactor backend structure

This commit is contained in:
2025-06-01 01:09:49 +02:00
parent 4dd3c4b1b1
commit 00c2cc3f27
15 changed files with 2264 additions and 218 deletions

View File

@ -969,36 +969,37 @@
let icon = '';
switch(type) {
case 'success':
icon = `<svg class="w-5 h-5 mr-3" fill="currentColor" viewBox="0 0 20 20">
icon = `<svg class="w-5 h-5 mr-3 flex-shrink-0" fill="currentColor" viewBox="0 0 20 20">
<path fill-rule="evenodd" d="M10 18a8 8 0 100-16 8 8 0 000 16zm3.707-9.293a1 1 0 00-1.414-1.414L9 10.586 7.707 9.293a1 1 0 00-1.414 1.414l2 2a1 1 0 001.414 0l4-4z" clip-rule="evenodd"/>
</svg>`;
break;
case 'error':
icon = `<svg class="w-5 h-5 mr-3" fill="currentColor" viewBox="0 0 20 20">
icon = `<svg class="w-5 h-5 mr-3 flex-shrink-0" fill="currentColor" viewBox="0 0 20 20">
<path fill-rule="evenodd" d="M10 18a8 8 0 100-16 8 8 0 000 16zM8.707 7.293a1 1 0 00-1.414 1.414L8.586 10l-1.293 1.293a1 1 0 101.414 1.414L10 11.414l1.293 1.293a1 1 0 001.414-1.414L11.414 10l1.293-1.293a1 1 0 00-1.414-1.414L10 8.586 8.707 7.293z" clip-rule="evenodd"/>
</svg>`;
break;
case 'warning':
icon = `<svg class="w-5 h-5 mr-3" fill="currentColor" viewBox="0 0 20 20">
icon = `<svg class="w-5 h-5 mr-3 flex-shrink-0" fill="currentColor" viewBox="0 0 20 20">
<path fill-rule="evenodd" d="M8.257 3.099c.765-1.36 2.722-1.36 3.486 0l5.58 9.92c.75 1.334-.213 2.98-1.742 2.98H4.42c-1.53 0-2.493-1.646-1.743-2.98l5.58-9.92zM11 13a1 1 0 11-2 0 1 1 0 012 0zm-1-8a1 1 0 00-1 1v3a1 1 0 002 0V6a1 1 0 00-1-1z" clip-rule="evenodd"/>
</svg>`;
break;
case 'info':
default:
icon = `<svg class="w-5 h-5 mr-3" fill="currentColor" viewBox="0 0 20 20">
icon = `<svg class="w-5 h-5 mr-3 flex-shrink-0" fill="currentColor" viewBox="0 0 20 20">
<path fill-rule="evenodd" d="M18 10a8 8 0 11-16 0 8 8 0 0116 0zm-7-4a1 1 0 11-2 0 1 1 0 012 0zM9 9a1 1 0 000 2v3a1 1 0 001 1h1a1 1 0 100-2v-3a1 1 0 00-1-1H9z" clip-rule="evenodd"/>
</svg>`;
}
// Inhalt der Flash Message
flashElement.innerHTML = `
<div class="flex items-center">
<div class="flex items-start">
${icon}
<div class="flex-1">
<p class="font-medium text-sm">${message}</p>
<div class="flex-1 min-w-0">
<p class="font-medium text-sm leading-relaxed">${message}</p>
</div>
<button class="flash-close-btn ml-4 text-current opacity-70 hover:opacity-100 transition-opacity duration-200"
onclick="closeFlashMessage('${messageId}')">
<button class="flash-close-btn ml-4 flex-shrink-0 text-current opacity-70 hover:opacity-100 transition-opacity duration-200 focus:outline-none focus:opacity-100"
onclick="closeFlashMessage('${messageId}')"
aria-label="Nachricht 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>
@ -1012,6 +1013,12 @@
// Flash Messages vertikal stapeln
repositionFlashMessages();
// Einblende-Animation starten
requestAnimationFrame(() => {
flashElement.style.transform = 'translateX(0) translateY(0)';
flashElement.style.opacity = '1';
});
// Nach der angegebenen Zeit automatisch entfernen
setTimeout(() => {
closeFlashMessage(messageId);
@ -1043,10 +1050,26 @@
*/
function repositionFlashMessages() {
const flashMessages = document.querySelectorAll('.flash-message:not(.hiding)');
const gap = 12; // Abstand zwischen Messages
const startTop = 16; // Top-Offset
flashMessages.forEach((flash, index) => {
flash.style.top = `${16 + (index * 80)}px`; // 16px base + 80px pro Message
const yPosition = startTop + (index * (80 + gap)); // 80px Höhe + gap
// Position setzen
flash.style.position = 'fixed';
flash.style.top = `${yPosition}px`;
flash.style.right = '16px';
flash.style.zIndex = 50 - index; // Neueste Messages haben höheren z-index
flash.style.zIndex = 50 + (flashMessages.length - index); // Neueste Messages haben höheren z-index
flash.style.width = 'auto';
flash.style.maxWidth = '420px';
flash.style.minWidth = '320px';
// Initiale Position für Animation (nur bei neuen Messages)
if (!flash.style.transform) {
flash.style.transform = 'translateX(100%) translateY(-20px)';
flash.style.opacity = '0';
}
});
}
@ -1485,6 +1508,11 @@
* Einstellungs-Modal anzeigen
*/
showSettings() {
// Prüfen ob Modal bereits offen ist
if (document.querySelector('.dnd-modal')) {
return; // Modal bereits offen, nicht doppelt öffnen
}
const modal = document.createElement('div');
modal.className = 'dnd-modal';
modal.innerHTML = `
@ -1493,7 +1521,8 @@
<h3 class="text-lg font-semibold text-slate-900 dark:text-white">
🔕 Nicht stören
</h3>
<button class="dnd-close-btn text-slate-500 hover:text-slate-700 dark:text-slate-400 dark:hover:text-slate-200">
<button class="dnd-close-btn text-slate-500 hover:text-slate-700 dark:text-slate-400 dark:hover:text-slate-200 transition-colors duration-200"
type="button">
<svg class="w-6 h-6" 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>
@ -1503,16 +1532,16 @@
<div class="space-y-4">
<!-- Schnell-Aktionen -->
<div class="grid grid-cols-2 gap-3">
<button class="dnd-quick-btn btn-primary" data-duration="30">
<button class="dnd-quick-btn btn-primary" data-duration="30" type="button">
30 Min
</button>
<button class="dnd-quick-btn btn-primary" data-duration="60">
<button class="dnd-quick-btn btn-primary" data-duration="60" type="button">
1 Stunde
</button>
<button class="dnd-quick-btn btn-primary" data-duration="480">
<button class="dnd-quick-btn btn-primary" data-duration="480" type="button">
8 Stunden
</button>
<button class="dnd-quick-btn btn-primary" data-duration="0">
<button class="dnd-quick-btn btn-primary" data-duration="0" type="button">
Dauerhaft
</button>
</div>
@ -1543,7 +1572,8 @@
<h4 class="text-sm font-medium text-slate-900 dark:text-white">
Unterdrückte Nachrichten (${this.suppressedMessages.length})
</h4>
<button class="dnd-clear-btn text-xs text-slate-500 hover:text-slate-700 dark:text-slate-400 dark:hover:text-slate-200">
<button class="dnd-clear-btn text-xs text-slate-500 hover:text-slate-700 dark:text-slate-400 dark:hover:text-slate-200 transition-colors duration-200"
type="button">
Alle löschen
</button>
</div>
@ -1573,11 +1603,11 @@
<!-- Aktions-Buttons -->
<div class="flex space-x-3 pt-4">
${this.isActive ? `
<button class="dnd-disable-btn btn-secondary flex-1">
<button class="dnd-disable-btn btn-secondary flex-1" type="button">
Deaktivieren
</button>
` : ''}
<button class="dnd-close-btn btn-primary flex-1">
<button class="dnd-close-btn-main btn-primary flex-1" type="button">
Schließen
</button>
</div>
@ -1585,43 +1615,91 @@
</div>
`;
// Event Listeners
// Event Listeners mit Event Delegation
modal.addEventListener('click', (e) => {
if (e.target === modal || e.target.classList.contains('dnd-close-btn')) {
modal.remove();
e.stopPropagation();
// Schließen bei Klick auf Hintergrund
if (e.target === modal) {
this.closeModal(modal);
return;
}
// Schließen-Buttons
if (e.target.closest('.dnd-close-btn') || e.target.closest('.dnd-close-btn-main')) {
e.preventDefault();
this.closeModal(modal);
return;
}
// Schnell-Aktionen
if (e.target.classList.contains('dnd-quick-btn')) {
e.preventDefault();
const duration = parseInt(e.target.dataset.duration);
if (duration === 0) {
this.enable();
} else {
this.enable(duration);
}
modal.remove();
this.closeModal(modal);
return;
}
// Deaktivieren-Button
if (e.target.classList.contains('dnd-disable-btn')) {
e.preventDefault();
this.disable();
modal.remove();
this.closeModal(modal);
return;
}
// Alle löschen
if (e.target.classList.contains('dnd-clear-btn')) {
e.preventDefault();
this.clearSuppressedMessages();
modal.remove();
this.showSettings(); // Modal neu laden
this.closeModal(modal);
// Modal neu öffnen mit aktualisierten Daten
setTimeout(() => this.showSettings(), 100);
return;
}
// Einstellungen-Checkboxen
if (e.target.classList.contains('dnd-setting')) {
const setting = e.target.dataset.setting;
this.settings[setting] = e.target.checked;
this.saveSettings();
return;
}
});
// ESC-Taste zum Schließen
const escapeHandler = (e) => {
if (e.key === 'Escape') {
this.closeModal(modal);
document.removeEventListener('keydown', escapeHandler);
}
};
document.addEventListener('keydown', escapeHandler);
// Modal zum DOM hinzufügen
document.body.appendChild(modal);
}
/**
* Modal schließen
*/
closeModal(modal) {
if (modal && modal.parentNode) {
modal.style.opacity = '0';
modal.style.pointerEvents = 'none';
setTimeout(() => {
if (modal.parentNode) {
modal.parentNode.removeChild(modal);
}
}, 200);
}
}
/**
* Unterdrückte Nachrichten löschen
*/
@ -1851,6 +1929,23 @@
});
console.log('✅ MYP UI Components erfolgreich initialisiert - Erweiterte Benutzeroberfläche mit Glassmorphism und Do Not Disturb bereit');
// Test der glasigen Flash Messages (nur im Development)
if (window.location.hostname === 'localhost' || window.location.hostname === '127.0.0.1') {
// Warten auf vollständige Initialisierung, dann Test-Messages anzeigen
setTimeout(() => {
console.log('🧪 Teste glasige Flash Messages...');
showFlashMessage('Glassmorphism Flash Messages sind aktiv! ✨', 'success', 7000);
setTimeout(() => {
showFlashMessage('Do Not Disturb System ist bereit. Probieren Sie es im Footer aus! 🔕', 'info', 7000);
}, 1000);
setTimeout(() => {
showFlashMessage('Warnung: Dies ist eine Test-Nachricht für das glasige Design.', 'warning', 7000);
}, 2000);
}, 2000);
}
});
// Globale Variablen für erweiterte Flash Messages