Jinja2 mit HTMX, Tailwind über die Standalone-Binärdatei im Docker-Build - kein Node.js, kein npm. Mobile-First, Tippflächen mindestens 44 px hoch. Seiten: Galerie mit Filterleiste, Detailseite, Erfassungsformular, Stapel-Import mit Entwurfsliste, Anmeldung. HTMX tauscht beim Filtern nur die Liste aus statt die ganze Seite neu zu laden. Aus den Entscheidungen im Plan folgt konkret: - Der Stapel-Import steht ZUERST im Formular: wer zwanzig Teile hat, will nicht zwanzigmal ein Formular ausfüllen. Bewusst ohne capture-Attribut, damit sich wahlweise fotografieren oder aus der Mediathek wählen lässt - mit capture ginge nur je ein Foto pro Vorgang. - Grösse, Kategorie, Geschlecht, Saison und Zustand werden vom zuletzt gespeicherten Teil übernommen. Beim Abarbeiten einer Kiste sind das fünf Felder weniger pro Stück. - Nach dem Nachtragen eines Entwurfs geht es direkt zum nächsten, nicht auf die Detailseite - das ist der eigentliche Arbeitsablauf. - Titel bleibt leer erlaubt; angezeigt wird dann Kategorie und Grösse. - reserved_by erscheint öffentlich nur als "reserviert". Den Namen sieht ausschliesslich der angemeldete Betreiber. - Nach dem Reservieren wird der Freigabe-Link angezeigt, als vollständige Adresse zum Aufbewahren. - Post/Redirect/Get überall, damit ein Neuladen nicht erneut abschickt. - CSRF-Token in jedem Formular, zusätzlich zu SameSite=Lax. HTMX liegt lokal im Repository, nicht vom CDN: die CSP erlaubt nur script-src 'self', und ein CDN-Aufruf gäbe die IP jedes Besuchers weiter - dieselbe Überlegung wie bei Swagger und bei den Schriften der Kantone-App. Ein Test prüft für alle Seiten, dass nichts von aussen geladen wird. Nebenbei TemplateResponse auf die aktuelle Signatur umgestellt (64 Deprecation-Warnungen weniger). 77 Tests, alle grün. Zusätzlich der ganze Weg gegen den Container: anmelden, drei Fotos als Stapel, Entwurf nachtragen, Werte werden für das nächste Teil übernommen, als Gast reservieren, Name bleibt verborgen, Selbst-Freigabe über den Link. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01GR4bNaj9GtRu57J4Niii8o
54 lines
2.2 KiB
HTML
54 lines
2.2 KiB
HTML
<!doctype html>
|
|
<html lang="de-CH">
|
|
<head>
|
|
<meta charset="utf-8">
|
|
<meta name="viewport" content="width=device-width, initial-scale=1">
|
|
<meta name="robots" content="noindex, nofollow">
|
|
<title>{% block titel %}Kinderkleider-Börse{% endblock %}</title>
|
|
<link rel="icon" href="/static/favicon.svg" type="image/svg+xml">
|
|
<link rel="stylesheet" href="/static/style.css">
|
|
{# Lokal ausgeliefert, nicht vom CDN: die CSP erlaubt nur script-src
|
|
'self', und ein CDN-Aufruf gäbe zudem die IP jedes Besuchers weiter. #}
|
|
<script src="/static/htmx.min.js" defer></script>
|
|
</head>
|
|
<body class="bg-slate-50 text-slate-900 min-h-screen flex flex-col">
|
|
|
|
<header class="bg-white border-b border-slate-200 sticky top-0 z-20">
|
|
<div class="max-w-5xl mx-auto px-4 h-14 flex items-center gap-3">
|
|
<a href="/" class="font-bold text-marke-700 text-lg">Kleider-Börse</a>
|
|
<nav class="ml-auto flex items-center gap-2 text-sm">
|
|
{% if betreiber %}
|
|
<a href="/erfassen" class="knopf-still">Erfassen</a>
|
|
{% if entwurf_anzahl %}
|
|
<a href="/entwuerfe" class="knopf-still">
|
|
Entwürfe
|
|
<span class="bg-marke-700 text-white rounded-full px-2 text-xs">
|
|
{{ entwurf_anzahl }}</span>
|
|
</a>
|
|
{% endif %}
|
|
<form method="post" action="/abmelden" class="inline">
|
|
<input type="hidden" name="csrf" value="{{ csrf }}">
|
|
<button class="knopf-still">Abmelden</button>
|
|
</form>
|
|
{% else %}
|
|
<a href="/anmelden" class="knopf-still">Anmelden</a>
|
|
{% endif %}
|
|
</nav>
|
|
</div>
|
|
</header>
|
|
|
|
<main class="flex-1 w-full max-w-5xl mx-auto px-4 py-5">
|
|
{% if meldung %}
|
|
<p class="mb-4 rounded-xl px-4 py-3 text-sm
|
|
{{ 'bg-emerald-100 text-emerald-900' if meldung_art == 'ok'
|
|
else 'bg-rose-100 text-rose-900' }}">{{ meldung }}</p>
|
|
{% endif %}
|
|
{% block inhalt %}{% endblock %}
|
|
</main>
|
|
|
|
<footer class="text-center text-xs text-slate-400 py-6">
|
|
Kinderkleider-Börse
|
|
</footer>
|
|
</body>
|
|
</html>
|