Update environment configuration and enhance app functionality: Add detailed comments to the .env file for better clarity, implement a route to reload environment variables dynamically, and ensure the .env file is loaded with force in the app. Remove obsolete build and development scripts to streamline the project structure. Update setup script to create a .env file if it doesn't exist, prompting users to configure necessary values.

This commit is contained in:
2025-04-27 07:28:05 +02:00
parent 5372fe220e
commit 8f0a6d4372
8 changed files with 537 additions and 579 deletions

View File

@@ -1 +1,13 @@
OPENAI_API_KEY=sk-placeholder
# MindMap Umgebungsvariablen
# Kopiere diese Datei zu .env und passe die Werte an
# Flask
SECRET_KEY=dein-geheimer-schluessel-hier
# OpenAI API
OPENAI_API_KEY=sk-dein-openai-api-schluessel-hier
# Datenbank
# Bei Bedarf kann hier eine andere Datenbank-URL angegeben werden
# Der Pfad wird relativ zum Projektverzeichnis angegeben
# SQLALCHEMY_DATABASE_URI=sqlite:////absoluter/pfad/zu/database/systades.db OPENAI_API_KEY=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

View File

@@ -26,7 +26,7 @@ from models import (
)
# Lade .env-Datei
load_dotenv()
load_dotenv(force=True) # force=True erzwingt die Synchronisierung
# Bestimme den absoluten Pfad zur Datenbank
basedir = os.path.abspath(os.path.dirname(__file__))
@@ -1126,6 +1126,31 @@ def dummy_network_bg():
"""Leere Antwort für die nicht mehr verwendeten Netzwerk-Hintergrundbilder."""
return '', 200
# Route zum expliziten Neu-Laden der Umgebungsvariablen
@app.route('/admin/reload-env', methods=['POST'])
@admin_required
def reload_env():
"""Lädt die Umgebungsvariablen aus der .env-Datei neu."""
try:
# Erzwinge das Neuladen der .env-Datei
load_dotenv(override=True, force=True)
# Aktualisiere OpenAI API-Key
openai.api_key = os.environ.get('OPENAI_API_KEY')
# Weitere Umgebungsvariablen hier aktualisieren, falls nötig
app.config['SECRET_KEY'] = os.environ.get('SECRET_KEY', app.config['SECRET_KEY'])
return jsonify({
'success': True,
'message': 'Umgebungsvariablen wurden erfolgreich neu geladen.'
})
except Exception as e:
return jsonify({
'success': False,
'message': f'Fehler beim Neuladen der Umgebungsvariablen: {str(e)}'
}), 500
# Flask starten
if __name__ == '__main__':
with app.app_context():

View File

@@ -1,104 +0,0 @@
#!/usr/bin/env python3
import os
import subprocess
import shutil
import platform
import tempfile
import zipfile
import requests
from pathlib import Path
def download_tailwind_cli():
"""Download the standalone Tailwind CLI for the current platform"""
# Get current system info
system = platform.system().lower()
arch = platform.machine().lower()
# Map to tailwind downloadable platform
if system == "linux":
platform_name = "linux"
elif system == "darwin":
platform_name = "macos"
elif system == "windows":
platform_name = "windows"
else:
raise Exception(f"Unsupported platform: {system}")
# Map architecture
if "arm" in arch or "aarch" in arch:
arch_name = "arm64"
elif "x86_64" in arch or "amd64" in arch or "x64" in arch:
arch_name = "x64"
else:
# Default to x64 for other architectures
arch_name = "x64"
# URL for the binary
url = f"https://github.com/tailwindlabs/tailwindcss/releases/latest/download/tailwindcss-{platform_name}-{arch_name}"
if system == "windows":
url += ".exe"
# Download location
bin_dir = Path("bin")
bin_dir.mkdir(exist_ok=True)
tailwind_bin = bin_dir / f"tailwindcss{'.exe' if system == 'windows' else ''}"
# Download if not exists
if not tailwind_bin.exists():
print(f"Downloading Tailwind CLI from {url}...")
response = requests.get(url, stream=True)
response.raise_for_status()
with open(tailwind_bin, 'wb') as f:
for chunk in response.iter_content(chunk_size=8192):
f.write(chunk)
# Make executable on Unix
if system != "windows":
os.chmod(tailwind_bin, 0o755)
return str(tailwind_bin)
def build_css(watch=False):
"""Build CSS using Tailwind CLI"""
base_dir = Path(__file__).parent
input_file = base_dir / "static" / "css" / "src" / "input.css"
output_file = base_dir / "static" / "css" / "main.css"
tailwind_bin = download_tailwind_cli()
config_file = base_dir / "tailwind.config.js"
# Prepare command
cmd = [
tailwind_bin,
"-i", str(input_file),
"-o", str(output_file),
"-c", str(config_file)
]
if watch:
cmd.append("--watch")
print(f"Running: {' '.join(cmd)}")
# Run the command
if watch:
process = subprocess.Popen(cmd)
try:
process.wait()
except KeyboardInterrupt:
process.terminate()
print("\nBuild process terminated")
else:
subprocess.run(cmd, check=True)
print(f"CSS built successfully: {output_file}")
if __name__ == "__main__":
import argparse
parser = argparse.ArgumentParser(description="Build Tailwind CSS")
parser.add_argument("--watch", action="store_true", help="Watch for changes")
args = parser.parse_args()
build_css(watch=args.watch)

