Compare commits
7 Commits
256d38e140
...
fab8d10f03
| Author | SHA1 | Date | |
|---|---|---|---|
| fab8d10f03 | |||
| dec30e4681 | |||
| a1bd999c6a | |||
| b1d33ce643 | |||
| 293f877017 | |||
| e86d0b0f90 | |||
| 059fd167d6 |
Binary file not shown.
Binary file not shown.
865
app.py
865
app.py
@@ -26,6 +26,7 @@ import sqlalchemy
|
||||
import ssl
|
||||
import certifi
|
||||
import os
|
||||
from sqlalchemy.orm import joinedload
|
||||
|
||||
# Modelle importieren
|
||||
from models import (
|
||||
@@ -277,7 +278,7 @@ def create_default_categories():
|
||||
"icon": "fa-palette",
|
||||
"subcategories": [
|
||||
{"name": "Literatur", "description": "Schriftliche Werke", "icon": "fa-book"},
|
||||
{"name": "Musik", "description": "Klangkunst", "icon": "fa-music"},
|
||||
{"name": "Musik", "description": "Klangkunst", "icon": "fa-musik"},
|
||||
{"name": "Bildende Kunst", "description": "Visuelle Kunstformen", "icon": "fa-paint-brush"}
|
||||
]
|
||||
},
|
||||
@@ -2342,750 +2343,184 @@ if __name__ == '__main__':
|
||||
db.create_all()
|
||||
socketio.run(app, debug=True, host='0.0.0.0')
|
||||
|
||||
@app.route('/api/refresh-mindmap')
|
||||
def refresh_mindmap():
|
||||
"""
|
||||
API-Endpunkt zum Neuladen der Mindmap-Daten,
|
||||
wenn die Datenbank-Verbindung vorübergehend fehlgeschlagen ist
|
||||
"""
|
||||
def get_category_mindmap_data(category_name):
|
||||
"""Generische Funktion zum Abrufen der Mindmap-Daten für eine Kategorie."""
|
||||
try:
|
||||
# Stelle sicher, dass wir Kategorien haben
|
||||
if Category.query.count() == 0:
|
||||
create_default_categories()
|
||||
# Kategorie mit allen Unterkategorien in einer Abfrage laden
|
||||
category = Category.query.filter_by(name=category_name).options(
|
||||
joinedload(Category.children)
|
||||
).first_or_404()
|
||||
|
||||
# Überprüfe, ob wir bereits einen "Wissen"-Knoten haben
|
||||
wissen_node = MindMapNode.query.filter_by(name="Wissen").first()
|
||||
# Basis-Knoten erstellen
|
||||
nodes = [{
|
||||
'id': f'cat_{category.id}',
|
||||
'name': category.name,
|
||||
'description': category.description or '',
|
||||
'color_code': category.color_code or '#9F7AEA',
|
||||
'is_center': True,
|
||||
'has_children': bool(category.children),
|
||||
'icon': category.icon or 'fa-solid fa-circle'
|
||||
}]
|
||||
|
||||
# Wenn kein "Wissen"-Knoten existiert, erstelle ihn
|
||||
if not wissen_node:
|
||||
wissen_node = MindMapNode(
|
||||
name="Wissen",
|
||||
description="Zentrale Wissensbasis",
|
||||
color_code="#4299E1",
|
||||
is_public=True
|
||||
)
|
||||
db.session.add(wissen_node)
|
||||
db.session.commit()
|
||||
# Unterkategorien hinzufügen
|
||||
for subcat in category.children:
|
||||
nodes.append({
|
||||
'id': f'cat_{subcat.id}',
|
||||
'name': subcat.name,
|
||||
'description': subcat.description or '',
|
||||
'color_code': subcat.color_code or '#9F7AEA',
|
||||
'category': category_name,
|
||||
'has_children': bool(subcat.children),
|
||||
'icon': subcat.icon or 'fa-solid fa-circle'
|
||||
})
|
||||
|
||||
# Hole alle Kategorien und Knoten
|
||||
categories = Category.query.filter_by(parent_id=None).all()
|
||||
category_tree = [build_category_tree(cat) for cat in categories]
|
||||
|
||||
# Hole alle Mindmap-Knoten außer dem "Wissen"-Knoten
|
||||
nodes = MindMapNode.query.filter(MindMapNode.id != wissen_node.id).all()
|
||||
|
||||
# Vorbereiten der Node- und Edge-Arrays für die Antwort
|
||||
node_data = []
|
||||
edge_data = []
|
||||
|
||||
# Zuerst den "Wissen"-Knoten hinzufügen
|
||||
node_data.append({
|
||||
'id': wissen_node.id,
|
||||
'name': wissen_node.name,
|
||||
'description': wissen_node.description or '',
|
||||
'color_code': wissen_node.color_code or '#4299E1',
|
||||
'thought_count': len(wissen_node.thoughts),
|
||||
'category_id': wissen_node.category_id
|
||||
})
|
||||
|
||||
# Dann die anderen Knoten
|
||||
for node in nodes:
|
||||
node_obj = {
|
||||
'id': node.id,
|
||||
'name': node.name,
|
||||
'description': node.description or '',
|
||||
'color_code': node.color_code or '#9F7AEA',
|
||||
'thought_count': len(node.thoughts),
|
||||
'category_id': node.category_id
|
||||
}
|
||||
|
||||
# Verbinde alle Top-Level-Knoten mit dem Wissen-Knoten
|
||||
if not node.parents.all():
|
||||
edge_data.append({
|
||||
'source': wissen_node.id,
|
||||
'target': node.id
|
||||
})
|
||||
|
||||
# Verbindungen zwischen vorhandenen Knoten hinzufügen
|
||||
node_children = node.children.all()
|
||||
for child in node_children:
|
||||
edge_data.append({
|
||||
'source': node.id,
|
||||
'target': child.id
|
||||
})
|
||||
|
||||
node_data.append(node_obj)
|
||||
# Kanten erstellen (vereinheitlichte Schlüssel)
|
||||
edges = [{
|
||||
'source': f'cat_{category.id}',
|
||||
'target': f'cat_{subcat.id}',
|
||||
'strength': 0.8
|
||||
} for subcat in category.children]
|
||||
|
||||
return jsonify({
|
||||
'success': True,
|
||||
'categories': category_tree,
|
||||
'nodes': node_data,
|
||||
'edges': edge_data
|
||||
'nodes': nodes,
|
||||
'edges': edges
|
||||
})
|
||||
|
||||
except Exception as e:
|
||||
print(f"Fehler beim Neuladen der Mindmap: {str(e)}")
|
||||
print(f"Fehler beim Abrufen der {category_name}-Mindmap: {str(e)}")
|
||||
return jsonify({
|
||||
'success': False,
|
||||
'error': 'Datenbankverbindung konnte nicht hergestellt werden'
|
||||
'error': f'{category_name}-Mindmap konnte nicht geladen werden',
|
||||
'details': str(e)
|
||||
}), 500
|
||||
|
||||
# Die Route '/mindmap' wird bereits in Zeile 474 definiert - doppelte Definition entfernt
|
||||
|
||||
# Weiterleitung für Community/Forum-Routen
|
||||
@app.route('/community')
|
||||
@app.route('/Community')
|
||||
@app.route('/forum')
|
||||
@app.route('/Forum')
|
||||
@app.route('/community_forum')
|
||||
def redirect_community():
|
||||
"""Leitet alle Community/Forum-URLs zur Startseite um"""
|
||||
return redirect(url_for('index'))
|
||||
|
||||
@app.route('/static/js/mindmap-init.js')
|
||||
def serve_mindmap_init_js():
|
||||
"""Bedient die Mindmap-Initialisierungsdatei."""
|
||||
return app.send_static_file('js/mindmap-init.js'), 200, {'Content-Type': 'application/javascript'}
|
||||
|
||||
# Datenbank-Update-Route (admin-geschützt)
|
||||
@app.route('/admin/update-database', methods=['GET', 'POST'])
|
||||
@admin_required
|
||||
def admin_update_database():
|
||||
"""Admin-Route zum Aktualisieren der Datenbank"""
|
||||
message = None
|
||||
success = None
|
||||
|
||||
if request.method == 'POST':
|
||||
try:
|
||||
import utils.update_db as update_db
|
||||
update_success = update_db.update_user_table()
|
||||
if update_success:
|
||||
message = "Die Datenbank wurde erfolgreich aktualisiert."
|
||||
success = True
|
||||
else:
|
||||
message = "Es gab ein Problem bei der Aktualisierung der Datenbank."
|
||||
success = False
|
||||
except Exception as e:
|
||||
message = f"Fehler: {str(e)}"
|
||||
success = False
|
||||
|
||||
return render_template('admin/update_database.html', message=message, success=success)
|
||||
|
||||
@app.route('/api/mindmap/<node_id>')
|
||||
def get_mindmap_data(node_id):
|
||||
"""
|
||||
Stellt Mindmap-Daten für das Frontend bereit.
|
||||
Liefert für 'root' die Hauptebene und für andere Node-IDs die entsprechenden Unterknoten.
|
||||
Daten werden aus der Datenbank abgerufen.
|
||||
"""
|
||||
app.logger.info(f"Mindmap-Daten werden für Node '{node_id}' angefordert.")
|
||||
|
||||
@app.route('/api/mindmap/root')
|
||||
def get_root_mindmap_data():
|
||||
"""Liefert die Daten für die Root-Mindmap."""
|
||||
try:
|
||||
# Fallback-Daten falls Datenbankzugriff fehlschlägt
|
||||
fallback_data = get_fallback_mindmap_data(node_id)
|
||||
# Hauptkategorien mit Unterkategorien in einer Abfrage laden
|
||||
categories = Category.query.filter_by(parent_id=None).options(
|
||||
joinedload(Category.children)
|
||||
).all()
|
||||
|
||||
if node_id == 'root':
|
||||
# Hauptebene der Mindmap - finde den "Wissen"-Knoten und seine Verbindungen
|
||||
wissen_node = MindMapNode.query.filter_by(name="Wissen").first()
|
||||
|
||||
if not wissen_node:
|
||||
app.logger.warning("'Wissen'-Knoten nicht in der Datenbank gefunden, Fallback zu Hardcoded-Daten.")
|
||||
return jsonify(fallback_data)
|
||||
|
||||
# Zentrum der Mindmap ist der "Wissen"-Knoten
|
||||
nodes = [{
|
||||
"id": str(wissen_node.id),
|
||||
"name": "Wissenskarte", # Frontend-Name für Root-Knoten
|
||||
"description": wissen_node.description or "Zentrale Wissenskarte mit allen Hauptthemen",
|
||||
"is_center": True,
|
||||
"color_code": "#f5f5f5",
|
||||
"has_children": True
|
||||
}]
|
||||
|
||||
# Hauptkategorien als Knoten
|
||||
main_categories = Category.query.filter_by(parent_id=None).all()
|
||||
category_nodes = []
|
||||
edges = []
|
||||
|
||||
for category in main_categories:
|
||||
category_node = {
|
||||
"id": f"cat_{category.id}",
|
||||
"name": category.name,
|
||||
"description": category.description or f"Kategorie: {category.name}",
|
||||
"category": category.name,
|
||||
"has_children": True,
|
||||
"color_code": category.color_code or "#9F7AEA"
|
||||
}
|
||||
category_nodes.append(category_node)
|
||||
|
||||
# Verbindung vom Wissen-Knoten zur Kategorie
|
||||
edges.append({
|
||||
"source_id": str(wissen_node.id),
|
||||
"target_id": f"cat_{category.id}",
|
||||
"strength": 0.9
|
||||
})
|
||||
|
||||
nodes.extend(category_nodes)
|
||||
|
||||
response = {
|
||||
"nodes": nodes,
|
||||
"edges": edges
|
||||
}
|
||||
|
||||
app.logger.info(f"Mindmap-Daten für 'root' erfolgreich aus Datenbank geladen. {len(nodes)} Knoten gefunden.")
|
||||
return jsonify(response)
|
||||
|
||||
elif node_id.startswith('cat_'):
|
||||
# Unterkategorien einer Hauptkategorie anzeigen
|
||||
category_id = node_id.replace('cat_', '')
|
||||
try:
|
||||
category_id = int(category_id)
|
||||
category = Category.query.get(category_id)
|
||||
|
||||
if not category:
|
||||
app.logger.warning(f"Kategorie mit ID {category_id} nicht gefunden.")
|
||||
return jsonify(fallback_data)
|
||||
|
||||
nodes = []
|
||||
edges = []
|
||||
|
||||
# Unterkategorien dieser Kategorie
|
||||
subcategories = Category.query.filter_by(parent_id=category_id).all()
|
||||
|
||||
for subcat in subcategories:
|
||||
subcat_node = {
|
||||
"id": f"subcat_{subcat.id}",
|
||||
"name": subcat.name,
|
||||
"description": subcat.description or f"Unterkategorie: {subcat.name}",
|
||||
"category": category.name,
|
||||
"has_children": True,
|
||||
"color_code": subcat.color_code or category.color_code
|
||||
}
|
||||
nodes.append(subcat_node)
|
||||
|
||||
# Verbindung von der Hauptkategorie zur Unterkategorie
|
||||
edges.append({
|
||||
"source_id": node_id,
|
||||
"target_id": f"subcat_{subcat.id}",
|
||||
"strength": 0.8
|
||||
})
|
||||
|
||||
# Wenn es keine Unterkategorien gibt, zeige verwandte Knoten
|
||||
if not subcategories:
|
||||
# Im Fallback-Modus zurückfallen
|
||||
app.logger.info(f"Keine Unterkategorien für Kategorie {category.name} gefunden, verwende Fallback-Daten.")
|
||||
return jsonify(fallback_data)
|
||||
|
||||
response = {
|
||||
"nodes": nodes,
|
||||
"edges": edges
|
||||
}
|
||||
|
||||
return jsonify(response)
|
||||
|
||||
except (ValueError, TypeError):
|
||||
app.logger.error(f"Ungültige Kategorie-ID: {category_id}")
|
||||
return jsonify(fallback_data)
|
||||
# Basis-Knoten erstellen
|
||||
nodes = [{
|
||||
'id': 'root',
|
||||
'name': 'Wissen',
|
||||
'description': 'Zentrale Wissensbasis',
|
||||
'color_code': '#4299E1',
|
||||
'is_center': True,
|
||||
'has_children': bool(categories),
|
||||
'icon': 'fa-solid fa-circle'
|
||||
}]
|
||||
|
||||
else:
|
||||
# Versuche, einen MindMapNode mit der gegebenen ID zu finden
|
||||
try:
|
||||
node_id_int = int(node_id)
|
||||
node = MindMapNode.query.get(node_id_int)
|
||||
|
||||
if node:
|
||||
# Zeige Gedanken oder verwandte Knoten
|
||||
# Hier würden wir verwandte Knoten aus der Datenbank laden
|
||||
# Für den Moment verwenden wir Fallback-Daten
|
||||
app.logger.info(f"Knoten {node.name} gefunden, aber keine spezifische Verarbeitung implementiert.")
|
||||
return jsonify(fallback_data)
|
||||
|
||||
except (ValueError, TypeError):
|
||||
# Wenn die ID kein Integer ist, verwende das bisherige Verhalten
|
||||
app.logger.info(f"Falle auf bisheriges Verhalten für Node ID '{node_id}' zurück.")
|
||||
return jsonify(fallback_data)
|
||||
# Kategorien als Knoten hinzufügen
|
||||
for category in categories:
|
||||
nodes.append({
|
||||
'id': f'cat_{category.id}',
|
||||
'name': category.name,
|
||||
'description': category.description or '',
|
||||
'color_code': category.color_code or '#9F7AEA',
|
||||
'category': category.name,
|
||||
'has_children': bool(category.children),
|
||||
'icon': category.icon or 'fa-solid fa-circle'
|
||||
})
|
||||
|
||||
# Wenn wir hier ankommen, gibt es keine spezifische Verarbeitung für diese node_id
|
||||
return jsonify(fallback_data)
|
||||
# Kanten erstellen (vereinheitlichte Schlüssel)
|
||||
edges = [{
|
||||
'source': 'root',
|
||||
'target': f'cat_{category.id}',
|
||||
'strength': 0.8
|
||||
} for category in categories]
|
||||
|
||||
return jsonify({
|
||||
'success': True,
|
||||
'nodes': nodes,
|
||||
'edges': edges
|
||||
})
|
||||
except Exception as e:
|
||||
app.logger.error(f"Fehler beim Abrufen der Mindmap-Daten: {str(e)}")
|
||||
app.logger.error(f"Stack Trace: {traceback.format_exc()}")
|
||||
return jsonify({"error": "Fehler beim Abrufen der Mindmap-Daten"}), 500
|
||||
print(f"Fehler beim Abrufen der Root-Mindmap: {str(e)}")
|
||||
return jsonify({
|
||||
'success': False,
|
||||
'error': 'Root-Mindmap konnte nicht geladen werden',
|
||||
'details': str(e)
|
||||
}), 500
|
||||
|
||||
|
||||
def get_fallback_mindmap_data(node_id):
|
||||
"""
|
||||
Liefert Fallback-Daten für die Mindmap, wenn die Datenbank nicht verfügbar ist.
|
||||
"""
|
||||
if node_id == 'root':
|
||||
# Hauptebene der Mindmap
|
||||
nodes = [
|
||||
{
|
||||
"id": "center",
|
||||
"name": "Wissenskarte",
|
||||
"description": "Zentrale Wissenskarte mit allen Hauptthemen",
|
||||
"is_center": True,
|
||||
"color_code": "#f5f5f5",
|
||||
"has_children": True
|
||||
},
|
||||
{
|
||||
"id": "philosophy",
|
||||
"name": "Philosophie",
|
||||
"description": "Die Lehre vom Denken und der Erkenntnis",
|
||||
"category": "Philosophie",
|
||||
"has_children": True,
|
||||
"color_code": "#9F7AEA"
|
||||
},
|
||||
{
|
||||
"id": "science",
|
||||
"name": "Wissenschaft",
|
||||
"description": "Systematische Erforschung der Natur und Gesellschaft",
|
||||
"category": "Wissenschaft",
|
||||
"has_children": True,
|
||||
"color_code": "#f4b400"
|
||||
},
|
||||
{
|
||||
"id": "technology",
|
||||
"name": "Technologie",
|
||||
"description": "Anwendung wissenschaftlicher Erkenntnisse",
|
||||
"category": "Technologie",
|
||||
"has_children": True,
|
||||
"color_code": "#0d47a1"
|
||||
},
|
||||
{
|
||||
"id": "arts",
|
||||
"name": "Künste",
|
||||
"description": "Kreativer Ausdruck und künstlerische Gestaltung",
|
||||
"category": "Künste",
|
||||
"has_children": True,
|
||||
"color_code": "#c2185b"
|
||||
}
|
||||
]
|
||||
|
||||
edges = [
|
||||
{"source_id": "center", "target_id": "philosophy", "strength": 0.9},
|
||||
{"source_id": "center", "target_id": "science", "strength": 0.9},
|
||||
{"source_id": "center", "target_id": "technology", "strength": 0.9},
|
||||
{"source_id": "center", "target_id": "arts", "strength": 0.9}
|
||||
]
|
||||
|
||||
elif node_id == 'philosophy':
|
||||
nodes = [
|
||||
{
|
||||
"id": "epistemology",
|
||||
"name": "Erkenntnistheorie",
|
||||
"description": "Untersuchung der Natur und Grenzen menschlicher Erkenntnis",
|
||||
"category": "Philosophie",
|
||||
"has_children": True,
|
||||
"color_code": "#9F7AEA"
|
||||
},
|
||||
{
|
||||
"id": "ethics",
|
||||
"name": "Ethik",
|
||||
"description": "Lehre vom moralisch richtigen Handeln",
|
||||
"category": "Philosophie",
|
||||
"has_children": True,
|
||||
"color_code": "#9F7AEA"
|
||||
},
|
||||
{
|
||||
"id": "metaphysics",
|
||||
"name": "Metaphysik",
|
||||
"description": "Grundfragen des Seins und der Wirklichkeit",
|
||||
"category": "Philosophie",
|
||||
"has_children": True,
|
||||
"color_code": "#9F7AEA"
|
||||
}
|
||||
]
|
||||
|
||||
edges = [
|
||||
{"source_id": "philosophy", "target_id": "epistemology", "strength": 0.8},
|
||||
{"source_id": "philosophy", "target_id": "ethics", "strength": 0.8},
|
||||
{"source_id": "philosophy", "target_id": "metaphysics", "strength": 0.8}
|
||||
]
|
||||
|
||||
elif node_id == 'science':
|
||||
nodes = [
|
||||
{
|
||||
"id": "physics",
|
||||
"name": "Physik",
|
||||
"description": "Lehre von der Materie und ihren Wechselwirkungen",
|
||||
"category": "Wissenschaft",
|
||||
"has_children": True,
|
||||
"color_code": "#f4b400"
|
||||
},
|
||||
{
|
||||
"id": "biology",
|
||||
"name": "Biologie",
|
||||
"description": "Lehre von den Lebewesen und ihren Lebensprozessen",
|
||||
"category": "Wissenschaft",
|
||||
"has_children": True,
|
||||
"color_code": "#f4b400"
|
||||
},
|
||||
{
|
||||
"id": "chemistry",
|
||||
"name": "Chemie",
|
||||
"description": "Wissenschaft von den Stoffen und ihren Reaktionen",
|
||||
"category": "Wissenschaft",
|
||||
"has_children": True,
|
||||
"color_code": "#f4b400"
|
||||
}
|
||||
]
|
||||
|
||||
edges = [
|
||||
{"source_id": "science", "target_id": "physics", "strength": 0.8},
|
||||
{"source_id": "science", "target_id": "biology", "strength": 0.8},
|
||||
{"source_id": "science", "target_id": "chemistry", "strength": 0.8}
|
||||
]
|
||||
|
||||
elif node_id == 'technology':
|
||||
nodes = [
|
||||
{
|
||||
"id": "ai",
|
||||
"name": "Künstliche Intelligenz",
|
||||
"description": "Maschinelles Lernen und intelligente Systeme",
|
||||
"category": "Technologie",
|
||||
"has_children": True,
|
||||
"color_code": "#0d47a1"
|
||||
},
|
||||
{
|
||||
"id": "robotics",
|
||||
"name": "Robotik",
|
||||
"description": "Entwicklung und Steuerung von Robotern",
|
||||
"category": "Technologie",
|
||||
"has_children": True,
|
||||
"color_code": "#0d47a1"
|
||||
},
|
||||
{
|
||||
"id": "quantum_computing",
|
||||
"name": "Quantencomputing",
|
||||
"description": "Computer basierend auf Quantenmechanik",
|
||||
"category": "Technologie",
|
||||
"has_children": True,
|
||||
"color_code": "#0d47a1"
|
||||
}
|
||||
]
|
||||
|
||||
edges = [
|
||||
{"source_id": "technology", "target_id": "ai", "strength": 0.8},
|
||||
{"source_id": "technology", "target_id": "robotics", "strength": 0.8},
|
||||
{"source_id": "technology", "target_id": "quantum_computing", "strength": 0.8}
|
||||
]
|
||||
|
||||
elif node_id == 'arts':
|
||||
nodes = [
|
||||
{
|
||||
"id": "visual_arts",
|
||||
"name": "Bildende Kunst",
|
||||
"description": "Malerei, Bildhauerei und andere visuelle Kunstformen",
|
||||
"category": "Künste",
|
||||
"has_children": True,
|
||||
"color_code": "#c2185b"
|
||||
},
|
||||
{
|
||||
"id": "music",
|
||||
"name": "Musik",
|
||||
"description": "Tonkunst und musikalische Komposition",
|
||||
"category": "Künste",
|
||||
"has_children": True,
|
||||
"color_code": "#c2185b"
|
||||
},
|
||||
{
|
||||
"id": "literature",
|
||||
"name": "Literatur",
|
||||
"description": "Schriftliche Kunstwerke und Poesie",
|
||||
"category": "Künste",
|
||||
"has_children": True,
|
||||
"color_code": "#c2185b"
|
||||
}
|
||||
]
|
||||
|
||||
edges = [
|
||||
{"source_id": "arts", "target_id": "visual_arts", "strength": 0.8},
|
||||
{"source_id": "arts", "target_id": "music", "strength": 0.8},
|
||||
{"source_id": "arts", "target_id": "literature", "strength": 0.8}
|
||||
]
|
||||
|
||||
else:
|
||||
# Für jede andere Node-ID geben wir eine leere Struktur zurück
|
||||
nodes = []
|
||||
edges = []
|
||||
|
||||
# Antwort zusammenstellen
|
||||
return {
|
||||
"nodes": nodes,
|
||||
"edges": edges
|
||||
}
|
||||
|
||||
# Diese Routen wurden an den Anfang der Datei verschoben und werden nicht mehr benötigt
|
||||
# Spezifische Routen für Kategorien
|
||||
@app.route('/api/mindmap/philosophy')
|
||||
def get_philosophy_mindmap_data():
|
||||
return get_category_mindmap_data('Philosophie')
|
||||
|
||||
@app.route('/api/mindmap/science')
|
||||
def get_science_mindmap():
|
||||
"""
|
||||
Gibt die Wissenschafts-Mindmap zurück für Frontend-Kompatibilität.
|
||||
"""
|
||||
app.logger.info("Wissenschafts-Mindmap-Daten werden angefordert.")
|
||||
|
||||
try:
|
||||
nodes = [
|
||||
{
|
||||
"id": "physics",
|
||||
"name": "Physik",
|
||||
"description": "Lehre von der Materie und ihren Wechselwirkungen",
|
||||
"category": "Wissenschaft",
|
||||
"has_children": True,
|
||||
"color_code": "#f4b400"
|
||||
},
|
||||
{
|
||||
"id": "biology",
|
||||
"name": "Biologie",
|
||||
"description": "Lehre von den Lebewesen und ihren Lebensprozessen",
|
||||
"category": "Wissenschaft",
|
||||
"has_children": True,
|
||||
"color_code": "#f4b400"
|
||||
},
|
||||
{
|
||||
"id": "chemistry",
|
||||
"name": "Chemie",
|
||||
"description": "Wissenschaft von den Stoffen und ihren Reaktionen",
|
||||
"category": "Wissenschaft",
|
||||
"has_children": True,
|
||||
"color_code": "#f4b400"
|
||||
}
|
||||
]
|
||||
|
||||
edges = [
|
||||
{"source_id": "science", "target_id": "physics", "strength": 0.8},
|
||||
{"source_id": "science", "target_id": "biology", "strength": 0.8},
|
||||
{"source_id": "science", "target_id": "chemistry", "strength": 0.8}
|
||||
]
|
||||
|
||||
return jsonify({
|
||||
"nodes": nodes,
|
||||
"edges": edges
|
||||
})
|
||||
|
||||
except Exception as e:
|
||||
app.logger.error(f"Fehler beim Abrufen der Wissenschafts-Mindmap-Daten: {str(e)}")
|
||||
return jsonify({"error": "Fehler beim Abrufen der Mindmap-Daten"}), 500
|
||||
|
||||
@app.route('/api/mindmap/root')
|
||||
def get_root_mindmap():
|
||||
"""
|
||||
Gibt die Root-Mindmap zurück, um Kompatibilität mit dem Frontend sicherzustellen.
|
||||
"""
|
||||
app.logger.info("Root-Mindmap-Daten werden angefordert.")
|
||||
|
||||
try:
|
||||
# Fallback-Daten
|
||||
nodes = [
|
||||
{
|
||||
"id": "center",
|
||||
"name": "Wissenskarte",
|
||||
"description": "Zentrale Wissenskarte mit allen Hauptthemen",
|
||||
"is_center": True,
|
||||
"color_code": "#f5f5f5",
|
||||
"has_children": True
|
||||
},
|
||||
{
|
||||
"id": "philosophy",
|
||||
"name": "Philosophie",
|
||||
"description": "Die Lehre vom Denken und der Erkenntnis",
|
||||
"category": "Philosophie",
|
||||
"has_children": True,
|
||||
"color_code": "#9F7AEA"
|
||||
},
|
||||
{
|
||||
"id": "science",
|
||||
"name": "Wissenschaft",
|
||||
"description": "Systematische Erforschung der Natur und Gesellschaft",
|
||||
"category": "Wissenschaft",
|
||||
"has_children": True,
|
||||
"color_code": "#f4b400"
|
||||
},
|
||||
{
|
||||
"id": "technology",
|
||||
"name": "Technologie",
|
||||
"description": "Anwendung wissenschaftlicher Erkenntnisse",
|
||||
"category": "Technologie",
|
||||
"has_children": True,
|
||||
"color_code": "#0d47a1"
|
||||
},
|
||||
{
|
||||
"id": "arts",
|
||||
"name": "Künste",
|
||||
"description": "Kreativer Ausdruck und künstlerische Gestaltung",
|
||||
"category": "Künste",
|
||||
"has_children": True,
|
||||
"color_code": "#c2185b"
|
||||
}
|
||||
]
|
||||
|
||||
edges = [
|
||||
{"source_id": "center", "target_id": "philosophy", "strength": 0.9},
|
||||
{"source_id": "center", "target_id": "science", "strength": 0.9},
|
||||
{"source_id": "center", "target_id": "technology", "strength": 0.9},
|
||||
{"source_id": "center", "target_id": "arts", "strength": 0.9}
|
||||
]
|
||||
|
||||
response = {
|
||||
"nodes": nodes,
|
||||
"edges": edges
|
||||
}
|
||||
|
||||
return jsonify(response)
|
||||
|
||||
except Exception as e:
|
||||
app.logger.error(f"Fehler beim Abrufen der Root-Mindmap-Daten: {str(e)}")
|
||||
app.logger.error(f"Stack Trace: {traceback.format_exc()}")
|
||||
return jsonify({"error": "Fehler beim Abrufen der Mindmap-Daten"}), 500
|
||||
def get_science_mindmap_data():
|
||||
return get_category_mindmap_data('Wissenschaft')
|
||||
|
||||
@app.route('/api/mindmap/technology')
|
||||
def get_technology_mindmap():
|
||||
"""
|
||||
Gibt die Technologie-Mindmap zurück für Frontend-Kompatibilität.
|
||||
"""
|
||||
app.logger.info("Technologie-Mindmap-Daten werden angefordert.")
|
||||
|
||||
try:
|
||||
nodes = [
|
||||
{
|
||||
"id": "ai",
|
||||
"name": "Künstliche Intelligenz",
|
||||
"description": "Maschinelles Lernen und intelligente Systeme",
|
||||
"category": "Technologie",
|
||||
"has_children": True,
|
||||
"color_code": "#0d47a1"
|
||||
},
|
||||
{
|
||||
"id": "robotics",
|
||||
"name": "Robotik",
|
||||
"description": "Entwicklung und Steuerung von Robotern",
|
||||
"category": "Technologie",
|
||||
"has_children": True,
|
||||
"color_code": "#0d47a1"
|
||||
},
|
||||
{
|
||||
"id": "quantum_computing",
|
||||
"name": "Quantencomputing",
|
||||
"description": "Computer basierend auf Quantenmechanik",
|
||||
"category": "Technologie",
|
||||
"has_children": True,
|
||||
"color_code": "#0d47a1"
|
||||
}
|
||||
]
|
||||
|
||||
edges = [
|
||||
{"source_id": "technology", "target_id": "ai", "strength": 0.8},
|
||||
{"source_id": "technology", "target_id": "robotics", "strength": 0.8},
|
||||
{"source_id": "technology", "target_id": "quantum_computing", "strength": 0.8}
|
||||
]
|
||||
|
||||
return jsonify({
|
||||
"nodes": nodes,
|
||||
"edges": edges
|
||||
})
|
||||
|
||||
except Exception as e:
|
||||
app.logger.error(f"Fehler beim Abrufen der Technologie-Mindmap-Daten: {str(e)}")
|
||||
return jsonify({"error": "Fehler beim Abrufen der Mindmap-Daten"}), 500
|
||||
def get_technology_mindmap_data():
|
||||
return get_category_mindmap_data('Technologie')
|
||||
|
||||
@app.route('/api/mindmap/arts')
|
||||
def get_arts_mindmap():
|
||||
"""
|
||||
Gibt die Künste-Mindmap zurück für Frontend-Kompatibilität.
|
||||
"""
|
||||
app.logger.info("Künste-Mindmap-Daten werden angefordert.")
|
||||
|
||||
try:
|
||||
nodes = [
|
||||
{
|
||||
"id": "visual_arts",
|
||||
"name": "Bildende Kunst",
|
||||
"description": "Malerei, Bildhauerei und andere visuelle Kunstformen",
|
||||
"category": "Künste",
|
||||
"has_children": True,
|
||||
"color_code": "#c2185b"
|
||||
},
|
||||
{
|
||||
"id": "music",
|
||||
"name": "Musik",
|
||||
"description": "Tonkunst und musikalische Komposition",
|
||||
"category": "Künste",
|
||||
"has_children": True,
|
||||
"color_code": "#c2185b"
|
||||
},
|
||||
{
|
||||
"id": "literature",
|
||||
"name": "Literatur",
|
||||
"description": "Schriftliche Kunstwerke und Poesie",
|
||||
"category": "Künste",
|
||||
"has_children": True,
|
||||
"color_code": "#c2185b"
|
||||
}
|
||||
]
|
||||
|
||||
edges = [
|
||||
{"source_id": "arts", "target_id": "visual_arts", "strength": 0.8},
|
||||
{"source_id": "arts", "target_id": "music", "strength": 0.8},
|
||||
{"source_id": "arts", "target_id": "literature", "strength": 0.8}
|
||||
]
|
||||
|
||||
return jsonify({
|
||||
"nodes": nodes,
|
||||
"edges": edges
|
||||
})
|
||||
|
||||
except Exception as e:
|
||||
app.logger.error(f"Fehler beim Abrufen der Künste-Mindmap-Daten: {str(e)}")
|
||||
return jsonify({"error": "Fehler beim Abrufen der Mindmap-Daten"}), 500
|
||||
def get_arts_mindmap_data():
|
||||
return get_category_mindmap_data('Künste')
|
||||
|
||||
@app.route('/api/mindmap/philosophy')
|
||||
def get_philosophy_mindmap():
|
||||
"""
|
||||
Gibt die Philosophie-Mindmap zurück für Frontend-Kompatibilität.
|
||||
"""
|
||||
app.logger.info("Philosophie-Mindmap-Daten werden angefordert.")
|
||||
|
||||
# Generische Route für spezifische Knoten
|
||||
@app.route('/api/mindmap/<node_id>')
|
||||
def get_mindmap_data(node_id):
|
||||
"""Liefert die Daten für einen spezifischen Mindmap-Knoten."""
|
||||
try:
|
||||
nodes = [
|
||||
{
|
||||
"id": "epistemology",
|
||||
"name": "Erkenntnistheorie",
|
||||
"description": "Untersuchung der Natur und Grenzen menschlicher Erkenntnis",
|
||||
"category": "Philosophie",
|
||||
"has_children": True,
|
||||
"color_code": "#9F7AEA"
|
||||
},
|
||||
{
|
||||
"id": "ethics",
|
||||
"name": "Ethik",
|
||||
"description": "Lehre vom moralisch richtigen Handeln",
|
||||
"category": "Philosophie",
|
||||
"has_children": True,
|
||||
"color_code": "#9F7AEA"
|
||||
},
|
||||
{
|
||||
"id": "metaphysics",
|
||||
"name": "Metaphysik",
|
||||
"description": "Grundfragen des Seins und der Wirklichkeit",
|
||||
"category": "Philosophie",
|
||||
"has_children": True,
|
||||
"color_code": "#9F7AEA"
|
||||
}
|
||||
]
|
||||
# Prüfen, ob es sich um eine spezielle Route handelt
|
||||
if node_id in ['root', 'philosophy', 'science', 'technology', 'arts']:
|
||||
return jsonify({
|
||||
'success': False,
|
||||
'error': 'Ungültige Knoten-ID',
|
||||
'details': 'Diese ID ist für spezielle Routen reserviert'
|
||||
}), 400
|
||||
|
||||
# Knoten mit Unterknoten in einer Abfrage laden
|
||||
node = MindMapNode.query.options(
|
||||
joinedload(MindMapNode.children)
|
||||
).get_or_404(node_id)
|
||||
|
||||
edges = [
|
||||
{"source_id": "philosophy", "target_id": "epistemology", "strength": 0.8},
|
||||
{"source_id": "philosophy", "target_id": "ethics", "strength": 0.8},
|
||||
{"source_id": "philosophy", "target_id": "metaphysics", "strength": 0.8}
|
||||
]
|
||||
# Basis-Knoten erstellen
|
||||
nodes = [{
|
||||
'id': str(node.id),
|
||||
'name': node.name,
|
||||
'description': node.description or '',
|
||||
'color_code': node.color_code or '#9F7AEA',
|
||||
'is_center': True,
|
||||
'has_children': bool(node.children),
|
||||
'icon': node.icon or 'fa-solid fa-circle'
|
||||
}]
|
||||
|
||||
# Unterknoten hinzufügen
|
||||
for child in node.children:
|
||||
nodes.append({
|
||||
'id': str(child.id),
|
||||
'name': child.name,
|
||||
'description': child.description or '',
|
||||
'color_code': child.color_code or '#9F7AEA',
|
||||
'category': node.name,
|
||||
'has_children': bool(child.children),
|
||||
'icon': child.icon or 'fa-solid fa-circle'
|
||||
})
|
||||
|
||||
# Kanten erstellen (vereinheitlichte Schlüssel)
|
||||
edges = [{
|
||||
'source': str(node.id),
|
||||
'target': str(child.id),
|
||||
'strength': 0.8
|
||||
} for child in node.children]
|
||||
|
||||
return jsonify({
|
||||
"nodes": nodes,
|
||||
"edges": edges
|
||||
'success': True,
|
||||
'nodes': nodes,
|
||||
'edges': edges
|
||||
})
|
||||
|
||||
except Exception as e:
|
||||
app.logger.error(f"Fehler beim Abrufen der Philosophie-Mindmap-Daten: {str(e)}")
|
||||
return jsonify({"error": "Fehler beim Abrufen der Mindmap-Daten"}), 500
|
||||
print(f"Fehler beim Abrufen der Mindmap-Daten für Knoten {node_id}: {str(e)}")
|
||||
return jsonify({
|
||||
'success': False,
|
||||
'error': 'Mindmap-Daten konnten nicht geladen werden',
|
||||
'details': str(e)
|
||||
}), 500
|
||||
|
||||
|
||||
2526
app.py.bak
Normal file
2526
app.py.bak
Normal file
File diff suppressed because it is too large
Load Diff
BIN
fix_routes.py
Normal file
BIN
fix_routes.py
Normal file
Binary file not shown.
4030
logs/app.log
4030
logs/app.log
File diff suppressed because it is too large
Load Diff
@@ -5,199 +5,260 @@
|
||||
* Implementiert Lazy Loading & Progressive Disclosure
|
||||
*/
|
||||
|
||||
// Mock-Datenbank für Subthemen (später durch echte DB-Abfragen ersetzen)
|
||||
const subthemesDatabase = {
|
||||
'philosophy': [
|
||||
{
|
||||
id: 'epistemology',
|
||||
label: 'Erkenntnistheorie',
|
||||
category: 'Philosophie',
|
||||
description: 'Untersuchung der Natur und Grenzen menschlicher Erkenntnis',
|
||||
hasChildren: true
|
||||
// Neue zentrale Konfiguration
|
||||
const mindmapConfig = {
|
||||
categories: {
|
||||
'Philosophie': {
|
||||
icon: 'fa-solid fa-lightbulb',
|
||||
color: '#b71c1c',
|
||||
description: 'Die Lehre vom Denken und der Erkenntnis'
|
||||
},
|
||||
{
|
||||
id: 'ethics',
|
||||
label: 'Ethik',
|
||||
category: 'Philosophie',
|
||||
description: 'Lehre vom moralisch richtigen Handeln',
|
||||
hasChildren: true
|
||||
'Wissenschaft': {
|
||||
icon: 'fa-solid fa-atom',
|
||||
color: '#f4b400',
|
||||
description: 'Systematische Erforschung der Natur und Gesellschaft'
|
||||
},
|
||||
{
|
||||
id: 'metaphysics',
|
||||
label: 'Metaphysik',
|
||||
category: 'Philosophie',
|
||||
description: 'Grundfragen des Seins und der Wirklichkeit',
|
||||
hasChildren: true
|
||||
'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'
|
||||
}
|
||||
],
|
||||
'science': [
|
||||
{
|
||||
id: 'physics',
|
||||
label: 'Physik',
|
||||
category: 'Wissenschaft',
|
||||
description: 'Lehre von der Materie und ihren Wechselwirkungen',
|
||||
hasChildren: true
|
||||
},
|
||||
{
|
||||
id: 'biology',
|
||||
label: 'Biologie',
|
||||
category: 'Wissenschaft',
|
||||
description: 'Lehre von den Lebewesen und ihren Lebensprozessen',
|
||||
hasChildren: true
|
||||
},
|
||||
{
|
||||
id: 'chemistry',
|
||||
label: 'Chemie',
|
||||
category: 'Wissenschaft',
|
||||
description: 'Wissenschaft von den Stoffen und ihren Reaktionen',
|
||||
hasChildren: true
|
||||
}
|
||||
],
|
||||
'technology': [
|
||||
{
|
||||
id: 'ai',
|
||||
label: 'Künstliche Intelligenz',
|
||||
category: 'Technologie',
|
||||
description: 'Maschinelles Lernen und intelligente Systeme',
|
||||
hasChildren: true
|
||||
},
|
||||
{
|
||||
id: 'robotics',
|
||||
label: 'Robotik',
|
||||
category: 'Technologie',
|
||||
description: 'Entwicklung und Steuerung von Robotern',
|
||||
hasChildren: true
|
||||
},
|
||||
{
|
||||
id: 'quantum_computing',
|
||||
label: 'Quantencomputing',
|
||||
category: 'Technologie',
|
||||
description: 'Computer basierend auf Quantenmechanik',
|
||||
hasChildren: true
|
||||
}
|
||||
],
|
||||
'arts': [
|
||||
{
|
||||
id: 'visual_arts',
|
||||
label: 'Bildende Kunst',
|
||||
category: 'Künste',
|
||||
description: 'Malerei, Bildhauerei und andere visuelle Kunstformen',
|
||||
hasChildren: true
|
||||
},
|
||||
{
|
||||
id: 'music',
|
||||
label: 'Musik',
|
||||
category: 'Künste',
|
||||
description: 'Tonkunst und musikalische Komposition',
|
||||
hasChildren: true
|
||||
},
|
||||
{
|
||||
id: 'literature',
|
||||
label: 'Literatur',
|
||||
category: 'Künste',
|
||||
description: 'Schriftliche Kunstwerke und Poesie',
|
||||
hasChildren: true
|
||||
}
|
||||
]
|
||||
},
|
||||
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'
|
||||
}
|
||||
};
|
||||
|
||||
// Icon-Definitionen für Kategorien (FontAwesome oder SVG-URL)
|
||||
const categoryIcons = {
|
||||
'Philosophie': 'fa-solid fa-lightbulb',
|
||||
'Wissenschaft': 'fa-solid fa-atom',
|
||||
'Technologie': 'fa-solid fa-microchip',
|
||||
'Künste': 'fa-solid fa-palette',
|
||||
'Psychologie': 'fa-solid fa-brain'
|
||||
};
|
||||
|
||||
// Farben für Kategorien (wie im Bild)
|
||||
const categoryColors = {
|
||||
'Philosophie': '#b71c1c', // Rot
|
||||
'Wissenschaft': '#f4b400', // Gelb
|
||||
'Technologie': '#0d47a1', // Blau
|
||||
'Künste': '#c2185b', // Pink
|
||||
'Psychologie': '#009688' // Türkis
|
||||
};
|
||||
|
||||
// Initiale Mindmap-Daten (nur oberste Ebene, mit Icon und Farbe)
|
||||
const mindmapData = {
|
||||
nodes: [
|
||||
{
|
||||
id: 'center',
|
||||
label: 'Wissenskarte',
|
||||
isCenter: true,
|
||||
color: '#f5f5f5',
|
||||
icon: 'fa-solid fa-circle',
|
||||
fontColor: '#222',
|
||||
fontSize: 22,
|
||||
neuronSize: 12,
|
||||
neuronActivity: 1.0
|
||||
// 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
|
||||
},
|
||||
{
|
||||
id: 'philosophy',
|
||||
label: 'Philosophie',
|
||||
category: 'Philosophie',
|
||||
description: 'Die Lehre vom Denken und der Erkenntnis',
|
||||
hasChildren: true,
|
||||
expanded: false,
|
||||
neuronSize: 8,
|
||||
neuronActivity: 0.8,
|
||||
color: categoryColors['Philosophie'],
|
||||
icon: categoryIcons['Philosophie'],
|
||||
fontColor: '#fff',
|
||||
fontSize: 18
|
||||
center: {
|
||||
'background-color': '#f5f5f5',
|
||||
'color': '#222',
|
||||
'font-size': 20,
|
||||
'border-width': 3,
|
||||
'width': 100,
|
||||
'height': 100
|
||||
},
|
||||
{
|
||||
id: 'science',
|
||||
label: 'Wissenschaft',
|
||||
category: 'Wissenschaft',
|
||||
description: 'Systematische Erforschung der Natur und Gesellschaft',
|
||||
hasChildren: true,
|
||||
expanded: false,
|
||||
neuronSize: 8,
|
||||
neuronActivity: 0.8,
|
||||
color: categoryColors['Wissenschaft'],
|
||||
icon: categoryIcons['Wissenschaft'],
|
||||
fontColor: '#fff',
|
||||
fontSize: 18
|
||||
},
|
||||
{
|
||||
id: 'technology',
|
||||
label: 'Technologie',
|
||||
category: 'Technologie',
|
||||
description: 'Anwendung wissenschaftlicher Erkenntnisse',
|
||||
hasChildren: true,
|
||||
expanded: false,
|
||||
neuronSize: 8,
|
||||
neuronActivity: 0.8,
|
||||
color: categoryColors['Technologie'],
|
||||
icon: categoryIcons['Technologie'],
|
||||
fontColor: '#fff',
|
||||
fontSize: 18
|
||||
},
|
||||
{
|
||||
id: 'arts',
|
||||
label: 'Künste',
|
||||
category: 'Künste',
|
||||
description: 'Kreativer Ausdruck und künstlerische Gestaltung',
|
||||
hasChildren: true,
|
||||
expanded: false,
|
||||
neuronSize: 8,
|
||||
neuronActivity: 0.8,
|
||||
color: categoryColors['Künste'],
|
||||
icon: categoryIcons['Künste'],
|
||||
fontColor: '#fff',
|
||||
fontSize: 18
|
||||
selected: {
|
||||
'border-color': '#f59e42',
|
||||
'border-width': 3,
|
||||
'background-opacity': 1
|
||||
}
|
||||
],
|
||||
edges: [
|
||||
{ source: 'center', target: 'philosophy', strength: 0.9 },
|
||||
{ source: 'center', target: 'science', strength: 0.9 },
|
||||
{ source: 'center', target: 'technology', strength: 0.9 },
|
||||
{ source: 'center', target: 'arts', strength: 0.9 }
|
||||
]
|
||||
},
|
||||
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');
|
||||
@@ -257,79 +318,22 @@ document.addEventListener('DOMContentLoaded', function() {
|
||||
style: [
|
||||
{
|
||||
selector: 'node',
|
||||
style: {
|
||||
'background-color': 'data(color)',
|
||||
'label': 'data(label)',
|
||||
'color': 'data(fontColor)',
|
||||
'text-valign': 'center',
|
||||
'text-halign': 'center',
|
||||
'font-size': 'data(fontSize)',
|
||||
'width': function(ele) {
|
||||
return ele.data('isCenter') ? 100 : 80;
|
||||
},
|
||||
'height': function(ele) {
|
||||
return ele.data('isCenter') ? 100 : 80;
|
||||
},
|
||||
'border-width': 2,
|
||||
'border-color': '#ffffff',
|
||||
'border-opacity': 0.8,
|
||||
'shape': 'ellipse',
|
||||
'background-opacity': 0.9,
|
||||
'text-wrap': 'wrap',
|
||||
'text-max-width': 80,
|
||||
'transition-property': 'background-color, border-width',
|
||||
'transition-duration': '0.2s'
|
||||
}
|
||||
style: mindmapStyles.node.base
|
||||
},
|
||||
{
|
||||
selector: 'node[isCenter]',
|
||||
style: {
|
||||
'background-color': '#f5f5f5',
|
||||
'color': '#222',
|
||||
'font-size': 20,
|
||||
'border-width': 3,
|
||||
'width': 100,
|
||||
'height': 100
|
||||
}
|
||||
style: mindmapStyles.node.center
|
||||
},
|
||||
{
|
||||
selector: 'node:selected',
|
||||
style: {
|
||||
'border-color': '#f59e42',
|
||||
'border-width': 3,
|
||||
'background-opacity': 1
|
||||
}
|
||||
style: mindmapStyles.node.selected
|
||||
},
|
||||
{
|
||||
selector: 'edge',
|
||||
style: {
|
||||
'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]
|
||||
}
|
||||
style: mindmapStyles.edge.base
|
||||
}
|
||||
],
|
||||
layout: {
|
||||
name: 'concentric',
|
||||
fit: true,
|
||||
padding: 50,
|
||||
animate: true,
|
||||
concentric: function(node) {
|
||||
return node.data('isCenter') ? 2 : 1;
|
||||
},
|
||||
levelWidth: function() { return 1; }
|
||||
}
|
||||
layout: mindmapStyles.layout.base
|
||||
});
|
||||
|
||||
console.log('Cytoscape initialisiert');
|
||||
@@ -469,63 +473,42 @@ function initializeNeuralDesign(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.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
|
||||
}
|
||||
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
|
||||
}
|
||||
|
||||
// Neue Kanten hinzufügen
|
||||
mindmapData.edges.forEach(edge => {
|
||||
cy.add({
|
||||
group: 'edges',
|
||||
data: {
|
||||
source: edge.source,
|
||||
target: edge.target,
|
||||
strength: edge.strength || 0.5
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
// Neuronales Design initialisieren
|
||||
initializeNeuralDesign(cy);
|
||||
|
||||
// Layout anwenden
|
||||
cy.layout({
|
||||
name: 'cose',
|
||||
animate: true,
|
||||
animationDuration: 1000,
|
||||
nodeDimensionsIncludeLabels: true,
|
||||
padding: 100,
|
||||
spacingFactor: 1.8,
|
||||
randomize: false,
|
||||
fit: true,
|
||||
componentSpacing: 100,
|
||||
nodeRepulsion: 8000,
|
||||
edgeElasticity: 100,
|
||||
nestingFactor: 1.2,
|
||||
gravity: 80
|
||||
}).run();
|
||||
|
||||
// Layout aktualisieren
|
||||
cy.layout(mindmapStyles.layout.base).run();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -764,31 +747,69 @@ function startNeuralActivitySimulation(cy) {
|
||||
|
||||
// Hilfe-Funktion zum Hinzufügen eines Flash-Hinweises
|
||||
function showFlash(message, type = 'info') {
|
||||
const flashContainer = document.getElementById('flash-messages') || createFlashContainer();
|
||||
|
||||
const flashMsg = document.createElement('div');
|
||||
flashMsg.className = `flash-message flash-${type} mb-2 p-3 rounded`;
|
||||
flashMsg.innerHTML = `
|
||||
<div class="flex items-center justify-between">
|
||||
<div>${message}</div>
|
||||
<button class="close-flash ml-2">×</button>
|
||||
</div>
|
||||
`;
|
||||
|
||||
flashContainer.appendChild(flashMsg);
|
||||
|
||||
// Nach 5 Sekunden automatisch ausblenden
|
||||
const flashContainer = createFlashContainer();
|
||||
const flash = document.createElement('div');
|
||||
flash.className = `flash-message ${type}`;
|
||||
flash.textContent = message;
|
||||
flashContainer.appendChild(flash);
|
||||
document.body.appendChild(flashContainer);
|
||||
|
||||
setTimeout(() => {
|
||||
flashMsg.style.opacity = '0';
|
||||
setTimeout(() => flashMsg.remove(), 300);
|
||||
}, 5000);
|
||||
|
||||
// Close-Button
|
||||
const closeBtn = flashMsg.querySelector('.close-flash');
|
||||
closeBtn.addEventListener('click', () => {
|
||||
flashMsg.style.opacity = '0';
|
||||
setTimeout(() => flashMsg.remove(), 300);
|
||||
});
|
||||
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
|
||||
@@ -798,152 +819,6 @@ function createFlashContainer() {
|
||||
container.className = 'fixed top-4 right-4 z-50 w-64';
|
||||
document.body.appendChild(container);
|
||||
return container;
|
||||
}
|
||||
|
||||
// Funktion zum Laden der Mindmap-Daten aus der Datenbank
|
||||
async function loadMindmapData(nodeId = null) {
|
||||
try {
|
||||
let url;
|
||||
// Wir müssen zwischen numerischen IDs und String-IDs unterscheiden
|
||||
if (nodeId === null || nodeId === undefined) {
|
||||
// Wenn keine ID angegeben ist, verwende 'root'
|
||||
url = '/api/mindmap/root';
|
||||
} else if (isNaN(parseInt(nodeId))) {
|
||||
// Für String-IDs wie 'root', 'technology', 'arts' - direkte Route
|
||||
url = `/api/mindmap/${nodeId}`;
|
||||
} else {
|
||||
// Für numerische IDs - neue Route mit /id/ Präfix
|
||||
url = `/api/mindmap/id/${nodeId}`;
|
||||
}
|
||||
|
||||
const response = await fetch(url);
|
||||
if (!response.ok) throw new Error('Fehler beim Laden der Mindmap-Daten');
|
||||
return await response.json();
|
||||
} catch (error) {
|
||||
console.error('Fehler beim Laden der Mindmap-Daten:', error);
|
||||
showFlash('Fehler beim Laden der Mindmap-Daten', 'error');
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
// Funktion zum Initialisieren der Mindmap
|
||||
async function initializeMindmap() {
|
||||
const mindmapData = await loadMindmapData();
|
||||
if (!mindmapData) return;
|
||||
|
||||
const elements = [
|
||||
// Knoten
|
||||
...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: node.is_center ? 20 : 16
|
||||
}
|
||||
})),
|
||||
// Kanten
|
||||
...mindmapData.edges.map(edge => ({
|
||||
data: {
|
||||
source: edge.source_id,
|
||||
target: edge.target_id,
|
||||
strength: edge.strength || 0.5
|
||||
}
|
||||
}))
|
||||
];
|
||||
|
||||
window.cy = cytoscape({
|
||||
container: document.getElementById('cy'),
|
||||
elements: elements,
|
||||
style: [
|
||||
{
|
||||
selector: 'node',
|
||||
style: {
|
||||
'background-color': 'data(color)',
|
||||
'label': 'data(label)',
|
||||
'color': 'data(fontColor)',
|
||||
'text-valign': 'center',
|
||||
'text-halign': 'center',
|
||||
'font-size': 'data(fontSize)',
|
||||
'width': function(ele) {
|
||||
return ele.data('isCenter') ? 100 : 80;
|
||||
},
|
||||
'height': function(ele) {
|
||||
return ele.data('isCenter') ? 100 : 80;
|
||||
},
|
||||
'border-width': 2,
|
||||
'border-color': '#ffffff',
|
||||
'border-opacity': 0.8,
|
||||
'shape': 'ellipse',
|
||||
'background-opacity': 0.9,
|
||||
'text-wrap': 'wrap',
|
||||
'text-max-width': 80,
|
||||
'transition-property': 'background-color, border-width',
|
||||
'transition-duration': '0.2s'
|
||||
}
|
||||
},
|
||||
{
|
||||
selector: 'node[isCenter]',
|
||||
style: {
|
||||
'background-color': '#f5f5f5',
|
||||
'color': '#222',
|
||||
'font-size': 20,
|
||||
'border-width': 3,
|
||||
'width': 100,
|
||||
'height': 100
|
||||
}
|
||||
},
|
||||
{
|
||||
selector: 'node:selected',
|
||||
style: {
|
||||
'border-color': '#f59e42',
|
||||
'border-width': 3,
|
||||
'background-opacity': 1
|
||||
}
|
||||
},
|
||||
{
|
||||
selector: 'edge',
|
||||
style: {
|
||||
'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: {
|
||||
name: 'concentric',
|
||||
fit: true,
|
||||
padding: 50,
|
||||
animate: true,
|
||||
concentric: function(node) {
|
||||
return node.data('isCenter') ? 2 : 1;
|
||||
},
|
||||
levelWidth: function() { return 1; }
|
||||
}
|
||||
});
|
||||
|
||||
// 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);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// Funktion zum Laden der Subthemen
|
||||
@@ -1003,24 +878,7 @@ async function loadSubthemes(node) {
|
||||
}))
|
||||
],
|
||||
style: cy.style(),
|
||||
layout: {
|
||||
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
|
||||
}
|
||||
layout: mindmapStyles.layout.base
|
||||
});
|
||||
|
||||
// Event-Listener für die neue Mindmap
|
||||
@@ -1120,6 +978,99 @@ style.textContent = `
|
||||
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);
|
||||
|
||||
|
||||
1078
static/js/update_mindmap.js.bak
Normal file
1078
static/js/update_mindmap.js.bak
Normal file
File diff suppressed because it is too large
Load Diff
BIN
static/js/update_mindmap.js.new
Normal file
BIN
static/js/update_mindmap.js.new
Normal file
Binary file not shown.
1078
static/js/update_mindmap.js.original
Normal file
1078
static/js/update_mindmap.js.original
Normal file
File diff suppressed because it is too large
Load Diff
BIN
update_routes.py
Normal file
BIN
update_routes.py
Normal file
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Reference in New Issue
Block a user