2025-10-14 20:19:52 -05:00
|
|
|
import { fisherYates, tankIcon } from "@blitzkit/core";
|
2025-10-12 22:48:14 -05:00
|
|
|
import { literals } from "@blitzkit/i18n";
|
2025-10-12 19:37:44 -05:00
|
|
|
import { ExclamationTriangleIcon } from "@radix-ui/react-icons";
|
2025-10-12 22:48:14 -05:00
|
|
|
import { Box, Button, Flex, Grid, Text } from "@radix-ui/themes";
|
|
|
|
|
import { useMemo } from "react";
|
|
|
|
|
import usePromise from "react-promise-suspense";
|
|
|
|
|
import { awaitableTankDefinitions } from "../core/awaitables/tankDefinitions";
|
|
|
|
|
import { filterTanks } from "../core/blitzkit/filterTanks";
|
2025-10-12 19:37:44 -05:00
|
|
|
import { generatePlaylist } from "../core/blitzkit/generatePlaylist";
|
|
|
|
|
import { useLocale } from "../hooks/useLocale";
|
|
|
|
|
import { App } from "../stores/app";
|
2025-10-12 22:48:14 -05:00
|
|
|
import { TankFilters } from "../stores/tankFilters";
|
|
|
|
|
import { LinkI18n } from "./LinkI18n";
|
|
|
|
|
import { FilterControl } from "./TankSearch/components/FilterControl";
|
|
|
|
|
|
|
|
|
|
const tankDefinitions = await awaitableTankDefinitions;
|
|
|
|
|
|
|
|
|
|
const POOL_HEIGHT = "16rem";
|
2025-10-12 19:37:44 -05:00
|
|
|
|
|
|
|
|
export function PlaylistGenerator() {
|
2025-10-12 22:48:14 -05:00
|
|
|
const { strings, locale } = useLocale();
|
2025-10-12 19:37:44 -05:00
|
|
|
const wargaming = App.use((state) => state.logins.wargaming);
|
2025-10-12 22:48:14 -05:00
|
|
|
const filters = TankFilters.use();
|
2025-10-14 20:19:52 -05:00
|
|
|
const randomTankList = useMemo(
|
|
|
|
|
() => fisherYates(Object.values(tankDefinitions.tanks)),
|
|
|
|
|
[filters]
|
|
|
|
|
);
|
2025-10-12 22:48:14 -05:00
|
|
|
const tanks = usePromise(
|
|
|
|
|
() => filterTanks(filters, randomTankList, wargaming?.id),
|
|
|
|
|
// react-promise-suspense has awful type annotations
|
|
|
|
|
[filters] as any
|
|
|
|
|
);
|
|
|
|
|
const tanksTrimmed = useMemo(() => tanks.slice(0, 65), [filters]);
|
2025-10-12 19:37:44 -05:00
|
|
|
|
|
|
|
|
return (
|
2025-10-14 21:36:37 -05:00
|
|
|
<Flex justify="center" width="100%" align="center">
|
2025-10-12 22:48:14 -05:00
|
|
|
<Flex
|
|
|
|
|
flexGrow="1"
|
2025-10-14 21:36:37 -05:00
|
|
|
gap="9"
|
2025-10-12 22:48:14 -05:00
|
|
|
align="center"
|
2025-10-14 21:36:37 -05:00
|
|
|
justify="center"
|
|
|
|
|
maxWidth="80rem"
|
2025-10-12 22:48:14 -05:00
|
|
|
>
|
2025-10-14 21:36:37 -05:00
|
|
|
<Flex direction="column" gap="4" align="center">
|
|
|
|
|
<FilterControl />
|
|
|
|
|
|
|
|
|
|
<Button onClick={generatePlaylist} size="3">
|
|
|
|
|
{strings.website.tools.playlist.generate}
|
|
|
|
|
</Button>
|
|
|
|
|
|
|
|
|
|
{!wargaming && (
|
|
|
|
|
<Text color="gray">
|
|
|
|
|
<Flex align="center" gap="1">
|
|
|
|
|
<ExclamationTriangleIcon />
|
|
|
|
|
{strings.website.tools.playlist.no_login_warning}
|
|
|
|
|
</Flex>
|
|
|
|
|
</Text>
|
|
|
|
|
)}
|
|
|
|
|
</Flex>
|
|
|
|
|
|
|
|
|
|
<Flex
|
|
|
|
|
direction="column"
|
|
|
|
|
flexGrow="1"
|
|
|
|
|
flexBasis="0"
|
|
|
|
|
align="center"
|
|
|
|
|
gap="4"
|
2025-10-12 22:48:14 -05:00
|
|
|
>
|
2025-10-14 21:36:37 -05:00
|
|
|
<Grid
|
|
|
|
|
columns="repeat(auto-fill, minmax(4rem, 1fr))"
|
|
|
|
|
flow="dense"
|
|
|
|
|
overflow="hidden"
|
|
|
|
|
position="relative"
|
|
|
|
|
maxHeight={POOL_HEIGHT}
|
|
|
|
|
width="100%"
|
|
|
|
|
>
|
|
|
|
|
{tanksTrimmed.map((tank) => (
|
|
|
|
|
<LinkI18n
|
|
|
|
|
target="_blank"
|
|
|
|
|
locale={locale}
|
|
|
|
|
href={`/tanks/${tank.slug}`}
|
|
|
|
|
key={tank.id}
|
|
|
|
|
style={{
|
|
|
|
|
aspectRatio: "4 / 3",
|
|
|
|
|
backgroundSize: "cover",
|
|
|
|
|
backgroundPosition: "center",
|
|
|
|
|
backgroundImage: `url(${tankIcon(tank.id)})`,
|
|
|
|
|
backgroundRepeat: "no-repeat",
|
|
|
|
|
}}
|
|
|
|
|
/>
|
|
|
|
|
))}
|
|
|
|
|
|
|
|
|
|
<Box
|
|
|
|
|
position="absolute"
|
|
|
|
|
top="0"
|
|
|
|
|
left="0"
|
|
|
|
|
width="100%"
|
|
|
|
|
height="100%"
|
2025-10-12 22:48:14 -05:00
|
|
|
style={{
|
2025-10-14 21:36:37 -05:00
|
|
|
pointerEvents: "none",
|
|
|
|
|
background: `linear-gradient(transparent, var(--gray-1) ${POOL_HEIGHT})`,
|
2025-10-12 22:48:14 -05:00
|
|
|
}}
|
|
|
|
|
/>
|
2025-10-14 21:36:37 -05:00
|
|
|
</Grid>
|
2025-10-12 22:48:14 -05:00
|
|
|
|
2025-10-14 21:36:37 -05:00
|
|
|
<Text color="gray">
|
|
|
|
|
{literals(strings.website.tools.playlist.pool_size, {
|
|
|
|
|
count: tanks.length,
|
|
|
|
|
})}
|
|
|
|
|
</Text>
|
|
|
|
|
</Flex>
|
2025-10-12 22:48:14 -05:00
|
|
|
</Flex>
|
2025-10-12 19:37:44 -05:00
|
|
|
</Flex>
|
|
|
|
|
);
|
|
|
|
|
}
|