Repository Public
1import Link from "next/link";2import type { Film } from "@/lib/films";3import { fmtDuration, href, type Locale } from "@/lib/i18n";45/** Poster card. The image is decorative: the link text carries the title. */6export function FilmCard({ film, locale, note, priority = false }: { film: Film; locale: Locale; note?: string; priority?: boolean }) {7 return (8 <article className="group relative">9 <Link href={href(locale, `/film/${film.slug}`)} className="block">10 <div className="poster relative aspect-[9/16]">11 <img src={film.thumb} alt="" width={360} height={640} loading={priority ? "eager" : "lazy"} decoding="async"12 className="h-full w-full object-cover transition-transform duration-700 ease-[var(--ease-film)] group-hover:scale-[1.04]" />13 <div className="absolute inset-0 bg-gradient-to-t from-black/85 via-black/10 to-transparent" />14 <span className="absolute right-2 top-2 rounded bg-black/60 px-1.5 py-0.5 text-[0.68rem] tabular-nums text-white/90">{fmtDuration(film.duration)}</span>15 <div className="absolute inset-x-0 bottom-0 p-3">16 {film.series && <p className="mb-1 text-[0.62rem] uppercase tracking-[0.18em]" style={{ color: film.series.accent }}>{film.series.title}</p>}17 <h3 className="display text-xl leading-tight text-white">{film.title}</h3>18 </div>19 </div>20 </Link>21 {note && <p className="mt-2 text-xs text-[var(--color-faint)]">{note}</p>}22 </article>23 );24}2526export function FilmGrid({ films, locale, notes }: { films: Film[]; locale: Locale; notes?: Record<string, string> }) {27 return (28 <div className="grid grid-cols-2 gap-3 sm:grid-cols-3 sm:gap-4 lg:grid-cols-4 xl:grid-cols-5">29 {films.map((f, i) => <FilmCard key={f.id} film={f} locale={locale} note={notes?.[f.id]} priority={i < 4} />)}30 </div>31 );32}33