Refactor node relationship handling in app.py and introduce new routes for thoughts association with nodes.

This commit is contained in:
2025-04-28 13:20:41 +02:00
parent 5399169b11
commit 65c44ab371
20 changed files with 181 additions and 152 deletions

Binary file not shown.

Binary file not shown.

33
app.py
View File

@@ -22,7 +22,7 @@ from dotenv import load_dotenv
from models import ( from models import (
db, User, Thought, Comment, MindMapNode, ThoughtRelation, ThoughtRating, db, User, Thought, Comment, MindMapNode, ThoughtRelation, ThoughtRating,
RelationType, Category, UserMindmap, UserMindmapNode, MindmapNote, RelationType, Category, UserMindmap, UserMindmapNode, MindmapNote,
node_thought_association, user_thought_bookmark node_thought_association, user_thought_bookmark, node_relationship
) )
# Lade .env-Datei # Lade .env-Datei
@@ -903,45 +903,30 @@ def delete_note(note_id):
@app.route('/api/mindmap') @app.route('/api/mindmap')
def get_mindmap(): def get_mindmap():
"""API-Endpunkt zur Bereitstellung der Mindmap-Daten in hierarchischer Form.""" """API-Endpunkt zur Bereitstellung der Mindmap-Daten in hierarchischer Form."""
# Alle root-Nodes (ohne parent) abrufen # Root-Knoten: Knoten ohne Eltern
root_nodes = MindMapNode.query.filter_by(parent_id=None).all() root_nodes = MindMapNode.query.\
outerjoin(node_relationship, MindMapNode.id == node_relationship.c.child_id).\
filter(node_relationship.c.parent_id == None).all()
if not root_nodes:
# Wenn keine Nodes existieren, rufen wir initialize_database direkt auf
# anstatt create_sample_mindmap zu verwenden
with app.app_context():
initialize_database()
root_nodes = MindMapNode.query.filter_by(parent_id=None).all()
# Ergebnisse in hierarchischer Struktur zurückgeben
result = [] result = []
for node in root_nodes: for node in root_nodes:
node_data = build_node_tree(node) node_data = build_node_tree(node)
result.append(node_data) result.append(node_data)
return jsonify({"nodes": result}) return jsonify({"nodes": result})
def build_node_tree(node): def build_node_tree(node):
"""Erzeugt eine hierarchische Darstellung eines Knotens inkl. seiner Kindknoten.""" """Erzeugt eine hierarchische Darstellung eines Knotens inkl. seiner Kindknoten."""
# Gedankenzähler abrufen von der many-to-many Beziehung
thought_count = len(node.thoughts) thought_count = len(node.thoughts)
# Daten für aktuellen Knoten
node_data = { node_data = {
"id": node.id, "id": node.id,
"name": node.name, "name": node.name,
"description": f"Knoten mit {thought_count} Gedanken", "description": node.description or "",
"thought_count": thought_count, "thought_count": thought_count,
"children": [] "children": []
} }
for child in node.children:
# Rekursiv Kinder hinzufügen child_data = build_node_tree(child)
child_nodes = MindMapNode.query.filter_by(parent_id=node.id).all()
for child_node in child_nodes:
child_data = build_node_tree(child_node)
node_data["children"].append(child_data) node_data["children"].append(child_data)
return node_data return node_data
@app.route('/api/nodes/<int:node_id>/thoughts') @app.route('/api/nodes/<int:node_id>/thoughts')
@@ -1250,7 +1235,7 @@ def chat_with_assistant():
# Zusammenfassen mehrerer Gedanken oder Analyse anfordern # Zusammenfassen mehrerer Gedanken oder Analyse anfordern
system_message = ( system_message = (
"Du bist ein hilfreicher Assistent, der Zugriff auf die Wissensdatenbank hat. " "Du bist ein hilfreicher Assistent, der Zugriff auf die Wissensdatenbank hat. Du antwortest nur auf Fragen bezüglich Systades und der Wissensdatenbank. "
"Du kannst Informationen zu Gedanken, Kategorien und Mindmaps liefern. " "Du kannst Informationen zu Gedanken, Kategorien und Mindmaps liefern. "
"Antworte informativ, sachlich und gut strukturiert auf Deutsch." "Antworte informativ, sachlich und gut strukturiert auf Deutsch."
) )

