mirror of
https://github.com/blitzkit/blitzkit.git
synced 2026-10-24 20:19:49 +02:00
cleaner equipment and modules ui
This commit is contained in:
1 parent
26cc0cc723
commit
c100a1e655
4 files changed
+150
-122
No files matched your search
@@ -1,11 +1,11 @@
|
|||||||
.price {
|
.price {
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
|
||||||
|
|
||||||
gap: var(--space-3);
|
gap: var(--space-3);
|
||||||
|
|
||||||
.entry {
|
.entry {
|
||||||
display: block;
|
display: block;
|
||||||
|
line-height: 1;
|
||||||
|
|
||||||
.wrapper {
|
.wrapper {
|
||||||
display: flex;
|
display: flex;
|
||||||
|
|||||||
@@ -20,25 +20,32 @@
|
|||||||
|
|
||||||
.slots {
|
.slots {
|
||||||
display: flex;
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: var(--space-2);
|
||||||
|
align-items: center;
|
||||||
|
|
||||||
.slot {
|
.options {
|
||||||
aspect-ratio: 1 / 1;
|
display: flex;
|
||||||
padding: var(--space-3);
|
|
||||||
|
|
||||||
font-size: var(--space-5);
|
.slot {
|
||||||
|
aspect-ratio: 1 / 1;
|
||||||
|
padding: var(--space-3);
|
||||||
|
|
||||||
&:first-child {
|
font-size: var(--space-5);
|
||||||
border-top-right-radius: 0;
|
|
||||||
border-bottom-right-radius: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
&:last-child {
|
&:first-child {
|
||||||
border-top-left-radius: 0;
|
border-top-right-radius: 0;
|
||||||
border-bottom-left-radius: 0;
|
border-bottom-right-radius: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
&[data-selected="true"] {
|
&:last-child {
|
||||||
z-index: 1;
|
border-top-left-radius: 0;
|
||||||
|
border-bottom-left-radius: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
&[data-selected="true"] {
|
||||||
|
z-index: 1;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -53,37 +60,41 @@
|
|||||||
|
|
||||||
.line {
|
.line {
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
|
||||||
|
|
||||||
gap: var(--space-3);
|
gap: var(--space-3);
|
||||||
|
|
||||||
.stage {
|
.wrapper {
|
||||||
position: relative;
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
align-items: center;
|
||||||
|
gap: var(--space-2);
|
||||||
|
|
||||||
padding: var(--space-3);
|
.stage {
|
||||||
|
position: relative;
|
||||||
|
|
||||||
font-size: 2em;
|
padding: var(--space-3);
|
||||||
|
|
||||||
.icon {
|
font-size: 2em;
|
||||||
width: 1em;
|
|
||||||
height: 1em;
|
|
||||||
|
|
||||||
padding: var(--space-3) 0;
|
.icon {
|
||||||
|
width: 1em;
|
||||||
|
height: 1em;
|
||||||
|
|
||||||
transform: translate(var(--space-1), calc(-1 * var(--space-1)));
|
transform: translate(var(--space-1), var(--space-1));
|
||||||
}
|
}
|
||||||
|
|
||||||
.tier {
|
.tier {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
left: var(--space-2);
|
left: var(--space-2);
|
||||||
top: var(--space-2);
|
top: var(--space-2);
|
||||||
}
|
}
|
||||||
|
|
||||||
.price {
|
.price {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
left: 50%;
|
left: 50%;
|
||||||
bottom: var(--space-2);
|
bottom: var(--space-2);
|
||||||
transform: translateX(-50%);
|
transform: translateX(-50%);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -39,10 +39,7 @@ export function TankopediaLoadout() {
|
|||||||
function Equipment() {
|
function Equipment() {
|
||||||
const strings = useStrings();
|
const strings = useStrings();
|
||||||
const tank = useProtagonist();
|
const tank = useProtagonist();
|
||||||
const equipment = useEquipment(
|
const equipment = useEquipment(tank.tank!);
|
||||||
tank.tank!.equipment_preset_catalog_id,
|
|
||||||
tank.tank!.equipment_price_preset_catalog_id,
|
|
||||||
);
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className={styles.section}>
|
<div className={styles.section}>
|
||||||
@@ -86,16 +83,25 @@ interface EquipmentSlotProps {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function EquipmentSlot({ slot, rowIndex, columnIndex }: EquipmentSlotProps) {
|
function EquipmentSlot({ slot, rowIndex, columnIndex }: EquipmentSlotProps) {
|
||||||
|
const equipmentIndex = rowIndex * equipmentColumns + columnIndex;
|
||||||
|
const tank = useProtagonist();
|
||||||
|
const equipment = useEquipment(tank.tank!);
|
||||||
|
const { price } = equipment.price.unlock_slot_prices[equipmentIndex];
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className={styles.slots}>
|
<div className={styles.slots}>
|
||||||
{slot.options_catalog_i_ds.map((id, index) => (
|
<div className={styles.options}>
|
||||||
<EquipmentOption
|
{slot.options_catalog_i_ds.map((id, index) => (
|
||||||
key={id}
|
<EquipmentOption
|
||||||
optionIndex={index}
|
key={id}
|
||||||
rowIndex={rowIndex}
|
optionIndex={index}
|
||||||
columnIndex={columnIndex}
|
rowIndex={rowIndex}
|
||||||
/>
|
columnIndex={columnIndex}
|
||||||
))}
|
/>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<Price price={price!} />
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@@ -112,11 +118,17 @@ function EquipmentOption({
|
|||||||
columnIndex,
|
columnIndex,
|
||||||
}: EquipmentOptionProps) {
|
}: EquipmentOptionProps) {
|
||||||
const equipmentIndex = rowIndex * equipmentColumns + columnIndex;
|
const equipmentIndex = rowIndex * equipmentColumns + columnIndex;
|
||||||
|
|
||||||
|
const tank = useProtagonist();
|
||||||
|
const equipment = useEquipment(tank.tank!);
|
||||||
const isSelected = Tankopedia.use(
|
const isSelected = Tankopedia.use(
|
||||||
(state) =>
|
(state) =>
|
||||||
equipmentIndex in state.protagonist.equipment &&
|
equipmentIndex in state.protagonist.equipment &&
|
||||||
state.protagonist.equipment[equipmentIndex] === optionIndex,
|
state.protagonist.equipment[equipmentIndex] === optionIndex,
|
||||||
);
|
);
|
||||||
|
const name =
|
||||||
|
equipment.preset.slots[equipmentIndex].options_catalog_i_ds[optionIndex];
|
||||||
|
const equipmentData = equipment.equipments[name];
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Button
|
<Button
|
||||||
@@ -292,87 +304,91 @@ function LineElement({ index, lineName, stage }: LineElementProps) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Button
|
<div className={styles.wrapper}>
|
||||||
color={isSelected ? undefined : "gray"}
|
<Button
|
||||||
variant={isSelected ? "surface" : "soft"}
|
className={styles.stage}
|
||||||
radius="1"
|
color={isSelected ? undefined : "gray"}
|
||||||
className={styles.stage}
|
variant={isSelected ? "surface" : "soft"}
|
||||||
onClick={() => {
|
radius="1"
|
||||||
Tankopedia.mutate((draft) => {
|
onClick={() => {
|
||||||
const tankData = tank.tank!;
|
Tankopedia.mutate((draft) => {
|
||||||
|
const tankData = tank.tank!;
|
||||||
|
|
||||||
if (isAlternativeLine(lineName)) {
|
if (isAlternativeLine(lineName)) {
|
||||||
const originalLine = originalLineName(lineName)!;
|
const originalLine = originalLineName(lineName)!;
|
||||||
|
|
||||||
draft.protagonist.alternates[originalLine] = true;
|
draft.protagonist.alternates[originalLine] = true;
|
||||||
draft.protagonist.upgrades[lineName] = index;
|
draft.protagonist.upgrades[lineName] = index;
|
||||||
} else {
|
} else {
|
||||||
draft.protagonist.alternates[lineName] = false;
|
draft.protagonist.alternates[lineName] = false;
|
||||||
draft.protagonist.upgrades[lineName] = index;
|
draft.protagonist.upgrades[lineName] = index;
|
||||||
}
|
}
|
||||||
|
|
||||||
for (const required of stage.required_upgrades) {
|
for (const required of stage.required_upgrades) {
|
||||||
for (const line of tankData.upgrade_lines) {
|
for (const line of tankData.upgrade_lines) {
|
||||||
let i = 0;
|
let i = 0;
|
||||||
|
|
||||||
for (const candidateStage of line.stages) {
|
for (const candidateStage of line.stages) {
|
||||||
if (candidateStage.tech_name === required) {
|
if (candidateStage.tech_name === required) {
|
||||||
draft.protagonist.upgrades[line.name] = Math.max(
|
draft.protagonist.upgrades[line.name] = Math.max(
|
||||||
draft.protagonist.upgrades[line.name],
|
draft.protagonist.upgrades[line.name],
|
||||||
i,
|
i,
|
||||||
);
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
i++;
|
||||||
}
|
}
|
||||||
|
|
||||||
i++;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
for (const line of tankData.upgrade_lines) {
|
for (const line of tankData.upgrade_lines) {
|
||||||
if (draft.protagonist.alternates[line.name]) {
|
if (draft.protagonist.alternates[line.name]) {
|
||||||
continue;
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
let i = draft.protagonist.upgrades[line.name];
|
||||||
|
|
||||||
|
while (i > 0) {
|
||||||
|
const currentStage = line.stages[i];
|
||||||
|
|
||||||
|
const valid = currentStage.required_upgrades.every(
|
||||||
|
(required) => {
|
||||||
|
for (const otherLine of tankData.upgrade_lines) {
|
||||||
|
const idx = draft.protagonist.upgrades[otherLine.name];
|
||||||
|
|
||||||
|
if (otherLine.stages[idx]?.tech_name === required) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
|
if (valid) break;
|
||||||
|
|
||||||
|
i--;
|
||||||
|
}
|
||||||
|
|
||||||
|
draft.protagonist.upgrades[line.name] = i;
|
||||||
}
|
}
|
||||||
|
});
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<img
|
||||||
|
className={styles.icon}
|
||||||
|
src={`/api/tanks/modules/${stage.stage_type}.webp`}
|
||||||
|
/>
|
||||||
|
{/* {stage.display_name} */}
|
||||||
|
|
||||||
let i = draft.protagonist.upgrades[line.name];
|
<Text weight="light" lowContrast size="minor" className={styles.tier}>
|
||||||
|
{isAlternativeLine(lineName)
|
||||||
while (i > 0) {
|
? strings.tanks.loadout.alternative
|
||||||
const currentStage = line.stages[i];
|
: romanize(stage.number)}
|
||||||
|
</Text>
|
||||||
const valid = currentStage.required_upgrades.every((required) => {
|
</Button>
|
||||||
for (const otherLine of tankData.upgrade_lines) {
|
|
||||||
const idx = draft.protagonist.upgrades[otherLine.name];
|
|
||||||
|
|
||||||
if (otherLine.stages[idx]?.tech_name === required) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
});
|
|
||||||
|
|
||||||
if (valid) break;
|
|
||||||
|
|
||||||
i--;
|
|
||||||
}
|
|
||||||
|
|
||||||
draft.protagonist.upgrades[line.name] = i;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<img
|
|
||||||
className={styles.icon}
|
|
||||||
src={`/api/tanks/modules/${stage.stage_type}.webp`}
|
|
||||||
/>
|
|
||||||
{/* {stage.display_name} */}
|
|
||||||
|
|
||||||
<Text weight="light" lowContrast size="minor" className={styles.tier}>
|
|
||||||
{isAlternativeLine(lineName)
|
|
||||||
? strings.tanks.loadout.alternative
|
|
||||||
: romanize(stage.number)}
|
|
||||||
</Text>
|
|
||||||
|
|
||||||
{price && <Price className={styles.price} price={price} />}
|
{price && <Price className={styles.price} price={price} />}
|
||||||
</Button>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@@ -1,10 +1,11 @@
|
|||||||
|
import type { TankCatalogComponent } from "@protos/blitz_static_tank_component";
|
||||||
import { api } from "../api/dynamic";
|
import { api } from "../api/dynamic";
|
||||||
import { useAwait } from "./useAwait";
|
import { useAwait } from "./useAwait";
|
||||||
|
|
||||||
export function useEquipment(presetId: string, priceId: string) {
|
export function useEquipment(tank: TankCatalogComponent) {
|
||||||
const equipment = useAwait(() => api.equipment(), "equipment");
|
const equipment = useAwait(() => api.equipment(), "equipment");
|
||||||
const preset = equipment.presets[presetId];
|
const preset = equipment.presets[tank.equipment_preset_catalog_id];
|
||||||
const price = equipment.prices[priceId];
|
const price = equipment.prices[tank.equipment_price_preset_catalog_id];
|
||||||
|
|
||||||
return { preset, price, equipment };
|
return { preset, price, equipments: equipment.equipments };
|
||||||
}
|
}
|
||||||
Reference in new issue
Block a user