Files

457 lines
15 KiB
HTML
Executable File

<!DOCTYPE html>
<html lang="de">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>{% block title %}Admin{% endblock %} - {{ branding.company_name }} Admin</title>
{% if branding.favicon_url %}
<link rel="icon" href="{{ branding.favicon_url }}" type="image/x-icon">
{% endif %}
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/css/bootstrap.min.css" rel="stylesheet">
<link href="https://cdn.jsdelivr.net/npm/bootstrap-icons@1.11.3/font/bootstrap-icons.min.css" rel="stylesheet">
<style>
:root {
--admin-primary: #dc3545;
--admin-primary-hover: #bb2d3b;
--sidebar-bg: {{ branding.colors.sidebar_bg }};
--sidebar-border: {{ branding.colors.border }};
--text-light: {{ branding.colors.text }};
--text-muted: {{ branding.colors.muted }};
--portal-bg: {{ branding.colors.background }};
}
body {
background: var(--portal-bg);
color: var(--text-light);
min-height: 100vh;
}
.admin-sidebar {
position: fixed;
left: 0;
top: 0;
width: 240px;
height: 100vh;
background: var(--sidebar-bg);
border-right: 1px solid var(--sidebar-border);
display: flex;
flex-direction: column;
z-index: 1000;
}
.admin-sidebar-header {
padding: 1.25rem;
border-bottom: 1px solid var(--sidebar-border);
}
.admin-logo {
display: flex;
align-items: center;
gap: 0.5rem;
color: var(--text-light);
text-decoration: none;
font-weight: 600;
}
.admin-logo i {
color: var(--admin-primary);
font-size: 1.5rem;
}
.admin-nav-wrapper {
flex: 1;
overflow-y: auto;
overflow-x: hidden;
}
.admin-nav-wrapper::-webkit-scrollbar {
width: 6px;
}
.admin-nav-wrapper::-webkit-scrollbar-track {
background: transparent;
}
.admin-nav-wrapper::-webkit-scrollbar-thumb {
background: rgba(255, 255, 255, 0.1);
border-radius: 3px;
}
.admin-nav-wrapper::-webkit-scrollbar-thumb:hover {
background: rgba(255, 255, 255, 0.2);
}
.admin-nav {
list-style: none;
padding: 1rem 0.75rem;
margin: 0;
}
.admin-nav .nav-item {
margin-bottom: 0.25rem;
}
.admin-nav .nav-link {
display: flex;
align-items: center;
gap: 0.75rem;
padding: 0.75rem 1rem;
color: var(--text-muted);
text-decoration: none;
border-radius: 0.5rem;
transition: all 0.2s ease;
}
.admin-nav .nav-link:hover {
color: var(--text-light);
background: rgba(255, 255, 255, 0.05);
}
.admin-nav .nav-link.active {
color: var(--text-light);
background: var(--admin-primary);
}
.admin-sidebar-footer {
padding: 1rem;
border-top: 1px solid var(--sidebar-border);
}
.admin-main {
margin-left: 240px;
min-height: 100vh;
padding: 2rem;
}
.card {
background: var(--sidebar-bg);
border-color: var(--sidebar-border);
}
.table {
--bs-table-bg: transparent;
--bs-table-color: var(--text-light);
--bs-table-border-color: var(--sidebar-border);
}
.form-control, .form-select {
background: #0d0f12;
border-color: var(--sidebar-border);
color: var(--text-light);
}
.form-control:focus, .form-select:focus {
background: #0d0f12;
border-color: var(--admin-primary);
color: var(--text-light);
box-shadow: 0 0 0 0.25rem rgba(220, 53, 69, 0.25);
}
.form-label {
color: var(--text-light);
}
.form-text {
color: var(--text-muted) !important;
}
.form-check-label {
color: var(--text-light);
}
.card-header {
color: var(--text-light);
background: rgba(255, 255, 255, 0.03);
border-color: var(--sidebar-border);
}
.card-body {
color: var(--text-light);
}
.breadcrumb-item {
color: var(--text-muted);
}
.breadcrumb-item.active {
color: var(--text-light);
}
.breadcrumb-item + .breadcrumb-item::before {
color: var(--text-muted);
}
h1, h2, h3, h4, h5, h6 {
color: var(--text-light);
}
.modal-content {
background: var(--sidebar-bg);
color: var(--text-light);
}
.modal-header, .modal-footer {
border-color: var(--sidebar-border);
}
.btn-close {
filter: invert(1);
}
/* Text colors - ensure visibility on dark background */
.text-muted {
color: var(--text-muted) !important;
}
p, li, td, th, span, strong, label {
color: var(--text-light);
}
.card .small, .card small {
color: var(--text-light);
}
.card ul {
color: var(--text-light);
}
.alert {
color: var(--text-light);
}
.alert-info {
background: rgba(13, 202, 240, 0.15);
border-color: rgba(13, 202, 240, 0.3);
}
.alert-warning {
background: rgba(255, 193, 7, 0.15);
border-color: rgba(255, 193, 7, 0.3);
}
.alert-danger {
background: rgba(220, 53, 69, 0.15);
border-color: rgba(220, 53, 69, 0.3);
}
.alert-success {
background: rgba(25, 135, 84, 0.15);
border-color: rgba(25, 135, 84, 0.3);
}
code {
color: #17a2b8;
}
.form-text {
color: var(--text-muted) !important;
}
.table-dark {
--bs-table-color: var(--text-light);
--bs-table-bg: transparent;
}
.table-dark th {
color: var(--text-light) !important;
}
.table-dark td {
color: var(--text-light) !important;
}
.btn-danger {
background: var(--admin-primary);
border-color: var(--admin-primary);
}
.btn-danger:hover {
background: var(--admin-primary-hover);
border-color: var(--admin-primary-hover);
}
@media (max-width: 991px) {
.admin-sidebar {
transform: translateX(-100%);
transition: transform 0.3s;
}
.admin-sidebar.show {
transform: translateX(0);
}
.admin-main {
margin-left: 0;
}
}
</style>
{% block extra_css %}{% endblock %}
</head>
<body>
<nav class="admin-sidebar">
<div class="admin-sidebar-header">
<a href="{{ url_for('admin.index') }}" class="admin-logo">
{% if branding.logo_url %}
<img src="{{ branding.logo_url }}" alt="{{ branding.company_name }}" style="max-height: 30px;">
{% else %}
<i class="bi bi-shield-lock"></i>
{% endif %}
<span>Admin</span>
</a>
</div>
<div class="admin-nav-wrapper">
<ul class="admin-nav">
<li class="nav-item">
<a class="nav-link {% if request.endpoint == 'admin.index' %}active{% endif %}"
href="{{ url_for('admin.index') }}">
<i class="bi bi-speedometer2"></i>
<span>Dashboard</span>
</a>
</li>
<!-- Benutzer -->
<li class="nav-item mt-3">
<span class="nav-label text-muted small px-3">BENUTZER</span>
</li>
<li class="nav-item">
<a class="nav-link {% if request.endpoint == 'admin.customers' %}active{% endif %}"
href="{{ url_for('admin.customers') }}">
<i class="bi bi-people"></i>
<span>Kunden</span>
</a>
</li>
<li class="nav-item">
<a class="nav-link {% if 'admins' in request.endpoint %}active{% endif %}"
href="{{ url_for('admin.admins') }}">
<i class="bi bi-shield-check"></i>
<span>Administratoren</span>
</a>
</li>
<!-- Buchungen -->
<li class="nav-item mt-3">
<span class="nav-label text-muted small px-3">BUCHUNGEN</span>
</li>
<li class="nav-item">
<a class="nav-link {% if request.endpoint == 'admin.bookings' %}active{% endif %}"
href="{{ url_for('admin.bookings') }}">
<i class="bi bi-calendar-check"></i>
<span>Buchungen</span>
</a>
</li>
<li class="nav-item">
<a class="nav-link {% if request.endpoint == 'admin.bookings_sync' %}active{% endif %}"
href="{{ url_for('admin.bookings_sync') }}">
<i class="bi bi-arrow-repeat"></i>
<span>Sync</span>
</a>
</li>
<li class="nav-item">
<a class="nav-link {% if request.endpoint == 'admin.bookings_import' %}active{% endif %}"
href="{{ url_for('admin.bookings_import') }}">
<i class="bi bi-upload"></i>
<span>Import</span>
</a>
</li>
<!-- Einstellungen -->
<li class="nav-item mt-3">
<span class="nav-label text-muted small px-3">EINSTELLUNGEN</span>
</li>
<li class="nav-item">
<a class="nav-link {% if request.endpoint == 'admin.field_config' %}active{% endif %}"
href="{{ url_for('admin.field_config') }}">
<i class="bi bi-sliders"></i>
<span>Profil-Felder</span>
</a>
</li>
<li class="nav-item">
<a class="nav-link {% if request.endpoint == 'admin.settings_customer_view' %}active{% endif %}"
href="{{ url_for('admin.settings_customer_view') }}">
<i class="bi bi-layout-text-sidebar"></i>
<span>Kundenansicht</span>
</a>
</li>
<li class="nav-item">
<a class="nav-link {% if request.endpoint == 'admin.settings_mail' %}active{% endif %}"
href="{{ url_for('admin.settings_mail') }}">
<i class="bi bi-envelope"></i>
<span>Mail-Server</span>
</a>
</li>
<li class="nav-item">
<a class="nav-link {% if request.endpoint == 'admin.settings_otp' %}active{% endif %}"
href="{{ url_for('admin.settings_otp') }}">
<i class="bi bi-key"></i>
<span>OTP & Sicherheit</span>
</a>
</li>
<li class="nav-item">
<a class="nav-link {% if request.endpoint == 'admin.settings_wordpress' %}active{% endif %}"
href="{{ url_for('admin.settings_wordpress') }}">
<i class="bi bi-wordpress"></i>
<span>WordPress</span>
</a>
</li>
<li class="nav-item">
<a class="nav-link {% if request.endpoint == 'admin.settings_csv' %}active{% endif %}"
href="{{ url_for('admin.settings_csv') }}">
<i class="bi bi-filetype-csv"></i>
<span>CSV Export/Import</span>
</a>
</li>
<li class="nav-item">
<a class="nav-link {% if request.endpoint == 'admin.settings_customer_defaults' %}active{% endif %}"
href="{{ url_for('admin.settings_customer_defaults') }}">
<i class="bi bi-person-plus"></i>
<span>Kunden-Standards</span>
</a>
</li>
<li class="nav-item">
<a class="nav-link {% if request.endpoint == 'admin.settings_field_mapping' %}active{% endif %}"
href="{{ url_for('admin.settings_field_mapping') }}">
<i class="bi bi-arrow-left-right"></i>
<span>Feld-Mapping</span>
</a>
</li>
<li class="nav-item">
<a class="nav-link {% if request.endpoint == 'admin.settings_branding' %}active{% endif %}"
href="{{ url_for('admin.settings_branding') }}">
<i class="bi bi-palette"></i>
<span>Branding</span>
</a>
</li>
</ul>
</div>
<div class="admin-sidebar-footer">
<div class="d-flex align-items-center gap-2 mb-2 text-muted small">
<i class="bi bi-person-circle"></i>
<span>{{ g.admin_user.name }}</span>
</div>
<a href="{{ url_for('admin.logout') }}" class="btn btn-outline-danger btn-sm w-100">
<i class="bi bi-box-arrow-right me-1"></i>
Abmelden
</a>
</div>
</nav>
<main class="admin-main">
{% with messages = get_flashed_messages(with_categories=true) %}
{% if messages %}
{% for category, message in messages %}
<div class="alert alert-{{ 'danger' if category == 'error' else category }} alert-dismissible fade show">
{{ message }}
<button type="button" class="btn-close" data-bs-dismiss="alert"></button>
</div>
{% endfor %}
{% endif %}
{% endwith %}
{% block content %}{% endblock %}
</main>
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/js/bootstrap.bundle.min.js"></script>
{% block extra_js %}{% endblock %}
</body>
</html>