Merge branch 'main' into data-driven

This commit is contained in:
tresabhi committed 2026-10-11 00:34:39 -05:00
commit 1b08393f65
60 files changed
+434 -474

No files matched your search

@@ -13,6 +13,7 @@ import { modelTransformEvent } from "../../../../../../../core/blitzkit/modelTra
import { Var } from "../../../../../../../core/radix/var";
import { useLocale } from "../../../../../../../hooks/useLocale";
import { Duel } from "../../../../../../../stores/duel";
import { Tankopedia } from "../../../../../../../stores/tankopedia";
import type { MaybeSkeletonComponentProps } from "../../../../../../../types/maybeSkeletonComponentProps";
import { VisualizerCard } from "../VisualizerCard";
import { VisualizerCornerStat } from "../VisualizerCornerStat";
@@ -43,6 +44,7 @@ export function GunFlexibilityVisualizer({
const tank = Duel.use((state) => state.protagonist.tank);
const turret = Duel.use((state) => state.protagonist.turret);
const gun = Duel.use((state) => state.protagonist.gun);
const modelRequested = Tankopedia.use((state) => state.modelRequested);
const tankModel = modelDefinition.models[tank.id];
const turretModel = tankModel.turrets[turret.id];
@@ -193,7 +195,7 @@ export function GunFlexibilityVisualizer({
top="0"
left="0"
>
{!skeleton && <FlexibilityCanvas />}
{!skeleton && modelRequested && <FlexibilityCanvas />}
<Box
position="absolute"
@@ -24,6 +24,14 @@ export function Survivability({ stats }: StatsAcceptorProps) {
decimals={0}
value={(stats) => stats.fireChance * 100}
/>
{stats.trackRepairTime !== undefined && (
<InfoWithDelta
value="trackRepairTime"
stats={stats}
deltaType="lowerIsBetter"
decimals={2}
/>
)}
<InfoWithDelta value="viewRange" stats={stats} decimals={0} />
<ViewRangeVisualizer stats={stats} />
<Info
@@ -28,23 +28,17 @@ export function Equalizer() {
width="100%"
style={{
cursor: "pointer",
borderRadius: "var(--radius-3)",
backgroundImage: `url(${alias("api", `/gamemodes/Insanity/banner.webp`)})`,
backgroundSize: "cover",
borderRadius: "var(--radius-3) 0 0 var(--radius-3)",
backgroundImage: `
linear-gradient(90deg, var(--black-a3), var(--gray-1)),
url(${alias("api", `/gamemodes/Insanity/banner.webp`)})
`,
backgroundSize: "auto, fit",
backgroundPosition: "50% 25%",
overflow: "hidden",
}}
>
<Flex
align="center"
width="100%"
justify="between"
p="4"
style={{
background:
"linear-gradient(90deg, var(--black-a3), var(--gray-1))",
}}
>
<Flex align="center" width="100%" justify="between" p="4" style={{}}>
<Text
style={{
textShadow: "0 0 var(--space-1) var(--black-a12)",
@@ -31,11 +31,11 @@ export function Thicknesses({ thicknessRange, skeleton }: ThicknessesProps) {
return (
<Flex
position="absolute"
right={display === TankopediaDisplay.StaticArmor ? "0" : "-6rem"}
right="0"
top="50%"
mr="4"
style={{
transform: "translateY(-50%)",
transform: `translate(${display === TankopediaDisplay.StaticArmor ? "0" : "calc(100% + var(--space-4))"}, -50%)`,
userSelect: "none",
transitionDuration: "200ms",
}}
@@ -77,6 +77,7 @@ export function Options({ thicknessRange, canvas, skeleton }: OptionsProps) {
const revealed = Tankopedia.use((state) => state.revealed);
const disturbed = Tankopedia.use((state) => state.disturbed);
const highGraphics = TankopediaPersistent.use((state) => state.highGraphics);
const modelRequested = Tankopedia.use((state) => state.modelRequested);
const equalize = Duel.use((state) => state.equalize);
const equalizer = Duel.use((state) => state.antagonist.tank.equalizer);
@@ -283,7 +284,7 @@ export function Options({ thicknessRange, canvas, skeleton }: OptionsProps) {
<SpallLinerSwitcher />
</Flex>
{!skeleton && (
{!skeleton && modelRequested && (
<Suspense>
<DynamicArmorSwitcher />
</Suspense>
@@ -1,11 +1,14 @@
import { Flex, Heading } from "@radix-ui/themes";
import { UpdateIcon } from "@radix-ui/react-icons";
import { Button, Flex, Heading } from "@radix-ui/themes";
import { useLocale } from "../../../../../../hooks/useLocale";
import { Duel } from "../../../../../../stores/duel";
import { Tankopedia } from "../../../../../../stores/tankopedia";
import type { MaybeSkeletonComponentProps } from "../../../../../../types/maybeSkeletonComponentProps";
import { Tracker } from "./components/Tracker";
export function Title() {
const { unwrap } = useLocale();
export function Title({ skeleton }: MaybeSkeletonComponentProps) {
const { unwrap, strings } = useLocale();
const modelRequested = Tankopedia.use((state) => state.modelRequested);
const protagonist = Duel.use((state) => state.protagonist.tank);
const revealed = Tankopedia.use((state) => state.revealed);
const disturbed = Tankopedia.use((state) => state.disturbed);
@@ -21,6 +24,8 @@ export function Title() {
onPointerDown={(event) => {
event.preventDefault();
if (!modelRequested) return;
Tankopedia.mutate((draft) => {
draft.revealed = true;
});
@@ -60,7 +65,36 @@ export function Title() {
{name}
</Heading>
{!revealed && <Tracker fontSize={fontSize} />}
{!skeleton && !revealed && modelRequested && (
<Tracker fontSize={fontSize} />
)}
{!skeleton && !modelRequested && (
<Flex
position="absolute"
left="50%"
top="50%"
width="min(100%, 16rem)"
justify="center"
style={{
transform: `translate(-50%, calc(${fontSize} * 0.75 + var(--space-4) - 50%))`,
}}
>
<Button
variant="solid"
highContrast
onPointerDown={(event) => event.stopPropagation()}
onClick={() => {
Tankopedia.mutate((draft) => {
draft.modelRequested = true;
});
}}
>
<UpdateIcon />
{strings.website.tools.tankopedia.sandbox.load_model}
</Button>
</Flex>
)}
</Flex>
);
}
@@ -20,6 +20,7 @@ export function HeroSection({ skeleton }: MaybeSkeletonComponentProps) {
const canvas = useRef<HTMLCanvasElement>(null!);
const isFullScreen = useFullScreen();
const protagonist = Duel.use((state) => state.protagonist.tank);
const modelRequested = Tankopedia.use((state) => state.modelRequested);
const thicknessRange = useMemo(() => {
const entries = Object.values(tankDefinitions.tanks);
const filtered = entries.filter(
@@ -131,13 +132,15 @@ export function HeroSection({ skeleton }: MaybeSkeletonComponentProps) {
top="0"
left="0"
>
{!skeleton && (
<TankSandbox ref={canvas} thicknessRange={thicknessRange} />
{!skeleton && modelRequested && (
<Suspense>
<TankSandbox ref={canvas} thicknessRange={thicknessRange} />
</Suspense>
)}
</Box>
</Box>
<Title />
<Title skeleton={skeleton} />
<Options
skeleton={skeleton}
@@ -127,7 +127,7 @@ export function Node({ id, highlight, nextIds, skeleton }: NodeProps) {
</Text>
</Flex>
{averages && nextTanks && tank.tier !== 10 && (
{averages && nextTanks && (
<Text color="gray" size="1" mt="2">
{skeleton && <Skeleton height="1em" width="4em" />}
{!skeleton &&
@@ -192,7 +192,7 @@ export function TechTreeSection({ skeleton }: MaybeSkeletonComponentProps) {
);
})}
{master.tier < 10 && (
{master.successors.length > 0 && (
<>
<Arrow />
{master.successors!.map((id, index) => (