"Refactor database schema for user profiles and profile templates updated to remove obsolete db table 'systades (feat): systades.db) system data)"
This commit is contained in:
@@ -241,6 +241,78 @@
|
|||||||
background: linear-gradient(135deg, #8b5cf6, #6366f1);
|
background: linear-gradient(135deg, #8b5cf6, #6366f1);
|
||||||
box-shadow: 0 4px 12px rgba(79, 70, 229, 0.3);
|
box-shadow: 0 4px 12px rgba(79, 70, 229, 0.3);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Style improvements for the theme toggle button */
|
||||||
|
.theme-toggle {
|
||||||
|
position: relative;
|
||||||
|
width: 48px;
|
||||||
|
height: 24px;
|
||||||
|
border-radius: 24px;
|
||||||
|
padding: 2px;
|
||||||
|
cursor: pointer;
|
||||||
|
transition: all 0.3s ease;
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
body.dark .theme-toggle {
|
||||||
|
background: linear-gradient(to right, #7c3aed, #3b82f6);
|
||||||
|
box-shadow: inset 0 2px 4px rgba(0, 0, 0, 0.3), 0 0 10px rgba(124, 58, 237, 0.3);
|
||||||
|
border: 1px solid rgba(255, 255, 255, 0.1);
|
||||||
|
}
|
||||||
|
|
||||||
|
body:not(.dark) .theme-toggle {
|
||||||
|
background: linear-gradient(to right, #8b5cf6, #60a5fa);
|
||||||
|
box-shadow: inset 0 2px 4px rgba(0, 0, 0, 0.1), 0 0 10px rgba(124, 58, 237, 0.15);
|
||||||
|
border: 1px solid rgba(0, 0, 0, 0.05);
|
||||||
|
}
|
||||||
|
|
||||||
|
.theme-toggle::after {
|
||||||
|
content: '';
|
||||||
|
position: absolute;
|
||||||
|
width: 20px;
|
||||||
|
height: 20px;
|
||||||
|
border-radius: 50%;
|
||||||
|
top: 2px;
|
||||||
|
transition: all 0.3s ease;
|
||||||
|
z-index: 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
body.dark .theme-toggle::after {
|
||||||
|
background: #f1f5f9 url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='%237c3aed' width='14' height='14'%3E%3Cpath d='M21.752 15.002A9.718 9.718 0 0118 15.75c-5.385 0-9.75-4.365-9.75-9.75 0-1.33.266-2.597.748-3.752A9.753 9.753 0 003 11.25C3 16.635 7.365 21 12.75 21a9.753 9.753 0 009.002-5.998z'%3E%3C/path%3E%3C/svg%3E") no-repeat center center;
|
||||||
|
transform: translateX(24px);
|
||||||
|
box-shadow: 0 0 5px rgba(0, 0, 0, 0.2);
|
||||||
|
}
|
||||||
|
|
||||||
|
body:not(.dark) .theme-toggle::after {
|
||||||
|
background: #fff url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='%23f59e0b' width='14' height='14'%3E%3Cpath d='M12 2.25a.75.75 0 01.75.75v2.25a.75.75 0 01-1.5 0V3a.75.75 0 01.75-.75zM7.5 12a4.5 4.5 0 119 0 4.5 4.5 0 01-9 0zM18.894 6.166a.75.75 0 00-1.06-1.06l-1.591 1.59a.75.75 0 101.06 1.061l1.591-1.59zM21.75 12a.75.75 0 01-.75.75h-2.25a.75.75 0 010-1.5H21a.75.75 0 01.75.75zM17.834 18.894a.75.75 0 001.06-1.06l-1.59-1.591a.75.75 0 10-1.061 1.06l1.59 1.591zM12 18a.75.75 0 01.75.75V21a.75.75 0 01-1.5 0v-2.25A.75.75 0 0112 18zM7.758 17.303a.75.75 0 00-1.061-1.06l-1.591 1.59a.75.75 0 001.06 1.061l1.591-1.59zM6 12a.75.75 0 01-.75.75H3a.75.75 0 010-1.5h2.25A.75.75 0 016 12zM6.697 7.757a.75.75 0 001.06-1.06l-1.59-1.591a.75.75 0 00-1.061 1.06l1.59 1.591z'%3E%3C/path%3E%3C/svg%3E") no-repeat center center;
|
||||||
|
transform: translateX(2px);
|
||||||
|
box-shadow: 0 0 8px rgba(124, 58, 237, 0.2);
|
||||||
|
}
|
||||||
|
|
||||||
|
.theme-toggle:hover::after {
|
||||||
|
box-shadow: 0 0 12px rgba(124, 58, 237, 0.4);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Fixes for light mode button text colors */
|
||||||
|
body:not(.dark) .btn-primary {
|
||||||
|
color: white !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Fix for KI-Chat container */
|
||||||
|
#chatgpt-assistant {
|
||||||
|
position: fixed;
|
||||||
|
bottom: 1.5rem;
|
||||||
|
right: 1.5rem;
|
||||||
|
z-index: 100;
|
||||||
|
}
|
||||||
|
|
||||||
|
.chat-assistant {
|
||||||
|
max-height: 80vh !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.chat-assistant .chat-messages {
|
||||||
|
max-height: calc(80vh - 160px) !important;
|
||||||
|
}
|
||||||
</style>
|
</style>
|
||||||
</head>
|
</head>
|
||||||
<body data-page="{{ request.endpoint }}" class="relative overflow-x-hidden dark bg-gray-900 text-white" x-data="{
|
<body data-page="{{ request.endpoint }}" class="relative overflow-x-hidden dark bg-gray-900 text-white" x-data="{
|
||||||
@@ -369,14 +441,9 @@
|
|||||||
<!-- Dark/Light Mode Schalter -->
|
<!-- Dark/Light Mode Schalter -->
|
||||||
<button
|
<button
|
||||||
@click="toggleDarkMode()"
|
@click="toggleDarkMode()"
|
||||||
class="theme-toggle relative w-12 h-6 rounded-full bg-gradient-to-r transition-all duration-300 flex items-center"
|
class="theme-toggle relative w-12 h-6 rounded-full transition-all duration-300 flex items-center overflow-hidden"
|
||||||
:class="darkMode ? 'from-purple-700 to-indigo-800' : 'from-purple-400 to-indigo-500'"
|
|
||||||
aria-label="Dark Mode umschalten"
|
aria-label="Dark Mode umschalten"
|
||||||
>
|
>
|
||||||
<span
|
|
||||||
class="absolute w-5 h-5 rounded-full bg-white shadow-md transform transition-transform duration-300"
|
|
||||||
:class="darkMode ? 'translate-x-7' : 'translate-x-1'"
|
|
||||||
></span>
|
|
||||||
<span class="sr-only" x-text="darkMode ? 'Zum Light Mode wechseln' : 'Zum Dark Mode wechseln'"></span>
|
<span class="sr-only" x-text="darkMode ? 'Zum Light Mode wechseln' : 'Zum Dark Mode wechseln'"></span>
|
||||||
</button>
|
</button>
|
||||||
<!-- Profil-Link oder Login -->
|
<!-- Profil-Link oder Login -->
|
||||||
@@ -703,6 +770,11 @@
|
|||||||
if (appEl && appEl.__x) {
|
if (appEl && appEl.__x) {
|
||||||
appEl.__x.$data.darkMode = isDarkMode;
|
appEl.__x.$data.darkMode = isDarkMode;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Event für andere Komponenten auslösen
|
||||||
|
document.dispatchEvent(new CustomEvent('darkModeToggled', {
|
||||||
|
detail: { isDark: isDarkMode }
|
||||||
|
}));
|
||||||
}
|
}
|
||||||
|
|
||||||
window.MindMap.toggleDarkMode = function() {
|
window.MindMap.toggleDarkMode = function() {
|
||||||
@@ -712,27 +784,12 @@
|
|||||||
// DOM aktualisieren
|
// DOM aktualisieren
|
||||||
applyDarkModeClasses(newIsDark);
|
applyDarkModeClasses(newIsDark);
|
||||||
|
|
||||||
// Alpine.js Status aktualisieren (falls verfügbar)
|
|
||||||
const appEl = document.querySelector('body');
|
|
||||||
if (appEl && appEl.__x) {
|
|
||||||
appEl.__x.$data.darkMode = newIsDark;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Server aktualisieren
|
// Server aktualisieren
|
||||||
fetch('/api/set_dark_mode', {
|
fetch('/api/set_dark_mode', {
|
||||||
method: 'POST',
|
method: 'POST',
|
||||||
headers: { 'Content-Type': 'application/json' },
|
headers: { 'Content-Type': 'application/json' },
|
||||||
body: JSON.stringify({ darkMode: newIsDark })
|
body: JSON.stringify({ darkMode: newIsDark })
|
||||||
})
|
})
|
||||||
.then(response => response.json())
|
|
||||||
.then(data => {
|
|
||||||
if (data.success) {
|
|
||||||
// Event für andere Komponenten auslösen
|
|
||||||
document.dispatchEvent(new CustomEvent('darkModeToggled', {
|
|
||||||
detail: { isDark: newIsDark }
|
|
||||||
}));
|
|
||||||
}
|
|
||||||
})
|
|
||||||
.catch(console.error);
|
.catch(console.error);
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -754,8 +811,10 @@
|
|||||||
fetch('/api/get_dark_mode')
|
fetch('/api/get_dark_mode')
|
||||||
.then(response => response.json())
|
.then(response => response.json())
|
||||||
.then(data => {
|
.then(data => {
|
||||||
|
if (data.success) {
|
||||||
const serverDarkMode = data.darkMode === true || data.darkMode === 'true';
|
const serverDarkMode = data.darkMode === true || data.darkMode === 'true';
|
||||||
applyDarkModeClasses(serverDarkMode);
|
applyDarkModeClasses(serverDarkMode);
|
||||||
|
}
|
||||||
})
|
})
|
||||||
.catch(error => console.error('Fehler beim Abrufen des Dark Mode Status:', error));
|
.catch(error => console.error('Fehler beim Abrufen des Dark Mode Status:', error));
|
||||||
|
|
||||||
|
|||||||
@@ -985,52 +985,173 @@
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
// Einstellungen-Formular-Handling
|
// Avatar-Bearbeitung
|
||||||
const settingsForm = document.querySelector('.settings-card form');
|
const avatarEditBtn = document.querySelector('.avatar-edit');
|
||||||
const saveSettingsBtn = document.querySelector('.settings-card .profile-action-btn.primary');
|
if (avatarEditBtn) {
|
||||||
|
avatarEditBtn.addEventListener('click', function() {
|
||||||
|
// Dateiauwahl öffnen
|
||||||
|
const fileInput = document.createElement('input');
|
||||||
|
fileInput.type = 'file';
|
||||||
|
fileInput.accept = 'image/*';
|
||||||
|
fileInput.style.display = 'none';
|
||||||
|
document.body.appendChild(fileInput);
|
||||||
|
|
||||||
if (saveSettingsBtn && !settingsForm) {
|
fileInput.click();
|
||||||
saveSettingsBtn.addEventListener('click', function() {
|
|
||||||
// Sammle Daten aus den Eingabefeldern
|
|
||||||
const formData = new FormData();
|
|
||||||
formData.append('action', 'update_profile');
|
|
||||||
formData.append('bio', document.getElementById('bio').value);
|
|
||||||
formData.append('location', document.getElementById('location').value);
|
|
||||||
formData.append('website', document.getElementById('website').value || '');
|
|
||||||
|
|
||||||
// AJAX-Anfrage senden
|
fileInput.addEventListener('change', function() {
|
||||||
fetch('{{ url_for("settings") }}', {
|
if (this.files && this.files[0]) {
|
||||||
method: 'POST',
|
// Anzeigen des gewählten Bildes
|
||||||
body: formData,
|
const avatarImg = document.querySelector('.avatar');
|
||||||
credentials: 'same-origin'
|
|
||||||
})
|
|
||||||
.then(response => response.json())
|
|
||||||
.catch(error => {
|
|
||||||
console.error('Fehler beim Speichern der Profileinstellungen:', error);
|
|
||||||
})
|
|
||||||
.then(data => {
|
|
||||||
// Erfolgsanimation
|
|
||||||
const originalText = this.innerHTML;
|
|
||||||
this.innerHTML = '<i class="fas fa-check mr-1"></i> Gespeichert';
|
|
||||||
|
|
||||||
setTimeout(() => {
|
// FileReader zum Einlesen des Bildes
|
||||||
this.innerHTML = originalText;
|
const reader = new FileReader();
|
||||||
}, 2000);
|
reader.onload = function(e) {
|
||||||
|
// Vorschau anzeigen
|
||||||
|
avatarImg.src = e.target.result;
|
||||||
|
|
||||||
|
// Avatar-URL im Einstellungsbereich speichern
|
||||||
|
const avatarUrlInput = document.createElement('input');
|
||||||
|
avatarUrlInput.type = 'hidden';
|
||||||
|
avatarUrlInput.name = 'avatar_url';
|
||||||
|
avatarUrlInput.id = 'avatar_url';
|
||||||
|
avatarUrlInput.value = e.target.result;
|
||||||
|
|
||||||
|
// Entferne vorhandenes Input, falls vorhanden
|
||||||
|
const existingInput = document.getElementById('avatar_url');
|
||||||
|
if (existingInput) {
|
||||||
|
existingInput.remove();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Zum Formular hinzufügen
|
||||||
|
const settingsForm = document.querySelector('.settings-card');
|
||||||
|
if (settingsForm) {
|
||||||
|
settingsForm.appendChild(avatarUrlInput);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Erfolgsmeldung anzeigen
|
||||||
|
showNotification('Avatar wurde aktualisiert! Bitte speichere deine Änderungen.', 'success');
|
||||||
|
};
|
||||||
|
|
||||||
|
reader.readAsDataURL(this.files[0]);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Input entfernen
|
||||||
|
document.body.removeChild(fileInput);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
// Mindmap-Karten mit Hover-Effekten
|
// Einstellungen-Formular-Handling
|
||||||
const mindmapItems = document.querySelectorAll('.mindmap-item');
|
const saveSettingsBtn = document.querySelectorAll('.settings-card .profile-action-btn.primary');
|
||||||
mindmapItems.forEach(item => {
|
|
||||||
item.addEventListener('mouseenter', () => {
|
|
||||||
item.style.transform = 'translateY(-5px)';
|
|
||||||
item.style.boxShadow = '0 12px 30px rgba(0, 0, 0, 0.15)';
|
|
||||||
});
|
|
||||||
|
|
||||||
item.addEventListener('mouseleave', () => {
|
saveSettingsBtn.forEach(btn => {
|
||||||
item.style.transform = 'translateY(0)';
|
btn.addEventListener('click', function() {
|
||||||
item.style.boxShadow = 'none';
|
const isPasswordUpdate = this.textContent.includes('Passwort');
|
||||||
|
|
||||||
|
// Passwort-Update
|
||||||
|
if (isPasswordUpdate) {
|
||||||
|
const currentPassword = document.getElementById('password').value;
|
||||||
|
const newPassword = document.getElementById('password_confirm').value;
|
||||||
|
|
||||||
|
if (!currentPassword || !newPassword) {
|
||||||
|
showNotification('Bitte fülle alle Passwortfelder aus', 'error');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// AJAX-Anfrage senden
|
||||||
|
const formData = new FormData();
|
||||||
|
formData.append('action', 'update_password');
|
||||||
|
formData.append('current_password', currentPassword);
|
||||||
|
formData.append('new_password', newPassword);
|
||||||
|
formData.append('confirm_password', newPassword);
|
||||||
|
|
||||||
|
// Visuelle Rückmeldung
|
||||||
|
const originalText = this.innerHTML;
|
||||||
|
this.innerHTML = '<i class="fas fa-circle-notch fa-spin mr-1"></i> Speichern...';
|
||||||
|
this.disabled = true;
|
||||||
|
|
||||||
|
fetch('{{ url_for("settings") }}', {
|
||||||
|
method: 'POST',
|
||||||
|
body: formData
|
||||||
|
})
|
||||||
|
.then(response => response.json())
|
||||||
|
.catch(error => {
|
||||||
|
console.error('Fehler beim Aktualisieren des Passworts:', error);
|
||||||
|
return { success: false, message: 'Netzwerkfehler. Bitte versuche es erneut.' };
|
||||||
|
})
|
||||||
|
.then(data => {
|
||||||
|
this.innerHTML = originalText;
|
||||||
|
this.disabled = false;
|
||||||
|
|
||||||
|
if (data && data.success) {
|
||||||
|
showNotification('Passwort erfolgreich aktualisiert!', 'success');
|
||||||
|
document.getElementById('password').value = '';
|
||||||
|
document.getElementById('password_confirm').value = '';
|
||||||
|
} else {
|
||||||
|
showNotification(data?.message || 'Fehler beim Aktualisieren des Passworts', 'error');
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
// Profil-Update
|
||||||
|
else {
|
||||||
|
// Sammle Daten aus den Eingabefeldern
|
||||||
|
const formData = new FormData();
|
||||||
|
formData.append('action', 'update_profile');
|
||||||
|
formData.append('bio', document.getElementById('bio').value || '');
|
||||||
|
formData.append('location', document.getElementById('location').value || '');
|
||||||
|
formData.append('website', document.getElementById('website').value || '');
|
||||||
|
|
||||||
|
// Avatar hinzufügen, falls vorhanden
|
||||||
|
const avatarUrlInput = document.getElementById('avatar_url');
|
||||||
|
if (avatarUrlInput) {
|
||||||
|
formData.append('avatar_url', avatarUrlInput.value);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Visuelle Rückmeldung
|
||||||
|
const originalText = this.innerHTML;
|
||||||
|
this.innerHTML = '<i class="fas fa-circle-notch fa-spin mr-1"></i> Speichern...';
|
||||||
|
this.disabled = true;
|
||||||
|
|
||||||
|
// AJAX-Anfrage senden
|
||||||
|
fetch('{{ url_for("settings") }}', {
|
||||||
|
method: 'POST',
|
||||||
|
body: formData
|
||||||
|
})
|
||||||
|
.then(response => {
|
||||||
|
if (!response.ok) {
|
||||||
|
throw new Error('Fehler beim Speichern');
|
||||||
|
}
|
||||||
|
return response.json();
|
||||||
|
})
|
||||||
|
.catch(error => {
|
||||||
|
console.error('Fehler beim Speichern der Profileinstellungen:', error);
|
||||||
|
return { success: false, message: 'Netzwerkfehler. Bitte versuche es erneut.' };
|
||||||
|
})
|
||||||
|
.then(data => {
|
||||||
|
this.innerHTML = originalText;
|
||||||
|
this.disabled = false;
|
||||||
|
|
||||||
|
if (data && data.success) {
|
||||||
|
// Erfolgsanimation
|
||||||
|
showNotification('Profil erfolgreich aktualisiert!', 'success');
|
||||||
|
|
||||||
|
// UI aktualisieren ohne Neuladen
|
||||||
|
const bioElement = document.querySelector('.user-bio');
|
||||||
|
const locationElement = document.querySelector('.user-meta span:first-child');
|
||||||
|
|
||||||
|
if (bioElement) {
|
||||||
|
bioElement.textContent = document.getElementById('bio').value || 'Keine Bio vorhanden. Klicke auf bearbeiten, um eine hinzuzufügen.';
|
||||||
|
}
|
||||||
|
|
||||||
|
if (locationElement) {
|
||||||
|
const location = document.getElementById('location').value;
|
||||||
|
locationElement.innerHTML = `<i class="fas fa-map-marker-alt"></i> ${location || 'Kein Standort angegeben'}`;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
showNotification(data?.message || 'Fehler beim Aktualisieren des Profils', 'error');
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -1054,6 +1175,76 @@
|
|||||||
borderElem.style.borderLeftColor = borderElem.dataset.color;
|
borderElem.style.borderLeftColor = borderElem.dataset.color;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// Mindmap-Karten mit Hover-Effekten
|
||||||
|
const mindmapItems = document.querySelectorAll('.mindmap-item');
|
||||||
|
mindmapItems.forEach(item => {
|
||||||
|
item.addEventListener('mouseenter', () => {
|
||||||
|
item.style.transform = 'translateY(-5px)';
|
||||||
|
item.style.boxShadow = '0 12px 30px rgba(0, 0, 0, 0.15)';
|
||||||
|
});
|
||||||
|
|
||||||
|
item.addEventListener('mouseleave', () => {
|
||||||
|
item.style.transform = 'translateY(0)';
|
||||||
|
item.style.boxShadow = 'none';
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
// Benachrichtigungsfunktion
|
||||||
|
function showNotification(message, type = 'info') {
|
||||||
|
// Bestehende Benachrichtigung entfernen
|
||||||
|
const existingNotification = document.getElementById('notification');
|
||||||
|
if (existingNotification) {
|
||||||
|
existingNotification.remove();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Neue Benachrichtigung erstellen
|
||||||
|
const notification = document.createElement('div');
|
||||||
|
notification.id = 'notification';
|
||||||
|
notification.className = `fixed top-4 right-4 p-4 rounded-lg shadow-lg z-50 flex items-center transform transition-all duration-300 translate-y-0 opacity-0`;
|
||||||
|
|
||||||
|
// Typ-basierte Stile
|
||||||
|
if (type === 'success') {
|
||||||
|
notification.classList.add('bg-green-500', 'text-white');
|
||||||
|
notification.innerHTML = `<i class="fas fa-check-circle mr-2"></i> ${message}`;
|
||||||
|
} else if (type === 'error') {
|
||||||
|
notification.classList.add('bg-red-500', 'text-white');
|
||||||
|
notification.innerHTML = `<i class="fas fa-exclamation-circle mr-2"></i> ${message}`;
|
||||||
|
} else {
|
||||||
|
notification.classList.add('bg-blue-500', 'text-white');
|
||||||
|
notification.innerHTML = `<i class="fas fa-info-circle mr-2"></i> ${message}`;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Close-Button
|
||||||
|
const closeBtn = document.createElement('button');
|
||||||
|
closeBtn.className = 'ml-4 text-white opacity-75 hover:opacity-100';
|
||||||
|
closeBtn.innerHTML = '<i class="fas fa-times"></i>';
|
||||||
|
closeBtn.addEventListener('click', () => {
|
||||||
|
notification.classList.add('opacity-0', 'translate-y-[-10px]');
|
||||||
|
setTimeout(() => notification.remove(), 300);
|
||||||
|
});
|
||||||
|
|
||||||
|
notification.appendChild(closeBtn);
|
||||||
|
document.body.appendChild(notification);
|
||||||
|
|
||||||
|
// Animation starten
|
||||||
|
setTimeout(() => {
|
||||||
|
notification.classList.remove('opacity-0');
|
||||||
|
notification.classList.add('opacity-100');
|
||||||
|
}, 10);
|
||||||
|
|
||||||
|
// Automatisch ausblenden nach 5 Sekunden
|
||||||
|
setTimeout(() => {
|
||||||
|
if (document.body.contains(notification)) {
|
||||||
|
notification.classList.add('opacity-0', 'translate-y-[-10px]');
|
||||||
|
setTimeout(() => {
|
||||||
|
if (document.body.contains(notification)) {
|
||||||
|
notification.remove();
|
||||||
|
}
|
||||||
|
}, 300);
|
||||||
|
}
|
||||||
|
}, 5000);
|
||||||
|
}
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
Reference in New Issue
Block a user