mirror of
https://github.com/blitzkit/blitzkit.git
synced 2026-10-23 19:49:50 +02:00
feat: tier filters
This commit is contained in:
1 parent
5b4601b671
commit
7020e5641f
4 files changed
+127
-70
No files matched your search
@@ -3,6 +3,10 @@
|
|||||||
import { CaretDownIcon } from '@radix-ui/react-icons';
|
import { CaretDownIcon } from '@radix-ui/react-icons';
|
||||||
import { Button, DropdownMenu, Flex } from '@radix-ui/themes';
|
import { Button, DropdownMenu, Flex } from '@radix-ui/themes';
|
||||||
import {
|
import {
|
||||||
|
TIERS,
|
||||||
|
TIER_ROMAN_NUMERALS,
|
||||||
|
} from '../../../../core/blitzkrieg/tankopedia';
|
||||||
|
import mutateTankopedia, {
|
||||||
TankopediaSortBy,
|
TankopediaSortBy,
|
||||||
TankopediaSortDirection,
|
TankopediaSortDirection,
|
||||||
useTankopedia,
|
useTankopedia,
|
||||||
@@ -12,52 +16,90 @@ export function Options() {
|
|||||||
const tankopediaState = useTankopedia();
|
const tankopediaState = useTankopedia();
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Flex gap="1">
|
<Flex justify="between">
|
||||||
<DropdownMenu.Root>
|
<Flex gap="1">
|
||||||
<DropdownMenu.Trigger>
|
<DropdownMenu.Root>
|
||||||
<Button variant="soft">
|
<DropdownMenu.Trigger>
|
||||||
Sort by
|
<Button variant="soft">
|
||||||
<CaretDownIcon />
|
Sort by
|
||||||
</Button>
|
<CaretDownIcon />
|
||||||
</DropdownMenu.Trigger>
|
</Button>
|
||||||
<DropdownMenu.Content>
|
</DropdownMenu.Trigger>
|
||||||
<DropdownMenu.RadioGroup
|
<DropdownMenu.Content>
|
||||||
value={tankopediaState.sortBy}
|
<DropdownMenu.RadioGroup
|
||||||
onValueChange={(value) =>
|
value={tankopediaState.sort.by}
|
||||||
useTankopedia.setState({ sortBy: value as TankopediaSortBy })
|
onValueChange={(value) =>
|
||||||
}
|
mutateTankopedia((draft) => {
|
||||||
>
|
draft.sort.by = value as TankopediaSortBy;
|
||||||
<DropdownMenu.RadioItem value="tier">Tier</DropdownMenu.RadioItem>
|
})
|
||||||
<DropdownMenu.RadioItem value="name">Name</DropdownMenu.RadioItem>
|
}
|
||||||
</DropdownMenu.RadioGroup>
|
>
|
||||||
</DropdownMenu.Content>
|
<DropdownMenu.RadioItem value="tier">Tier</DropdownMenu.RadioItem>
|
||||||
</DropdownMenu.Root>
|
<DropdownMenu.RadioItem value="name">Name</DropdownMenu.RadioItem>
|
||||||
|
</DropdownMenu.RadioGroup>
|
||||||
|
</DropdownMenu.Content>
|
||||||
|
</DropdownMenu.Root>
|
||||||
|
|
||||||
<DropdownMenu.Root>
|
<DropdownMenu.Root>
|
||||||
<DropdownMenu.Trigger>
|
<DropdownMenu.Trigger>
|
||||||
<Button variant="soft">
|
<Button variant="soft">
|
||||||
Sort order
|
Sort order
|
||||||
<CaretDownIcon />
|
<CaretDownIcon />
|
||||||
</Button>
|
</Button>
|
||||||
</DropdownMenu.Trigger>
|
</DropdownMenu.Trigger>
|
||||||
<DropdownMenu.Content>
|
<DropdownMenu.Content>
|
||||||
<DropdownMenu.RadioGroup
|
<DropdownMenu.RadioGroup
|
||||||
value={tankopediaState.sortDirection}
|
value={tankopediaState.sort.direction}
|
||||||
onValueChange={(value) =>
|
onValueChange={(value) =>
|
||||||
useTankopedia.setState({
|
mutateTankopedia((draft) => {
|
||||||
sortDirection: value as TankopediaSortDirection,
|
draft.sort.direction = value as TankopediaSortDirection;
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
>
|
>
|
||||||
<DropdownMenu.RadioItem value="ascending">
|
<DropdownMenu.RadioItem value="ascending">
|
||||||
Ascending
|
Ascending
|
||||||
</DropdownMenu.RadioItem>
|
</DropdownMenu.RadioItem>
|
||||||
<DropdownMenu.RadioItem value="descending">
|
<DropdownMenu.RadioItem value="descending">
|
||||||
Descending
|
Descending
|
||||||
</DropdownMenu.RadioItem>
|
</DropdownMenu.RadioItem>
|
||||||
</DropdownMenu.RadioGroup>
|
</DropdownMenu.RadioGroup>
|
||||||
</DropdownMenu.Content>
|
</DropdownMenu.Content>
|
||||||
</DropdownMenu.Root>
|
</DropdownMenu.Root>
|
||||||
|
</Flex>
|
||||||
|
|
||||||
|
<Flex gap="1">
|
||||||
|
<Flex>
|
||||||
|
{TIERS.toReversed().map((tier, index) => (
|
||||||
|
<Button
|
||||||
|
variant={
|
||||||
|
tankopediaState.filters.tiers.includes(tier) ? 'solid' : 'soft'
|
||||||
|
}
|
||||||
|
style={{
|
||||||
|
margin: -0.5,
|
||||||
|
borderTopLeftRadius: index === 0 ? undefined : 0,
|
||||||
|
borderBottomLeftRadius: index === 0 ? undefined : 0,
|
||||||
|
borderTopRightRadius:
|
||||||
|
index === TIERS.length - 1 ? undefined : 0,
|
||||||
|
borderBottomRightRadius:
|
||||||
|
index === TIERS.length - 1 ? undefined : 0,
|
||||||
|
}}
|
||||||
|
onClick={() =>
|
||||||
|
mutateTankopedia((draft) => {
|
||||||
|
if (draft.filters.tiers.includes(tier)) {
|
||||||
|
draft.filters.tiers = draft.filters.tiers.filter(
|
||||||
|
(preexistingTier) => preexistingTier !== tier,
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
draft.filters.tiers.push(tier);
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
>
|
||||||
|
{TIER_ROMAN_NUMERALS[tier]}
|
||||||
|
</Button>
|
||||||
|
))}
|
||||||
|
</Flex>
|
||||||
|
</Flex>
|
||||||
</Flex>
|
</Flex>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@@ -30,34 +30,36 @@ export default function Page() {
|
|||||||
const tankopediaState = useTankopedia();
|
const tankopediaState = useTankopedia();
|
||||||
const awaitedTanks = use(tanks);
|
const awaitedTanks = use(tanks);
|
||||||
const input = useRef<HTMLInputElement>(null);
|
const input = useRef<HTMLInputElement>(null);
|
||||||
const sortedTanks = useMemo(
|
const searchableTanks = useMemo(
|
||||||
() =>
|
() =>
|
||||||
awaitedTanks.toSorted((a, b) => {
|
awaitedTanks
|
||||||
let diff = 0;
|
.filter((tank) => tankopediaState.filters.tiers.includes(tank.tier))
|
||||||
|
.toSorted((a, b) => {
|
||||||
|
let diff = 0;
|
||||||
|
|
||||||
if (tankopediaState.sortBy === 'tier') {
|
if (tankopediaState.sort.by === 'tier') {
|
||||||
diff = a.tier - b.tier;
|
diff = a.tier - b.tier;
|
||||||
}
|
}
|
||||||
if (tankopediaState.sortBy === 'name') {
|
if (tankopediaState.sort.by === 'name') {
|
||||||
diff = (
|
diff = (
|
||||||
a.name_short ??
|
a.name_short ??
|
||||||
a.name ??
|
a.name ??
|
||||||
`Unknown tank ${a.id}`
|
`Unknown tank ${a.id}`
|
||||||
).localeCompare(b.name_short ?? b.name ?? `Unknown tank ${b.id}`);
|
).localeCompare(b.name_short ?? b.name ?? `Unknown tank ${b.id}`);
|
||||||
}
|
}
|
||||||
|
|
||||||
return tankopediaState.sortDirection === 'ascending' ? diff : -diff;
|
return tankopediaState.sort.direction === 'ascending' ? diff : -diff;
|
||||||
}),
|
}),
|
||||||
[tankopediaState.sortBy, tankopediaState.sortDirection],
|
[tankopediaState.filters, tankopediaState.sort],
|
||||||
);
|
);
|
||||||
const [searchedList, setSearchedList] = useState(sortedTanks);
|
const [searchedList, setSearchedList] = useState(searchableTanks);
|
||||||
const [page, setPage] = useState(0);
|
const [page, setPage] = useState(0);
|
||||||
const pageInput = useRef<HTMLInputElement>(null);
|
const pageInput = useRef<HTMLInputElement>(null);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
setSearchedList(sortedTanks);
|
setSearchedList(searchableTanks);
|
||||||
if (input.current) input.current.value = '';
|
if (input.current) input.current.value = '';
|
||||||
}, [sortedTanks]);
|
}, [searchableTanks]);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (pageInput.current) pageInput.current.value = `${page + 1}`;
|
if (pageInput.current) pageInput.current.value = `${page + 1}`;
|
||||||
@@ -84,10 +86,10 @@ export default function Page() {
|
|||||||
placeholder="Search tanks..."
|
placeholder="Search tanks..."
|
||||||
onChange={(event) => {
|
onChange={(event) => {
|
||||||
if (event.target.value.length === 0) {
|
if (event.target.value.length === 0) {
|
||||||
setSearchedList(sortedTanks);
|
setSearchedList(searchableTanks);
|
||||||
} else {
|
} else {
|
||||||
setSearchedList(
|
setSearchedList(
|
||||||
go(event.target.value, sortedTanks, {
|
go(event.target.value, searchableTanks, {
|
||||||
keys: [
|
keys: [
|
||||||
'name',
|
'name',
|
||||||
'name_short',
|
'name_short',
|
||||||
|
|||||||
@@ -84,6 +84,8 @@ export const TANK_ICONS_COLLECTOR: Record<TankType, string> = {
|
|||||||
|
|
||||||
export type Tier = 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10;
|
export type Tier = 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10;
|
||||||
|
|
||||||
|
export const TIERS: Tier[] = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
|
||||||
|
|
||||||
export const TIER_ROMAN_NUMERALS: Record<Tier, string> = {
|
export const TIER_ROMAN_NUMERALS: Record<Tier, string> = {
|
||||||
1: 'I',
|
1: 'I',
|
||||||
2: 'II',
|
2: 'II',
|
||||||
|
|||||||
@@ -1,21 +1,32 @@
|
|||||||
import { produce } from 'immer';
|
import { produce } from 'immer';
|
||||||
import { create } from 'zustand';
|
import { create } from 'zustand';
|
||||||
import { devtools, persist } from 'zustand/middleware';
|
import { devtools, persist } from 'zustand/middleware';
|
||||||
|
import { TIERS, Tier } from '../core/blitzkrieg/tankopedia';
|
||||||
|
|
||||||
export type TankopediaSortBy = 'tier' | 'name';
|
export type TankopediaSortBy = 'tier' | 'name';
|
||||||
export type TankopediaSortDirection = 'ascending' | 'descending';
|
export type TankopediaSortDirection = 'ascending' | 'descending';
|
||||||
|
|
||||||
type Tankopedia = {
|
type Tankopedia = {
|
||||||
sortBy: TankopediaSortBy;
|
sort: {
|
||||||
sortDirection: TankopediaSortDirection;
|
by: TankopediaSortBy;
|
||||||
|
direction: TankopediaSortDirection;
|
||||||
|
};
|
||||||
|
filters: {
|
||||||
|
tiers: Tier[];
|
||||||
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
export const useTankopedia = create<Tankopedia>()(
|
export const useTankopedia = create<Tankopedia>()(
|
||||||
devtools(
|
devtools(
|
||||||
persist(
|
persist(
|
||||||
(set) => ({
|
(set) => ({
|
||||||
sortBy: 'tier',
|
sort: {
|
||||||
sortDirection: 'descending',
|
by: 'tier',
|
||||||
|
direction: 'descending',
|
||||||
|
},
|
||||||
|
filters: {
|
||||||
|
tiers: [...TIERS],
|
||||||
|
},
|
||||||
}),
|
}),
|
||||||
{ name: 'tankopedia' },
|
{ name: 'tankopedia' },
|
||||||
),
|
),
|
||||||
|
|||||||
Reference in new issue
Block a user