mirror of
https://github.com/blitzkit/blitzkit.git
synced 2026-10-21 10:47:04 +02:00
game mode abilities
This commit is contained in:
1 parent
5c482e0bac
commit
53eebc7a43
6 files changed
+164
-122
No files matched your search
Vendored
+1
@@ -96,6 +96,7 @@
|
|||||||
"fullstats",
|
"fullstats",
|
||||||
"fuzzysort",
|
"fuzzysort",
|
||||||
"gamemode",
|
"gamemode",
|
||||||
|
"gamemodes",
|
||||||
"gameplay",
|
"gameplay",
|
||||||
"glsl",
|
"glsl",
|
||||||
"GLTF",
|
"GLTF",
|
||||||
|
|||||||
@@ -98,6 +98,10 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
|
"game_modes": {
|
||||||
|
"title": "Game mode abilities"
|
||||||
|
},
|
||||||
|
|
||||||
"navigation": {
|
"navigation": {
|
||||||
"tank": "Tank",
|
"tank": "Tank",
|
||||||
"characteristics": "Characteristics"
|
"characteristics": "Characteristics"
|
||||||
|
|||||||
@@ -0,0 +1,64 @@
|
|||||||
|
.section {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
align-items: center;
|
||||||
|
gap: var(--space-5);
|
||||||
|
padding: var(--space-4);
|
||||||
|
|
||||||
|
.cards {
|
||||||
|
display: flex;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
justify-content: center;
|
||||||
|
gap: var(--space-4);
|
||||||
|
width: 100%;
|
||||||
|
|
||||||
|
.card {
|
||||||
|
width: 16rem;
|
||||||
|
height: 20rem;
|
||||||
|
display: flex;
|
||||||
|
flex: 0 0 auto;
|
||||||
|
flex-direction: column;
|
||||||
|
overflow: hidden;
|
||||||
|
border-radius: var(--space-3);
|
||||||
|
background-size: cover;
|
||||||
|
background-position: center;
|
||||||
|
|
||||||
|
.banner {
|
||||||
|
flex: 1;
|
||||||
|
background-size: cover;
|
||||||
|
background-position: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.info {
|
||||||
|
display: flex;
|
||||||
|
min-height: 6.125rem;
|
||||||
|
flex-direction: column;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
gap: var(--space-2);
|
||||||
|
padding: var(--space-3);
|
||||||
|
backdrop-filter: blur(4rem);
|
||||||
|
-webkit-backdrop-filter: blur(4rem);
|
||||||
|
|
||||||
|
.abilities {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
align-items: flex-start;
|
||||||
|
|
||||||
|
.ability {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: var(--space-1);
|
||||||
|
white-space: nowrap;
|
||||||
|
|
||||||
|
img {
|
||||||
|
width: 1.5em;
|
||||||
|
height: 1.5em;
|
||||||
|
object-fit: contain;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,93 @@
|
|||||||
|
import { alias } from "@blitzkit/core";
|
||||||
|
import { api } from "../../api/dynamic";
|
||||||
|
import { DuelModule, useDuel } from "../../hooks/useDuel";
|
||||||
|
import { useStrings } from "../../hooks/useStrings";
|
||||||
|
import { useUnwrapper } from "../../hooks/useUnwrapper";
|
||||||
|
import { Heading } from "../Heading";
|
||||||
|
import { Text } from "../Text";
|
||||||
|
import styles from "./index.module.css";
|
||||||
|
|
||||||
|
const [gameDefinitions, consumableDefinitions, provisionDefinitions, tanks] =
|
||||||
|
await Promise.all([
|
||||||
|
api.game(),
|
||||||
|
api.consumables(),
|
||||||
|
api.provisions(),
|
||||||
|
api.tanks(),
|
||||||
|
]);
|
||||||
|
|
||||||
|
export function GameModeSection() {
|
||||||
|
const unwrap = useUnwrapper();
|
||||||
|
const strings = useStrings();
|
||||||
|
const tank = useDuel("protagonist", DuelModule.Tank);
|
||||||
|
const roles = Object.entries(tank.roles);
|
||||||
|
|
||||||
|
if (roles.length === 0) return null;
|
||||||
|
|
||||||
|
return (
|
||||||
|
<section className={styles.section}>
|
||||||
|
<Heading size="3">{strings.tanks.game_modes.title}</Heading>
|
||||||
|
|
||||||
|
<div className={styles.cards}>
|
||||||
|
{roles.map(([id, value]) => {
|
||||||
|
const gameMode = gameDefinitions.gameModes[id];
|
||||||
|
const role = gameDefinitions.roles[value];
|
||||||
|
const banner = alias("api", `/gamemodes/${id}/banner.webp`);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<article
|
||||||
|
key={id}
|
||||||
|
className={styles.card}
|
||||||
|
style={{ backgroundImage: `url(${banner})` }}
|
||||||
|
>
|
||||||
|
<div
|
||||||
|
className={styles.banner}
|
||||||
|
style={{ backgroundImage: `url(${banner})` }}
|
||||||
|
/>
|
||||||
|
|
||||||
|
<div className={styles.info}>
|
||||||
|
<Text size="major" weight="bold" align="center">
|
||||||
|
{unwrap(gameMode.name!)}
|
||||||
|
</Text>
|
||||||
|
|
||||||
|
<div className={styles.abilities}>
|
||||||
|
{role.provisions.map((id) => {
|
||||||
|
const provisions = provisionDefinitions.provisions[id];
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Ability
|
||||||
|
key={`provision-${id}`}
|
||||||
|
icon={alias("api", `/icons/provisions/${id}.webp`)}
|
||||||
|
name={unwrap(provisions.name!)}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
})}
|
||||||
|
|
||||||
|
{role.consumables.map((id) => {
|
||||||
|
const consumable = consumableDefinitions.consumables[id];
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Ability
|
||||||
|
key={`consumable-${id}`}
|
||||||
|
icon={alias("api", `/icons/consumables/${id}.webp`)}
|
||||||
|
name={unwrap(consumable.name!)}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
})}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</article>
|
||||||
|
);
|
||||||
|
})}
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
function Ability({ icon, name }: { icon: string; name: string }) {
|
||||||
|
return (
|
||||||
|
<Text lowContrast className={styles.ability}>
|
||||||
|
<img src={icon} alt={name} />
|
||||||
|
{name}
|
||||||
|
</Text>
|
||||||
|
);
|
||||||
|
}
|
||||||
@@ -1,122 +0,0 @@
|
|||||||
import { alias } from "@blitzkit/core";
|
|
||||||
import { Box, Flex, Heading, Text } from "@radix-ui/themes";
|
|
||||||
import { api } from "../../api/dynamic";
|
|
||||||
import { useLocale } from "../../hooks/useLocale";
|
|
||||||
import { Duel } from "../../stores/duel";
|
|
||||||
|
|
||||||
const [gameDefinitions, consumableDefinitions, provisionDefinitions] =
|
|
||||||
await Promise.all([api.game(), api.consumables(), api.provisions()]);
|
|
||||||
|
|
||||||
export function GameModeSection() {
|
|
||||||
const { unwrap, strings } = useLocale();
|
|
||||||
const tank = Duel.use((state) => state.protagonist.tank);
|
|
||||||
const roles = Object.entries(tank.roles);
|
|
||||||
|
|
||||||
if (roles.length === 0) return null;
|
|
||||||
|
|
||||||
return (
|
|
||||||
<Flex direction="column" gap="4" align="center">
|
|
||||||
<Heading size="6">
|
|
||||||
{strings.website.tools.tankopedia.game_modes.title}
|
|
||||||
</Heading>
|
|
||||||
|
|
||||||
<Flex justify="center" gap="4" wrap="wrap" px="4">
|
|
||||||
{roles.map(([id, value]) => {
|
|
||||||
const gameMode = gameDefinitions.gameModes[id];
|
|
||||||
|
|
||||||
return (
|
|
||||||
<Flex
|
|
||||||
key={id}
|
|
||||||
width="16rem"
|
|
||||||
height="20rem"
|
|
||||||
overflow="hidden"
|
|
||||||
direction="column"
|
|
||||||
style={{
|
|
||||||
borderRadius: "var(--radius-3)",
|
|
||||||
background: `url(${alias(
|
|
||||||
"api",
|
|
||||||
`/gamemodes/${id}/banner.webp`,
|
|
||||||
)})`,
|
|
||||||
backgroundSize: "cover",
|
|
||||||
backgroundPosition: "center",
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<Box
|
|
||||||
flexGrow="1"
|
|
||||||
style={{
|
|
||||||
background: `url(${alias(
|
|
||||||
"api",
|
|
||||||
`/gamemodes/${id}/banner.webp`,
|
|
||||||
)})`,
|
|
||||||
backgroundSize: "cover",
|
|
||||||
backgroundPosition: "center",
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
|
|
||||||
<Flex
|
|
||||||
p="3"
|
|
||||||
direction="column"
|
|
||||||
height="98px"
|
|
||||||
flexShrink="0"
|
|
||||||
style={{
|
|
||||||
backdropFilter: "blur(4rem)",
|
|
||||||
WebkitBackdropFilter: "blur(4rem)",
|
|
||||||
}}
|
|
||||||
align="center"
|
|
||||||
justify="center"
|
|
||||||
>
|
|
||||||
<Text size="4" weight="bold">
|
|
||||||
{unwrap(gameMode.name!)}
|
|
||||||
</Text>
|
|
||||||
|
|
||||||
<Flex direction="column">
|
|
||||||
{gameDefinitions.roles[value].provisions.map((id) => {
|
|
||||||
const provisions = provisionDefinitions.provisions[id];
|
|
||||||
|
|
||||||
return (
|
|
||||||
<Text color="gray" wrap="nowrap" key={id}>
|
|
||||||
<Flex align="center" gap="1">
|
|
||||||
<img
|
|
||||||
style={{
|
|
||||||
width: "1.5em",
|
|
||||||
height: "1.5em",
|
|
||||||
objectFit: "contain",
|
|
||||||
}}
|
|
||||||
src={alias("api", `/icons/provisions/${id}.webp`)}
|
|
||||||
alt={unwrap(provisions.name!)}
|
|
||||||
/>
|
|
||||||
{unwrap(provisions.name!)}
|
|
||||||
</Flex>
|
|
||||||
</Text>
|
|
||||||
);
|
|
||||||
})}
|
|
||||||
|
|
||||||
{gameDefinitions.roles[value].consumables.map((id) => {
|
|
||||||
const consumable = consumableDefinitions.consumables[id];
|
|
||||||
|
|
||||||
return (
|
|
||||||
<Text color="gray" wrap="nowrap" key={id}>
|
|
||||||
<Flex align="center" gap="1">
|
|
||||||
<img
|
|
||||||
style={{
|
|
||||||
width: "1.5em",
|
|
||||||
height: "1.5em",
|
|
||||||
objectFit: "contain",
|
|
||||||
}}
|
|
||||||
src={alias("api", `/icons/consumables/${id}.webp`)}
|
|
||||||
alt={unwrap(consumable.name!)}
|
|
||||||
/>
|
|
||||||
{unwrap(consumable.name!)}
|
|
||||||
</Flex>
|
|
||||||
</Text>
|
|
||||||
);
|
|
||||||
})}
|
|
||||||
</Flex>
|
|
||||||
</Flex>
|
|
||||||
</Flex>
|
|
||||||
);
|
|
||||||
})}
|
|
||||||
</Flex>
|
|
||||||
</Flex>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
@@ -3,6 +3,7 @@ import { api } from "../../../../../api/dynamic";
|
|||||||
import type { ThicknessRange } from "../../../../../components/StaticArmor";
|
import type { ThicknessRange } from "../../../../../components/StaticArmor";
|
||||||
import { TankopediaCharacteristics } from "../../../../../components/TankopediaCharacteristics";
|
import { TankopediaCharacteristics } from "../../../../../components/TankopediaCharacteristics";
|
||||||
import { TankopediaLoadout } from "../../../../../components/TankopediaLoadout";
|
import { TankopediaLoadout } from "../../../../../components/TankopediaLoadout";
|
||||||
|
import { GameModeSection } from "../../../../../components/GameModeSection";
|
||||||
import { defaultEqualizer } from "../../../../../config/equalizer";
|
import { defaultEqualizer } from "../../../../../config/equalizer";
|
||||||
import { withErrorWrapper } from "../../../../../hocs/withErrorWrapper";
|
import { withErrorWrapper } from "../../../../../hocs/withErrorWrapper";
|
||||||
import { withLocale } from "../../../../../hocs/withLocale";
|
import { withLocale } from "../../../../../hocs/withLocale";
|
||||||
@@ -58,6 +59,7 @@ export const Page = withErrorWrapper(
|
|||||||
<div className={styles.sandbox}>
|
<div className={styles.sandbox}>
|
||||||
{/* {!skeleton && <TankopediaSandbox thicknessRange={thicknessRange} />} */}
|
{/* {!skeleton && <TankopediaSandbox thicknessRange={thicknessRange} />} */}
|
||||||
<TankopediaCharacteristics characteristics={characteristics} />
|
<TankopediaCharacteristics characteristics={characteristics} />
|
||||||
|
<GameModeSection />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
|||||||
Reference in new issue
Block a user