/** * Update Mindmap * Dieses Skript fügt Knoten zur Mindmap hinzu und stellt sicher, * dass sie im neuronalen Netzwerk-Design angezeigt werden. * Implementiert Lazy Loading & Progressive Disclosure */ // Neue zentrale Konfiguration const mindmapConfig = { categories: { 'Philosophie': { icon: 'fa-solid fa-lightbulb', color: '#b71c1c', description: 'Die Lehre vom Denken und der Erkenntnis' }, 'Wissenschaft': { icon: 'fa-solid fa-atom', color: '#f4b400', description: 'Systematische Erforschung der Natur und Gesellschaft' }, 'Technologie': { icon: 'fa-solid fa-microchip', color: '#0d47a1', description: 'Anwendung wissenschaftlicher Erkenntnisse' }, 'Künste': { icon: 'fa-solid fa-palette', color: '#c2185b', description: 'Kreativer Ausdruck und künstlerische Gestaltung' } }, defaultNodeStyle: { fontSize: 18, fontColor: '#fff', neuronSize: 8, neuronActivity: 0.8 }, centerNodeStyle: { fontSize: 22, fontColor: '#222', neuronSize: 12, neuronActivity: 1.0, color: '#f5f5f5', icon: 'fa-solid fa-circle' } }; // Zentrale Styling-Konfiguration const mindmapStyles = { node: { base: { 'background-color': 'data(color)', 'label': 'data(label)', 'color': '#ffffff', 'text-background-color': 'rgba(0, 0, 0, 0.7)', 'text-background-opacity': 0.8, 'text-background-padding': '4px', 'text-valign': 'center', 'text-halign': 'center', 'font-size': 16, 'width': 'mapData(neuronSize, 3, 10, 30, 60)', 'height': 'mapData(neuronSize, 3, 10, 30, 60)', 'border-width': 2, 'border-color': '#ffffff', 'border-opacity': 0.8, 'shape': 'ellipse', 'background-opacity': 0.85 }, center: { 'background-color': '#f5f5f5', 'color': '#222', 'font-size': 20, 'border-width': 3, 'width': 100, 'height': 100 }, selected: { 'border-color': '#f59e42', 'border-width': 3, 'background-opacity': 1 } }, edge: { base: { 'width': function(ele) { return ele.data('strength') ? ele.data('strength') * 2 : 1; }, 'line-color': function(ele) { const sourceColor = ele.source().data('color'); return sourceColor || '#8a8aaa'; }, 'line-opacity': function(ele) { return ele.data('strength') ? ele.data('strength') * 0.6 : 0.4; }, 'curve-style': 'bezier', 'target-arrow-shape': 'none', 'control-point-distances': [30, -30], 'control-point-weights': [0.5, 0.5] } }, layout: { base: { name: 'cose', animate: true, animationDuration: 500, refresh: 20, fit: true, padding: 30, nodeRepulsion: 4500, idealEdgeLength: 50, edgeElasticity: 0.45, randomize: true, componentSpacing: 100, nodeOverlap: 20, gravity: 0.25, initialTemp: 1000, coolingFactor: 0.95, minTemp: 1 } } }; // Globale Variable für die Mindmap-Daten let mindmapData = null; // Funktion zum Laden der Mindmap-Daten aus der Datenbank async function loadMindmapData(nodeId = null) { try { const apiUrl = nodeId ? `/api/mindmap/${nodeId}` : '/api/mindmap/root'; console.log('Lade Mindmap-Daten von:', apiUrl); const response = await fetch(apiUrl); console.log('API-Antwort Status:', response.status); if (!response.ok) { let errorData; try { errorData = await response.json(); console.log('API-Fehler Details:', { status: response.status, statusText: response.statusText, errorData }); } catch (e) { console.error('Fehler beim Parsen der Fehlerantwort:', e); errorData = { error: `HTTP-Fehler ${response.status}: ${response.statusText}` }; } // Fehlerobjekt für die Benachrichtigung erstellen const errorMessage = { error: errorData.error || errorData.message || 'Unbekannter Fehler', details: errorData.details || null }; showUINotification(errorMessage, 'error'); throw new Error(errorMessage.error); } const data = await response.json(); console.log('Geladene Mindmap-Daten:', data); if (!data.success) { const errorMessage = { error: data.error || 'Mindmap-Daten konnten nicht geladen werden', details: data.details || null }; showUINotification(errorMessage, 'error'); throw new Error(errorMessage.error); } // Erfolgreiche Antwort mindmapData = data; // Speichere die Daten in der globalen Variable showUINotification('Mindmap-Daten erfolgreich geladen', 'success'); return data; } catch (error) { console.error('Fehler beim Laden der Mindmap-Daten:', { message: error.message, stack: error.stack, nodeId }); // Stelle sicher, dass wir eine aussagekräftige Fehlermeldung haben const errorMessage = { error: error.message || 'Unbekannter Fehler beim Laden der Mindmap-Daten', details: error.stack }; showUINotification(errorMessage, 'error'); throw error; } } // Funktion zum Initialisieren der Mindmap async function initializeMindmap() { try { const data = await loadMindmapData(); if (!data || !data.nodes || !data.edges) { throw new Error('Ungültiges Datenformat: Mindmap-Daten fehlen oder sind unvollständig'); } const elements = [ // Knoten ...data.nodes.map(node => ({ data: { id: node.id, label: node.name, category: node.category, description: node.description, hasChildren: node.has_children, expanded: false, color: node.color_code, fontColor: '#ffffff', fontSize: node.is_center ? 20 : 16 } })), // Kanten ...data.edges.map(edge => ({ data: { source: edge.source, target: edge.target, strength: edge.strength || 0.5 } })) ]; // Bestehende Cytoscape-Instanz entfernen, falls vorhanden if (window.cy) { window.cy.destroy(); } window.cy = cytoscape({ container: document.getElementById('cy'), elements: elements, style: mindmapStyles, layout: mindmapStyles.layout.base }); // Event-Listener für Knoten-Klicks cy.on('tap', 'node', async function(evt) { const node = evt.target; if (node.data('hasChildren') && !node.data('expanded')) { await loadSubthemes(node); } }); // Layout ausführen cy.layout(mindmapStyles.layout.base).run(); return true; } catch (error) { console.error('Fehler bei der Mindmap-Initialisierung:', error); showUINotification({ error: 'Mindmap konnte nicht initialisiert werden', details: error.message }, 'error'); return false; } } // Warte bis DOM geladen ist document.addEventListener('DOMContentLoaded', function() { console.log('DOMContentLoaded Event ausgelöst'); // Prüfe, ob der Container existiert const cyContainer = document.getElementById('cy'); console.log('Container gefunden:', cyContainer); if (!cyContainer) { console.error('Mindmap-Container #cy nicht gefunden!'); return; } // Prüfe, ob Cytoscape verfügbar ist if (typeof cytoscape === 'undefined') { console.error('Cytoscape ist nicht definiert!'); return; } console.log('Cytoscape ist verfügbar'); // Beispiel-Daten entfernt, stattdessen große Mindmap-Daten verwenden const elements = [ // Knoten ...mindmapData.nodes.map(node => ({ data: { id: node.id, label: node.label, category: node.category, description: node.description, hasChildren: node.hasChildren, expanded: node.expanded, neuronSize: node.neuronSize, neuronActivity: node.neuronActivity, color: node.color, icon: node.icon, fontColor: node.fontColor, fontSize: node.fontSize } })), // Kanten ...mindmapData.edges.map(edge => ({ data: { source: edge.source, target: edge.target, label: edge.label, strength: edge.strength } })) ]; console.log('Initialisiere Cytoscape...'); // Initialisiere Cytoscape mit einem schlichten, modernen Design window.cy = cytoscape({ container: cyContainer, elements: elements, style: [ { selector: 'node', style: mindmapStyles.node.base }, { selector: 'node[isCenter]', style: mindmapStyles.node.center }, { selector: 'node:selected', style: mindmapStyles.node.selected }, { selector: 'edge', style: mindmapStyles.edge.base } ], layout: mindmapStyles.layout.base }); console.log('Cytoscape initialisiert'); // Füge neuronale Eigenschaften zu allen Knoten hinzu cy.nodes().forEach(node => { const data = node.data(); node.data({ ...data, neuronSize: data.neuronSize || 8, neuronActivity: data.neuronActivity || 0.8, refractionPeriod: Math.random() * 300 + 700, threshold: Math.random() * 0.3 + 0.6, lastFired: 0, color: categoryColors[data.category] || '#60a5fa' }); }); // Füge synaptische Eigenschaften zu allen Kanten hinzu cy.edges().forEach(edge => { const data = edge.data(); edge.data({ ...data, strength: data.strength || 0.5, conductionVelocity: Math.random() * 0.5 + 0.3, latency: Math.random() * 100 + 50 }); }); // Starte neuronale Aktivitätssimulation startNeuralActivitySimulation(cy); // Mindmap mit echten Daten befüllen (Styles, Farben etc.) updateMindmap(); // Event auslösen, damit andere Scripte reagieren können document.dispatchEvent(new Event('mindmap-loaded')); console.log('mindmap-loaded Event ausgelöst'); // Event-Listener für Knoten-Klicks cy.on('tap', 'node', async function(evt) { const node = evt.target; console.log('Node clicked:', node.id(), 'hasChildren:', node.data('hasChildren'), 'expanded:', node.data('expanded')); if (node.data('hasChildren') && !node.data('expanded')) { await loadSubthemes(node); } }); // Entferne den Icon-Overlay-Code setTimeout(() => { // Entferne alle existierenden Icon-Overlays document.querySelectorAll('.cy-node-icon').forEach(icon => icon.remove()); }, 0); }); // Funktion zum Initialisieren des neuronalen Designs function initializeNeuralDesign(cy) { // Füge neuronale Eigenschaften zu allen Knoten hinzu cy.nodes().forEach(node => { const data = node.data(); node.data({ ...data, neuronSize: data.neuronSize || 8, neuronActivity: data.neuronActivity || 0.8, refractionPeriod: Math.random() * 300 + 700, threshold: Math.random() * 0.3 + 0.6, lastFired: 0, color: categoryColors[data.category] || '#60a5fa' }); }); // Füge synaptische Eigenschaften zu allen Kanten hinzu cy.edges().forEach(edge => { const data = edge.data(); edge.data({ ...data, strength: data.strength || 0.5, conductionVelocity: Math.random() * 0.5 + 0.3, latency: Math.random() * 100 + 50 }); }); // Wende neuronales Styling an cy.style() .selector('node') .style({ 'background-color': 'data(color)', 'label': 'data(label)', 'color': '#fff', 'text-background-color': 'rgba(0, 0, 0, 0.7)', 'text-background-opacity': 0.8, 'text-background-padding': '4px', 'text-valign': 'center', 'text-halign': 'center', 'font-size': 16, 'width': 'mapData(neuronSize, 3, 10, 30, 60)', 'height': 'mapData(neuronSize, 3, 10, 30, 60)', 'border-width': 2, 'border-color': '#fff', 'border-opacity': 0.8, 'overlay-padding': 4, 'z-index': 10, 'shape': 'ellipse', 'background-opacity': 0.85, 'shadow-blur': 'mapData(neuronActivity, 0.3, 1, 10, 20)', 'shadow-color': 'data(color)', 'shadow-opacity': 0.6, 'shadow-offset-x': 0, 'shadow-offset-y': 0 }) .selector('edge') .style({ 'width': 'mapData(strength, 0.2, 1, 1, 3)', 'line-color': '#a78bfa', 'line-opacity': 'mapData(strength, 0.2, 1, 0.4, 0.8)', 'target-arrow-color': '#a78bfa', 'target-arrow-shape': 'none', 'curve-style': 'bezier', 'control-point-distances': [20, -20], 'control-point-weights': [0.5, 0.5], 'edge-distances': 'intersection', 'loop-direction': '-45deg', 'loop-sweep': '-90deg', 'line-style': function(ele) { const strength = ele.data('strength'); if (strength <= 0.4) return 'dotted'; if (strength <= 0.6) return 'dashed'; return 'solid'; } }) .update(); // Starte neuronale Aktivitätssimulation startNeuralActivitySimulation(cy); } // Modifiziere die updateMindmap Funktion function updateMindmap() { if (!cy) return; // Bestehende Elemente entfernen cy.elements().remove(); // Neue Knoten hinzufügen mindmapData.nodes.forEach(node => { cy.add({ group: 'nodes', data: { id: node.id, label: node.name, category: node.category, description: node.description, hasChildren: node.has_children, expanded: false, color: node.color_code || mindmapConfig.categories[node.category]?.color || '#60a5fa', icon: node.icon || mindmapConfig.categories[node.category]?.icon || 'fa-solid fa-circle' } }); }); // Neue Kanten hinzufügen mindmapData.edges.forEach(edge => { cy.add({ group: 'edges', data: { source: edge.source, target: edge.target, strength: edge.strength || 0.5 } }); }); // Layout aktualisieren cy.layout(mindmapStyles.layout.base).run(); } /** * Erweitert die Mindmap mit dem neuronalen Netzwerk-Design */ function enhanceMindmap() { // Auf die bestehende Cytoscape-Instanz zugreifen const cy = window.cy; if (!cy) { console.error('Keine Cytoscape-Instanz gefunden.'); return; } // Aktualisiere das Layout für eine bessere Verteilung cy.layout({ name: 'cose', animate: true, animationDuration: 2000, nodeDimensionsIncludeLabels: true, padding: 100, spacingFactor: 2, randomize: true, fit: true, componentSpacing: 150, nodeRepulsion: 10000, edgeElasticity: 150, nestingFactor: 1.5, gravity: 100, initialTemp: 1000, coolingFactor: 0.95, minTemp: 1 }).run(); // Neuronen-Namen mit besserer Lesbarkeit umgestalten cy.style() .selector('node') .style({ 'text-background-color': 'rgba(10, 14, 25, 0.7)', 'text-background-opacity': 0.7, 'text-background-padding': '2px', 'text-border-opacity': 0.2, 'text-border-width': 1, 'text-border-color': '#8b5cf6' }) .update(); // Sicherstellen, dass alle Knoten Neuronen-Eigenschaften haben cy.nodes().forEach(node => { if (!node.data('neuronSize')) { const neuronSize = Math.floor(Math.random() * 8) + 3; node.data('neuronSize', neuronSize); } if (!node.data('neuronActivity')) { const neuronActivity = Math.random() * 0.7 + 0.3; node.data('neuronActivity', neuronActivity); } // Zusätzliche Neuronale Eigenschaften node.data('pulseFrequency', Math.random() * 4 + 2); // Pulsfrequenz (2-6 Hz) node.data('refractionPeriod', Math.random() * 300 + 700); // Refraktionszeit (700-1000ms) node.data('threshold', Math.random() * 0.3 + 0.6); // Aktivierungsschwelle (0.6-0.9) }); // Sicherstellen, dass alle Kanten Synapse-Eigenschaften haben cy.edges().forEach(edge => { if (!edge.data('strength')) { const strength = Math.random() * 0.6 + 0.2; edge.data('strength', strength); } // Zusätzliche synaptische Eigenschaften edge.data('conductionVelocity', Math.random() * 0.5 + 0.3); // Leitungsgeschwindigkeit (0.3-0.8) edge.data('latency', Math.random() * 100 + 50); // Signalverzögerung (50-150ms) }); // Neuronales Netzwerk-Stil anwenden applyNeuralNetworkStyle(cy); console.log('Mindmap wurde erfolgreich im neuronalen Netzwerk-Stil aktualisiert'); // Spezielle Effekte für das neuronale Netzwerk hinzufügen startNeuralActivitySimulation(cy); } /** * Wendet detaillierte neuronale Netzwerkstile auf die Mindmap an * @param {Object} cy - Cytoscape-Instanz */ function applyNeuralNetworkStyle(cy) { cy.style() .selector('node') .style({ 'label': 'data(label)', 'text-valign': 'center', 'text-halign': 'center', 'color': 'data(fontColor)', 'text-outline-width': 2, 'text-outline-color': 'rgba(0,0,0,0.8)', 'text-outline-opacity': 0.9, 'font-size': 'data(fontSize)', 'font-weight': '500', 'text-margin-y': 8, 'width': function(ele) { if (ele.data('isCenter')) return 120; return ele.data('neuronSize') ? ele.data('neuronSize') * 10 : 80; }, 'height': function(ele) { if (ele.data('isCenter')) return 120; return ele.data('neuronSize') ? ele.data('neuronSize') * 10 : 80; }, 'background-color': 'data(color)', 'background-opacity': 0.9, 'border-width': 2, 'border-color': '#ffffff', 'border-opacity': 0.8, 'shape': 'ellipse', 'transition-property': 'background-color, background-opacity, border-width', 'transition-duration': '0.3s', 'transition-timing-function': 'ease-in-out' }) .selector('edge') .style({ 'width': function(ele) { return ele.data('strength') ? ele.data('strength') * 3 : 1; }, 'curve-style': 'bezier', 'line-color': function(ele) { const sourceColor = ele.source().data('color'); return sourceColor || '#8a8aaa'; }, 'line-opacity': function(ele) { return ele.data('strength') ? ele.data('strength') * 0.8 : 0.4; }, 'line-style': function(ele) { const strength = ele.data('strength'); if (!strength) return 'solid'; if (strength <= 0.4) return 'dotted'; if (strength <= 0.6) return 'dashed'; return 'solid'; }, 'target-arrow-shape': 'none', 'source-endpoint': '0% 50%', 'target-endpoint': '100% 50%', 'transition-property': 'line-opacity, width', 'transition-duration': '0.3s', 'transition-timing-function': 'ease-in-out' }) .update(); } // Vereinfachte neuronale Aktivitätssimulation function startNeuralActivitySimulation(cy) { if (window.neuralInterval) clearInterval(window.neuralInterval); const nodes = cy.nodes(); let currentTime = Date.now(); function simulateNeuralActivity() { currentTime = Date.now(); nodes.forEach(node => { const data = node.data(); const lastFired = data.lastFired || 0; const timeSinceLastFire = currentTime - lastFired; if (timeSinceLastFire > data.refractionPeriod) { if (Math.random() < data.neuronActivity * 0.1) { fireNeuron(node, true, currentTime); } } }); } function fireNeuron(node, state, currentTime) { const data = node.data(); data.lastFired = currentTime; node.style({ 'background-opacity': 1, 'border-width': 3 }); setTimeout(() => { node.style({ 'background-opacity': 0.9, 'border-width': 2 }); }, 200); if (state) { propagateSignal(node, currentTime); } } function propagateSignal(sourceNode, currentTime) { const outgoingEdges = sourceNode.connectedEdges(); outgoingEdges.forEach(edge => { const targetNode = edge.target(); const edgeData = edge.data(); const latency = edgeData.latency; edge.style({ 'line-opacity': 0.8, 'width': edgeData.strength * 3 }); setTimeout(() => { edge.style({ 'line-opacity': edgeData.strength * 0.6, 'width': edgeData.strength * 2 }); }, 200); setTimeout(() => { const targetData = targetNode.data(); const timeSinceLastFire = currentTime - (targetData.lastFired || 0); if (timeSinceLastFire > targetData.refractionPeriod) { const signalStrength = edgeData.strength * edgeData.conductionVelocity * sourceNode.data('neuronActivity'); if (signalStrength > targetData.threshold) { fireNeuron(targetNode, true, currentTime + latency); } } }, latency); }); } window.neuralInterval = setInterval(simulateNeuralActivity, 100); } // Hilfe-Funktion zum Hinzufügen eines Flash-Hinweises function showFlash(message, type = 'info') { const flashContainer = createFlashContainer(); const flash = document.createElement('div'); flash.className = `flash-message ${type}`; flash.textContent = message; flashContainer.appendChild(flash); document.body.appendChild(flashContainer); setTimeout(() => { flash.classList.add('show'); setTimeout(() => { flash.classList.remove('show'); setTimeout(() => { flashContainer.remove(); }, 300); }, 3000); }, 100); } /** * Zeigt eine Benachrichtigung in der UI an * @param {string|object} message - Die anzuzeigende Nachricht oder ein Fehlerobjekt * @param {string} type - Der Typ der Benachrichtigung ('info', 'success', 'warning', 'error') * @param {number} duration - Die Anzeigedauer in Millisekunden (Standard: 3000) */ function showUINotification(message, type = 'info', duration = 3000) { // Überprüfe und formatiere die Nachricht let displayMessage; if (typeof message === 'object') { if (message.message) { displayMessage = message.message; } else if (message.error) { displayMessage = message.error; } else if (message.details) { displayMessage = message.details; } else { console.error('Ungültiges Nachrichtenobjekt:', message); displayMessage = 'Ein unbekannter Fehler ist aufgetreten'; } } else if (typeof message === 'string') { displayMessage = message; } else { console.error('Ungültige Nachricht für UI-Benachrichtigung:', message); displayMessage = 'Ein unbekannter Fehler ist aufgetreten'; } // Validiere den Typ const validTypes = ['info', 'success', 'warning', 'error']; if (!validTypes.includes(type)) { console.warn(`Ungültiger Benachrichtigungstyp: ${type}. Verwende 'info' als Fallback.`); type = 'info'; } // Validiere die Dauer if (typeof duration !== 'number' || duration < 1000 || duration > 10000) { console.warn(`Ungültige Dauer: ${duration}ms. Verwende 3000ms als Fallback.`); duration = 3000; } // Zeige die Benachrichtigung an showFlash(displayMessage, type); // Logging für Debugging-Zwecke console.log(`UI-Benachrichtigung [${type}]:`, displayMessage); } // Hilfsfunktion zum Erstellen eines Flash-Containers, falls keiner existiert function createFlashContainer() { const container = document.createElement('div'); container.id = 'flash-messages'; container.className = 'fixed top-4 right-4 z-50 w-64'; document.body.appendChild(container); return container; } // Funktion zum Laden der Subthemen async function loadSubthemes(node) { try { const mindmapData = await loadMindmapData(node.id()); if (!mindmapData) return; showFlash('Lade Subthemen...', 'info'); const mindmapContainer = document.querySelector('.mindmap-container'); const newPage = document.createElement('div'); newPage.className = 'mindmap-page'; newPage.style.display = 'none'; const header = document.createElement('div'); header.className = 'mindmap-header'; header.innerHTML = `