View File

@@ -1,41 +0,0 @@
#!/usr/bin/env python3
import os
import sys
import subprocess
import threading
import time
from pathlib import Path
def run_flask():
"""Run the Flask development server"""
env = os.environ.copy()
env["FLASK_ENV"] = "development"
env["FLASK_DEBUG"] = "1"
# Import and run the Flask app
from run import app
app.run(debug=True, use_reloader=False)
def run_tailwind_watch():
"""Run the Tailwind CSS watcher"""
# Import the build_css function from build_css.py
from build_css import build_css
build_css(watch=True)
def main():
"""Run both the Flask server and Tailwind CSS watcher"""
print("Starting development environment...")
# Start Tailwind watcher in a separate thread
tailwind_thread = threading.Thread(target=run_tailwind_watch, daemon=True)
tailwind_thread.start()
# Give Tailwind a moment to start
time.sleep(1)
# Run Flask in the main thread
print("Starting Flask development server...")
run_flask()
if __name__ == "__main__":
main()

View File

@@ -2,10 +2,19 @@
import os
import sys
from pathlib import Path
from dotenv import load_dotenv
from init_db import init_database
from app import app
if __name__ == "__main__":
# Lade .env-Datei explizit
env_path = Path(__file__).parent / ".env"
if env_path.exists():
print(f"Lade Umgebungsvariablen aus {env_path}")
load_dotenv(dotenv_path=env_path, override=True, force=True)
else:
print("Warnung: .env-Datei nicht gefunden!")
# Check if CSS file exists, build it if it doesn't
css_file = Path(__file__).parent / "static" / "css" / "main.css"
if not css_file.exists():

View File

@@ -4,6 +4,7 @@
GREEN='\033[0;32m'
BLUE='\033[0;34m'
RED='\033[0;31m'
YELLOW='\033[0;33m'
NC='\033[0m' # No Color
echo -e "${GREEN}==== MindMap Projekt Setup ====${NC}"
@@ -15,6 +16,17 @@ mkdir -p static/img
mkdir -p static/js
mkdir -p bin
# Überprüfe, ob .env-Datei existiert und erstelle sie, wenn nicht
echo -e "${BLUE}Überprüfe .env-Datei...${NC}"
if [ ! -f ".env" ]; then
echo -e "${YELLOW}Keine .env-Datei gefunden. Erstelle neue .env-Datei aus example.env...${NC}"
cp example.env .env
echo -e "${YELLOW}Bitte bearbeiten Sie die .env-Datei und setzen Sie die erforderlichen Werte.${NC}"
echo -e "${YELLOW}Insbesondere müssen Sie einen gültigen API-Schlüssel für OpenAI setzen.${NC}"
else
echo -e "${GREEN}.env-Datei existiert bereits.${NC}"
fi
# Python-Abhängigkeiten installieren
echo -e "${BLUE}Installiere Python-Abhängigkeiten...${NC}"
pip install -r requirements.txt

View File

