mirror of
https://github.com/blitzkit/blitzkit.git
synced 2026-10-23 19:49:50 +02:00
Reworked Game Mode Ability Filters
This commit is contained in:
1 parent
cbe22035cb
commit
636a2934a2
1 file changed
+145
-187
@@ -26,7 +26,7 @@ import {
|
|||||||
type FlexProps,
|
type FlexProps,
|
||||||
} from "@radix-ui/themes";
|
} from "@radix-ui/themes";
|
||||||
import { times } from "lodash-es";
|
import { times } from "lodash-es";
|
||||||
import { Fragment, type ComponentProps, type ReactNode } from "react";
|
import { Fragment, useState, type ComponentProps, type ReactNode } from "react";
|
||||||
import { awaitableConsumableDefinitions } from "../../../core/awaitables/consumableDefinitions";
|
import { awaitableConsumableDefinitions } from "../../../core/awaitables/consumableDefinitions";
|
||||||
import { awaitableGameDefinitions } from "../../../core/awaitables/gameDefinitions";
|
import { awaitableGameDefinitions } from "../../../core/awaitables/gameDefinitions";
|
||||||
import { awaitableProvisionDefinitions } from "../../../core/awaitables/provisionDefinitions";
|
import { awaitableProvisionDefinitions } from "../../../core/awaitables/provisionDefinitions";
|
||||||
@@ -160,17 +160,13 @@ export function FilterControl() {
|
|||||||
<ClassFilter />
|
<ClassFilter />
|
||||||
<TypeFilter />
|
<TypeFilter />
|
||||||
<NationsFilter />
|
<NationsFilter />
|
||||||
|
|
||||||
<OwnershipFilter />
|
<OwnershipFilter />
|
||||||
<TestFilter />
|
<TestFilter />
|
||||||
|
|
||||||
<GunTypeFilter />
|
<GunTypeFilter />
|
||||||
<ShellFilter />
|
<ShellFilter />
|
||||||
<ConsumablesFilter />
|
<ConsumablesFilter />
|
||||||
<ProvisionsFilter />
|
<ProvisionsFilter />
|
||||||
<AbilitiesFilter />
|
<GameModeAbilitiesFilter />
|
||||||
<PowersFilter />
|
|
||||||
|
|
||||||
<ResetButton />
|
<ResetButton />
|
||||||
</Flex>
|
</Flex>
|
||||||
);
|
);
|
||||||
@@ -1031,205 +1027,166 @@ function ProvisionsFilter() {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
function PowersFilter() {
|
function GameModeAbilitiesFilter() {
|
||||||
const { unwrap, strings } = useLocale();
|
const { unwrap } = useLocale();
|
||||||
|
const rawAbilities = TankFilters.use((state) => state.abilities);
|
||||||
const rawPowers = TankFilters.use((state) => state.powers);
|
const rawPowers = TankFilters.use((state) => state.powers);
|
||||||
const powers =
|
const [activeTab, setActiveTab] = useState<"active" | "passive">("active");
|
||||||
rawPowers.length === 0
|
|
||||||
? Array.from(allGameModeProvisions.values())
|
const totalSelected = rawAbilities.length + rawPowers.length;
|
||||||
: rawPowers;
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<DropdownMenu.Root modal={false}>
|
<DropdownMenu.Root modal={false}>
|
||||||
<DropdownMenu.Trigger>
|
<DropdownMenu.Trigger>
|
||||||
<Button color="gray" variant="surface">
|
<Button color="gray" variant="surface">
|
||||||
<Flex>
|
Game Mode Abilities
|
||||||
{powers.slice(0, MAX_ICONS).map((power, index) => (
|
{totalSelected > 0 && (
|
||||||
<img
|
<Text size="1" ml="1">
|
||||||
key={power}
|
({totalSelected})
|
||||||
style={{
|
</Text>
|
||||||
filter: "drop-shadow(0 0 var(--space-1) var(--black-a11))",
|
)}
|
||||||
marginLeft: index > 0 ? "-0.5em" : undefined,
|
|
||||||
width: "1.25em",
|
|
||||||
height: "1.25em",
|
|
||||||
objectFit: "contain",
|
|
||||||
}}
|
|
||||||
src={asset(`icons/provisions/${power}.webp`)}
|
|
||||||
/>
|
|
||||||
))}
|
|
||||||
|
|
||||||
{powers.length > MAX_ICONS && (
|
|
||||||
<Text size="1" ml="1">
|
|
||||||
{literals(strings.common.units.plus, {
|
|
||||||
value: powers.length - MAX_ICONS,
|
|
||||||
})}
|
|
||||||
</Text>
|
|
||||||
)}
|
|
||||||
</Flex>
|
|
||||||
</Button>
|
</Button>
|
||||||
</DropdownMenu.Trigger>
|
</DropdownMenu.Trigger>
|
||||||
|
|
||||||
<DropdownMenu.Content>
|
<DropdownMenu.Content style={{ minWidth: "249px", maxWidth: "249px" }}>
|
||||||
{gameModeRoles.map(({ gameModeId, provisions }) => {
|
{/* Tab buttons */}
|
||||||
const gameMode = gameDefinitions.gameModes[gameModeId];
|
<Flex gap="2" p="2" mb="2" width="100%">
|
||||||
|
<Button
|
||||||
if (provisions.length === 0) return null;
|
size="1"
|
||||||
|
variant={activeTab === "active" ? "solid" : "soft"}
|
||||||
return (
|
color={activeTab === "active" ? "violet" : "gray"}
|
||||||
<Fragment key={gameModeId}>
|
onClick={() => setActiveTab("active")}
|
||||||
<DropdownMenu.Label>{unwrap(gameMode.name)}</DropdownMenu.Label>
|
style={{ flex: 1, minWidth: 0 }}
|
||||||
|
>
|
||||||
{provisions.map((provision) => {
|
Active
|
||||||
{
|
</Button>
|
||||||
const selected = rawPowers.includes(provision);
|
<Button
|
||||||
const powerDefinition =
|
size="1"
|
||||||
provisionDefinitions.provisions[provision];
|
variant={activeTab === "passive" ? "solid" : "soft"}
|
||||||
|
color={activeTab === "passive" ? "violet" : "gray"}
|
||||||
return (
|
onClick={() => setActiveTab("passive")}
|
||||||
<DropdownMenu.CheckboxItem
|
style={{ flex: 1, minWidth: 0 }}
|
||||||
onClick={(event) => {
|
>
|
||||||
event.preventDefault();
|
Passive
|
||||||
|
</Button>
|
||||||
TankFilters.mutate((draft) => {
|
</Flex>
|
||||||
if (selected) {
|
|
||||||
draft.powers = draft.powers.filter(
|
|
||||||
(n) => n !== provision
|
|
||||||
);
|
|
||||||
} else {
|
|
||||||
draft.powers = [...draft.powers, provision];
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}}
|
|
||||||
checked={selected}
|
|
||||||
key={provision}
|
|
||||||
>
|
|
||||||
<img
|
|
||||||
style={{
|
|
||||||
width: "1.25em",
|
|
||||||
height: "1.25em",
|
|
||||||
objectFit: "contain",
|
|
||||||
}}
|
|
||||||
src={asset(`icons/provisions/${provision}.webp`)}
|
|
||||||
/>
|
|
||||||
|
|
||||||
{unwrap(powerDefinition.name)}
|
|
||||||
</DropdownMenu.CheckboxItem>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
})}
|
|
||||||
</Fragment>
|
|
||||||
);
|
|
||||||
})}
|
|
||||||
|
|
||||||
<DropdownMenu.Separator />
|
<DropdownMenu.Separator />
|
||||||
|
|
||||||
<DropdownMenu.Item
|
{/* Active Abilities Content */}
|
||||||
color="red"
|
{activeTab === "active" && (
|
||||||
onClick={(event) => {
|
<>
|
||||||
event.preventDefault();
|
{gameModeRoles.map(({ gameModeId, consumables }) => {
|
||||||
|
const gameMode = gameDefinitions.gameModes[gameModeId];
|
||||||
|
|
||||||
TankFilters.mutate((draft) => {
|
if (consumables.length === 0) return null;
|
||||||
draft.powers = [];
|
|
||||||
});
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<TrashIcon />
|
|
||||||
{strings.website.common.tank_search.clear}
|
|
||||||
</DropdownMenu.Item>
|
|
||||||
</DropdownMenu.Content>
|
|
||||||
</DropdownMenu.Root>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
function AbilitiesFilter() {
|
return (
|
||||||
const { unwrap, strings } = useLocale();
|
<Fragment key={`active-${gameModeId}`}>
|
||||||
const rawAbilities = TankFilters.use((state) => state.abilities);
|
<DropdownMenu.Label>
|
||||||
const abilities =
|
{unwrap(gameMode.name)}
|
||||||
rawAbilities.length === 0
|
</DropdownMenu.Label>
|
||||||
? Array.from(allGameModeConsumables.values())
|
|
||||||
: rawAbilities;
|
|
||||||
|
|
||||||
return (
|
{consumables.map((consumable) => {
|
||||||
<DropdownMenu.Root modal={false}>
|
const selected = rawAbilities.includes(consumable);
|
||||||
<DropdownMenu.Trigger>
|
const abilityDefinition =
|
||||||
<Button color="gray" variant="surface">
|
consumableDefinitions.consumables[consumable];
|
||||||
<Flex>
|
|
||||||
{abilities.slice(0, MAX_ICONS).map((ability, index) => (
|
|
||||||
<img
|
|
||||||
key={ability}
|
|
||||||
style={{
|
|
||||||
filter: "drop-shadow(0 0 var(--space-1) var(--black-a11))",
|
|
||||||
marginLeft: index > 0 ? "-0.5em" : undefined,
|
|
||||||
width: "1.25em",
|
|
||||||
height: "1.25em",
|
|
||||||
objectFit: "contain",
|
|
||||||
}}
|
|
||||||
src={asset(`icons/consumables/${ability}.webp`)}
|
|
||||||
/>
|
|
||||||
))}
|
|
||||||
|
|
||||||
{abilities.length > MAX_ICONS && (
|
return (
|
||||||
<Text size="1" ml="1">
|
<DropdownMenu.CheckboxItem
|
||||||
{literals(strings.common.units.plus, {
|
onClick={(event) => {
|
||||||
value: abilities.length - MAX_ICONS,
|
event.preventDefault();
|
||||||
})}
|
|
||||||
</Text>
|
|
||||||
)}
|
|
||||||
</Flex>
|
|
||||||
</Button>
|
|
||||||
</DropdownMenu.Trigger>
|
|
||||||
|
|
||||||
<DropdownMenu.Content>
|
TankFilters.mutate((draft) => {
|
||||||
{gameModeRoles.map(({ gameModeId, consumables }) => {
|
if (selected) {
|
||||||
const gameMode = gameDefinitions.gameModes[gameModeId];
|
draft.abilities = draft.abilities.filter(
|
||||||
|
(n) => n !== consumable
|
||||||
if (consumables.length === 0) return null;
|
);
|
||||||
|
} else {
|
||||||
return (
|
draft.abilities = [
|
||||||
<Fragment key={gameModeId}>
|
...draft.abilities,
|
||||||
<DropdownMenu.Label>{unwrap(gameMode.name)}</DropdownMenu.Label>
|
consumable,
|
||||||
|
];
|
||||||
{consumables.map((consumable) => {
|
}
|
||||||
{
|
});
|
||||||
const selected = rawAbilities.includes(consumable);
|
|
||||||
const abilityDefinition =
|
|
||||||
consumableDefinitions.consumables[consumable];
|
|
||||||
|
|
||||||
return (
|
|
||||||
<DropdownMenu.CheckboxItem
|
|
||||||
onClick={(event) => {
|
|
||||||
event.preventDefault();
|
|
||||||
|
|
||||||
TankFilters.mutate((draft) => {
|
|
||||||
if (selected) {
|
|
||||||
draft.abilities = draft.abilities.filter(
|
|
||||||
(n) => n !== consumable
|
|
||||||
);
|
|
||||||
} else {
|
|
||||||
draft.abilities = [...draft.abilities, consumable];
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}}
|
|
||||||
checked={selected}
|
|
||||||
key={consumable}
|
|
||||||
>
|
|
||||||
<img
|
|
||||||
style={{
|
|
||||||
width: "1.25em",
|
|
||||||
height: "1.25em",
|
|
||||||
objectFit: "contain",
|
|
||||||
}}
|
}}
|
||||||
src={asset(`icons/consumables/${consumable}.webp`)}
|
checked={selected}
|
||||||
/>
|
key={consumable}
|
||||||
|
>
|
||||||
|
<img
|
||||||
|
style={{
|
||||||
|
width: "1.25em",
|
||||||
|
height: "1.25em",
|
||||||
|
objectFit: "contain",
|
||||||
|
}}
|
||||||
|
src={asset(`icons/consumables/${consumable}.webp`)}
|
||||||
|
/>
|
||||||
|
|
||||||
{unwrap(abilityDefinition.name)}
|
{unwrap(abilityDefinition.name)}
|
||||||
</DropdownMenu.CheckboxItem>
|
</DropdownMenu.CheckboxItem>
|
||||||
);
|
);
|
||||||
}
|
})}
|
||||||
})}
|
</Fragment>
|
||||||
</Fragment>
|
);
|
||||||
);
|
})}
|
||||||
})}
|
</>
|
||||||
|
)}
|
||||||
|
|
||||||
|
{/* Passive Abilities Content */}
|
||||||
|
{activeTab === "passive" && (
|
||||||
|
<>
|
||||||
|
{gameModeRoles.map(({ gameModeId, provisions }) => {
|
||||||
|
const gameMode = gameDefinitions.gameModes[gameModeId];
|
||||||
|
|
||||||
|
if (provisions.length === 0) return null;
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Fragment key={`passive-${gameModeId}`}>
|
||||||
|
<DropdownMenu.Label>
|
||||||
|
{unwrap(gameMode.name)}
|
||||||
|
</DropdownMenu.Label>
|
||||||
|
|
||||||
|
{provisions.map((provision) => {
|
||||||
|
const selected = rawPowers.includes(provision);
|
||||||
|
const powerDefinition =
|
||||||
|
provisionDefinitions.provisions[provision];
|
||||||
|
|
||||||
|
return (
|
||||||
|
<DropdownMenu.CheckboxItem
|
||||||
|
onClick={(event) => {
|
||||||
|
event.preventDefault();
|
||||||
|
|
||||||
|
TankFilters.mutate((draft) => {
|
||||||
|
if (selected) {
|
||||||
|
draft.powers = draft.powers.filter(
|
||||||
|
(n) => n !== provision
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
draft.powers = [...draft.powers, provision];
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}}
|
||||||
|
checked={selected}
|
||||||
|
key={provision}
|
||||||
|
>
|
||||||
|
<img
|
||||||
|
style={{
|
||||||
|
width: "1.25em",
|
||||||
|
height: "1.25em",
|
||||||
|
objectFit: "contain",
|
||||||
|
}}
|
||||||
|
src={asset(`icons/provisions/${provision}.webp`)}
|
||||||
|
/>
|
||||||
|
|
||||||
|
{unwrap(powerDefinition.name)}
|
||||||
|
</DropdownMenu.CheckboxItem>
|
||||||
|
);
|
||||||
|
})}
|
||||||
|
</Fragment>
|
||||||
|
);
|
||||||
|
})}
|
||||||
|
</>
|
||||||
|
)}
|
||||||
|
|
||||||
<DropdownMenu.Separator />
|
<DropdownMenu.Separator />
|
||||||
|
|
||||||
@@ -1240,11 +1197,12 @@ function AbilitiesFilter() {
|
|||||||
|
|
||||||
TankFilters.mutate((draft) => {
|
TankFilters.mutate((draft) => {
|
||||||
draft.abilities = [];
|
draft.abilities = [];
|
||||||
|
draft.powers = [];
|
||||||
});
|
});
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<TrashIcon />
|
<TrashIcon />
|
||||||
{strings.website.common.tank_search.clear}
|
Clear All
|
||||||
</DropdownMenu.Item>
|
</DropdownMenu.Item>
|
||||||
</DropdownMenu.Content>
|
</DropdownMenu.Content>
|
||||||
</DropdownMenu.Root>
|
</DropdownMenu.Root>
|
||||||
|
|||||||
Reference in new issue
Block a user