Compare commits

..

42 Commits

Author SHA1 Message Date
cb3bfe0e6a LOL 2025-05-01 19:57:26 +01:00
fd63810845 feat: update environment and scripts for improved functionality 2025-05-01 16:29:57 +02:00
883973fe7b feat: update environment variables and enhance mindmap functionality 2025-05-01 16:27:40 +02:00
027e632856 feat: update example.env with new configuration settings 2025-05-01 16:24:29 +02:00
406289e54f 🎨 feat(mindmap): improve rendering performance and optimize code structure 2025-05-01 16:16:26 +02:00
71b33e6cec feat(mindmap): enhance mindmap rendering performance and responsiveness 2025-05-01 16:14:14 +02:00
c74d3164bb 🎨 feat: update mindmap templates and JS module for improved UI design 2025-05-01 16:11:42 +02:00
4982cddeef 🎉 feat: update Dockerfile and scripts for improved functionality 2025-05-01 16:05:52 +02:00
631619ccb4 feat: update docker-compose.yml for improved service configuration 2025-05-01 16:01:00 +02:00
f9881b678d 🔄 chore: aktualisiere die .env-Datei für verbesserte Konfiguration 2025-05-01 11:27:11 +01:00
259ce3cf69 feat: update Dockerfile and docker-compose for improved build process 2025-05-01 11:24:27 +01:00
9f4743eaea feat: update cached Python files and add new static image asset 2025-05-01 10:55:30 +01:00
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
1c49ddfb19 chore: automatic commit 2025-04-30 15:49 2025-04-30 15:49:18 +02:00
46c16e5f01 chore: automatic commit 2025-04-30 15:44 2025-04-30 15:44:02 +02:00
84667bca00 chore: automatic commit 2025-04-30 15:41 2025-04-30 15:41:00 +02:00
779449559d chore: automatic commit 2025-04-30 15:38 2025-04-30 15:38:56 +02:00
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
a431873ca2 chore: automatic commit 2025-04-30 15:29 2025-04-30 15:29:23 +02:00
e4ab1e1bb5 chore: automatic commit 2025-04-30 12:48 2025-04-30 12:48:06 +02:00
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
38ac13e87c chore: automatic commit 2025-04-30 12:32 2025-04-30 12:32:36 +02:00
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
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
4aba72efa2 Merge branch 'main' of https://git.clickcandit.com/marwinm/website 2025-04-29 20:52:11 +01:00
89476d5353 w 2025-04-29 20:51:49 +01:00
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
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
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
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
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
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
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
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
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
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
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
e9fe907af0 Update requirements.txt to include email_validator==2.1.1 for improved email validation functionality. 2025-04-20 19:29:19 +01:00
0c69d9aba3 Remove unnecessary 'force' option from docker-compose.yml for cleaner configuration. 2025-04-20 19:26:44 +01:00
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
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
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
.env

Binary file not shown.

33
Dockerfile Normal file
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.

BIN
backup/archiv_0.1.zip Normal file

Binary file not shown.

17
docker-compose.yml Normal file
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
edit_file Normal file
View File

@@ -0,0 +1 @@

View File

@@ -2,10 +2,12 @@
# Kopiere diese Datei zu .env und passe die Werte an
# 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_KEY=sk-dein-openai-api-schluessel-hier
OPENAI_API_KEY=your-openai-api-key
# Datenbank
# Bei Bedarf kann hier eine andere Datenbank-URL angegeben werden

53
start.sh Normal file
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 "----------------------------------------"

View File

@@ -0,0 +1 @@

View File

