CatalogTile.tsx 1.2 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849
  1. import type { CandidateMovie } from '../types'
  2. import { formatRating } from '../lib/format'
  3. interface CatalogTileProps {
  4. movie: CandidateMovie
  5. index: number
  6. selected?: boolean
  7. seen?: boolean
  8. onSelect: (movie: CandidateMovie) => void
  9. }
  10. export function CatalogTile({
  11. movie,
  12. index,
  13. selected,
  14. seen,
  15. onSelect,
  16. }: CatalogTileProps) {
  17. const rating = formatRating(movie.rating)
  18. return (
  19. <button
  20. type="button"
  21. className={
  22. selected
  23. ? 'catalog-tile is-selected'
  24. : 'catalog-tile'
  25. }
  26. style={{ animationDelay: `${Math.min(index, 12) * 40}ms` }}
  27. onClick={() => onSelect(movie)}
  28. >
  29. <div className="catalog-tile__poster">
  30. {movie.poster_url ? (
  31. <img src={movie.poster_url} alt="" loading="lazy" />
  32. ) : (
  33. <div className="catalog-tile__fallback">{movie.title.slice(0, 1)}</div>
  34. )}
  35. {seen && <span className="catalog-tile__badge">已看</span>}
  36. </div>
  37. <div className="catalog-tile__meta">
  38. <span className="catalog-tile__title">{movie.title}</span>
  39. <span className="catalog-tile__sub">
  40. {movie.year ?? '—'}
  41. {rating ? ` · ${rating}` : ''}
  42. </span>
  43. </div>
  44. </button>
  45. )
  46. }