Binary file not shown.

0
instance/systades.db Normal file
View File

View File

@@ -7,15 +7,6 @@
* Verwaltet die globale Anwendungslogik * Verwaltet die globale Anwendungslogik
*/ */
document.addEventListener('DOMContentLoaded', function() {
// Initialisiere die Anwendung
MindMap.init();
// Wende Dunkel-/Hellmodus an
const isDarkMode = localStorage.getItem('darkMode') === 'dark';
document.documentElement.classList.toggle('dark', isDarkMode);
});
/** /**
* Hauptobjekt der MindMap-Anwendung * Hauptobjekt der MindMap-Anwendung
*/ */
@@ -24,7 +15,7 @@ const MindMap = {
initialized: false, initialized: false,
darkMode: document.documentElement.classList.contains('dark'), darkMode: document.documentElement.classList.contains('dark'),
pageInitializers: {}, pageInitializers: {},
currentPage: document.body.dataset.page, currentPage: null,
/** /**
* Initialisiert die MindMap-Anwendung * Initialisiert die MindMap-Anwendung
@@ -32,6 +23,9 @@ const MindMap = {
init() { init() {
if (this.initialized) return; if (this.initialized) return;
// Setze currentPage erst jetzt, wenn DOM garantiert geladen ist
this.currentPage = document.body && document.body.dataset ? document.body.dataset.page : null;
console.log('MindMap-Anwendung wird initialisiert...'); console.log('MindMap-Anwendung wird initialisiert...');
// Initialisiere den ChatGPT-Assistenten // Initialisiere den ChatGPT-Assistenten
@@ -229,6 +223,13 @@ const MindMap = {
}); });
} }
}; };
// Globale Export für andere Module
window.MindMap = MindMap; window.MindMap = MindMap;
document.addEventListener('DOMContentLoaded', function() {
// Initialisiere die Anwendung
MindMap.init();
// Wende Dunkel-/Hellmodus an
const isDarkMode = localStorage.getItem('darkMode') === 'dark';
document.documentElement.classList.toggle('dark', isDarkMode);
});

View File

@@ -14,9 +14,18 @@ if (window.MindMap) {
window.MindMap.pageInitializers.mindmap = initMindmapPage; window.MindMap.pageInitializers.mindmap = initMindmapPage;
} }
// Initialisiere die Mindmap-Seite nur, wenn alle Abhängigkeiten vorhanden sind
if (window.MindMap && typeof MindMapVisualization !== 'undefined') {
if (document.body && document.body.dataset && document.body.dataset.page === 'mindmap') {
window.MindMap.pageInitializers = window.MindMap.pageInitializers || {};
window.MindMap.pageInitializers.mindmap = initMindmapPage;
initMindmapPage();
}
}
document.addEventListener('DOMContentLoaded', function() { document.addEventListener('DOMContentLoaded', function() {
// Prüfe, ob wir auf der Mindmap-Seite sind und initialisiere // Prüfe, ob wir auf der Mindmap-Seite sind und initialisiere
if (document.body.dataset.page === 'mindmap') { if (document.body && document.body.dataset && document.body.dataset.page === 'mindmap') {
initMindmapPage(); initMindmapPage();
} }
}); });

View File

@@ -818,6 +818,26 @@ class MindMapVisualization {
this.updateNodeAppearance(d.id, isBookmarked); this.updateNodeAppearance(d.id, isBookmarked);
}); });
} }
/**
* Gibt alle direkt verbundenen Knoten eines Knotens zurück
* @param {Object} node - Der Knoten, für den die Verbindungen gesucht werden
* @returns {Array} Array der verbundenen Knotenobjekte
*/
getConnectedNodes(node) {
if (!node || !this.links || !this.nodes) return [];
const nodeId = node.id;
const connectedIds = new Set();
this.links.forEach(link => {
if (link.source === nodeId || (link.source && link.source.id === nodeId)) {
connectedIds.add(link.target.id ? link.target.id : link.target);
}
if (link.target === nodeId || (link.target && link.target.id === nodeId)) {
connectedIds.add(link.source.id ? link.source.id : link.source);
}
});
return this.nodes.filter(n => connectedIds.has(n.id));
}
} }
// Exportiere die Klasse für die Verwendung in anderen Modulen // Exportiere die Klasse für die Verwendung in anderen Modulen

