import { TIER_ROMAN_NUMERALS } from "@blitzkit/core"; import { literals } from "@blitzkit/i18n/src/literals"; import { useRef } from "react"; import { characteristicsGroups } from "../../config/characteristicsGroups"; import { toys } from "../../config/toys"; import { useCharacteristicRenderer } from "../../hooks/useCharacteristicRenderer"; import { DuelModule, useDuel } from "../../hooks/useDuel"; import { useRankings } from "../../hooks/useRankings"; import { useStrings } from "../../hooks/useStrings"; import { Tankopedia, TankopediaRelativeAgainst } from "../../stores/tankopedia"; import type { CharacteristicRank } from "../../tankopedia/calculateRankings"; import type { CharacteristicName, CharacteristicRenderConfig, CharacteristicReturnType, CharacteristicsGroup, ComputedCharacteristics, ToyName, } from "../../types/characteristics"; import { Heading } from "../Heading"; import { SegmentedControl } from "../SegmentedControl"; import { Text } from "../Text"; import styles from "./index.module.css"; interface TankopediaCharacteristicsProps { characteristics: ComputedCharacteristics; } export function TankopediaCharacteristics({ characteristics, }: TankopediaCharacteristicsProps) { const rankings = useRankings(characteristics); return (
{characteristicsGroups.map((group) => { const items = group.order.filter( (item) => "name" in item && characteristics.has(item.name), ).length; const shouldRender = items > 0; if (!shouldRender) return null; return ( ); })}
); } interface GroupProps { group: CharacteristicsGroup; characteristics: ComputedCharacteristics; rankings: Map; } function Group({ group, characteristics, rankings }: GroupProps) { const strings = useStrings(); const toys = group.order.filter((item) => "toy" in item).length; const characteristicsCount = group.order.filter( (item) => "name" in item && characteristics.has(item.name), ).length; const labelsCount = characteristicsCount > 0 ? group.order.filter((item) => "label" in item).length : 0; const items = characteristicsCount + labelsCount; const groupSpan = `calc(${toys} * var(--group-span) + ${items} + 2)`; const contentSpan = `calc(${toys} * var(--group-span) + ${items})`; return (
{ ( strings.tanks.characteristics.titles as Record )[group.name] }
{group.order.map((item) => ( <> {"toy" in item && ( )} {"label" in item &&
); } interface LabelProps { label: string; } function Label({ label }: LabelProps) { const strings = useStrings(); return (
{(strings.tanks.characteristics.items as Record)[label]}
); } interface ItemProps { config: CharacteristicRenderConfig; value: CharacteristicReturnType; ranking?: CharacteristicRank; } function Item({ config, value, ranking }: ItemProps) { const strings = useStrings(); const renderCharacteristic = useCharacteristicRenderer(); const hasUnits = config.units !== undefined; return (
{ (strings.tanks.characteristics.items as Record)[ config.name ] }
{renderCharacteristic(value, config)}
{ranking && (
{literals(strings.units.fraction, { numerator: ranking.rank, denominator: ranking.total, })}
)}
); } function CompareOptions() { const tank = useDuel("protagonist", DuelModule.Tank); const relativeAgainst = Tankopedia.use((state) => state.relative_against); const strings = useStrings(); const options = useRef([ { value: TankopediaRelativeAgainst.ClassAndTier, label: literals(strings.tanks.characteristics.compare.class, { tier: TIER_ROMAN_NUMERALS[tank.tier], class: strings.common.tank_class_short_plural_lowercase[tank.class], }), }, { value: TankopediaRelativeAgainst.Tier, label: literals(strings.tanks.characteristics.compare.tier, { tier: TIER_ROMAN_NUMERALS[tank.tier], }), }, { value: TankopediaRelativeAgainst.All, label: strings.tanks.characteristics.compare.all, }, ]); return (
{strings.tanks.characteristics.compare.label} { Tankopedia.mutate((draft) => { draft.relative_against = value; }); }} />
); } interface BarProps { value: number; } const barColors = ["red", "orange", "amber", "jade"]; function Bar({ value }: BarProps) { const index = (barColors.length - 1) * value; const iA = Math.floor(index); const iB = Math.ceil(index); const A = barColors[iA]; const B = barColors[iB]; const x = index % 1; const p = (1 - x) * 100; const v = 7; return (
); } interface ToyAssignerProps { toy: ToyName; characteristics: ComputedCharacteristics; } function ToyAssigner({ toy, characteristics }: ToyAssignerProps) { const Toy = toys[toy]; return (
{Toy ? ( ) : ( {toy} )}
); }