feat: simpler filter ui

This commit is contained in:
TrèsAbhi committed 2024-02-06 15:10:54 -06:00
1 parent ed8a1c2f57
commit 4fb0aa3936
3 files changed
+279 -284

No files matched your search

@@ -26,274 +26,110 @@ export function Options() {
const filters = useTankopediaPersistent((state) => state.filters);
return (
<Flex justify="center" direction="column" gap="2">
<Flex gap="2" style={{ flex: 1 }} wrap="wrap">
<Button
color="red"
onClick={() =>
useTankopediaPersistent.setState({
filters: {
nations: [],
tiers: [],
treeTypes: [],
types: [],
test: 'include',
page: 0,
},
})
}
>
Reset
</Button>
<DropdownMenu.Root>
<DropdownMenu.Trigger>
<Button variant="soft" color="gray">
Test tanks
<CaretDownIcon />
</Button>
</DropdownMenu.Trigger>
<DropdownMenu.Content>
<DropdownMenu.RadioGroup
value={filters.test}
onValueChange={(value) =>
mutateTankopediaPersistent((draft) => {
draft.filters.test = value as TankopediaTestTankDisplay;
})
}
>
<DropdownMenu.RadioItem value="include">
Include
</DropdownMenu.RadioItem>
<DropdownMenu.RadioItem value="exclude">
Exclude
</DropdownMenu.RadioItem>
<DropdownMenu.RadioItem value="only">Only</DropdownMenu.RadioItem>
</DropdownMenu.RadioGroup>
</DropdownMenu.Content>
</DropdownMenu.Root>
<Flex style={{ flex: 1 }}>
{TREE_TYPES.map((type, index) => (
<Button
key={type}
color={filters.treeTypes.includes(type) ? undefined : 'gray'}
variant={filters.treeTypes.includes(type) ? 'surface' : 'soft'}
style={{
flex: 1,
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={() =>
mutateTankopediaPersistent((draft) => {
if (draft.filters.treeTypes.includes(type)) {
draft.filters.treeTypes = draft.filters.treeTypes.filter(
(preexistingType) => preexistingType !== type,
);
} else {
draft.filters.treeTypes.push(type);
}
})
}
>
<img
src={TREE_TYPE_IMAGES[type]}
style={{ width: '1em', height: '1em' }}
/>
</Button>
))}
</Flex>
<Flex style={{ flex: 1 }}>
{[...TANK_TYPES].map((type, index) => (
<Button
key={type}
color={filters.types.includes(type) ? undefined : 'gray'}
variant={filters.types.includes(type) ? 'surface' : 'soft'}
style={{
flex: 1,
margin: -0.5,
borderTopLeftRadius: index === 0 ? undefined : 0,
borderBottomLeftRadius: index === 0 ? undefined : 0,
borderTopRightRadius:
index === TANK_TYPES.length - 1 ? undefined : 0,
borderBottomRightRadius:
index === TANK_TYPES.length - 1 ? undefined : 0,
}}
onClick={() =>
mutateTankopediaPersistent((draft) => {
if (draft.filters.types.includes(type)) {
draft.filters.types = draft.filters.types.filter(
(preexistingType) => preexistingType !== type,
);
} else {
draft.filters.types.push(type);
}
})
}
>
<img
src={TREE_TYPE_ICONS.researchable[type]}
style={{ width: '1em', height: '1em' }}
/>
</Button>
))}
</Flex>
<Flex
direction="column"
className={styles.splitFilters}
style={{ width: '100%' }}
>
<Flex>
{[...TIERS].slice(0, 5).map((tier, index) => (
<Button
key={tier}
color={filters.tiers.includes(tier) ? undefined : 'gray'}
variant={filters.tiers.includes(tier) ? 'surface' : 'soft'}
style={{
flex: 1,
margin: -0.5,
borderTopLeftRadius: index === 0 ? 16 : 0,
borderBottomLeftRadius: 0,
borderTopRightRadius:
index === TIERS.length - Math.round(TIERS.length / 2) - 1
? 16
: 0,
borderBottomRightRadius: 0,
}}
onClick={() =>
mutateTankopediaPersistent((draft) => {
if (draft.filters.tiers.includes(tier)) {
draft.filters.tiers = draft.filters.tiers.filter(
(preexistingTier) => preexistingTier !== tier,
);
} else {
draft.filters.tiers.push(tier);
}
})
<Flex gap="2" wrap="wrap" justify="center">
<DropdownMenu.Root>
<DropdownMenu.Trigger>
<Button variant="soft" color="gray">
Test tanks
<CaretDownIcon />
</Button>
</DropdownMenu.Trigger>
<DropdownMenu.Content>
<DropdownMenu.RadioGroup
value={filters.test}
onValueChange={(value) =>
mutateTankopediaPersistent((draft) => {
draft.filters.test = value as TankopediaTestTankDisplay;
})
}
>
<DropdownMenu.RadioItem value="include">
Include
</DropdownMenu.RadioItem>
<DropdownMenu.RadioItem value="exclude">
Exclude
</DropdownMenu.RadioItem>
<DropdownMenu.RadioItem value="only">Only</DropdownMenu.RadioItem>
</DropdownMenu.RadioGroup>
</DropdownMenu.Content>
</DropdownMenu.Root>
<Flex>
{TREE_TYPES.map((type, index) => (
<Button
key={type}
color={filters.treeTypes.includes(type) ? undefined : 'gray'}
variant={filters.treeTypes.includes(type) ? 'surface' : 'soft'}
style={{
flex: 1,
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={() =>
mutateTankopediaPersistent((draft) => {
if (draft.filters.treeTypes.includes(type)) {
draft.filters.treeTypes = draft.filters.treeTypes.filter(
(preexistingType) => preexistingType !== type,
);
} else {
draft.filters.treeTypes.push(type);
}
>
{TIER_ROMAN_NUMERALS[tier]}
</Button>
))}
</Flex>
<Flex>
{[...TIERS].slice(5).map((tier, index) => (
<Button
key={tier}
color={filters.tiers.includes(tier) ? undefined : 'gray'}
variant={filters.tiers.includes(tier) ? 'surface' : 'soft'}
style={{
flex: 1,
margin: -0.5,
borderTopLeftRadius: 0,
borderBottomLeftRadius: index === 0 ? 16 : 0,
borderTopRightRadius: 0,
borderBottomRightRadius:
index === TIERS.length - Math.round(TIERS.length / 2) - 1
? 16
: 0,
}}
onClick={() =>
mutateTankopediaPersistent((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
direction="column"
className={styles.splitFilters}
style={{ width: '100%' }}
>
<Flex>
{nations.slice(0, 5).map((nation, index) => (
<Button
key={nation}
color={filters.nations.includes(nation) ? undefined : 'gray'}
variant={filters.nations.includes(nation) ? 'surface' : 'soft'}
style={{
flex: 1,
margin: -0.5,
borderTopLeftRadius: index === 0 ? 16 : 0,
borderBottomLeftRadius: 0,
borderTopRightRadius:
index === nations.length - Math.round(nations.length / 2)
? 16
: 0,
borderBottomRightRadius:
index === nations.length - 1 ? undefined : 0,
}}
onClick={() =>
mutateTankopediaPersistent((draft) => {
if (draft.filters.nations.includes(nation)) {
draft.filters.nations = draft.filters.nations.filter(
(preexistingType) => preexistingType !== nation,
);
} else {
draft.filters.nations.push(nation);
}
})
}
>
<Flag nation={nation} />
</Button>
))}
</Flex>
<Flex>
{nations.slice(5).map((nation, index) => (
<Button
key={nation}
color={filters.nations.includes(nation) ? undefined : 'gray'}
variant={filters.nations.includes(nation) ? 'surface' : 'soft'}
style={{
flex: 1,
margin: -0.5,
borderTopLeftRadius: 0,
borderBottomLeftRadius: index === 0 ? 16 : 0,
borderTopRightRadius:
index === nations.length - 1 ? undefined : 0,
borderBottomRightRadius:
index ===
nations.length - Math.round(nations.length / 2) - 1
? 16
: 0,
}}
onClick={() =>
mutateTankopediaPersistent((draft) => {
if (draft.filters.nations.includes(nation)) {
draft.filters.nations = draft.filters.nations.filter(
(preexistingType) => preexistingType !== nation,
);
} else {
draft.filters.nations.push(nation);
}
})
}
>
<Flag nation={nation} />
</Button>
))}
</Flex>
</Flex>
})
}
>
<img
src={TREE_TYPE_IMAGES[type]}
style={{ width: '1em', height: '1em' }}
/>
</Button>
))}
</Flex>
<Flex gap="2" style={{ flex: 1 }} wrap="wrap">
<Flex className={styles.oneLineFilters} style={{ flex: 1 }}>
{[...TIERS].map((tier, index) => (
<Flex>
{[...TANK_TYPES].map((type, index) => (
<Button
key={type}
color={filters.types.includes(type) ? undefined : 'gray'}
variant={filters.types.includes(type) ? 'surface' : 'soft'}
style={{
flex: 1,
margin: -0.5,
borderTopLeftRadius: index === 0 ? undefined : 0,
borderBottomLeftRadius: index === 0 ? undefined : 0,
borderTopRightRadius:
index === TANK_TYPES.length - 1 ? undefined : 0,
borderBottomRightRadius:
index === TANK_TYPES.length - 1 ? undefined : 0,
}}
onClick={() =>
mutateTankopediaPersistent((draft) => {
if (draft.filters.types.includes(type)) {
draft.filters.types = draft.filters.types.filter(
(preexistingType) => preexistingType !== type,
);
} else {
draft.filters.types.push(type);
}
})
}
>
<img
src={TREE_TYPE_ICONS.researchable[type]}
style={{ width: '1em', height: '1em' }}
/>
</Button>
))}
</Flex>
<Flex
direction="column"
className={styles.splitFilters}
style={{ width: '100%' }}
>
<Flex>
{[...TIERS].slice(0, 5).map((tier, index) => (
<Button
key={tier}
color={filters.tiers.includes(tier) ? undefined : 'gray'}
@@ -301,12 +137,13 @@ export function Options() {
style={{
flex: 1,
margin: -0.5,
borderTopLeftRadius: index === 0 ? undefined : 0,
borderBottomLeftRadius: index === 0 ? undefined : 0,
borderTopLeftRadius: index === 0 ? 16 : 0,
borderBottomLeftRadius: 0,
borderTopRightRadius:
index === TIERS.length - 1 ? undefined : 0,
borderBottomRightRadius:
index === TIERS.length - 1 ? undefined : 0,
index === TIERS.length - Math.round(TIERS.length / 2) - 1
? 16
: 0,
borderBottomRightRadius: 0,
}}
onClick={() =>
mutateTankopediaPersistent((draft) => {
@@ -324,8 +161,47 @@ export function Options() {
</Button>
))}
</Flex>
<Flex className={styles.oneLineFilters} style={{ flex: 1 }}>
{nations.map((nation, index) => (
<Flex>
{[...TIERS].slice(5).map((tier, index) => (
<Button
key={tier}
color={filters.tiers.includes(tier) ? undefined : 'gray'}
variant={filters.tiers.includes(tier) ? 'surface' : 'soft'}
style={{
flex: 1,
margin: -0.5,
borderTopLeftRadius: 0,
borderBottomLeftRadius: index === 0 ? 16 : 0,
borderTopRightRadius: 0,
borderBottomRightRadius:
index === TIERS.length - Math.round(TIERS.length / 2) - 1
? 16
: 0,
}}
onClick={() =>
mutateTankopediaPersistent((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
direction="column"
className={styles.splitFilters}
style={{ width: '100%' }}
>
<Flex>
{nations.slice(0, 5).map((nation, index) => (
<Button
key={nation}
color={filters.nations.includes(nation) ? undefined : 'gray'}
@@ -333,10 +209,12 @@ export function Options() {
style={{
flex: 1,
margin: -0.5,
borderTopLeftRadius: index === 0 ? undefined : 0,
borderBottomLeftRadius: index === 0 ? undefined : 0,
borderTopLeftRadius: index === 0 ? 16 : 0,
borderBottomLeftRadius: 0,
borderTopRightRadius:
index === nations.length - 1 ? undefined : 0,
index === nations.length - Math.round(nations.length / 2)
? 16
: 0,
borderBottomRightRadius:
index === nations.length - 1 ? undefined : 0,
}}
@@ -356,6 +234,104 @@ export function Options() {
</Button>
))}
</Flex>
<Flex>
{nations.slice(5).map((nation, index) => (
<Button
key={nation}
color={filters.nations.includes(nation) ? undefined : 'gray'}
variant={filters.nations.includes(nation) ? 'surface' : 'soft'}
style={{
flex: 1,
margin: -0.5,
borderTopLeftRadius: 0,
borderBottomLeftRadius: index === 0 ? 16 : 0,
borderTopRightRadius:
index === nations.length - 1 ? undefined : 0,
borderBottomRightRadius:
index === nations.length - Math.round(nations.length / 2) - 1
? 16
: 0,
}}
onClick={() =>
mutateTankopediaPersistent((draft) => {
if (draft.filters.nations.includes(nation)) {
draft.filters.nations = draft.filters.nations.filter(
(preexistingType) => preexistingType !== nation,
);
} else {
draft.filters.nations.push(nation);
}
})
}
>
<Flag nation={nation} />
</Button>
))}
</Flex>
</Flex>
<Flex className={styles.oneLineFilters}>
{nations.map((nation, index) => (
<Button
key={nation}
color={filters.nations.includes(nation) ? undefined : 'gray'}
variant={filters.nations.includes(nation) ? 'surface' : 'soft'}
style={{
flex: 1,
margin: -0.5,
borderTopLeftRadius: index === 0 ? undefined : 0,
borderBottomLeftRadius: index === 0 ? undefined : 0,
borderTopRightRadius:
index === nations.length - 1 ? undefined : 0,
borderBottomRightRadius:
index === nations.length - 1 ? undefined : 0,
}}
onClick={() =>
mutateTankopediaPersistent((draft) => {
if (draft.filters.nations.includes(nation)) {
draft.filters.nations = draft.filters.nations.filter(
(preexistingType) => preexistingType !== nation,
);
} else {
draft.filters.nations.push(nation);
}
})
}
>
<Flag nation={nation} />
</Button>
))}
</Flex>
<Flex className={styles.oneLineFilters}>
{[...TIERS].map((tier, index) => (
<Button
key={tier}
color={filters.tiers.includes(tier) ? undefined : 'gray'}
variant={filters.tiers.includes(tier) ? 'surface' : '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={() =>
mutateTankopediaPersistent((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>
);
@@ -1,5 +1,9 @@
import { slateDark } from '@radix-ui/colors';
import { CaretDownIcon, MagnifyingGlassIcon } from '@radix-ui/react-icons';
import {
CaretDownIcon,
MagnifyingGlassIcon,
TrashIcon,
} from '@radix-ui/react-icons';
import {
Button,
Card,
@@ -10,7 +14,7 @@ import {
TextField,
} from '@radix-ui/themes';
import { go } from 'fuzzysort';
import { Suspense, use, useEffect, useMemo, useRef, useState } from 'react';
import { use, useEffect, useMemo, useRef, useState } from 'react';
import { TankType, TreeType } from '../../../../../components/Tanks';
import { asset } from '../../../../../core/blitzkrieg/asset';
import {
@@ -202,13 +206,28 @@ export function TankSearch({ compact, onSelect = () => {} }: TankSearchProps) {
</DropdownMenu.RadioGroup>
</DropdownMenu.Content>
</DropdownMenu.Root>
<Button
color="red"
variant="soft"
onClick={() =>
useTankopediaPersistent.setState({
filters: {
nations: [],
tiers: [],
treeTypes: [],
types: [],
test: 'include',
page: 0,
},
})
}
>
<TrashIcon />
</Button>
</Flex>
<Card variant={compact ? 'ghost' : 'surface'}>
<Suspense fallback={<Text>Loading...</Text>}>
<Options />
</Suspense>
</Card>
<Options />
</Flex>
{!compact && (
+1 -1
View File
@@ -8,7 +8,7 @@ export default function Page() {
const router = useRouter();
return (
<PageWrapper size="wide" color="purple">
<PageWrapper size="double" color="purple">
<TankSearch
onSelect={(tank) => {
router.push(`./tankopedia/${tank.id}`);