Files
kleiderboerse/app/templates/erfassen.html
T
StefanandClaude Opus 5 75b95b38e6 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
2026-08-29 23:29:56 +02:00

42 lines
1.5 KiB
HTML

{% extends "basis.html" %}
{% block titel %}Erfassen{% endblock %}
{% block inhalt %}
<h1 class="text-xl font-bold mb-4">Kleider erfassen</h1>
{# Der schnelle Weg für den Erstbestand. Bewusst zuerst: wer zwanzig Teile
hat, will nicht zwanzigmal ein Formular ausfüllen. #}
<form method="post" action="/stapel" enctype="multipart/form-data"
class="karte p-4 space-y-3">
<input type="hidden" name="csrf" value="{{ csrf }}">
<h2 class="font-semibold">Viele auf einmal</h2>
<p class="text-sm text-slate-600">
Erst alles mit der Kamera fotografieren, dann hier alle Fotos
zusammen auswählen. Pro Foto entsteht ein Entwurf, die Angaben
trägst du danach in Ruhe nach.
</p>
{# Ohne "capture": so lässt sich wahlweise fotografieren ODER aus der
Mediathek wählen. Mit capture ginge nur je ein Foto pro Vorgang. #}
<input class="feld py-2" type="file" name="dateien" accept="image/*" multiple required>
<button class="knopf-haupt w-full">Fotos hochladen</button>
</form>
<p class="text-center text-sm text-slate-500 my-5">oder einzeln erfassen</p>
<form method="post" action="/erfassen" enctype="multipart/form-data"
class="karte p-4 space-y-4">
<input type="hidden" name="csrf" value="{{ csrf }}">
<div>
<label class="etikett" for="fotos">Fotos</label>
<input class="feld py-2" id="fotos" type="file" name="dateien"
accept="image/*" multiple>
</div>
{% include "_felder.html" %}
<button class="knopf-haupt w-full">Speichern</button>
</form>
{% endblock %}