mirror of
https://github.com/blitzkit/blitzkit.git
synced 2026-10-28 13:09:51 +01:00
feat: multi-select
This commit is contained in:
1 parent
3542cb1ece
commit
ac243a3cdd
11 files changed
+142
-115
No files matched your search
@@ -3,9 +3,9 @@
|
|||||||
import { Table } from '@radix-ui/themes';
|
import { Table } from '@radix-ui/themes';
|
||||||
import { Suspense, use, useMemo } from 'react';
|
import { Suspense, use, useMemo } from 'react';
|
||||||
import { averageDefinitionsArray } from '../../../../core/blitzkit/averageDefinitions';
|
import { averageDefinitionsArray } from '../../../../core/blitzkit/averageDefinitions';
|
||||||
|
import { filterTank } from '../../../../core/blitzkit/filterTank';
|
||||||
import { tankDefinitions } from '../../../../core/blitzkit/tankDefinitions';
|
import { tankDefinitions } from '../../../../core/blitzkit/tankDefinitions';
|
||||||
import { tankopediaFilterTank } from '../../../../core/blitzkit/tankopediaFilterTank';
|
import { useTankFilters } from '../../../../stores/tankFilters';
|
||||||
import { useTankopediaFilters } from '../../../../stores/tankopediaFilters';
|
|
||||||
import { useTankPerformanceSort } from '../../../../stores/tankPerformanceSort';
|
import { useTankPerformanceSort } from '../../../../stores/tankPerformanceSort';
|
||||||
import { RowLoader } from './RowLoader';
|
import { RowLoader } from './RowLoader';
|
||||||
import { TankRow } from './TankRow';
|
import { TankRow } from './TankRow';
|
||||||
@@ -13,7 +13,7 @@ import { TankRow } from './TankRow';
|
|||||||
export function Tanks() {
|
export function Tanks() {
|
||||||
const awaitedTankDefinitions = use(tankDefinitions);
|
const awaitedTankDefinitions = use(tankDefinitions);
|
||||||
const awaitedAverageDefinitionsArray = use(averageDefinitionsArray);
|
const awaitedAverageDefinitionsArray = use(averageDefinitionsArray);
|
||||||
const filters = useTankopediaFilters();
|
const filters = useTankFilters();
|
||||||
const sort = useTankPerformanceSort();
|
const sort = useTankPerformanceSort();
|
||||||
const tanksSorted = useMemo(() => {
|
const tanksSorted = useMemo(() => {
|
||||||
switch (sort.type) {
|
switch (sort.type) {
|
||||||
@@ -106,7 +106,7 @@ export function Tanks() {
|
|||||||
}, [sort]);
|
}, [sort]);
|
||||||
const tanks = useMemo(() => {
|
const tanks = useMemo(() => {
|
||||||
return tanksSorted.filter((tank) =>
|
return tanksSorted.filter((tank) =>
|
||||||
tankopediaFilterTank(filters, awaitedTankDefinitions[tank.id]),
|
filterTank(filters, awaitedTankDefinitions[tank.id]),
|
||||||
);
|
);
|
||||||
}, [filters, tanksSorted]);
|
}, [filters, tanksSorted]);
|
||||||
|
|
||||||
|
|||||||
@@ -15,9 +15,9 @@ import { gameDefinitions } from '../../../../core/blitzkit/gameDefinitions';
|
|||||||
import { Tier } from '../../../../core/blitzkit/tankDefinitions';
|
import { Tier } from '../../../../core/blitzkit/tankDefinitions';
|
||||||
import { TIER_ROMAN_NUMERALS } from '../../../../core/blitzkit/tankDefinitions/constants';
|
import { TIER_ROMAN_NUMERALS } from '../../../../core/blitzkit/tankDefinitions/constants';
|
||||||
import {
|
import {
|
||||||
mutateTankopediaFilters,
|
mutateTankFilters,
|
||||||
useTankopediaFilters,
|
useTankFilters,
|
||||||
} from '../../../../stores/tankopediaFilters';
|
} from '../../../../stores/tankFilters';
|
||||||
|
|
||||||
interface FilterControlProps {
|
interface FilterControlProps {
|
||||||
compact?: boolean;
|
compact?: boolean;
|
||||||
@@ -25,7 +25,7 @@ interface FilterControlProps {
|
|||||||
|
|
||||||
export function FilterControl({ compact }: FilterControlProps) {
|
export function FilterControl({ compact }: FilterControlProps) {
|
||||||
const awaitedGameDefinitions = use(gameDefinitions);
|
const awaitedGameDefinitions = use(gameDefinitions);
|
||||||
const filters = useTankopediaFilters();
|
const filters = useTankFilters();
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Flex height="fit-content" gap="2" align="start" justify="center">
|
<Flex height="fit-content" gap="2" align="start" justify="center">
|
||||||
@@ -37,7 +37,7 @@ export function FilterControl({ compact }: FilterControlProps) {
|
|||||||
<Flex direction={compact ? 'column' : { sm: 'row', initial: 'column' }}>
|
<Flex direction={compact ? 'column' : { sm: 'row', initial: 'column' }}>
|
||||||
{times(5, (index) => {
|
{times(5, (index) => {
|
||||||
const tier = (index + 1) as Tier;
|
const tier = (index + 1) as Tier;
|
||||||
const selected = filters.tier === tier;
|
const selected = filters.tiers?.includes(tier);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<IconButton
|
<IconButton
|
||||||
@@ -47,8 +47,12 @@ export function FilterControl({ compact }: FilterControlProps) {
|
|||||||
color={selected ? undefined : 'gray'}
|
color={selected ? undefined : 'gray'}
|
||||||
highContrast
|
highContrast
|
||||||
onClick={() =>
|
onClick={() =>
|
||||||
mutateTankopediaFilters((draft) => {
|
mutateTankFilters((draft) => {
|
||||||
draft.tier = draft.tier === tier ? undefined : tier;
|
if (draft.tiers?.includes(tier)) {
|
||||||
|
draft.tiers = draft.tiers?.filter((t) => t !== tier);
|
||||||
|
} else {
|
||||||
|
draft.tiers = [...(draft.tiers ?? []), tier];
|
||||||
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
>
|
>
|
||||||
@@ -60,7 +64,7 @@ export function FilterControl({ compact }: FilterControlProps) {
|
|||||||
<Flex direction={compact ? 'column' : { sm: 'row', initial: 'column' }}>
|
<Flex direction={compact ? 'column' : { sm: 'row', initial: 'column' }}>
|
||||||
{times(5, (index) => {
|
{times(5, (index) => {
|
||||||
const tier = (index + 6) as Tier;
|
const tier = (index + 6) as Tier;
|
||||||
const selected = filters.tier === tier;
|
const selected = filters.tiers?.includes(tier);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<IconButton
|
<IconButton
|
||||||
@@ -70,8 +74,12 @@ export function FilterControl({ compact }: FilterControlProps) {
|
|||||||
color={selected ? undefined : 'gray'}
|
color={selected ? undefined : 'gray'}
|
||||||
highContrast
|
highContrast
|
||||||
onClick={() =>
|
onClick={() =>
|
||||||
mutateTankopediaFilters((draft) => {
|
mutateTankFilters((draft) => {
|
||||||
draft.tier = draft.tier === tier ? undefined : tier;
|
if (draft.tiers?.includes(tier)) {
|
||||||
|
draft.tiers = draft.tiers?.filter((t) => t !== tier);
|
||||||
|
} else {
|
||||||
|
draft.tiers = [...(draft.tiers ?? []), tier];
|
||||||
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
>
|
>
|
||||||
@@ -91,7 +99,7 @@ export function FilterControl({ compact }: FilterControlProps) {
|
|||||||
{awaitedGameDefinitions.nations
|
{awaitedGameDefinitions.nations
|
||||||
.slice(0, Math.ceil(awaitedGameDefinitions.nations.length / 2))
|
.slice(0, Math.ceil(awaitedGameDefinitions.nations.length / 2))
|
||||||
.map((nation) => {
|
.map((nation) => {
|
||||||
const selected = filters.nation === nation;
|
const selected = filters.nations?.includes(nation);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<IconButton
|
<IconButton
|
||||||
@@ -101,9 +109,14 @@ export function FilterControl({ compact }: FilterControlProps) {
|
|||||||
highContrast
|
highContrast
|
||||||
radius="none"
|
radius="none"
|
||||||
onClick={() =>
|
onClick={() =>
|
||||||
mutateTankopediaFilters((draft) => {
|
mutateTankFilters((draft) => {
|
||||||
draft.nation =
|
if (draft.nations?.includes(nation)) {
|
||||||
draft.nation === nation ? undefined : nation;
|
draft.nations = draft.nations?.filter(
|
||||||
|
(n) => n !== nation,
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
draft.nations = [...(draft.nations ?? []), nation];
|
||||||
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
>
|
>
|
||||||
@@ -119,7 +132,7 @@ export function FilterControl({ compact }: FilterControlProps) {
|
|||||||
{awaitedGameDefinitions.nations
|
{awaitedGameDefinitions.nations
|
||||||
.slice(Math.ceil(awaitedGameDefinitions.nations.length / 2))
|
.slice(Math.ceil(awaitedGameDefinitions.nations.length / 2))
|
||||||
.map((nation) => {
|
.map((nation) => {
|
||||||
const selected = filters.nation === nation;
|
const selected = filters.nations?.includes(nation);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<IconButton
|
<IconButton
|
||||||
@@ -130,9 +143,14 @@ export function FilterControl({ compact }: FilterControlProps) {
|
|||||||
highContrast
|
highContrast
|
||||||
radius="none"
|
radius="none"
|
||||||
onClick={() =>
|
onClick={() =>
|
||||||
mutateTankopediaFilters((draft) => {
|
mutateTankFilters((draft) => {
|
||||||
draft.nation =
|
if (draft.nations?.includes(nation)) {
|
||||||
draft.nation === nation ? undefined : nation;
|
draft.nations = draft.nations?.filter(
|
||||||
|
(n) => n !== nation,
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
draft.nations = [...(draft.nations ?? []), nation];
|
||||||
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
>
|
>
|
||||||
@@ -153,7 +171,7 @@ export function FilterControl({ compact }: FilterControlProps) {
|
|||||||
>
|
>
|
||||||
{TANK_CLASSES.map((tankClass) => {
|
{TANK_CLASSES.map((tankClass) => {
|
||||||
const Icon = classIcons[tankClass];
|
const Icon = classIcons[tankClass];
|
||||||
const selected = filters.class === tankClass;
|
const selected = filters.classes?.includes(tankClass);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<IconButton
|
<IconButton
|
||||||
@@ -163,9 +181,14 @@ export function FilterControl({ compact }: FilterControlProps) {
|
|||||||
color={selected ? undefined : 'gray'}
|
color={selected ? undefined : 'gray'}
|
||||||
highContrast
|
highContrast
|
||||||
onClick={() =>
|
onClick={() =>
|
||||||
mutateTankopediaFilters((draft) => {
|
mutateTankFilters((draft) => {
|
||||||
draft.class =
|
if (draft.classes?.includes(tankClass)) {
|
||||||
draft.class === tankClass ? undefined : tankClass;
|
draft.classes = draft.classes?.filter(
|
||||||
|
(c) => c !== tankClass,
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
draft.classes = [...(draft.classes ?? []), tankClass];
|
||||||
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
>
|
>
|
||||||
@@ -181,50 +204,61 @@ export function FilterControl({ compact }: FilterControlProps) {
|
|||||||
direction={compact ? 'column' : { sm: 'row', initial: 'column' }}
|
direction={compact ? 'column' : { sm: 'row', initial: 'column' }}
|
||||||
>
|
>
|
||||||
<IconButton
|
<IconButton
|
||||||
variant={filters.type === 'researchable' ? 'solid' : 'soft'}
|
variant={filters.types?.includes('researchable') ? 'solid' : 'soft'}
|
||||||
radius="none"
|
radius="none"
|
||||||
color={filters.type === 'researchable' ? undefined : 'gray'}
|
color={filters.types?.includes('researchable') ? undefined : 'gray'}
|
||||||
highContrast
|
highContrast
|
||||||
onClick={() =>
|
onClick={() =>
|
||||||
mutateTankopediaFilters((draft) => {
|
mutateTankFilters((draft) => {
|
||||||
draft.type =
|
if (draft.types?.includes('researchable')) {
|
||||||
draft.type === 'researchable' ? undefined : 'researchable';
|
draft.types = draft.types?.filter((t) => t !== 'researchable');
|
||||||
|
} else {
|
||||||
|
draft.types = [...(draft.types ?? []), 'researchable'];
|
||||||
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
>
|
>
|
||||||
<ResearchedIcon style={{ width: '1em', height: '1em' }} />
|
<ResearchedIcon style={{ width: '1em', height: '1em' }} />
|
||||||
</IconButton>
|
</IconButton>
|
||||||
<IconButton
|
<IconButton
|
||||||
variant={filters.type === 'premium' ? 'solid' : 'soft'}
|
variant={filters.types?.includes('premium') ? 'solid' : 'soft'}
|
||||||
radius="none"
|
radius="none"
|
||||||
color={filters.type === 'premium' ? 'amber' : 'gray'}
|
color={filters.types?.includes('premium') ? 'amber' : 'gray'}
|
||||||
highContrast
|
highContrast
|
||||||
onClick={() =>
|
onClick={() =>
|
||||||
mutateTankopediaFilters((draft) => {
|
mutateTankFilters((draft) => {
|
||||||
draft.type = draft.type === 'premium' ? undefined : 'premium';
|
if (draft.types?.includes('premium')) {
|
||||||
|
draft.types = draft.types?.filter((t) => t !== 'premium');
|
||||||
|
} else {
|
||||||
|
draft.types = [...(draft.types ?? []), 'premium'];
|
||||||
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
>
|
>
|
||||||
<Text
|
<Text
|
||||||
color={filters.type === 'premium' ? undefined : 'amber'}
|
color={filters.types?.includes('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
|
<IconButton
|
||||||
variant={filters.type === 'collector' ? 'solid' : 'soft'}
|
variant={filters.types?.includes('collector') ? 'solid' : 'soft'}
|
||||||
radius="none"
|
radius="none"
|
||||||
color={filters.type === 'collector' ? 'blue' : 'gray'}
|
color={filters.types?.includes('collector') ? 'blue' : 'gray'}
|
||||||
highContrast
|
highContrast
|
||||||
onClick={() =>
|
onClick={() =>
|
||||||
mutateTankopediaFilters((draft) => {
|
mutateTankFilters((draft) => {
|
||||||
draft.type = draft.type === 'collector' ? undefined : 'collector';
|
if (draft.types?.includes('collector')) {
|
||||||
|
draft.types = draft.types?.filter((t) => t !== 'collector');
|
||||||
|
} else {
|
||||||
|
draft.types = [...(draft.types ?? []), 'collector'];
|
||||||
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
>
|
>
|
||||||
<Text
|
<Text
|
||||||
color={filters.type === 'collector' ? undefined : 'blue'}
|
color={filters.types?.includes('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' }} />
|
||||||
@@ -243,7 +277,7 @@ export function FilterControl({ compact }: FilterControlProps) {
|
|||||||
color={filters.testing === 'include' ? undefined : 'gray'}
|
color={filters.testing === 'include' ? undefined : 'gray'}
|
||||||
highContrast
|
highContrast
|
||||||
onClick={() =>
|
onClick={() =>
|
||||||
mutateTankopediaFilters((draft) => {
|
mutateTankFilters((draft) => {
|
||||||
draft.testing = 'include';
|
draft.testing = 'include';
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
@@ -258,7 +292,7 @@ export function FilterControl({ compact }: FilterControlProps) {
|
|||||||
color={filters.testing === 'exclude' ? undefined : 'gray'}
|
color={filters.testing === 'exclude' ? undefined : 'gray'}
|
||||||
highContrast
|
highContrast
|
||||||
onClick={() =>
|
onClick={() =>
|
||||||
mutateTankopediaFilters((draft) => {
|
mutateTankFilters((draft) => {
|
||||||
draft.testing = 'exclude';
|
draft.testing = 'exclude';
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
@@ -273,7 +307,7 @@ export function FilterControl({ compact }: FilterControlProps) {
|
|||||||
color={filters.testing === 'only' ? undefined : 'gray'}
|
color={filters.testing === 'only' ? undefined : 'gray'}
|
||||||
highContrast
|
highContrast
|
||||||
onClick={() =>
|
onClick={() =>
|
||||||
mutateTankopediaFilters((draft) => {
|
mutateTankFilters((draft) => {
|
||||||
draft.testing = 'only';
|
draft.testing = 'only';
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
@@ -288,10 +322,7 @@ export function FilterControl({ compact }: FilterControlProps) {
|
|||||||
<IconButton
|
<IconButton
|
||||||
color="red"
|
color="red"
|
||||||
onClick={() =>
|
onClick={() =>
|
||||||
useTankopediaFilters.setState(
|
useTankFilters.setState(useTankFilters.getInitialState(), true)
|
||||||
useTankopediaFilters.getInitialState(),
|
|
||||||
true,
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
>
|
>
|
||||||
<ReloadIcon />
|
<ReloadIcon />
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import { Flex, Link, Text } from '@radix-ui/themes';
|
import { Flex, Link, Text } from '@radix-ui/themes';
|
||||||
import { useTankopediaFilters } from '../../../../stores/tankopediaFilters';
|
import { useTankFilters } from '../../../../stores/tankFilters';
|
||||||
|
|
||||||
interface NoResultsProps {
|
interface NoResultsProps {
|
||||||
type?: 'filters' | 'search';
|
type?: 'filters' | 'search';
|
||||||
@@ -15,10 +15,7 @@ export function NoResults({ type = 'filters' }: NoResultsProps) {
|
|||||||
underline="always"
|
underline="always"
|
||||||
color="red"
|
color="red"
|
||||||
onClick={() =>
|
onClick={() =>
|
||||||
useTankopediaFilters.setState(
|
useTankFilters.setState(useTankFilters.getInitialState(), true)
|
||||||
useTankopediaFilters.getInitialState(),
|
|
||||||
true,
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
>
|
>
|
||||||
{type === 'filters' ? 'Try clearing filters' : 'Try searching again'}
|
{type === 'filters' ? 'Try clearing filters' : 'Try searching again'}
|
||||||
|
|||||||
@@ -1,15 +1,15 @@
|
|||||||
import { CaretRightIcon } from '@radix-ui/react-icons';
|
import { CaretRightIcon } from '@radix-ui/react-icons';
|
||||||
import { Button, Link, TextField } from '@radix-ui/themes';
|
import { Button, Link, TextField } from '@radix-ui/themes';
|
||||||
import { TankDefinition } from '../../../../core/blitzkit/tankDefinitions';
|
import { TankDefinition } from '../../../../core/blitzkit/tankDefinitions';
|
||||||
import { useTankopediaFilters } from '../../../../stores/tankopediaFilters';
|
import { useTankFilters } from '../../../../stores/tankFilters';
|
||||||
|
|
||||||
interface QuickLinkProps {
|
interface QuickLinkProps {
|
||||||
topResult?: TankDefinition;
|
topResult?: TankDefinition;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function QuickLink({ topResult }: QuickLinkProps) {
|
export function QuickLink({ topResult }: QuickLinkProps) {
|
||||||
const search = useTankopediaFilters((state) => state.search);
|
const search = useTankFilters((state) => state.search);
|
||||||
const searching = useTankopediaFilters((state) => state.searching);
|
const searching = useTankFilters((state) => state.searching);
|
||||||
|
|
||||||
if (!search || !topResult || searching) return null;
|
if (!search || !topResult || searching) return null;
|
||||||
|
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ import { debounce } from 'lodash';
|
|||||||
import { useRouter } from 'next/navigation';
|
import { useRouter } from 'next/navigation';
|
||||||
import { KeyboardEventHandler, useCallback, useRef } from 'react';
|
import { KeyboardEventHandler, useCallback, useRef } from 'react';
|
||||||
import { TankDefinition } from '../../../../core/blitzkit/tankDefinitions';
|
import { TankDefinition } from '../../../../core/blitzkit/tankDefinitions';
|
||||||
import { useTankopediaFilters } from '../../../../stores/tankopediaFilters';
|
import { useTankFilters } from '../../../../stores/tankFilters';
|
||||||
import { QuickLink } from './QuickLink';
|
import { QuickLink } from './QuickLink';
|
||||||
import { Sort } from './Sort';
|
import { Sort } from './Sort';
|
||||||
|
|
||||||
@@ -16,24 +16,24 @@ interface SearchBarProps {
|
|||||||
export function SearchBar({ topResult, onSelect }: SearchBarProps) {
|
export function SearchBar({ topResult, onSelect }: SearchBarProps) {
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
const input = useRef<HTMLInputElement>(null);
|
const input = useRef<HTMLInputElement>(null);
|
||||||
const searching = useTankopediaFilters((state) => state.searching);
|
const searching = useTankFilters((state) => state.searching);
|
||||||
const performSearch = useCallback(
|
const performSearch = useCallback(
|
||||||
debounce(() => {
|
debounce(() => {
|
||||||
useTankopediaFilters.setState({ searching: false });
|
useTankFilters.setState({ searching: false });
|
||||||
|
|
||||||
if (!input.current) return;
|
if (!input.current) return;
|
||||||
|
|
||||||
const sanitized = input.current.value.trim();
|
const sanitized = input.current.value.trim();
|
||||||
|
|
||||||
useTankopediaFilters.setState({
|
useTankFilters.setState({
|
||||||
search: sanitized.length === 0 ? undefined : sanitized,
|
search: sanitized.length === 0 ? undefined : sanitized,
|
||||||
});
|
});
|
||||||
}, 500),
|
}, 500),
|
||||||
[],
|
[],
|
||||||
);
|
);
|
||||||
const handleChange = useCallback(() => {
|
const handleChange = useCallback(() => {
|
||||||
if (!useTankopediaFilters.getState().searching) {
|
if (!useTankFilters.getState().searching) {
|
||||||
useTankopediaFilters.setState({ searching: true });
|
useTankFilters.setState({ searching: true });
|
||||||
}
|
}
|
||||||
|
|
||||||
performSearch();
|
performSearch();
|
||||||
|
|||||||
@@ -6,6 +6,7 @@ import { AdMidSectionResponsive } from '../../../../../components/AdMidSectionRe
|
|||||||
import { ExperimentIcon } from '../../../../../components/ExperimentIcon';
|
import { ExperimentIcon } from '../../../../../components/ExperimentIcon';
|
||||||
import { TANK_CLASSES } from '../../../../../components/Tanks/components/Item/constants';
|
import { TANK_CLASSES } from '../../../../../components/Tanks/components/Item/constants';
|
||||||
import { resolveNearPenetration } from '../../../../../core/blitz/resolveNearPenetration';
|
import { resolveNearPenetration } from '../../../../../core/blitz/resolveNearPenetration';
|
||||||
|
import { filterTank } from '../../../../../core/blitzkit/filterTank';
|
||||||
import { gameDefinitions } from '../../../../../core/blitzkit/gameDefinitions';
|
import { gameDefinitions } from '../../../../../core/blitzkit/gameDefinitions';
|
||||||
import { modelDefinitions } from '../../../../../core/blitzkit/modelDefinitions';
|
import { modelDefinitions } from '../../../../../core/blitzkit/modelDefinitions';
|
||||||
import { normalizeBoundingBox } from '../../../../../core/blitzkit/normalizeBoundingBox';
|
import { normalizeBoundingBox } from '../../../../../core/blitzkit/normalizeBoundingBox';
|
||||||
@@ -17,11 +18,10 @@ import {
|
|||||||
tankNames,
|
tankNames,
|
||||||
tanksDefinitionsArray,
|
tanksDefinitionsArray,
|
||||||
} from '../../../../../core/blitzkit/tankDefinitions';
|
} from '../../../../../core/blitzkit/tankDefinitions';
|
||||||
import { tankopediaFilterTank } from '../../../../../core/blitzkit/tankopediaFilterTank';
|
|
||||||
import { unionBoundingBox } from '../../../../../core/blitzkit/unionBoundingBox';
|
import { unionBoundingBox } from '../../../../../core/blitzkit/unionBoundingBox';
|
||||||
import { useAdExempt } from '../../../../../hooks/useAdExempt';
|
import { useAdExempt } from '../../../../../hooks/useAdExempt';
|
||||||
|
import { useTankFilters } from '../../../../../stores/tankFilters';
|
||||||
import { SORT_NAMES, SORT_UNITS } from '../../../../../stores/tankopedia';
|
import { SORT_NAMES, SORT_UNITS } from '../../../../../stores/tankopedia';
|
||||||
import { useTankopediaFilters } from '../../../../../stores/tankopediaFilters';
|
|
||||||
import { useTankopediaSort } from '../../../../../stores/tankopediaSort';
|
import { useTankopediaSort } from '../../../../../stores/tankopediaSort';
|
||||||
import { FilterControl } from '../FilterControl';
|
import { FilterControl } from '../FilterControl';
|
||||||
import { NoResults } from '../NoResults';
|
import { NoResults } from '../NoResults';
|
||||||
@@ -45,12 +45,12 @@ export const TankSearch = memo<TankSearchProps>(
|
|||||||
const awaitedTankDefinitions = use(tankDefinitions);
|
const awaitedTankDefinitions = use(tankDefinitions);
|
||||||
const awaitedTanksDefinitionsArray = use(tanksDefinitionsArray);
|
const awaitedTanksDefinitionsArray = use(tanksDefinitionsArray);
|
||||||
const awaitedTankNames = use(tankNames);
|
const awaitedTankNames = use(tankNames);
|
||||||
const filters = useTankopediaFilters();
|
const filters = useTankFilters();
|
||||||
const sort = useTankopediaSort();
|
const sort = useTankopediaSort();
|
||||||
const tanks = useMemo(() => {
|
const tanks = useMemo(() => {
|
||||||
if (filters.search === undefined) {
|
if (filters.search === undefined) {
|
||||||
const filtered = awaitedTanksDefinitionsArray.filter((tank) =>
|
const filtered = awaitedTanksDefinitionsArray.filter((tank) =>
|
||||||
tankopediaFilterTank(filters, tank),
|
filterTank(filters, tank),
|
||||||
);
|
);
|
||||||
let sorted: TankDefinition[];
|
let sorted: TankDefinition[];
|
||||||
|
|
||||||
|
|||||||
@@ -4,15 +4,15 @@ import { memo } from 'react';
|
|||||||
import { Tier } from '../../../../core/blitzkit/tankDefinitions';
|
import { Tier } from '../../../../core/blitzkit/tankDefinitions';
|
||||||
import { TIER_ROMAN_NUMERALS } from '../../../../core/blitzkit/tankDefinitions/constants';
|
import { TIER_ROMAN_NUMERALS } from '../../../../core/blitzkit/tankDefinitions/constants';
|
||||||
import {
|
import {
|
||||||
mutateTankopediaFilters,
|
mutateTankFilters,
|
||||||
useTankopediaFilters,
|
useTankFilters,
|
||||||
} from '../../../../stores/tankopediaFilters';
|
} from '../../../../stores/tankFilters';
|
||||||
import { useTankopediaSort } from '../../../../stores/tankopediaSort';
|
import { useTankopediaSort } from '../../../../stores/tankopediaSort';
|
||||||
|
|
||||||
export const TierFilter = memo(() => {
|
export const TierFilter = memo(() => {
|
||||||
const tierFilter = useTankopediaFilters((state) => state.tier);
|
const tierFilter = useTankFilters((state) => state.tiers);
|
||||||
const sort = useTankopediaSort();
|
const sort = useTankopediaSort();
|
||||||
const search = useTankopediaFilters((state) => state.search);
|
const search = useTankFilters((state) => state.search);
|
||||||
|
|
||||||
if (sort.by !== 'meta.none' || search) return null;
|
if (sort.by !== 'meta.none' || search) return null;
|
||||||
|
|
||||||
@@ -35,8 +35,8 @@ export const TierFilter = memo(() => {
|
|||||||
color={selected ? undefined : 'gray'}
|
color={selected ? undefined : 'gray'}
|
||||||
highContrast
|
highContrast
|
||||||
onClick={() =>
|
onClick={() =>
|
||||||
mutateTankopediaFilters((draft) => {
|
mutateTankFilters((draft) => {
|
||||||
draft.tier = tier;
|
draft.tiers = tier;
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
>
|
>
|
||||||
|
|||||||
@@ -0,0 +1,14 @@
|
|||||||
|
import { TankFilters } from '../../stores/tankFilters';
|
||||||
|
import { TankDefinition } from './tankDefinitions';
|
||||||
|
|
||||||
|
export function filterTank(filters: TankFilters, tank: TankDefinition) {
|
||||||
|
return (
|
||||||
|
(filters.tiers.length === 0 || filters.tiers.includes(tank.tier)) &&
|
||||||
|
(filters.nations.length === 0 || filters.nations.includes(tank.nation)) &&
|
||||||
|
(filters.classes.length === 0 || filters.classes.includes(tank.class)) &&
|
||||||
|
(filters.types.length === 0 || filters.types.includes(tank.treeType)) &&
|
||||||
|
(filters.testing === 'include' ||
|
||||||
|
(filters.testing === 'only' && tank.testing) ||
|
||||||
|
(filters.testing === 'exclude' && !tank.testing))
|
||||||
|
);
|
||||||
|
}
|
||||||
@@ -1,17 +0,0 @@
|
|||||||
import { TankopediaFilters } from '../../stores/tankopediaFilters';
|
|
||||||
import { TankDefinition } from './tankDefinitions';
|
|
||||||
|
|
||||||
export function tankopediaFilterTank(
|
|
||||||
filters: TankopediaFilters,
|
|
||||||
tank: TankDefinition,
|
|
||||||
) {
|
|
||||||
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))
|
|
||||||
);
|
|
||||||
}
|
|
||||||
@@ -0,0 +1,27 @@
|
|||||||
|
import { produce } from 'immer';
|
||||||
|
import { create } from 'zustand';
|
||||||
|
import { TankClass, TreeType } from '../components/Tanks';
|
||||||
|
import { Tier } from '../core/blitzkit/tankDefinitions';
|
||||||
|
|
||||||
|
export interface TankFilters {
|
||||||
|
tiers: Tier[];
|
||||||
|
nations: string[];
|
||||||
|
classes: TankClass[];
|
||||||
|
types: TreeType[];
|
||||||
|
testing: 'include' | 'exclude' | 'only';
|
||||||
|
search?: string;
|
||||||
|
searching: boolean;
|
||||||
|
}
|
||||||
|
|
||||||
|
export const useTankFilters = create<TankFilters>()(() => ({
|
||||||
|
testing: 'include',
|
||||||
|
searching: false,
|
||||||
|
classes: [],
|
||||||
|
nations: [],
|
||||||
|
tiers: [],
|
||||||
|
types: [],
|
||||||
|
}));
|
||||||
|
|
||||||
|
export function mutateTankFilters(recipe: (draft: TankFilters) => void) {
|
||||||
|
useTankFilters.setState(produce(recipe));
|
||||||
|
}
|
||||||
@@ -1,25 +0,0 @@
|
|||||||
import { produce } from 'immer';
|
|
||||||
import { create } from 'zustand';
|
|
||||||
import { TankClass, TreeType } from '../components/Tanks';
|
|
||||||
import { Tier } from '../core/blitzkit/tankDefinitions';
|
|
||||||
|
|
||||||
export interface TankopediaFilters {
|
|
||||||
tier?: Tier;
|
|
||||||
nation?: string;
|
|
||||||
class?: TankClass;
|
|
||||||
type?: TreeType;
|
|
||||||
testing: 'include' | 'exclude' | 'only';
|
|
||||||
search?: string;
|
|
||||||
searching: boolean;
|
|
||||||
}
|
|
||||||
|
|
||||||
export const useTankopediaFilters = create<TankopediaFilters>()(() => ({
|
|
||||||
testing: 'include',
|
|
||||||
searching: false,
|
|
||||||
}));
|
|
||||||
|
|
||||||
export function mutateTankopediaFilters(
|
|
||||||
recipe: (draft: TankopediaFilters) => void,
|
|
||||||
) {
|
|
||||||
useTankopediaFilters.setState(produce(recipe));
|
|
||||||
}
|
|
||||||
Reference in new issue
Block a user