Phase 4: Oberfläche mit Galerie, Erfassung und Reservierung
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
This commit is contained in:
@@ -0,0 +1,30 @@
|
||||
{# Eine Kachel in der Galerie. Eigene Datei, weil HTMX beim Filtern nur die
|
||||
Liste austauscht und dieselbe Darstellung braucht. #}
|
||||
<a href="/kleid/{{ item.id }}" class="karte block group">
|
||||
<div class="aspect-[3/4] bg-slate-100">
|
||||
{% if item.hauptbild %}
|
||||
<img src="/uploads/{{ item.hauptbild.image_url }}"
|
||||
alt="{{ item.anzeige_titel }}" loading="lazy"
|
||||
class="w-full h-full object-cover">
|
||||
{% else %}
|
||||
<div class="w-full h-full grid place-items-center text-slate-300 text-sm">
|
||||
kein Bild
|
||||
</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
<div class="p-3">
|
||||
<p class="font-semibold leading-tight">{{ item.anzeige_titel }}</p>
|
||||
<p class="text-sm text-slate-500 mt-1">
|
||||
{{ groesse_text(item) }}
|
||||
</p>
|
||||
{% if item.status == 'reserved' %}
|
||||
{# Bewusst ohne Namen: die Galerie ist öffentlich, der Name steht
|
||||
nur in der Verwaltung. #}
|
||||
<span class="inline-block mt-2 text-xs font-semibold rounded-full
|
||||
px-2 py-0.5 bg-amber-100 text-amber-900">reserviert</span>
|
||||
{% elif item.status == 'given_away' %}
|
||||
<span class="inline-block mt-2 text-xs font-semibold rounded-full
|
||||
px-2 py-0.5 bg-slate-200 text-slate-600">abgegeben</span>
|
||||
{% endif %}
|
||||
</div>
|
||||
</a>
|
||||
Reference in New Issue
Block a user