View File

@@ -68,18 +68,18 @@ class NeuralNetworkBackground {
// Config - Drastisch verstärkt für strahlende Animationen und neuronale Vernetzung // Config - Drastisch verstärkt für strahlende Animationen und neuronale Vernetzung
this.config = { this.config = {
nodeCount: 120, // Viel mehr Knoten für ein dichtes Netzwerk nodeCount: 120, // Anzahl der Knoten bleibt hoch für Netzwerkstruktur
nodeSize: 1.4, // Größere Knoten für mehr Sichtbarkeit nodeSize: 1.1, // Dezenter: kleinere Knoten
nodeVariation: 0.6, // Mehr Variation für organisches Aussehen nodeVariation: 0.4, // Weniger Variation für ruhigeres Bild
connectionDistance: 220, // Deutlich längere Verbindungen für mehr Vernetzung connectionDistance: 220, // Unverändert: gute Vernetzung
connectionOpacity: 0.4, // Wesentlich stärkere Verbindungen connectionOpacity: 0.18, // Deutlich dezentere Verbindungen
animationSpeed: 0.08, // Schnellere Bewegung animationSpeed: 0.05, // Ruhigere Bewegung
pulseSpeed: 0.006, // Schnelleres Pulsieren für lebendiges Aussehen pulseSpeed: 0.004, // Ruhigeres Pulsieren
flowSpeed: 0.8, // Schnellere Flussanimationen flowSpeed: 1.2, // Flows schneller für flüssigere Aktivität
flowDensity: 0.005, // Viel mehr Flussanimationen flowDensity: 0.012, // Mehr Flows für sichtbare Aktivität
flowLength: 0.25, // Längere Flussanimationen flowLength: 0.32, // Flows länger sichtbar
maxConnections: 6, // NEW: Neue Eigenschaft für mehr neuronale Verbindungen pro Knoten maxConnections: 5, // Weniger Überlagerung
clusteringFactor: 0.3 // NEW: Erzeugt Cluster wie in einem neuronalen Netzwerk clusteringFactor: 0.35 // Mehr Cluster für neuronalen Effekt
}; };
// Initialize // Initialize
@@ -335,17 +335,17 @@ class NeuralNetworkBackground {
if (!this.connections.some(conn => if (!this.connections.some(conn =>
(conn.from === i && conn.to === j) || (conn.from === j && conn.to === i) (conn.from === i && conn.to === j) || (conn.from === j && conn.to === i)
)) { )) {
// Create connection // Neue Verbindung startet mit progress=0 für animierten Aufbau
this.connections.push({ this.connections.push({
from: i, from: i,
to: j, to: j,
distance: distance, distance: distance,
opacity: connOpacity, opacity: connOpacity,
strength: connectionStrength, strength: connectionStrength,
hasFlow: false, // Each connection can have a flow hasFlow: false,
lastActivated: 0 // For neural firing animation lastActivated: 0,
progress: 0 // Animationsfortschritt für Verbindungsaufbau
}); });
nodeA.connections.push(j); nodeA.connections.push(j);
nodeB.connections.push(i); nodeB.connections.push(i);
} }
@@ -406,6 +406,15 @@ class NeuralNetworkBackground {
} }
} }
// Animierter Verbindungsaufbau: progress inkrementieren
for (const connection of this.connections) {
if (connection.progress < 1) {
// Langsamer Aufbau: Geschwindigkeit kann angepasst werden
connection.progress += 0.012; // Sehr langsam, für subtilen Effekt
if (connection.progress > 1) connection.progress = 1;
}
}
// Update flows // Update flows
this.updateFlows(); this.updateFlows();
@@ -515,21 +524,8 @@ class NeuralNetworkBackground {
positions[i * 2] = node.x; positions[i * 2] = node.x;
positions[i * 2 + 1] = node.y; positions[i * 2 + 1] = node.y;
// Enhanced pulse effect with additional boost for active nodes // Sichtbarkeit der Neuronen erhöhen
let pulse = Math.sin(node.pulsePhase) * 0.4 + 1; let pulse = Math.sin(node.pulsePhase) * 0.22 + 1.08;
// Make active nodes pulse more intensely (neural firing effect)
if (node.isActive) {
const timeSinceFired = now - node.lastFired;
if (timeSinceFired < 300) {
// Quick expand then contract effect
const normalizedTime = timeSinceFired / 300;
const fireBoost = 1.5 * (1 - normalizedTime);
pulse += fireBoost;
}
}
// Nodes with more connections are larger (hub neurons)
const connectivityFactor = 1 + (node.connections.length / this.config.maxConnections) * 0.8; const connectivityFactor = 1 + (node.connections.length / this.config.maxConnections) * 0.8;
sizes[i] = node.size * pulse * connectivityFactor; sizes[i] = node.size * pulse * connectivityFactor;
} }
@@ -585,10 +581,11 @@ class NeuralNetworkBackground {
b = (b + nodePulseColor.b / 255) / 2; b = (b + nodePulseColor.b / 255) / 2;
} }
// Sehr sichtbare Knoten
this.gl.uniform4f( this.gl.uniform4f(
this.programInfo.uniformLocations.color, this.programInfo.uniformLocations.color,
r, g, b, r, g, b,
0.95 // Higher opacity for maximum visibility node.isActive ? 0.98 : 0.8 // Sehr sichtbar
); );
// Draw each node individually for better control // Draw each node individually for better control
@@ -598,50 +595,40 @@ class NeuralNetworkBackground {
renderConnectionsWebGL() { renderConnectionsWebGL() {
const now = Date.now(); const now = Date.now();
// For each connection, draw a line
for (const connection of this.connections) { for (const connection of this.connections) {
const fromNode = this.nodes[connection.from]; const fromNode = this.nodes[connection.from];
const toNode = this.nodes[connection.to]; const toNode = this.nodes[connection.to];
// Animierter Verbindungsaufbau: nur Teil der Linie zeichnen
// Line positions const progress = connection.progress || 1;
const x1 = fromNode.x;
const y1 = fromNode.y;
const x2 = x1 + (toNode.x - x1) * progress;
const y2 = y1 + (toNode.y - y1) * progress;
const positions = new Float32Array([ const positions = new Float32Array([
fromNode.x, fromNode.y, x1, y1,
toNode.x, toNode.y x2, y2
]); ]);
// Bind position buffer
this.gl.bindBuffer(this.gl.ARRAY_BUFFER, this.positionBuffer); this.gl.bindBuffer(this.gl.ARRAY_BUFFER, this.positionBuffer);
this.gl.bufferData(this.gl.ARRAY_BUFFER, positions, this.gl.STATIC_DRAW); this.gl.bufferData(this.gl.ARRAY_BUFFER, positions, this.gl.STATIC_DRAW);
this.gl.vertexAttribPointer( this.gl.vertexAttribPointer(
this.programInfo.attribLocations.vertexPosition, this.programInfo.attribLocations.vertexPosition,
2, // components per vertex 2,
this.gl.FLOAT, // data type this.gl.FLOAT,
false, // normalize false,
0, // stride 0,
0 // offset 0
); );
this.gl.enableVertexAttribArray(this.programInfo.attribLocations.vertexPosition); this.gl.enableVertexAttribArray(this.programInfo.attribLocations.vertexPosition);
// Disable point size attribute for lines
this.gl.disableVertexAttribArray(this.programInfo.attribLocations.pointSize); this.gl.disableVertexAttribArray(this.programInfo.attribLocations.pointSize);
// Set line color with connection opacity
const colorObj = this.isDarkMode ? this.darkModeColors : this.lightModeColors; const colorObj = this.isDarkMode ? this.darkModeColors : this.lightModeColors;
let lineColor = this.hexToRgb(colorObj.connectionColor); let lineColor = this.hexToRgb(colorObj.connectionColor);
// Sehr dezente Grundopazität
// Highlight recently activated connections for neural pathway effect let opacity = connection.opacity * 0.7;
let opacity = connection.opacity * 1.4; // Base increased visibility
if (now - connection.lastActivated < 800) { if (now - connection.lastActivated < 800) {
// Make recently activated connections brighter
lineColor = this.hexToRgb(colorObj.flowColor); lineColor = this.hexToRgb(colorObj.flowColor);
// Fade out effect
const timeFactor = 1 - ((now - connection.lastActivated) / 800); const timeFactor = 1 - ((now - connection.lastActivated) / 800);
opacity = Math.max(opacity, timeFactor * 0.9); opacity = Math.max(opacity, timeFactor * 0.32);
} }
this.gl.uniform4f( this.gl.uniform4f(
this.programInfo.uniformLocations.color, this.programInfo.uniformLocations.color,
lineColor.r / 255, lineColor.r / 255,
@@ -649,11 +636,8 @@ class NeuralNetworkBackground {
lineColor.b / 255, lineColor.b / 255,
opacity opacity
); );
// Sehr dünne Linien
// Draw the line this.gl.lineWidth(0.5);
this.gl.enable(this.gl.BLEND);
this.gl.blendFunc(this.gl.SRC_ALPHA, this.gl.ONE);
this.gl.lineWidth(1);
this.gl.drawArrays(this.gl.LINES, 0, 2); this.gl.drawArrays(this.gl.LINES, 0, 2);
} }
} }
@@ -730,18 +714,18 @@ class NeuralNetworkBackground {
// Flow color - much stronger glow // Flow color - much stronger glow
const colorObj = this.isDarkMode ? this.darkModeColors : this.lightModeColors; const colorObj = this.isDarkMode ? this.darkModeColors : this.lightModeColors;
const flowColor = this.hexToRgb(colorObj.flowColor); const flowColor = this.hexToRgb(colorObj.flowColor);
// Flows mit sanftem, aber sichtbarem Glow und höherer Opazität
this.gl.uniform4f( this.gl.uniform4f(
this.programInfo.uniformLocations.color, this.programInfo.uniformLocations.color,
flowColor.r / 255, flowColor.r / 255,
flowColor.g / 255, flowColor.g / 255,
flowColor.b / 255, flowColor.b / 255,
0.9 * fadeOpacity * flow.intensity // Much stronger flow opacity with intensity variation 0.55 * fadeOpacity * (flow.intensity || 1) // Dezenter, aber sichtbar
); );
// Draw the flow line // Dünnere Flows für subtilen Effekt
this.gl.enable(this.gl.BLEND); this.gl.lineWidth(1.2);
this.gl.blendFunc(this.gl.SRC_ALPHA, this.gl.ONE);
this.gl.lineWidth(2.5); // Even thicker for dramatic visibility
this.gl.drawArrays(this.gl.LINES, 0, 2); this.gl.drawArrays(this.gl.LINES, 0, 2);
} }
} }
@@ -769,13 +753,19 @@ class NeuralNetworkBackground {
for (const connection of this.connections) { for (const connection of this.connections) {
const fromNode = this.nodes[connection.from]; const fromNode = this.nodes[connection.from];
const toNode = this.nodes[connection.to]; const toNode = this.nodes[connection.to];
// Animierter Verbindungsaufbau: nur Teil der Linie zeichnen
const progress = connection.progress || 1;
const x1 = fromNode.x;
const y1 = fromNode.y;
const x2 = x1 + (toNode.x - x1) * progress;
const y2 = y1 + (toNode.y - y1) * progress;
this.ctx.beginPath(); this.ctx.beginPath();
this.ctx.moveTo(fromNode.x, fromNode.y); this.ctx.moveTo(x1, y1);
this.ctx.lineTo(toNode.x, toNode.y); this.ctx.lineTo(x2, y2);
const rgbColor = this.hexToRgb(connectionColor); const rgbColor = this.hexToRgb(connectionColor);
this.ctx.strokeStyle = `rgba(${rgbColor.r}, ${rgbColor.g}, ${rgbColor.b}, ${connection.opacity})`; // Sehr dezente Opazität
this.ctx.strokeStyle = `rgba(${rgbColor.r}, ${rgbColor.g}, ${rgbColor.b}, ${connection.opacity * 0.7})`;
this.ctx.lineWidth = 0.5;
this.ctx.stroke(); this.ctx.stroke();
} }
@@ -792,33 +782,22 @@ class NeuralNetworkBackground {
: this.lightModeColors.nodePulse; : this.lightModeColors.nodePulse;
for (const node of this.nodes) { for (const node of this.nodes) {
// Node with subtle glow effect // Sichtbarkeit der Neuronen erhöhen
const pulse = Math.sin(node.pulsePhase) * 0.2 + 1; const pulse = Math.sin(node.pulsePhase) * 0.18 + 1.08; // Leicht erhöhte Amplitude
const nodeSize = node.size * pulse * (node.connections.length > 3 ? 1.3 : 1); const nodeSize = node.size * pulse * (node.connections.length > 3 ? 1.22 : 1);
// Glow effect
const glow = this.ctx.createRadialGradient( const glow = this.ctx.createRadialGradient(
node.x, node.y, 0, node.x, node.y, 0,
node.x, node.y, nodeSize * 2 node.x, node.y, nodeSize * 2.2
); );
glow.addColorStop(0, `rgba(${nodePulse.r}, ${nodePulse.g}, ${nodePulse.b}, 0.52)`);
const rgbNodeColor = this.hexToRgb(nodeColor); glow.addColorStop(0.5, `rgba(${nodeColor.r}, ${nodeColor.g}, ${nodeColor.b}, 0.22)`);
const rgbPulseColor = this.hexToRgb(nodePulse); glow.addColorStop(1, `rgba(${nodeColor.r}, ${nodeColor.g}, ${nodeColor.b}, 0)`);
glow.addColorStop(0, `rgba(${rgbPulseColor.r}, ${rgbPulseColor.g}, ${rgbPulseColor.b}, 0.6)`);
glow.addColorStop(0.5, `rgba(${rgbNodeColor.r}, ${rgbNodeColor.g}, ${rgbNodeColor.b}, 0.2)`);
glow.addColorStop(1, `rgba(${rgbNodeColor.r}, ${rgbNodeColor.g}, ${rgbNodeColor.b}, 0)`);
this.ctx.beginPath();
this.ctx.arc(node.x, node.y, nodeSize * 2, 0, Math.PI * 2);
this.ctx.fillStyle = glow;
this.ctx.fill();
// Main node
this.ctx.beginPath(); this.ctx.beginPath();
this.ctx.arc(node.x, node.y, nodeSize, 0, Math.PI * 2); this.ctx.arc(node.x, node.y, nodeSize, 0, Math.PI * 2);
this.ctx.fillStyle = nodeColor; this.ctx.fillStyle = glow;
this.ctx.globalAlpha = node.isActive ? 0.95 : 0.7; // Sehr sichtbar
this.ctx.fill(); this.ctx.fill();
this.ctx.globalAlpha = 1.0;
} }
} }
@@ -876,12 +855,12 @@ class NeuralNetworkBackground {
1 1
); );
// Draw flow // Dezente Flows mit sanftem Fade-Out
this.ctx.beginPath(); this.ctx.beginPath();
this.ctx.moveTo(p1.x, p1.y); this.ctx.moveTo(p1.x, p1.y);
this.ctx.lineTo(p2.x, p2.y); this.ctx.lineTo(p2.x, p2.y);
this.ctx.strokeStyle = `rgba(${rgbFlowColor.r}, ${rgbFlowColor.g}, ${rgbFlowColor.b}, ${0.4 * fadeOpacity})`; this.ctx.strokeStyle = `rgba(${rgbFlowColor.r}, ${rgbFlowColor.g}, ${rgbFlowColor.b}, ${0.28 * fadeOpacity})`;
this.ctx.lineWidth = 1.5; this.ctx.lineWidth = 1.1;
this.ctx.stroke(); this.ctx.stroke();
} }
} }

