diff --git a/bun.lockb b/bun.lockb
index f814b6a02..1d37e34dd 100644
Binary files a/bun.lockb and b/bun.lockb differ
diff --git a/package.json b/package.json
index 553d715f5..8206b459f 100644
--- a/package.json
+++ b/package.json
@@ -46,9 +46,9 @@
"devDependencies": {
"@types/bun": "latest",
"@types/lodash-es": "^4.17.12",
- "@types/node": "^22.5.4",
- "prettier": "^3.3.3",
- "prisma": "^6.0.0",
- "typescript": "^5.5.4"
+ "@types/node": "^22.14.1",
+ "prettier": "^3.5.3",
+ "prisma": "^6.6.0",
+ "typescript": "^5.8.3"
}
}
diff --git a/packages/website/src/components/MissingShellIcon.tsx b/packages/website/src/components/MissingShellIcon.tsx
index e8df7963b..fe9754709 100644
--- a/packages/website/src/components/MissingShellIcon.tsx
+++ b/packages/website/src/components/MissingShellIcon.tsx
@@ -13,8 +13,8 @@ export function MissingShellIcon(props: ComponentProps<'svg'>) {
diff --git a/packages/website/src/components/Tankopedia/HeroSection/components/Options/components/Thicknesses.tsx b/packages/website/src/components/Tankopedia/HeroSection/components/Options/components/Thicknesses.tsx
index 7aa365e85..a6e000fd1 100644
--- a/packages/website/src/components/Tankopedia/HeroSection/components/Options/components/Thicknesses.tsx
+++ b/packages/website/src/components/Tankopedia/HeroSection/components/Options/components/Thicknesses.tsx
@@ -5,14 +5,17 @@ import { Suspense } from 'react';
import { useLocale } from '../../../../../../hooks/useLocale';
import { TankopediaEphemeral } from '../../../../../../stores/tankopediaEphemeral';
import { TankopediaPersistent } from '../../../../../../stores/tankopediaPersistent';
+import { TankopediaDisplay } from '../../../../../../stores/tankopediaPersistent/constants';
+import type { MaybeSkeletonComponentProps } from '../../../../../../types/maybeSkeletonComponentProps';
import type { ThicknessRange } from '../../../../../Armor/components/StaticArmor';
import { DynamicArmorSwitcher } from './DynamicArmorSwitcher';
-interface ThicknessesProps {
+type ThicknessesProps = MaybeSkeletonComponentProps & {
thicknessRange: ThicknessRange;
-}
+};
-export function Thicknesses({ thicknessRange }: ThicknessesProps) {
+export function Thicknesses({ thicknessRange, skeleton }: ThicknessesProps) {
+ const display = TankopediaEphemeral.use((state) => state.display);
const showExternalModules = TankopediaPersistent.use(
(state) => state.showExternalModules,
);
@@ -31,10 +34,14 @@ export function Thicknesses({ thicknessRange }: ThicknessesProps) {
return (
-
-
-
+ {!skeleton && (
+
+
+
+ )}
);
}
diff --git a/packages/website/src/components/Tankopedia/HeroSection/components/Options/index.tsx b/packages/website/src/components/Tankopedia/HeroSection/components/Options/index.tsx
index 8d4cf44d4..dc251d0f4 100644
--- a/packages/website/src/components/Tankopedia/HeroSection/components/Options/index.tsx
+++ b/packages/website/src/components/Tankopedia/HeroSection/components/Options/index.tsx
@@ -42,6 +42,7 @@ import {
} from '../../../../../stores/tankopediaEphemeral';
import { TankopediaPersistent } from '../../../../../stores/tankopediaPersistent';
import { TankopediaDisplay } from '../../../../../stores/tankopediaPersistent/constants';
+import type { MaybeSkeletonComponentProps } from '../../../../../types/maybeSkeletonComponentProps';
import type { ThicknessRange } from '../../../../Armor/components/StaticArmor';
import { ModuleButton } from '../../../../ModuleButtons/ModuleButton';
import { SmallTankIcon } from '../../../../SmallTankIcon';
@@ -51,12 +52,12 @@ import { DynamicArmorSwitcher } from './components/DynamicArmorSwitcher';
import { QuickInputs } from './components/QuickInputs';
import { Thicknesses } from './components/Thicknesses';
-interface OptionsProps {
+type OptionsProps = MaybeSkeletonComponentProps & {
thicknessRange: ThicknessRange;
canvas: RefObject;
-}
+};
-export function Options({ thicknessRange, canvas }: OptionsProps) {
+export function Options({ thicknessRange, canvas, skeleton }: OptionsProps) {
const hasCustomShell = TankopediaEphemeral.use(
(state) => state.customShell !== undefined,
);
@@ -111,216 +112,212 @@ export function Options({ thicknessRange, canvas }: OptionsProps) {
/>
)}
- {display === TankopediaDisplay.StaticArmor && (
-
- )}
+
- {display === TankopediaDisplay.DynamicArmor && (
-
- {!hasCustomShell && (
-
- {literals(strings.common.units.mm, [
- (
- resolvePenetrationCoefficient(
- hasCalibratedShells,
- antagonistShell.type,
- ) * antagonistShell.penetration.near
- ).toFixed(0),
- ])}
-
- )}
- {antagonistUniqueGuns.length > 1 && (
-
-
-
-
- {
- TIER_ROMAN_NUMERALS[
- antagonistGun.gun_type!.value.base.tier
- ]
- }
-
+
+ {!hasCustomShell && (
+
+ {literals(strings.common.units.mm, [
+ (
+ resolvePenetrationCoefficient(
+ hasCalibratedShells,
+ antagonistShell.type,
+ ) * antagonistShell.penetration.near
+ ).toFixed(0),
+ ])}
+
+ )}
-
-
-
-
-
-
- {[...antagonistUniqueGuns]
- .reverse()
- .map(({ gun, turret }) => (
-
- mutateDuel((draft) => {
- draft.antagonist.turret = turret;
- draft.antagonist.gun = gun;
- draft.antagonist.shell =
- gun.gun_type!.value.base.shells[0];
- })
- }
- selected={
- gun.gun_type!.value.base.id ===
- antagonistGun.gun_type!.value.base.id
- }
- discriminator={
- TIER_ROMAN_NUMERALS[gun.gun_type!.value.base.tier]
- }
- secondaryDiscriminator={
-
- {literals(strings.common.units.mm, [
- gun.gun_type!.value.base.shells[0].caliber.toFixed(
- 0,
- ),
- ])}
-
- }
- />
- ))}
-
-
-
- )}
-
- {antagonistGun.gun_type!.value.base.shells.map((thisShell) => (
+ {antagonistUniqueGuns.length > 1 && (
+
+
{
- mutateDuel((draft) => {
- draft.antagonist.shell = thisShell;
- });
- mutateTankopediaEphemeral((draft) => {
- draft.shot = undefined;
- draft.customShell = undefined;
- });
- }}
+ style={{ position: 'relative' }}
>
-
+ {TIER_ROMAN_NUMERALS[antagonistGun.gun_type!.value.base.tier]}
+
+
+
- ))}
+
-
-
+
+
+ {[...antagonistUniqueGuns].reverse().map(({ gun, turret }) => (
+
+ mutateDuel((draft) => {
+ draft.antagonist.turret = turret;
+ draft.antagonist.gun = gun;
+ draft.antagonist.shell =
+ gun.gun_type!.value.base.shells[0];
+ })
+ }
+ selected={
+ gun.gun_type!.value.base.id ===
+ antagonistGun.gun_type!.value.base.id
+ }
+ discriminator={
+ TIER_ROMAN_NUMERALS[gun.gun_type!.value.base.tier]
+ }
+ secondaryDiscriminator={
+
+ {literals(strings.common.units.mm, [
+ gun.gun_type!.value.base.shells[0].caliber.toFixed(0),
+ ])}
+
+ }
+ />
+ ))}
+
+
+
+ )}
-
+ {antagonistGun.gun_type!.value.base.shells.map((thisShell) => (
+ {
+ mutateDuel((draft) => {
+ draft.antagonist.shell = thisShell;
+ });
+ mutateTankopediaEphemeral((draft) => {
+ draft.shot = undefined;
+ draft.customShell = undefined;
+ });
+ }}
+ >
+
+
+ ))}
+
+
+
+
+
+ {
+ mutateDuel((draft) => {
+ draft.antagonist.equipmentMatrix[0][0] = hasCalibratedShells
+ ? 0
+ : 1;
+ });
+ mutateTankopediaEphemeral((draft) => {
+ draft.shot = undefined;
+ });
}}
- overflow="hidden"
>
- {
- mutateDuel((draft) => {
- draft.antagonist.equipmentMatrix[0][0] = hasCalibratedShells
- ? 0
- : 1;
- });
- mutateTankopediaEphemeral((draft) => {
- draft.shot = undefined;
- });
+
-
-
- {
- mutateDuel((draft) => {
- draft.protagonist.equipmentMatrix[1][1] = hasEnhancedArmor
- ? 0
- : -1;
- });
- mutateTankopediaEphemeral((draft) => {
- draft.shot = undefined;
- });
+ />
+
+ {
+ mutateDuel((draft) => {
+ draft.protagonist.equipmentMatrix[1][1] = hasEnhancedArmor
+ ? 0
+ : -1;
+ });
+ mutateTankopediaEphemeral((draft) => {
+ draft.shot = undefined;
+ });
+ }}
+ >
+
-
-
-
+ />
+
+
+ {!skeleton && (
-
- )}
+ )}
+
- {display === TankopediaDisplay.DynamicArmor && (
- <>
- {
- mutateTankopediaPersistent((draft) => {
- draft.advancedHighlighting = !draft.advancedHighlighting;
- });
- }}
+
+ {
+ mutateTankopediaPersistent((draft) => {
+ draft.advancedHighlighting = !draft.advancedHighlighting;
+ });
+ }}
+ >
+
+
+ {strings.website.tools.tankopedia.sandbox.dynamic.advanced}
+
+
+
+
+
+ {strings.website.tools.tankopedia.sandbox.dynamic.shooter}
+
+
-
-
- {strings.website.tools.tankopedia.sandbox.dynamic.advanced}
-
-
+
+
+
-
-
- {strings.website.tools.tankopedia.sandbox.dynamic.shooter}
-
-
-
-
-
+
+ Select tank
-
- Select tank
+
+ {
+ mutateDuel((draft) => {
+ draft.antagonist.tank = tank;
+ draft.antagonist.engine = tank.engines.at(-1)!;
+ draft.antagonist.track = tank.tracks.at(-1)!;
+ draft.antagonist.turret = tank.turrets.at(-1)!;
+ draft.antagonist.gun =
+ draft.antagonist.turret.guns.at(-1)!;
+ draft.antagonist.shell =
+ draft.antagonist.gun.gun_type!.value.base.shells[0];
+ });
+ setAntagonistSelectorOpen(false);
+ }}
+ />
+
+
+
+
+
-
- {
- mutateDuel((draft) => {
- draft.antagonist.tank = tank;
- draft.antagonist.engine = tank.engines.at(-1)!;
- draft.antagonist.track = tank.tracks.at(-1)!;
- draft.antagonist.turret = tank.turrets.at(-1)!;
- draft.antagonist.gun =
- draft.antagonist.turret.guns.at(-1)!;
- draft.antagonist.shell =
- draft.antagonist.gun.gun_type!.value.base.shells[0];
- });
- setAntagonistSelectorOpen(false);
- }}
- />
-
-
-
-
- >
- )}
{skeleton && }
@@ -171,7 +171,11 @@ export function HeroSection({ skeleton }: MaybeSkeletonComponentProps) {
-
+