@@ -40,8 +40,8 @@
--light-bg: #f9fafb;
--light-text: #1e293b;
--light-heading: #0f172a;
--light-primary: #3b82f6;
--light-primary-hover: #4f46e5;
--light-primary: #7c3aed;
--light-primary-hover: #6d28d9;
--light-secondary: #6b7280;
--light-border: #e5e7eb;
--light-card-bg: rgba(255, 255, 255, 0.92);
@@ -523,4 +523,232 @@ body:not(.dark) .navbar {
background-color: var(--light-navbar-bg);
box-shadow: var(--light-shadow);
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.

View File

@@ -69,8 +69,8 @@
<link href="{{ url_for('static', filename='fonts/inter.css') }}" rel="stylesheet">
<link href="{{ url_for('static', filename='fonts/jetbrains-mono.css') }}" rel="stylesheet">
<!-- Icons - Self-hosted Font Awesome -->
<link href="{{ url_for('static', filename='css/all.min.css') }}" rel="stylesheet">
<!-- Font Awesome vom CDN -->
<link href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.5.1/css/all.min.css" rel="stylesheet">
<!-- Assistent CSS -->
<link href="{{ url_for('static', filename='css/assistant.css') }}" rel="stylesheet">
@@ -111,7 +111,7 @@
<!-- Seitenspezifische Styles -->
{% block extra_css %}{% endblock %}
<!-- Custom dark mode styles -->
<!-- Custom dark/light mode styles -->
<!-- ► ► FarbToken strikt getrennt ◄ ◄ -->
<style>
/* LightMode */
@@ -149,6 +149,39 @@
.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); }
.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>
</head>
<body data-page="{{ request.endpoint }}" class="relative overflow-x-hidden dark bg-gray-900 text-white" x-data="{
@@ -158,6 +191,17 @@
showSettingsModal: false,
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();
},
@@ -167,7 +211,7 @@
.then(data => {
if (data.success) {
this.darkMode = data.darkMode === 'true';
document.querySelector('html').classList.toggle('dark', this.darkMode);
this.applyDarkMode();
}
})
.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() {
this.darkMode = !this.darkMode;
document.querySelector('html').classList.toggle('dark', this.darkMode);
this.applyDarkMode();
fetch('/api/set_dark_mode', {
method: 'POST',
@@ -189,7 +239,6 @@
.then(response => response.json())
.then(data => {
if (data.success) {
localStorage.setItem('darkMode', this.darkMode ? 'dark' : 'light');
document.dispatchEvent(new CustomEvent('darkModeToggled', {
detail: { isDark: this.darkMode }
}));
@@ -578,37 +627,42 @@
});
</script>
<!-- Dark/Light-Mode persistent und robust -->
<!-- Dark/Light-Mode vereinheitlicht -->
<script>
(function() {
function applyMode(mode) {
if (mode === 'dark') {
// Globaler Zugriff für externe Skripte
window.MindMap = window.MindMap || {};
window.MindMap.toggleDarkMode = function() {
// Alpine.js-Instanz benutzen, wenn verfügbar
const appEl = document.querySelector('body');
if (appEl && appEl.__x) {
appEl.__x.$data.toggleDarkMode();
} else {
// Fallback: Nur classList und localStorage
const isDark = document.documentElement.classList.contains('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);
}
};
// Fallback für Browser-Präferenz, falls keine Einstellung geladen werden konnte
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');
localStorage.setItem('colorMode', 'dark');
} else {
document.documentElement.classList.remove('dark');
localStorage.setItem('colorMode', 'light');
document.body.classList.add('dark');
}
}
// Beim Laden: Präferenz aus localStorage oder System übernehmen
const stored = localStorage.getItem('colorMode');
if (stored === 'dark' || stored === 'light') {
applyMode(stored);
} else {
// Systempräferenz als Fallback
const prefersDark = window.matchMedia('(prefers-color-scheme: dark)').matches;
applyMode(prefersDark ? 'dark' : 'light');
}
// Umschalter für alle Mode-Toggles
window.toggleColorMode = function() {
const isDark = document.documentElement.classList.contains('dark');
applyMode(isDark ? 'light' : 'dark');
};
// Optional: globales Event für andere Skripte
window.addEventListener('storage', function(e) {
if (e.key === 'colorMode') applyMode(e.newValue);
});
})();
});
</script>
</body>
</html>

View File

@@ -1,234 +1,265 @@
<!DOCTYPE html>
<html lang="de">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Interaktive Mindmap</title>
{% extends "base.html" %}
{% block title %}Mindmap{% endblock %}
{% block extra_css %}
<style>
/* Spezifische Stile für die Mindmap-Seite */
#cy {
width: 100%;
height: 600px;
background-color: var(--bg-secondary);
transition: background-color 0.3s ease;
border-radius: 10px;
overflow: hidden;
position: relative;
}
<!-- Cytoscape.js -->
<script src="https://cdnjs.cloudflare.com/ajax/libs/cytoscape/3.26.0/cytoscape.min.js"></script>
.mindmap-container {
position: relative;
border-radius: 10px;
overflow: hidden;
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.1);
transition: all 0.3s ease;
}
<!-- Socket.IO -->
<script src="https://cdnjs.cloudflare.com/ajax/libs/socket.io/4.7.2/socket.io.min.js"></script>
.dark .mindmap-container {
box-shadow: 0 4px 20px rgba(0, 0, 0, 0.2);
}
<!-- Feather Icons (optional) -->
<script src="https://cdn.jsdelivr.net/npm/feather-icons/dist/feather.min.js"></script>
.mindmap-toolbar {
display: flex;
gap: 0.5rem;
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;
}
<style>
* {
box-sizing: border-box;
margin: 0;
padding: 0;
body:not(.dark) .mindmap-toolbar {
border-bottom: 1px solid rgba(0, 0, 0, 0.1);
}
.btn {
display: flex;
align-items: center;
gap: 0.5rem;
font-size: 0.875rem;
border-radius: 0.375rem;
transition: all 0.3s ease;
}
.category-filters {
display: flex;
gap: 0.5rem;
flex-wrap: wrap;
padding: 0.75rem;
background-color: var(--bg-secondary);
transition: background-color 0.3s ease;
}
.category-filter {
border: none;
border-radius: 0.25rem;
padding: 0.25rem 0.75rem;
font-size: 0.75rem;
cursor: pointer;
transition: opacity 0.2s;
color: white;
}
.category-filter:not(.active) {
opacity: 0.6;
}
.category-filter:hover:not(.active) {
opacity: 0.8;
}
/* Kontextmenü */
#context-menu {
position: absolute;
border-radius: 0.375rem;
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 {
padding: 0.5rem 1rem;
cursor: pointer;
transition: background-color 0.2s ease;
}
.dark #context-menu .menu-item:hover {
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;
}
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%;
}
.header {
background-color: #1f2937;
color: white;
padding: 1rem;
display: flex;
justify-content: space-between;
align-items: center;
}
.header h1 {
font-size: 1.5rem;
font-weight: 500;
}
.toolbar {
background-color: #f3f4f6;
padding: 0.75rem;
display: flex;
gap: 0.5rem;
border-bottom: 1px solid #e5e7eb;
}
.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;
align-items: center;
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;
}
#cy {
flex: 1;
width: 100%;
position: relative;
}
.category-filters {
display: flex;
gap: 0.5rem;
flex-wrap: wrap;
padding: 0.75rem;
background-color: #ffffff;
border-bottom: 1px solid #e5e7eb;
}
.category-filter {
border: none;
border-radius: 0.25rem;
padding: 0.25rem 0.75rem;
font-size: 0.75rem;
cursor: pointer;
transition: opacity 0.2s;
color: white;
}
.category-filter:not(.active) {
opacity: 0.6;
}
.category-filter:hover:not(.active) {
opacity: 0.8;
}
.footer {
background-color: #f3f4f6;
padding: 0.75rem;
text-align: center;
font-size: 0.75rem;
color: #6b7280;
border-top: 1px solid #e5e7eb;
}
/* Kontextmenü Styling */
#context-menu {
position: absolute;
background-color: white;
border: 1px solid #e5e7eb;
border-radius: 0.25rem;
box-shadow: 0 2px 10px rgba(0, 0, 0, 0.1);
z-index: 1000;
}
#context-menu .menu-item {
padding: 0.5rem 1rem;
cursor: pointer;
}
#context-menu .menu-item:hover {
background-color: #f3f4f6;
}
</style>
</head>
<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...">
}
</style>
{% endblock %}
{% block content %}
<div class="container mx-auto px-4 py-8">
<div class="flex flex-col lg:flex-row gap-8">
<!-- 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 id="reset-btn" class="mindmap-action-btn">
<i class="fa-solid fa-undo"></i>
<span>Zurücksetzen</span>
</button>
<button id="toggle-labels-btn" class="mindmap-action-btn">
<i class="fa-solid fa-tags"></i>
<span>Labels ein/aus</span>
</button>
</div>
<!-- Hauptvisualisierung -->
<div id="cy"></div>
<!-- Info-Panel -->
<div id="node-info-panel" class="mindmap-info-panel">
<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>
</header>
<div class="toolbar">
<button id="addNode" class="btn">
<i data-feather="plus-circle"></i>
Knoten hinzufügen
</button>
<button id="addEdge" class="btn">
<i data-feather="git-branch"></i>
Verbindung erstellen
</button>
<button id="editNode" class="btn btn-secondary">
<i data-feather="edit-2"></i>
Knoten bearbeiten
</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>
</div>
<div id="category-filters" class="category-filters">
<!-- Wird dynamisch befüllt -->
<!-- Seitenleiste -->
<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>
<!-- 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 id="cy"></div>
<footer class="footer">
Mindmap-Anwendung © 2023
</footer>
</div>
<!-- Unsere Mindmap JS -->
<script src="{{ url_for('static', filename='js/mindmap.js') }}"></script>
<!-- Icons initialisieren -->
<script>
document.addEventListener('DOMContentLoaded', () => {
if (typeof feather !== 'undefined') {
feather.replace();
}
});
</script>
</body>
</html>
</div>
{% endblock %}
{% block extra_js %}
<script>
// Sobald die Seite und die Scripte geladen sind, initialisiere die Mindmap
document.addEventListener('DOMContentLoaded', function() {
if (window.MindMap && window.MindMap.pageInitializers && window.MindMap.pageInitializers.mindmap) {
window.MindMap.pageInitializers.mindmap();
} else {
console.error('Mindmap-Initialisierung konnte nicht gefunden werden!');
}
});
</script>
{% endblock %}

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