Compare commits

42 Commits

Author SHA1 Message Date
marwinm cb3bfe0e6a LOL 2025-05-01 19:57:26 +01:00
tilltmk fd63810845 feat: update environment and scripts for improved functionality 2025-05-01 16:29:57 +02:00
tilltmk 883973fe7b feat: update environment variables and enhance mindmap functionality 2025-05-01 16:27:40 +02:00
tilltmk 027e632856 feat: update example.env with new configuration settings 2025-05-01 16:24:29 +02:00
tilltmk 406289e54f 🎨 feat(mindmap): improve rendering performance and optimize code structure 2025-05-01 16:16:26 +02:00
tilltmk 71b33e6cec feat(mindmap): enhance mindmap rendering performance and responsiveness 2025-05-01 16:14:14 +02:00
tilltmk c74d3164bb 🎨 feat: update mindmap templates and JS module for improved UI design 2025-05-01 16:11:42 +02:00
tilltmk 4982cddeef 🎉 feat: update Dockerfile and scripts for improved functionality 2025-05-01 16:05:52 +02:00
tilltmk 631619ccb4 feat: update docker-compose.yml for improved service configuration 2025-05-01 16:01:00 +02:00
marwinm f9881b678d 🔄 chore: aktualisiere die .env-Datei für verbesserte Konfiguration 2025-05-01 11:27:11 +01:00
marwinm 259ce3cf69 feat: update Dockerfile and docker-compose for improved build process 2025-05-01 11:24:27 +01:00
marwinm 9f4743eaea feat: update cached Python files and add new static image asset 2025-05-01 10:55:30 +01:00
tilltmk de0f837cfd Optimierung der Projektstruktur: Entferne nicht mehr benötigte Skripte und Dateien, um die Wartbarkeit zu erhöhen und veraltete Komponenten zu beseitigen. 2025-04-30 15:51:07 +02:00
tilltmk 1c49ddfb19 chore: automatic commit 2025-04-30 15:49 2025-04-30 15:49:18 +02:00
tilltmk 46c16e5f01 chore: automatic commit 2025-04-30 15:44 2025-04-30 15:44:02 +02:00
tilltmk 84667bca00 chore: automatic commit 2025-04-30 15:41 2025-04-30 15:41:00 +02:00
tilltmk 779449559d chore: automatic commit 2025-04-30 15:38 2025-04-30 15:38:56 +02:00
tilltmk 721a10e861 Entferne nicht mehr benötigte Skripte: Lösche die Dateien check_schema.py, create_default_users.py, fix_user_table.py, test_app.py und windows_setup.bat, um die Projektstruktur zu optimieren und veraltete Komponenten zu entfernen. 2025-04-30 15:33:39 +02:00
tilltmk a431873ca2 chore: automatic commit 2025-04-30 15:29 2025-04-30 15:29:23 +02:00
tilltmk e4ab1e1bb5 chore: automatic commit 2025-04-30 12:48 2025-04-30 12:48:06 +02:00
tilltmk f69356473b Entferne nicht mehr benötigte Dateien: Lösche docker-compose.yml, Dockerfile, README.md, requirements.txt, start_server.bat, start-flask-server.py, start.sh, test_server.py, sowie alle zugehörigen Datenbank- und Website-Dateien. Diese Bereinigung optimiert die Projektstruktur und entfernt veraltete Komponenten. 2025-04-30 12:34:06 +02:00
tilltmk 38ac13e87c chore: automatic commit 2025-04-30 12:32 2025-04-30 12:32:36 +02:00
marwinm 0afb8cb6e2 Update neural network background configuration: reduce node count and connection distance, adjust glow and node colors, and modify shadow blur for improved visual clarity and performance. 2025-04-29 20:58:27 +01:00
marwinm 5d282d2108 Refactor neural network background animation: streamline the code by consolidating node and connection logic, enhancing visual effects with improved glow and animation dynamics. Introduce responsive canvas resizing and optimize particle behavior for a smoother experience. 2025-04-29 20:54:24 +01:00
marwinm 4aba72efa2 Merge branch 'main' of https://git.clickcandit.com/marwinm/website 2025-04-29 20:52:11 +01:00
marwinm 89476d5353 w 2025-04-29 20:51:49 +01:00
marwinm 0f7a33340a Update mindmap database: replace binary file with a new version to reflect recent changes in structure and data. 2025-04-27 08:56:56 +01:00
marwinm 73501e7cda Add Flask server startup scripts: introduce start_server.bat for Windows and start-flask-server.py for enhanced server management. Update run.py to include logging and threaded request handling. Add test_server.py for server accessibility testing. 2025-04-25 17:09:09 +01:00
marwinm 9f8eba6736 Refactor database initialization: streamline the process by removing the old init_database function, implementing a new structure for database setup, and ensuring the creation of a comprehensive mindmap hierarchy with an admin user. Update app.py to run on port 5000 instead of 6000. 2025-04-21 18:43:58 +01:00
marwinm b6bf9f387d Update mindmap database: replace binary file with a new version to incorporate recent structural and data changes. 2025-04-21 18:26:41 +01:00
marwinm d9fe1f8efc Update mindmap database: replace existing binary file with a new version, reflecting recent changes in mindmap structure and data. 2025-04-20 20:28:51 +01:00
marwinm fd7bc59851 Add user authentication routes: implement login, registration, and logout functionality, along with user profile and admin routes. Enhance mindmap API with error handling and default node creation. 2025-04-20 19:58:27 +01:00
marwinm 55f1f87509 Refactor app initialization: encapsulate Flask app setup and database initialization within a create_app function, improving modularity and error handling during startup. 2025-04-20 19:54:07 +01:00
marwinm 03f8761312 Update Docker configuration to change exposed port from 5000 to 6000 in Dockerfile and docker-compose.yml, ensuring consistency across the application. 2025-04-20 19:48:49 +01:00
marwinm 506748fda7 Implement error handling and default node creation for mindmap routes; initialize database on first request to ensure root node exists. 2025-04-20 19:43:21 +01:00
marwinm 6d069f68cd Update requirements.txt to include new dependencies for enhanced functionality and remove outdated packages for better compatibility. 2025-04-20 19:32:32 +01:00
marwinm 4310239a7a Enhance Dockerfile: add system dependencies for building Python packages, update requirements.txt to remove specific version constraints, and verify installations with pip list. 2025-04-20 19:31:13 +01:00
marwinm e9fe907af0 Update requirements.txt to include email_validator==2.1.1 for improved email validation functionality. 2025-04-20 19:29:19 +01:00
marwinm 0c69d9aba3 Remove unnecessary 'force' option from docker-compose.yml for cleaner configuration. 2025-04-20 19:26:44 +01:00
marwinm 6da85cdece Refactor Docker setup: update docker-compose.yml to use a specific website directory for volumes, enable automatic restarts, and modify Dockerfile to clean up and copy application files more efficiently. 2025-04-20 19:25:08 +01:00
marwinm a073b09115 Update Docker configuration: change Docker Compose version to 3.8, enhance web service setup with context and dockerfile specifications, add volume and environment variables for Flask development, and modify Dockerfile to use Python 3.11 and improve file copying and command execution. 2025-04-20 19:22:08 +01:00
marwinm f1f4870989 Update dependencies in requirements.txt to specific versions for Flask, Flask-Login, Flask-SQLAlchemy, Werkzeug, and SQLAlchemy 2025-04-20 19:16:34 +01:00
27 changed files with 1078 additions and 1055 deletions
BIN
View File
Binary file not shown.
+33
View File
@@ -0,0 +1,33 @@
# Dockerfile
FROM python:3.11-slim
# Arbeitsverzeichnis in Container
WORKDIR /app
# Systemabhängigkeiten installieren und Verzeichnisse anlegen
RUN apt-get update && \
apt-get install -y --no-install-recommends gcc && \
rm -rf /var/lib/apt/lists/* && \
mkdir -p /app/database
# pip auf den neuesten Stand bringen und Requirements installieren
COPY requirements.txt ./
RUN pip install --upgrade pip && \
pip install --no-cache-dir -U -r requirements.txt
# Anwendungscode kopieren
COPY . .
# Berechtigungen für database-Ordner
RUN chmod -R 777 /app/database
# Exponiere Port 5000 für Flask
EXPOSE 5000
# Setze Umgebungsvariablen
ENV FLASK_APP=app.py
ENV PYTHONUNBUFFERED=1
ENV PYTHONDONTWRITEBYTECODE=1
# Startkommando mit spezifischen Flags für Produktion
CMD ["python", "app.py"]
Binary file not shown.
Binary file not shown.
Binary file not shown.
+17
View File
@@ -0,0 +1,17 @@
version: '3.9'
services:
web:
build: .
image: systades_app:latest
container_name: systades_app
restart: always
env_file:
- .env
ports:
- "5000:5000"
volumes:
- ./database:/app/database
volumes:
db_data:
+1
View File
@@ -0,0 +1 @@
+4 -2
View File
@@ -2,10 +2,12 @@
# Kopiere diese Datei zu .env und passe die Werte an # Kopiere diese Datei zu .env und passe die Werte an
# Flask # Flask
SECRET_KEY=dein-geheimer-schluessel-hier FLASK_APP=app.py
FLASK_ENV=development
SECRET_KEY=your-secret-key-replace-in-production
# OpenAI API # OpenAI API
OPENAI_API_KEY=sk-dein-openai-api-schluessel-hier OPENAI_API_KEY=your-openai-api-key
# Datenbank # Datenbank
# Bei Bedarf kann hier eine andere Datenbank-URL angegeben werden # Bei Bedarf kann hier eine andere Datenbank-URL angegeben werden
+53
View File
@@ -0,0 +1,53 @@
#!/usr/bin/env powershell
# Windows PowerShell-Version des Start-Skripts
# Datum: 01.05.2025
# Docker-Status prüfen
Write-Host "Prüfe Docker-Status..." -ForegroundColor Cyan
try {
$status = docker ps -q
if ($LASTEXITCODE -ne 0) {
Write-Host "Docker ist nicht gestartet. Bitte starten Sie Docker Desktop." -ForegroundColor Red
exit 1
}
} catch {
Write-Host "Docker ist nicht verfügbar. Bitte installieren Sie Docker Desktop und starten Sie es." -ForegroundColor Red
Write-Host $_.Exception.Message
exit 1
}
# Alte Container stoppen und entfernen
$containerExists = docker ps -a --filter "name=systades_app" -q
if ($containerExists) {
Write-Host "Stoppe und entferne alten Container..." -ForegroundColor Yellow
docker rm -f systades_app
}
# Alte Images löschen
Write-Host "Entferne altes Image..." -ForegroundColor Yellow
docker rmi -f systades_app:latest
# Stelle sicher, dass das Datenbankverzeichnis existiert
if (-not (Test-Path "database")) {
New-Item -Path "database" -ItemType Directory -Force
}
# Docker-Compose Setup neu bauen
Write-Host "Baue Container neu..." -ForegroundColor Green
docker-compose build --no-cache
# Docker-Compose neu starten
Write-Host "Starte Container..." -ForegroundColor Green
docker-compose up -d --force-recreate
# Warte kurz und prüfe, ob der Container läuft
Write-Host "Prüfe Container-Status..." -ForegroundColor Cyan
Start-Sleep -Seconds 3
docker ps | Select-String "systades_app"
# Ausgabe
Write-Host "`nSystemstatus:" -ForegroundColor Cyan
Write-Host "----------------------------------------"
Write-Host "Systades-Anwendung ist jetzt unter http://localhost:5000 erreichbar." -ForegroundColor Green
Write-Host "Container-Logs können mit 'docker logs -f systades_app' angezeigt werden." -ForegroundColor Green
Write-Host "----------------------------------------"
@@ -0,0 +1 @@
+230 -2
View File
@@ -40,8 +40,8 @@
--light-bg: #f9fafb; --light-bg: #f9fafb;
--light-text: #1e293b; --light-text: #1e293b;
--light-heading: #0f172a; --light-heading: #0f172a;
--light-primary: #3b82f6; --light-primary: #7c3aed;
--light-primary-hover: #4f46e5; --light-primary-hover: #6d28d9;
--light-secondary: #6b7280; --light-secondary: #6b7280;
--light-border: #e5e7eb; --light-border: #e5e7eb;
--light-card-bg: rgba(255, 255, 255, 0.92); --light-card-bg: rgba(255, 255, 255, 0.92);
@@ -524,3 +524,231 @@ body:not(.dark) .navbar {
box-shadow: var(--light-shadow); box-shadow: var(--light-shadow);
border-bottom: 1px solid var(--light-border); border-bottom: 1px solid var(--light-border);
} }
/* Erweiterte Light-Mode-spezifische Stile */
body:not(.dark) .glass-effect {
background-color: rgba(255, 255, 255, 0.7);
backdrop-filter: blur(12px);
-webkit-backdrop-filter: blur(12px);
border: 1px solid rgba(209, 213, 219, 0.3);
}
body:not(.dark) .card {
background-color: rgba(255, 255, 255, 0.85);
border: 1px solid var(--light-border);
box-shadow: var(--light-shadow);
transition: all 0.3s ease;
}
body:not(.dark) .card:hover {
box-shadow: 0 8px 15px -3px rgba(0, 0, 0, 0.1), 0 4px 6px -2px rgba(0, 0, 0, 0.05);
transform: translateY(-2px);
}
/* Light Mode Buttons */
body:not(.dark) .btn-primary {
background-color: var(--light-primary);
color: white;
border: none;
transition: all 0.2s ease;
}
body:not(.dark) .btn-primary:hover {
background-color: var(--light-primary-hover);
box-shadow: 0 4px 12px rgba(124, 58, 237, 0.2);
}
body:not(.dark) .btn-secondary {
background-color: #f3f4f6;
color: var(--light-text);
border: 1px solid #e5e7eb;
}
body:not(.dark) .btn-secondary:hover {
background-color: #e5e7eb;
}
body:not(.dark) .btn-outline {
background-color: transparent;
color: var(--light-primary);
border: 1px solid var(--light-primary);
}
body:not(.dark) .btn-outline:hover {
background-color: rgba(124, 58, 237, 0.05);
}
/* Light Mode Formulare */
body:not(.dark) input,
body:not(.dark) select,
body:not(.dark) textarea {
background-color: white;
border: 1px solid #d1d5db;
color: #1f2937;
}
body:not(.dark) input:focus,
body:not(.dark) select:focus,
body:not(.dark) textarea:focus {
border-color: var(--light-primary);
box-shadow: 0 0 0 2px rgba(124, 58, 237, 0.2);
}
/* Light Mode Navigation */
body:not(.dark) .sidebar {
background-color: white;
border-right: 1px solid #e5e7eb;
}
body:not(.dark) .sidebar-link {
color: #4b5563;
}
body:not(.dark) .sidebar-link:hover {
background-color: #f3f4f6;
color: var(--light-primary);
}
body:not(.dark) .sidebar-link.active {
background-color: rgba(124, 58, 237, 0.08);
color: var(--light-primary);
font-weight: 500;
}
/* Light Mode Tabellen */
body:not(.dark) table {
border-color: #e5e7eb;
}
body:not(.dark) th {
background-color: #f9fafb;
color: #111827;
font-weight: 600;
}
body:not(.dark) tr:nth-child(even) {
background-color: #f9fafb;
}
body:not(.dark) tr:hover {
background-color: #f3f4f6;
}
/* Light Mode Icons */
body:not(.dark) .icon {
color: #6b7280;
}
body:not(.dark) .icon-primary {
color: var(--light-primary);
}
/* Light Mode Alerts/Benachrichtigungen */
body:not(.dark) .alert-info {
background-color: #eff6ff;
border-left: 4px solid #3b82f6;
color: #1e40af;
}
body:not(.dark) .alert-success {
background-color: #ecfdf5;
border-left: 4px solid #10b981;
color: #065f46;
}
body:not(.dark) .alert-warning {
background-color: #fffbeb;
border-left: 4px solid #f59e0b;
color: #92400e;
}
body:not(.dark) .alert-error {
background-color: #fef2f2;
border-left: 4px solid #ef4444;
color: #b91c1c;
}
/* Light Mode Badge */
body:not(.dark) .badge {
background-color: #e5e7eb;
color: #374151;
}
body:not(.dark) .badge-primary {
background-color: rgba(124, 58, 237, 0.1);
color: var(--light-primary);
}
/* Light Mode Mindmap spezifisch */
body:not(.dark) #cy {
background-color: rgba(255, 255, 255, 0.7);
border: 1px solid #e5e7eb;
}
body:not(.dark) .node {
border: 2px solid white;
box-shadow: 0 2px 5px rgba(0, 0, 0, 0.1);
}
body:not(.dark) .node:hover,
body:not(.dark) .node.selected {
box-shadow: 0 0 0 2px rgba(124, 58, 237, 0.5), 0 4px 8px rgba(0, 0, 0, 0.1);
}
body:not(.dark) .edge {
opacity: 0.7;
}
body:not(.dark) .edge:hover,
body:not(.dark) .edge.selected {
opacity: 1;
}
/* Footer im Light Mode */
body:not(.dark) footer {
background-color: rgba(249, 250, 251, 0.7);
border-top: 1px solid #e5e7eb;
}
/* Alpine.js Transitions im Light Mode */
body:not(.dark) [x-cloak] {
display: none !important;
}
/* Suchfeldstyling im Light Mode */
body:not(.dark) .search-container input {
background-color: white;
border: 1px solid #d1d5db;
color: #1f2937;
}
body:not(.dark) .search-container input:focus {
border-color: var(--light-primary);
box-shadow: 0 0 0 2px rgba(124, 58, 237, 0.2);
}
body:not(.dark) .search-results {
background-color: white;
border: 1px solid #e5e7eb;
box-shadow: 0 4px 6px -1px rgba(0, 0, 0, 0.1), 0 2px 4px -1px rgba(0, 0, 0, 0.06);
}
body:not(.dark) .search-result-item:hover {
background-color: #f3f4f6;
}
/* Profile und Benutzermenü im Light Mode */
body:not(.dark) .avatar {
border: 2px solid white;
box-shadow: 0 2px 5px rgba(0, 0, 0, 0.1);
}
body:not(.dark) .user-dropdown {
background-color: white;
border: 1px solid #e5e7eb;
box-shadow: 0 4px 6px -1px rgba(0, 0, 0, 0.1), 0 2px 4px -1px rgba(0, 0, 0, 0.06);
}
body:not(.dark) .user-dropdown-item:hover {
background-color: #f3f4f6;
}
File diff suppressed because it is too large Load Diff
Binary file not shown.
+86 -32
View File
@@ -69,8 +69,8 @@
<link href="{{ url_for('static', filename='fonts/inter.css') }}" rel="stylesheet"> <link href="{{ url_for('static', filename='fonts/inter.css') }}" rel="stylesheet">
<link href="{{ url_for('static', filename='fonts/jetbrains-mono.css') }}" rel="stylesheet"> <link href="{{ url_for('static', filename='fonts/jetbrains-mono.css') }}" rel="stylesheet">
<!-- Icons - Self-hosted Font Awesome --> <!-- Font Awesome vom CDN -->
<link href="{{ url_for('static', filename='css/all.min.css') }}" rel="stylesheet"> <link href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.5.1/css/all.min.css" rel="stylesheet">
<!-- Assistent CSS --> <!-- Assistent CSS -->
<link href="{{ url_for('static', filename='css/assistant.css') }}" rel="stylesheet"> <link href="{{ url_for('static', filename='css/assistant.css') }}" rel="stylesheet">
@@ -111,7 +111,7 @@
<!-- Seitenspezifische Styles --> <!-- Seitenspezifische Styles -->
{% block extra_css %}{% endblock %} {% block extra_css %}{% endblock %}
<!-- Custom dark mode styles --> <!-- Custom dark/light mode styles -->
<!-- ► ► FarbToken strikt getrennt ◄ ◄ --> <!-- ► ► FarbToken strikt getrennt ◄ ◄ -->
<style> <style>
/* LightMode */ /* LightMode */
@@ -149,6 +149,39 @@
.glass-navbar { @apply glass-morphism border backdrop-blur-xl; } .glass-navbar { @apply glass-morphism border backdrop-blur-xl; }
.light .glass-navbar { background-color:rgba(255,255,255,.8); border-color:rgba(0,0,0,.05); } .light .glass-navbar { background-color:rgba(255,255,255,.8); border-color:rgba(0,0,0,.05); }
.dark .glass-navbar { background-color:rgba(10,14,25,.8); border-color:rgba(255,255,255,.05); } .dark .glass-navbar { background-color:rgba(10,14,25,.8); border-color:rgba(255,255,255,.05); }
/* Light-Mode spezifische Stile */
body:not(.dark) {
background-color: var(--bg-primary);
color: var(--text-primary);
}
.nav-link-light {
color: var(--text-secondary);
transition: all 0.3s ease;
}
.nav-link-light:hover {
color: var(--text-primary);
background-color: rgba(126, 34, 206, 0.1);
}
.nav-link-light-active {
color: var(--accent-primary);
background-color: rgba(126, 34, 206, 0.15);
font-weight: 500;
}
/* Kartendesign im Light-Mode */
body:not(.dark) .card {
background-color: white;
border: 1px solid #e5e7eb;
box-shadow: 0 4px 6px -1px rgba(0, 0, 0, 0.1), 0 2px 4px -1px rgba(0, 0, 0, 0.06);
}
body:not(.dark) .card:hover {
box-shadow: 0 10px 15px -3px rgba(0, 0, 0, 0.1), 0 4px 6px -2px rgba(0, 0, 0, 0.05);
}
</style> </style>
</head> </head>
<body data-page="{{ request.endpoint }}" class="relative overflow-x-hidden dark bg-gray-900 text-white" x-data="{ <body data-page="{{ request.endpoint }}" class="relative overflow-x-hidden dark bg-gray-900 text-white" x-data="{
@@ -158,6 +191,17 @@
showSettingsModal: false, showSettingsModal: false,
init() { init() {
this.initDarkMode();
},
initDarkMode() {
// Lade zuerst den Wert aus dem localStorage (client-seitig)
const storedMode = localStorage.getItem('colorMode');
if (storedMode) {
this.darkMode = storedMode === 'dark';
}
// Dann hole die Server-Einstellung, die Vorrang hat
this.fetchDarkModeFromSession(); this.fetchDarkModeFromSession();
}, },
@@ -167,7 +211,7 @@
.then(data => { .then(data => {
if (data.success) { if (data.success) {
this.darkMode = data.darkMode === 'true'; this.darkMode = data.darkMode === 'true';
document.querySelector('html').classList.toggle('dark', this.darkMode); this.applyDarkMode();
} }
}) })
.catch(error => { .catch(error => {
@@ -175,9 +219,15 @@
}); });
}, },
applyDarkMode() {
document.querySelector('html').classList.toggle('dark', this.darkMode);
document.querySelector('body').classList.toggle('dark', this.darkMode);
localStorage.setItem('colorMode', this.darkMode ? 'dark' : 'light');
},
toggleDarkMode() { toggleDarkMode() {
this.darkMode = !this.darkMode; this.darkMode = !this.darkMode;
document.querySelector('html').classList.toggle('dark', this.darkMode); this.applyDarkMode();
fetch('/api/set_dark_mode', { fetch('/api/set_dark_mode', {
method: 'POST', method: 'POST',
@@ -189,7 +239,6 @@
.then(response => response.json()) .then(response => response.json())
.then(data => { .then(data => {
if (data.success) { if (data.success) {
localStorage.setItem('darkMode', this.darkMode ? 'dark' : 'light');
document.dispatchEvent(new CustomEvent('darkModeToggled', { document.dispatchEvent(new CustomEvent('darkModeToggled', {
detail: { isDark: this.darkMode } detail: { isDark: this.darkMode }
})); }));
@@ -578,37 +627,42 @@
}); });
</script> </script>
<!-- Dark/Light-Mode persistent und robust --> <!-- Dark/Light-Mode vereinheitlicht -->
<script> <script>
(function() { // Globaler Zugriff für externe Skripte
function applyMode(mode) { window.MindMap = window.MindMap || {};
if (mode === 'dark') {
document.documentElement.classList.add('dark'); window.MindMap.toggleDarkMode = function() {
localStorage.setItem('colorMode', 'dark'); // Alpine.js-Instanz benutzen, wenn verfügbar
const appEl = document.querySelector('body');
if (appEl && appEl.__x) {
appEl.__x.$data.toggleDarkMode();
} else { } else {
document.documentElement.classList.remove('dark'); // Fallback: Nur classList und localStorage
localStorage.setItem('colorMode', 'light');
}
}
// Beim Laden: Präferenz aus localStorage oder System übernehmen
const stored = localStorage.getItem('colorMode');
if (stored === 'dark' || stored === 'light') {
applyMode(stored);
} else {
// Systempräferenz als Fallback
const prefersDark = window.matchMedia('(prefers-color-scheme: dark)').matches;
applyMode(prefersDark ? 'dark' : 'light');
}
// Umschalter für alle Mode-Toggles
window.toggleColorMode = function() {
const isDark = document.documentElement.classList.contains('dark'); const isDark = document.documentElement.classList.contains('dark');
applyMode(isDark ? 'light' : 'dark'); document.documentElement.classList.toggle('dark', !isDark);
document.body.classList.toggle('dark', !isDark);
localStorage.setItem('colorMode', !isDark ? 'dark' : 'light');
// Server aktualisieren
fetch('/api/set_dark_mode', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ darkMode: !isDark })
}).catch(console.error);
}
}; };
// Optional: globales Event für andere Skripte
window.addEventListener('storage', function(e) { // Fallback für Browser-Präferenz, falls keine Einstellung geladen werden konnte
if (e.key === 'colorMode') applyMode(e.newValue); document.addEventListener('DOMContentLoaded', function() {
if (!document.body.classList.contains('dark') && !document.documentElement.classList.contains('dark')) {
const prefersDark = window.matchMedia('(prefers-color-scheme: dark)').matches;
if (prefersDark) {
document.documentElement.classList.add('dark');
document.body.classList.add('dark');
}
}
}); });
})();
</script> </script>
</body> </body>
</html> </html>
+192 -161
View File
@@ -1,115 +1,53 @@
<!DOCTYPE html> {% extends "base.html" %}
<html lang="de">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Interaktive Mindmap</title>
<!-- Cytoscape.js --> {% block title %}Mindmap{% endblock %}
<script src="https://cdnjs.cloudflare.com/ajax/libs/cytoscape/3.26.0/cytoscape.min.js"></script>
<!-- Socket.IO -->
<script src="https://cdnjs.cloudflare.com/ajax/libs/socket.io/4.7.2/socket.io.min.js"></script>
<!-- Feather Icons (optional) -->
<script src="https://cdn.jsdelivr.net/npm/feather-icons/dist/feather.min.js"></script>
{% block extra_css %}
<style> <style>
* { /* Spezifische Stile für die Mindmap-Seite */
box-sizing: border-box; #cy {
margin: 0;
padding: 0;
}
body {
font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
background-color: #f9fafb;
color: #111827;
line-height: 1.5;
}
.container {
display: flex;
flex-direction: column;
height: 100vh;
width: 100%; width: 100%;
height: 600px;
background-color: var(--bg-secondary);
transition: background-color 0.3s ease;
border-radius: 10px;
overflow: hidden;
position: relative;
} }
.header { .mindmap-container {
background-color: #1f2937; position: relative;
color: white; border-radius: 10px;
padding: 1rem; overflow: hidden;
display: flex; box-shadow: 0 4px 12px rgba(0, 0, 0, 0.1);
justify-content: space-between; transition: all 0.3s ease;
align-items: center;
} }
.header h1 { .dark .mindmap-container {
font-size: 1.5rem; box-shadow: 0 4px 20px rgba(0, 0, 0, 0.2);
font-weight: 500;
} }
.toolbar { .mindmap-toolbar {
background-color: #f3f4f6;
padding: 0.75rem;
display: flex; display: flex;
gap: 0.5rem; gap: 0.5rem;
border-bottom: 1px solid #e5e7eb; flex-wrap: wrap;
padding: 0.75rem;
background-color: var(--bg-secondary);
border-bottom: 1px solid rgba(255, 255, 255, 0.1);
transition: background-color 0.3s ease;
}
body:not(.dark) .mindmap-toolbar {
border-bottom: 1px solid rgba(0, 0, 0, 0.1);
} }
.btn { .btn {
background-color: #3b82f6;
color: white;
border: none;
border-radius: 0.25rem;
padding: 0.5rem 1rem;
font-size: 0.875rem;
cursor: pointer;
transition: background-color 0.2s;
display: flex; display: flex;
align-items: center; align-items: center;
gap: 0.5rem; gap: 0.5rem;
}
.btn:hover {
background-color: #2563eb;
}
.btn-secondary {
background-color: #6b7280;
}
.btn-secondary:hover {
background-color: #4b5563;
}
.btn-danger {
background-color: #ef4444;
}
.btn-danger:hover {
background-color: #dc2626;
}
.search-container {
flex: 1;
display: flex;
margin-left: 1rem;
}
.search-input {
width: 100%;
max-width: 300px;
padding: 0.5rem;
border: 1px solid #d1d5db;
border-radius: 0.25rem;
font-size: 0.875rem; font-size: 0.875rem;
} border-radius: 0.375rem;
transition: all 0.3s ease;
#cy {
flex: 1;
width: 100%;
position: relative;
} }
.category-filters { .category-filters {
@@ -117,8 +55,8 @@
gap: 0.5rem; gap: 0.5rem;
flex-wrap: wrap; flex-wrap: wrap;
padding: 0.75rem; padding: 0.75rem;
background-color: #ffffff; background-color: var(--bg-secondary);
border-bottom: 1px solid #e5e7eb; transition: background-color 0.3s ease;
} }
.category-filter { .category-filter {
@@ -139,96 +77,189 @@
opacity: 0.8; opacity: 0.8;
} }
.footer { /* Kontextmenü */
background-color: #f3f4f6;
padding: 0.75rem;
text-align: center;
font-size: 0.75rem;
color: #6b7280;
border-top: 1px solid #e5e7eb;
}
/* Kontextmenü Styling */
#context-menu { #context-menu {
position: absolute; position: absolute;
background-color: white; border-radius: 0.375rem;
border: 1px solid #e5e7eb;
border-radius: 0.25rem;
box-shadow: 0 2px 10px rgba(0, 0, 0, 0.1);
z-index: 1000; z-index: 1000;
box-shadow: 0 4px 15px rgba(0, 0, 0, 0.1);
overflow: hidden;
}
.dark #context-menu {
background-color: #232837;
border: 1px solid rgba(255, 255, 255, 0.1);
}
body:not(.dark) #context-menu {
background-color: white;
border: 1px solid rgba(0, 0, 0, 0.1);
} }
#context-menu .menu-item { #context-menu .menu-item {
padding: 0.5rem 1rem; padding: 0.5rem 1rem;
cursor: pointer; cursor: pointer;
transition: background-color 0.2s ease;
} }
#context-menu .menu-item:hover { .dark #context-menu .menu-item:hover {
background-color: #f3f4f6; background-color: rgba(255, 255, 255, 0.05);
}
body:not(.dark) #context-menu .menu-item:hover {
background-color: rgba(0, 0, 0, 0.05);
}
/* Zusätzliches Layout */
.mindmap-section {
display: grid;
grid-template-columns: 1fr;
gap: 1.5rem;
}
@media (min-width: 1024px) {
.mindmap-section {
grid-template-columns: 2fr 1fr;
}
} }
</style> </style>
</head> {% endblock %}
<body>
<div class="container">
<header class="header">
<h1>Interaktive Mindmap</h1>
<div class="search-container">
<input type="text" id="search-mindmap" class="search-input" placeholder="Suchen...">
</div>
</header>
<div class="toolbar"> {% block content %}
<button id="addNode" class="btn"> <div class="container mx-auto px-4 py-8">
<i data-feather="plus-circle"></i> <div class="flex flex-col lg:flex-row gap-8">
Knoten hinzufügen <!-- Hauptinhalt -->
<div class="w-full lg:w-3/4">
<!-- Mindmap-Titelbereich -->
<div class="mb-6">
<h1 class="text-3xl font-bold mb-2 mystical-glow"
x-bind:class="darkMode ? 'text-white' : 'text-gray-800'">
Wissenslandkarte
</h1>
<p class="opacity-80 text-lg"
x-bind:class="darkMode ? 'text-gray-300' : 'text-gray-600'">
Visualisiere die Verbindungen zwischen Gedanken und Konzepten
</p>
</div>
<!-- Mindmap-Container -->
<div class="mindmap-container">
<!-- Toolbar -->
<div class="mindmap-toolbar">
<button id="fit-btn" class="mindmap-action-btn">
<i class="fa-solid fa-expand"></i>
<span>Ansicht anpassen</span>
</button> </button>
<button id="addEdge" class="btn"> <button id="reset-btn" class="mindmap-action-btn">
<i data-feather="git-branch"></i> <i class="fa-solid fa-undo"></i>
Verbindung erstellen <span>Zurücksetzen</span>
</button> </button>
<button id="editNode" class="btn btn-secondary"> <button id="toggle-labels-btn" class="mindmap-action-btn">
<i data-feather="edit-2"></i> <i class="fa-solid fa-tags"></i>
Knoten bearbeiten <span>Labels ein/aus</span>
</button>
<button id="deleteNode" class="btn btn-danger">
<i data-feather="trash-2"></i>
Knoten löschen
</button>
<button id="deleteEdge" class="btn btn-danger">
<i data-feather="scissors"></i>
Verbindung löschen
</button>
<button id="reLayout" class="btn btn-secondary">
<i data-feather="refresh-cw"></i>
Layout neu anordnen
</button>
<button id="exportMindmap" class="btn btn-secondary">
<i data-feather="download"></i>
Exportieren
</button> </button>
</div> </div>
<div id="category-filters" class="category-filters"> <!-- Hauptvisualisierung -->
<!-- Wird dynamisch befüllt -->
</div>
<div id="cy"></div> <div id="cy"></div>
<footer class="footer"> <!-- Info-Panel -->
Mindmap-Anwendung © 2023 <div id="node-info-panel" class="mindmap-info-panel">
</footer> <h4 class="info-panel-title">Knoteninfo</h4>
<p id="node-description" class="info-panel-description">Wählen Sie einen Knoten aus...</p>
<div class="node-navigation">
<h5 class="node-navigation-title">Verknüpfte Knoten</h5>
<div id="connected-nodes" class="node-links">
<!-- Wird dynamisch befüllt -->
</div>
</div>
</div>
</div>
</div> </div>
<!-- Unsere Mindmap JS --> <!-- Seitenleiste -->
<script src="{{ url_for('static', filename='js/mindmap.js') }}"></script> <div class="w-full lg:w-1/4 space-y-6">
<!-- Nutzlänge -->
<div class="p-5 rounded-lg overflow-hidden border transition-colors duration-300"
x-bind:class="darkMode ? 'bg-slate-800/40 border-slate-700/50' : 'bg-white border-slate-200'">
<h3 class="text-xl font-semibold mb-3"
x-bind:class="darkMode ? 'text-white' : 'text-gray-800'">
<i class="fa-solid fa-circle-info text-purple-400 mr-2"></i>Über die Mindmap
</h3>
<div x-bind:class="darkMode ? 'text-gray-300' : 'text-gray-600'">
<p class="mb-2">Die interaktive Wissenslandkarte zeigt Verbindungen zwischen verschiedenen Gedanken und Konzepten.</p>
<p class="mb-2">Sie können:</p>
<ul class="list-disc pl-5 space-y-1 text-sm">
<li>Knoten auswählen, um Details zu sehen</li>
<li>Zoomen (Mausrad oder Pinch-Geste)</li>
<li>Die Karte verschieben (Drag & Drop)</li>
<li>Die Toolbar nutzen für weitere Aktionen</li>
</ul>
</div>
</div>
<!-- Icons initialisieren --> <!-- Kategorienlegende -->
<div class="p-5 rounded-lg overflow-hidden border transition-colors duration-300"
x-bind:class="darkMode ? 'bg-slate-800/40 border-slate-700/50' : 'bg-white border-slate-200'">
<h3 class="text-xl font-semibold mb-3"
x-bind:class="darkMode ? 'text-white' : 'text-gray-800'">
<i class="fa-solid fa-palette text-purple-400 mr-2"></i>Kategorien
</h3>
<div id="category-legend" class="space-y-2 text-sm"
x-bind:class="darkMode ? 'text-gray-300' : 'text-gray-600'">
<!-- Wird dynamisch befüllt -->
<div class="flex items-center"><span class="w-3 h-3 rounded-full bg-purple-500 mr-2"></span> Philosophie</div>
<div class="flex items-center"><span class="w-3 h-3 rounded-full bg-green-500 mr-2"></span> Wissenschaft</div>
<div class="flex items-center"><span class="w-3 h-3 rounded-full bg-orange-500 mr-2"></span> Technologie</div>
<div class="flex items-center"><span class="w-3 h-3 rounded-full bg-pink-500 mr-2"></span> Künste</div>
<div class="flex items-center"><span class="w-3 h-3 rounded-full bg-blue-500 mr-2"></span> Psychologie</div>
</div>
</div>
<!-- Meine Mindmaps -->
{% if current_user.is_authenticated %}
<div class="p-5 rounded-lg overflow-hidden border transition-colors duration-300"
x-bind:class="darkMode ? 'bg-slate-800/40 border-slate-700/50' : 'bg-white border-slate-200'">
<h3 class="text-xl font-semibold mb-3"
x-bind:class="darkMode ? 'text-white' : 'text-gray-800'">
<i class="fa-solid fa-map text-purple-400 mr-2"></i>Meine Mindmaps
</h3>
<div class="mb-3">
<a href="{{ url_for('create_mindmap') }}" class="w-full inline-block py-2 px-4 bg-purple-600 hover:bg-purple-700 text-white rounded-lg text-center text-sm font-medium transition-colors">
<i class="fa-solid fa-plus mr-1"></i> Neue Mindmap erstellen
</a>
</div>
<div class="space-y-2 max-h-60 overflow-y-auto"
x-bind:class="darkMode ? 'text-gray-300' : 'text-gray-600'">
{% if user_mindmaps %}
{% for mindmap in user_mindmaps %}
<a href="{{ url_for('user_mindmap', mindmap_id=mindmap.id) }}" class="block p-2 hover:bg-purple-500/20 rounded-lg transition-colors">
<div class="text-sm font-medium">{{ mindmap.name }}</div>
<div class="text-xs opacity-70">{{ mindmap.nodes|length }} Knoten</div>
</a>
{% endfor %}
{% else %}
<p class="text-sm italic">Sie haben noch keine eigenen Mindmaps erstellt.</p>
{% endif %}
</div>
</div>
{% endif %}
</div>
</div>
</div>
{% endblock %}
{% block extra_js %}
<script> <script>
document.addEventListener('DOMContentLoaded', () => { // Sobald die Seite und die Scripte geladen sind, initialisiere die Mindmap
if (typeof feather !== 'undefined') { document.addEventListener('DOMContentLoaded', function() {
feather.replace(); if (window.MindMap && window.MindMap.pageInitializers && window.MindMap.pageInitializers.mindmap) {
window.MindMap.pageInitializers.mindmap();
} else {
console.error('Mindmap-Initialisierung konnte nicht gefunden werden!');
} }
}); });
</script> </script>
</body> {% endblock %}
</html>
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.
View File
-58
View File
@@ -1,58 +0,0 @@
@echo off
echo Mindmap Projekt - Windows Setup
echo ==============================
echo.
REM Prüfen, ob Python installiert ist
python --version >nul 2>&1
if %errorlevel% neq 0 (
echo Python ist nicht installiert oder nicht im PATH.
echo Bitte installiere Python 3.11 von https://www.python.org/downloads/
echo und stelle sicher, dass "Add Python to PATH" während der Installation aktiviert ist.
pause
exit /b 1
)
echo Erstelle virtuelle Umgebung...
python -m venv venv
if %errorlevel% neq 0 (
echo Fehler beim Erstellen der virtuellen Umgebung.
pause
exit /b 1
)
echo Aktiviere virtuelle Umgebung...
call venv\Scripts\activate.bat
if %errorlevel% neq 0 (
echo Fehler beim Aktivieren der virtuellen Umgebung.
pause
exit /b 1
)
echo Aktualisiere pip...
python -m pip install --upgrade pip
if %errorlevel% neq 0 (
echo Warnung: Pip konnte nicht aktualisiert werden. Fahre trotzdem fort.
)
echo Installiere Abhängigkeiten...
pip install -r requirements.txt
if %errorlevel% neq 0 (
echo Fehler beim Installieren der Abhängigkeiten.
pause
exit /b 1
)
echo.
echo Setup abgeschlossen!
echo.
echo Zum Starten des Servers:
echo 1. Führe "venv\Scripts\activate.bat" aus
echo 2. Führe "python TOOLS.py db:rebuild" aus (Nur beim ersten Mal oder zum Zurücksetzen der Datenbank)
echo 3. Führe "python TOOLS.py user:admin" aus (Erstellt einen Admin-Benutzer: admin/admin)
echo 4. Führe "python TOOLS.py server:run" aus
echo.
echo Die Anwendung ist dann unter http://localhost:5000 erreichbar.
echo.
pause