From 73de6e35214835b2ba5e896bbfddf78465330cd2 Mon Sep 17 00:00:00 2001 From: tresabhi <43380238+tresabhi@users.noreply.github.com> Date: Mon, 1 Jun 2026 13:48:16 -0500 Subject: [PATCH] new basic layout --- .../index.module.css | 114 +++++++------- .../TankopediaCharacteristics/index.tsx | 64 ++++---- .../pages/[...locale]/tanks/[slug]/_index.tsx | 63 +------- .../[...locale]/tanks/[slug]/index.astro | 1 + .../src/tankopedia/characteristics.ts | 56 +++++++ .../src/tankopedia/characteristicsOrder.tsx | 142 +++++++++++++----- 6 files changed, 254 insertions(+), 186 deletions(-) diff --git a/packages/website-ue/src/components/TankopediaCharacteristics/index.module.css b/packages/website-ue/src/components/TankopediaCharacteristics/index.module.css index 8b7773572..fd0a5a77c 100644 --- a/packages/website-ue/src/components/TankopediaCharacteristics/index.module.css +++ b/packages/website-ue/src/components/TankopediaCharacteristics/index.module.css @@ -1,24 +1,37 @@ .characteristics { + --cell-width: 2.5rem; + --group-span: 7; + --inner-padding: var(--space-4); + + display: grid; + grid-auto-rows: var(--cell-width); + grid-template-columns: repeat(auto-fill, minmax(var(--cell-width), 1fr)); + grid-auto-flow: dense; + padding: var(--space-5); + gap: var(--space-4); - display: flex; - flex-direction: column; - gap: var(--space-5); box-sizing: border-box; .group { - display: flex; - flex-direction: column; + display: grid; + grid-template-columns: 1fr; - gap: var(--space-4); + grid-column: span var(--group-span); + gap: inherit; .title-wrapper { + background-color: var(--amber-a3); + grid-row: span 1; + + padding: 0 var(--inner-padding); + display: flex; align-items: center; - gap: var(--space-4); + gap: var(--space-3); .title { - .title-content { + .content { display: flex; align-items: center; gap: var(--space-2); @@ -31,67 +44,60 @@ } } } - - .separator { - height: var(--space-1); - flex: 1; - - background-color: var(--gray-5); - } } - .content { - --cell-width: 2rem; - --toy-span: 6; + .item { + padding: 0 var(--inner-padding); - display: grid; - grid-auto-rows: var(--cell-width); - grid-template-columns: repeat(auto-fill, minmax(var(--cell-width), 1fr)); - grid-auto-flow: row dense; - gap: var(--space-4); + grid-row: span 1; - .item { - grid-row: span 1; - grid-column: span var(--toy-span); + display: flex; + flex-direction: column; + justify-content: center; + gap: var(--space-2); + .value { display: flex; - flex-direction: column; - justify-content: center; - gap: var(--space-2); + justify-content: space-between; + } - .value { - display: flex; - justify-content: space-between; - } + .ranking { + display: flex; + align-items: center; + gap: var(--space-3); - .ranking { - display: flex; - align-items: center; - gap: var(--space-3); + .bar-wrapper { + flex: 1; + height: var(--space-1); - .bar-wrapper { - flex: 1; - height: var(--space-1); + background-color: var(--gray-3); + border-radius: var(--radius-max); + overflow: hidden; - background-color: var(--gray-3); - border-radius: var(--radius-max); - overflow: hidden; - - .bar { - background-color: var(--jade-9); - width: 75%; - height: 100%; - } + .bar { + background-color: var(--jade-9); + width: 75%; + height: 100%; } } } + } - .toy { - grid-row: span var(--toy-span); - grid-column: span var(--toy-span); + .toy { + grid-row: span var(--group-span); + padding: var(--inner-padding); - background-color: var(--gray-3); - border: var(--gray-5) solid var(--space-1); + .content { + background-color: green; + width: 100%; + height: 100%; + + display: flex; + align-items: center; + justify-content: center; + + background-color: var(--gray-2); + outline: var(--gray-5) solid var(--space-1); border-radius: var(--space-3); } diff --git a/packages/website-ue/src/components/TankopediaCharacteristics/index.tsx b/packages/website-ue/src/components/TankopediaCharacteristics/index.tsx index 6af504f42..d753ceba0 100644 --- a/packages/website-ue/src/components/TankopediaCharacteristics/index.tsx +++ b/packages/website-ue/src/components/TankopediaCharacteristics/index.tsx @@ -1,7 +1,6 @@ -import { CaretDownIcon, CaretRightIcon } from "@radix-ui/react-icons"; +import { GearIcon } from "@radix-ui/react-icons"; import { useCharacteristicRenderer } from "../../hooks/useCharacteristicRenderer"; import { useStrings } from "../../hooks/useStrings"; -import { Tankopedia } from "../../stores/tankopedia"; import type { CharacteristicOutput } from "../../tankopedia/characteristics"; import { characteristicsOrder, @@ -9,7 +8,6 @@ import { type CharacteristicsGroup, } from "../../tankopedia/characteristicsOrder"; import type { ComputedCharacteristics } from "../../tankopedia/computeCharacteristics"; -import { Heading } from "../Heading"; import { Text } from "../Text"; import styles from "./index.module.css"; @@ -35,35 +33,35 @@ interface GroupProps { } function Group({ group, characteristics }: GroupProps) { - const isOpen = Tankopedia.use((state) => state.groups[group.group]); const strings = useStrings(); + const toys = group.order.filter((item) => "toy" in item).length; + const items = group.order.filter((item) => "name" in item).length; + const span = `calc(${toys} * var(--group-span) + ${items} + 1)`; return ( -
+
- -
- {isOpen ? : } - { - (strings.tanks.characteristics.titles as Record)[ - group.group - ] - } + +
+ {group.group} +
- - -
+
-
- {group.order.map((item) => - "toy" in item ? ( - - ) : ( - - ), - )} -
+ {group.order.map((item) => + "toy" in item ? ( + + ) : ( + + ), + )}
); } @@ -80,13 +78,7 @@ function Item({ config, value }: ItemProps) { return (
- - { - (strings.tanks.characteristics.items as Record)[ - config.name - ] - } - + {config.name} {renderCharacteristic(value, config)}
@@ -108,5 +100,11 @@ interface ToyProps { } function Toy({ toy }: ToyProps) { - return ; + return ( +
+
+ {toy} toy +
+
+ ); } 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 a3c30a4c7..023ff37c2 100644 --- a/packages/website-ue/src/pages/[...locale]/tanks/[slug]/_index.tsx +++ b/packages/website-ue/src/pages/[...locale]/tanks/[slug]/_index.tsx @@ -1,4 +1,4 @@ -import { Fragment, useMemo } from "react"; +import { useMemo } from "react"; import { api } from "../../../../api/dynamic"; import { TankopediaCharacteristics } from "../../../../components/TankopediaCharacteristics"; import { TankopediaLoadout } from "../../../../components/TankopediaLoadout"; @@ -6,10 +6,8 @@ import { TankopediaSandbox } from "../../../../components/TankopediaSandbox"; import { withErrorWrapper } from "../../../../hocs/withErrorWrapper"; import { withLocale } from "../../../../hocs/withLocale"; import { useAwait } from "../../../../hooks/useAwait"; -import { useCharacteristicRenderer } from "../../../../hooks/useCharacteristicRenderer"; import { useEquipment } from "../../../../hooks/useEquipment"; import { Tankopedia } from "../../../../stores/tankopedia"; -import { characteristicsOrder } from "../../../../tankopedia/characteristicsOrder"; import { computeCharacteristics } from "../../../../tankopedia/computeCharacteristics"; import styles from "./_index.module.css"; @@ -50,62 +48,3 @@ export const Page = withErrorWrapper( ); }), ); - -export const _Page = withErrorWrapper( - withLocale(({ id }) => { - const protagonistTank = useAwait(() => api.tank(id), `tank-${id}`); - - Tankopedia.useInitialization(protagonistTank); - - const renderCharacteristic = useCharacteristicRenderer(); - - const protagonist = Tankopedia.use((state) => state.protagonist); - const protagonistEquipment = useEquipment(protagonistTank.tank!); - - const { characteristics } = useMemo( - () => - computeCharacteristics( - protagonistTank, - protagonistEquipment, - protagonist, - ), - [protagonist], - ); - - return ( - <> -

{protagonist.id}

- -
- - - -

characteristics

- - {characteristicsOrder.map((group) => { - return ( - -

{group.group}

- - {group.order.map((item) => { - if ("toy" in item) { - return toy: {item.toy}; - } - - const value = characteristics[item.name]; - - if (value == null) return null; - - return ( - - {item.name}: {renderCharacteristic(value, item)} - - ); - })} -
- ); - })} - - ); - }), -); diff --git a/packages/website-ue/src/pages/[...locale]/tanks/[slug]/index.astro b/packages/website-ue/src/pages/[...locale]/tanks/[slug]/index.astro index e41516244..2e2577c7c 100644 --- a/packages/website-ue/src/pages/[...locale]/tanks/[slug]/index.astro +++ b/packages/website-ue/src/pages/[...locale]/tanks/[slug]/index.astro @@ -23,6 +23,7 @@ const { id, locale } = Astro.props; + diff --git a/packages/website-ue/src/tankopedia/characteristics.ts b/packages/website-ue/src/tankopedia/characteristics.ts index c6897a338..0741d9891 100644 --- a/packages/website-ue/src/tankopedia/characteristics.ts +++ b/packages/website-ue/src/tankopedia/characteristics.ts @@ -419,4 +419,60 @@ export const characteristics = { compensation({ tank }) { return tank.compensation!.compensation?.currency_reward?.amount ?? null; }, + + purchase_price() { + return -Infinity; + }, + + upgrade_price() { + return -Infinity; + }, + + research_level() { + return -Infinity; + }, + + crew_xp_multiplier() { + return -Infinity; + }, + + clipping_potential() { + return -Infinity; + }, + + burst_size() { + return -Infinity; + }, + + intra_burst() { + return -Infinity; + }, + + dispersion_angle() { + return -Infinity; + }, + + gun_yaw_range() { + return -Infinity; + }, + + brake_force() { + return -Infinity; + }, + + gun_traverse_speed() { + return -Infinity; + }, + + fire_health_burn() { + return -Infinity; + }, + + ramming_resistance() { + return -Infinity; + }, + + width() { + return -Infinity; + }, } satisfies Record; diff --git a/packages/website-ue/src/tankopedia/characteristicsOrder.tsx b/packages/website-ue/src/tankopedia/characteristicsOrder.tsx index d33885532..982980dc0 100644 --- a/packages/website-ue/src/tankopedia/characteristicsOrder.tsx +++ b/packages/website-ue/src/tankopedia/characteristicsOrder.tsx @@ -29,19 +29,25 @@ export interface CharacteristicRenderConfig { }) => ReactNode; } +export interface ToyRenderConfig { + toy: string; +} + export type CharacteristicsGroup = { group: string; - order: ( - | CharacteristicRenderConfig - | { - toy: string; - } - )[]; + render: CharacteristicsGroupRender; + order: (CharacteristicRenderConfig | ToyRenderConfig)[]; }; +export enum CharacteristicsGroupRender { + Flashy, + Statistical, +} + export const characteristicsOrder: CharacteristicsGroup[] = [ { group: "meta", + render: CharacteristicsGroupRender.Flashy, order: [ { name: "name", @@ -80,15 +86,29 @@ export const characteristicsOrder: CharacteristicsGroup[] = [ return strings.tiers[name as keyof typeof strings.tiers]; }, }, - { name: "compensation" }, { name: "id" }, { name: "slug" }, ], }, + { - group: "firepower", + group: "economics", + render: CharacteristicsGroupRender.Statistical, + order: [ + { name: "purchase_price" }, + { name: "compensation" }, + { name: "upgrade_price" }, + { name: "research_level" }, + { name: "crew_xp_multiplier" }, + + // TODO: investigate ATTRIBUTE_NAME_CREW_XP_MULTIPLIER + ], + }, + + { + group: "gun", + render: CharacteristicsGroupRender.Statistical, order: [ - { toy: "reload" }, { name: "gun_type", render({ output }) { @@ -96,75 +116,123 @@ export const characteristicsOrder: CharacteristicsGroup[] = [ }, }, { name: "dpm", decimals: 0, units: "hp_min" }, + { name: "damage", units: "hp" }, + { name: "module_damage", units: "hp" }, { name: "reload", decimals: 2, units: "s" }, { name: "reloads", decimals: 2, units: "s" }, - { name: "damage", units: "hp" }, - { name: "module_damage", units: "hp" }, + { toy: "reload" }, + ], + }, + + { + group: "clip", + render: CharacteristicsGroupRender.Statistical, + order: [ + { name: "clipping_potential" }, { name: "clip_size" }, + { name: "optimal_shell" }, { name: "intra_clip", decimals: 2, units: "s" }, - // { name: "burst_size" }, // TODO: implement burst size - // { name: 'intra_burst', decimals: 2, units: "s" }, // TODO: implement intra burst + { name: "burst_size" }, + { name: "intra_burst", decimals: 2, units: "s" }, + // TODO: investigate ATTRIBUTE_NAME_SHELLS_SLOTS // TODO: investigate ATTRIBUTE_NAME_RELOAD_SPEED_SCALE // TODO: investigate ATTRIBUTE_NAME_AVERAGE_THICKNESS + // TODO: investigate ATTRIBUTE_NAME_TRACER_SHELLS_OBSERVATION_TIMEOUT + ], + }, - // { toy: "ricochet" }, + { + group: "shell", + render: CharacteristicsGroupRender.Statistical, + order: [ { name: "penetration", units: "mm" }, + { name: "shell_velocity", units: "m_s" }, + { name: "shell_range", units: "m" }, + { name: "shell_capacity" }, { name: "caliber", units: "mm" }, { name: "normalization", units: "deg" }, { name: "ricochet", units: "deg" }, - { name: "shell_velocity", units: "m_s" }, - { name: "shell_range", units: "m" }, - { name: "shell_capacity" }, - - // { toy: "aim_time" }, - { name: "aim_time", decimals: 1, units: "s" }, - { name: "dispersion", decimals: 3, units: "m" }, - // { name: "dispersion_angle", decimals: 3, units: "m" }, // TODO: implement dispersion angle - - // { toy: "flexibility" }, - { name: "gun_depression", decimals: 0, units: "deg" }, - { name: "gun_elevation", decimals: 0, units: "deg" }, - // { name: "gun_yaw_range", decimals: 0, units: "deg" }, // TODO: implement gun yaw range + { toy: "ricochet" }, ], }, + + { + group: "accuracy", + render: CharacteristicsGroupRender.Statistical, + order: [ + { name: "aim_time", decimals: 1, units: "s" }, + { name: "dispersion", decimals: 3, units: "m" }, + { name: "dispersion_angle", decimals: 3, units: "m" }, + { toy: "aim_time" }, + ], + }, + + { + group: "flexibility", + render: CharacteristicsGroupRender.Statistical, + order: [ + { name: "gun_depression", decimals: 0, units: "deg" }, + { name: "gun_elevation", decimals: 0, units: "deg" }, + { name: "gun_yaw_range", decimals: 0, units: "deg" }, + + { toy: "flexibility" }, + ], + }, + { group: "maneuverability", + render: CharacteristicsGroupRender.Statistical, order: [ - // { toy: "traverse" }, { name: "speed_forward", units: "km_h" }, { name: "speed_backward", units: "km_h" }, { name: "engine_power", units: "bhp" }, - // { name: "brake_force", units: "N" }, // TODO: implement brake force + { name: "brake_force", units: "N" }, { name: "weight", decimals: 1, units: "t" }, { name: "terrain_coefficient" }, { name: "power_to_weight", decimals: 1, units: "bhp_t" }, + { name: "hull_traverse_speed", units: "deg_s" }, { name: "turret_traverse_speed", units: "deg_s" }, - // { name: "gun_traverse_speed", units: "deg_s" }, // TODO: implement gun traverse speed + { name: "gun_traverse_speed", units: "deg_s" }, + + { toy: "traverse" }, + + // TODO: investigate ATTRIBUTE_NAME_TERRAIN_SIDE_FRICTION + // TODO: investigate ATTRIBUTE_NAME_TERRAIN_FORWARD_FRICTION + // TODO: investigate ATTRIBUTE_NAME_RESERVE_TRACK_BACKWARD_SPEED ], }, + { group: "survivability", + render: CharacteristicsGroupRender.Statistical, order: [ { name: "health", units: "hp" }, { name: "fire_chance", units: "%" }, - // { name: "fire_health_burn", units: "hp_s" }, // TODO: implement fire health burn - // { name: "ramming_resistance", units: "%" }, // TODO: implement ramming resistance + { name: "fire_health_burn", units: "hp_s" }, + { name: "ramming_resistance", units: "%" }, - // { toy: "view_range" }, + { toy: "fire_health_burn" }, + + // TODO: investigate ATTRIBUTE_NAME_MAX_FIRE_DURATION + ], + }, + + { + group: "concealment", + render: CharacteristicsGroupRender.Statistical, + order: [ { name: "view_range", units: "m" }, { name: "camouflage", decimals: 0, units: "%" }, - // { name: "consumable_cooldown", decimals: 0, units: "%" }, // TODO: implement consumable cooldown - // { name: "consumable_duration", decimals: 0, units: "s" }, // TODO: implement consumable duration - // { name: "consumable_reload", decimals: 0, units: "s" }, // TODO: implement consumable reload + { toy: "view_range" }, - // { name: "width", units: "m" }, // TODO: implement width + { name: "width", units: "m" }, { name: "height", units: "m" }, { name: "length", units: "m" }, { name: "volume", units: "m" },