mirror of
https://github.com/blitzkit/blitzkit.git
synced 2026-10-24 03:59:50 +02:00
feat: better layout
This commit is contained in:
1 parent
0c74cb90e9
commit
fe945cced1
11 files changed
+156
-137
No files matched your search
@@ -1,10 +1,9 @@
|
|||||||
import { TrashIcon } from '@radix-ui/react-icons';
|
import { ReloadIcon } from '@radix-ui/react-icons';
|
||||||
import { Box, Button, Flex, IconButton, Text } from '@radix-ui/themes';
|
import { Box, Flex, IconButton, Text } from '@radix-ui/themes';
|
||||||
import { times } from 'lodash';
|
import { times } from 'lodash';
|
||||||
import { use } from 'react';
|
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 { NAVBAR_HEIGHT } from '../../../../components/Navbar';
|
|
||||||
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';
|
||||||
@@ -23,19 +22,11 @@ export function FilterControl() {
|
|||||||
const filters = useTankopediaFilters();
|
const filters = useTankopediaFilters();
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Flex
|
<Flex height="fit-content" gap="2" align="start" justify="center">
|
||||||
direction={{ initial: 'row', sm: 'column' }}
|
|
||||||
height="fit-content"
|
|
||||||
gap="2"
|
|
||||||
align={{ initial: 'start', sm: 'start' }}
|
|
||||||
justify={{ initial: 'center', sm: 'start' }}
|
|
||||||
position={{ initial: 'static', sm: 'sticky' }}
|
|
||||||
style={{ top: `calc(${NAVBAR_HEIGHT}px + var(--space-3))` }}
|
|
||||||
>
|
|
||||||
<Flex
|
<Flex
|
||||||
direction={{ initial: 'row', sm: 'column' }}
|
direction={{ initial: 'row', sm: 'column' }}
|
||||||
overflow="hidden"
|
overflow="hidden"
|
||||||
style={{ borderRadius: 'var(--radius-4)' }}
|
style={{ borderRadius: 'var(--radius-5)' }}
|
||||||
>
|
>
|
||||||
<Flex direction={{ sm: 'row', initial: 'column' }}>
|
<Flex direction={{ sm: 'row', initial: 'column' }}>
|
||||||
{times(5, (index) => {
|
{times(5, (index) => {
|
||||||
@@ -51,7 +42,7 @@ export function FilterControl() {
|
|||||||
highContrast
|
highContrast
|
||||||
onClick={() =>
|
onClick={() =>
|
||||||
mutateTankopediaFilters((draft) => {
|
mutateTankopediaFilters((draft) => {
|
||||||
draft.tier = draft.tier === tier ? undefined : tier;
|
draft.tier = tier;
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
>
|
>
|
||||||
@@ -74,7 +65,7 @@ export function FilterControl() {
|
|||||||
highContrast
|
highContrast
|
||||||
onClick={() =>
|
onClick={() =>
|
||||||
mutateTankopediaFilters((draft) => {
|
mutateTankopediaFilters((draft) => {
|
||||||
draft.tier = draft.tier === tier ? undefined : tier;
|
draft.tier = tier;
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
>
|
>
|
||||||
@@ -88,7 +79,7 @@ export function FilterControl() {
|
|||||||
<Flex
|
<Flex
|
||||||
direction={{ initial: 'row', sm: 'column' }}
|
direction={{ initial: 'row', sm: 'column' }}
|
||||||
overflow="hidden"
|
overflow="hidden"
|
||||||
style={{ borderRadius: 'var(--radius-4)' }}
|
style={{ borderRadius: 'var(--radius-5)' }}
|
||||||
>
|
>
|
||||||
<Flex direction={{ sm: 'row', initial: 'column' }}>
|
<Flex direction={{ sm: 'row', initial: 'column' }}>
|
||||||
{awaitedGameDefinitions.nations
|
{awaitedGameDefinitions.nations
|
||||||
@@ -227,7 +218,7 @@ export function FilterControl() {
|
|||||||
}
|
}
|
||||||
>
|
>
|
||||||
<Text
|
<Text
|
||||||
color={filters.type === 'premium' ? undefined : 'blue'}
|
color={filters.type === 'collector' ? undefined : 'blue'}
|
||||||
style={{ display: 'flex', justifyContent: 'center' }}
|
style={{ display: 'flex', justifyContent: 'center' }}
|
||||||
>
|
>
|
||||||
<ResearchedIcon style={{ width: '1em', height: '1em' }} />
|
<ResearchedIcon style={{ width: '1em', height: '1em' }} />
|
||||||
@@ -287,10 +278,9 @@ export function FilterControl() {
|
|||||||
</IconButton>
|
</IconButton>
|
||||||
</Flex>
|
</Flex>
|
||||||
|
|
||||||
<Box display={{ initial: 'block', sm: 'none' }}>
|
<Box>
|
||||||
<IconButton
|
<IconButton
|
||||||
color="red"
|
color="red"
|
||||||
ml="2"
|
|
||||||
onClick={() =>
|
onClick={() =>
|
||||||
useTankopediaFilters.setState(
|
useTankopediaFilters.setState(
|
||||||
useTankopediaFilters.getInitialState(),
|
useTankopediaFilters.getInitialState(),
|
||||||
@@ -298,23 +288,9 @@ export function FilterControl() {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
>
|
>
|
||||||
<TrashIcon />
|
<ReloadIcon />
|
||||||
</IconButton>
|
</IconButton>
|
||||||
</Box>
|
</Box>
|
||||||
<Box display={{ initial: 'none', sm: 'block' }}>
|
|
||||||
<Button
|
|
||||||
color="red"
|
|
||||||
mt="2"
|
|
||||||
onClick={() =>
|
|
||||||
useTankopediaFilters.setState(
|
|
||||||
useTankopediaFilters.getInitialState(),
|
|
||||||
true,
|
|
||||||
)
|
|
||||||
}
|
|
||||||
>
|
|
||||||
<TrashIcon /> Clear
|
|
||||||
</Button>
|
|
||||||
</Box>
|
|
||||||
</Flex>
|
</Flex>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@@ -1,8 +1,6 @@
|
|||||||
import { Callout, Flex } from '@radix-ui/themes';
|
import { Callout, Flex } from '@radix-ui/themes';
|
||||||
import { go } from 'fuzzysort';
|
import { go } from 'fuzzysort';
|
||||||
import { range } from 'lodash';
|
|
||||||
import { memo, use, useMemo } from 'react';
|
import { memo, use, useMemo } from 'react';
|
||||||
import { Vector2Tuple } from 'three';
|
|
||||||
import { ExperimentIcon } from '../../../../components/ExperimentIcon';
|
import { ExperimentIcon } from '../../../../components/ExperimentIcon';
|
||||||
import { resolveNearPenetration } from '../../../../core/blitz/resolveNearPenetration';
|
import { resolveNearPenetration } from '../../../../core/blitz/resolveNearPenetration';
|
||||||
import { modelDefinitions } from '../../../../core/blitzkit/modelDefinitions';
|
import { modelDefinitions } from '../../../../core/blitzkit/modelDefinitions';
|
||||||
@@ -11,13 +9,13 @@ import { resolveDpm } from '../../../../core/blitzkit/resolveDpm';
|
|||||||
import { resolveReload } from '../../../../core/blitzkit/resolveReload';
|
import { resolveReload } from '../../../../core/blitzkit/resolveReload';
|
||||||
import {
|
import {
|
||||||
TankDefinition,
|
TankDefinition,
|
||||||
Tier,
|
|
||||||
tankDefinitions,
|
tankDefinitions,
|
||||||
tankNames,
|
tankNames,
|
||||||
tanksDefinitionsArray,
|
tanksDefinitionsArray,
|
||||||
} from '../../../../core/blitzkit/tankDefinitions';
|
} from '../../../../core/blitzkit/tankDefinitions';
|
||||||
import { unionBoundingBox } from '../../../../core/blitzkit/unionBoundingBox';
|
import { unionBoundingBox } from '../../../../core/blitzkit/unionBoundingBox';
|
||||||
import { useTankopediaFilters } from '../../../../stores/tankopediaFilters';
|
import { useTankopediaFilters } from '../../../../stores/tankopediaFilters';
|
||||||
|
import { FilterControl } from './FilterControl';
|
||||||
import { SearchBar } from './SearchBar';
|
import { SearchBar } from './SearchBar';
|
||||||
import { TankCard } from './TankCard';
|
import { TankCard } from './TankCard';
|
||||||
import { TankCardWrapper } from './TankCardWrapper';
|
import { TankCardWrapper } from './TankCardWrapper';
|
||||||
@@ -30,10 +28,14 @@ export const Results = memo(() => {
|
|||||||
const awaitedTankNames = use(tankNames);
|
const awaitedTankNames = use(tankNames);
|
||||||
const testing = useTankopediaFilters((state) => state.testing);
|
const testing = useTankopediaFilters((state) => state.testing);
|
||||||
const search = useTankopediaFilters((state) => state.search);
|
const search = useTankopediaFilters((state) => state.search);
|
||||||
|
const tier = useTankopediaFilters((state) => state.tier);
|
||||||
const sort = useTankopediaFilters((state) => state.sort);
|
const sort = useTankopediaFilters((state) => state.sort);
|
||||||
const searchedTanks = useMemo(() => {
|
const searchedTanks = useMemo(() => {
|
||||||
if (search !== undefined) {
|
if (search !== undefined) {
|
||||||
const searchedRaw = go(search, awaitedTankNames, { key: 'combined' });
|
const searchedRaw = go(search, awaitedTankNames, {
|
||||||
|
key: 'combined',
|
||||||
|
limit: 25,
|
||||||
|
});
|
||||||
const searchedTanks = searchedRaw.map(
|
const searchedTanks = searchedRaw.map(
|
||||||
(result) => awaitedTankDefinitions[result.obj.id],
|
(result) => awaitedTankDefinitions[result.obj.id],
|
||||||
);
|
);
|
||||||
@@ -45,10 +47,6 @@ export const Results = memo(() => {
|
|||||||
let sorted: TankDefinition[];
|
let sorted: TankDefinition[];
|
||||||
|
|
||||||
switch (sort.by) {
|
switch (sort.by) {
|
||||||
case 'meta.name':
|
|
||||||
sorted = filtered.sort((a, b) => a.name?.localeCompare(b.name));
|
|
||||||
break;
|
|
||||||
|
|
||||||
case 'survivability.health': {
|
case 'survivability.health': {
|
||||||
sorted = filtered.sort((a, b) => {
|
sorted = filtered.sort((a, b) => {
|
||||||
const aHealth = a.health + a.turrets.at(-1)!.health;
|
const aHealth = a.health + a.turrets.at(-1)!.health;
|
||||||
@@ -332,25 +330,23 @@ export const Results = memo(() => {
|
|||||||
<Flex direction="column" gap="4" flexGrow="1">
|
<Flex direction="column" gap="4" flexGrow="1">
|
||||||
<SearchBar topResult={searchedTanks?.[0]} />
|
<SearchBar topResult={searchedTanks?.[0]} />
|
||||||
|
|
||||||
|
{!search && <FilterControl />}
|
||||||
|
|
||||||
{testing === 'only' && (
|
{testing === 'only' && (
|
||||||
<Callout.Root color="amber">
|
<Flex justify="center" mt="4">
|
||||||
<Callout.Icon>
|
<Callout.Root color="amber">
|
||||||
<ExperimentIcon style={{ width: '1em', height: '1em' }} />
|
<Callout.Icon>
|
||||||
</Callout.Icon>
|
<ExperimentIcon style={{ width: '1em', height: '1em' }} />
|
||||||
<Callout.Text>
|
</Callout.Icon>
|
||||||
Tanks in testing are subject to change and many not represent the
|
<Callout.Text>
|
||||||
final product.
|
Tanks in testing are subject to change and many not represent the
|
||||||
</Callout.Text>
|
final product.
|
||||||
</Callout.Root>
|
</Callout.Text>
|
||||||
|
</Callout.Root>
|
||||||
|
</Flex>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
{!search &&
|
{!search && sort.by === 'meta.tier' && <TierCard tier={tier} />}
|
||||||
sort.by === 'meta.tier' &&
|
|
||||||
range(
|
|
||||||
...(sort.direction === 'descending'
|
|
||||||
? ([10, 0] as Vector2Tuple)
|
|
||||||
: ([1, 11] as Vector2Tuple)),
|
|
||||||
).map((tier) => <TierCard key={tier} tier={tier as Tier} />)}
|
|
||||||
|
|
||||||
{(search || sort.by !== 'meta.tier') && (
|
{(search || sort.by !== 'meta.tier') && (
|
||||||
<TankCardWrapper py="4">
|
<TankCardWrapper py="4">
|
||||||
|
|||||||
@@ -45,31 +45,32 @@ export function SearchBar({ topResult }: SearchBarProps) {
|
|||||||
);
|
);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Flex gap="2">
|
<Flex justify="center">
|
||||||
<TextField.Root
|
<Flex gap="2" flexGrow="1">
|
||||||
style={{ flex: 1 }}
|
<TextField.Root
|
||||||
ref={input}
|
style={{ flex: 1 }}
|
||||||
placeholder="Search tanks..."
|
ref={input}
|
||||||
size="3"
|
placeholder="Search tanks..."
|
||||||
onChange={handleChange}
|
onChange={handleChange}
|
||||||
onKeyDown={handleKeyDown}
|
onKeyDown={handleKeyDown}
|
||||||
>
|
>
|
||||||
<TextField.Slot>
|
|
||||||
{searching ? <Spinner /> : <MagnifyingGlassIcon />}
|
|
||||||
</TextField.Slot>
|
|
||||||
|
|
||||||
{topResult && (
|
|
||||||
<TextField.Slot>
|
<TextField.Slot>
|
||||||
<Link href={`/tools/tankopedia/${topResult.id}`}>
|
{searching ? <Spinner /> : <MagnifyingGlassIcon />}
|
||||||
<Button variant="ghost" size="3">
|
|
||||||
{topResult.name} <CaretRightIcon />
|
|
||||||
</Button>
|
|
||||||
</Link>
|
|
||||||
</TextField.Slot>
|
</TextField.Slot>
|
||||||
)}
|
|
||||||
</TextField.Root>
|
|
||||||
|
|
||||||
<Sort />
|
{topResult && (
|
||||||
|
<TextField.Slot>
|
||||||
|
<Link href={`/tools/tankopedia/${topResult.id}`}>
|
||||||
|
<Button variant="ghost">
|
||||||
|
{topResult.name} <CaretRightIcon />
|
||||||
|
</Button>
|
||||||
|
</Link>
|
||||||
|
</TextField.Slot>
|
||||||
|
)}
|
||||||
|
</TextField.Root>
|
||||||
|
|
||||||
|
<Sort />
|
||||||
|
</Flex>
|
||||||
</Flex>
|
</Flex>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@@ -12,7 +12,7 @@ export function Sort() {
|
|||||||
return (
|
return (
|
||||||
<DropdownMenu.Root modal={false}>
|
<DropdownMenu.Root modal={false}>
|
||||||
<DropdownMenu.Trigger>
|
<DropdownMenu.Trigger>
|
||||||
<Button variant="surface" size="3" color="gray">
|
<Button variant="surface" color="gray">
|
||||||
Sort
|
Sort
|
||||||
<CaretDownIcon />
|
<CaretDownIcon />
|
||||||
</Button>
|
</Button>
|
||||||
|
|||||||
@@ -1,13 +1,10 @@
|
|||||||
import { Flex, Text } from '@radix-ui/themes';
|
import { Flex, Text } from '@radix-ui/themes';
|
||||||
import { Icon } from '@radix-ui/themes/dist/cjs/components/callout';
|
import { Icon } from '@radix-ui/themes/dist/cjs/components/callout';
|
||||||
import { assignInlineVars } from '@vanilla-extract/dynamic';
|
import { assignInlineVars } from '@vanilla-extract/dynamic';
|
||||||
import { useEffect, useRef } from 'react';
|
|
||||||
import { Link } from '../../../../components/Link';
|
import { Link } from '../../../../components/Link';
|
||||||
import { asset } from '../../../../core/blitzkit/asset';
|
import { asset } from '../../../../core/blitzkit/asset';
|
||||||
import { TankDefinition } from '../../../../core/blitzkit/tankDefinitions';
|
import { TankDefinition } from '../../../../core/blitzkit/tankDefinitions';
|
||||||
import { tankIcon } from '../../../../core/blitzkit/tankIcon';
|
import { tankIcon } from '../../../../core/blitzkit/tankIcon';
|
||||||
import { tankopediaFilterTank } from '../../../../core/blitzkit/tankopediaFilterTank';
|
|
||||||
import { useTankopediaFilters } from '../../../../stores/tankopediaFilters';
|
|
||||||
import * as styles from './TankCard.css';
|
import * as styles from './TankCard.css';
|
||||||
|
|
||||||
interface TankCardProps {
|
interface TankCardProps {
|
||||||
@@ -17,7 +14,7 @@ interface TankCardProps {
|
|||||||
export function TankCard({ tank }: TankCardProps) {
|
export function TankCard({ tank }: TankCardProps) {
|
||||||
// const awaitedModelDefinitions = use(modelDefinitions);
|
// const awaitedModelDefinitions = use(modelDefinitions);
|
||||||
// const Icon = classIcons[tank.class];
|
// const Icon = classIcons[tank.class];
|
||||||
const link = useRef<HTMLAnchorElement>(null);
|
// const link = useRef<HTMLAnchorElement>(null);
|
||||||
// const sortBy = useTankopediaFilters((state) => state.sort.by);
|
// const sortBy = useTankopediaFilters((state) => state.sort.by);
|
||||||
// const discriminator = useMemo(() => {
|
// const discriminator = useMemo(() => {
|
||||||
// if (sortBy.startsWith('meta')) return undefined;
|
// if (sortBy.startsWith('meta')) return undefined;
|
||||||
@@ -46,20 +43,20 @@ export function TankCard({ tank }: TankCardProps) {
|
|||||||
// }
|
// }
|
||||||
// }, [sortBy]);
|
// }, [sortBy]);
|
||||||
|
|
||||||
useEffect(() => {
|
// useEffect(() => {
|
||||||
const unsubscribe = useTankopediaFilters.subscribe((filters) => {
|
// const unsubscribe = useTankopediaFilters.subscribe((filters) => {
|
||||||
if (!link.current) return;
|
// if (!link.current) return;
|
||||||
|
|
||||||
const visible = tankopediaFilterTank(filters, tank);
|
// const visible = tankopediaFilterTank(filters, tank);
|
||||||
link.current.style.display = visible ? 'flex' : 'none';
|
// link.current.style.display = visible ? 'flex' : 'none';
|
||||||
});
|
// });
|
||||||
|
|
||||||
return unsubscribe;
|
// return unsubscribe;
|
||||||
}, []);
|
// }, []);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Link
|
<Link
|
||||||
ref={link}
|
// ref={link}
|
||||||
size="1"
|
size="1"
|
||||||
color={
|
color={
|
||||||
tank.treeType === 'collector'
|
tank.treeType === 'collector'
|
||||||
|
|||||||
@@ -3,7 +3,6 @@ import { Grid, GridProps } from '@radix-ui/themes';
|
|||||||
export function TankCardWrapper(props: GridProps) {
|
export function TankCardWrapper(props: GridProps) {
|
||||||
return (
|
return (
|
||||||
<Grid
|
<Grid
|
||||||
flexGrow="1"
|
|
||||||
columns="repeat(auto-fill, minmax(100px, 1fr))"
|
columns="repeat(auto-fill, minmax(100px, 1fr))"
|
||||||
gap="2"
|
gap="2"
|
||||||
gapY="6"
|
gapY="6"
|
||||||
|
|||||||
@@ -1,12 +1,12 @@
|
|||||||
import { Flex, Heading, Separator } from '@radix-ui/themes';
|
import { Flex, Text } from '@radix-ui/themes';
|
||||||
import { memo, use, useEffect, useMemo, useRef } from 'react';
|
import { memo, use, useMemo } from 'react';
|
||||||
|
import { Link } from '../../../../components/Link';
|
||||||
import { TANK_CLASSES } from '../../../../components/Tanks/components/Item/constants';
|
import { TANK_CLASSES } from '../../../../components/Tanks/components/Item/constants';
|
||||||
import { gameDefinitions } from '../../../../core/blitzkit/gameDefinitions';
|
import { gameDefinitions } from '../../../../core/blitzkit/gameDefinitions';
|
||||||
import {
|
import {
|
||||||
Tier,
|
Tier,
|
||||||
tanksDefinitionsArray,
|
tanksDefinitionsArray,
|
||||||
} from '../../../../core/blitzkit/tankDefinitions';
|
} from '../../../../core/blitzkit/tankDefinitions';
|
||||||
import { TIER_ROMAN_NUMERALS } from '../../../../core/blitzkit/tankDefinitions/constants';
|
|
||||||
import { tankopediaFilterTank } from '../../../../core/blitzkit/tankopediaFilterTank';
|
import { tankopediaFilterTank } from '../../../../core/blitzkit/tankopediaFilterTank';
|
||||||
import { useTankopediaFilters } from '../../../../stores/tankopediaFilters';
|
import { useTankopediaFilters } from '../../../../stores/tankopediaFilters';
|
||||||
import { TankCard } from './TankCard';
|
import { TankCard } from './TankCard';
|
||||||
@@ -21,11 +21,11 @@ export const TierCard = memo(
|
|||||||
({ tier }: TierCardProps) => {
|
({ tier }: TierCardProps) => {
|
||||||
const awaitedGameDefinitions = use(gameDefinitions);
|
const awaitedGameDefinitions = use(gameDefinitions);
|
||||||
const awaitedTanksDefinitionsArray = use(tanksDefinitionsArray);
|
const awaitedTanksDefinitionsArray = use(tanksDefinitionsArray);
|
||||||
const container = useRef<HTMLDivElement>(null);
|
const filters = useTankopediaFilters();
|
||||||
const tanks = useMemo(
|
const tanks = useMemo(
|
||||||
() =>
|
() =>
|
||||||
awaitedTanksDefinitionsArray
|
awaitedTanksDefinitionsArray
|
||||||
.filter((tank) => tank.tier === tier)
|
.filter((tank) => tankopediaFilterTank(filters, tank))
|
||||||
.sort(
|
.sort(
|
||||||
(a, b) =>
|
(a, b) =>
|
||||||
treeTypeOrder.indexOf(a.treeType) -
|
treeTypeOrder.indexOf(a.treeType) -
|
||||||
@@ -40,41 +40,38 @@ export const TierCard = memo(
|
|||||||
awaitedGameDefinitions.nations.indexOf(a.nation) -
|
awaitedGameDefinitions.nations.indexOf(a.nation) -
|
||||||
awaitedGameDefinitions.nations.indexOf(b.nation),
|
awaitedGameDefinitions.nations.indexOf(b.nation),
|
||||||
),
|
),
|
||||||
[tier],
|
[tier, filters],
|
||||||
);
|
);
|
||||||
|
|
||||||
useEffect(() => {
|
if (tanks.length === 0)
|
||||||
const unsubscribe = useTankopediaFilters.subscribe((filters) => {
|
return (
|
||||||
if (!container.current) return;
|
<Flex flexGrow="1" align="center" justify="center">
|
||||||
|
<Text color="gray">
|
||||||
const visible = tanks.some((tank) =>
|
No tanks found.{' '}
|
||||||
tankopediaFilterTank(filters, tank),
|
<Link
|
||||||
);
|
href="#"
|
||||||
container.current.style.display = visible ? 'flex' : 'none';
|
underline="always"
|
||||||
});
|
color="red"
|
||||||
|
onClick={() =>
|
||||||
return unsubscribe;
|
useTankopediaFilters.setState(
|
||||||
}, []);
|
useTankopediaFilters.getInitialState(),
|
||||||
|
true,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
>
|
||||||
|
Try clearing filters
|
||||||
|
</Link>
|
||||||
|
.
|
||||||
|
</Text>
|
||||||
|
</Flex>
|
||||||
|
);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Flex
|
<TankCardWrapper mt="6">
|
||||||
ref={container}
|
{tanks.map((tank) => (
|
||||||
direction="column"
|
<TankCard key={tank.id} tank={tank} />
|
||||||
gap="4"
|
))}
|
||||||
display={tanks.length === 0 ? 'none' : 'flex'}
|
</TankCardWrapper>
|
||||||
py="4"
|
|
||||||
>
|
|
||||||
<Flex align="center" mb="4" gap="4">
|
|
||||||
<Heading weight="regular">Tier {TIER_ROMAN_NUMERALS[tier]}</Heading>
|
|
||||||
<Separator style={{ flex: 1 }} />
|
|
||||||
</Flex>
|
|
||||||
|
|
||||||
<TankCardWrapper>
|
|
||||||
{tanks.map((tank) => (
|
|
||||||
<TankCard key={tank.id} tank={tank} />
|
|
||||||
))}
|
|
||||||
</TankCardWrapper>
|
|
||||||
</Flex>
|
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
(prev, next) => prev.tier === next.tier,
|
(prev, next) => prev.tier === next.tier,
|
||||||
|
|||||||
@@ -0,0 +1,49 @@
|
|||||||
|
import { Flex, IconButton, Text } from '@radix-ui/themes';
|
||||||
|
import { times } from 'lodash';
|
||||||
|
import { memo } from 'react';
|
||||||
|
import { Tier } from '../../../../core/blitzkit/tankDefinitions';
|
||||||
|
import { TIER_ROMAN_NUMERALS } from '../../../../core/blitzkit/tankDefinitions/constants';
|
||||||
|
import {
|
||||||
|
mutateTankopediaFilters,
|
||||||
|
useTankopediaFilters,
|
||||||
|
} from '../../../../stores/tankopediaFilters';
|
||||||
|
|
||||||
|
export const TierFilter = memo(() => {
|
||||||
|
const tierFilter = useTankopediaFilters((state) => state.tier);
|
||||||
|
const sort = useTankopediaFilters((state) => state.sort);
|
||||||
|
const search = useTankopediaFilters((state) => state.search);
|
||||||
|
|
||||||
|
if (sort.by !== 'meta.tier' || search) return null;
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Flex justify="center">
|
||||||
|
<Flex
|
||||||
|
direction="row"
|
||||||
|
overflow="hidden"
|
||||||
|
style={{ borderRadius: 'var(--radius-full)' }}
|
||||||
|
>
|
||||||
|
{times(10, (index) => {
|
||||||
|
const tier = (10 - index) as Tier;
|
||||||
|
const selected = tierFilter === tier;
|
||||||
|
|
||||||
|
return (
|
||||||
|
<IconButton
|
||||||
|
key={tier}
|
||||||
|
variant={selected ? 'solid' : 'soft'}
|
||||||
|
radius="none"
|
||||||
|
color={selected ? undefined : 'gray'}
|
||||||
|
highContrast
|
||||||
|
onClick={() =>
|
||||||
|
mutateTankopediaFilters((draft) => {
|
||||||
|
draft.tier = tier;
|
||||||
|
})
|
||||||
|
}
|
||||||
|
>
|
||||||
|
<Text size="2">{TIER_ROMAN_NUMERALS[tier]}</Text>
|
||||||
|
</IconButton>
|
||||||
|
);
|
||||||
|
})}
|
||||||
|
</Flex>
|
||||||
|
</Flex>
|
||||||
|
);
|
||||||
|
});
|
||||||
@@ -2,14 +2,18 @@
|
|||||||
|
|
||||||
import { Flex } from '@radix-ui/themes';
|
import { Flex } from '@radix-ui/themes';
|
||||||
import PageWrapper from '../../../components/PageWrapper';
|
import PageWrapper from '../../../components/PageWrapper';
|
||||||
import { FilterControl } from './components/FilterControl';
|
|
||||||
import { Results } from './components/Results';
|
import { Results } from './components/Results';
|
||||||
|
|
||||||
export default function Page() {
|
export default function Page() {
|
||||||
return (
|
return (
|
||||||
<PageWrapper color="purple" size={1028 + 256}>
|
<PageWrapper color="purple" size={1028}>
|
||||||
<Flex gap="8" direction={{ initial: 'column', sm: 'row' }} pb="6">
|
<Flex
|
||||||
<FilterControl />
|
gap="8"
|
||||||
|
direction={{ initial: 'column', sm: 'row' }}
|
||||||
|
py="4"
|
||||||
|
flexGrow="1"
|
||||||
|
>
|
||||||
|
{/* <FilterControl /> */}
|
||||||
<Results />
|
<Results />
|
||||||
</Flex>
|
</Flex>
|
||||||
</PageWrapper>
|
</PageWrapper>
|
||||||
|
|||||||
@@ -107,7 +107,6 @@ export type ArmorPiercingLayer =
|
|||||||
|
|
||||||
export const SORT_NAMES = {
|
export const SORT_NAMES = {
|
||||||
'meta.tier': 'tier',
|
'meta.tier': 'tier',
|
||||||
'meta.name': 'name',
|
|
||||||
'survivability.health': 'health',
|
'survivability.health': 'health',
|
||||||
'survivability.viewRange': 'view range',
|
'survivability.viewRange': 'view range',
|
||||||
'survivability.camouflageStill': 'camouflage still',
|
'survivability.camouflageStill': 'camouflage still',
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ import { Tier } from '../core/blitzkit/tankDefinitions';
|
|||||||
import { TankopediaSortBy, TankopediaSortDirection } from './tankopedia';
|
import { TankopediaSortBy, TankopediaSortDirection } from './tankopedia';
|
||||||
|
|
||||||
export interface TankopediaFilters {
|
export interface TankopediaFilters {
|
||||||
tier?: Tier;
|
tier: Tier;
|
||||||
nation?: string;
|
nation?: string;
|
||||||
class?: TankClass;
|
class?: TankClass;
|
||||||
type?: TreeType;
|
type?: TreeType;
|
||||||
@@ -23,6 +23,7 @@ export const useTankopediaFilters = create<TankopediaFilters>()(() => ({
|
|||||||
by: 'meta.tier',
|
by: 'meta.tier',
|
||||||
direction: 'descending',
|
direction: 'descending',
|
||||||
},
|
},
|
||||||
|
tier: 10,
|
||||||
}));
|
}));
|
||||||
|
|
||||||
export function mutateTankopediaFilters(
|
export function mutateTankopediaFilters(
|
||||||
|
|||||||
Reference in new issue
Block a user