mirror of
https://github.com/blitzkit/blitzkit.git
synced 2026-10-21 18:57:03 +02:00
feat: playlist table
This commit is contained in:
1 parent
ed0dde37d2
commit
bfceacdf3c
10 files changed
+166
-7
No files matched your search
@@ -7,12 +7,13 @@ import { awaitableTankDefinitions } from "../core/awaitables/tankDefinitions";
|
||||
import { filterTanks } from "../core/blitzkit/filterTanks";
|
||||
import { useLocale } from "../hooks/useLocale";
|
||||
import { TankFilters } from "../stores/tankFilters";
|
||||
import { LinkI18n } from "./LinkI18n";
|
||||
import { FilterControl } from "./TankSearch/components/FilterControl";
|
||||
|
||||
const tankDefinitions = await awaitableTankDefinitions;
|
||||
|
||||
export function PlaylistPool() {
|
||||
const { strings } = useLocale();
|
||||
const { strings, locale } = useLocale();
|
||||
const filters = TankFilters.use();
|
||||
const randomTankList = useMemo(() => {
|
||||
const list = Object.values(tankDefinitions.tanks);
|
||||
@@ -52,7 +53,10 @@ export function PlaylistPool() {
|
||||
width="100%"
|
||||
>
|
||||
{tanksTrimmed.map((tank) => (
|
||||
<Box
|
||||
<LinkI18n
|
||||
target="_blank"
|
||||
locale={locale}
|
||||
href={`/tanks/${tank.slug}`}
|
||||
key={tank.id}
|
||||
style={{
|
||||
aspectRatio: "4 / 3",
|
||||
@@ -72,8 +76,8 @@ export function PlaylistPool() {
|
||||
width="100%"
|
||||
height="100%"
|
||||
style={{
|
||||
background:
|
||||
"linear-gradient(transparent, var(--gray-1) calc(100% - 2rem))",
|
||||
background: "linear-gradient(transparent, var(--gray-1))",
|
||||
pointerEvents: "none",
|
||||
}}
|
||||
/>
|
||||
</Box>
|
||||
|
||||
@@ -0,0 +1,34 @@
|
||||
import { ExclamationTriangleIcon } from "@radix-ui/react-icons";
|
||||
import { Button, Flex, Text } from "@radix-ui/themes";
|
||||
import { generatePlaylist } from "../core/blitzkit/generatePlaylist";
|
||||
import { useLocale } from "../hooks/useLocale";
|
||||
import { App } from "../stores/app";
|
||||
|
||||
export function PlaylistGenerator() {
|
||||
const { strings } = useLocale();
|
||||
const wargaming = App.use((state) => state.logins.wargaming);
|
||||
|
||||
return (
|
||||
<Flex
|
||||
flexGrow="1"
|
||||
flexBasis="1"
|
||||
direction="column"
|
||||
align="center"
|
||||
justify="center"
|
||||
gap="4"
|
||||
>
|
||||
<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>
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,38 @@
|
||||
import { Checkbox, Flex, Table } from "@radix-ui/themes";
|
||||
import { useLocale } from "../hooks/useLocale";
|
||||
import { Playlist } from "../stores/playlist";
|
||||
import { TankRowHeaderCell } from "./TankRowHeaderCell";
|
||||
|
||||
export function PlaylistOrder() {
|
||||
const { unwrap, strings } = useLocale();
|
||||
const list = Playlist.use((state) => state.list);
|
||||
|
||||
if (!list) return null;
|
||||
|
||||
return (
|
||||
<Flex justify="center" flexGrow="1" flexBasis="0">
|
||||
<Table.Root variant="surface">
|
||||
<Table.Header>
|
||||
<Table.Row>
|
||||
<Table.ColumnHeaderCell />
|
||||
<Table.ColumnHeaderCell>
|
||||
{strings.website.tools.playlist.table.tank}
|
||||
</Table.ColumnHeaderCell>
|
||||
</Table.Row>
|
||||
</Table.Header>
|
||||
|
||||
<Table.Body>
|
||||
{list.map(({ tank }) => (
|
||||
<Table.Row>
|
||||
<Table.Cell>
|
||||
<Checkbox variant="classic" checked={Math.random() > 0.5} />
|
||||
</Table.Cell>
|
||||
|
||||
<TankRowHeaderCell tank={tank} />
|
||||
</Table.Row>
|
||||
))}
|
||||
</Table.Body>
|
||||
</Table.Root>
|
||||
</Flex>
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,40 @@
|
||||
import {
|
||||
getTankStats,
|
||||
idToRegion,
|
||||
type IndividualTankStats,
|
||||
} from "@blitzkit/core";
|
||||
import { App } from "../../stores/app";
|
||||
import { Playlist } from "../../stores/playlist";
|
||||
import { TankFilters } from "../../stores/tankFilters";
|
||||
import { awaitableTankDefinitions } from "../awaitables/tankDefinitions";
|
||||
import { filterTanks } from "./filterTanks";
|
||||
|
||||
const tankDefinitions = await awaitableTankDefinitions;
|
||||
const tanks = Object.values(tankDefinitions.tanks);
|
||||
|
||||
export async function generatePlaylist() {
|
||||
const id = App.state.logins.wargaming?.id;
|
||||
const filtered = await filterTanks(TankFilters.state, tanks);
|
||||
const statsList = id ? await getTankStats(idToRegion(id), id) : undefined;
|
||||
const stats: Record<number, IndividualTankStats> = {};
|
||||
|
||||
if (statsList) {
|
||||
for (const tankStat of statsList) {
|
||||
stats[tankStat.tank_id] = tankStat;
|
||||
}
|
||||
}
|
||||
|
||||
for (let i = filtered.length - 1; i > 0; i--) {
|
||||
const j = Math.floor(Math.random() * (i + 1));
|
||||
[filtered[i], filtered[j]] = [filtered[j], filtered[i]];
|
||||
}
|
||||
|
||||
Playlist.mutate((draft) => {
|
||||
draft.list = filtered.map((tank, index) => ({
|
||||
index,
|
||||
tank,
|
||||
battles: stats[tank.id]?.all.battles,
|
||||
wins: stats[tank.id]?.all.wins,
|
||||
}));
|
||||
});
|
||||
}
|
||||
Whitespace-only changes.
@@ -1,6 +1,12 @@
|
||||
import { useEffect } from "react";
|
||||
import { PageWrapper } from "../../../components/PageWrapper";
|
||||
import { PlaylistPool } from "../../../components/PlaylistFilters";
|
||||
import { PlaylistGenerator } from "../../../components/PlaylistGenerator";
|
||||
import { PlaylistOrder } from "../../../components/PLaylistOrder";
|
||||
import { LocaleProvider } from "../../../hooks/useLocale";
|
||||
import { App } from "../../../stores/app";
|
||||
import { Playlist } from "../../../stores/playlist";
|
||||
import { TankFilters } from "../../../stores/tankFilters";
|
||||
import type { MaybeSkeletonComponentProps } from "../../../types/maybeSkeletonComponentProps";
|
||||
|
||||
interface Props {
|
||||
@@ -11,10 +17,23 @@ export function Page({
|
||||
locale,
|
||||
skeleton,
|
||||
}: Props & MaybeSkeletonComponentProps) {
|
||||
const list = Playlist.use((state) => state.list);
|
||||
const wargaming = App.use((state) => state.logins.wargaming);
|
||||
|
||||
useEffect(() => {
|
||||
if (wargaming) {
|
||||
TankFilters.mutate((draft) => {
|
||||
draft.ownership = "owned";
|
||||
});
|
||||
}
|
||||
}, []);
|
||||
|
||||
return (
|
||||
<LocaleProvider locale={locale}>
|
||||
<PageWrapper color="tomato" direction="row">
|
||||
<PageWrapper color="tomato" direction="row" maxWidth="100rem">
|
||||
<PlaylistPool />
|
||||
{!list && <PlaylistGenerator />}
|
||||
{list && <PlaylistOrder />}
|
||||
</PageWrapper>
|
||||
</LocaleProvider>
|
||||
);
|
||||
|
||||
@@ -0,0 +1,13 @@
|
||||
import type { TankDefinition } from "@blitzkit/core";
|
||||
import { Varuna } from "varuna";
|
||||
|
||||
export interface Playlist {
|
||||
list?: {
|
||||
index: number;
|
||||
tank: TankDefinition;
|
||||
battles?: number;
|
||||
wins?: number;
|
||||
}[];
|
||||
}
|
||||
|
||||
export const Playlist = new Varuna<Playlist>({}, "playlist");
|
||||
Reference in new issue
Block a user