diff --git a/.vscode/settings.json b/.vscode/settings.json index a8be47c2a..b31a7bf35 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -96,6 +96,7 @@ "fullstats", "fuzzysort", "gamemode", + "gamemodes", "gameplay", "glsl", "GLTF", diff --git a/packages/i18n/strings/en.json b/packages/i18n/strings/en.json index 062790b93..2696d8665 100644 --- a/packages/i18n/strings/en.json +++ b/packages/i18n/strings/en.json @@ -98,6 +98,10 @@ } }, + "game_modes": { + "title": "Game mode abilities" + }, + "navigation": { "tank": "Tank", "characteristics": "Characteristics" diff --git a/packages/website/src/components/GameModeSection/index.module.css b/packages/website/src/components/GameModeSection/index.module.css new file mode 100644 index 000000000..2d023d358 --- /dev/null +++ b/packages/website/src/components/GameModeSection/index.module.css @@ -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; + } + } + } + } + } + } +} diff --git a/packages/website/src/components/GameModeSection/index.tsx b/packages/website/src/components/GameModeSection/index.tsx new file mode 100644 index 000000000..844a1ef17 --- /dev/null +++ b/packages/website/src/components/GameModeSection/index.tsx @@ -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 ( +
+ {strings.tanks.game_modes.title} + +
+ {roles.map(([id, value]) => { + const gameMode = gameDefinitions.gameModes[id]; + const role = gameDefinitions.roles[value]; + const banner = alias("api", `/gamemodes/${id}/banner.webp`); + + return ( +
+
+ +
+ + {unwrap(gameMode.name!)} + + +
+ {role.provisions.map((id) => { + const provisions = provisionDefinitions.provisions[id]; + + return ( + + ); + })} + + {role.consumables.map((id) => { + const consumable = consumableDefinitions.consumables[id]; + + return ( + + ); + })} +
+
+
+ ); + })} +
+
+ ); +} + +function Ability({ icon, name }: { icon: string; name: string }) { + return ( + + {name} + {name} + + ); +} diff --git a/packages/website/src/components/Tankopedia/GameModeSection.tsx b/packages/website/src/components/Tankopedia/GameModeSection.tsx deleted file mode 100644 index a095138e5..000000000 --- a/packages/website/src/components/Tankopedia/GameModeSection.tsx +++ /dev/null @@ -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 ( - - - {strings.website.tools.tankopedia.game_modes.title} - - - - {roles.map(([id, value]) => { - const gameMode = gameDefinitions.gameModes[id]; - - return ( - - - - - - {unwrap(gameMode.name!)} - - - - {gameDefinitions.roles[value].provisions.map((id) => { - const provisions = provisionDefinitions.provisions[id]; - - return ( - - - {unwrap(provisions.name!)} - {unwrap(provisions.name!)} - - - ); - })} - - {gameDefinitions.roles[value].consumables.map((id) => { - const consumable = consumableDefinitions.consumables[id]; - - return ( - - - {unwrap(consumable.name!)} - {unwrap(consumable.name!)} - - - ); - })} - - - - ); - })} - - - ); -} diff --git a/packages/website/src/pages/[...chunk_default]/[...locale]/tanks/[slug]/_index.tsx b/packages/website/src/pages/[...chunk_default]/[...locale]/tanks/[slug]/_index.tsx index 67f6f637d..0d598afe1 100644 --- a/packages/website/src/pages/[...chunk_default]/[...locale]/tanks/[slug]/_index.tsx +++ b/packages/website/src/pages/[...chunk_default]/[...locale]/tanks/[slug]/_index.tsx @@ -3,6 +3,7 @@ import { api } from "../../../../../api/dynamic"; import type { ThicknessRange } from "../../../../../components/StaticArmor"; import { TankopediaCharacteristics } from "../../../../../components/TankopediaCharacteristics"; import { TankopediaLoadout } from "../../../../../components/TankopediaLoadout"; +import { GameModeSection } from "../../../../../components/GameModeSection"; import { defaultEqualizer } from "../../../../../config/equalizer"; import { withErrorWrapper } from "../../../../../hocs/withErrorWrapper"; import { withLocale } from "../../../../../hocs/withLocale"; @@ -58,6 +59,7 @@ export const Page = withErrorWrapper(
{/* {!skeleton && } */} +
);