@@ -0,0 +1,426 @@
/* Globale Variablen */
:root {
--dark-bg: #0e1220;
--dark-card-bg: rgba(24, 28, 45, 0.8);
--dark-element-bg: rgba(24, 28, 45, 0.8);
--light-bg: #f0f4f8;
--light-card-bg: rgba(255, 255, 255, 0.85);
--accent-color: #b38fff;
--accent-gradient: linear-gradient(135deg, #b38fff, #58a9ff);
--accent-gradient-hover: linear-gradient(135deg, #c7a8ff, #70b5ff);
--blur-amount: 20px;
--border-radius: 28px;
--card-border-radius: 24px;
--button-radius: 18px;
--nav-item-radius: 14px;
}
/* Dark Mode Einstellungen */
html.dark {
color-scheme: dark;
}
/* Base Styles */
html, body {
background-color: var(--dark-bg) !important;
min-height: 100vh;
width: 100%;
color: #ffffff;
margin: 0;
padding: 0;
font-family: 'Inter', system-ui, -apple-system, sans-serif;
overflow-x: hidden;
transition: background-color 0.5s ease, color 0.5s ease;
}
/* Sicherstellen, dass der dunkle Hintergrund die gesamte Seite abdeckt */
#app-container, .container, main, .mx-auto, .py-12, #content-wrapper {
background-color: transparent !important;
width: 100%;
}
/* Light Mode Einstellungen */
html.light, html.light body {
background-color: var(--light-bg) !important;
color: #1a202c;
}
/* Große Headings mit verbesserten Stilen */
h1.hero-heading {
font-size: clamp(2.5rem, 8vw, 5rem);
line-height: 1.1;
font-weight: 800;
letter-spacing: -0.03em;
margin-bottom: 1.5rem;
}
h2.section-heading {
font-size: clamp(1.75rem, 5vw, 3rem);
line-height: 1.2;
font-weight: 700;
letter-spacing: -0.02em;
margin-bottom: 1.25rem;
}
/* Verbesserte Glasmorphismus-Stile */
.glass-morphism {
background: var(--dark-card-bg);
backdrop-filter: blur(var(--blur-amount));
-webkit-backdrop-filter: blur(var(--blur-amount));
border: 1px solid rgba(255, 255, 255, 0.12);
border-radius: var(--card-border-radius);
box-shadow: 0 12px 36px rgba(0, 0, 0, 0.35);
transition: all 0.3s ease;
}
.glass-morphism:hover {
border: 1px solid rgba(255, 255, 255, 0.2);
box-shadow: 0 16px 48px rgba(0, 0, 0, 0.45);
transform: translateY(-2px);
}
.glass-morphism-light {
background: var(--light-card-bg);
backdrop-filter: blur(var(--blur-amount));
-webkit-backdrop-filter: blur(var(--blur-amount));
border: 1px solid rgba(0, 0, 0, 0.08);
border-radius: var(--card-border-radius);
box-shadow: 0 10px 30px rgba(0, 0, 0, 0.12);
transition: all 0.3s ease;
}
.glass-morphism-light:hover {
border: 1px solid rgba(0, 0, 0, 0.15);
box-shadow: 0 16px 40px rgba(0, 0, 0, 0.18);
transform: translateY(-2px);
}
/* Verbesserte Navbar-Styles */
.glass-navbar-dark {
background: rgba(14, 18, 32, 0.85);
backdrop-filter: blur(15px);
-webkit-backdrop-filter: blur(15px);
border-color: rgba(255, 255, 255, 0.1);
box-shadow: 0 4px 20px rgba(0, 0, 0, 0.25);
border-radius: 0 0 20px 20px;
}
.glass-navbar-light {
background: rgba(255, 255, 255, 0.85);
backdrop-filter: blur(15px);
-webkit-backdrop-filter: blur(15px);
border-color: rgba(0, 0, 0, 0.05);
box-shadow: 0 4px 15px rgba(0, 0, 0, 0.08);
border-radius: 0 0 20px 20px;
}
/* Verbesserte Button-Stile mit besserer Lesbarkeit und stärkeren Farbverläufen */
.btn, button, .button, [type="button"], [type="submit"] {
transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
border-radius: var(--button-radius);
padding: 0.75rem 1.5rem;
font-weight: 600;
letter-spacing: 0.4px;
color: rgba(255, 255, 255, 1);
background: linear-gradient(135deg, rgba(99, 102, 241, 0.8), rgba(168, 85, 247, 0.8));
border: 1px solid rgba(255, 255, 255, 0.15);
box-shadow: 0 6px 14px rgba(0, 0, 0, 0.2);
text-shadow: 0 1px 2px rgba(0, 0, 0, 0.3);
backdrop-filter: blur(15px);
-webkit-backdrop-filter: blur(15px);
position: relative;
overflow: hidden;
outline: none;
}
.btn:hover, button:hover, .button:hover, [type="button"]:hover, [type="submit"]:hover {
background: linear-gradient(135deg, rgba(129, 140, 248, 0.9), rgba(192, 132, 252, 0.9));
transform: translateY(-3px);
border: 1px solid rgba(255, 255, 255, 0.3);
box-shadow: 0 8px 22px rgba(0, 0, 0, 0.25), 0 0 12px rgba(179, 143, 255, 0.35);
color: white;
}
.btn:active, button:active, .button:active, [type="button"]:active, [type="submit"]:active {
transform: translateY(1px);
box-shadow: 0 3px 8px rgba(0, 0, 0, 0.2);
}
/* Navigation Stile mit verbesserten Farbverläufen */
.nav-link {
transition: all 0.25s ease;
border-radius: var(--nav-item-radius);
padding: 0.625rem 1rem;
font-weight: 500;
letter-spacing: 0.3px;
color: rgba(255, 255, 255, 0.9);
position: relative;
overflow: visible;
}
.nav-link:hover {
background: rgba(179, 143, 255, 0.2);
color: white;
transform: translateY(-2px);
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.1);
}
.nav-link-active {
background: linear-gradient(135deg, rgba(124, 58, 237, 0.3), rgba(139, 92, 246, 0.3));
color: white;
font-weight: 600;
box-shadow: 0 6px 16px rgba(0, 0, 0, 0.18);
}
.nav-link-active::after {
content: '';
position: absolute;
bottom: 0;
left: 10%;
width: 80%;
height: 2px;
background: linear-gradient(90deg, transparent, rgba(255, 255, 255, 0.7), transparent);
}
/* Light-Mode Navigation Stile */
.nav-link-light {
color: rgba(26, 32, 44, 0.85);
}
.nav-link-light:hover {
background: rgba(179, 143, 255, 0.15);
color: rgba(26, 32, 44, 1);
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.05);
}
.nav-link-light-active {
background: linear-gradient(135deg, rgba(124, 58, 237, 0.2), rgba(139, 92, 246, 0.2));
color: rgba(26, 32, 44, 1);
font-weight: 600;
box-shadow: 0 6px 16px rgba(0, 0, 0, 0.1);
}
.nav-link-light-active::after {
background: linear-gradient(90deg, transparent, rgba(26, 32, 44, 0.5), transparent);
}
/* Entfernung von Gradient-Hintergrund überall */
.gradient-bg, .purple-gradient, .gradient-purple-bg {
background: var(--dark-bg) !important;
background-image: none !important;
}
/* Verbesserte Light-Mode-Stile für Buttons */
html.light .btn, html.light button, html.light .button,
html.light [type="button"], html.light [type="submit"] {
background: linear-gradient(135deg, rgba(124, 58, 237, 0.7), rgba(139, 92, 246, 0.7));
color: #ffffff;
border: 1px solid rgba(0, 0, 0, 0.1);
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.08);
text-shadow: none;
}
html.light .btn:hover, html.light button:hover, html.light .button:hover,
html.light [type="button"]:hover, html.light [type="submit"]:hover {
background: linear-gradient(135deg, rgba(139, 92, 246, 0.85), rgba(168, 85, 247, 0.85));
color: #ffffff;
border: 1px solid rgba(0, 0, 0, 0.08);
box-shadow: 0 8px 22px rgba(0, 0, 0, 0.12), 0 0 12px rgba(179, 143, 255, 0.2);
text-shadow: 0 1px 2px rgba(0, 0, 0, 0.2);
}
/* Verbesserte Buttons mit Glasmorphismus */
.btn-primary {
background: linear-gradient(135deg, rgba(179, 143, 255, 0.8), rgba(88, 169, 255, 0.8));
backdrop-filter: blur(var(--blur-amount));
-webkit-backdrop-filter: blur(var(--blur-amount));
border: 1px solid rgba(255, 255, 255, 0.2);
border-radius: var(--button-radius);
color: white !important;
font-weight: 600;
padding: 0.75rem 1.5rem;
transition: all 0.3s ease;
box-shadow: 0 8px 24px rgba(0, 0, 0, 0.25);
}
.btn-primary:hover {
transform: translateY(-3px);
box-shadow: 0 12px 32px rgba(0, 0, 0, 0.35);
background: linear-gradient(135deg, rgba(190, 160, 255, 0.9), rgba(100, 180, 255, 0.9));
}
.btn-secondary {
background: rgba(32, 36, 55, 0.8);
backdrop-filter: blur(var(--blur-amount));
-webkit-backdrop-filter: blur(var(--blur-amount));
border: 1px solid rgba(255, 255, 255, 0.1);
border-radius: var(--button-radius);
color: white;
font-weight: 500;
padding: 0.75rem 1.5rem;
transition: all 0.3s ease;
box-shadow: 0 6px 20px rgba(0, 0, 0, 0.2);
}
.btn-secondary:hover {
transform: translateY(-3px);
box-shadow: 0 10px 28px rgba(0, 0, 0, 0.3);
background: rgba(38, 42, 65, 0.9);
border: 1px solid rgba(255, 255, 255, 0.15);
}
/* Steuerungsbutton-Stil */
.control-btn {
padding: 0.5rem 1rem;
background: rgba(32, 36, 55, 0.8);
color: rgba(255, 255, 255, 0.9);
border: 1px solid rgba(255, 255, 255, 0.12);
border-radius: 14px;
font-size: 0.875rem;
font-weight: 500;
transition: all 0.25s ease;
backdrop-filter: blur(15px);
-webkit-backdrop-filter: blur(15px);
}
.control-btn:hover {
background: rgba(38, 42, 65, 0.9);
border: 1px solid rgba(255, 255, 255, 0.2);
transform: translateY(-2px);
box-shadow: 0 6px 16px rgba(0, 0, 0, 0.25);
}
/* Verbesserter Farbverlauf-Text */
.gradient-text {
background: linear-gradient(135deg, rgba(200, 170, 255, 1), rgba(100, 180, 255, 1));
-webkit-background-clip: text;
background-clip: text;
color: transparent;
font-weight: 700;
letter-spacing: -0.02em;
text-shadow: 0 2px 10px rgba(179, 143, 255, 0.3);
filter: drop-shadow(0 2px 6px rgba(179, 143, 255, 0.3));
}
/* Globaler Hintergrund */
.full-page-bg {
position: fixed;
top: 0;
left: 0;
width: 100vw;
height: 100vh;
background-color: var(--dark-bg);
z-index: -10;
}
html.light .full-page-bg {
background-color: var(--light-bg);
}
/* Animationen für Hintergrundeffekte */
@keyframes float {
0% { transform: translateY(0); }
50% { transform: translateY(-12px); }
100% { transform: translateY(0); }
}
@keyframes pulse {
0% { opacity: 0.7; transform: scale(1); }
50% { opacity: 1; transform: scale(1.05); }
100% { opacity: 0.7; transform: scale(1); }
}
.animate-float {
animation: float 6s ease-in-out infinite;
}
.animate-pulse {
animation: pulse 3s ease-in-out infinite;
}
/* Verbesserter Container für konsistente Layouts */
.page-container {
max-width: 1200px;
margin: 0 auto;
padding: 2rem 1rem;
}
/* Dark Mode Toggle Stile */
.dot {
transform: translateX(0);
transition: transform 0.3s ease-in-out, background-color 0.3s ease;
}
input:checked ~ .dot {
transform: translateX(100%);
background-color: #58a9ff;
}
input:checked ~ .block {
background-color: rgba(88, 169, 255, 0.4);
}
/* Feature Cards mit Glasmorphismus und Farbverlauf */
.feature-card {
border-radius: var(--card-border-radius);
padding: 2rem;
transition: all 0.3s ease;
background: linear-gradient(145deg, rgba(32, 36, 55, 0.7), rgba(24, 28, 45, 0.9));
backdrop-filter: blur(var(--blur-amount));
-webkit-backdrop-filter: blur(var(--blur-amount));
border: 1px solid rgba(255, 255, 255, 0.1);
box-shadow: 0 8px 32px rgba(0, 0, 0, 0.2);
}
.feature-card:hover {
transform: translateY(-5px);
box-shadow: 0 12px 40px rgba(0, 0, 0, 0.3);
border: 1px solid rgba(255, 255, 255, 0.15);
background: linear-gradient(145deg, rgba(40, 44, 65, 0.8), rgba(28, 32, 50, 0.95));
}
html.light .feature-card {
background: linear-gradient(145deg, rgba(255, 255, 255, 0.8), rgba(240, 240, 250, 0.9));
border: 1px solid rgba(0, 0, 0, 0.05);
box-shadow: 0 8px 24px rgba(0, 0, 0, 0.08);
}
html.light .feature-card:hover {
background: linear-gradient(145deg, rgba(255, 255, 255, 0.9), rgba(245, 245, 255, 0.95));
border: 1px solid rgba(0, 0, 0, 0.08);
box-shadow: 0 12px 32px rgba(0, 0, 0, 0.12);
}
.feature-card .icon {
width: 60px;
height: 60px;
border-radius: 18px;
display: flex;
align-items: center;
justify-content: center;
font-size: 1.5rem;
margin-bottom: 1.25rem;
background: linear-gradient(135deg, rgba(124, 58, 237, 0.8), rgba(139, 92, 246, 0.6));
color: white;
box-shadow: 0 8px 16px rgba(0, 0, 0, 0.15);
}
.feature-card h3 {
font-size: 1.25rem;
font-weight: 600;
margin-bottom: 0.75rem;
color: rgba(255, 255, 255, 0.95);
}
html.light .feature-card h3 {
color: rgba(26, 32, 44, 0.95);
}
.feature-card p {
color: rgba(255, 255, 255, 0.75);
line-height: 1.6;
}
html.light .feature-card p {
color: rgba(26, 32, 44, 0.75);
}

