Files
flimmer/src/components/library/LibraryCard.tsx
T
Florian Wilde a853b066b5
CI / pruefen (pull_request) Canceled after 0s
Titelraster auf eine feste Zeilenhoehe bringen
Der Titelblock hatte mit line-clamp-2 zwar eine Ober-, aber keine
Untergrenze. Einzeilige Titel belegten dadurch 19 statt 39 Pixel, und alles
darunter rutschte um eine Zeilenhoehe nach oben — neben Karten mit
zweizeiligem Titel wirkte das Raster ausgefranst.

Der Titelblock bekommt jetzt mit min-h-[2lh] immer zwei Zeilen. Die Einheit
lh haengt an der tatsaechlichen Zeilenhoehe, damit der Wert nicht von einer
Aenderung an leading-snug abgehaengt wird.

In der Bibliothekskarte kam hinzu, dass der Fortschrittsbalken nur bei
Serien erscheint. Sein Platz wird jetzt auch dann freigehalten, wenn er
leer bleibt — als unsichtbarer Nachbau statt einer festen Pixelhoehe, damit
er sich von selbst nachzieht.

Nachgemessen bei 1400 px: Metazeilen einer Reihe liegen jetzt alle auf
derselben Oberkante (Suche 711 px, Bibliothek 715/1117/1520 px), und alle
Karten sind gleich hoch (353 bzw. 387 px). Vorher: 691 gegen 711 px und
Kartenhoehen von 333 bis 367 px. Bei Handybreite ebenfalls sauber.

Refs #2
2026-09-01 23:29:12 +02:00

103 lines
4.0 KiB
TypeScript

import Link from "next/link";
import { Poster } from "@/components/Poster";
import { ProgressBar } from "@/components/ProgressBar";
import { STATUS_COLOR, STATUS_LABEL, type StatusKey } from "@/lib/labels";
import type { LibraryItem } from "@/lib/queries";
/**
* Posterkachel der Bibliothek.
*
* Alles Wesentliche steht ohne Klick da: Status, Fortschritt, Bewertung.
* Die Karte ist ein Link — der ganze Bereich ist anklickbar, nicht nur der Titel.
*/
export function LibraryCard({ item }: { item: LibraryItem }) {
const status = item.status as StatusKey;
const showProgress = item.type === "SERIES" && item.total > 0 && item.status !== "WATCHLIST";
return (
<Link href={`/titel/${item.titleId}`} className="fl-poster-card group block focus:outline-none">
<div className="relative">
<Poster path={item.posterPath} alt={item.title} size="w342" />
{/* Status und Sammlung teilen sich die obere Zeile — unten sitzt bei
den Postern oft der Titel, dort würden sie ihn verdecken. */}
<span className="absolute left-2 top-2 flex flex-wrap gap-1">
<span
className="rounded-full px-2 py-0.5 text-[0.65rem] font-semibold backdrop-blur-md"
style={{
color: STATUS_COLOR[status],
backgroundColor: `color-mix(in oklab, var(--fl-bg) 72%, transparent)`,
boxShadow: `inset 0 0 0 1px color-mix(in oklab, ${STATUS_COLOR[status]} 45%, transparent)`,
}}
>
{STATUS_LABEL[status]}
</span>
{item.owned && (
<span
className="rounded-full px-2 py-0.5 text-[0.65rem] font-semibold text-[var(--fl-on-accent)]"
style={{ backgroundImage: "var(--fl-gradient)" }}
title={
item.ownedSource ? `In deiner Sammlung: ${item.ownedSource}` : "In deiner Sammlung"
}
>
Hab ich
</span>
)}
</span>
{item.rating != null && (
<span
className="absolute right-2 top-2 rounded-full px-2 py-0.5 text-[0.65rem] font-semibold text-[var(--fl-on-accent)]"
style={{ backgroundImage: "var(--fl-gradient)" }}
>
{item.rating}
</span>
)}
{item.currentRun > 0 && (
<span className="absolute bottom-2 right-2 rounded-full bg-[color-mix(in_oklab,var(--fl-bg)_78%,transparent)] px-2 py-0.5 text-[0.65rem] font-medium text-[var(--fl-muted)] backdrop-blur-md">
{item.currentRun + 1}. Durchlauf
</span>
)}
</div>
<div className="mt-2 space-y-1">
<p className="line-clamp-2 min-h-[2lh] text-sm font-medium leading-snug">{item.title}</p>
<p className="text-xs text-[var(--fl-faint)]">
{item.type === "SERIES" ? "Serie" : "Film"}
{item.year ? ` · ${item.year}` : ""}
{item.owned && item.ownedSource
? ` · ${item.ownedSource}`
: item.whereToWatch
? ` · ${item.whereToWatch}`
: ""}
</p>
<div className="pt-0.5">
{showProgress ? (
<>
<ProgressBar
percent={item.percent}
label={`${item.watched} von ${item.total} Episoden gesehen`}
/>
<p className="mt-1 text-xs text-[var(--fl-faint)]">
{item.watched}/{item.total} Episoden
</p>
</>
) : (
// Filme und Watchlist-Einträge haben keinen Balken. Der Platz wird
// trotzdem freigehalten — sonst fallen sie kürzer aus als Serien und
// das Raster franst reihenweise aus. Der Nachbau statt einer festen
// Pixelhöhe hält sich von selbst nach, wenn sich der Balken ändert.
<div className="invisible" aria-hidden>
<div className="fl-progress" />
<p className="mt-1 text-xs">&nbsp;</p>
</div>
)}
</div>
</div>
</Link>
);
}