0
systades.db Normal file
View File

View File

@@ -14,11 +14,12 @@
<meta name="keywords" content="systades, wissen, visualisierung, lernen, gedanken, theorie"> <meta name="keywords" content="systades, wissen, visualisierung, lernen, gedanken, theorie">
<meta name="author" content="Systades-Team"> <meta name="author" content="Systades-Team">
<!-- Tailwind CSS - Beide Optionen verfügbar --> <!-- Tailwind CSS - CDN für Entwicklung und Produktion (laut Vorgabe) -->
<script src="https://cdn.tailwindcss.com"></script> <script src="https://cdn.tailwindcss.com"></script>
<!-- Alternative lokale Version, falls die CDN-Version blockiert wird --> <!-- Alternative lokale Version, falls die CDN-Version blockiert wird -->
<link href="{{ url_for('static', filename='css/tailwind.min.css') }}" rel="stylesheet"> <link href="{{ url_for('static', filename='css/tailwind.min.css') }}" rel="stylesheet">
<script> <script>
tailwind = window.tailwind || {};
tailwind.config = { tailwind.config = {
darkMode: 'class', darkMode: 'class',
theme: { theme: {
@@ -113,32 +114,33 @@
<!-- Custom dark mode styles --> <!-- Custom dark mode styles -->
<style> <style>
/* Dark mystical theme */ /* Dezenter Hintergrund für beide Modi */
.dark { .dark {
--bg-primary: #0a0e19; --bg-primary: #181c24;
--bg-secondary: #111827; --bg-secondary: #232837;
--text-primary: #f9fafb; --text-primary: #f9fafb;
--text-secondary: #e5e7eb; --text-secondary: #e5e7eb;
--accent-primary: #6d28d9; --accent-primary: #6d28d9;
--accent-secondary: #8b5cf6; --accent-secondary: #8b5cf6;
--glow-effect: 0 0 15px rgba(124, 58, 237, 0.5); --glow-effect: 0 0 8px rgba(124, 58, 237, 0.15);
} }
/* Light theme with mystical tones */
:root { :root {
--bg-primary: #f8fafc; --bg-primary: #f4f6fa;
--bg-secondary: #f1f5f9; --bg-secondary: #e9ecf3;
--text-primary: #1e293b; --text-primary: #232837;
--text-secondary: #475569; --text-secondary: #475569;
--accent-primary: #7c3aed; --accent-primary: #7c3aed;
--accent-secondary: #8b5cf6; --accent-secondary: #8b5cf6;
--glow-effect: 0 0 15px rgba(139, 92, 246, 0.3); --glow-effect: 0 0 8px rgba(139, 92, 246, 0.08);
} }
body.dark { body.dark {
background-color: var(--bg-primary); background-color: var(--bg-primary);
color: var(--text-primary); color: var(--text-primary);
} }
body {
background-color: var(--bg-primary);
color: var(--text-primary);
}
/* Mystical glowing effects */ /* Mystical glowing effects */
.mystical-glow { .mystical-glow {
@@ -611,5 +613,38 @@
} }
}); });
</script> </script>
<!-- Dark/Light-Mode persistent und robust -->
<script>
(function() {
function applyMode(mode) {
if (mode === 'dark') {
document.documentElement.classList.add('dark');
localStorage.setItem('colorMode', 'dark');
} else {
document.documentElement.classList.remove('dark');
localStorage.setItem('colorMode', 'light');
}
}
// Beim Laden: Präferenz aus localStorage oder System übernehmen
const stored = localStorage.getItem('colorMode');
if (stored === 'dark' || stored === 'light') {
applyMode(stored);
} else {
// Systempräferenz als Fallback
const prefersDark = window.matchMedia('(prefers-color-scheme: dark)').matches;
applyMode(prefersDark ? 'dark' : 'light');
}
// Umschalter für alle Mode-Toggles
window.toggleColorMode = function() {
const isDark = document.documentElement.classList.contains('dark');
applyMode(isDark ? 'light' : 'dark');
};
// Optional: globales Event für andere Skripte
window.addEventListener('storage', function(e) {
if (e.key === 'colorMode') applyMode(e.newValue);
});
})();
</script>
</body> </body>
</html> </html>

View File

@@ -391,7 +391,7 @@
<div id="mindmap-canvas"></div> <div id="mindmap-canvas"></div>
<!-- Control Panel --> <!-- Control Panel -->
<div class="control-panel p-4 w-64"> <div class="control-panel p-4 w-64" x-data="{ isExpanded: true }">
<div class="panel-toggle" @click="isExpanded = !isExpanded"> <div class="panel-toggle" @click="isExpanded = !isExpanded">
<i class="fa-solid" :class="isExpanded ? 'fa-chevron-left' : 'fa-chevron-right'"></i> <i class="fa-solid" :class="isExpanded ? 'fa-chevron-left' : 'fa-chevron-right'"></i>
</div> </div>

View File

@@ -1,5 +1,5 @@
home = /usr/bin home = C:\Program Files\Python313
include-system-site-packages = false include-system-site-packages = false
version = 3.11.2 version = 3.13.3
executable = /usr/bin/python3.11 executable = C:\Program Files\Python313\python.exe
command = /usr/bin/python3.11 -m venv /home/core/dev/website/venv command = C:\Program Files\Python313\python.exe -m venv C:\Users\TTOMCZA.EMEA\Dev\website\venv