mirror of
https://github.com/blitzkit/blitzkit.git
synced 2026-10-24 20:19:49 +02:00
feat: functional filters
This commit is contained in:
1 parent
7225fb0231
commit
5b7ce1ae7b
2 files changed
+350
-191
No files matched your search
@@ -0,0 +1,149 @@
|
|||||||
|
import { Flex, Grid, Heading, Link, Separator, Text } from '@radix-ui/themes';
|
||||||
|
import { range } from 'lodash';
|
||||||
|
import { memo, use } from 'react';
|
||||||
|
import { classIcons } from '../../../../components/ClassIcon';
|
||||||
|
import { TANK_CLASSES } from '../../../../components/Tanks/components/Item/constants';
|
||||||
|
import { asset } from '../../../../core/blitzkit/asset';
|
||||||
|
import { gameDefinitions } from '../../../../core/blitzkit/gameDefinitions';
|
||||||
|
import {
|
||||||
|
Tier,
|
||||||
|
tanksDefinitionsArray,
|
||||||
|
} from '../../../../core/blitzkit/tankDefinitions';
|
||||||
|
import { TIER_ROMAN_NUMERALS } from '../../../../core/blitzkit/tankDefinitions/constants';
|
||||||
|
import { tankIcon } from '../../../../core/blitzkit/tankIcon';
|
||||||
|
import { TankopediaSearchPageFilters } from '../page';
|
||||||
|
import { treeTypeOrder } from './TankSearch/constants';
|
||||||
|
|
||||||
|
interface ResultsProps {
|
||||||
|
filters: TankopediaSearchPageFilters;
|
||||||
|
}
|
||||||
|
|
||||||
|
export const Results = memo<ResultsProps>(({ filters }) => {
|
||||||
|
const awaitedTanksDefinitionsArray = use(tanksDefinitionsArray);
|
||||||
|
const tanksFiltered = awaitedTanksDefinitionsArray.filter((tank) => {
|
||||||
|
return (
|
||||||
|
(filters.tier === undefined || filters.tier === tank.tier) &&
|
||||||
|
(filters.nation === undefined || filters.nation === tank.nation) &&
|
||||||
|
(filters.class === undefined || filters.class === tank.class) &&
|
||||||
|
(filters.type === undefined || filters.type === tank.treeType) &&
|
||||||
|
(filters.testing === 'include' ||
|
||||||
|
(filters.testing === 'only' && tank.testing) ||
|
||||||
|
(filters.testing === 'exclude' && !tank.testing))
|
||||||
|
);
|
||||||
|
});
|
||||||
|
const awaitedGameDefinitions = use(gameDefinitions);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Flex direction="column" gap="8" flexGrow="1">
|
||||||
|
{range(10, 0).map((tierUntyped) => {
|
||||||
|
const tier = tierUntyped as Tier;
|
||||||
|
const tierTanks = tanksFiltered
|
||||||
|
.filter((tank) => tank.tier === tier)
|
||||||
|
.sort(
|
||||||
|
(a, b) =>
|
||||||
|
treeTypeOrder.indexOf(a.treeType) -
|
||||||
|
treeTypeOrder.indexOf(b.treeType),
|
||||||
|
)
|
||||||
|
.sort(
|
||||||
|
(a, b) =>
|
||||||
|
TANK_CLASSES.indexOf(a.class) - TANK_CLASSES.indexOf(b.class),
|
||||||
|
)
|
||||||
|
.sort(
|
||||||
|
(a, b) =>
|
||||||
|
awaitedGameDefinitions.nations.indexOf(a.nation) -
|
||||||
|
awaitedGameDefinitions.nations.indexOf(b.nation),
|
||||||
|
);
|
||||||
|
|
||||||
|
if (tierTanks.length === 0) return null;
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Flex key={tier} direction="column" gap="4">
|
||||||
|
<Flex align="center" mb="4" gap="4">
|
||||||
|
<Heading weight="regular">
|
||||||
|
Tier {TIER_ROMAN_NUMERALS[tier]}
|
||||||
|
</Heading>
|
||||||
|
<Separator style={{ flex: 1 }} />
|
||||||
|
</Flex>
|
||||||
|
|
||||||
|
<Grid
|
||||||
|
flexGrow="1"
|
||||||
|
columns="repeat(auto-fill, minmax(100px, 1fr))"
|
||||||
|
gap="2"
|
||||||
|
gapY="6"
|
||||||
|
>
|
||||||
|
{tierTanks.map((tank) => {
|
||||||
|
const Icon = classIcons[tank.class];
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Link
|
||||||
|
key={tank.id}
|
||||||
|
size="1"
|
||||||
|
color={
|
||||||
|
tank.treeType === 'collector'
|
||||||
|
? 'blue'
|
||||||
|
: tank.treeType === 'premium'
|
||||||
|
? 'amber'
|
||||||
|
: 'gray'
|
||||||
|
}
|
||||||
|
highContrast={tank.treeType === 'researchable'}
|
||||||
|
underline="hover"
|
||||||
|
href={`/tools/tankopedia/${tank.id}`}
|
||||||
|
style={{
|
||||||
|
display: 'flex',
|
||||||
|
flexDirection: 'column',
|
||||||
|
alignItems: 'center',
|
||||||
|
gap: 'var(--space-2)',
|
||||||
|
background: `url(${asset(`flags/scratched/${tank.nation}.webp`)})`,
|
||||||
|
backgroundSize: 'contain',
|
||||||
|
backgroundRepeat: 'no-repeat',
|
||||||
|
backgroundPosition: 'top left',
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<img
|
||||||
|
alt={tank.name}
|
||||||
|
src={tankIcon(tank.id)}
|
||||||
|
height={64}
|
||||||
|
style={{
|
||||||
|
width: '100%',
|
||||||
|
objectPosition: 'center right',
|
||||||
|
objectFit: 'contain',
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
|
||||||
|
<Flex
|
||||||
|
justify="center"
|
||||||
|
gap="1"
|
||||||
|
align="center"
|
||||||
|
overflow="hidden"
|
||||||
|
width="100%"
|
||||||
|
maxWidth="100%"
|
||||||
|
>
|
||||||
|
<Icon
|
||||||
|
style={{
|
||||||
|
width: '1em',
|
||||||
|
height: '1em',
|
||||||
|
minWidth: '1em',
|
||||||
|
minHeight: '1em',
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
<Text
|
||||||
|
align="center"
|
||||||
|
style={{
|
||||||
|
whiteSpace: 'nowrap',
|
||||||
|
overflow: 'hidden',
|
||||||
|
textOverflow: 'ellipsis',
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{tank.name}
|
||||||
|
</Text>
|
||||||
|
</Flex>
|
||||||
|
</Link>
|
||||||
|
);
|
||||||
|
})}
|
||||||
|
</Grid>
|
||||||
|
</Flex>
|
||||||
|
);
|
||||||
|
})}
|
||||||
|
</Flex>
|
||||||
|
);
|
||||||
|
});
|
||||||
+201
-191
@@ -1,35 +1,45 @@
|
|||||||
import {
|
'use client';
|
||||||
Button,
|
|
||||||
Flex,
|
import { TrashIcon } from '@radix-ui/react-icons';
|
||||||
Grid,
|
import { Box, Button, Flex, IconButton, Text } from '@radix-ui/themes';
|
||||||
Heading,
|
import { produce } from 'immer';
|
||||||
IconButton,
|
import { times } from 'lodash';
|
||||||
Separator,
|
import { use, useState } from 'react';
|
||||||
Text,
|
|
||||||
} from '@radix-ui/themes';
|
|
||||||
import { range, times } from 'lodash';
|
|
||||||
import { use } from 'react';
|
|
||||||
import { classIcons } from '../../../components/ClassIcon';
|
import { classIcons } from '../../../components/ClassIcon';
|
||||||
import { ExperimentIcon } from '../../../components/ExperimentIcon';
|
import { ExperimentIcon } from '../../../components/ExperimentIcon';
|
||||||
import { Link } from '../../../components/Link';
|
|
||||||
import PageWrapper from '../../../components/PageWrapper';
|
import PageWrapper from '../../../components/PageWrapper';
|
||||||
import { ResearchedIcon } from '../../../components/ResearchedIcon';
|
import { ResearchedIcon } from '../../../components/ResearchedIcon';
|
||||||
import { ScienceIcon } from '../../../components/ScienceIcon';
|
import { ScienceIcon } from '../../../components/ScienceIcon';
|
||||||
import { ScienceOffIcon } from '../../../components/ScienceOffIcon';
|
import { ScienceOffIcon } from '../../../components/ScienceOffIcon';
|
||||||
|
import { TankClass, TreeType } from '../../../components/Tanks';
|
||||||
import { TANK_CLASSES } from '../../../components/Tanks/components/Item/constants';
|
import { TANK_CLASSES } from '../../../components/Tanks/components/Item/constants';
|
||||||
import { asset } from '../../../core/blitzkit/asset';
|
import { asset } from '../../../core/blitzkit/asset';
|
||||||
import { gameDefinitions } from '../../../core/blitzkit/gameDefinitions';
|
import { gameDefinitions } from '../../../core/blitzkit/gameDefinitions';
|
||||||
import {
|
import { Tier } from '../../../core/blitzkit/tankDefinitions';
|
||||||
Tier,
|
|
||||||
tanksDefinitionsArray,
|
|
||||||
} from '../../../core/blitzkit/tankDefinitions';
|
|
||||||
import { TIER_ROMAN_NUMERALS } from '../../../core/blitzkit/tankDefinitions/constants';
|
import { TIER_ROMAN_NUMERALS } from '../../../core/blitzkit/tankDefinitions/constants';
|
||||||
import { tankIcon } from '../../../core/blitzkit/tankIcon';
|
import { Results } from './components/Results';
|
||||||
import { treeTypeOrder } from './components/TankSearch/constants';
|
|
||||||
|
export interface TankopediaSearchPageFilters {
|
||||||
|
tier?: Tier;
|
||||||
|
nation?: string;
|
||||||
|
class?: TankClass;
|
||||||
|
type?: TreeType;
|
||||||
|
testing: 'include' | 'exclude' | 'only';
|
||||||
|
}
|
||||||
|
|
||||||
|
const defaultTankopediaSearchPageFilters: TankopediaSearchPageFilters = {
|
||||||
|
testing: 'include',
|
||||||
|
};
|
||||||
|
|
||||||
export default function Page() {
|
export default function Page() {
|
||||||
const awaitedTanksDefinitionsArray = use(tanksDefinitionsArray);
|
|
||||||
const awaitedGameDefinitions = use(gameDefinitions);
|
const awaitedGameDefinitions = use(gameDefinitions);
|
||||||
|
const [filters, setFilters] = useState<TankopediaSearchPageFilters>(
|
||||||
|
defaultTankopediaSearchPageFilters,
|
||||||
|
);
|
||||||
|
|
||||||
|
function mutateFilters(recipe: (draft: TankopediaSearchPageFilters) => void) {
|
||||||
|
setFilters(produce(recipe));
|
||||||
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<PageWrapper color="purple" size={1028 + 256}>
|
<PageWrapper color="purple" size={1028 + 256}>
|
||||||
@@ -58,10 +68,6 @@ export default function Page() {
|
|||||||
initial: 'center',
|
initial: 'center',
|
||||||
sm: 'start',
|
sm: 'start',
|
||||||
}}
|
}}
|
||||||
pt={{
|
|
||||||
initial: '0',
|
|
||||||
sm: '8',
|
|
||||||
}}
|
|
||||||
>
|
>
|
||||||
<Flex
|
<Flex
|
||||||
direction={{
|
direction={{
|
||||||
@@ -81,20 +87,23 @@ export default function Page() {
|
|||||||
>
|
>
|
||||||
{times(5, (index) => {
|
{times(5, (index) => {
|
||||||
const tier = (index + 1) as Tier;
|
const tier = (index + 1) as Tier;
|
||||||
|
const selected = filters.tier === tier;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Button
|
<IconButton
|
||||||
key={tier}
|
key={tier}
|
||||||
variant="soft"
|
variant={selected ? 'solid' : 'soft'}
|
||||||
radius="none"
|
radius="none"
|
||||||
color="gray"
|
color={selected ? undefined : 'gray'}
|
||||||
highContrast
|
highContrast
|
||||||
style={{
|
onClick={() =>
|
||||||
width: 32,
|
mutateFilters((draft) => {
|
||||||
}}
|
draft.tier = draft.tier === tier ? undefined : tier;
|
||||||
|
})
|
||||||
|
}
|
||||||
>
|
>
|
||||||
{TIER_ROMAN_NUMERALS[tier]}
|
<Text size="2">{TIER_ROMAN_NUMERALS[tier]}</Text>
|
||||||
</Button>
|
</IconButton>
|
||||||
);
|
);
|
||||||
})}
|
})}
|
||||||
</Flex>
|
</Flex>
|
||||||
@@ -106,20 +115,23 @@ export default function Page() {
|
|||||||
>
|
>
|
||||||
{times(5, (index) => {
|
{times(5, (index) => {
|
||||||
const tier = (index + 6) as Tier;
|
const tier = (index + 6) as Tier;
|
||||||
|
const selected = filters.tier === tier;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Button
|
<IconButton
|
||||||
key={tier}
|
key={tier}
|
||||||
variant="soft"
|
variant={selected ? 'solid' : 'soft'}
|
||||||
radius="none"
|
radius="none"
|
||||||
color="gray"
|
color={selected ? undefined : 'gray'}
|
||||||
highContrast
|
highContrast
|
||||||
style={{
|
onClick={() =>
|
||||||
width: 32,
|
mutateFilters((draft) => {
|
||||||
}}
|
draft.tier = draft.tier === tier ? undefined : tier;
|
||||||
|
})
|
||||||
|
}
|
||||||
>
|
>
|
||||||
{TIER_ROMAN_NUMERALS[tier]}
|
<Text size="2">{TIER_ROMAN_NUMERALS[tier]}</Text>
|
||||||
</Button>
|
</IconButton>
|
||||||
);
|
);
|
||||||
})}
|
})}
|
||||||
</Flex>
|
</Flex>
|
||||||
@@ -143,20 +155,29 @@ export default function Page() {
|
|||||||
>
|
>
|
||||||
{awaitedGameDefinitions.nations
|
{awaitedGameDefinitions.nations
|
||||||
.slice(0, Math.ceil(awaitedGameDefinitions.nations.length / 2))
|
.slice(0, Math.ceil(awaitedGameDefinitions.nations.length / 2))
|
||||||
.map((nation) => (
|
.map((nation) => {
|
||||||
<IconButton
|
const selected = filters.nation === nation;
|
||||||
// style={{ flex: 1 }}
|
|
||||||
variant="soft"
|
return (
|
||||||
color="gray"
|
<IconButton
|
||||||
highContrast
|
variant={selected ? 'solid' : 'soft'}
|
||||||
radius="none"
|
color={selected ? undefined : 'gray'}
|
||||||
>
|
highContrast
|
||||||
<img
|
radius="none"
|
||||||
style={{ width: '1em', height: '1em' }}
|
onClick={() =>
|
||||||
src={asset(`flags/circle/${nation}.webp`)}
|
mutateFilters((draft) => {
|
||||||
/>
|
draft.nation =
|
||||||
</IconButton>
|
draft.nation === nation ? undefined : nation;
|
||||||
))}
|
})
|
||||||
|
}
|
||||||
|
>
|
||||||
|
<img
|
||||||
|
style={{ width: '1em', height: '1em' }}
|
||||||
|
src={asset(`flags/circle/${nation}.webp`)}
|
||||||
|
/>
|
||||||
|
</IconButton>
|
||||||
|
);
|
||||||
|
})}
|
||||||
</Flex>
|
</Flex>
|
||||||
<Flex
|
<Flex
|
||||||
direction={{
|
direction={{
|
||||||
@@ -166,21 +187,30 @@ export default function Page() {
|
|||||||
>
|
>
|
||||||
{awaitedGameDefinitions.nations
|
{awaitedGameDefinitions.nations
|
||||||
.slice(Math.ceil(awaitedGameDefinitions.nations.length / 2))
|
.slice(Math.ceil(awaitedGameDefinitions.nations.length / 2))
|
||||||
.map((nation) => (
|
.map((nation) => {
|
||||||
<IconButton
|
const selected = filters.nation === nation;
|
||||||
style={{ flex: 1 }}
|
|
||||||
variant="soft"
|
return (
|
||||||
color="gray"
|
<IconButton
|
||||||
highContrast
|
style={{ flex: 1 }}
|
||||||
radius="none"
|
variant={selected ? 'solid' : 'soft'}
|
||||||
>
|
color={selected ? undefined : 'gray'}
|
||||||
{/* TODO: trim icons */}
|
highContrast
|
||||||
<img
|
radius="none"
|
||||||
style={{ width: '1em', height: '1em' }}
|
onClick={() =>
|
||||||
src={asset(`flags/circle/${nation}.webp`)}
|
mutateFilters((draft) => {
|
||||||
/>
|
draft.nation =
|
||||||
</IconButton>
|
draft.nation === nation ? undefined : nation;
|
||||||
))}
|
})
|
||||||
|
}
|
||||||
|
>
|
||||||
|
<img
|
||||||
|
style={{ width: '1em', height: '1em' }}
|
||||||
|
src={asset(`flags/circle/${nation}.webp`)}
|
||||||
|
/>
|
||||||
|
</IconButton>
|
||||||
|
);
|
||||||
|
})}
|
||||||
</Flex>
|
</Flex>
|
||||||
</Flex>
|
</Flex>
|
||||||
|
|
||||||
@@ -196,14 +226,21 @@ export default function Page() {
|
|||||||
>
|
>
|
||||||
{TANK_CLASSES.map((tankClass) => {
|
{TANK_CLASSES.map((tankClass) => {
|
||||||
const Icon = classIcons[tankClass];
|
const Icon = classIcons[tankClass];
|
||||||
|
const selected = filters.class === tankClass;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<IconButton
|
<IconButton
|
||||||
key={tankClass}
|
key={tankClass}
|
||||||
variant="soft"
|
variant={selected ? 'solid' : 'soft'}
|
||||||
radius="none"
|
radius="none"
|
||||||
color="gray"
|
color={selected ? undefined : 'gray'}
|
||||||
highContrast
|
highContrast
|
||||||
|
onClick={() =>
|
||||||
|
mutateFilters((draft) => {
|
||||||
|
draft.class =
|
||||||
|
draft.class === tankClass ? undefined : tankClass;
|
||||||
|
})
|
||||||
|
}
|
||||||
>
|
>
|
||||||
<Icon style={{ width: '1em', height: '1em' }} />
|
<Icon style={{ width: '1em', height: '1em' }} />
|
||||||
</IconButton>
|
</IconButton>
|
||||||
@@ -221,20 +258,52 @@ export default function Page() {
|
|||||||
initial: 'column',
|
initial: 'column',
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<IconButton variant="soft" radius="none" color="gray" highContrast>
|
<IconButton
|
||||||
|
variant={filters.type === 'researchable' ? 'solid' : 'soft'}
|
||||||
|
radius="none"
|
||||||
|
color={filters.type === 'researchable' ? undefined : 'gray'}
|
||||||
|
highContrast
|
||||||
|
onClick={() =>
|
||||||
|
mutateFilters((draft) => {
|
||||||
|
draft.type =
|
||||||
|
draft.type === 'researchable' ? undefined : 'researchable';
|
||||||
|
})
|
||||||
|
}
|
||||||
|
>
|
||||||
<ResearchedIcon style={{ width: '1em', height: '1em' }} />
|
<ResearchedIcon style={{ width: '1em', height: '1em' }} />
|
||||||
</IconButton>
|
</IconButton>
|
||||||
<IconButton variant="soft" radius="none" color="gray" highContrast>
|
<IconButton
|
||||||
|
variant={filters.type === 'premium' ? 'solid' : 'soft'}
|
||||||
|
radius="none"
|
||||||
|
color={filters.type === 'premium' ? 'amber' : 'gray'}
|
||||||
|
highContrast
|
||||||
|
onClick={() =>
|
||||||
|
mutateFilters((draft) => {
|
||||||
|
draft.type = draft.type === 'premium' ? undefined : 'premium';
|
||||||
|
})
|
||||||
|
}
|
||||||
|
>
|
||||||
<Text
|
<Text
|
||||||
color="amber"
|
color={filters.type === 'premium' ? undefined : 'amber'}
|
||||||
style={{ display: 'flex', justifyContent: 'center' }}
|
style={{ display: 'flex', justifyContent: 'center' }}
|
||||||
>
|
>
|
||||||
<ResearchedIcon style={{ width: '1em', height: '1em' }} />
|
<ResearchedIcon style={{ width: '1em', height: '1em' }} />
|
||||||
</Text>
|
</Text>
|
||||||
</IconButton>
|
</IconButton>
|
||||||
<IconButton variant="soft" radius="none" color="gray" highContrast>
|
<IconButton
|
||||||
|
variant={filters.type === 'collector' ? 'solid' : 'soft'}
|
||||||
|
radius="none"
|
||||||
|
color={filters.type === 'collector' ? 'blue' : 'gray'}
|
||||||
|
highContrast
|
||||||
|
onClick={() =>
|
||||||
|
mutateFilters((draft) => {
|
||||||
|
draft.type =
|
||||||
|
draft.type === 'collector' ? undefined : 'collector';
|
||||||
|
})
|
||||||
|
}
|
||||||
|
>
|
||||||
<Text
|
<Text
|
||||||
color="blue"
|
color={filters.type === 'premium' ? undefined : 'blue'}
|
||||||
style={{ display: 'flex', justifyContent: 'center' }}
|
style={{ display: 'flex', justifyContent: 'center' }}
|
||||||
>
|
>
|
||||||
<ResearchedIcon style={{ width: '1em', height: '1em' }} />
|
<ResearchedIcon style={{ width: '1em', height: '1em' }} />
|
||||||
@@ -252,133 +321,74 @@ export default function Page() {
|
|||||||
initial: 'column',
|
initial: 'column',
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<IconButton variant="soft" radius="none" color="gray" highContrast>
|
<IconButton
|
||||||
|
variant={filters.testing === 'include' ? 'solid' : 'soft'}
|
||||||
|
radius="none"
|
||||||
|
color={filters.testing === 'include' ? undefined : 'gray'}
|
||||||
|
highContrast
|
||||||
|
onClick={() =>
|
||||||
|
mutateFilters((draft) => {
|
||||||
|
draft.testing = 'include';
|
||||||
|
})
|
||||||
|
}
|
||||||
|
>
|
||||||
<ExperimentIcon
|
<ExperimentIcon
|
||||||
style={{ width: '1em', height: '1em', color: 'currentColor' }}
|
style={{ width: '1em', height: '1em', color: 'currentColor' }}
|
||||||
/>
|
/>
|
||||||
</IconButton>
|
</IconButton>
|
||||||
<IconButton variant="soft" radius="none" color="gray" highContrast>
|
<IconButton
|
||||||
<ScienceIcon
|
variant={filters.testing === 'exclude' ? 'solid' : 'soft'}
|
||||||
style={{ width: '1em', height: '1em', color: 'currentColor' }}
|
radius="none"
|
||||||
/>
|
color={filters.testing === 'exclude' ? undefined : 'gray'}
|
||||||
</IconButton>
|
highContrast
|
||||||
<IconButton variant="soft" radius="none" color="gray" highContrast>
|
onClick={() =>
|
||||||
|
mutateFilters((draft) => {
|
||||||
|
draft.testing = 'exclude';
|
||||||
|
})
|
||||||
|
}
|
||||||
|
>
|
||||||
<ScienceOffIcon
|
<ScienceOffIcon
|
||||||
style={{ width: '1em', height: '1em', color: 'currentColor' }}
|
style={{ width: '1em', height: '1em', color: 'currentColor' }}
|
||||||
/>
|
/>
|
||||||
</IconButton>
|
</IconButton>
|
||||||
|
<IconButton
|
||||||
|
variant={filters.testing === 'only' ? 'solid' : 'soft'}
|
||||||
|
radius="none"
|
||||||
|
color={filters.testing === 'only' ? undefined : 'gray'}
|
||||||
|
highContrast
|
||||||
|
onClick={() =>
|
||||||
|
mutateFilters((draft) => {
|
||||||
|
draft.testing = 'only';
|
||||||
|
})
|
||||||
|
}
|
||||||
|
>
|
||||||
|
<ScienceIcon
|
||||||
|
style={{ width: '1em', height: '1em', color: 'currentColor' }}
|
||||||
|
/>
|
||||||
|
</IconButton>
|
||||||
</Flex>
|
</Flex>
|
||||||
|
|
||||||
|
<Box display={{ initial: 'block', sm: 'none' }}>
|
||||||
|
<IconButton
|
||||||
|
color="red"
|
||||||
|
ml="2"
|
||||||
|
onClick={() => setFilters(defaultTankopediaSearchPageFilters)}
|
||||||
|
>
|
||||||
|
<TrashIcon />
|
||||||
|
</IconButton>
|
||||||
|
</Box>
|
||||||
|
<Box display={{ initial: 'none', sm: 'block' }}>
|
||||||
|
<Button
|
||||||
|
color="red"
|
||||||
|
mt="2"
|
||||||
|
onClick={() => setFilters(defaultTankopediaSearchPageFilters)}
|
||||||
|
>
|
||||||
|
<TrashIcon /> Clear
|
||||||
|
</Button>
|
||||||
|
</Box>
|
||||||
</Flex>
|
</Flex>
|
||||||
|
|
||||||
<Flex direction="column" gap="8" flexGrow="1">
|
<Results filters={filters} />
|
||||||
{range(10, 0).map((tierUntyped) => {
|
|
||||||
const tier = tierUntyped as Tier;
|
|
||||||
const tierTanks = awaitedTanksDefinitionsArray
|
|
||||||
.filter((tank) => tank.tier === tier)
|
|
||||||
.sort(
|
|
||||||
(a, b) =>
|
|
||||||
treeTypeOrder.indexOf(a.treeType) -
|
|
||||||
treeTypeOrder.indexOf(b.treeType),
|
|
||||||
)
|
|
||||||
.sort(
|
|
||||||
(a, b) =>
|
|
||||||
TANK_CLASSES.indexOf(a.class) - TANK_CLASSES.indexOf(b.class),
|
|
||||||
)
|
|
||||||
.sort(
|
|
||||||
(a, b) =>
|
|
||||||
awaitedGameDefinitions.nations.indexOf(a.nation) -
|
|
||||||
awaitedGameDefinitions.nations.indexOf(b.nation),
|
|
||||||
);
|
|
||||||
|
|
||||||
return (
|
|
||||||
<Flex key={tier} direction="column" gap="4">
|
|
||||||
<Flex align="center" mb="4" gap="4">
|
|
||||||
<Heading weight="regular">
|
|
||||||
Tier {TIER_ROMAN_NUMERALS[tier]}
|
|
||||||
</Heading>
|
|
||||||
<Separator style={{ flex: 1 }} />
|
|
||||||
</Flex>
|
|
||||||
|
|
||||||
<Grid
|
|
||||||
flexGrow="1"
|
|
||||||
columns="repeat(auto-fill, minmax(100px, 1fr))"
|
|
||||||
gap="2"
|
|
||||||
gapY="6"
|
|
||||||
>
|
|
||||||
{tierTanks.map((tank) => {
|
|
||||||
const Icon = classIcons[tank.class];
|
|
||||||
|
|
||||||
return (
|
|
||||||
<Link
|
|
||||||
key={tank.id}
|
|
||||||
size="1"
|
|
||||||
color={
|
|
||||||
tank.treeType === 'collector'
|
|
||||||
? 'blue'
|
|
||||||
: tank.treeType === 'premium'
|
|
||||||
? 'amber'
|
|
||||||
: 'gray'
|
|
||||||
}
|
|
||||||
highContrast={tank.treeType === 'researchable'}
|
|
||||||
underline="hover"
|
|
||||||
href={`/tools/tankopedia/${tank.id}`}
|
|
||||||
style={{
|
|
||||||
display: 'flex',
|
|
||||||
flexDirection: 'column',
|
|
||||||
alignItems: 'center',
|
|
||||||
gap: 'var(--space-2)',
|
|
||||||
background: `url(${asset(`flags/scratched/${tank.nation}.webp`)})`,
|
|
||||||
backgroundSize: 'contain',
|
|
||||||
backgroundRepeat: 'no-repeat',
|
|
||||||
backgroundPosition: 'top left',
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<img
|
|
||||||
alt={tank.name}
|
|
||||||
src={tankIcon(tank.id)}
|
|
||||||
height={64}
|
|
||||||
style={{
|
|
||||||
width: '100%',
|
|
||||||
objectPosition: 'center right',
|
|
||||||
objectFit: 'contain',
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
|
|
||||||
<Flex
|
|
||||||
justify="center"
|
|
||||||
gap="1"
|
|
||||||
align="center"
|
|
||||||
overflow="hidden"
|
|
||||||
width="100%"
|
|
||||||
maxWidth="100%"
|
|
||||||
>
|
|
||||||
<Icon
|
|
||||||
style={{
|
|
||||||
width: '1em',
|
|
||||||
height: '1em',
|
|
||||||
minWidth: '1em',
|
|
||||||
minHeight: '1em',
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
<Text
|
|
||||||
align="center"
|
|
||||||
style={{
|
|
||||||
whiteSpace: 'nowrap',
|
|
||||||
overflow: 'hidden',
|
|
||||||
textOverflow: 'ellipsis',
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
{tank.name}
|
|
||||||
</Text>
|
|
||||||
</Flex>
|
|
||||||
</Link>
|
|
||||||
);
|
|
||||||
})}
|
|
||||||
</Grid>
|
|
||||||
</Flex>
|
|
||||||
);
|
|
||||||
})}
|
|
||||||
</Flex>
|
|
||||||
</Flex>
|
</Flex>
|
||||||
</PageWrapper>
|
</PageWrapper>
|
||||||
);
|
);
|
||||||
|
|||||||
Reference in new issue
Block a user