Compare commits
8 Commits
d49b266d96
...
505fb9aa47
| Author | SHA1 | Date | |
|---|---|---|---|
| 505fb9aa47 | |||
| e4e6541b8c | |||
| e724181915 | |||
| 460c3f987e | |||
| 7f33dea278 | |||
| 726d9c9c70 | |||
| 81170fbd3d | |||
| eff3fda1ca |
Binary file not shown.
Binary file not shown.
2
app.py
2
app.py
@@ -288,6 +288,7 @@ def login():
|
||||
password = request.form.get('password')
|
||||
|
||||
user = User.query.filter_by(username=username).first()
|
||||
|
||||
if user and user.check_password(password):
|
||||
login_user(user)
|
||||
# Aktualisiere letzten Login-Zeitpunkt
|
||||
@@ -296,6 +297,7 @@ def login():
|
||||
|
||||
next_page = request.args.get('next')
|
||||
return redirect(next_page or url_for('index'))
|
||||
|
||||
flash('Ungültiger Benutzername oder Passwort')
|
||||
return render_template('login.html')
|
||||
|
||||
|
||||
Binary file not shown.
BIN
instance/systades.db
Normal file
BIN
instance/systades.db
Normal file
Binary file not shown.
BIN
migrations/__pycache__/env.cpython-313.pyc
Normal file
BIN
migrations/__pycache__/env.cpython-313.pyc
Normal file
Binary file not shown.
Binary file not shown.
Binary file not shown.
40
migrations/versions/add_missing_user_fields.py
Normal file
40
migrations/versions/add_missing_user_fields.py
Normal file
@@ -0,0 +1,40 @@
|
||||
"""Add missing user fields
|
||||
|
||||
Revision ID: 5a23f8c6db37
|
||||
Revises: d4406f5b12f7
|
||||
Create Date: 2025-05-02 10:45:00.000000
|
||||
|
||||
"""
|
||||
from alembic import op
|
||||
import sqlalchemy as sa
|
||||
|
||||
|
||||
# revision identifiers, used by Alembic.
|
||||
revision = '5a23f8c6db37'
|
||||
down_revision = 'd4406f5b12f7'
|
||||
branch_labels = None
|
||||
depends_on = None
|
||||
|
||||
|
||||
def upgrade():
|
||||
# ### commands auto generated by Alembic - please adjust! ###
|
||||
with op.batch_alter_table('user', schema=None) as batch_op:
|
||||
batch_op.add_column(sa.Column('bio', sa.Text(), nullable=True))
|
||||
batch_op.add_column(sa.Column('location', sa.String(length=100), nullable=True))
|
||||
batch_op.add_column(sa.Column('website', sa.String(length=200), nullable=True))
|
||||
batch_op.add_column(sa.Column('avatar', sa.String(length=200), nullable=True))
|
||||
batch_op.add_column(sa.Column('last_login', sa.DateTime(), nullable=True))
|
||||
|
||||
# ### end Alembic commands ###
|
||||
|
||||
|
||||
def downgrade():
|
||||
# ### commands auto generated by Alembic - please adjust! ###
|
||||
with op.batch_alter_table('user', schema=None) as batch_op:
|
||||
batch_op.drop_column('last_login')
|
||||
batch_op.drop_column('avatar')
|
||||
batch_op.drop_column('website')
|
||||
batch_op.drop_column('location')
|
||||
batch_op.drop_column('bio')
|
||||
|
||||
# ### end Alembic commands ###
|
||||
@@ -81,6 +81,10 @@ class User(db.Model, UserMixin):
|
||||
def is_admin(self):
|
||||
return self.role == 'admin'
|
||||
|
||||
@is_admin.setter
|
||||
def is_admin(self, value):
|
||||
self.role = 'admin' if value else 'user'
|
||||
|
||||
class Category(db.Model):
|
||||
"""Wissenschaftliche Kategorien für die Gliederung der öffentlichen Mindmap"""
|
||||
id = db.Column(db.Integer, primary_key=True)
|
||||
|
||||
@@ -457,20 +457,57 @@ body:not(.dark) a:hover {
|
||||
/* Light Mode Buttons */
|
||||
body:not(.dark) .btn,
|
||||
body:not(.dark) button:not(.toggle) {
|
||||
background-color: var(--light-primary);
|
||||
background: linear-gradient(135deg, #6d28d9, #5b21b6);
|
||||
color: white;
|
||||
border: none;
|
||||
box-shadow: var(--light-shadow);
|
||||
border-radius: 0.375rem;
|
||||
padding: 0.5rem 1rem;
|
||||
transition: all 0.3s ease;
|
||||
box-shadow: 0 2px 4px rgba(91, 33, 182, 0.25);
|
||||
border-radius: 8px;
|
||||
padding: 0.625rem 1.25rem;
|
||||
transition: all 0.2s ease;
|
||||
font-weight: 600;
|
||||
letter-spacing: 0.02em;
|
||||
text-shadow: 0 1px 2px rgba(0, 0, 0, 0.3);
|
||||
}
|
||||
|
||||
body:not(.dark) .btn:hover,
|
||||
body:not(.dark) button:not(.toggle):hover {
|
||||
background-color: var(--light-primary-hover);
|
||||
transform: translateY(-2px);
|
||||
box-shadow: 0 6px 10px rgba(0, 0, 0, 0.1);
|
||||
background: linear-gradient(135deg, #7c3aed, #6d28d9);
|
||||
transform: translateY(-1px);
|
||||
box-shadow: 0 4px 12px rgba(109, 40, 217, 0.3);
|
||||
}
|
||||
|
||||
/* Dark/Light Mode Switch Button */
|
||||
.theme-toggle {
|
||||
position: relative;
|
||||
width: 48px;
|
||||
height: 24px;
|
||||
background: linear-gradient(to right, #7c3aed, #3b82f6);
|
||||
border-radius: 24px;
|
||||
padding: 2px;
|
||||
cursor: pointer;
|
||||
transition: all 0.3s ease;
|
||||
box-shadow: inset 0 2px 4px rgba(0, 0, 0, 0.1);
|
||||
}
|
||||
|
||||
.theme-toggle::after {
|
||||
content: '';
|
||||
position: absolute;
|
||||
width: 20px;
|
||||
height: 20px;
|
||||
background: white;
|
||||
border-radius: 50%;
|
||||
top: 2px;
|
||||
left: 2px;
|
||||
transition: all 0.3s ease;
|
||||
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.2);
|
||||
}
|
||||
|
||||
.theme-toggle.dark::after {
|
||||
transform: translateX(24px);
|
||||
}
|
||||
|
||||
.theme-toggle:hover::after {
|
||||
box-shadow: 0 4px 6px rgba(0, 0, 0, 0.2);
|
||||
}
|
||||
|
||||
/* Light Mode Cards und Panels */
|
||||
@@ -545,27 +582,39 @@ body:not(.dark) .card:hover {
|
||||
transform: translateY(-2px);
|
||||
}
|
||||
|
||||
/* Light Mode Buttons */
|
||||
/* Light Mode Buttons mit verbesserter Lesbarkeit */
|
||||
body:not(.dark) .btn-primary {
|
||||
background-color: var(--light-primary);
|
||||
background: linear-gradient(135deg, #6d28d9, #5b21b6);
|
||||
color: white;
|
||||
border: none;
|
||||
transition: all 0.2s ease;
|
||||
text-shadow: 0 1px 2px rgba(0, 0, 0, 0.4);
|
||||
font-weight: 600;
|
||||
letter-spacing: 0.02em;
|
||||
box-shadow: 0 2px 4px rgba(91, 33, 182, 0.3);
|
||||
border-radius: 8px;
|
||||
}
|
||||
|
||||
body:not(.dark) .btn-primary:hover {
|
||||
background-color: var(--light-primary-hover);
|
||||
box-shadow: 0 4px 12px rgba(124, 58, 237, 0.2);
|
||||
background: linear-gradient(135deg, #7c3aed, #6d28d9);
|
||||
box-shadow: 0 4px 12px rgba(109, 40, 217, 0.4), 0 2px 4px rgba(0, 0, 0, 0.1);
|
||||
transform: translateY(-1px);
|
||||
}
|
||||
|
||||
body:not(.dark) .btn-secondary {
|
||||
background-color: #f3f4f6;
|
||||
color: var(--light-text);
|
||||
border: 1px solid #e5e7eb;
|
||||
background: linear-gradient(135deg, #ffffff, #f9fafb);
|
||||
color: #1f2937;
|
||||
border: 2px solid #e5e7eb;
|
||||
font-weight: 600;
|
||||
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.08);
|
||||
border-radius: 8px;
|
||||
}
|
||||
|
||||
body:not(.dark) .btn-secondary:hover {
|
||||
background-color: #e5e7eb;
|
||||
background: linear-gradient(135deg, #f9fafb, #f3f4f6);
|
||||
border-color: #d1d5db;
|
||||
box-shadow: 0 4px 8px rgba(0, 0, 0, 0.12);
|
||||
transform: translateY(-1px);
|
||||
}
|
||||
|
||||
body:not(.dark) .btn-outline {
|
||||
|
||||
@@ -41,14 +41,28 @@ class NeuralNetworkBackground {
|
||||
this.animationFrameId = null;
|
||||
this.isDestroying = false;
|
||||
|
||||
// Farben - Lila Farbpalette
|
||||
// Farben für Dark/Light Mode
|
||||
this.colors = {
|
||||
background: '#040215',
|
||||
nodeColor: '#6a5498',
|
||||
nodePulse: '#9c7fe0',
|
||||
connectionColor: '#4a3870',
|
||||
flowColor: '#b47fea'
|
||||
dark: {
|
||||
background: '#040215',
|
||||
nodeColor: '#6a5498',
|
||||
nodePulse: '#9c7fe0',
|
||||
connectionColor: '#4a3870',
|
||||
flowColor: '#b47fea'
|
||||
},
|
||||
light: {
|
||||
background: '#f8f9fc',
|
||||
nodeColor: '#8c6db5',
|
||||
nodePulse: '#b094dd',
|
||||
connectionColor: '#9882bd',
|
||||
flowColor: '#7d5bb5'
|
||||
}
|
||||
};
|
||||
|
||||
// Aktuelle Farbpalette basierend auf Theme
|
||||
this.currentColors = document.documentElement.classList.contains('dark')
|
||||
? this.colors.dark
|
||||
: this.colors.light;
|
||||
|
||||
// Konfiguration
|
||||
this.config = {
|
||||
@@ -266,7 +280,11 @@ class NeuralNetworkBackground {
|
||||
}
|
||||
|
||||
render(now) {
|
||||
const colors = this.colors;
|
||||
// Aktualisiere Farben basierend auf aktuellem Theme
|
||||
this.currentColors = document.documentElement.classList.contains('dark')
|
||||
? this.colors.dark
|
||||
: this.colors.light;
|
||||
const colors = this.currentColors;
|
||||
const width = this.canvas.width / (window.devicePixelRatio || 1);
|
||||
const height = this.canvas.height / (window.devicePixelRatio || 1);
|
||||
|
||||
@@ -386,7 +404,12 @@ class NeuralNetworkBackground {
|
||||
document.addEventListener('DOMContentLoaded', () => {
|
||||
window.neuralBackground = new NeuralNetworkBackground();
|
||||
|
||||
// Sicherstellen, dass die Seite immer im Dark Mode ist
|
||||
document.documentElement.classList.add('dark');
|
||||
document.body.classList.add('dark');
|
||||
// Theme-Wechsel-Event-Listener
|
||||
document.addEventListener('theme-changed', () => {
|
||||
if (window.neuralBackground) {
|
||||
window.neuralBackground.currentColors = document.documentElement.classList.contains('dark')
|
||||
? window.neuralBackground.colors.dark
|
||||
: window.neuralBackground.colors.light;
|
||||
}
|
||||
});
|
||||
});
|
||||
0
systades.db
Normal file
0
systades.db
Normal file
@@ -129,13 +129,15 @@
|
||||
<style>
|
||||
/* Light‑Mode */
|
||||
:root {
|
||||
--bg-primary:#f4f6fa;
|
||||
--bg-secondary:#e9ecf3;
|
||||
--bg-primary:#f8fafc;
|
||||
--bg-secondary:#f1f5f9;
|
||||
--text-primary:#232837;
|
||||
--text-secondary:#475569;
|
||||
--accent-primary:#7c3aed;
|
||||
--accent-secondary:#8b5cf6;
|
||||
--glow-effect:0 0 8px rgba(139,92,246,.08);
|
||||
background-image: linear-gradient(to bottom right, rgba(248, 250, 252, 0.8), rgba(241, 245, 249, 0.8));
|
||||
background-attachment: fixed;
|
||||
}
|
||||
/* Dark‑Mode */
|
||||
.dark {
|
||||
@@ -149,7 +151,8 @@
|
||||
}
|
||||
|
||||
body {
|
||||
@apply min-h-screen bg-[color:var(--bg-primary)] text-[color:var(--text-primary)] transition-colors duration-300;
|
||||
@apply min-h-screen bg-[color:var(--bg-primary)] text-[color:var(--text-primary)];
|
||||
transition: background-color 0.5s ease-in-out, color 0.3s ease-in-out, background-image 0.5s ease-in-out;
|
||||
}
|
||||
|
||||
/* Utilities */
|
||||
@@ -320,6 +323,14 @@
|
||||
|
||||
<!-- Rechte Seite -->
|
||||
<div class="flex items-center space-x-4">
|
||||
<!-- Dark/Light Mode Schalter -->
|
||||
<button
|
||||
@click="toggleDarkMode()"
|
||||
class="theme-toggle"
|
||||
:class="{ 'dark': darkMode }"
|
||||
aria-label="Dark Mode umschalten"
|
||||
>
|
||||
</button>
|
||||
<!-- Profil-Link oder Login -->
|
||||
{% if current_user.is_authenticated %}
|
||||
<div class="relative" x-data="{ open: false }">
|
||||
|
||||
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.
@@ -55,7 +55,7 @@ def create_user(username, email, password, is_admin=False):
|
||||
user = User(
|
||||
username=username,
|
||||
email=email,
|
||||
is_admin=is_admin,
|
||||
role='admin' if is_admin else 'user',
|
||||
created_at=datetime.utcnow()
|
||||
)
|
||||
user.set_password(password)
|
||||
|
||||
Reference in New Issue
Block a user