feat: cleaner filters

This commit is contained in:
TrèsAbhi committed 2023-12-06 12:40:43 -06:00
1 parent b804e60bac
commit 84a1af8100
5 files changed
+388 -185

No files matched your search

@@ -0,0 +1,17 @@
import { style } from '@vanilla-extract/css';
export const splitFilters = style({
'@media': {
'screen and (min-width: 513px)': {
display: 'none',
},
},
});
export const oneLineFilters = style({
'@media': {
'screen and (max-width: 512px)': {
display: 'none',
},
},
});
@@ -9,19 +9,18 @@ import {
TREE_TYPE_ICONS,
TREE_TYPE_IMAGES,
TreeTypeEnum,
} from '../../../../components/Tanks';
import { asset } from '../../../../core/blitzkrieg/asset';
} from '../../../../../components/Tanks';
import { asset } from '../../../../../core/blitzkrieg/asset';
import {
NATIONS,
TIERS,
TIER_ROMAN_NUMERALS,
} from '../../../../core/blitzkrieg/definitions/tanks';
} from '../../../../../core/blitzkrieg/definitions/tanks';
import mutateTankopedia, {
TankopediaSortBy,
TankopediaSortDirection,
TankopediaTestTankDisplay,
useTankopedia,
} from '../../../../stores/tankopedia';
} from '../../../../../stores/tankopedia';
import * as styles from './index.css';
export function Options() {
const nations = use(NATIONS);
@@ -29,55 +28,22 @@ export function Options() {
return (
<Flex justify="center" wrap="wrap" gap="2">
<Flex gap="1">
<DropdownMenu.Root>
<DropdownMenu.Trigger>
<Button variant="soft">
Sort by
<CaretDownIcon />
</Button>
</DropdownMenu.Trigger>
<DropdownMenu.Content>
<DropdownMenu.RadioGroup
value={tankopediaState.sort.by}
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.Root>
<DropdownMenu.Root>
<DropdownMenu.Trigger>
<Button variant="soft">
Sort order
<CaretDownIcon />
</Button>
</DropdownMenu.Trigger>
<DropdownMenu.Content>
<DropdownMenu.RadioGroup
value={tankopediaState.sort.direction}
onValueChange={(value) =>
mutateTankopedia((draft) => {
draft.sort.direction = value as TankopediaSortDirection;
})
}
>
<DropdownMenu.RadioItem value="ascending">
Ascending
</DropdownMenu.RadioItem>
<DropdownMenu.RadioItem value="descending">
Descending
</DropdownMenu.RadioItem>
</DropdownMenu.RadioGroup>
</DropdownMenu.Content>
</DropdownMenu.Root>
</Flex>
<Button
color="red"
onClick={() =>
useTankopedia.setState({
filters: {
nations: [],
tiers: [],
treeTypes: [],
types: [],
test: 'include',
},
})
}
>
Clear
</Button>
<DropdownMenu.Root>
<DropdownMenu.Trigger>
@@ -106,39 +72,46 @@ export function Options() {
</DropdownMenu.Content>
</DropdownMenu.Root>
<Flex>
{[...TIERS].reverse().map((tier, index) => (
<Flex style={{ flex: 1 }}>
{TREE_TYPES.map((type, index) => (
<Button
key={tier}
key={type}
variant={
tankopediaState.filters.tiers.includes(tier) ? 'solid' : 'soft'
tankopediaState.filters.treeTypes.includes(type)
? 'solid'
: 'soft'
}
style={{
flex: 1,
margin: -0.5,
borderTopLeftRadius: index === 0 ? undefined : 0,
borderBottomLeftRadius: index === 0 ? undefined : 0,
borderTopRightRadius: index === TIERS.length - 1 ? undefined : 0,
borderTopRightRadius:
index === TREE_TYPES.length - 1 ? undefined : 0,
borderBottomRightRadius:
index === TIERS.length - 1 ? undefined : 0,
index === TREE_TYPES.length - 1 ? undefined : 0,
}}
onClick={() =>
mutateTankopedia((draft) => {
if (draft.filters.tiers.includes(tier)) {
draft.filters.tiers = draft.filters.tiers.filter(
(preexistingTier) => preexistingTier !== tier,
if (draft.filters.treeTypes.includes(type)) {
draft.filters.treeTypes = draft.filters.treeTypes.filter(
(preexistingType) => preexistingType !== type,
);
} else {
draft.filters.tiers.push(tier);
draft.filters.treeTypes.push(type);
}
})
}
>
{TIER_ROMAN_NUMERALS[tier]}
<img
src={TREE_TYPE_IMAGES[type]}
style={{ width: '1em', height: '1em' }}
/>
</Button>
))}
</Flex>
<Flex>
<Flex style={{ flex: 1 }}>
{[...TANK_TYPES].reverse().map((type, index) => (
<Button
key={type}
@@ -146,6 +119,7 @@ export function Options() {
tankopediaState.filters.types.includes(type) ? 'solid' : 'soft'
}
style={{
flex: 1,
margin: -0.5,
borderTopLeftRadius: index === 0 ? undefined : 0,
borderBottomLeftRadius: index === 0 ? undefined : 0,
@@ -174,7 +148,40 @@ export function Options() {
))}
</Flex>
<Flex>
<Flex className={styles.oneLineFilters} style={{ flex: 1 }}>
{[...TIERS].reverse().map((tier, index) => (
<Button
key={tier}
variant={
tankopediaState.filters.tiers.includes(tier) ? 'solid' : 'soft'
}
style={{
flex: 1,
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 className={styles.oneLineFilters} style={{ flex: 1 }}>
{nations.map((nation, index) => (
<Button
key={nation}
@@ -184,6 +191,7 @@ export function Options() {
: 'soft'
}
style={{
flex: 1,
margin: -0.5,
borderTopLeftRadius: index === 0 ? undefined : 0,
borderBottomLeftRadius: index === 0 ? undefined : 0,
@@ -217,60 +225,181 @@ export function Options() {
))}
</Flex>
<Flex>
{TREE_TYPES.map((type, index) => (
<Button
key={type}
variant={
tankopediaState.filters.treeTypes.includes(type)
? 'solid'
: 'soft'
}
style={{
margin: -0.5,
borderTopLeftRadius: index === 0 ? undefined : 0,
borderBottomLeftRadius: index === 0 ? undefined : 0,
borderTopRightRadius:
index === TREE_TYPES.length - 1 ? undefined : 0,
borderBottomRightRadius:
index === TREE_TYPES.length - 1 ? undefined : 0,
}}
onClick={() =>
mutateTankopedia((draft) => {
if (draft.filters.treeTypes.includes(type)) {
draft.filters.treeTypes = draft.filters.treeTypes.filter(
(preexistingType) => preexistingType !== type,
);
} else {
draft.filters.treeTypes.push(type);
<Flex
direction="column"
className={styles.splitFilters}
style={{ width: '100%' }}
>
<Flex>
{[...TIERS]
.reverse()
.slice(0, 5)
.map((tier, index) => (
<Button
key={tier}
variant={
tankopediaState.filters.tiers.includes(tier)
? 'solid'
: 'soft'
}
})
}
>
<img
src={TREE_TYPE_IMAGES[type]}
style={{ width: '1em', height: '1em' }}
/>
</Button>
))}
style={{
flex: 1,
margin: -0.5,
borderTopLeftRadius: index === 0 ? undefined : 0,
borderBottomLeftRadius: 0,
borderTopRightRadius:
index === TIERS.length - 6 ? undefined : 0,
borderBottomRightRadius: 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>
{[...TIERS]
.reverse()
.slice(5, 10)
.map((tier, index) => (
<Button
key={tier}
variant={
tankopediaState.filters.tiers.includes(tier)
? 'solid'
: 'soft'
}
style={{
flex: 1,
margin: -0.5,
borderTopLeftRadius: 0,
borderBottomLeftRadius: index === 0 ? undefined : 0,
borderTopRightRadius: 0,
borderBottomRightRadius:
index === TIERS.length - 6 ? 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>
<Button
color="red"
onClick={() =>
useTankopedia.setState({
filters: {
nations: [],
tiers: [],
treeTypes: [],
types: [],
test: 'include',
},
})
}
<Flex
direction="column"
className={styles.splitFilters}
style={{ width: '100%' }}
>
Clear
</Button>
<Flex>
{nations.slice(0, 5).map((nation, index) => (
<Button
key={nation}
variant={
tankopediaState.filters.nations.includes(nation)
? 'solid'
: 'soft'
}
style={{
flex: 1,
margin: -0.5,
borderTopLeftRadius: index === 0 ? undefined : 0,
borderBottomLeftRadius: 0,
borderTopRightRadius:
index === nations.length - 5 ? undefined : 0,
borderBottomRightRadius:
index === nations.length - 1 ? undefined : 0,
}}
onClick={() =>
mutateTankopedia((draft) => {
if (draft.filters.nations.includes(nation)) {
draft.filters.nations = draft.filters.nations.filter(
(preexistingType) => preexistingType !== nation,
);
} else {
draft.filters.nations.push(nation);
}
})
}
>
<img
src={asset(`flags/circle/${nation}.webp`)}
style={{
width: '1em',
height: '1em',
scale: 2,
transform: 'translate(15%, 15%)',
}}
/>
</Button>
))}
</Flex>
<Flex>
{nations.slice(5, 10).map((nation, index) => (
<Button
key={nation}
variant={
tankopediaState.filters.nations.includes(nation)
? 'solid'
: 'soft'
}
style={{
flex: 1,
margin: -0.5,
borderTopLeftRadius: 0,
borderBottomLeftRadius: index === 0 ? undefined : 0,
borderTopRightRadius:
index === nations.length - 1 ? undefined : 0,
borderBottomRightRadius:
index === nations.length - 6 ? undefined : 0,
}}
onClick={() =>
mutateTankopedia((draft) => {
if (draft.filters.nations.includes(nation)) {
draft.filters.nations = draft.filters.nations.filter(
(preexistingType) => preexistingType !== nation,
);
} else {
draft.filters.nations.push(nation);
}
})
}
>
<img
src={asset(`flags/circle/${nation}.webp`)}
style={{
width: '1em',
height: '1em',
scale: 2,
transform: 'translate(15%, 15%)',
}}
/>
</Button>
))}
</Flex>
</Flex>
</Flex>
);
}
+94 -27
View File
@@ -1,8 +1,16 @@
'use client';
import { slateDark } from '@radix-ui/colors';
import { MagnifyingGlassIcon } from '@radix-ui/react-icons';
import { Card, Flex, Inset, Text, TextField } from '@radix-ui/themes';
import { CaretDownIcon, MagnifyingGlassIcon } from '@radix-ui/react-icons';
import {
Button,
Card,
DropdownMenu,
Flex,
Inset,
Text,
TextField,
} from '@radix-ui/themes';
import { go } from 'fuzzysort';
import { Suspense, use, useEffect, useMemo, useRef, useState } from 'react';
import PageWrapper from '../../../components/PageWrapper';
@@ -17,7 +25,12 @@ import {
} from '../../../core/blitzkrieg/definitions/tanks';
import { tankIcon } from '../../../core/blitzkrieg/tankIcon';
import { theme } from '../../../stitches.config';
import { useTankopedia } from '../../../stores/tankopedia';
import mutateTankopedia, {
TankopediaSortBy,
TankopediaSortDirection,
TankopediaTestTankDisplay,
useTankopedia,
} from '../../../stores/tankopedia';
import { Options } from './components/Options';
import { PageTurner } from './components/PageTurner';
import * as styles from './page.css';
@@ -90,30 +103,79 @@ export default function Page() {
<PageWrapper size="wide" color="purple">
<Suspense fallback={<Text>Loading...</Text>}>
<Flex direction="column" gap="6">
<TextField.Root>
<TextField.Slot>
<MagnifyingGlassIcon height="16" width="16" />
</TextField.Slot>
<TextField.Input
ref={input}
placeholder="Search tanks..."
onChange={(event) => {
if (event.target.value.length === 0) {
setSearchedList(searchableTanks);
} else {
setSearchedList(
go(event.target.value, searchableTanks, {
keys: [
'name',
'name_short',
'id',
] satisfies (keyof TankDefinition)[],
}).map(({ obj }) => obj),
);
}
}}
/>
</TextField.Root>
<Flex gap="2">
<TextField.Root style={{ flex: 1 }}>
<TextField.Slot>
<MagnifyingGlassIcon height="16" width="16" />
</TextField.Slot>
<TextField.Input
ref={input}
placeholder="Search tanks..."
onChange={(event) => {
if (event.target.value.length === 0) {
setSearchedList(searchableTanks);
} else {
setSearchedList(
go(event.target.value, searchableTanks, {
keys: [
'name',
'name_short',
'id',
] satisfies (keyof TankDefinition)[],
}).map(({ obj }) => obj),
);
}
}}
/>
</TextField.Root>
<DropdownMenu.Root>
<DropdownMenu.Trigger>
<Button variant="soft">
Sort
<CaretDownIcon />
</Button>
</DropdownMenu.Trigger>
<DropdownMenu.Content>
<DropdownMenu.Label>By</DropdownMenu.Label>
<DropdownMenu.RadioGroup
value={tankopediaState.sort.by}
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.Separator />
<DropdownMenu.Label>Direction</DropdownMenu.Label>
<DropdownMenu.RadioGroup
value={tankopediaState.sort.direction}
onValueChange={(value) =>
mutateTankopedia((draft) => {
draft.sort.direction = value as TankopediaSortDirection;
})
}
>
<DropdownMenu.RadioItem value="ascending">
Ascending
</DropdownMenu.RadioItem>
<DropdownMenu.RadioItem value="descending">
Descending
</DropdownMenu.RadioItem>
</DropdownMenu.RadioGroup>
</DropdownMenu.Content>
</DropdownMenu.Root>
</Flex>
<Options />
@@ -222,6 +284,11 @@ export default function Page() {
tank.tree_type === 'researchable'
? slateDark.slate12
: undefined,
whiteSpace: 'nowrap',
maxWidth: 160,
display: 'block',
textOverflow: 'ellipsis',
overflow: 'hidden',
}}
>
{tank.name_short ??
+17 -19
View File
@@ -1,6 +1,6 @@
import { produce } from 'immer';
import { create } from 'zustand';
import { devtools, persist } from 'zustand/middleware';
import { persist } from 'zustand/middleware';
import { CustomColumnDisplay } from '../app/tools/session/components/CustomColumn';
import { AccentColor, GrayColor } from '../constants/radixColors';
import { Region } from '../constants/regions';
@@ -65,25 +65,23 @@ export function resetSession() {
}
export const useSession = create<Session>()(
devtools(
persist(
(set) => ({
isTracking: false,
resetPrompt: true,
showTotal: true,
showCareer: true,
embedPrompt: true,
persist(
(set) => ({
isTracking: false,
resetPrompt: true,
showTotal: true,
showCareer: true,
embedPrompt: true,
customColumns: [
{ display: 'battles', showDelta: false },
{ display: 'winrate', showDelta: true },
{ display: 'wn8', showDelta: false },
{ display: 'damage', showDelta: true },
],
color: 'slate',
}),
{ name: 'session' },
),
customColumns: [
{ display: 'battles', showDelta: false },
{ display: 'winrate', showDelta: true },
{ display: 'wn8', showDelta: false },
{ display: 'damage', showDelta: true },
],
color: 'slate',
}),
{ name: 'session' },
),
);
+13 -21
View File
@@ -1,6 +1,5 @@
import { produce } from 'immer';
import { create } from 'zustand';
import { devtools, persist } from 'zustand/middleware';
import { TankType, TreeTypeString } from '../components/Tanks';
import { Tier } from '../core/blitzkrieg/definitions/tanks';
@@ -22,26 +21,19 @@ type Tankopedia = {
};
};
export const useTankopedia = create<Tankopedia>()(
devtools(
persist(
(set) => ({
sort: {
by: 'tier',
direction: 'descending',
},
filters: {
tiers: [],
types: [],
treeTypes: [],
nations: [],
test: 'include',
},
}),
{ name: 'tankopedia' },
),
),
);
export const useTankopedia = create<Tankopedia>()(() => ({
sort: {
by: 'tier',
direction: 'descending',
},
filters: {
tiers: [],
types: [],
treeTypes: [],
nations: [],
test: 'include',
},
}));
export default function mutateTankopedia(recipe: (draft: Tankopedia) => void) {
useTankopedia.setState(produce(recipe));