🎨 style: update styles and layout in base templates and CSS files
This commit is contained in:
@@ -1018,5 +1018,232 @@ class MindMap {
|
||||
// Implementierung für das Erstellen von Verbindungen
|
||||
}
|
||||
|
||||
// ... existing code ...
|
||||
// Zeigt Gedanken für einen Knoten an
|
||||
showThoughtsForNode(node) {
|
||||
const nodeId = node.id().split('_')[1]; // "node_123" => "123"
|
||||
|
||||
// Wir verwenden die fetchThoughtsForNode-Methode, die wir bereits implementiert haben
|
||||
this.fetchThoughtsForNode(nodeId)
|
||||
.then(thoughts => {
|
||||
// Nur fortfahren, wenn wir tatsächlich Gedanken haben
|
||||
if (thoughts.length === 0) {
|
||||
this.showFlash('Keine Gedanken für diesen Knoten gefunden', 'info');
|
||||
return;
|
||||
}
|
||||
|
||||
// Erstelle einen Gedanken-Viewer, wenn er nicht existiert
|
||||
let thoughtsViewer = document.getElementById('thoughts-viewer');
|
||||
if (!thoughtsViewer) {
|
||||
thoughtsViewer = document.createElement('div');
|
||||
thoughtsViewer.id = 'thoughts-viewer';
|
||||
thoughtsViewer.className = 'fixed inset-0 flex items-center justify-center z-50';
|
||||
thoughtsViewer.innerHTML = `
|
||||
<div class="fixed inset-0 bg-black bg-opacity-50 thoughts-backdrop"></div>
|
||||
<div class="bg-slate-800 rounded-lg w-full max-w-3xl mx-4 relative z-10 border border-purple-500/20 thoughts-content overflow-hidden">
|
||||
<div class="flex justify-between items-center p-4 border-b border-gray-700">
|
||||
<h3 class="text-xl font-semibold text-white">Gedanken zu: <span class="node-name"></span></h3>
|
||||
<button id="close-thoughts" class="text-gray-400 hover:text-white">
|
||||
<i class="fas fa-times"></i>
|
||||
</button>
|
||||
</div>
|
||||
<div class="p-4 thoughts-container max-h-[70vh] overflow-y-auto"></div>
|
||||
</div>
|
||||
`;
|
||||
document.body.appendChild(thoughtsViewer);
|
||||
|
||||
// Event-Listener für Schließen-Button
|
||||
document.getElementById('close-thoughts').addEventListener('click', () => {
|
||||
// Animation für das Schließen
|
||||
const content = thoughtsViewer.querySelector('.thoughts-content');
|
||||
const backdrop = thoughtsViewer.querySelector('.thoughts-backdrop');
|
||||
|
||||
content.style.transform = 'scale(0.9)';
|
||||
content.style.opacity = '0';
|
||||
backdrop.style.opacity = '0';
|
||||
|
||||
setTimeout(() => thoughtsViewer.remove(), 300);
|
||||
});
|
||||
|
||||
// Event-Listener für Backdrop-Klick
|
||||
thoughtsViewer.querySelector('.thoughts-backdrop').addEventListener('click', () => {
|
||||
document.getElementById('close-thoughts').click();
|
||||
});
|
||||
}
|
||||
|
||||
// Aktualisiere den Titel mit dem Knotennamen
|
||||
thoughtsViewer.querySelector('.node-name').textContent = node.data('name');
|
||||
|
||||
// Container für die Gedanken
|
||||
const thoughtsContainer = thoughtsViewer.querySelector('.thoughts-container');
|
||||
thoughtsContainer.innerHTML = '';
|
||||
|
||||
// Gedanken rendern
|
||||
this.renderThoughts(thoughts, thoughtsContainer);
|
||||
|
||||
// Animation für das Öffnen
|
||||
const content = thoughtsViewer.querySelector('.thoughts-content');
|
||||
const backdrop = thoughtsViewer.querySelector('.thoughts-backdrop');
|
||||
|
||||
content.style.transform = 'scale(0.9)';
|
||||
content.style.opacity = '0';
|
||||
backdrop.style.opacity = '0';
|
||||
|
||||
setTimeout(() => {
|
||||
content.style.transition = 'all 0.3s ease';
|
||||
backdrop.style.transition = 'opacity 0.3s ease';
|
||||
content.style.transform = 'scale(1)';
|
||||
content.style.opacity = '1';
|
||||
backdrop.style.opacity = '1';
|
||||
}, 10);
|
||||
});
|
||||
}
|
||||
|
||||
// Rendert die Gedanken in der UI mit Animationen
|
||||
renderThoughts(thoughts, container) {
|
||||
if (!container) return;
|
||||
|
||||
container.innerHTML = '';
|
||||
|
||||
// Animation delay counter
|
||||
let delay = 0;
|
||||
|
||||
thoughts.forEach(thought => {
|
||||
const thoughtCard = document.createElement('div');
|
||||
thoughtCard.className = 'thought-card mb-4 bg-slate-700/50 rounded-lg overflow-hidden border border-slate-600/50 transition-all duration-300 hover:border-purple-500/30';
|
||||
thoughtCard.setAttribute('data-id', thought.id);
|
||||
thoughtCard.style.opacity = '0';
|
||||
thoughtCard.style.transform = 'translateY(20px)';
|
||||
|
||||
const cardColor = thought.color_code || this.colorPalette.default;
|
||||
|
||||
thoughtCard.innerHTML = `
|
||||
<div class="thought-card-header p-4" style="border-left: 4px solid ${cardColor}">
|
||||
<h3 class="thought-title text-lg font-semibold text-white">${thought.title}</h3>
|
||||
<div class="thought-meta flex gap-3 text-sm text-gray-400 mt-1">
|
||||
<span class="thought-date"><i class="far fa-calendar-alt mr-1"></i>${new Date(thought.created_at).toLocaleDateString('de-DE')}</span>
|
||||
${thought.author ? `<span class="thought-author"><i class="far fa-user mr-1"></i>${thought.author.username}</span>` : ''}
|
||||
</div>
|
||||
</div>
|
||||
<div class="thought-content p-4 text-gray-200">
|
||||
<p>${thought.abstract || thought.content.substring(0, 150) + '...'}</p>
|
||||
</div>
|
||||
<div class="thought-footer p-4 pt-0 flex justify-between items-center">
|
||||
<div class="thought-keywords flex flex-wrap gap-1">
|
||||
${thought.keywords ? thought.keywords.split(',').map(kw =>
|
||||
`<span class="keyword text-xs px-2 py-1 bg-purple-800/30 text-purple-200 rounded-full">${kw.trim()}</span>`).join('') : ''}
|
||||
</div>
|
||||
<a href="/thoughts/${thought.id}" class="thought-link text-purple-400 hover:text-purple-300 text-sm flex items-center">
|
||||
Mehr lesen <i class="fas fa-arrow-right ml-1"></i>
|
||||
</a>
|
||||
</div>
|
||||
`;
|
||||
|
||||
// Animation-Effekt mit Verzögerung für jede Karte
|
||||
setTimeout(() => {
|
||||
thoughtCard.style.transition = 'all 0.5s ease';
|
||||
thoughtCard.style.opacity = '1';
|
||||
thoughtCard.style.transform = 'translateY(0)';
|
||||
}, delay);
|
||||
delay += 100; // Jede Karte erscheint mit 100ms Verzögerung
|
||||
|
||||
// Event-Listener für Klick auf Gedanken
|
||||
thoughtCard.addEventListener('click', (e) => {
|
||||
// Verhindern, dass der Link-Klick den Kartenklick auslöst
|
||||
if (e.target.tagName === 'A' || e.target.closest('a')) return;
|
||||
window.location.href = `/thoughts/${thought.id}`;
|
||||
});
|
||||
|
||||
// Hover-Animation für Karten
|
||||
thoughtCard.addEventListener('mouseenter', () => {
|
||||
thoughtCard.style.transform = 'translateY(-5px)';
|
||||
thoughtCard.style.boxShadow = '0 10px 25px rgba(0, 0, 0, 0.2)';
|
||||
});
|
||||
|
||||
thoughtCard.addEventListener('mouseleave', () => {
|
||||
thoughtCard.style.transform = 'translateY(0)';
|
||||
thoughtCard.style.boxShadow = 'none';
|
||||
});
|
||||
|
||||
container.appendChild(thoughtCard);
|
||||
});
|
||||
}
|
||||
|
||||
// Flash-Nachrichten mit Animationen
|
||||
showFlash(message, type = 'info') {
|
||||
if (!this.flashContainer) {
|
||||
this.flashContainer = document.createElement('div');
|
||||
this.flashContainer.className = 'fixed top-4 right-4 z-50 flex flex-col gap-2';
|
||||
document.body.appendChild(this.flashContainer);
|
||||
}
|
||||
|
||||
const flash = document.createElement('div');
|
||||
flash.className = `flash-message p-3 rounded-lg shadow-lg flex items-center gap-3 max-w-xs text-white`;
|
||||
|
||||
// Verschiedene Stile je nach Typ
|
||||
let backgroundColor, icon;
|
||||
switch (type) {
|
||||
case 'success':
|
||||
backgroundColor = 'bg-green-500';
|
||||
icon = 'fa-check-circle';
|
||||
break;
|
||||
case 'error':
|
||||
backgroundColor = 'bg-red-500';
|
||||
icon = 'fa-exclamation-circle';
|
||||
break;
|
||||
case 'warning':
|
||||
backgroundColor = 'bg-yellow-500';
|
||||
icon = 'fa-exclamation-triangle';
|
||||
break;
|
||||
default:
|
||||
backgroundColor = 'bg-blue-500';
|
||||
icon = 'fa-info-circle';
|
||||
}
|
||||
|
||||
flash.classList.add(backgroundColor);
|
||||
|
||||
flash.innerHTML = `
|
||||
<div class="flash-icon"><i class="fas ${icon} text-lg"></i></div>
|
||||
<div class="flash-text">${message}</div>
|
||||
<button class="flash-close ml-auto text-white/80 hover:text-white"><i class="fas fa-times"></i></button>
|
||||
`;
|
||||
|
||||
// Füge den Flash zum Container hinzu
|
||||
this.flashContainer.appendChild(flash);
|
||||
|
||||
// Einblend-Animation
|
||||
flash.style.opacity = '0';
|
||||
flash.style.transform = 'translateX(20px)';
|
||||
|
||||
setTimeout(() => {
|
||||
flash.style.transition = 'all 0.3s ease';
|
||||
flash.style.opacity = '1';
|
||||
flash.style.transform = 'translateX(0)';
|
||||
}, 10);
|
||||
|
||||
// Schließen-Button
|
||||
const closeBtn = flash.querySelector('.flash-close');
|
||||
closeBtn.addEventListener('click', () => {
|
||||
// Ausblend-Animation
|
||||
flash.style.opacity = '0';
|
||||
flash.style.transform = 'translateX(20px)';
|
||||
|
||||
setTimeout(() => {
|
||||
flash.remove();
|
||||
}, 300);
|
||||
});
|
||||
|
||||
// Automatisches Ausblenden nach 5 Sekunden
|
||||
setTimeout(() => {
|
||||
if (flash.parentNode) {
|
||||
flash.style.opacity = '0';
|
||||
flash.style.transform = 'translateX(20px)';
|
||||
|
||||
setTimeout(() => {
|
||||
if (flash.parentNode) flash.remove();
|
||||
}, 300);
|
||||
}
|
||||
}, 5000);
|
||||
|
||||
return flash;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user