diff --git a/src/app/tools/tankopedia/[id]/components/Model/TechTreeSection.tsx b/src/app/tools/tankopedia/[id]/components/Model/TechTreeSection.tsx deleted file mode 100644 index 4ad1352df..000000000 --- a/src/app/tools/tankopedia/[id]/components/Model/TechTreeSection.tsx +++ /dev/null @@ -1,218 +0,0 @@ -import { CaretRightIcon, PlusIcon } from '@radix-ui/react-icons'; -import { Box, Flex, Heading, ScrollArea, Text } from '@radix-ui/themes'; -import Link from 'next/link'; -import { use, useEffect, useMemo, useRef } from 'react'; -import { asset } from '../../../../../../core/blitzkit/asset'; -import { - TankDefinition, - tankDefinitions, -} from '../../../../../../core/blitzkit/tankDefinitions'; -import { TIER_ROMAN_NUMERALS } from '../../../../../../core/blitzkit/tankDefinitions/constants'; -import { formatCompact } from '../../../../../../core/math/formatCompact'; -import * as Duel from '../../../../../../stores/duel'; - -function Card({ id, highlight }: { id: number; highlight?: boolean }) { - const awaitedTankDefinitions = use(tankDefinitions); - const tank = awaitedTankDefinitions[id]; - - return ( - - - - {tank.name} - - - - - {TIER_ROMAN_NUMERALS[tank.tier]} - - {tank.name} - - - - - - XP - {tank.xp === undefined || tank.tier === 1 - ? 0 - : formatCompact(tank.xp!)} - - - - - - Silver - {formatCompact(tank.price.value)} - - - - - - - - ); -} - -function Arrow() { - return ( - - - - ); -} - -export function TechTreeSection() { - const tank = Duel.use((state) => state.protagonist.tank); - const awaitedTankDefinitions = use(tankDefinitions); - const container = useRef(null); - - if ( - tank.treeType !== 'researchable' || - tank.ancestors === undefined || - tank.ancestors.length === 0 - ) { - return null; - } - - const ancestors = useMemo(() => { - const treeBackwards: number[] = []; - let ancestor: TankDefinition | undefined = tank; - - while (ancestor !== undefined) { - if ( - ancestor.tier === 1 || - ancestor.ancestors === undefined || - ancestor.ancestors.length === 0 - ) { - ancestor = undefined; - break; - } else if (ancestor.ancestors.length === 1) { - ancestor = awaitedTankDefinitions[ancestor.ancestors[0]]; - } else { - let bestAncestor = awaitedTankDefinitions[ancestor.ancestors[0]]; - - ancestor.ancestors.forEach((thisAncestorId) => { - const possibleAncestor = awaitedTankDefinitions[thisAncestorId]; - - if (possibleAncestor.xp! < bestAncestor.xp!) { - bestAncestor = possibleAncestor; - } - }); - - ancestor = bestAncestor as TankDefinition; - } - - treeBackwards.push(ancestor.id); - } - - return treeBackwards.reverse(); - }, []); - - useEffect(() => { - if (!container.current) return; - - container.current.scrollLeft = container.current.scrollWidth; - }); - - return ( - - - Tech tree - - - - - {ancestors.map((id, index) => ( - <> - {index > 0 && } - - - ))} - - - - - {tank.tier < 10 && ( - <> - - {tank.successors!.map((id, index) => ( - <> - {index > 0 && ( - - - - )} - - - ))} - - )} - - - - ); -} diff --git a/src/app/tools/tankopedia/[id]/components/Model/TechTreeSection/components/Arrow.tsx b/src/app/tools/tankopedia/[id]/components/Model/TechTreeSection/components/Arrow.tsx new file mode 100644 index 000000000..79acdf3f3 --- /dev/null +++ b/src/app/tools/tankopedia/[id]/components/Model/TechTreeSection/components/Arrow.tsx @@ -0,0 +1,10 @@ +import { CaretRightIcon } from '@radix-ui/react-icons'; +import { Text } from '@radix-ui/themes'; + +export function Arrow() { + return ( + + + + ); +} diff --git a/src/app/tools/tankopedia/[id]/components/Model/TechTreeSection/components/Node.tsx b/src/app/tools/tankopedia/[id]/components/Model/TechTreeSection/components/Node.tsx new file mode 100644 index 000000000..be6df1460 --- /dev/null +++ b/src/app/tools/tankopedia/[id]/components/Model/TechTreeSection/components/Node.tsx @@ -0,0 +1,104 @@ +import { Box, Flex, Text } from '@radix-ui/themes'; +import Link from 'next/link'; +import { use } from 'react'; +import { asset } from '../../../../../../../../core/blitzkit/asset'; +import { tankDefinitions } from '../../../../../../../../core/blitzkit/tankDefinitions'; +import { TIER_ROMAN_NUMERALS } from '../../../../../../../../core/blitzkit/tankDefinitions/constants'; +import { formatCompact } from '../../../../../../../../core/math/formatCompact'; + +export function Node({ id, highlight }: { id: number; highlight?: boolean }) { + const awaitedTankDefinitions = use(tankDefinitions); + const tank = awaitedTankDefinitions[id]; + + return ( + + + + {tank.name} + + + + + {TIER_ROMAN_NUMERALS[tank.tier]} + + {tank.name} + + + + + + XP + {tank.xp === undefined || tank.tier === 1 + ? 0 + : formatCompact(tank.xp!)} + + + + + + Silver + {formatCompact(tank.price.value)} + + + + + + + + ); +} diff --git a/src/app/tools/tankopedia/[id]/components/Model/TechTreeSection/index.tsx b/src/app/tools/tankopedia/[id]/components/Model/TechTreeSection/index.tsx new file mode 100644 index 000000000..23796023c --- /dev/null +++ b/src/app/tools/tankopedia/[id]/components/Model/TechTreeSection/index.tsx @@ -0,0 +1,145 @@ +import { CaretLeftIcon, CaretRightIcon, PlusIcon } from '@radix-ui/react-icons'; +import { Flex, Heading, IconButton, ScrollArea, Text } from '@radix-ui/themes'; +import { use, useEffect, useMemo, useRef, useState } from 'react'; +import { tankDefinitions } from '../../../../../../../core/blitzkit/tankDefinitions'; +import * as Duel from '../../../../../../../stores/duel'; +import { Arrow } from './components/Arrow'; +import { Node } from './components/Node'; + +// function Ancestry({ line }: { line: Line }) { +// return ( +// +// +// {line.map((node) => { +// if (typeof node === 'number') { +// return ; +// } else { +// return ( +// +// {node.map((line) => ( +// +// ))} +// +// ); +// } +// })} +// +// +// ); +// } + +type Line = number[]; + +export function TechTreeSection() { + const master = Duel.use((state) => state.protagonist.tank); + const awaitedTankDefinitions = use(tankDefinitions); + const container = useRef(null); + const lines = useMemo(() => { + function extend(line: Line): Line[] { + const root = awaitedTankDefinitions[line.at(-1)!]; + + if (root.ancestors === undefined || root.tier === 1) { + return [line]; + } else { + if (root.ancestors.length === 1 || root.tier === 2) { + line.push(root.ancestors[0]); + return extend(line); + } else { + return root.ancestors + .map((ancestor) => { + const newLine = [...line, ancestor]; + return extend(newLine); + }) + .flat(); + } + } + } + + return extend([master.id]); + }, [master]); + const [lineIndex, setLineIndex] = useState(0); + const line = useMemo( + () => [...lines[lineIndex]].toReversed(), + [master, lineIndex], + ); + + if ( + master.treeType !== 'researchable' || + master.ancestors === undefined || + master.ancestors.length === 0 + ) { + return null; + } + + useEffect(() => { + if (!container.current) return; + + container.current.scrollLeft = container.current.scrollWidth; + }); + + return ( + + + Tech tree + + {lines.length > 1 && ( + + + setLineIndex((lines.length + lineIndex - 1) % lines.length) + } + > + + + + Route {lineIndex + 1} of {lines.length} + + setLineIndex((lineIndex + 1) % lines.length)} + > + + + + )} + + + + + {line.map((id, index) => ( + <> + {index > 0 && } + + + ))} + + {master.tier < 10 && ( + <> + + {master.successors!.map((id, index) => ( + <> + {index > 0 && ( + + + + )} + + + ))} + + )} + + + + ); +}