feat: multi-select

This commit is contained in:
TrèsAbhi committed 2024-07-02 19:30:29 -05:00
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;
}) })
} }
> >
+14
View File
@@ -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))
);
}
-17
View File
@@ -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))
);
}
+27
View File
@@ -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));
}
-25
View File
@@ -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));
}