import { clsx } from "clsx"; import { posterUrl, type ImageSize } from "@/lib/image-url"; import { FlimmerMark } from "@/components/brand/FlimmerLogo"; /** * Posterbild mit Rückfallebene. * * Nicht jeder Titel hat bei TMDB ein Poster, manuell angelegte schon gar * nicht, und einzelne Pfade verschwinden mit der Zeit. * * Die Rückfallkachel liegt deshalb **dauerhaft darunter**, das Bild darüber: * lädt es, verdeckt es die Kachel; lädt es nicht, bleibt die Kachel stehen. * Bewusst ohne onError-Handler — ein Bild kann schon fehlschlagen, bevor React * den Handler überhaupt angehängt hat. Das leere alt-Attribut sorgt dafür, * dass ein kaputtes Bild in sich zusammenfällt statt ein Symbol zu zeigen; * den Titel trägt der Container als aria-label. */ export function Poster({ path, alt, size = "w342", className, sizes = "(min-width: 1024px) 12rem, 40vw", priority = false, }: { path: string | null | undefined; alt: string; size?: ImageSize; className?: string; sizes?: string; priority?: boolean; }) { const url = posterUrl(path, size); return (
{alt}
{url && ( // Bewusst statt next/image: die Bilder laufen bereits über den // eigenen Cache-Endpunkt, eine zweite Optimierungsschicht brächte dem // selbst gehosteten Server nur zusätzliche Last. // eslint-disable-next-line @next/next/no-img-element )}
); } /** Breitbild-Variante für Kopfbereiche (Backdrop). */ export function Backdrop({ path, alt, className, }: { path: string | null | undefined; alt: string; className?: string; }) { const url = posterUrl(path, "w1280"); if (!url) return null; return (
{/* eslint-disable-next-line @next/next/no-img-element */}
); }