Farbschema folgt zunächst der Systemeinstellung, lässt sich per Knopf in der Kopfzeile umstellen und wird dann gemerkt. Bei gesperrtem Speicher (privates Fenster) greift wieder die Systemeinstellung. theme.js steht bewusst OHNE defer und vor dem Inhalt: es setzt die Farbklasse, bevor gezeichnet wird. Mit defer blitzte beim Laden kurz die helle Fassung auf. Eine eigene Datei statt eines <script>-Blocks, weil die CSP nur script-src 'self' erlaubt - inline wäre blockiert. Fusszeile zeigt Version oder Commit, gleiches Muster wie die Kantone-App: die CI reicht beides als Build-Argument durch, lokal erscheint der Build-Zeitpunkt. Der ändert sich bei jedem Neubau und zeigt damit sofort, ob wirklich der neue Stand läuft. Beim Ergänzen der Dunkel-Varianten hatte mein Ersetzer die eben eingefügten dark:-Klassen selbst nochmal getroffen und daraus Paare wie "dark:text-slate-300 dark:text-slate-600" gemacht - bereinigt. 81 Tests, alle grün. Neu darunter: die Fusszeile zeigt Tag bzw. Commit, theme.js steht vor <body> und ohne defer, der Umschalter ist da. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01GR4bNaj9GtRu57J4Niii8o
103 lines
5.1 KiB
HTML
103 lines
5.1 KiB
HTML
{% extends "basis.html" %}
|
||
{% block titel %}{{ item.anzeige_titel }}{% endblock %}
|
||
{% block inhalt %}
|
||
|
||
<a href="/" class="text-sm text-marke-700 dark:text-marke-100 font-semibold">← Übersicht</a>
|
||
|
||
<div class="mt-3 grid md:grid-cols-2 gap-5">
|
||
<div class="karte">
|
||
{% if item.bilder %}
|
||
<img src="/uploads/{{ item.hauptbild.image_url }}"
|
||
alt="{{ item.anzeige_titel }}" class="w-full object-cover">
|
||
{% if item.bilder|length > 1 %}
|
||
<div class="grid grid-cols-4 gap-1 p-1">
|
||
{% for b in item.bilder %}
|
||
<img src="/uploads/{{ b.image_url }}" alt="" loading="lazy"
|
||
class="aspect-square object-cover rounded-lg">
|
||
{% endfor %}
|
||
</div>
|
||
{% endif %}
|
||
{% else %}
|
||
<div class="aspect-[3/4] grid place-items-center text-slate-300 dark:text-slate-600">
|
||
kein Bild
|
||
</div>
|
||
{% endif %}
|
||
</div>
|
||
|
||
<div>
|
||
<h1 class="text-2xl font-bold">{{ item.anzeige_titel }}</h1>
|
||
<dl class="mt-4 grid grid-cols-2 gap-3 text-sm">
|
||
<div><dt class="text-slate-500 dark:text-slate-400 dark:text-slate-500">Grösse</dt>
|
||
<dd class="font-semibold">{{ item.size or '–' }}</dd></div>
|
||
<div><dt class="text-slate-500 dark:text-slate-400 dark:text-slate-500">Kategorie</dt>
|
||
<dd class="font-semibold">{{ item.kategorie.name if item.kategorie else '–' }}</dd></div>
|
||
<div><dt class="text-slate-500 dark:text-slate-400 dark:text-slate-500">Für</dt>
|
||
<dd class="font-semibold">{{ geschlecht_text(item.gender) }}</dd></div>
|
||
<div><dt class="text-slate-500 dark:text-slate-400 dark:text-slate-500">Zustand</dt>
|
||
<dd class="font-semibold">{{ zustand_text(item.condition) }}</dd></div>
|
||
<div><dt class="text-slate-500 dark:text-slate-400 dark:text-slate-500">Saison</dt>
|
||
<dd class="font-semibold">{{ saison_text(item.season) }}</dd></div>
|
||
</dl>
|
||
|
||
{% if item.description %}
|
||
<p class="mt-4 text-slate-700 dark:text-slate-200 whitespace-pre-line">{{ item.description }}</p>
|
||
{% endif %}
|
||
|
||
<div class="mt-6">
|
||
{% if item.status == 'available' %}
|
||
<form method="post" action="/kleid/{{ item.id }}/reservieren"
|
||
class="karte p-4 space-y-3">
|
||
<input type="hidden" name="csrf" value="{{ csrf }}">
|
||
<label class="etikett" for="wer">Dein Name</label>
|
||
<input class="feld" id="wer" name="reserved_by" required
|
||
maxlength="100" autocomplete="name"
|
||
placeholder="z.B. Familie Meier">
|
||
<button class="knopf-haupt w-full">Reservieren</button>
|
||
<p class="text-xs text-slate-500 dark:text-slate-400 dark:text-slate-500">
|
||
Du bekommst danach einen Link, mit dem du die Reservierung
|
||
selbst wieder aufheben kannst.
|
||
</p>
|
||
</form>
|
||
|
||
{% elif item.status == 'reserved' %}
|
||
<p class="rounded-xl bg-amber-100 dark:bg-amber-900 text-amber-900 dark:text-amber-100 px-4 py-3">
|
||
Ist bereits reserviert.
|
||
</p>
|
||
{% if betreiber %}
|
||
<p class="mt-2 text-sm text-slate-600 dark:text-slate-300">
|
||
Reserviert von: <strong>{{ item.reserved_by }}</strong>
|
||
</p>
|
||
<form method="post" action="/kleid/{{ item.id }}/freigeben" class="mt-2">
|
||
<input type="hidden" name="csrf" value="{{ csrf }}">
|
||
<button class="knopf-still">Reservierung aufheben</button>
|
||
</form>
|
||
{% endif %}
|
||
|
||
{% elif item.status == 'given_away' %}
|
||
<p class="rounded-xl bg-slate-200 dark:bg-slate-700 text-slate-700 dark:text-slate-200 px-4 py-3">
|
||
Schon abgegeben.
|
||
</p>
|
||
{% endif %}
|
||
</div>
|
||
|
||
{% if betreiber %}
|
||
<div class="mt-6 border-t border-slate-200 dark:border-slate-700 pt-4 flex flex-wrap gap-2">
|
||
<a href="/kleid/{{ item.id }}/bearbeiten" class="knopf-still">Bearbeiten</a>
|
||
{% if item.status == 'reserved' %}
|
||
<form method="post" action="/kleid/{{ item.id }}/abgegeben">
|
||
<input type="hidden" name="csrf" value="{{ csrf }}">
|
||
<button class="knopf-still">Als abgegeben markieren</button>
|
||
</form>
|
||
{% endif %}
|
||
<form method="post" action="/kleid/{{ item.id }}/loeschen"
|
||
onsubmit="return confirm('Wirklich löschen? Auch die Fotos werden entfernt.')">
|
||
<input type="hidden" name="csrf" value="{{ csrf }}">
|
||
<button class="knopf-still text-rose-700 dark:text-rose-400">Löschen</button>
|
||
</form>
|
||
</div>
|
||
{% endif %}
|
||
</div>
|
||
</div>
|
||
|
||
{% endblock %}
|