Coverbilder (bild_url) + responsives Layout für Mobil/Tablet
Teil 1 — Coverbilder: - Migration 0004_bild_url (neuheiten), 0002_bild_url (planung, archiv mit beiden Spiegel-Tabellen); nullable VARCHAR(500), SQLite↔Postgres portabel, bestehende Zeilen bleiben erhalten - BGG-Client extrahiert Cover aus der Thing-Antwort (bevorzugt <image>, sonst <thumbnail>; protokoll-relative URLs → https) - Sync-Upsert pflegt bild_url beim Update; fehlendes Bild löscht keines - Web-Quellen übernehmen img-URLs aus den Listenelementen (src/data-src, relative Pfade gegen die Seiten-URL aufgelöst); SPIEL-Essen nutzt das BILDER-Feld des JSON-Endpunkts - Verschiebung Neuheiten→Planung und Archivierung/Wiederherstellen schreiben bild_url mit - Anzeige: kleine Vorschaubilder (40x56) in den Listen, groß (max 200px) in Planung-Bearbeiten/Prüf-Dialog; Platzhalter-Div ohne Bild; Hotlinking mit loading=lazy + decoding=async Teil 2 — Responsives Layout: - Basislayout: Burger-Menü (Alpine.js) auf Mobil, Desktop-Leiste ab md: - Listen kollabieren <768px zu Karten-Ansichten (Cover links, Titel + Metadaten rechts, Status-Badge oben); Desktop behält Tabellenform - Touch-Ziele >= 44px auf Mobil, Formulare vollbreit mit Labels oben - Sync-Übersicht/Audit-Log bleiben horizontal scrollbare Tabellen Tests: 15 neue Fälle (tests/test_covers.py) — Migration inkl. Daten-Erhalt, BGG-Parsing gemockt, Quellen-Übernahme, Template-Render; 316 Tests grün. README aktualisiert.
This commit is contained in:
@@ -70,9 +70,34 @@ class BggSpiel:
|
||||
verlag: str | None
|
||||
autor: str | None
|
||||
erscheinungsjahr: int | None
|
||||
#: URL des Coverbildes — bevorzugt das größere <image>, sonst das
|
||||
#: <thumbnail>; None, wenn BGG keins liefert.
|
||||
bild_url: str | None = None
|
||||
typ: str = TYP_BRETTSPIEL
|
||||
|
||||
|
||||
def _bild_url(element: ET.Element) -> str | None:
|
||||
"""Extrahiert die Coverbild-URL aus einem Thing-Item.
|
||||
|
||||
Bevorzugt das große `<image>`, fällt zurück auf das kleinere
|
||||
`<thumbnail>`. Protokoll-relative URLs (`//cf.geekdo-images.com/…`)
|
||||
werden auf https normalisiert; leere/kaputte Angaben → None.
|
||||
"""
|
||||
for tag in ("image", "thumbnail"):
|
||||
roh = element.findtext(tag)
|
||||
if roh is None:
|
||||
continue
|
||||
url = roh.strip()
|
||||
if not url:
|
||||
continue
|
||||
if url.startswith("//"):
|
||||
url = f"https:{url}"
|
||||
if url.startswith(("http://", "https://")):
|
||||
return url
|
||||
return None
|
||||
return None
|
||||
|
||||
|
||||
def _attribut_wert(element: ET.Element | None, tag: str) -> str | None:
|
||||
"""Liest `<tag><value>…</value></tag>` tolerant aus."""
|
||||
if element is None:
|
||||
@@ -161,6 +186,7 @@ def parse_things(xml_daten: bytes | str) -> list[BggSpiel]:
|
||||
verlag=_verketten(element, "boardgamepublisher"),
|
||||
autor=_verketten(element, "boardgamedesigner"),
|
||||
erscheinungsjahr=_jahr(_attribut_wert(element, "yearpublished")),
|
||||
bild_url=_bild_url(element),
|
||||
typ=typ,
|
||||
)
|
||||
)
|
||||
|
||||
Reference in New Issue
Block a user