64 lines
1.7 KiB
TypeScript
64 lines
1.7 KiB
TypeScript
import { ListItem } from "@/shared/components/ui/list-item"
|
|
import type { Game } from "@/shared/db/schema"
|
|
import { formatPlaytime } from "../schema"
|
|
import { gameStateColors } from "../schema"
|
|
|
|
const apiBase = import.meta.env.BASE_URL.replace(/\/$/, "")
|
|
|
|
interface GameListItemProps {
|
|
game: Game
|
|
onClick?: () => void
|
|
}
|
|
|
|
export function GameListItem({ game, onClick }: GameListItemProps) {
|
|
const coverUrl = game.cover_image_id
|
|
? `${apiBase}/api/igdb/image/${game.cover_image_id}/thumb`
|
|
: game.source === "steam"
|
|
? `${apiBase}/api/steam/icon/${game.source_id}`
|
|
: undefined
|
|
|
|
const imgClass = game.cover_image_id
|
|
? "h-10 w-10 rounded object-cover"
|
|
: "h-10 w-16 rounded object-cover"
|
|
|
|
return (
|
|
<ListItem
|
|
link
|
|
title={game.title}
|
|
subtitle={
|
|
game.playtime_hours > 0
|
|
? formatPlaytime(game.playtime_hours)
|
|
: undefined
|
|
}
|
|
media={
|
|
coverUrl ? (
|
|
<img src={coverUrl} alt="" className={imgClass} />
|
|
) : (
|
|
<span className="flex h-10 w-10 items-center justify-center rounded bg-muted text-[10px] font-medium text-muted-foreground">
|
|
{game.source.toUpperCase()}
|
|
</span>
|
|
)
|
|
}
|
|
after={<GameListItemAfter game={game} />}
|
|
onClick={onClick}
|
|
/>
|
|
)
|
|
}
|
|
|
|
function GameListItemAfter({ game }: { game: Game }) {
|
|
const ratingText =
|
|
game.rating >= 0 ? `★ ${Math.round(game.rating / 2)}/5` : null
|
|
const dotColor =
|
|
game.game_state !== "not_set" ? gameStateColors[game.game_state] : null
|
|
|
|
return (
|
|
<span className="flex items-center gap-1.5 text-xs text-muted-foreground">
|
|
{ratingText && <span>{ratingText}</span>}
|
|
{dotColor && (
|
|
<span className={`inline-block h-2 w-2 rounded-full ${dotColor}`} />
|
|
)}
|
|
{game.is_favorite && <span className="text-red-500">♥</span>}
|
|
</span>
|
|
)
|
|
}
|