diff --git a/logs/app.log b/logs/app.log
index 7791ffc..e550e79 100644
--- a/logs/app.log
+++ b/logs/app.log
@@ -428,3 +428,15 @@ werkzeug.exceptions.NotFound: 404 Not Found: The requested URL was not found on
2025-05-14 12:13:20,274 INFO: Anwendung gestartet [in C:\Users\TTOMCZA.EMEA\Dev\website\app.py:77]
2025-05-14 12:13:22,949 INFO: Anwendung gestartet [in C:\Users\TTOMCZA.EMEA\Dev\website\app.py:77]
2025-05-14 12:13:22,949 INFO: Anwendung gestartet [in C:\Users\TTOMCZA.EMEA\Dev\website\app.py:77]
+2025-05-14 12:45:09,092 INFO: Anwendung gestartet [in C:\Users\TTOMCZA.EMEA\Dev\website\app.py:77]
+2025-05-14 12:45:11,512 INFO: Anwendung gestartet [in C:\Users\TTOMCZA.EMEA\Dev\website\app.py:77]
+2025-05-14 12:45:11,512 INFO: Anwendung gestartet [in C:\Users\TTOMCZA.EMEA\Dev\website\app.py:77]
+2025-05-14 12:45:15,327 INFO: Anwendung gestartet [in C:\Users\TTOMCZA.EMEA\Dev\website\app.py:77]
+2025-05-14 12:45:17,576 INFO: Anwendung gestartet [in C:\Users\TTOMCZA.EMEA\Dev\website\app.py:77]
+2025-05-14 12:45:17,576 INFO: Anwendung gestartet [in C:\Users\TTOMCZA.EMEA\Dev\website\app.py:77]
+2025-05-14 12:45:22,725 INFO: Anwendung gestartet [in C:\Users\TTOMCZA.EMEA\Dev\website\app.py:77]
+2025-05-14 12:45:25,195 INFO: Anwendung gestartet [in C:\Users\TTOMCZA.EMEA\Dev\website\app.py:77]
+2025-05-14 12:45:25,195 INFO: Anwendung gestartet [in C:\Users\TTOMCZA.EMEA\Dev\website\app.py:77]
+2025-05-14 12:45:29,299 INFO: Anwendung gestartet [in C:\Users\TTOMCZA.EMEA\Dev\website\app.py:77]
+2025-05-14 12:45:31,561 INFO: Anwendung gestartet [in C:\Users\TTOMCZA.EMEA\Dev\website\app.py:77]
+2025-05-14 12:45:31,561 INFO: Anwendung gestartet [in C:\Users\TTOMCZA.EMEA\Dev\website\app.py:77]
diff --git a/static/css/mindmap.css b/static/css/mindmap.css
index c1b7a4f..9fa9dcc 100644
--- a/static/css/mindmap.css
+++ b/static/css/mindmap.css
@@ -250,210 +250,4 @@
.dark .mindmap-tooltip {
background: rgba(30, 41, 59, 0.9);
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.2);
-}
-
-/* Mindmap Styles
- Stylesheets für die interaktive Mindmap-Funktionalität
- Umfasst Bearbeitungsmodus, CRUD-Funktionen und UI-Elemente
-*/
-
-/* Bearbeitungsmodus-Indikator */
-#cy.editing-mode {
- background: rgba(245, 158, 11, 0.1) !important;
-}
-
-/* Edge-Erstellungsmodus */
-#cy.edge-creation-mode {
- cursor: crosshair !important;
-}
-
-/* Aktivierter Knoten */
-#cy .edge-source {
- border-color: #f59e0b !important;
- border-width: 4px !important;
- border-style: dashed !important;
-}
-
-/* Node-Dialog Overlay */
-.node-dialog-overlay {
- position: fixed;
- top: 0;
- left: 0;
- right: 0;
- bottom: 0;
- background: rgba(0, 0, 0, 0.5);
- backdrop-filter: blur(3px);
- z-index: 1900;
-}
-
-/* Kontext-Menü */
-.context-menu {
- position: absolute;
- z-index: 2000;
- background: rgba(15, 23, 42, 0.95);
- border-radius: 0.5rem;
- box-shadow: 0 4px 12px rgba(0, 0, 0, 0.2);
- min-width: 180px;
- border: 1px solid rgba(255, 255, 255, 0.1);
- backdrop-filter: blur(10px);
- overflow: hidden;
-}
-
-.context-menu-header {
- padding: 0.5rem 1rem;
- color: rgba(255, 255, 255, 0.7);
- font-size: 0.8rem;
- border-bottom: 1px solid rgba(255, 255, 255, 0.1);
-}
-
-.context-menu-item {
- padding: 0.5rem 1rem;
- display: flex;
- align-items: center;
- gap: 0.5rem;
- color: rgba(255, 255, 255, 0.9);
- cursor: pointer;
- transition: all 0.2s ease;
-}
-
-.context-menu-item:hover {
- background: rgba(255, 255, 255, 0.1);
-}
-
-/* Benachrichtigungen */
-#notification-container {
- position: fixed;
- top: 1rem;
- right: 1rem;
- z-index: 2000;
- max-width: 400px;
- display: flex;
- flex-direction: column;
- gap: 0.5rem;
-}
-
-.notification {
- padding: 1rem;
- border-radius: 0.5rem;
- background: rgba(15, 23, 42, 0.95);
- color: white;
- box-shadow: 0 4px 12px rgba(0, 0, 0, 0.2);
- display: flex;
- align-items: center;
- gap: 0.75rem;
- transform: translateX(120%);
- transition: transform 0.3s ease-out;
- backdrop-filter: blur(10px);
- border: 1px solid rgba(255, 255, 255, 0.1);
-}
-
-.notification i {
- font-size: 1.25rem;
-}
-
-.notification-success {
- background: rgba(16, 185, 129, 0.9);
-}
-
-.notification-error {
- background: rgba(239, 68, 68, 0.9);
-}
-
-.notification-warning {
- background: rgba(245, 158, 11, 0.9);
-}
-
-.notification-info {
- background: rgba(59, 130, 246, 0.9);
-}
-
-/* CRUD-Aktionen Styles */
-.crud-panel {
- transition: transform 0.3s ease, opacity 0.3s ease;
-}
-
-.crud-panel.hidden {
- opacity: 0;
- transform: translateY(50px);
- pointer-events: none;
-}
-
-/* Tooltip für CRUD-Buttons */
-.crud-button::after {
- content: attr(data-tooltip);
- position: absolute;
- bottom: 100%;
- left: 50%;
- transform: translateX(-50%);
- background: rgba(15, 23, 42, 0.95);
- padding: 0.3rem 0.6rem;
- border-radius: 0.4rem;
- font-size: 0.7rem;
- white-space: nowrap;
- opacity: 0;
- transition: opacity 0.2s ease;
- pointer-events: none;
- margin-bottom: 5px;
-}
-
-.crud-button:hover::after {
- opacity: 1;
-}
-
-/* Visueller Indikator für den Bearbeitungsmodus */
-.edit-mode-indicator {
- animation: pulse-warning 2s infinite;
- box-shadow: 0 0 10px rgba(245, 158, 11, 0.5);
-}
-
-@keyframes pulse-warning {
- 0% { box-shadow: 0 0 0 0 rgba(245, 158, 11, 0.7); }
- 70% { box-shadow: 0 0 0 10px rgba(245, 158, 11, 0); }
- 100% { box-shadow: 0 0 0 0 rgba(245, 158, 11, 0); }
-}
-
-/* Verbesserter Info-Panel */
-.info-panel {
- transition: all 0.3s ease;
-}
-
-.info-title {
- position: relative;
-}
-
-.info-title::after {
- content: '';
- position: absolute;
- bottom: -5px;
- left: 0;
- width: 50px;
- height: 3px;
- background: linear-gradient(90deg, #60a5fa, #8b5cf6);
- border-radius: 2px;
-}
-
-.info-content {
- max-height: 300px;
- overflow-y: auto;
-}
-
-/* Anpassungen für kleinere Bildschirme */
-@media (max-width: 768px) {
- .crud-panel {
- bottom: 1rem;
- left: 1rem;
- right: 1rem;
- transform: none;
- justify-content: space-around;
- }
-
- .info-panel {
- left: 1rem;
- width: calc(100% - 2rem);
- max-width: none;
- }
-
- .control-panel {
- right: 1rem;
- }
}
\ No newline at end of file
diff --git a/static/js/update_mindmap.js b/static/js/update_mindmap.js
index 2e97f87..2541013 100644
--- a/static/js/update_mindmap.js
+++ b/static/js/update_mindmap.js
@@ -820,11 +820,11 @@ function showUINotification(message, type = 'info', duration = 3000) {
closeButton.onclick = () => {
notification.style.opacity = '0';
notification.style.transform = 'translateY(-20px)';
- setTimeout(() => {
+ setTimeout(() => {
if (notification.parentNode === container) {
container.removeChild(notification);
- }
- }, 300);
+ }
+ }, 300);
};
notification.appendChild(closeButton);
@@ -832,23 +832,23 @@ function showUINotification(message, type = 'info', duration = 3000) {
container.appendChild(notification);
// Animation starten
- setTimeout(() => {
+ setTimeout(() => {
notification.style.opacity = '1';
notification.style.transform = 'translateY(0)';
}, 10);
// Automatisch ausblenden, wenn keine Dauer von 0 übergeben wurde
if (duration > 0) {
- setTimeout(() => {
+ setTimeout(() => {
if (notification.parentNode === container) {
notification.style.opacity = '0';
notification.style.transform = 'translateY(-20px)';
setTimeout(() => {
if (notification.parentNode === container) {
container.removeChild(notification);
- }
- }, 300);
- }
+ }
+ }, 300);
+ }
}, duration);
}
}
@@ -968,279 +968,194 @@ function handleEditingAction(action, nodeId) {
}
// Funktion zum Hinzufügen eines neuen Knotens
-function addNewNode(cy, parentNode = null) {
- // Dialog erstellen
- const dialog = document.createElement('div');
- dialog.className = 'node-dialog';
- dialog.style.position = 'absolute';
- dialog.style.top = '50%';
- dialog.style.left = '50%';
- dialog.style.transform = 'translate(-50%, -50%)';
- dialog.style.background = 'rgba(15, 23, 42, 0.95)';
- dialog.style.padding = '1.5rem';
- dialog.style.borderRadius = '0.75rem';
- dialog.style.boxShadow = '0 4px 20px rgba(0, 0, 0, 0.3)';
- dialog.style.zIndex = '2000';
- dialog.style.width = '400px';
- dialog.style.maxWidth = '90vw';
- dialog.style.backdropFilter = 'blur(8px)';
- dialog.style.border = '1px solid rgba(255, 255, 255, 0.1)';
-
- dialog.innerHTML = `
-
Neuen Knoten erstellen
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- `;
-
- document.body.appendChild(dialog);
-
- // Event-Listener
- document.getElementById('cancel-node').addEventListener('click', () => {
- document.body.removeChild(dialog);
- });
-
- document.getElementById('create-node').addEventListener('click', () => {
- const name = document.getElementById('node-name').value || 'Neuer Knoten';
- const description = document.getElementById('node-description').value || '';
- const category = document.getElementById('node-category').value;
- const color = document.getElementById('node-color').value;
-
- // Temporäre ID erstellen (wird später durch die echte ID ersetzt)
- const tempId = 'new-' + Date.now();
-
- // Knoten zur Visualisierung hinzufügen
- const newNode = cy.add({
- group: 'nodes',
- data: {
- id: tempId,
- label: name,
- description: description,
- category: category,
- color: color,
- icon: 'fa-solid fa-circle'
- },
- position: {
- x: cy.width() / 2 + (Math.random() * 100 - 50),
- y: cy.height() / 2 + (Math.random() * 100 - 50)
- }
- });
-
- // Wenn ein Elternknoten angegeben ist, eine Verbindung erstellen
- if (parentNode) {
- cy.add({
- group: 'edges',
- data: {
- source: parentNode.id(),
- target: tempId,
- strength: 0.5
- }
- });
- }
-
- // Layout neu berechnen
- cy.layout(mindmapStyles.layout.base).run();
-
- document.body.removeChild(dialog);
- showUINotification('Neuer Knoten erstellt!', 'success');
- });
-
- // Kategorie-Auswahl mit Farben verknüpfen
- document.getElementById('node-category').addEventListener('change', (e) => {
- const category = e.target.value;
- let color = '#9F7AEA'; // Standardfarbe
-
- switch(category) {
- case 'Philosophie':
- color = '#9F7AEA'; // Lila
- break;
- case 'Wissenschaft':
- color = '#60A5FA'; // Blau
- break;
- case 'Technologie':
- color = '#10B981'; // Grün
- break;
- case 'Künste':
- color = '#F59E0B'; // Orange
- break;
- case 'Psychologie':
- color = '#EF4444'; // Rot
- break;
- }
-
- document.getElementById('node-color').value = color;
+function addNewNode(cy) {
+ // Zentriere den neuen Knoten im sichtbaren Bereich
+ const extent = cy.extent();
+ const centerX = (extent.x1 + extent.x2) / 2;
+ const centerY = (extent.y1 + extent.y2) / 2;
+
+ // Generiere eine eindeutige ID
+ const newId = 'new-node-' + Date.now();
+
+ // Füge den neuen Knoten hinzu
+ cy.add({
+ group: 'nodes',
+ data: {
+ id: newId,
+ label: 'Neuer Knoten',
+ category: 'Wissenschaft',
+ description: 'Beschreibung hinzufügen',
+ hasChildren: false,
+ expanded: false,
+ color: mindmapConfig.categories['Wissenschaft'].color,
+ fontColor: '#ffffff',
+ fontSize: 16,
+ neuronSize: 8,
+ neuronActivity: 0.8
+ },
+ position: { x: centerX, y: centerY }
});
+
+ // Wähle den neuen Knoten aus, um ihn zu bearbeiten
+ const newNode = cy.getElementById(newId);
+ newNode.select();
+
+ // Öffne den Bearbeitungsdialog für den neuen Knoten
+ setTimeout(() => {
+ editNodeProperties(newNode);
+ }, 300);
}
-// Funktion zum Bearbeiten eines Knotens
+// Funktion zum Bearbeiten von Knoteneigenschaften
function editNodeProperties(node) {
if (!node) return;
+ // Erstelle den Modal-Hintergrund
+ const backdrop = document.createElement('div');
+ backdrop.className = 'modal-backdrop';
+ document.body.appendChild(backdrop);
+
+ // Erstelle den Bearbeitungsdialog
+ const dialog = document.createElement('div');
+ dialog.className = 'node-edit-dialog';
+
+ // Hole die aktuellen Daten des Knotens
const data = node.data();
- // Dialog erstellen
- const dialog = document.createElement('div');
- dialog.className = 'node-dialog';
- dialog.style.position = 'absolute';
- dialog.style.top = '50%';
- dialog.style.left = '50%';
- dialog.style.transform = 'translate(-50%, -50%)';
- dialog.style.background = 'rgba(15, 23, 42, 0.95)';
- dialog.style.padding = '1.5rem';
- dialog.style.borderRadius = '0.75rem';
- dialog.style.boxShadow = '0 4px 20px rgba(0, 0, 0, 0.3)';
- dialog.style.zIndex = '2000';
- dialog.style.width = '400px';
- dialog.style.maxWidth = '90vw';
- dialog.style.backdropFilter = 'blur(8px)';
- dialog.style.border = '1px solid rgba(255, 255, 255, 0.1)';
-
+ // Generiere die Kategorie-Optionen
+ let categoryOptions = '';
+ for (const category in mindmapConfig.categories) {
+ categoryOptions += ``;
+ }
+
+ // Erstelle das Formular
dialog.innerHTML = `
- Knoten bearbeiten
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+ Knoten bearbeiten
+
`;
-
+
document.body.appendChild(dialog);
-
- // Event-Listener
- document.getElementById('cancel-edit').addEventListener('click', () => {
+
+ // Event-Listener für den Abbrechen-Button
+ dialog.querySelector('button.cancel').addEventListener('click', function() {
document.body.removeChild(dialog);
+ document.body.removeChild(backdrop);
});
-
- document.getElementById('save-edit').addEventListener('click', () => {
- const name = document.getElementById('node-name').value || 'Unbenannter Knoten';
- const description = document.getElementById('node-description').value || '';
+
+ // Event-Listener für den Modal-Hintergrund
+ backdrop.addEventListener('click', function() {
+ document.body.removeChild(dialog);
+ document.body.removeChild(backdrop);
+ });
+
+ // Event-Listener für das Formular
+ dialog.querySelector('form').addEventListener('submit', function(e) {
+ e.preventDefault();
+
+ // Hole die neuen Werte aus dem Formular
+ const label = document.getElementById('node-label').value;
const category = document.getElementById('node-category').value;
- const color = document.getElementById('node-color').value;
-
- // Knoten aktualisieren
+ const description = document.getElementById('node-description').value;
+ const hasChildren = document.getElementById('node-has-children').value === 'true';
+
+ // Bestimme die Farbe basierend auf der Kategorie
+ const color = mindmapConfig.categories[category]?.color || data.color || '#60a5fa';
+
+ // Aktualisiere die Daten des Knotens
node.data({
- label: name,
- description: description,
- category: category,
- color: color
+ ...data,
+ label,
+ category,
+ description,
+ hasChildren,
+ color
});
-
+
+ // Schließe den Dialog
document.body.removeChild(dialog);
- showUINotification('Knoten wurde aktualisiert!', 'success');
- });
-
- // Kategorie-Auswahl mit Farben verknüpfen
- document.getElementById('node-category').addEventListener('change', (e) => {
- const category = e.target.value;
- let color = '#9F7AEA'; // Standardfarbe
+ document.body.removeChild(backdrop);
- switch(category) {
- case 'Philosophie':
- color = '#9F7AEA'; // Lila
- break;
- case 'Wissenschaft':
- color = '#60A5FA'; // Blau
- break;
- case 'Technologie':
- color = '#10B981'; // Grün
- break;
- case 'Künste':
- color = '#F59E0B'; // Orange
- break;
- case 'Psychologie':
- color = '#EF4444'; // Rot
- break;
- }
-
- document.getElementById('node-color').value = color;
+ // Benachrichtigung anzeigen
+ showUINotification('Knoten wurde aktualisiert', 'success');
});
}
-// Funktion zum Löschen eines Knotens
-function deleteNode(node) {
+// Funktion zum Anzeigen des Kontext-Menüs für einen Knoten
+function showNodeContextMenu(node, position) {
if (!node) return;
- if (confirm(`Möchten Sie den Knoten "${node.data('label')}" wirklich löschen?`)) {
- // Alle verbundenen Kanten löschen
- node.connectedEdges().remove();
- // Knoten löschen
- node.remove();
- showUINotification('Knoten wurde gelöscht!', 'success');
+ // Entferne existierende Kontext-Menüs
+ const existingMenu = document.querySelector('.context-menu');
+ if (existingMenu) {
+ existingMenu.parentNode.removeChild(existingMenu);
}
-}
-
-// Kontextmenü für Knoten anzeigen
-function showNodeContextMenu(node, position) {
- // Entferne vorhandene Kontextmenüs
- removeContextMenus();
- const contextMenu = document.createElement('div');
- contextMenu.className = 'context-menu';
- contextMenu.style.left = `${position.x}px`;
- contextMenu.style.top = `${position.y}px`;
+ // Erstelle das Kontext-Menü
+ const menu = document.createElement('div');
+ menu.className = 'context-menu';
+ menu.style.left = `${position.x}px`;
+ menu.style.top = `${position.y}px`;
- contextMenu.innerHTML = `
+ // Menü-Einträge
+ menu.innerHTML = `
-