diff --git a/cspell.json b/cspell.json index ba729b144..edc0cd11e 100644 --- a/cspell.json +++ b/cspell.json @@ -6,6 +6,7 @@ "uasset", "oodle", "blitzkit", - "webp" + "webp", + "hocs" ] } \ No newline at end of file diff --git a/packages/i18n/strings/en.json b/packages/i18n/strings/en.json index 3aa611c5d..e6bd6a8e7 100644 --- a/packages/i18n/strings/en.json +++ b/packages/i18n/strings/en.json @@ -202,6 +202,20 @@ }, "tanks": { + "characteristics": { + "titles": { + "meta": "Meta", + "firepower": "Firepower", + "maneuverability": "Maneuverability", + "survivability": "Survivability" + } + }, + + "navigation": { + "tank": "Tank", + "characteristics": "Characteristics" + }, + "loadout": { "consumables": "Consumables", "modules": "Modules", diff --git a/packages/website-ue/src/components/TankopediaCharacteristics/index.module.css b/packages/website-ue/src/components/TankopediaCharacteristics/index.module.css new file mode 100644 index 000000000..e834eff75 --- /dev/null +++ b/packages/website-ue/src/components/TankopediaCharacteristics/index.module.css @@ -0,0 +1,56 @@ +.characteristics { + padding: var(--space-5); + padding-top: var(--space-6); + + display: flex; + flex-direction: column; + gap: var(--space-5); + box-sizing: border-box; + + max-height: 100%; + overflow-y: auto; + + &[data-visible="false"] { + display: none; + } + + .group { + display: flex; + flex-direction: column; + + gap: var(--space-4); + + .title-wrapper { + display: flex; + align-items: center; + gap: var(--space-4); + + .title { + .title-content { + display: flex; + align-items: center; + gap: var(--space-2); + + cursor: pointer; + + svg { + width: 1em; + height: 1em; + } + } + } + + .separator { + height: var(--space-1); + flex: 1; + + background-color: var(--gray-5); + } + } + + .content { + display: flex; + flex-direction: column; + } + } +} diff --git a/packages/website-ue/src/components/TankopediaCharacteristics/index.tsx b/packages/website-ue/src/components/TankopediaCharacteristics/index.tsx new file mode 100644 index 000000000..e96336710 --- /dev/null +++ b/packages/website-ue/src/components/TankopediaCharacteristics/index.tsx @@ -0,0 +1,62 @@ +import { CaretDownIcon, CaretRightIcon } from "@radix-ui/react-icons"; +import { + characteristicsOrder, + type CharacteristicRenderConfig, + type CharacteristicsGroup, +} from "../../tankopedia/characteristicsOrder"; +import styles from "./index.module.css"; +import { Heading } from "../Heading"; +import { Tankopedia, TankopediaTab } from "../../stores/tankopedia"; +import { useStrings } from "../../hooks/useStrings"; + +export function TankopediaCharacteristics() { + const isVisible = Tankopedia.use( + (state) => state.tab === TankopediaTab.Characteristics, + ); + + return ( +
+ {characteristicsOrder.map((group) => ( + + ))} +
+ ); +} + +function Group({ group, order }: CharacteristicsGroup) { + const isOpen = Tankopedia.use((state) => state.groups[group]); + const strings = useStrings(); + + return ( +
+
+ +
+ {isOpen ? : } + {strings.tanks.characteristics.titles[group]} +
+
+ +
+
+ +
+ {order.map((item) => + "toy" in item ? : , + )} +
+
+ ); +} + +interface ToyProps { + toy: string; +} + +function Toy({ toy }: ToyProps) { + return {toy}; +} + +function Item({ name }: CharacteristicRenderConfig) { + return {name}; +} diff --git a/packages/website-ue/src/components/TankopediaNavigation/index.module.css b/packages/website-ue/src/components/TankopediaNavigation/index.module.css new file mode 100644 index 000000000..9d3251994 --- /dev/null +++ b/packages/website-ue/src/components/TankopediaNavigation/index.module.css @@ -0,0 +1,20 @@ +.tabs { + display: flex; + + position: absolute; + top: 0; + left: 50%; + transform: translateX(-50%); + + .tab { + padding: var(--space-3) var(--space-5); + border-top: var(--space-2) solid transparent; + + cursor: pointer; + + &[data-selected="true"] { + background: linear-gradient(var(--accent-a4), transparent); + border-top: var(--space-2) solid var(--accent-9); + } + } +} diff --git a/packages/website-ue/src/components/TankopediaNavigation/index.tsx b/packages/website-ue/src/components/TankopediaNavigation/index.tsx new file mode 100644 index 000000000..a553eaa0b --- /dev/null +++ b/packages/website-ue/src/components/TankopediaNavigation/index.tsx @@ -0,0 +1,37 @@ +import { useStrings } from "../../hooks/useStrings"; +import { Tankopedia, TankopediaTab } from "../../stores/tankopedia"; +import { Text } from "../Text"; +import styles from "./index.module.css"; + +export function TankopediaNavigation() { + const strings = useStrings(); + const tab = Tankopedia.use((state) => state.tab); + + return ( +
+
{ + Tankopedia.mutate((draft) => { + draft.tab = TankopediaTab.Tank; + }); + }} + > + {strings.tanks.navigation.tank} +
+ +
{ + Tankopedia.mutate((draft) => { + draft.tab = TankopediaTab.Characteristics; + }); + }} + > + {strings.tanks.navigation.characteristics} +
+
+ ); +} diff --git a/packages/website-ue/src/components/TankopediaSandbox/index.module.css b/packages/website-ue/src/components/TankopediaSandbox/index.module.css index 2b50355e7..59f36b805 100644 --- a/packages/website-ue/src/components/TankopediaSandbox/index.module.css +++ b/packages/website-ue/src/components/TankopediaSandbox/index.module.css @@ -1,7 +1,11 @@ .sandbox { - position: relative; + position: absolute; + top: 0; + left: 0; + width: 100%; height: 100%; - .canvas { + &[data-visible="false"] { + display: none; } } diff --git a/packages/website-ue/src/components/TankopediaSandbox/index.tsx b/packages/website-ue/src/components/TankopediaSandbox/index.tsx index 1ac6162ec..7097ced63 100644 --- a/packages/website-ue/src/components/TankopediaSandbox/index.tsx +++ b/packages/website-ue/src/components/TankopediaSandbox/index.tsx @@ -2,11 +2,19 @@ import { Canvas, useLoader } from "@react-three/fiber"; import { OrbitControls } from "@react-three/drei"; import styles from "./index.module.css"; import { GLTFLoader } from "three-stdlib"; +import { Tankopedia } from "../../stores/tankopedia"; +import { TankopediaTab } from "../../stores/tankopedia"; export function TankopediaSandbox() { + const isVisible = Tankopedia.use((state) => state.tab === TankopediaTab.Tank); + return ( -
- +
+ {!import.meta.env.SSR && }
diff --git a/packages/website-ue/src/pages/[...locale]/tanks/[slug]/_index.module.css b/packages/website-ue/src/pages/[...locale]/tanks/[slug]/_index.module.css index 3b82456cf..196a19a2a 100644 --- a/packages/website-ue/src/pages/[...locale]/tanks/[slug]/_index.module.css +++ b/packages/website-ue/src/pages/[...locale]/tanks/[slug]/_index.module.css @@ -4,6 +4,8 @@ display: flex; .sandbox { + position: relative; + flex-grow: 1; background-color: black; } diff --git a/packages/website-ue/src/pages/[...locale]/tanks/[slug]/_index.tsx b/packages/website-ue/src/pages/[...locale]/tanks/[slug]/_index.tsx index 056344059..3459813dc 100644 --- a/packages/website-ue/src/pages/[...locale]/tanks/[slug]/_index.tsx +++ b/packages/website-ue/src/pages/[...locale]/tanks/[slug]/_index.tsx @@ -11,6 +11,8 @@ import { characteristicsOrder } from "../../../../tankopedia/characteristicsOrde import { computeCharacteristics } from "../../../../tankopedia/computeCharacteristics"; import styles from "./_index.module.css"; import { TankopediaSandbox } from "../../../../components/TankopediaSandbox"; +import { TankopediaNavigation } from "../../../../components/TankopediaNavigation"; +import { TankopediaCharacteristics } from "../../../../components/TankopediaCharacteristics"; interface PageProps { id: string; @@ -41,6 +43,8 @@ export const Page = withErrorWrapper(
+ +
diff --git a/packages/website-ue/src/stores/tankopedia.ts b/packages/website-ue/src/stores/tankopedia.ts index 74cc2d66e..e1c1c4e8b 100644 --- a/packages/website-ue/src/stores/tankopedia.ts +++ b/packages/website-ue/src/stores/tankopedia.ts @@ -2,9 +2,13 @@ import type { Tank } from "@protos/tank"; import { Varuna } from "varuna"; import { createTankState } from "../tankopedia/createTankState"; import { type TankState } from "../tankopedia/tankState"; +import { characteristicsOrder } from "../tankopedia/characteristicsOrder"; interface Tankopedia { compare: TankopediaCompare; + tab: TankopediaTab; + groups: Record; + protagonist: TankState; } @@ -14,7 +18,21 @@ export enum TankopediaCompare { All, } +export enum TankopediaTab { + Tank, + Characteristics, +} + +const groups: Record = {}; + +for (const { group } of characteristicsOrder) { + groups[group] = true; +} + export const Tankopedia = new Varuna((tank) => ({ compare: TankopediaCompare.TierAndClass, + tab: TankopediaTab.Characteristics, + groups, + protagonist: createTankState(tank), })); diff --git a/packages/website-ue/src/tankopedia/characteristicsOrder.tsx b/packages/website-ue/src/tankopedia/characteristicsOrder.tsx index 5d778f2fe..00bd51877 100644 --- a/packages/website-ue/src/tankopedia/characteristicsOrder.tsx +++ b/packages/website-ue/src/tankopedia/characteristicsOrder.tsx @@ -29,7 +29,7 @@ export interface CharacteristicRenderConfig { }) => ReactNode; } -type CharacteristicsOrder = { +export type CharacteristicsGroup = { group: string; order: ( | CharacteristicRenderConfig @@ -37,9 +37,9 @@ type CharacteristicsOrder = { toy: string; } )[]; -}[]; +}; -export const characteristicsOrder: CharacteristicsOrder = [ +export const characteristicsOrder: CharacteristicsGroup[] = [ { group: "meta", order: [