${node.data('label')}

`; const newContainer = document.createElement('div'); newContainer.id = `cy-${node.id()}`; newContainer.className = 'mindmap-view'; newPage.appendChild(header); newPage.appendChild(newContainer); mindmapContainer.appendChild(newPage); const newCy = cytoscape({ container: newContainer, elements: [ ...mindmapData.nodes.map(node => ({ data: { id: node.id, label: node.name, category: node.category, description: node.description, hasChildren: node.has_children, expanded: false, color: node.color_code, fontColor: '#ffffff', fontSize: 16 } })), ...mindmapData.edges.map(edge => ({ data: { source: edge.source_id, target: edge.target_id, strength: edge.strength || 0.5 } })) ], style: cy.style(), layout: mindmapStyles.layout.base }); // Event-Listener für die neue Mindmap newCy.on('tap', 'node', async function(evt) { const clickedNode = evt.target; if (clickedNode.data('hasChildren') && !clickedNode.data('expanded')) { await loadSubthemes(clickedNode); } }); // Alte Seite ausblenden und neue anzeigen cy.container().style.display = 'none'; newPage.style.display = 'block'; showFlash('Subthemen erfolgreich geladen', 'success'); } catch (error) { console.error('Fehler beim Laden der Subthemen:', error); showFlash('Fehler beim Laden der Subthemen', 'error'); } } // Funktion zum Zurücknavigieren function goBack() { const currentPage = document.querySelector('.mindmap-page:not([style*="display: none"])'); if (currentPage) { currentPage.style.display = 'none'; cy.container().style.display = 'block'; } } // CSS-Styles für die neue Seite const style = document.createElement('style'); style.textContent = ` .mindmap-page { position: absolute; top: 0; left: 0; width: 100%; height: 100%; background: var(--bg-color, #1a1a1a); z-index: 1000; } .mindmap-header { display: flex; align-items: center; padding: 1rem; background: rgba(0, 0, 0, 0.2); border-bottom: 1px solid rgba(255, 255, 255, 0.1); } .back-button { background: none; border: none; color: #fff; cursor: pointer; padding: 0.5rem; margin-right: 1rem; border-radius: 50%; transition: background-color 0.3s; } .back-button:hover { background: rgba(255, 255, 255, 0.1); } .mindmap-title { color: #fff; font-size: 1.5rem; font-weight: 600; margin: 0; } .mindmap-view { width: 100%; height: calc(100% - 4rem); } /* Neuronale Effekte */ .cy-container { background: linear-gradient(45deg, #1a1a1a, #2a2a2a); } .cy-container node { transition: all 0.3s ease; } .cy-container node:hover { filter: brightness(1.2); } .cy-node-icon { position: absolute; pointer-events: none; z-index: 1001; color: #fff; text-shadow: 0 2px 8px rgba(0,0,0,0.25); } /* Verbesserte Flash-Benachrichtigungen */ #flash-messages { position: fixed; top: 1rem; right: 1rem; z-index: 9999; display: flex; flex-direction: column; gap: 0.5rem; max-width: 24rem; } .flash-message { padding: 1rem 1.25rem; border-radius: 0.5rem; background: rgba(17, 24, 39, 0.95); color: #fff; font-size: 0.875rem; line-height: 1.25rem; box-shadow: 0 4px 6px -1px rgba(0, 0, 0, 0.1), 0 2px 4px -1px rgba(0, 0, 0, 0.06); transform: translateX(120%); opacity: 0; transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1); backdrop-filter: blur(8px); border: 1px solid rgba(255, 255, 255, 0.1); } .flash-message.show { transform: translateX(0); opacity: 1; } .flash-message.info { border-left: 4px solid #3b82f6; background: linear-gradient(to right, rgba(59, 130, 246, 0.1), rgba(17, 24, 39, 0.95)); } .flash-message.success { border-left: 4px solid #10b981; background: linear-gradient(to right, rgba(16, 185, 129, 0.1), rgba(17, 24, 39, 0.95)); } .flash-message.warning { border-left: 4px solid #f59e0b; background: linear-gradient(to right, rgba(245, 158, 11, 0.1), rgba(17, 24, 39, 0.95)); } .flash-message.error { border-left: 4px solid #ef4444; background: linear-gradient(to right, rgba(239, 68, 68, 0.1), rgba(17, 24, 39, 0.95)); } .flash-message::before { content: ''; position: absolute; top: 0; left: 0; width: 100%; height: 100%; background: linear-gradient(45deg, rgba(255, 255, 255, 0.1) 0%, rgba(255, 255, 255, 0) 100%); pointer-events: none; } @keyframes pulse { 0% { transform: scale(1); } 50% { transform: scale(1.02); } 100% { transform: scale(1); } } .flash-message.show { animation: pulse 0.3s ease-in-out; } /* Neuronale Effekte für Benachrichtigungen */ .flash-message.info:hover { box-shadow: 0 0 15px rgba(59, 130, 246, 0.3); } .flash-message.success:hover { box-shadow: 0 0 15px rgba(16, 185, 129, 0.3); } .flash-message.warning:hover { box-shadow: 0 0 15px rgba(245, 158, 11, 0.3); } .flash-message.error:hover { box-shadow: 0 0 15px rgba(239, 68, 68, 0.3); } `; document.head.appendChild(style); // Initialisiere die Mindmap beim Laden der Seite document.addEventListener('DOMContentLoaded', initializeMindmap);