View File

@@ -14,6 +14,55 @@
<meta name="keywords" content="systades, wissen, visualisierung, lernen, gedanken, theorie">
<meta name="author" content="Systades-Team">
<!-- Tailwind CSS über CDN -->
<script src="https://cdn.tailwindcss.com"></script>
<script>
tailwind.config = {
darkMode: 'class',
theme: {
extend: {
fontFamily: {
sans: ['Inter', 'ui-sans-serif', 'system-ui', '-apple-system', 'sans-serif'],
mono: ['JetBrains Mono', 'ui-monospace', 'monospace']
},
colors: {
primary: {
50: '#f5f3ff',
100: '#ede9fe',
200: '#ddd6fe',
300: '#c4b5fd',
400: '#a78bfa',
500: '#8b5cf6',
600: '#7c3aed',
700: '#6d28d9',
800: '#5b21b6',
900: '#4c1d95'
},
secondary: {
50: '#ecfdf5',
100: '#d1fae5',
200: '#a7f3d0',
300: '#6ee7b7',
400: '#34d399',
500: '#10b981',
600: '#059669',
700: '#047857',
800: '#065f46',
900: '#064e3b'
},
dark: {
500: '#374151',
600: '#1f2937',
700: '#111827',
800: '#0e1220',
900: '#0a0e19'
}
}
}
}
}
</script>
<!-- Fonts -->
<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
@@ -28,8 +77,8 @@
<!-- Basis-Stylesheet -->
<link href="{{ url_for('static', filename='style.css') }}" rel="stylesheet">
<!-- Tailwind CSS -->
<link href="{{ url_for('static', filename='css/main.css') }}" rel="stylesheet">
<!-- Base-Styles ausgelagert in eigene Datei -->
<link href="{{ url_for('static', filename='css/base-styles.css') }}" rel="stylesheet">
<!-- Alpine.js -->
<script defer src="https://cdn.jsdelivr.net/npm/alpinejs@3.12.3/dist/cdn.min.js"></script>
@@ -102,437 +151,7 @@
// MindMap global verfügbar machen (für Alpine.js und andere nicht-Module Skripte)
window.MindMap = MindMap;
</script>
<!-- Globale Stile für konsistentes Glasmorphismus-Design -->
<style>
/* Globale Variablen */
:root {
--dark-bg: #0e1220;
--dark-card-bg: rgba(24, 28, 45, 0.8);
--dark-element-bg: rgba(24, 28, 45, 0.8);
--light-bg: #f0f4f8;
--light-card-bg: rgba(255, 255, 255, 0.85);
--accent-color: #b38fff;
--accent-gradient: linear-gradient(135deg, #b38fff, #58a9ff);
--accent-gradient-hover: linear-gradient(135deg, #c7a8ff, #70b5ff);
--blur-amount: 20px;
--border-radius: 28px;
--card-border-radius: 24px;
--button-radius: 18px;
--nav-item-radius: 14px;
}
/* Dark Mode Einstellungen */
html.dark {
color-scheme: dark;
}
/* Base Styles */
html, body {
background-color: var(--dark-bg) !important;
min-height: 100vh;
width: 100%;
color: #ffffff;
margin: 0;
padding: 0;
font-family: 'Inter', system-ui, -apple-system, sans-serif;
overflow-x: hidden;
transition: background-color 0.5s ease, color 0.5s ease;
}
/* Sicherstellen, dass der dunkle Hintergrund die gesamte Seite abdeckt */
#app-container, .container, main, .mx-auto, .py-12, #content-wrapper {
background-color: transparent !important;
width: 100%;
}
/* Light Mode Einstellungen */
html.light, html.light body {
background-color: var(--light-bg) !important;
color: #1a202c;
}
/* Große Headings mit verbesserten Stilen */
h1.hero-heading {
font-size: clamp(2.5rem, 8vw, 5rem);
line-height: 1.1;
font-weight: 800;
letter-spacing: -0.03em;
margin-bottom: 1.5rem;
}
h2.section-heading {
font-size: clamp(1.75rem, 5vw, 3rem);
line-height: 1.2;
font-weight: 700;
letter-spacing: -0.02em;
margin-bottom: 1.25rem;
}
/* Verbesserte Glasmorphismus-Stile */
.glass-morphism {
background: var(--dark-card-bg);
backdrop-filter: blur(var(--blur-amount));
-webkit-backdrop-filter: blur(var(--blur-amount));
border: 1px solid rgba(255, 255, 255, 0.12);
border-radius: var(--card-border-radius);
box-shadow: 0 12px 36px rgba(0, 0, 0, 0.35);
transition: all 0.3s ease;
}
.glass-morphism:hover {
border: 1px solid rgba(255, 255, 255, 0.2);
box-shadow: 0 16px 48px rgba(0, 0, 0, 0.45);
transform: translateY(-2px);
}
.glass-morphism-light {
background: var(--light-card-bg);
backdrop-filter: blur(var(--blur-amount));
-webkit-backdrop-filter: blur(var(--blur-amount));
border: 1px solid rgba(0, 0, 0, 0.08);
border-radius: var(--card-border-radius);
box-shadow: 0 10px 30px rgba(0, 0, 0, 0.12);
transition: all 0.3s ease;
}
.glass-morphism-light:hover {
border: 1px solid rgba(0, 0, 0, 0.15);
box-shadow: 0 16px 40px rgba(0, 0, 0, 0.18);
transform: translateY(-2px);
}
/* Verbesserte Navbar-Styles */
.glass-navbar-dark {
background: rgba(14, 18, 32, 0.85);
backdrop-filter: blur(15px);
-webkit-backdrop-filter: blur(15px);
border-color: rgba(255, 255, 255, 0.1);
box-shadow: 0 4px 20px rgba(0, 0, 0, 0.25);
border-radius: 0 0 20px 20px;
}
.glass-navbar-light {
background: rgba(255, 255, 255, 0.85);
backdrop-filter: blur(15px);
-webkit-backdrop-filter: blur(15px);
border-color: rgba(0, 0, 0, 0.05);
box-shadow: 0 4px 15px rgba(0, 0, 0, 0.08);
border-radius: 0 0 20px 20px;
}
/* Verbesserte Button-Stile mit besserer Lesbarkeit und stärkeren Farbverläufen */
.btn, button, .button, [type="button"], [type="submit"] {
transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
border-radius: var(--button-radius);
padding: 0.75rem 1.5rem;
font-weight: 600;
letter-spacing: 0.4px;
color: rgba(255, 255, 255, 1);
background: linear-gradient(135deg, rgba(99, 102, 241, 0.8), rgba(168, 85, 247, 0.8));
border: 1px solid rgba(255, 255, 255, 0.15);
box-shadow: 0 6px 14px rgba(0, 0, 0, 0.2);
text-shadow: 0 1px 2px rgba(0, 0, 0, 0.3);
backdrop-filter: blur(15px);
-webkit-backdrop-filter: blur(15px);
position: relative;
overflow: hidden;
outline: none;
}
.btn:hover, button:hover, .button:hover, [type="button"]:hover, [type="submit"]:hover {
background: linear-gradient(135deg, rgba(129, 140, 248, 0.9), rgba(192, 132, 252, 0.9));
transform: translateY(-3px);
border: 1px solid rgba(255, 255, 255, 0.3);
box-shadow: 0 8px 22px rgba(0, 0, 0, 0.25), 0 0 12px rgba(179, 143, 255, 0.35);
color: white;
}
.btn:active, button:active, .button:active, [type="button"]:active, [type="submit"]:active {
transform: translateY(1px);
box-shadow: 0 3px 8px rgba(0, 0, 0, 0.2);
}
/* Navigation Stile mit verbesserten Farbverläufen */
.nav-link {
transition: all 0.25s ease;
border-radius: var(--nav-item-radius);
padding: 0.625rem 1rem;
font-weight: 500;
letter-spacing: 0.3px;
color: rgba(255, 255, 255, 0.9);
position: relative;
overflow: visible;
}
.nav-link:hover {
background: rgba(179, 143, 255, 0.2);
color: white;
transform: translateY(-2px);
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.1);
}
.nav-link-active {
background: linear-gradient(135deg, rgba(124, 58, 237, 0.3), rgba(139, 92, 246, 0.3));
color: white;
font-weight: 600;
box-shadow: 0 6px 16px rgba(0, 0, 0, 0.18);
}
.nav-link-active::after {
content: '';
position: absolute;
bottom: 0;
left: 10%;
width: 80%;
height: 2px;
background: linear-gradient(90deg, transparent, rgba(255, 255, 255, 0.7), transparent);
}
/* Light-Mode Navigation Stile */
.nav-link-light {
color: rgba(26, 32, 44, 0.85);
}
.nav-link-light:hover {
background: rgba(179, 143, 255, 0.15);
color: rgba(26, 32, 44, 1);
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.05);
}
.nav-link-light-active {
background: linear-gradient(135deg, rgba(124, 58, 237, 0.2), rgba(139, 92, 246, 0.2));
color: rgba(26, 32, 44, 1);
font-weight: 600;
box-shadow: 0 6px 16px rgba(0, 0, 0, 0.1);
}
.nav-link-light-active::after {
background: linear-gradient(90deg, transparent, rgba(26, 32, 44, 0.5), transparent);
}
/* Entfernung von Gradient-Hintergrund überall */
.gradient-bg, .purple-gradient, .gradient-purple-bg {
background: var(--dark-bg) !important;
background-image: none !important;
}
/* Verbesserte Light-Mode-Stile für Buttons */
html.light .btn, html.light button, html.light .button,
html.light [type="button"], html.light [type="submit"] {
background: linear-gradient(135deg, rgba(124, 58, 237, 0.7), rgba(139, 92, 246, 0.7));
color: #ffffff;
border: 1px solid rgba(0, 0, 0, 0.1);
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.08);
text-shadow: none;
}
html.light .btn:hover, html.light button:hover, html.light .button:hover,
html.light [type="button"]:hover, html.light [type="submit"]:hover {
background: linear-gradient(135deg, rgba(139, 92, 246, 0.85), rgba(168, 85, 247, 0.85));
color: #ffffff;
border: 1px solid rgba(0, 0, 0, 0.08);
box-shadow: 0 8px 22px rgba(0, 0, 0, 0.12), 0 0 12px rgba(179, 143, 255, 0.2);
text-shadow: 0 1px 2px rgba(0, 0, 0, 0.2);
}
/* Verbesserte Buttons mit Glasmorphismus */
.btn-primary {
background: linear-gradient(135deg, rgba(179, 143, 255, 0.8), rgba(88, 169, 255, 0.8));
backdrop-filter: blur(var(--blur-amount));
-webkit-backdrop-filter: blur(var(--blur-amount));
border: 1px solid rgba(255, 255, 255, 0.2);
border-radius: var(--button-radius);
color: white !important;
font-weight: 600;
padding: 0.75rem 1.5rem;
transition: all 0.3s ease;
box-shadow: 0 8px 24px rgba(0, 0, 0, 0.25);
}
.btn-primary:hover {
transform: translateY(-3px);
box-shadow: 0 12px 32px rgba(0, 0, 0, 0.35);
background: linear-gradient(135deg, rgba(190, 160, 255, 0.9), rgba(100, 180, 255, 0.9));
}
.btn-secondary {
background: rgba(32, 36, 55, 0.8);
backdrop-filter: blur(var(--blur-amount));
-webkit-backdrop-filter: blur(var(--blur-amount));
border: 1px solid rgba(255, 255, 255, 0.1);
border-radius: var(--button-radius);
color: white;
font-weight: 500;
padding: 0.75rem 1.5rem;
transition: all 0.3s ease;
box-shadow: 0 6px 20px rgba(0, 0, 0, 0.2);
}
.btn-secondary:hover {
transform: translateY(-3px);
box-shadow: 0 10px 28px rgba(0, 0, 0, 0.3);
background: rgba(38, 42, 65, 0.9);
border: 1px solid rgba(255, 255, 255, 0.15);
}
/* Steuerungsbutton-Stil */
.control-btn {
padding: 0.5rem 1rem;
background: rgba(32, 36, 55, 0.8);
color: rgba(255, 255, 255, 0.9);
border: 1px solid rgba(255, 255, 255, 0.12);
border-radius: 14px;
font-size: 0.875rem;
font-weight: 500;
transition: all 0.25s ease;
backdrop-filter: blur(15px);
-webkit-backdrop-filter: blur(15px);
}
.control-btn:hover {
background: rgba(38, 42, 65, 0.9);
border: 1px solid rgba(255, 255, 255, 0.2);
transform: translateY(-2px);
box-shadow: 0 6px 16px rgba(0, 0, 0, 0.25);
}
/* Verbesserter Farbverlauf-Text */
.gradient-text {
background: linear-gradient(135deg, rgba(200, 170, 255, 1), rgba(100, 180, 255, 1));
-webkit-background-clip: text;
background-clip: text;
color: transparent;
font-weight: 700;
letter-spacing: -0.02em;
text-shadow: 0 2px 10px rgba(179, 143, 255, 0.3);
filter: drop-shadow(0 2px 6px rgba(179, 143, 255, 0.3));
}
/* Globaler Hintergrund */
.full-page-bg {
position: fixed;
top: 0;
left: 0;
width: 100vw;
height: 100vh;
background-color: var(--dark-bg);
z-index: -10;
}
html.light .full-page-bg {
background-color: var(--light-bg);
}
/* Animationen für Hintergrundeffekte */
@keyframes float {
0% { transform: translateY(0); }
50% { transform: translateY(-12px); }
100% { transform: translateY(0); }
}
@keyframes pulse {
0% { opacity: 0.7; transform: scale(1); }
50% { opacity: 1; transform: scale(1.05); }
100% { opacity: 0.7; transform: scale(1); }
}
.animate-float {
animation: float 6s ease-in-out infinite;
}
.animate-pulse {
animation: pulse 3s ease-in-out infinite;
}
/* Verbesserter Container für konsistente Layouts */
.page-container {
max-width: 1200px;
margin: 0 auto;
padding: 2rem 1rem;
}
/* Dark Mode Toggle Stile */
.dot {
transform: translateX(0);
transition: transform 0.3s ease-in-out, background-color 0.3s ease;
}
input:checked ~ .dot {
transform: translateX(100%);
background-color: #58a9ff;
}
input:checked ~ .block {
background-color: rgba(88, 169, 255, 0.4);
}
/* Feature Cards mit Glasmorphismus und Farbverlauf */
.feature-card {
border-radius: var(--card-border-radius);
padding: 2rem;
transition: all 0.3s ease;
background: linear-gradient(145deg, rgba(32, 36, 55, 0.7), rgba(24, 28, 45, 0.9));
backdrop-filter: blur(var(--blur-amount));
-webkit-backdrop-filter: blur(var(--blur-amount));
border: 1px solid rgba(255, 255, 255, 0.1);
box-shadow: 0 8px 32px rgba(0, 0, 0, 0.2);
}
.feature-card:hover {
transform: translateY(-5px);
box-shadow: 0 12px 40px rgba(0, 0, 0, 0.3);
border: 1px solid rgba(255, 255, 255, 0.15);
background: linear-gradient(145deg, rgba(40, 44, 65, 0.8), rgba(28, 32, 50, 0.95));
}
html.light .feature-card {
background: linear-gradient(145deg, rgba(255, 255, 255, 0.8), rgba(240, 240, 250, 0.9));
border: 1px solid rgba(0, 0, 0, 0.05);
box-shadow: 0 8px 24px rgba(0, 0, 0, 0.08);
}
html.light .feature-card:hover {
background: linear-gradient(145deg, rgba(255, 255, 255, 0.9), rgba(245, 245, 255, 0.95));
border: 1px solid rgba(0, 0, 0, 0.08);
box-shadow: 0 12px 32px rgba(0, 0, 0, 0.12);
}
.feature-card .icon {
width: 60px;
height: 60px;
border-radius: 18px;
display: flex;
align-items: center;
justify-content: center;
font-size: 1.5rem;
margin-bottom: 1.25rem;
background: linear-gradient(135deg, rgba(124, 58, 237, 0.8), rgba(139, 92, 246, 0.6));
color: white;
box-shadow: 0 8px 16px rgba(0, 0, 0, 0.15);
}
.feature-card h3 {
font-size: 1.25rem;
font-weight: 600;
margin-bottom: 0.75rem;
color: rgba(255, 255, 255, 0.95);
}
html.light .feature-card h3 {
color: rgba(26, 32, 44, 0.95);
}
.feature-card p {
color: rgba(255, 255, 255, 0.75);
line-height: 1.6;
}
html.light .feature-card p {
color: rgba(26, 32, 44, 0.75);
}
</style>
<!-- Seitenspezifische Styles -->
{% block extra_css %}{% endblock %}
</head>