mirror of
https://github.com/blitzkit/blitzkit.git
synced 2026-10-23 19:49:50 +02:00
feat: provisions
This commit is contained in:
1 parent
f885fba4bd
commit
718576d5a9
3 files changed
+135
-2
No files matched your search
@@ -4,7 +4,8 @@ Thank you to [Mark Greene](https://github.com/Hitjack007) for your contributions
|
|||||||
|
|
||||||
## Features
|
## Features
|
||||||
|
|
||||||
- [Mark Greene] Added the ability to filter tanks by Consumables and game-mode Abilities
|
- [Mark Greene] Added the ability to filter tanks by consumables
|
||||||
|
- Also added the ability to filter tanks by game-mode abilities and provisions
|
||||||
|
|
||||||
## Fixes
|
## Fixes
|
||||||
|
|
||||||
|
|||||||
@@ -28,6 +28,7 @@ import { times } from "lodash-es";
|
|||||||
import type { ComponentProps, ReactNode } from "react";
|
import type { ComponentProps, 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 { useLocale } from "../../../hooks/useLocale";
|
import { useLocale } from "../../../hooks/useLocale";
|
||||||
import { App } from "../../../stores/app";
|
import { App } from "../../../stores/app";
|
||||||
import { TankFilters, type CaseType } from "../../../stores/tankFilters";
|
import { TankFilters, type CaseType } from "../../../stores/tankFilters";
|
||||||
@@ -42,6 +43,7 @@ import { ScienceOffIcon } from "../../ScienceOffIcon";
|
|||||||
|
|
||||||
const gameDefinitions = await awaitableGameDefinitions;
|
const gameDefinitions = await awaitableGameDefinitions;
|
||||||
const consumableDefinitions = await awaitableConsumableDefinitions;
|
const consumableDefinitions = await awaitableConsumableDefinitions;
|
||||||
|
const provisionDefinitions = await awaitableProvisionDefinitions;
|
||||||
|
|
||||||
const consumablesArray = Object.values(consumableDefinitions.consumables)
|
const consumablesArray = Object.values(consumableDefinitions.consumables)
|
||||||
.filter(
|
.filter(
|
||||||
@@ -52,7 +54,38 @@ const consumablesArray = Object.values(consumableDefinitions.consumables)
|
|||||||
.map((consumable) => consumable.id);
|
.map((consumable) => consumable.id);
|
||||||
const abilitiesArray = Array.from(
|
const abilitiesArray = Array.from(
|
||||||
Object.values(consumableDefinitions.consumables)
|
Object.values(consumableDefinitions.consumables)
|
||||||
.filter((c) => c.game_mode_exclusive)
|
.filter((ability) => ability.game_mode_exclusive)
|
||||||
|
.reduce((uniqueMap, consumable) => {
|
||||||
|
if (!uniqueMap.has(consumable.name.locales[locales.default])) {
|
||||||
|
uniqueMap.set(consumable.name.locales[locales.default], consumable.id);
|
||||||
|
}
|
||||||
|
|
||||||
|
return uniqueMap;
|
||||||
|
}, new Map<string, number>())
|
||||||
|
.values()
|
||||||
|
);
|
||||||
|
const provisionsArray = Array.from(
|
||||||
|
Object.values(provisionDefinitions.provisions)
|
||||||
|
.filter(
|
||||||
|
(provision) =>
|
||||||
|
!provision.game_mode_exclusive &&
|
||||||
|
provision.name.locales[locales.default]
|
||||||
|
)
|
||||||
|
.reduce((uniqueMap, consumable) => {
|
||||||
|
if (!uniqueMap.has(consumable.name.locales[locales.default])) {
|
||||||
|
uniqueMap.set(consumable.name.locales[locales.default], consumable.id);
|
||||||
|
}
|
||||||
|
|
||||||
|
return uniqueMap;
|
||||||
|
}, new Map<string, number>())
|
||||||
|
.values()
|
||||||
|
);
|
||||||
|
const powersArray = Array.from(
|
||||||
|
Object.values(provisionDefinitions.provisions)
|
||||||
|
.filter(
|
||||||
|
(provision) =>
|
||||||
|
provision.game_mode_exclusive && provision.name.locales[locales.default]
|
||||||
|
)
|
||||||
.reduce((uniqueMap, consumable) => {
|
.reduce((uniqueMap, consumable) => {
|
||||||
if (!uniqueMap.has(consumable.name.locales[locales.default])) {
|
if (!uniqueMap.has(consumable.name.locales[locales.default])) {
|
||||||
uniqueMap.set(consumable.name.locales[locales.default], consumable.id);
|
uniqueMap.set(consumable.name.locales[locales.default], consumable.id);
|
||||||
@@ -91,6 +124,7 @@ const GUN_TYPES = Object.keys(
|
|||||||
|
|
||||||
const MAX_TIERS = 4;
|
const MAX_TIERS = 4;
|
||||||
const MAX_CONSUMABLES = 4;
|
const MAX_CONSUMABLES = 4;
|
||||||
|
const MAX_PROVISIONS = 4;
|
||||||
const MAX_ABILITIES = 4;
|
const MAX_ABILITIES = 4;
|
||||||
|
|
||||||
const TIERS = times(10, (i) => 10 - i);
|
const TIERS = times(10, (i) => 10 - i);
|
||||||
@@ -109,7 +143,9 @@ export function FilterControl() {
|
|||||||
<GunTypeFilter />
|
<GunTypeFilter />
|
||||||
<ShellFilter />
|
<ShellFilter />
|
||||||
<ConsumablesFilter />
|
<ConsumablesFilter />
|
||||||
|
<ProvisionsFilter />
|
||||||
<AbilitiesFilter />
|
<AbilitiesFilter />
|
||||||
|
<PowersFilter />
|
||||||
|
|
||||||
<ClearButton />
|
<ClearButton />
|
||||||
</Flex>
|
</Flex>
|
||||||
@@ -881,6 +917,100 @@ function ConsumablesFilter() {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function ProvisionsFilter() {
|
||||||
|
const { unwrap, strings } = useLocale();
|
||||||
|
const rawProvisions = TankFilters.use((state) => state.provisions);
|
||||||
|
const provisions =
|
||||||
|
rawProvisions.length === 0 ? provisionsArray : rawProvisions;
|
||||||
|
|
||||||
|
return (
|
||||||
|
<DropdownMenu.Root modal={false}>
|
||||||
|
<DropdownMenu.Trigger>
|
||||||
|
<Button color="gray" variant="surface">
|
||||||
|
<Flex>
|
||||||
|
{provisions.slice(0, MAX_PROVISIONS).map((provision, index) => (
|
||||||
|
<img
|
||||||
|
key={provision}
|
||||||
|
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/provisions/${provision}.webp`)}
|
||||||
|
/>
|
||||||
|
))}
|
||||||
|
|
||||||
|
{provisions.length > MAX_CONSUMABLES && (
|
||||||
|
<Text size="1" ml="1">
|
||||||
|
{literals(strings.common.units.plus, {
|
||||||
|
value: provisions.length - MAX_CONSUMABLES,
|
||||||
|
})}
|
||||||
|
</Text>
|
||||||
|
)}
|
||||||
|
</Flex>
|
||||||
|
</Button>
|
||||||
|
</DropdownMenu.Trigger>
|
||||||
|
|
||||||
|
<DropdownMenu.Content>
|
||||||
|
{provisionsArray.map((provision) => {
|
||||||
|
const selected = rawProvisions.includes(provision);
|
||||||
|
const provisionDefinition =
|
||||||
|
provisionDefinitions.provisions[provision];
|
||||||
|
|
||||||
|
return (
|
||||||
|
<DropdownMenu.CheckboxItem
|
||||||
|
onClick={(event) => {
|
||||||
|
event.preventDefault();
|
||||||
|
|
||||||
|
TankFilters.mutate((draft) => {
|
||||||
|
if (selected) {
|
||||||
|
draft.provisions = draft.provisions.filter(
|
||||||
|
(n) => n !== provision
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
draft.provisions = [...draft.provisions, provision];
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}}
|
||||||
|
checked={selected}
|
||||||
|
key={provision}
|
||||||
|
>
|
||||||
|
<img
|
||||||
|
style={{
|
||||||
|
width: "1.25em",
|
||||||
|
height: "1.25em",
|
||||||
|
objectFit: "contain",
|
||||||
|
}}
|
||||||
|
src={asset(`icons/provisions/${provision}.webp`)}
|
||||||
|
/>
|
||||||
|
|
||||||
|
{unwrap(provisionDefinition.name)}
|
||||||
|
</DropdownMenu.CheckboxItem>
|
||||||
|
);
|
||||||
|
})}
|
||||||
|
|
||||||
|
<DropdownMenu.Separator />
|
||||||
|
|
||||||
|
<DropdownMenu.Item
|
||||||
|
color="red"
|
||||||
|
onClick={(event) => {
|
||||||
|
event.preventDefault();
|
||||||
|
|
||||||
|
TankFilters.mutate((draft) => {
|
||||||
|
draft.provisions = [];
|
||||||
|
});
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<TrashIcon />
|
||||||
|
{strings.website.common.tank_search.clear}
|
||||||
|
</DropdownMenu.Item>
|
||||||
|
</DropdownMenu.Content>
|
||||||
|
</DropdownMenu.Root>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
function AbilitiesFilter() {
|
function AbilitiesFilter() {
|
||||||
const { unwrap, strings } = useLocale();
|
const { unwrap, strings } = useLocale();
|
||||||
const rawAbilities = TankFilters.use((state) => state.abilities);
|
const rawAbilities = TankFilters.use((state) => state.abilities);
|
||||||
|
|||||||
@@ -22,6 +22,7 @@ export interface TankFilters {
|
|||||||
gunType: CaseType<GunDefinition>[];
|
gunType: CaseType<GunDefinition>[];
|
||||||
shells: [ShellType | null, ShellType | null, ShellType | null];
|
shells: [ShellType | null, ShellType | null, ShellType | null];
|
||||||
consumables: number[];
|
consumables: number[];
|
||||||
|
provisions: number[];
|
||||||
abilities: number[];
|
abilities: number[];
|
||||||
|
|
||||||
showTesting: boolean;
|
showTesting: boolean;
|
||||||
@@ -40,6 +41,7 @@ export const TankFilters = new Varuna<TankFilters>({
|
|||||||
gunType: [],
|
gunType: [],
|
||||||
shells: [null, null, null],
|
shells: [null, null, null],
|
||||||
consumables: [],
|
consumables: [],
|
||||||
|
provisions: [],
|
||||||
abilities: [],
|
abilities: [],
|
||||||
|
|
||||||
showTesting: true,
|
showTesting: true,
|
||||||
|
|||||||
Reference in new issue
Block a user