Files
patrick 5ecd143535 Feature: HTMX + Jinja2 Frontend ersetzt Next.js komplett
- Kein Node.js, kein npm, kein Build-Schritt mehr
- HTMX 2.0.4 + PicoCSS 2 vendored in backend/static/
- Jinja2 Templates für alle 9 Seiten (Dashboard, ZFS, Snapshots,
  Shares, Identities, Logs, Services, Navigator, Login)
- HTMX Fragments für Live-Updates (30s Polling Dashboard)
- JWT als httpOnly Cookie statt localStorage
- Disk Usage zeigt TB/PB korrekt (Jinja2 serverseitig formatiert)
- Update-safe: nur Python-Deps, keine npm-Abhängigkeiten

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-05 18:45:46 +02:00

73 lines
3.9 KiB
HTML

<!DOCTYPE html>
<html lang="de" data-theme="dark">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>{% block title %}ZMB Webui{% endblock %}</title>
<link rel="stylesheet" href="/static/pico.min.css">
<script src="/static/htmx.min.js"></script>
<style>
:root { --pico-font-size: 87.5%; }
nav.top-nav { padding: 0.5rem 1rem; border-bottom: 1px solid var(--pico-muted-border-color); }
nav.top-nav ul { margin: 0; }
nav.top-nav a { text-decoration: none; padding: 0.4rem 0.7rem; border-radius: 4px; }
nav.top-nav a.active, nav.top-nav a:hover { background: var(--pico-primary-background); color: var(--pico-primary-inverse); }
nav.top-nav .brand { font-weight: bold; font-size: 1.1rem; color: var(--pico-primary); }
main.container { padding-top: 1.5rem; }
.htmx-indicator { opacity: 0; transition: opacity 200ms; }
.htmx-request .htmx-indicator { opacity: 1; }
.badge { display: inline-block; padding: 0.1rem 0.4rem; border-radius: 4px; font-size: 0.75rem; background: var(--pico-secondary-background); }
.badge-green { background: #166534; color: #bbf7d0; }
.badge-red { background: #7f1d1d; color: #fecaca; }
.badge-yellow { background: #713f12; color: #fef08a; }
.badge-blue { background: #1e3a5f; color: #bfdbfe; }
.progress-bar-wrap { background: var(--pico-muted-border-color); border-radius: 4px; height: 8px; overflow: hidden; }
.progress-bar { height: 100%; border-radius: 4px; transition: width 0.3s; }
.bar-blue { background: #3b82f6; }
.bar-yellow { background: #eab308; }
.bar-red { background: #ef4444; }
.flash-error { background: #7f1d1d; color: #fecaca; padding: 0.75rem 1rem; border-radius: 6px; margin-bottom: 1rem; }
.flash-ok { background: #166534; color: #bbf7d0; padding: 0.75rem 1rem; border-radius: 6px; margin-bottom: 1rem; }
.grid-stats { display: grid; grid-template-columns: repeat(auto-fill, minmax(200px, 1fr)); gap: 1rem; }
.stat-card { padding: 1rem; border: 1px solid var(--pico-muted-border-color); border-radius: 8px; }
.stat-card h3 { margin: 0 0 0.25rem 0; font-size: 0.8rem; color: var(--pico-muted-color); text-transform: uppercase; }
.stat-card .value { font-size: 1.4rem; font-weight: bold; margin: 0; }
table { font-size: 0.9rem; }
.actions { display: flex; gap: 0.5rem; flex-wrap: wrap; }
.actions button, .actions a[role=button] { padding: 0.25rem 0.6rem; font-size: 0.8rem; margin: 0; }
details summary { cursor: pointer; }
</style>
{% block head %}{% endblock %}
</head>
<body>
<nav class="top-nav">
<ul>
<li><span class="brand">&#128241; ZMB Webui</span></li>
</ul>
<ul>
<li><a href="/" class="{% if active == 'dashboard' %}active{% endif %}">Dashboard</a></li>
<li><a href="/zfs" class="{% if active == 'zfs' %}active{% endif %}">ZFS</a></li>
<li><a href="/snapshots" class="{% if active == 'snapshots' %}active{% endif %}">Snapshots</a></li>
<li><a href="/shares" class="{% if active == 'shares' %}active{% endif %}">Shares</a></li>
<li><a href="/navigator" class="{% if active == 'navigator' %}active{% endif %}">Navigator</a></li>
<li><a href="/identities" class="{% if active == 'identities' %}active{% endif %}">Identities</a></li>
<li><a href="/logs" class="{% if active == 'logs' %}active{% endif %}">Logs</a></li>
<li><a href="/services" class="{% if active == 'services' %}active{% endif %}">Services</a></li>
</ul>
<ul>
<li>
<form method="post" action="/logout" style="margin:0">
<button type="submit" class="outline secondary" style="padding:0.3rem 0.7rem;font-size:0.85rem">Logout</button>
</form>
</li>
</ul>
</nav>
<main class="container">
{% if flash_error %}<div class="flash-error">{{ flash_error }}</div>{% endif %}
{% if flash_ok %}<div class="flash-ok">{{ flash_ok }}</div>{% endif %}
{% block content %}{% endblock %}
</main>
</body>
</html>