Files
blitzkit/packages/website/src/components/TankCard/index.tsx
T
2026-08-01 14:54:40 -05:00

116 lines
3.2 KiB
TypeScript

import { asset, TankType, type TankDefinition } from "@blitzkit/core";
import { Flex, Text, type TextProps } from "@radix-ui/themes";
import { uniq } from "lodash-es";
import { forwardRef, type ReactNode } from "react";
import { api } from "../../core/blitzkit/api";
import { useLocale } from "../../hooks/useLocale";
import { TankopediaPersistent } from "../../stores/tankopediaPersistent";
import { classIcons } from "../ClassIcon";
import { LinkI18n } from "../LinkI18n";
import { MAX_RECENTLY_VIEWED } from "../TankSearch/constants";
import "./index.css";
type TankCardProps = TextProps & {
tank: TankDefinition;
onTankSelect?: (tank: TankDefinition) => void;
discriminator?: ReactNode;
noLink?: boolean;
};
const tankDefinitions = await api.tankDefinitions();
export const TankCard = forwardRef<HTMLSpanElement, TankCardProps>(
(
{
tank,
discriminator,
onTankSelect: onSelect,
noLink,
style,
...props
}: TankCardProps,
ref,
) => {
const { unwrap, locale } = useLocale();
const provideLink = !noLink && onSelect === undefined;
const Icon = classIcons[tank.class];
return (
<Text
ref={ref}
tabIndex={onSelect ? 0 : undefined}
size="2"
color={
tank.type === TankType.TANK_TYPE_COLLECTOR
? "blue"
: tank.type === TankType.TANK_TYPE_PREMIUM
? "amber"
: "gray"
}
highContrast={tank.type === TankType.TANK_TYPE_RESEARCHABLE}
onClick={() => {
onSelect?.(tank);
TankopediaPersistent.mutate((draft) => {
draft.recentlyViewed = uniq([tank.id, ...draft.recentlyViewed])
.filter((id) => id in tankDefinitions.tanks)
.slice(0, MAX_RECENTLY_VIEWED);
});
}}
className="tank-search-card"
data-provide-link={provideLink}
style={{
backgroundImage: `url(${asset(`flags/scratched/${tank.nation}.webp`)})`,
...style,
}}
{...props}
>
<LinkI18n
locale={locale}
className="link"
underline="hover"
href={provideLink ? `/tanks/${tank.slug}` : "#"}
onClick={(event) => {
if (!provideLink) event.preventDefault();
}}
>
<img
alt={unwrap(tank.name!)}
src={asset(`icons/tanks/big/${tank.id}.webp`)}
className="image"
draggable={false}
/>
<Flex
justify="center"
gap="1"
align="center"
overflow="hidden"
width="100%"
mt="1"
>
<Icon className="class-icon" />
<Text align="center" className="name">
{unwrap(tank.name!)}
</Text>
</Flex>
{discriminator && (
<Text
color="gray"
align="center"
style={{
whiteSpace: "nowrap",
overflow: "hidden",
textOverflow: "ellipsis",
}}
>
{discriminator}
</Text>
)}
</LinkI18n>
</Text>
);
},
);