diff --git a/logs/app.log b/logs/app.log
index a026c04..d65938a 100644
--- a/logs/app.log
+++ b/logs/app.log
@@ -554,3 +554,213 @@ werkzeug.exceptions.NotFound: 404 Not Found: The requested URL was not found on
2025-05-16 20:28:49,108 INFO: Anwendung gestartet [in C:\Users\firem\Desktop\111\Systades\website\app.py:77]
2025-05-16 20:28:50,916 INFO: Anwendung gestartet [in C:\Users\firem\Desktop\111\Systades\website\app.py:77]
2025-05-16 20:28:50,916 INFO: Anwendung gestartet [in C:\Users\firem\Desktop\111\Systades\website\app.py:77]
+2025-05-16 20:36:14,790 INFO: Anwendung gestartet [in C:\Users\firem\Desktop\111\Systades\website\app.py:77]
+2025-05-16 20:36:17,121 INFO: Anwendung gestartet [in C:\Users\firem\Desktop\111\Systades\website\app.py:77]
+2025-05-16 20:36:17,121 INFO: Anwendung gestartet [in C:\Users\firem\Desktop\111\Systades\website\app.py:77]
+2025-05-16 20:36:22,222 INFO: Anwendung gestartet [in C:\Users\firem\Desktop\111\Systades\website\app.py:77]
+2025-05-16 20:36:25,551 INFO: Anwendung gestartet [in C:\Users\firem\Desktop\111\Systades\website\app.py:77]
+2025-05-16 20:36:25,551 INFO: Anwendung gestartet [in C:\Users\firem\Desktop\111\Systades\website\app.py:77]
+2025-05-16 20:40:02,710 INFO: Anwendung gestartet [in C:\Users\firem\Desktop\111\Systades\website\app.py:77]
+2025-05-16 20:40:04,924 INFO: Anwendung gestartet [in C:\Users\firem\Desktop\111\Systades\website\app.py:77]
+2025-05-16 20:40:04,924 INFO: Anwendung gestartet [in C:\Users\firem\Desktop\111\Systades\website\app.py:77]
+2025-05-16 20:40:11,918 INFO: Anwendung gestartet [in C:\Users\firem\Desktop\111\Systades\website\app.py:77]
+2025-05-16 20:40:13,550 INFO: Anwendung gestartet [in C:\Users\firem\Desktop\111\Systades\website\app.py:77]
+2025-05-16 20:40:13,550 INFO: Anwendung gestartet [in C:\Users\firem\Desktop\111\Systades\website\app.py:77]
+2025-05-16 20:44:54,482 INFO: Anwendung gestartet [in C:\Users\firem\Desktop\111\Systades\website\app.py:77]
+2025-05-16 20:44:58,286 INFO: Anwendung gestartet [in C:\Users\firem\Desktop\111\Systades\website\app.py:77]
+2025-05-16 20:44:58,286 INFO: Anwendung gestartet [in C:\Users\firem\Desktop\111\Systades\website\app.py:77]
+2025-05-16 20:45:04,175 INFO: Anwendung gestartet [in C:\Users\firem\Desktop\111\Systades\website\app.py:77]
+2025-05-16 20:45:06,483 INFO: Anwendung gestartet [in C:\Users\firem\Desktop\111\Systades\website\app.py:77]
+2025-05-16 20:45:06,483 INFO: Anwendung gestartet [in C:\Users\firem\Desktop\111\Systades\website\app.py:77]
+2025-05-16 20:46:46,140 ERROR: Fehler 404: 404 Not Found: The requested URL was not found on the server. If you entered the URL manually please check your spelling and try again.
+Endpoint: /.well-known/appspecific/com.chrome.devtools.json, Method: GET, IP: 127.0.0.1
+Nicht angemeldet
+Traceback (most recent call last):
+ File "C:\Users\firem\Desktop\111\Systades\website\.venv\Lib\site-packages\flask\app.py", line 1823, in full_dispatch_request
+ rv = self.dispatch_request()
+ File "C:\Users\firem\Desktop\111\Systades\website\.venv\Lib\site-packages\flask\app.py", line 1788, in dispatch_request
+ self.raise_routing_exception(req)
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~^^^^^
+ File "C:\Users\firem\Desktop\111\Systades\website\.venv\Lib\site-packages\flask\app.py", line 1770, in raise_routing_exception
+ raise request.routing_exception # type: ignore
+ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ File "C:\Users\firem\Desktop\111\Systades\website\.venv\Lib\site-packages\flask\ctx.py", line 351, in match_request
+ result = self.url_adapter.match(return_rule=True) # type: ignore
+ File "C:\Users\firem\Desktop\111\Systades\website\.venv\Lib\site-packages\werkzeug\routing\map.py", line 624, in match
+ raise NotFound() from None
+werkzeug.exceptions.NotFound: 404 Not Found: The requested URL was not found on the server. If you entered the URL manually please check your spelling and try again.
+ [in C:\Users\firem\Desktop\111\Systades\website\app.py:93]
+2025-05-16 20:46:46,140 ERROR: Fehler 404: 404 Not Found: The requested URL was not found on the server. If you entered the URL manually please check your spelling and try again.
+Endpoint: /.well-known/appspecific/com.chrome.devtools.json, Method: GET, IP: 127.0.0.1
+Nicht angemeldet
+Traceback (most recent call last):
+ File "C:\Users\firem\Desktop\111\Systades\website\.venv\Lib\site-packages\flask\app.py", line 1823, in full_dispatch_request
+ rv = self.dispatch_request()
+ File "C:\Users\firem\Desktop\111\Systades\website\.venv\Lib\site-packages\flask\app.py", line 1788, in dispatch_request
+ self.raise_routing_exception(req)
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~^^^^^
+ File "C:\Users\firem\Desktop\111\Systades\website\.venv\Lib\site-packages\flask\app.py", line 1770, in raise_routing_exception
+ raise request.routing_exception # type: ignore
+ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ File "C:\Users\firem\Desktop\111\Systades\website\.venv\Lib\site-packages\flask\ctx.py", line 351, in match_request
+ result = self.url_adapter.match(return_rule=True) # type: ignore
+ File "C:\Users\firem\Desktop\111\Systades\website\.venv\Lib\site-packages\werkzeug\routing\map.py", line 624, in match
+ raise NotFound() from None
+werkzeug.exceptions.NotFound: 404 Not Found: The requested URL was not found on the server. If you entered the URL manually please check your spelling and try again.
+ [in C:\Users\firem\Desktop\111\Systades\website\app.py:93]
+2025-05-16 20:50:10,093 INFO: Anwendung gestartet [in C:\Users\firem\Desktop\111\Systades\website\app.py:77]
+2025-05-16 20:50:13,779 INFO: Anwendung gestartet [in C:\Users\firem\Desktop\111\Systades\website\app.py:77]
+2025-05-16 20:50:13,779 INFO: Anwendung gestartet [in C:\Users\firem\Desktop\111\Systades\website\app.py:77]
+2025-05-16 20:50:34,297 ERROR: Fehler 404: 404 Not Found: The requested URL was not found on the server. If you entered the URL manually please check your spelling and try again.
+Endpoint: /.well-known/appspecific/com.chrome.devtools.json, Method: GET, IP: 127.0.0.1
+Nicht angemeldet
+Traceback (most recent call last):
+ File "C:\Users\firem\Desktop\111\Systades\website\.venv\Lib\site-packages\flask\app.py", line 1823, in full_dispatch_request
+ rv = self.dispatch_request()
+ File "C:\Users\firem\Desktop\111\Systades\website\.venv\Lib\site-packages\flask\app.py", line 1788, in dispatch_request
+ self.raise_routing_exception(req)
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~^^^^^
+ File "C:\Users\firem\Desktop\111\Systades\website\.venv\Lib\site-packages\flask\app.py", line 1770, in raise_routing_exception
+ raise request.routing_exception # type: ignore
+ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ File "C:\Users\firem\Desktop\111\Systades\website\.venv\Lib\site-packages\flask\ctx.py", line 351, in match_request
+ result = self.url_adapter.match(return_rule=True) # type: ignore
+ File "C:\Users\firem\Desktop\111\Systades\website\.venv\Lib\site-packages\werkzeug\routing\map.py", line 624, in match
+ raise NotFound() from None
+werkzeug.exceptions.NotFound: 404 Not Found: The requested URL was not found on the server. If you entered the URL manually please check your spelling and try again.
+ [in C:\Users\firem\Desktop\111\Systades\website\app.py:93]
+2025-05-16 20:50:34,297 ERROR: Fehler 404: 404 Not Found: The requested URL was not found on the server. If you entered the URL manually please check your spelling and try again.
+Endpoint: /.well-known/appspecific/com.chrome.devtools.json, Method: GET, IP: 127.0.0.1
+Nicht angemeldet
+Traceback (most recent call last):
+ File "C:\Users\firem\Desktop\111\Systades\website\.venv\Lib\site-packages\flask\app.py", line 1823, in full_dispatch_request
+ rv = self.dispatch_request()
+ File "C:\Users\firem\Desktop\111\Systades\website\.venv\Lib\site-packages\flask\app.py", line 1788, in dispatch_request
+ self.raise_routing_exception(req)
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~^^^^^
+ File "C:\Users\firem\Desktop\111\Systades\website\.venv\Lib\site-packages\flask\app.py", line 1770, in raise_routing_exception
+ raise request.routing_exception # type: ignore
+ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ File "C:\Users\firem\Desktop\111\Systades\website\.venv\Lib\site-packages\flask\ctx.py", line 351, in match_request
+ result = self.url_adapter.match(return_rule=True) # type: ignore
+ File "C:\Users\firem\Desktop\111\Systades\website\.venv\Lib\site-packages\werkzeug\routing\map.py", line 624, in match
+ raise NotFound() from None
+werkzeug.exceptions.NotFound: 404 Not Found: The requested URL was not found on the server. If you entered the URL manually please check your spelling and try again.
+ [in C:\Users\firem\Desktop\111\Systades\website\app.py:93]
+2025-05-16 20:50:34,970 INFO: Anwendung gestartet [in C:\Users\firem\Desktop\111\Systades\website\app.py:77]
+2025-05-16 20:50:38,891 INFO: Anwendung gestartet [in C:\Users\firem\Desktop\111\Systades\website\app.py:77]
+2025-05-16 20:50:38,891 INFO: Anwendung gestartet [in C:\Users\firem\Desktop\111\Systades\website\app.py:77]
+2025-05-16 20:57:15,614 INFO: Anwendung gestartet [in C:\Users\firem\Desktop\111\Systades\website\app.py:77]
+2025-05-16 20:57:27,085 INFO: Anwendung gestartet [in C:\Users\firem\Desktop\111\Systades\website\app.py:77]
+2025-05-16 20:57:27,085 INFO: Anwendung gestartet [in C:\Users\firem\Desktop\111\Systades\website\app.py:77]
+2025-05-16 20:57:57,575 ERROR: Fehler 404: 404 Not Found: The requested URL was not found on the server. If you entered the URL manually please check your spelling and try again.
+Endpoint: /.well-known/appspecific/com.chrome.devtools.json, Method: GET, IP: 127.0.0.1
+Nicht angemeldet
+Traceback (most recent call last):
+ File "C:\Users\firem\Desktop\111\Systades\website\.venv\Lib\site-packages\flask\app.py", line 1823, in full_dispatch_request
+ rv = self.dispatch_request()
+ File "C:\Users\firem\Desktop\111\Systades\website\.venv\Lib\site-packages\flask\app.py", line 1788, in dispatch_request
+ self.raise_routing_exception(req)
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~^^^^^
+ File "C:\Users\firem\Desktop\111\Systades\website\.venv\Lib\site-packages\flask\app.py", line 1770, in raise_routing_exception
+ raise request.routing_exception # type: ignore
+ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ File "C:\Users\firem\Desktop\111\Systades\website\.venv\Lib\site-packages\flask\ctx.py", line 351, in match_request
+ result = self.url_adapter.match(return_rule=True) # type: ignore
+ File "C:\Users\firem\Desktop\111\Systades\website\.venv\Lib\site-packages\werkzeug\routing\map.py", line 624, in match
+ raise NotFound() from None
+werkzeug.exceptions.NotFound: 404 Not Found: The requested URL was not found on the server. If you entered the URL manually please check your spelling and try again.
+ [in C:\Users\firem\Desktop\111\Systades\website\app.py:93]
+2025-05-16 20:57:57,575 ERROR: Fehler 404: 404 Not Found: The requested URL was not found on the server. If you entered the URL manually please check your spelling and try again.
+Endpoint: /.well-known/appspecific/com.chrome.devtools.json, Method: GET, IP: 127.0.0.1
+Nicht angemeldet
+Traceback (most recent call last):
+ File "C:\Users\firem\Desktop\111\Systades\website\.venv\Lib\site-packages\flask\app.py", line 1823, in full_dispatch_request
+ rv = self.dispatch_request()
+ File "C:\Users\firem\Desktop\111\Systades\website\.venv\Lib\site-packages\flask\app.py", line 1788, in dispatch_request
+ self.raise_routing_exception(req)
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~^^^^^
+ File "C:\Users\firem\Desktop\111\Systades\website\.venv\Lib\site-packages\flask\app.py", line 1770, in raise_routing_exception
+ raise request.routing_exception # type: ignore
+ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ File "C:\Users\firem\Desktop\111\Systades\website\.venv\Lib\site-packages\flask\ctx.py", line 351, in match_request
+ result = self.url_adapter.match(return_rule=True) # type: ignore
+ File "C:\Users\firem\Desktop\111\Systades\website\.venv\Lib\site-packages\werkzeug\routing\map.py", line 624, in match
+ raise NotFound() from None
+werkzeug.exceptions.NotFound: 404 Not Found: The requested URL was not found on the server. If you entered the URL manually please check your spelling and try again.
+ [in C:\Users\firem\Desktop\111\Systades\website\app.py:93]
+2025-05-16 20:57:59,166 INFO: Anwendung gestartet [in C:\Users\firem\Desktop\111\Systades\website\app.py:77]
+2025-05-16 20:58:02,510 INFO: Anwendung gestartet [in C:\Users\firem\Desktop\111\Systades\website\app.py:77]
+2025-05-16 20:58:02,510 INFO: Anwendung gestartet [in C:\Users\firem\Desktop\111\Systades\website\app.py:77]
+2025-05-16 21:00:03,808 ERROR: Fehler 404: 404 Not Found: The requested URL was not found on the server. If you entered the URL manually please check your spelling and try again.
+Endpoint: /.well-known/appspecific/com.chrome.devtools.json, Method: GET, IP: 127.0.0.1
+Nicht angemeldet
+Traceback (most recent call last):
+ File "C:\Users\firem\Desktop\111\Systades\website\.venv\Lib\site-packages\flask\app.py", line 1823, in full_dispatch_request
+ rv = self.dispatch_request()
+ File "C:\Users\firem\Desktop\111\Systades\website\.venv\Lib\site-packages\flask\app.py", line 1788, in dispatch_request
+ self.raise_routing_exception(req)
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~^^^^^
+ File "C:\Users\firem\Desktop\111\Systades\website\.venv\Lib\site-packages\flask\app.py", line 1770, in raise_routing_exception
+ raise request.routing_exception # type: ignore
+ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ File "C:\Users\firem\Desktop\111\Systades\website\.venv\Lib\site-packages\flask\ctx.py", line 351, in match_request
+ result = self.url_adapter.match(return_rule=True) # type: ignore
+ File "C:\Users\firem\Desktop\111\Systades\website\.venv\Lib\site-packages\werkzeug\routing\map.py", line 624, in match
+ raise NotFound() from None
+werkzeug.exceptions.NotFound: 404 Not Found: The requested URL was not found on the server. If you entered the URL manually please check your spelling and try again.
+ [in C:\Users\firem\Desktop\111\Systades\website\app.py:93]
+2025-05-16 21:00:03,808 ERROR: Fehler 404: 404 Not Found: The requested URL was not found on the server. If you entered the URL manually please check your spelling and try again.
+Endpoint: /.well-known/appspecific/com.chrome.devtools.json, Method: GET, IP: 127.0.0.1
+Nicht angemeldet
+Traceback (most recent call last):
+ File "C:\Users\firem\Desktop\111\Systades\website\.venv\Lib\site-packages\flask\app.py", line 1823, in full_dispatch_request
+ rv = self.dispatch_request()
+ File "C:\Users\firem\Desktop\111\Systades\website\.venv\Lib\site-packages\flask\app.py", line 1788, in dispatch_request
+ self.raise_routing_exception(req)
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~^^^^^
+ File "C:\Users\firem\Desktop\111\Systades\website\.venv\Lib\site-packages\flask\app.py", line 1770, in raise_routing_exception
+ raise request.routing_exception # type: ignore
+ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ File "C:\Users\firem\Desktop\111\Systades\website\.venv\Lib\site-packages\flask\ctx.py", line 351, in match_request
+ result = self.url_adapter.match(return_rule=True) # type: ignore
+ File "C:\Users\firem\Desktop\111\Systades\website\.venv\Lib\site-packages\werkzeug\routing\map.py", line 624, in match
+ raise NotFound() from None
+werkzeug.exceptions.NotFound: 404 Not Found: The requested URL was not found on the server. If you entered the URL manually please check your spelling and try again.
+ [in C:\Users\firem\Desktop\111\Systades\website\app.py:93]
+2025-05-16 21:01:35,404 ERROR: Fehler 404: 404 Not Found: The requested URL was not found on the server. If you entered the URL manually please check your spelling and try again.
+Endpoint: /.well-known/appspecific/com.chrome.devtools.json, Method: GET, IP: 127.0.0.1
+Nicht angemeldet
+Traceback (most recent call last):
+ File "C:\Users\firem\Desktop\111\Systades\website\.venv\Lib\site-packages\flask\app.py", line 1823, in full_dispatch_request
+ rv = self.dispatch_request()
+ File "C:\Users\firem\Desktop\111\Systades\website\.venv\Lib\site-packages\flask\app.py", line 1788, in dispatch_request
+ self.raise_routing_exception(req)
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~^^^^^
+ File "C:\Users\firem\Desktop\111\Systades\website\.venv\Lib\site-packages\flask\app.py", line 1770, in raise_routing_exception
+ raise request.routing_exception # type: ignore
+ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ File "C:\Users\firem\Desktop\111\Systades\website\.venv\Lib\site-packages\flask\ctx.py", line 351, in match_request
+ result = self.url_adapter.match(return_rule=True) # type: ignore
+ File "C:\Users\firem\Desktop\111\Systades\website\.venv\Lib\site-packages\werkzeug\routing\map.py", line 624, in match
+ raise NotFound() from None
+werkzeug.exceptions.NotFound: 404 Not Found: The requested URL was not found on the server. If you entered the URL manually please check your spelling and try again.
+ [in C:\Users\firem\Desktop\111\Systades\website\app.py:93]
+2025-05-16 21:01:35,404 ERROR: Fehler 404: 404 Not Found: The requested URL was not found on the server. If you entered the URL manually please check your spelling and try again.
+Endpoint: /.well-known/appspecific/com.chrome.devtools.json, Method: GET, IP: 127.0.0.1
+Nicht angemeldet
+Traceback (most recent call last):
+ File "C:\Users\firem\Desktop\111\Systades\website\.venv\Lib\site-packages\flask\app.py", line 1823, in full_dispatch_request
+ rv = self.dispatch_request()
+ File "C:\Users\firem\Desktop\111\Systades\website\.venv\Lib\site-packages\flask\app.py", line 1788, in dispatch_request
+ self.raise_routing_exception(req)
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~^^^^^
+ File "C:\Users\firem\Desktop\111\Systades\website\.venv\Lib\site-packages\flask\app.py", line 1770, in raise_routing_exception
+ raise request.routing_exception # type: ignore
+ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ File "C:\Users\firem\Desktop\111\Systades\website\.venv\Lib\site-packages\flask\ctx.py", line 351, in match_request
+ result = self.url_adapter.match(return_rule=True) # type: ignore
+ File "C:\Users\firem\Desktop\111\Systades\website\.venv\Lib\site-packages\werkzeug\routing\map.py", line 624, in match
+ raise NotFound() from None
+werkzeug.exceptions.NotFound: 404 Not Found: The requested URL was not found on the server. If you entered the URL manually please check your spelling and try again.
+ [in C:\Users\firem\Desktop\111\Systades\website\app.py:93]
diff --git a/static/css/mindmap.css b/static/css/mindmap.css
index 9fa9dcc..a298a88 100644
--- a/static/css/mindmap.css
+++ b/static/css/mindmap.css
@@ -9,7 +9,91 @@
overflow: hidden;
}
-/* Toolbar Styles */
+/* Cytoscape Container für die Hauptmindmap */
+#cy {
+ width: 100%;
+ height: 100%;
+ background: transparent;
+ position: absolute;
+ top: 0;
+ left: 0;
+ z-index: 1;
+}
+
+/* Subpage Styles - Identisches Design wie Hauptmindmap */
+.mindmap-subpage {
+ position: absolute;
+ top: 0;
+ left: 0;
+ width: 100%;
+ height: 100%;
+ background: var(--bg-primary);
+ display: flex;
+ flex-direction: column;
+ z-index: 10;
+ transition: opacity 0.3s ease, transform 0.3s ease;
+ opacity: 1;
+ transform: translateY(0);
+}
+
+/* Subpage Header */
+.subpage-header {
+ display: flex;
+ align-items: center;
+ padding: 16px;
+ background: var(--bg-secondary);
+ border-bottom: 1px solid rgba(0, 0, 0, 0.1);
+ z-index: 2;
+}
+
+.dark .subpage-header {
+ background: rgba(30, 41, 59, 0.8);
+ border-bottom: 1px solid rgba(255, 255, 255, 0.1);
+}
+
+/* Zurück-Button */
+.back-button {
+ background: rgba(255, 255, 255, 0.1);
+ border: none;
+ color: white;
+ width: 40px;
+ height: 40px;
+ border-radius: 50%;
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ cursor: pointer;
+ transition: all 0.2s ease;
+ margin-right: 12px;
+}
+
+.back-button:hover {
+ background: rgba(255, 255, 255, 0.2);
+ transform: translateY(-2px);
+}
+
+/* Subpage Titel */
+.subpage-title {
+ font-size: 1.5rem;
+ font-weight: 600;
+ color: white;
+ margin: 0;
+ background: linear-gradient(90deg, #60a5fa, #8b5cf6);
+ -webkit-background-clip: text;
+ -webkit-text-fill-color: transparent;
+}
+
+/* Subpage Cytoscape Container */
+.subpage-cy-container {
+ position: relative;
+ flex: 1;
+ width: 100%;
+ height: calc(100% - 72px);
+ overflow: hidden;
+ z-index: 1;
+}
+
+/* Toolbar für Zoom-Kontrollen */
.mindmap-toolbar {
position: absolute;
top: 20px;
@@ -18,48 +102,74 @@
display: flex;
gap: 8px;
padding: 8px;
- background: var(--bg-secondary);
- border-radius: 12px;
- box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1);
- z-index: 1000;
- transition: all 0.3s ease;
-}
-
-.dark .mindmap-toolbar {
background: rgba(30, 41, 59, 0.8);
+ border-radius: 8px;
box-shadow: 0 4px 6px rgba(0, 0, 0, 0.2);
+ z-index: 20;
+ backdrop-filter: blur(8px);
border: 1px solid rgba(255, 255, 255, 0.1);
}
-/* Toolbar Buttons */
.mindmap-toolbar button {
+ width: 40px;
+ height: 40px;
+ border: none;
+ background: rgba(255, 255, 255, 0.1);
+ color: white;
+ border-radius: 6px;
display: flex;
align-items: center;
justify-content: center;
- width: 36px;
- height: 36px;
- border: none;
- border-radius: 8px;
- background: transparent;
- color: var(--text-primary);
cursor: pointer;
transition: all 0.2s ease;
}
.mindmap-toolbar button:hover {
- background: var(--accent-primary);
- color: white;
- transform: translateY(-1px);
-}
-
-.mindmap-toolbar button:active {
- transform: translateY(0);
+ background: rgba(139, 92, 246, 0.5);
+ transform: translateY(-2px);
}
.mindmap-toolbar button i {
font-size: 16px;
}
+/* Mindmap Header */
+.mindmap-header {
+ position: absolute;
+ top: 0;
+ left: 0;
+ right: 0;
+ padding: 1.5rem;
+ background: rgba(15, 23, 42, 0.8);
+ backdrop-filter: blur(10px);
+ border-bottom: 1px solid rgba(255, 255, 255, 0.1);
+ z-index: 10;
+ display: flex;
+ justify-content: space-between;
+ align-items: center;
+}
+
+/* Dark Mode spezifische Stile */
+.dark .mindmap-subpage {
+ background: linear-gradient(135deg, #0f172a 0%, #0c1221 100%);
+}
+
+/* Fix für Zoom-Buttons */
+body.dark .mindmap-toolbar button {
+ background: rgba(255, 255, 255, 0.1);
+ color: white;
+}
+
+body:not(.dark) .mindmap-toolbar button {
+ background: rgba(30, 41, 59, 0.2);
+ color: #1e293b;
+}
+
+/* Kontext-Menü-Anpassungen */
+.context-menu {
+ z-index: 1000;
+}
+
/* Export Group Styles */
.export-group {
position: relative;
diff --git a/static/js/update_mindmap.js b/static/js/update_mindmap.js
index 2ea7019..ed49cd0 100644
--- a/static/js/update_mindmap.js
+++ b/static/js/update_mindmap.js
@@ -185,11 +185,64 @@ async function loadMindmapData(nodeId = null) {
// Funktion zum Initialisieren der Mindmap
async function initializeMindmap() {
try {
+ // Zeige Ladeanimation
+ const loader = document.getElementById('loader');
+ const statusMessage = document.getElementById('statusMessage');
+
+ if (loader) loader.style.display = 'block';
+ if (statusMessage) {
+ statusMessage.textContent = 'Lade Mindmap...';
+ statusMessage.style.display = 'block';
+ }
+
+ // Prüfe auf bestehende Cytoscape-Instanz und zerstöre sie
+ if (window.cy && typeof window.cy.destroy === 'function') {
+ try {
+ window.cy.destroy();
+ } catch (e) {
+ console.error('Fehler beim Zerstören der bestehenden Cytoscape-Instanz:', e);
+ }
+ window.cy = null;
+ }
+
+ // Bereinige auch alle Subthemen-Instanzen
+ if (window.subthemeCyInstances) {
+ Object.keys(window.subthemeCyInstances).forEach(key => {
+ try {
+ if (window.subthemeCyInstances[key] && typeof window.subthemeCyInstances[key].destroy === 'function') {
+ window.subthemeCyInstances[key].destroy();
+ }
+ } catch (e) {
+ console.error(`Fehler beim Zerstören der Subthemen-Instanz ${key}:`, e);
+ }
+ });
+ window.subthemeCyInstances = {};
+ }
+
+ // Entferne bestehende Subpages aus dem DOM
+ const existingSubpages = document.querySelectorAll('.mindmap-subpage');
+ existingSubpages.forEach(subpage => {
+ if (subpage.parentNode) {
+ subpage.parentNode.removeChild(subpage);
+ }
+ });
+
+ // Lade Mindmap-Daten
const data = await loadMindmapData();
if (!data || !data.nodes || !data.edges) {
throw new Error('Ungültiges Datenformat: Mindmap-Daten fehlen oder sind unvollständig');
}
+ // Prüfe, ob der Container existiert
+ const cyContainer = document.getElementById('cy');
+ if (!cyContainer) {
+ throw new Error('Mindmap-Container #cy nicht gefunden!');
+ }
+
+ // Stelle sicher, dass der Container sichtbar ist
+ cyContainer.style.display = 'block';
+
+ // Elemente für Cytoscape erstellen
const elements = [
// Knoten
...data.nodes.map(node => ({
@@ -215,16 +268,7 @@ async function initializeMindmap() {
}))
];
- // Bestehende Cytoscape-Instanz entfernen, falls vorhanden
- if (window.cy && typeof window.cy.destroy === 'function') {
- window.cy.destroy();
- }
-
- const cyContainer = document.getElementById('cy');
- if (!cyContainer) {
- throw new Error('Mindmap-Container #cy nicht gefunden!');
- }
-
+ // Cytoscape-Instanz erstellen
window.cy = cytoscape({
container: cyContainer,
elements: elements,
@@ -253,8 +297,13 @@ async function initializeMindmap() {
maxZoom: 2.5
});
+ // Prüfe, ob die Cytoscape-Instanz erfolgreich erstellt wurde
+ if (!window.cy || !window.cy.container()) {
+ throw new Error('Cytoscape-Instanz konnte nicht korrekt initialisiert werden');
+ }
+
// Füge neuronale Eigenschaften zu allen Knoten hinzu
- cy.nodes().forEach(node => {
+ window.cy.nodes().forEach(node => {
const data = node.data();
// Verwende mindmapConfig für Kategorie-Farben oder einen Standardwert
const categoryColor = data.category && mindmapConfig.categories[data.category]
@@ -273,7 +322,7 @@ async function initializeMindmap() {
});
// Füge synaptische Eigenschaften zu allen Kanten hinzu
- cy.edges().forEach(edge => {
+ window.cy.edges().forEach(edge => {
const data = edge.data();
edge.data({
...data,
@@ -283,51 +332,99 @@ async function initializeMindmap() {
});
});
- // Event-Listener für Knoten-Klicks
- cy.on('tap', 'node', async function(evt) {
- const node = evt.target;
- console.log('Node clicked:', node.id(), 'hasChildren:', node.data('hasChildren') || node.data('has_children'), 'expanded:', node.data('expanded'));
-
- if ((node.data('hasChildren') || node.data('has_children')) && !node.data('expanded')) {
- await loadSubthemes(node);
+ // Event-Listener für Knoten-Klicks mit Fehlerbehandlung
+ window.cy.on('tap', 'node', async function(evt) {
+ try {
+ const node = evt.target;
+ console.log('Node clicked:', node.id(), 'hasChildren:', node.data('hasChildren') || node.data('has_children'), 'expanded:', node.data('expanded'));
+
+ if ((node.data('hasChildren') || node.data('has_children')) && !node.data('expanded')) {
+ await loadSubthemes(node);
+ }
+ } catch (e) {
+ console.error('Fehler beim Node-Tap-Event:', e);
+ showUINotification('Fehler beim Verarbeiten des Klicks: ' + e.message, 'error');
}
});
// Event-Listener für Hover über Knoten (für Info-Panel)
- cy.on('mouseover', 'node', function(evt) {
- const node = evt.target;
- showNodeInfo(node);
+ window.cy.on('mouseover', 'node', function(evt) {
+ try {
+ const node = evt.target;
+ showNodeInfo(node);
+ } catch (e) {
+ console.error('Fehler beim Mouseover-Event:', e);
+ }
});
- cy.on('mouseout', 'node', function() {
- hideNodeInfo();
+ window.cy.on('mouseout', 'node', function() {
+ try {
+ hideNodeInfo();
+ } catch (e) {
+ console.error('Fehler beim Mouseout-Event:', e);
+ }
});
// Layout ausführen
- cy.layout(mindmapStyles.layout.base).run();
+ window.cy.layout(mindmapStyles.layout.base).run();
// Starte neuronale Aktivitätssimulation
- startNeuralActivitySimulation(cy);
+ try {
+ startNeuralActivitySimulation(window.cy);
+ } catch (e) {
+ console.error('Fehler beim Starten der neuronalen Simulation:', e);
+ }
// Mindmap mit echten Daten befüllen (Styles, Farben etc.)
- updateMindmap();
+ try {
+ updateMindmap();
+ } catch (e) {
+ console.error('Fehler beim Aktualisieren der Mindmap:', e);
+ }
// Setze anfänglichen Zoom auf eine kleinere Stufe, damit mehr sichtbar ist
setTimeout(() => {
- cy.zoom({
- level: 0.7,
- renderedPosition: { x: cy.width() / 2, y: cy.height() / 2 }
- });
- cy.center();
+ try {
+ window.cy.zoom({
+ level: 0.7,
+ renderedPosition: { x: window.cy.width() / 2, y: window.cy.height() / 2 }
+ });
+ window.cy.center();
+ } catch (e) {
+ console.error('Fehler beim Setzen des anfänglichen Zooms:', e);
+ }
}, 300);
+ // Verstecke Ladeanimation
+ if (loader) loader.style.display = 'none';
+ if (statusMessage) statusMessage.style.display = 'none';
+
+ // Event auslösen, damit andere Scripte reagieren können
+ document.dispatchEvent(new Event('mindmap-loaded'));
+ console.log('mindmap-loaded Event ausgelöst');
+
return true;
} catch (error) {
console.error('Fehler bei der Mindmap-Initialisierung:', error);
+
+ // Verstecke Ladeanimation
+ const loader = document.getElementById('loader');
+ const statusMessage = document.getElementById('statusMessage');
+
+ if (loader) loader.style.display = 'none';
+
+ // Zeige Fehlermeldung
+ if (statusMessage) {
+ statusMessage.textContent = 'Fehler beim Laden der Mindmap: ' + error.message;
+ statusMessage.style.backgroundColor = 'rgba(220, 38, 38, 0.9)';
+ statusMessage.style.display = 'block';
+ }
+
showUINotification({
error: 'Mindmap konnte nicht initialisiert werden',
details: error.message
}, 'error');
+
return false;
}
}
@@ -348,11 +445,25 @@ document.addEventListener('DOMContentLoaded', function() {
// Prüfe, ob Cytoscape verfügbar ist
if (typeof cytoscape === 'undefined') {
console.error('Cytoscape ist nicht definiert!');
+
+ // Versuche, Cytoscape nachzuladen
+ const script = document.createElement('script');
+ script.src = 'https://cdnjs.cloudflare.com/ajax/libs/cytoscape/3.26.0/cytoscape.min.js';
+ script.onload = function() {
+ console.log('Cytoscape wurde nachgeladen');
+ initializeMindmap().catch(console.error);
+ };
+ script.onerror = function() {
+ console.error('Cytoscape konnte nicht nachgeladen werden');
+ showUINotification('Cytoscape-Bibliothek konnte nicht geladen werden', 'error');
+ };
+ document.head.appendChild(script);
return;
}
+
console.log('Cytoscape ist verfügbar');
- // Initialisiere die Mindmap
+ // Initialisiere die Mindmap mit Fehlerbehandlung
initializeMindmap()
.then(success => {
if (success) {
@@ -659,86 +770,174 @@ function applyNeuralNetworkStyle(cy) {
// Vereinfachte neuronale Aktivitätssimulation
function startNeuralActivitySimulation(cy) {
- if (window.neuralInterval) clearInterval(window.neuralInterval);
+ if (!cy || !cy.nodes) {
+ console.error('Keine gültige Cytoscape-Instanz für neuronale Simulation');
+ return;
+ }
+
+ // Bestehende Intervalle stoppen, um Speicherlecks zu vermeiden
+ if (window.neuralIntervals) {
+ window.neuralIntervals.forEach(clearInterval);
+ }
+
+ // Erstelle ein Array für die Intervalle dieser Instanz
+ window.neuralIntervals = window.neuralIntervals || [];
const nodes = cy.nodes();
let currentTime = Date.now();
+ // Sicherer Zugriff auf Nodes mit Fehlerbehandlung
function simulateNeuralActivity() {
- currentTime = Date.now();
-
- nodes.forEach(node => {
- const data = node.data();
- const lastFired = data.lastFired || 0;
- const timeSinceLastFire = currentTime - lastFired;
-
- if (timeSinceLastFire > data.refractionPeriod) {
- if (Math.random() < data.neuronActivity * 0.1) {
- fireNeuron(node, true, currentTime);
+ try {
+ if (!cy || !cy.nodes) {
+ console.warn('Cytoscape-Instanz nicht mehr verfügbar, stoppe Simulation');
+ clearInterval(intervalId);
+ const index = window.neuralIntervals.indexOf(intervalId);
+ if (index > -1) {
+ window.neuralIntervals.splice(index, 1);
}
+ return;
}
- });
+
+ currentTime = Date.now();
+
+ cy.nodes().forEach(node => {
+ try {
+ const data = node.data();
+ if (!data) return;
+
+ const lastFired = data.lastFired || 0;
+ const timeSinceLastFire = currentTime - lastFired;
+
+ if (timeSinceLastFire > data.refractionPeriod) {
+ if (Math.random() < data.neuronActivity * 0.1) {
+ fireNeuron(node, true, currentTime);
+ }
+ }
+ } catch (e) {
+ // Ignoriere Fehler für einzelne Nodes
+ console.debug('Fehler bei Node in Simulation:', e);
+ }
+ });
+ } catch (e) {
+ console.error('Fehler in neuronaler Simulation:', e);
+ }
}
function fireNeuron(node, state, currentTime) {
- const data = node.data();
- data.lastFired = currentTime;
-
- node.style({
- 'background-opacity': 1,
- 'border-width': 3
- });
-
- setTimeout(() => {
- node.style({
- 'background-opacity': 0.9,
- 'border-width': 2
- });
- }, 200);
-
- if (state) {
- propagateSignal(node, currentTime);
+ try {
+ if (!node || !node.data) return;
+
+ const data = node.data();
+ if (!data) return;
+
+ data.lastFired = currentTime;
+
+ try {
+ node.style({
+ 'background-opacity': 1,
+ 'border-width': 3
+ });
+
+ setTimeout(() => {
+ try {
+ node.style({
+ 'background-opacity': 0.9,
+ 'border-width': 2
+ });
+ } catch (e) {
+ // Ignoriere Fehler beim Styling, da der Node möglicherweise nicht mehr existiert
+ }
+ }, 200);
+ } catch (e) {
+ // Ignoriere Styling-Fehler
+ }
+
+ if (state) {
+ propagateSignal(node, currentTime);
+ }
+ } catch (e) {
+ // Ignoriere Fehler für einzelne Nodes
}
}
function propagateSignal(sourceNode, currentTime) {
- const outgoingEdges = sourceNode.connectedEdges();
-
- outgoingEdges.forEach(edge => {
- const targetNode = edge.target();
- const edgeData = edge.data();
- const latency = edgeData.latency;
+ try {
+ if (!sourceNode || !sourceNode.connectedEdges) return;
- edge.style({
- 'line-opacity': 0.8,
- 'width': edgeData.strength * 3
- });
+ const outgoingEdges = sourceNode.connectedEdges();
- setTimeout(() => {
- edge.style({
- 'line-opacity': edgeData.strength * 0.6,
- 'width': edgeData.strength * 2
- });
- }, 200);
-
- setTimeout(() => {
- const targetData = targetNode.data();
- const timeSinceLastFire = currentTime - (targetData.lastFired || 0);
-
- if (timeSinceLastFire > targetData.refractionPeriod) {
- const signalStrength = edgeData.strength *
- edgeData.conductionVelocity *
- sourceNode.data('neuronActivity');
+ outgoingEdges.forEach(edge => {
+ try {
+ const targetNode = edge.target();
+ const edgeData = edge.data();
+ if (!targetNode || !edgeData) return;
- if (signalStrength > targetData.threshold) {
- fireNeuron(targetNode, true, currentTime + latency);
+ const latency = edgeData.latency || 100;
+
+ try {
+ edge.style({
+ 'line-opacity': 0.8,
+ 'width': edgeData.strength * 3
+ });
+
+ setTimeout(() => {
+ try {
+ edge.style({
+ 'line-opacity': edgeData.strength * 0.6,
+ 'width': edgeData.strength * 2
+ });
+ } catch (e) {
+ // Ignoriere Styling-Fehler
+ }
+ }, 200);
+ } catch (e) {
+ // Ignoriere Styling-Fehler
}
+
+ setTimeout(() => {
+ try {
+ if (!targetNode || !targetNode.data) return;
+
+ const targetData = targetNode.data();
+ if (!targetData) return;
+
+ const timeSinceLastFire = currentTime - (targetData.lastFired || 0);
+
+ if (timeSinceLastFire > targetData.refractionPeriod) {
+ const signalStrength = edgeData.strength *
+ edgeData.conductionVelocity *
+ sourceNode.data('neuronActivity');
+
+ if (signalStrength > targetData.threshold) {
+ fireNeuron(targetNode, true, currentTime + latency);
+ }
+ }
+ } catch (e) {
+ // Ignoriere Fehler für einzelne Nodes
+ }
+ }, latency);
+ } catch (e) {
+ // Ignoriere Fehler für einzelne Edges
}
- }, latency);
- });
+ });
+ } catch (e) {
+ // Ignoriere Fehler für einzelne Nodes
+ }
}
- window.neuralInterval = setInterval(simulateNeuralActivity, 100);
+ // Starte das Intervall und speichere die Referenz
+ const intervalId = setInterval(simulateNeuralActivity, 100);
+ window.neuralIntervals.push(intervalId);
+
+ // Rückgabefunktion zum manuellen Stoppen
+ return function stopSimulation() {
+ clearInterval(intervalId);
+ const index = window.neuralIntervals.indexOf(intervalId);
+ if (index > -1) {
+ window.neuralIntervals.splice(index, 1);
+ }
+ };
}
// Hilfe-Funktion zum Hinzufügen eines Flash-Hinweises
@@ -1894,8 +2093,30 @@ document.head.appendChild(editingStyles);
// Funktion zum Laden der Subthemen
async function loadSubthemes(node) {
try {
- const mindmapData = await loadMindmapData(node.id());
- if (!mindmapData) return;
+ if (!node || !node.id) {
+ console.error('Ungültiger Knoten für Subthemen');
+ return;
+ }
+
+ const nodeId = node.id();
+ if (!nodeId) {
+ console.error('Ungültige Knoten-ID für Subthemen');
+ return;
+ }
+
+ // Prüfe ob die Haupt-Cytoscape-Instanz noch gültig ist
+ if (!window.cy || typeof window.cy.container !== 'function') {
+ console.error('Haupt-Cytoscape-Instanz nicht mehr gültig');
+ showUINotification('Fehler: Mindmap-Instanz nicht mehr verfügbar', 'error');
+ return;
+ }
+
+ const mindmapData = await loadMindmapData(nodeId);
+ if (!mindmapData || !mindmapData.nodes || !mindmapData.edges) {
+ console.warn('Keine gültigen Daten für Subthemen gefunden');
+ showUINotification('Keine Unterthemen verfügbar', 'info');
+ return;
+ }
showUINotification('Lade Subthemen...', 'info');
@@ -1907,9 +2128,22 @@ async function loadSubthemes(node) {
return;
}
+ // Verstecke die Hauptmindmap nur wenn sie noch gültig ist
+ try {
+ const mainContainer = window.cy.container();
+ if (mainContainer && mainContainer.parentNode) {
+ mainContainer.style.display = 'none';
+ } else {
+ console.warn('Haupt-Cytoscape-Container nicht mehr gültig');
+ }
+ } catch (e) {
+ console.error('Fehler beim Verstecken der Hauptmindmap:', e);
+ }
+
// Erstelle eine neue Seite für die Unterkategorien
const subpage = document.createElement('div');
subpage.className = 'mindmap-subpage';
+ subpage.setAttribute('data-parent-id', nodeId);
// Erstelle den Header mit Zurück-Button und Titel
const header = document.createElement('div');
@@ -1920,25 +2154,25 @@ async function loadSubthemes(node) {