mirror of
https://github.com/blitzkit/blitzkit.git
synced 2026-10-21 10:47:04 +02:00
add consumable buttons
This commit is contained in:
1 parent
f8a71feb46
commit
885c260605
9 files changed
+124
-32
No files matched your search
+3
-1
@@ -4,6 +4,8 @@
|
||||
"amogos",
|
||||
"Tankopedia",
|
||||
"uasset",
|
||||
"oodle"
|
||||
"oodle",
|
||||
"blitzkit",
|
||||
"webp"
|
||||
]
|
||||
}
|
||||
@@ -198,12 +198,8 @@
|
||||
},
|
||||
|
||||
"tanks": {
|
||||
"characteristics": {
|
||||
"title": "Characteristics"
|
||||
},
|
||||
|
||||
"loadout": {
|
||||
"title": "Loadout",
|
||||
"consumables": "Consumables",
|
||||
"modules": "Modules",
|
||||
"equipment": "Equipment",
|
||||
"alternative": "Alt"
|
||||
|
||||
@@ -13,6 +13,36 @@
|
||||
}
|
||||
}
|
||||
|
||||
.consumables {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(3, minmax(0, 1fr));
|
||||
gap: var(--space-3);
|
||||
|
||||
.consumable {
|
||||
font-size: var(--space-5);
|
||||
|
||||
img {
|
||||
width: 1em;
|
||||
height: 1em;
|
||||
}
|
||||
|
||||
.info {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
|
||||
.entry {
|
||||
display: flex;
|
||||
gap: var(--space-2);
|
||||
|
||||
svg {
|
||||
width: 1em;
|
||||
height: 1em;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.equipment {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
|
||||
@@ -5,9 +5,11 @@ import { StandardPrice } from "@protos/blitz_static_standard_price";
|
||||
import type { UpgradeLine } from "@protos/blitz_static_tank_upgrade_line";
|
||||
import type { StageParameters } from "@protos/blitz_static_tank_upgrade_single_stage";
|
||||
import {
|
||||
ClockIcon,
|
||||
CornerBottomLeftIcon,
|
||||
DoubleArrowLeftIcon,
|
||||
DoubleArrowRightIcon,
|
||||
ResetIcon,
|
||||
TrashIcon,
|
||||
} from "@radix-ui/react-icons";
|
||||
import { chunk } from "lodash-es";
|
||||
@@ -26,7 +28,7 @@ import { useProtagonist } from "../../hooks/useProtagonist";
|
||||
import { useStrings } from "../../hooks/useStrings";
|
||||
import { useTierPrices } from "../../hooks/useTierPrices";
|
||||
import { useUpgradePreset } from "../../hooks/useUpgradePreset";
|
||||
import { Tankopedia } from "../../stores/tankopedia";
|
||||
import { Tankopedia, TankopediaCompare } from "../../stores/tankopedia";
|
||||
import { Button } from "../Button";
|
||||
import { Heading } from "../Heading";
|
||||
import { IconButton } from "../IconButton";
|
||||
@@ -38,13 +40,15 @@ import type { ComputedCharacteristics } from "../../tankopedia/computeCharacteri
|
||||
import { Tooltip } from "../Tooltip";
|
||||
import { useGameStrings } from "../../hooks/useGameStrings";
|
||||
import { TankopediaCollapsible } from "../TankopediaCollapsible";
|
||||
import type { ConsumableComponent } from "@protos/blitz_static_consumable_component";
|
||||
import { Tank } from "@protos/tank";
|
||||
import { select } from "three/src/nodes/math/ConditionalNode.js";
|
||||
|
||||
interface TankopediaLoadoutProps {
|
||||
characteristics: ComputedCharacteristics;
|
||||
}
|
||||
|
||||
export function TankopediaLoadout({ characteristics }: TankopediaLoadoutProps) {
|
||||
const strings = useStrings();
|
||||
const tank = useProtagonist();
|
||||
|
||||
const showModules = tank.tank!.upgrade_lines.some(
|
||||
@@ -53,15 +57,9 @@ export function TankopediaLoadout({ characteristics }: TankopediaLoadoutProps) {
|
||||
|
||||
return (
|
||||
<>
|
||||
<TankopediaCollapsible title={strings.tanks.loadout.title}>
|
||||
{showModules && <Modules />}
|
||||
<Equipment />
|
||||
<Consumables characteristics={characteristics} />
|
||||
</TankopediaCollapsible>
|
||||
|
||||
<TankopediaCollapsible title={strings.tanks.characteristics.title}>
|
||||
lmao
|
||||
</TankopediaCollapsible>
|
||||
{showModules && <Modules />}
|
||||
<Equipment />
|
||||
<Consumables characteristics={characteristics} />
|
||||
</>
|
||||
);
|
||||
}
|
||||
@@ -71,21 +69,88 @@ interface ConsumablesProps {
|
||||
}
|
||||
|
||||
function Consumables({ characteristics }: ConsumablesProps) {
|
||||
const strings = useStrings();
|
||||
const consumables = useConsumables();
|
||||
const tierPrices = useTierPrices();
|
||||
const tank = useProtagonist();
|
||||
const isCompatible = useCompatibility(tank, characteristics);
|
||||
|
||||
return Object.entries(consumables.consumables).map(
|
||||
([id, { compatibility, consumable, purchase }]) => {
|
||||
if (!isCompatible(compatibility!)) return null;
|
||||
return (
|
||||
<div className={styles.section}>
|
||||
<div className={styles.header}>
|
||||
<Heading size="4">{strings.tanks.loadout.consumables}</Heading>
|
||||
|
||||
return (
|
||||
<span>
|
||||
{id} {JSON.stringify(consumable, null, 2)}
|
||||
</span>
|
||||
);
|
||||
},
|
||||
<IconButton
|
||||
color="red"
|
||||
onClick={() => {
|
||||
Tankopedia.mutate((draft) => {
|
||||
draft.protagonist.consumables = [];
|
||||
});
|
||||
}}
|
||||
>
|
||||
<TrashIcon />
|
||||
</IconButton>
|
||||
</div>
|
||||
|
||||
<div className={styles.consumables}>
|
||||
{Object.entries(consumables.consumables).map(
|
||||
([id, { compatibility, consumable, purchase }]) => {
|
||||
if (!isCompatible(compatibility!)) return null;
|
||||
return <Consumable id={id} consumable={consumable!} />;
|
||||
},
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
interface ConsumableProps {
|
||||
id: string;
|
||||
consumable: ConsumableComponent;
|
||||
}
|
||||
|
||||
function Consumable({ id, consumable }: ConsumableProps) {
|
||||
const gameStrings = useGameStrings("ConsumableEntity");
|
||||
const isSelected = Tankopedia.use((state) =>
|
||||
state.protagonist.consumables.includes(id),
|
||||
);
|
||||
|
||||
return (
|
||||
<Tooltip tooltip={gameStrings[consumable!.name_key]}>
|
||||
<Button
|
||||
radius="1"
|
||||
variant={isSelected ? "surface" : "soft"}
|
||||
color={isSelected ? undefined : "gray"}
|
||||
className={styles.consumable}
|
||||
onClick={() => {
|
||||
Tankopedia.mutate((draft) => {
|
||||
const index = draft.protagonist.consumables.indexOf(id);
|
||||
|
||||
if (index === -1) {
|
||||
draft.protagonist.consumables.push(id);
|
||||
} else {
|
||||
draft.protagonist.consumables.splice(index, 1);
|
||||
}
|
||||
});
|
||||
}}
|
||||
>
|
||||
<img src={`/media/consumables/${id}.webp`} />
|
||||
<div className={styles.info}>
|
||||
<Text lowContrast size="minor">
|
||||
<div className={styles.entry}>
|
||||
<ClockIcon />
|
||||
10s
|
||||
</div>
|
||||
</Text>
|
||||
|
||||
<Text lowContrast size="minor">
|
||||
<div className={styles.entry}>
|
||||
<ResetIcon />
|
||||
10s
|
||||
</div>
|
||||
</Text>
|
||||
</div>
|
||||
</Button>
|
||||
</Tooltip>
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@@ -20,9 +20,7 @@
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
&:hover,
|
||||
&:active,
|
||||
&:focus-within {
|
||||
&:hover {
|
||||
.text {
|
||||
display: block;
|
||||
}
|
||||
|
||||
@@ -12,7 +12,7 @@
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
|
||||
gap: var(--space-6);
|
||||
gap: var(--space-5);
|
||||
padding: var(--space-5);
|
||||
|
||||
overflow-y: auto;
|
||||
|
||||
@@ -16,6 +16,5 @@ export enum TankopediaCompare {
|
||||
|
||||
export const Tankopedia = new Varuna<Tankopedia, Tank>((tank) => ({
|
||||
compare: TankopediaCompare.TierAndClass,
|
||||
|
||||
protagonist: createTankState(tank),
|
||||
}));
|
||||
@@ -23,6 +23,7 @@ export function createTankState({ tank, id }: Tank) {
|
||||
id,
|
||||
|
||||
equipment: {},
|
||||
consumables: [],
|
||||
|
||||
upgrades,
|
||||
alternates,
|
||||
|
||||
@@ -8,6 +8,7 @@ export interface TankState {
|
||||
id: string;
|
||||
|
||||
equipment: Record<number, number>;
|
||||
consumables: string[];
|
||||
|
||||
upgrades: Record<string, number>;
|
||||
alternates: Record<string, boolean>;
|
||||
|
||||
Reference in new issue
Block a user