fix: update errors

This commit is contained in:
TrèsAbhi committed 2025-09-27 16:07:45 -05:00
1 parent 4ff9a2ec7f
commit c14efe86cc
34 files changed
+217 -280

No files matched your search

BIN
View File
Binary file not shown.
+4 -4
View File
@@ -1,12 +1,12 @@
import { I18nString } from '@blitzkit/core'; import { I18nString } from "@blitzkit/core";
import { DEFAULT_LOCALE } from './strings'; import locales from "@blitzkit/i18n/locales.json";
export function unwrapper(locale: string) { export function unwrapper(locale = locales.default) {
return function (i18nString: I18nString) { return function (i18nString: I18nString) {
if (locale in i18nString.locales) { if (locale in i18nString.locales) {
return i18nString.locales[locale]; return i18nString.locales[locale];
} }
return i18nString.locales[DEFAULT_LOCALE]; return i18nString.locales[locales.default];
}; };
} }
+3
View File
@@ -5,16 +5,19 @@
"dev": "astro dev", "dev": "astro dev",
"build": "astro build", "build": "astro build",
"preview": "astro preview", "preview": "astro preview",
"lint": "astro check",
"astro": "astro" "astro": "astro"
}, },
"dependencies": { "dependencies": {
"@astrojs/react": "^4.4.0", "@astrojs/react": "^4.4.0",
"@radix-ui/colors": "^3.0.0", "@radix-ui/colors": "^3.0.0",
"@react-three/fiber": "^9.3.0",
"@types/react": "^19.1.14", "@types/react": "^19.1.14",
"@types/react-dom": "^19.1.9", "@types/react-dom": "^19.1.9",
"@vite-pwa/astro": "^1.1.0", "@vite-pwa/astro": "^1.1.0",
"astro": "^5.14.1", "astro": "^5.14.1",
"astro-favicons": "^3.1.5", "astro-favicons": "^3.1.5",
"fuzzysort": "^3.1.0",
"react": "^19.1.1", "react": "^19.1.1",
"react-dom": "^19.1.1" "react-dom": "^19.1.1"
} }
@@ -1,7 +1,8 @@
import type { GroupProps } from '@react-three/fiber'; import { forwardRef, type ComponentProps } from "react";
import { forwardRef } from 'react'; import { Group } from "three";
import { Group } from 'three';
export const ModelTankWrapper = forwardRef<Group, GroupProps>((props, ref) => { export const ModelTankWrapper = forwardRef<Group, ComponentProps<"group">>(
return <group rotation={[-Math.PI / 2, 0, 0]} ref={ref} {...props} />; (props, ref) => {
}); return <group rotation={[-Math.PI / 2, 0, 0]} ref={ref} {...props} />;
}
);
@@ -1,19 +1,19 @@
import { memo, useRef } from 'react'; import { memo, useRef } from "react";
import { Group } from 'three'; import { Group } from "three";
import { correctZYTuple } from '../../../core/blitz/correctZYTuple'; import { correctZYTuple } from "../../../core/blitz/correctZYTuple";
import { nameToArmorId } from '../../../core/blitzkit/nameToArmorId'; import { nameToArmorId } from "../../../core/blitzkit/nameToArmorId";
import { resolveArmor } from '../../../core/blitzkit/resolveThickness'; import { resolveArmor } from "../../../core/blitzkit/resolveThickness";
import { useArmor } from '../../../hooks/useArmor'; import { useArmor } from "../../../hooks/useArmor";
import { useTankModelDefinition } from '../../../hooks/useTankModelDefinition'; import { useTankModelDefinition } from "../../../hooks/useTankModelDefinition";
import { useTankTransform } from '../../../hooks/useTankTransform'; import { useTankTransform } from "../../../hooks/useTankTransform";
import { Duel } from '../../../stores/duel'; import { Duel } from "../../../stores/duel";
import { ModelTankWrapper } from './ModelTankWrapper'; import { ModelTankWrapper } from "./ModelTankWrapper";
import { PrimaryArmorSceneComponent } from './PrimaryArmorSceneComponent'; import { PrimaryArmorSceneComponent } from "./PrimaryArmorSceneComponent";
export const PrimaryArmorScene = memo(() => { export const PrimaryArmorScene = memo(() => {
const wrapper = useRef<Group>(null); const wrapper = useRef<Group>(null);
const turretContainer = useRef<Group>(null); const turretContainer = useRef<Group>(null!);
const gunContainer = useRef<Group>(null); const gunContainer = useRef<Group>(null!);
const tank = Duel.use((state) => state.protagonist.tank); const tank = Duel.use((state) => state.protagonist.tank);
const track = Duel.use((state) => state.protagonist.track); const track = Duel.use((state) => state.protagonist.track);
const turret = Duel.use((state) => state.protagonist.turret); const turret = Duel.use((state) => state.protagonist.turret);
@@ -28,7 +28,7 @@ export const PrimaryArmorScene = memo(() => {
const turretOrigin = correctZYTuple(tankModelDefinition.turret_origin); const turretOrigin = correctZYTuple(tankModelDefinition.turret_origin);
const gunOrigin = correctZYTuple(turretModelDefinition.gun_origin); const gunOrigin = correctZYTuple(turretModelDefinition.gun_origin);
const isDynamicArmorActive = Duel.use((state) => const isDynamicArmorActive = Duel.use((state) =>
state.protagonist.consumables.includes(73), state.protagonist.consumables.includes(73)
); );
useTankTransform(track, turret, turretContainer, gunContainer); useTankTransform(track, turret, turretContainer, gunContainer);
@@ -37,20 +37,20 @@ export const PrimaryArmorScene = memo(() => {
<ModelTankWrapper ref={wrapper}> <ModelTankWrapper ref={wrapper}>
<group position={hullOrigin}> <group position={hullOrigin}>
{armorNodes.map((node) => { {armorNodes.map((node) => {
const isHull = node.name.startsWith('hull_'); const isHull = node.name.startsWith("hull_");
const isVisible = isHull; const isVisible = isHull;
const armorId = nameToArmorId(node.name); const armorId = nameToArmorId(node.name);
const { spaced, thickness } = resolveArmor( const { spaced, thickness } = resolveArmor(
tankModelDefinition.armor, tankModelDefinition.armor,
armorId, armorId
); );
if ( if (
!isVisible || !isVisible ||
spaced || spaced ||
thickness === undefined || thickness === undefined ||
(isDynamicArmorActive && node.name.includes('state_01')) || (isDynamicArmorActive && node.name.includes("state_01")) ||
(!isDynamicArmorActive && node.name.includes('state_00')) (!isDynamicArmorActive && node.name.includes("state_00"))
) )
return null; return null;
@@ -67,21 +67,21 @@ export const PrimaryArmorScene = memo(() => {
<group ref={turretContainer}> <group ref={turretContainer}>
{armorNodes.map((node) => { {armorNodes.map((node) => {
const isCurrentTurret = node.name.startsWith( const isCurrentTurret = node.name.startsWith(
`turret_${turretModelDefinition.model_id.toString().padStart(2, '0')}`, `turret_${turretModelDefinition.model_id.toString().padStart(2, "0")}`
); );
const isVisible = isCurrentTurret; const isVisible = isCurrentTurret;
const armorId = nameToArmorId(node.name); const armorId = nameToArmorId(node.name);
const { spaced, thickness } = resolveArmor( const { spaced, thickness } = resolveArmor(
turretModelDefinition.armor, turretModelDefinition.armor,
armorId, armorId
); );
if ( if (
!isVisible || !isVisible ||
spaced || spaced ||
thickness === undefined || thickness === undefined ||
(isDynamicArmorActive && node.name.includes('state_01')) || (isDynamicArmorActive && node.name.includes("state_01")) ||
(!isDynamicArmorActive && node.name.includes('state_00')) (!isDynamicArmorActive && node.name.includes("state_00"))
) )
return null; return null;
@@ -101,21 +101,21 @@ export const PrimaryArmorScene = memo(() => {
<group ref={gunContainer}> <group ref={gunContainer}>
{armorNodes.map((node) => { {armorNodes.map((node) => {
const isCurrentGun = node.name.startsWith( const isCurrentGun = node.name.startsWith(
`gun_${gunModelDefinition.model_id.toString().padStart(2, '0')}`, `gun_${gunModelDefinition.model_id.toString().padStart(2, "0")}`
); );
const isVisible = isCurrentGun; const isVisible = isCurrentGun;
const armorId = nameToArmorId(node.name); const armorId = nameToArmorId(node.name);
const { spaced, thickness } = resolveArmor( const { spaced, thickness } = resolveArmor(
gunModelDefinition.armor, gunModelDefinition.armor,
armorId, armorId
); );
if ( if (
!isVisible || !isVisible ||
spaced || spaced ||
thickness === undefined || thickness === undefined ||
(isDynamicArmorActive && node.name.includes('state_01')) || (isDynamicArmorActive && node.name.includes("state_01")) ||
(!isDynamicArmorActive && node.name.includes('state_00')) (!isDynamicArmorActive && node.name.includes("state_00"))
) )
return null; return null;
@@ -1,15 +1,15 @@
import { memo, useRef } from 'react'; import { memo, useRef } from "react";
import { Group, Plane, Scene, Vector3 } from 'three'; import { Group, Plane, Scene, Vector3 } from "three";
import { correctZYTuple } from '../../../core/blitz/correctZYTuple'; import { correctZYTuple } from "../../../core/blitz/correctZYTuple";
import { nameToArmorId } from '../../../core/blitzkit/nameToArmorId'; import { nameToArmorId } from "../../../core/blitzkit/nameToArmorId";
import { resolveArmor } from '../../../core/blitzkit/resolveThickness'; import { resolveArmor } from "../../../core/blitzkit/resolveThickness";
import { useArmor } from '../../../hooks/useArmor'; import { useArmor } from "../../../hooks/useArmor";
import { useModel } from '../../../hooks/useModel'; import { useModel } from "../../../hooks/useModel";
import { useTankModelDefinition } from '../../../hooks/useTankModelDefinition'; import { useTankModelDefinition } from "../../../hooks/useTankModelDefinition";
import { useTankTransform } from '../../../hooks/useTankTransform'; import { useTankTransform } from "../../../hooks/useTankTransform";
import { Duel } from '../../../stores/duel'; import { Duel } from "../../../stores/duel";
import { ModelTankWrapper } from './ModelTankWrapper'; import { ModelTankWrapper } from "./ModelTankWrapper";
import { SpacedArmorSceneComponent } from './SpacedArmorSceneComponent'; import { SpacedArmorSceneComponent } from "./SpacedArmorSceneComponent";
export enum ArmorType { export enum ArmorType {
Primary, Primary,
@@ -23,8 +23,8 @@ interface SpacedArmorSceneProps {
export const SpacedArmorScene = memo<SpacedArmorSceneProps>(({ scene }) => { export const SpacedArmorScene = memo<SpacedArmorSceneProps>(({ scene }) => {
const wrapper = useRef<Group>(null); const wrapper = useRef<Group>(null);
const turretContainer = useRef<Group>(null); const turretContainer = useRef<Group>(null!);
const gunContainer = useRef<Group>(null); const gunContainer = useRef<Group>(null!);
const tank = Duel.use((state) => state.protagonist.tank); const tank = Duel.use((state) => state.protagonist.tank);
const track = Duel.use((state) => state.protagonist.track); const track = Duel.use((state) => state.protagonist.track);
const turret = Duel.use((state) => state.protagonist.turret); const turret = Duel.use((state) => state.protagonist.turret);
@@ -45,7 +45,7 @@ export const SpacedArmorScene = memo<SpacedArmorSceneProps>(({ scene }) => {
? undefined ? undefined
: gunModelDefinition.mask + hullOrigin.y + turretOrigin.y + gunOrigin.y; : gunModelDefinition.mask + hullOrigin.y + turretOrigin.y + gunOrigin.y;
const isDynamicArmorActive = Duel.use((state) => const isDynamicArmorActive = Duel.use((state) =>
state.protagonist.consumables.includes(73), state.protagonist.consumables.includes(73)
); );
useTankTransform(track, turret, turretContainer, gunContainer); useTankTransform(track, turret, turretContainer, gunContainer);
@@ -54,19 +54,19 @@ export const SpacedArmorScene = memo<SpacedArmorSceneProps>(({ scene }) => {
<ModelTankWrapper ref={wrapper}> <ModelTankWrapper ref={wrapper}>
<group position={hullOrigin}> <group position={hullOrigin}>
{armorNodes.map((node) => { {armorNodes.map((node) => {
const isHull = node.name.startsWith('hull_'); const isHull = node.name.startsWith("hull_");
const isVisible = isHull; const isVisible = isHull;
const armorId = nameToArmorId(node.name); const armorId = nameToArmorId(node.name);
const { spaced, thickness } = resolveArmor( const { spaced, thickness } = resolveArmor(
tankModelDefinition.armor, tankModelDefinition.armor,
armorId, armorId
); );
if ( if (
!isVisible || !isVisible ||
thickness === undefined || thickness === undefined ||
(isDynamicArmorActive && node.name.includes('state_00')) || (isDynamicArmorActive && node.name.includes("state_00")) ||
(!isDynamicArmorActive && node.name.includes('state_01')) (!isDynamicArmorActive && node.name.includes("state_01"))
) )
return null; return null;
@@ -83,8 +83,8 @@ export const SpacedArmorScene = memo<SpacedArmorSceneProps>(({ scene }) => {
</group> </group>
{modelNodes.map((node) => { {modelNodes.map((node) => {
const isWheel = node.name.startsWith('chassis_wheel_'); const isWheel = node.name.startsWith("chassis_wheel_");
const isTrack = node.name.startsWith('chassis_track_'); const isTrack = node.name.startsWith("chassis_track_");
const isVisible = isWheel || isTrack; const isVisible = isWheel || isTrack;
if (!isVisible) return null; if (!isVisible) return null;
@@ -104,20 +104,20 @@ export const SpacedArmorScene = memo<SpacedArmorSceneProps>(({ scene }) => {
<group ref={turretContainer}> <group ref={turretContainer}>
{armorNodes.map((node) => { {armorNodes.map((node) => {
const isCurrentTurret = node.name.startsWith( const isCurrentTurret = node.name.startsWith(
`turret_${turretModelDefinition.model_id.toString().padStart(2, '0')}`, `turret_${turretModelDefinition.model_id.toString().padStart(2, "0")}`
); );
const isVisible = isCurrentTurret; const isVisible = isCurrentTurret;
const armorId = nameToArmorId(node.name); const armorId = nameToArmorId(node.name);
const { spaced, thickness } = resolveArmor( const { spaced, thickness } = resolveArmor(
turretModelDefinition.armor, turretModelDefinition.armor,
armorId, armorId
); );
if ( if (
!isVisible || !isVisible ||
thickness === undefined || thickness === undefined ||
(isDynamicArmorActive && node.name.includes('state_00')) || (isDynamicArmorActive && node.name.includes("state_00")) ||
(!isDynamicArmorActive && node.name.includes('state_01')) (!isDynamicArmorActive && node.name.includes("state_01"))
) )
return null; return null;
@@ -139,20 +139,20 @@ export const SpacedArmorScene = memo<SpacedArmorSceneProps>(({ scene }) => {
<group ref={gunContainer}> <group ref={gunContainer}>
{armorNodes.map((node) => { {armorNodes.map((node) => {
const isCurrentGun = node.name.startsWith( const isCurrentGun = node.name.startsWith(
`gun_${gunModelDefinition.model_id.toString().padStart(2, '0')}`, `gun_${gunModelDefinition.model_id.toString().padStart(2, "0")}`
); );
const isVisible = isCurrentGun; const isVisible = isCurrentGun;
const armorId = nameToArmorId(node.name); const armorId = nameToArmorId(node.name);
const { spaced, thickness } = resolveArmor( const { spaced, thickness } = resolveArmor(
gunModelDefinition.armor, gunModelDefinition.armor,
armorId, armorId
); );
if ( if (
!isVisible || !isVisible ||
thickness === undefined || thickness === undefined ||
(isDynamicArmorActive && node.name.includes('state_00')) || (isDynamicArmorActive && node.name.includes("state_00")) ||
(!isDynamicArmorActive && node.name.includes('state_01')) (!isDynamicArmorActive && node.name.includes("state_01"))
) )
return null; return null;
@@ -173,7 +173,7 @@ export const SpacedArmorScene = memo<SpacedArmorSceneProps>(({ scene }) => {
{modelNodes.map((node) => { {modelNodes.map((node) => {
const gunString = `gun_${gunModelDefinition.model_id const gunString = `gun_${gunModelDefinition.model_id
.toString() .toString()
.padStart(2, '0')}`; .padStart(2, "0")}`;
const isCurrentGun = gunModelDefinition.mask const isCurrentGun = gunModelDefinition.mask
? node.name.startsWith(gunString) ? node.name.startsWith(gunString)
: node.name === gunString; : node.name === gunString;
@@ -28,8 +28,8 @@ export interface ThicknessRange {
export const StaticArmor = memo<ArmorSceneProps>(({ thicknessRange }) => { export const StaticArmor = memo<ArmorSceneProps>(({ thicknessRange }) => {
const wrapper = useRef<Group>(null); const wrapper = useRef<Group>(null);
const turretContainer = useRef<Group>(null); const turretContainer = useRef<Group>(null!);
const gunContainer = useRef<Group>(null); const gunContainer = useRef<Group>(null!);
const tank = Duel.use((state) => state.protagonist.tank); const tank = Duel.use((state) => state.protagonist.tank);
const track = Duel.use((state) => state.protagonist.track); const track = Duel.use((state) => state.protagonist.track);
const turret = Duel.use((state) => state.protagonist.turret); const turret = Duel.use((state) => state.protagonist.turret);
@@ -1,8 +1,8 @@
import { I_HAT, J_HAT } from "@blitzkit/core"; import { I_HAT, J_HAT } from "@blitzkit/core";
import { type MeshProps, useThree } from "@react-three/fiber"; import { useThree } from "@react-three/fiber";
import { clamp } from "lodash-es"; import { clamp } from "lodash-es";
import type { QuicklimeEvent } from "quicklime"; import type { QuicklimeEvent } from "quicklime";
import { useEffect, useMemo } from "react"; import { useEffect, useMemo, type ComponentProps } from "react";
import { import {
Box3, Box3,
Color, Color,
@@ -19,8 +19,8 @@ import {
import { unrotateDavaVector } from "../../../core/blitz/unrotateDavaVector"; import { unrotateDavaVector } from "../../../core/blitz/unrotateDavaVector";
import { jsxTree } from "../../../core/blitzkit/jsxTree"; import { jsxTree } from "../../../core/blitzkit/jsxTree";
import { import {
type ModelTransformEventData,
modelTransformEvent, modelTransformEvent,
type ModelTransformEventData,
} from "../../../core/blitzkit/modelTransform"; } from "../../../core/blitzkit/modelTransform";
import { discardClippingPlane } from "../../../core/three/discardClippingPlane"; import { discardClippingPlane } from "../../../core/three/discardClippingPlane";
import { Tankopedia } from "../../../stores/tankopedia"; import { Tankopedia } from "../../../stores/tankopedia";
@@ -36,7 +36,7 @@ type StaticArmorSceneComponentProps = {
thickness: number; thickness: number;
thicknessRange: ThicknessRange; thicknessRange: ThicknessRange;
node: Object3D; node: Object3D;
onPointerDown?: MeshProps["onPointerDown"]; onPointerDown?: ComponentProps<"mesh">["onPointerDown"];
} & ( } & (
| { | {
type: Exclude<ArmorType, ArmorType.External>; type: Exclude<ArmorType, ArmorType.External>;
+30 -30
View File
@@ -1,15 +1,15 @@
--- ---
import { assertSecret, fetchGameDefinitions } from '@blitzkit/core'; import { assertSecret, fetchGameDefinitions } from "@blitzkit/core";
import { DEFAULT_LOCALE } from '@blitzkit/i18n'; import locales from "@blitzkit/i18n/locales.json";
import { Box, Code, Flex, Heading, Link, Text } from '@radix-ui/themes'; import { Box, Code, Flex, Heading, Link, Text } from "@radix-ui/themes";
import packageJson from '../../../../package.json'; import packageJson from "../../../../package.json";
import { getStrings } from '../core/i18n/getStrings'; import { getStrings } from "../core/i18n/getStrings";
import { LinkI18n } from './LinkI18n'; import { LinkI18n } from "./LinkI18n";
import { LocaleSwitcherThemeWrapper } from './LocaleSwitcher'; import { LocaleSwitcherThemeWrapper } from "./LocaleSwitcher";
const gameDefinitions = await fetchGameDefinitions(); const gameDefinitions = await fetchGameDefinitions();
const PUBLIC_ASSET_BRANCH = assertSecret(import.meta.env.PUBLIC_BRANCH); const PUBLIC_ASSET_BRANCH = assertSecret(import.meta.env.PUBLIC_BRANCH);
const locale = Astro.params.locale ?? DEFAULT_LOCALE; const locale = Astro.params.locale ?? locales.default;
const strings = getStrings(locale); const strings = getStrings(locale);
--- ---
@@ -28,13 +28,13 @@ const strings = getStrings(locale);
flexGrow="1" flexGrow="1"
gap="5" gap="5"
position="relative" position="relative"
direction={{ initial: 'column', sm: 'row' }} direction={{ initial: "column", sm: "row" }}
> >
<Flex <Flex
direction="column" direction="column"
align={{ align={{
initial: 'center', initial: "center",
sm: 'start', sm: "start",
}} }}
> >
<Heading>BlitzKit</Heading> <Heading>BlitzKit</Heading>
@@ -51,32 +51,32 @@ const strings = getStrings(locale);
<Flex <Flex
gap="6" gap="6"
width={{ width={{
initial: '100%', initial: "100%",
sm: 'auto', sm: "auto",
}} }}
> >
<Flex <Flex
direction="column" direction="column"
gap="1" gap="1"
align={{ align={{
initial: 'end', initial: "end",
sm: 'start', sm: "start",
}} }}
flexGrow={{ flexGrow={{
initial: '1', initial: "1",
sm: '0', sm: "0",
}} }}
flexBasis={{ flexBasis={{
initial: '0', initial: "0",
sm: 'auto', sm: "auto",
}} }}
> >
<Heading size="3">{strings.website.footer.about.title}</Heading> <Heading size="3">{strings.website.footer.about.title}</Heading>
<Flex <Flex
direction="column" direction="column"
align={{ align={{
initial: 'end', initial: "end",
sm: 'start', sm: "start",
}} }}
> >
<LinkI18n {locale} href="/docs/about/credits" color="gray"> <LinkI18n {locale} href="/docs/about/credits" color="gray">
@@ -106,12 +106,12 @@ const strings = getStrings(locale);
direction="column" direction="column"
gap="1" gap="1"
flexGrow={{ flexGrow={{
initial: '1', initial: "1",
sm: '0', sm: "0",
}} }}
flexBasis={{ flexBasis={{
initial: '0', initial: "0",
sm: 'auto', sm: "auto",
}} }}
> >
<Heading size="3">{strings.website.footer.legal.title}</Heading> <Heading size="3">{strings.website.footer.legal.title}</Heading>
@@ -127,11 +127,11 @@ const strings = getStrings(locale);
</Flex> </Flex>
</Flex> </Flex>
<Flex gap="5" display={{ initial: 'flex', sm: 'none' }} width="100%"> <Flex gap="5" display={{ initial: "flex", sm: "none" }} width="100%">
<Flex direction="column" gap="1" flexGrow="1" flexBasis="0" align="end"> <Flex direction="column" gap="1" flexGrow="1" flexBasis="0" align="end">
<Text size="2" color="gray">BlitzKit</Text> <Text size="2" color="gray">BlitzKit</Text>
{ {
PUBLIC_ASSET_BRANCH !== 'preview' && ( PUBLIC_ASSET_BRANCH !== "preview" && (
<Text size="2" color="gray"> <Text size="2" color="gray">
WoTB WoTB
</Text> </Text>
@@ -145,7 +145,7 @@ const strings = getStrings(locale);
{packageJson.version} {packageJson.version}
</Code> </Code>
{ {
PUBLIC_ASSET_BRANCH !== 'preview' && ( PUBLIC_ASSET_BRANCH !== "preview" && (
<Code size="2" color="gray"> <Code size="2" color="gray">
{gameDefinitions.version} {gameDefinitions.version}
</Code> </Code>
@@ -157,14 +157,14 @@ const strings = getStrings(locale);
</Flex> </Flex>
</Flex> </Flex>
<Flex gap="2" align="center" display={{ initial: 'none', sm: 'flex' }}> <Flex gap="2" align="center" display={{ initial: "none", sm: "flex" }}>
<Text size="2" color="gray">BlitzKit</Text> <Text size="2" color="gray">BlitzKit</Text>
<Code size="2" color="gray"> <Code size="2" color="gray">
{packageJson.version} {packageJson.version}
</Code> </Code>
{ {
PUBLIC_ASSET_BRANCH !== 'preview' && ( PUBLIC_ASSET_BRANCH !== "preview" && (
<> <>
<Text size="2" color="gray"> <Text size="2" color="gray">
WoTB WoTB
@@ -1,5 +1,5 @@
import { asset, Avatar } from '@blitzkit/core'; import { asset, Avatar } from "@blitzkit/core";
import { Cross1Icon, DownloadIcon } from '@radix-ui/react-icons'; import { Cross1Icon, DownloadIcon } from "@radix-ui/react-icons";
import { import {
Dialog, Dialog,
Flex, Flex,
@@ -7,11 +7,11 @@ import {
Link, Link,
Skeleton, Skeleton,
Text, Text,
} from '@radix-ui/themes'; } from "@radix-ui/themes";
import { useRef } from 'react'; import { useRef } from "react";
import { useIntersection } from '../../hooks/useIntersection'; import { useIntersection } from "../../hooks/useIntersection";
import { useLocale } from '../../hooks/useLocale'; import { useLocale } from "../../hooks/useLocale";
import type { MaybeSkeletonComponentProps } from '../../types/maybeSkeletonComponentProps'; import type { MaybeSkeletonComponentProps } from "../../types/maybeSkeletonComponentProps";
type GalleryCardProps = MaybeSkeletonComponentProps<{ type GalleryCardProps = MaybeSkeletonComponentProps<{
avatar: Avatar; avatar: Avatar;
@@ -19,9 +19,9 @@ type GalleryCardProps = MaybeSkeletonComponentProps<{
export function GalleryCard(props: GalleryCardProps) { export function GalleryCard(props: GalleryCardProps) {
const src = asset( const src = asset(
`gallery/avatars/${!props.skeleton && `${props.avatar.id}${props.avatar.extension}`}`, `gallery/avatars/${!props.skeleton && `${props.avatar.id}${props.avatar.extension}`}`
); );
const card = useRef<HTMLDivElement>(null); const card = useRef<HTMLDivElement>(null!);
const { unwrap } = useLocale(); const { unwrap } = useLocale();
useIntersection(() => props.skeleton && props.onIntersection?.(), card, { useIntersection(() => props.skeleton && props.onIntersection?.(), card, {
@@ -35,7 +35,7 @@ export function GalleryCard(props: GalleryCardProps) {
width="6rem" width="6rem"
gap="1" gap="1"
ref={card} ref={card}
style={{ cursor: 'pointer' }} style={{ cursor: "pointer" }}
> >
{props.skeleton && ( {props.skeleton && (
<> <>
@@ -48,16 +48,16 @@ export function GalleryCard(props: GalleryCardProps) {
<> <>
<img <img
style={{ style={{
width: '4rem', width: "4rem",
height: '4.57rem', height: "4.57rem",
// aspect ratio 7 / 8 // aspect ratio 7 / 8
objectFit: 'cover', objectFit: "cover",
}} }}
src={src} src={src}
alt={unwrap(props.avatar.name)} alt={unwrap(props.avatar.name)}
/> />
<Text size="1" align="center" style={{ maxWidth: '100%' }}> <Text size="1" align="center" style={{ maxWidth: "100%" }}>
{unwrap(props.avatar.name)} {unwrap(props.avatar.name)}
</Text> </Text>
</> </>
@@ -94,7 +94,7 @@ export function GalleryCard(props: GalleryCardProps) {
</Flex> </Flex>
<Flex justify="center" mt="4"> <Flex justify="center" mt="4">
<Dialog.Title align="center" style={{ maxWidth: '10rem' }}> <Dialog.Title align="center" style={{ maxWidth: "10rem" }}>
{unwrap(props.avatar.name)} {unwrap(props.avatar.name)}
</Dialog.Title> </Dialog.Title>
</Flex> </Flex>
@@ -1,7 +1,6 @@
import type { SpotLightProps } from '@react-three/fiber'; import { memo, type ComponentProps } from "react";
import { memo } from 'react';
interface Props extends SpotLightProps { interface Props extends ComponentProps<"spotLight"> {
debug?: boolean; debug?: boolean;
} }
@@ -1,12 +1,12 @@
import { DEFAULT_LOCALE } from '@blitzkit/i18n'; import locales from "@blitzkit/i18n/locales.json";
import { GlobeIcon } from '@radix-ui/react-icons'; import { GlobeIcon } from "@radix-ui/react-icons";
import { Flex, Text } from '@radix-ui/themes'; import { Flex, Text } from "@radix-ui/themes";
import type { LocaleAcceptorProps } from '../../hooks/useLocale'; import type { LocaleAcceptorProps } from "../../hooks/useLocale";
import { BlitzKitTheme } from '../BlitzKitTheme'; import { BlitzKitTheme } from "../BlitzKitTheme";
import { LocaleSwitcher } from '../LocaleSwitcher'; import { LocaleSwitcher } from "../LocaleSwitcher";
export function HomeLocaleSwitcher({ export function HomeLocaleSwitcher({
locale = DEFAULT_LOCALE, locale = locales.default,
}: LocaleAcceptorProps) { }: LocaleAcceptorProps) {
return ( return (
<BlitzKitTheme> <BlitzKitTheme>
+5 -5
View File
@@ -1,14 +1,14 @@
import { DEFAULT_LOCALE } from '@blitzkit/i18n'; import locales from "@blitzkit/i18n/locales.json";
import { Link, type LinkProps } from '@radix-ui/themes'; import { Link, type LinkProps } from "@radix-ui/themes";
import type { LocaleAcceptorProps } from '../hooks/useLocale'; import type { LocaleAcceptorProps } from "../hooks/useLocale";
type LinkI18nProps = LinkProps & LocaleAcceptorProps; type LinkI18nProps = LinkProps & LocaleAcceptorProps;
export function LinkI18n({ locale, href, ...props }: LinkI18nProps) { export function LinkI18n({ locale, href, ...props }: LinkI18nProps) {
const prefix = const prefix =
locale === undefined || locale === DEFAULT_LOCALE ? '' : `/${locale}`; locale === undefined || locale === locales.default ? "" : `/${locale}`;
return ( return (
<Link href={href?.startsWith('/') ? `${prefix}${href}` : href} {...props} /> <Link href={href?.startsWith("/") ? `${prefix}${href}` : href} {...props} />
); );
} }
@@ -1,12 +1,13 @@
<script> <script>
import { SUPPORTED_LOCALES } from "@blitzkit/i18n"; import locales from "@blitzkit/i18n/locales.json";
import { getBestLocale } from "../core/i18n/getBestLocale"; import { getBestLocale } from "../core/i18n/getBestLocale";
const isAPI = window.location.pathname.startsWith("/api"); const isAPI = window.location.pathname.startsWith("/api");
const isI18nPath = SUPPORTED_LOCALES.some((locale) => const isI18nPath = locales.supported.some(({ locale }) =>
window.location.pathname.startsWith(`/${locale}`) window.location.pathname.startsWith(`/${locale}`)
); );
const bestLocale = getBestLocale(); const bestLocale = getBestLocale();
const currentPathLocale = SUPPORTED_LOCALES.find((locale) => const currentPathLocale = locales.supported.find(({ locale }) =>
window.location.pathname.startsWith(`/${locale}`) window.location.pathname.startsWith(`/${locale}`)
); );
@@ -1,19 +0,0 @@
import {
ResponsiveBar,
type BarDatum,
type ResponsiveBarSvgProps,
} from '@nivo/bar';
import { nivoTheme } from '../../core/nivo/theme';
export function ThemedBar<RawDatum extends BarDatum>(
props: ResponsiveBarSvgProps<RawDatum>,
) {
return (
<ResponsiveBar
colors={{ scheme: 'yellow_green_blue' }}
theme={nivoTheme}
borderRadius={4}
{...props}
/>
);
}
@@ -1,15 +0,0 @@
import { ResponsiveLine, type LineSvgProps } from '@nivo/line';
import { nivoTheme } from '../../core/nivo/theme';
export function ThemedLine(props: LineSvgProps) {
return (
<ResponsiveLine
colors={{ scheme: 'yellow_green_blue' }}
theme={nivoTheme}
margin={{ top: 50, right: 110, bottom: 50, left: 60 }}
enablePoints={true}
useMesh
{...props}
/>
);
}
@@ -1,15 +1,15 @@
import { Skeleton, Table } from '@radix-ui/themes'; import { Skeleton, Table } from "@radix-ui/themes";
import { times } from 'lodash-es'; import { times } from "lodash-es";
import { memo, useRef } from 'react'; import { memo, useRef } from "react";
import { useIntersection } from '../../hooks/useIntersection'; import { useIntersection } from "../../hooks/useIntersection";
import { TankPerformanceSortTypeNamesArray } from '../../stores/tankPerformanceSort/constants'; import { TankPerformanceSortTypeNamesArray } from "../../stores/tankPerformanceSort/constants";
interface RowLoaderProps { interface RowLoaderProps {
onIntersection?: () => void; onIntersection?: () => void;
} }
export const RowLoader = memo<RowLoaderProps>(({ onIntersection }) => { export const RowLoader = memo<RowLoaderProps>(({ onIntersection }) => {
const row = useRef<HTMLTableRowElement>(null); const row = useRef<HTMLTableRowElement>(null!);
useIntersection(() => onIntersection?.(), row, { useIntersection(() => onIntersection?.(), row, {
disabled: onIntersection === undefined, disabled: onIntersection === undefined,
@@ -1,20 +1,20 @@
import { Canvas, type CanvasProps } from '@react-three/fiber'; import { Canvas, type CanvasProps } from "@react-three/fiber";
import { forwardRef, useImperativeHandle, useRef } from 'react'; import { forwardRef, useImperativeHandle, useRef } from "react";
import { useOnScreen } from '../hooks/useOnScreen'; import { useOnScreen } from "../hooks/useOnScreen";
export const SmartCanvas = forwardRef<HTMLCanvasElement, CanvasProps>( export const SmartCanvas = forwardRef<HTMLCanvasElement, CanvasProps>(
(props, ref) => { (props, ref) => {
const canvas = useRef<HTMLCanvasElement>(null); const canvas = useRef<HTMLCanvasElement>(null!);
const onScreen = useOnScreen(canvas); const onScreen = useOnScreen(canvas);
useImperativeHandle(ref, () => canvas.current!, []); useImperativeHandle(ref, () => canvas.current!, []);
return ( return (
<Canvas <Canvas
frameloop={onScreen ? 'demand' : 'never'} frameloop={onScreen ? "demand" : "never"}
ref={canvas} ref={canvas}
{...props} {...props}
/> />
); );
}, }
); );
@@ -1,6 +1,6 @@
import { Flex, Skeleton } from '@radix-ui/themes'; import { Flex, Skeleton } from "@radix-ui/themes";
import { memo, useRef } from 'react'; import { memo, useRef } from "react";
import { useIntersection } from '../../../hooks/useIntersection'; import { useIntersection } from "../../../hooks/useIntersection";
interface SkeletonTankCardProps { interface SkeletonTankCardProps {
onIntersection?: () => void; onIntersection?: () => void;
@@ -8,7 +8,7 @@ interface SkeletonTankCardProps {
export const SkeletonTankCard = memo( export const SkeletonTankCard = memo(
({ onIntersection }: SkeletonTankCardProps) => { ({ onIntersection }: SkeletonTankCardProps) => {
const card = useRef<HTMLDivElement>(null); const card = useRef<HTMLDivElement>(null!);
useIntersection(() => onIntersection?.(), card, { useIntersection(() => onIntersection?.(), card, {
disabled: onIntersection === undefined, disabled: onIntersection === undefined,
@@ -21,5 +21,5 @@ export const SkeletonTankCard = memo(
</Flex> </Flex>
); );
}, },
() => true, () => true
); );
@@ -38,7 +38,7 @@ export function Info({
const result = fuzzysort.single(statSearch, name); const result = fuzzysort.single(statSearch, name);
if (result) { if (result) {
label = fuzzysort.highlight(result, (match, index) => ( label = result.highlight((match, index) => (
<Mark key={index}>{match}</Mark> <Mark key={index}>{match}</Mark>
)); ));
highlighted = true; highlighted = true;
@@ -19,8 +19,8 @@ export function TankModel() {
const turret = Duel.use((state) => state.protagonist.turret); const turret = Duel.use((state) => state.protagonist.turret);
const canvas = useThree((state) => state.gl.domElement); const canvas = useThree((state) => state.gl.domElement);
const hullContainer = useRef<Group>(null); const hullContainer = useRef<Group>(null);
const turretContainer = useRef<Group>(null); const turretContainer = useRef<Group>(null!);
const gunContainer = useRef<Group>(null); const gunContainer = useRef<Group>(null!);
const tankModelDefinition = useTankModelDefinition(); const tankModelDefinition = useTankModelDefinition();
const turretModelDefinition = const turretModelDefinition =
tankModelDefinition.turrets[protagonist.turret.id]; tankModelDefinition.turrets[protagonist.turret.id];
@@ -26,8 +26,8 @@ export function TransitionSkeleton() {
const gun = Duel.use((state) => state.protagonist.gun); const gun = Duel.use((state) => state.protagonist.gun);
const track = Duel.use((state) => state.protagonist.track); const track = Duel.use((state) => state.protagonist.track);
const turret = Duel.use((state) => state.protagonist.turret); const turret = Duel.use((state) => state.protagonist.turret);
const turretContainer = useRef<Group>(null); const turretContainer = useRef<Group>(null!);
const gunContainer = useRef<Group>(null); const gunContainer = useRef<Group>(null!);
const { gltf: armorGltf } = useArmor(tank.id); const { gltf: armorGltf } = useArmor(tank.id);
const { gltf: modelGltf } = useModel(tank.id); const { gltf: modelGltf } = useModel(tank.id);
const modelNodes = Object.values(modelGltf.nodes); const modelNodes = Object.values(modelGltf.nodes);
@@ -16,7 +16,7 @@ const tankDefinitions = await awaitableTankDefinitions;
export function HeroSection({ skeleton }: MaybeSkeletonComponentProps) { export function HeroSection({ skeleton }: MaybeSkeletonComponentProps) {
const revealed = Tankopedia.use((state) => state.revealed); const revealed = Tankopedia.use((state) => state.revealed);
const disturbed = Tankopedia.use((state) => state.disturbed); const disturbed = Tankopedia.use((state) => state.disturbed);
const canvas = useRef<HTMLCanvasElement>(null); const canvas = useRef<HTMLCanvasElement>(null!);
const isFullScreen = useFullScreen(); const isFullScreen = useFullScreen();
const protagonist = Duel.use((state) => state.protagonist.tank); const protagonist = Duel.use((state) => state.protagonist.tank);
const thicknessRange = useMemo(() => { const thicknessRange = useMemo(() => {
+13 -6
View File
@@ -1,13 +1,20 @@
import type { GroupProps, MeshProps } from '@react-three/fiber'; import type { ComponentProps, ReactNode } from "react";
import type { ReactNode } from 'react'; import { Mesh, Object3D } from "three";
import { Mesh, Object3D } from 'three';
export function jsxTree( export function jsxTree(
node: Object3D, node: Object3D,
mergers?: { mergers?: {
mesh?: (mesh: Mesh, props: MeshProps, key: string) => ReactNode; mesh?: (
group?: (object3d: Object3D, props: GroupProps, key: string) => ReactNode; mesh: Mesh,
}, props: ComponentProps<"mesh">,
key: string
) => ReactNode;
group?: (
object3d: Object3D,
props: ComponentProps<"group">,
key: string
) => ReactNode;
}
): ReactNode { ): ReactNode {
if (node instanceof Mesh) { if (node instanceof Mesh) {
const props = { const props = {
@@ -1,13 +1,13 @@
import { DEFAULT_LOCALE, SUPPORTED_LOCALES } from '@blitzkit/i18n'; import locales from "@blitzkit/i18n/locales.json";
export function getBestLocale() { export function getBestLocale() {
const desiredLocale = const desiredLocale =
localStorage.getItem('preferred-locale') ?? localStorage.getItem("preferred-locale") ??
navigator.language.split('-')[0]; navigator.language.split("-")[0];
const isSupported = (SUPPORTED_LOCALES as unknown as string[]).includes( const isSupported = locales.supported.some(
desiredLocale, ({ locale }) => locale === desiredLocale
); );
const isDefault = desiredLocale === DEFAULT_LOCALE; const isDefault = desiredLocale === locales.default;
if (!isSupported || isDefault) return undefined; if (!isSupported || isDefault) return undefined;
-39
View File
@@ -1,39 +0,0 @@
import type { Theme } from '@nivo/core';
import { Var } from '../radix/var';
export const nivoTheme = {
background: Var('color-background'),
text: {
fill: Var('gray-contrast'),
fontFamily: 'inherit',
},
axis: {
ticks: {
text: {
fill: Var('gray-indicator'),
},
line: {
stroke: Var('gray-indicator'),
},
},
},
grid: {
line: {
stroke: Var('gray-indicator'),
},
},
tooltip: {
container: {
background: Var('color-overlay'),
backdropFilter: 'blur(4rem)',
WebkitBackdropFilter: 'blur(4rem)',
color: Var('gray-contrast'),
borderRadius: Var('radius-2'),
},
},
labels: {
text: {
fill: Var('gray-1'),
},
},
} satisfies Theme;
@@ -1,4 +1,4 @@
import { type RefObject, useEffect, useRef } from 'react'; import { type RefObject, useEffect, useRef } from "react";
interface UseIntersectionOptions extends IntersectionObserverInit { interface UseIntersectionOptions extends IntersectionObserverInit {
disabled: boolean; disabled: boolean;
@@ -7,9 +7,9 @@ interface UseIntersectionOptions extends IntersectionObserverInit {
export function useIntersection( export function useIntersection(
callback: () => void, callback: () => void,
ref: RefObject<HTMLElement>, ref: RefObject<HTMLElement>,
options?: UseIntersectionOptions, options?: UseIntersectionOptions
) { ) {
const observer = useRef<IntersectionObserver>(); const observer = useRef<IntersectionObserver>(null!);
useEffect(() => { useEffect(() => {
if (options?.disabled || !ref.current) return; if (options?.disabled || !ref.current) return;
+6 -5
View File
@@ -1,6 +1,7 @@
import { DEFAULT_LOCALE, unwrapper } from '@blitzkit/i18n'; import { unwrapper } from "@blitzkit/i18n";
import { createContext, useContext, type ReactNode } from 'react'; import locales from "@blitzkit/i18n/locales.json";
import { getStrings } from '../core/i18n/getStrings'; import { createContext, useContext, type ReactNode } from "react";
import { getStrings } from "../core/i18n/getStrings";
const LocaleContext = createContext<{ const LocaleContext = createContext<{
locale: string; locale: string;
@@ -14,7 +15,7 @@ interface LocaleProviderProps extends LocaleAcceptorProps {
export function LocaleProvider({ locale, children }: LocaleProviderProps) { export function LocaleProvider({ locale, children }: LocaleProviderProps) {
return ( return (
<LocaleContext.Provider <LocaleContext.Provider
value={{ locale: locale ?? DEFAULT_LOCALE, localeRaw: locale }} value={{ locale: locale ?? locales.default, localeRaw: locale }}
> >
{children} {children}
</LocaleContext.Provider> </LocaleContext.Provider>
@@ -25,7 +26,7 @@ export function useLocale() {
const context = useContext(LocaleContext); const context = useContext(LocaleContext);
if (!context) { if (!context) {
throw new Error('useLocale must be used within a LocaleProvider'); throw new Error("useLocale must be used within a LocaleProvider");
} }
const strings = getStrings(context.locale); const strings = getStrings(context.locale);
+4 -4
View File
@@ -1,17 +1,17 @@
import { type RefObject, useEffect, useRef, useState } from 'react'; import { type RefObject, useEffect, useRef, useState } from "react";
/** /**
* Thanks GuCier! * Thanks GuCire!
* *
* https://stackoverflow.com/a/65008608/12294756 * https://stackoverflow.com/a/65008608/12294756
*/ */
export function useOnScreen(ref: RefObject<HTMLElement>) { export function useOnScreen(ref: RefObject<HTMLElement>) {
const [isIntersecting, setIntersecting] = useState(false); const [isIntersecting, setIntersecting] = useState(false);
const observer = useRef<IntersectionObserver>(); const observer = useRef<IntersectionObserver>(null!);
useEffect(() => { useEffect(() => {
observer.current = new IntersectionObserver(([entry]) => observer.current = new IntersectionObserver(([entry]) =>
setIntersecting(entry.isIntersecting), setIntersecting(entry.isIntersecting)
); );
}, [ref]); }, [ref]);
@@ -1,5 +1,4 @@
--- ---
import { DEFAULT_LOCALE } from "@blitzkit/i18n";
import strings from "@blitzkit/i18n/strings/en.json"; import strings from "@blitzkit/i18n/strings/en.json";
import "@fontsource/inter"; import "@fontsource/inter";
import { Flex } from "@radix-ui/themes"; import { Flex } from "@radix-ui/themes";
@@ -22,7 +21,7 @@ export interface Props {
const servicing = import.meta.env.SERVICING; const servicing = import.meta.env.SERVICING;
const { noFooter, noNavbar, integrated } = Astro.props; const { noFooter, noNavbar, integrated } = Astro.props;
const locale = Astro.params.locale ?? DEFAULT_LOCALE; const locale = Astro.params.locale;
--- ---
<html lang={locale}> <html lang={locale}>
@@ -60,7 +60,7 @@ function Content({ embed }: PageProps) {
const [backgroundImage, setBackgroundImage] = useState( const [backgroundImage, setBackgroundImage] = useState(
"/assets/images/backgrounds/embed-default.webp" "/assets/images/backgrounds/embed-default.webp"
); );
const fileInput = useRef<HTMLInputElement>(); const fileInput = useRef<HTMLInputElement>(null!);
const { strings } = useLocale(); const { strings } = useLocale();
useEffect(() => { useEffect(() => {
@@ -109,7 +109,7 @@ function Content({ skeleton }: MaybeSkeletonComponentProps) {
const hull = Mixer.use((state) => state.hull); const hull = Mixer.use((state) => state.hull);
const turretId = Mixer.use((state) => state.turret.tank.id); const turretId = Mixer.use((state) => state.turret.tank.id);
const gunId = Mixer.use((state) => state.gun.tank.id); const gunId = Mixer.use((state) => state.gun.tank.id);
const canvas = useRef<HTMLCanvasElement>(null); const canvas = useRef<HTMLCanvasElement>(null!);
const { strings } = useLocale(); const { strings } = useLocale();
return ( return (
@@ -1,4 +1,3 @@
import { DEFAULT_LOCALE } from "@blitzkit/i18n";
import { Flex, Switch, Text } from "@radix-ui/themes"; import { Flex, Switch, Text } from "@radix-ui/themes";
import { LocaleSwitcher } from "../../../components/LocaleSwitcher"; import { LocaleSwitcher } from "../../../components/LocaleSwitcher";
import { PageWrapper } from "../../../components/PageWrapper"; import { PageWrapper } from "../../../components/PageWrapper";
@@ -9,7 +8,7 @@ import {
} from "../../../hooks/useLocale"; } from "../../../hooks/useLocale";
import { App } from "../../../stores/app"; import { App } from "../../../stores/app";
export function Page({ locale = DEFAULT_LOCALE }: LocaleAcceptorProps) { export function Page({ locale }: LocaleAcceptorProps) {
return ( return (
<LocaleProvider locale={locale}> <LocaleProvider locale={locale}>
<Content locale={locale} /> <Content locale={locale} />
@@ -1,5 +1,5 @@
--- ---
import { AstroSeo } from '@astrolib/seo'; import { AstroSeo } from "@astrolib/seo";
import { import {
assertSecret, assertSecret,
asset, asset,
@@ -11,17 +11,17 @@ import {
fetchSkillDefinitions, fetchSkillDefinitions,
fetchTankDefinitions, fetchTankDefinitions,
TIER_ROMAN_NUMERALS, TIER_ROMAN_NUMERALS,
} from '@blitzkit/core'; } from "@blitzkit/core";
import { DEFAULT_LOCALE, unwrapper } from '@blitzkit/i18n'; import { unwrapper } from "@blitzkit/i18n";
import { literals } from '@blitzkit/i18n/src/literals'; import { literals } from "@blitzkit/i18n/src/literals";
import type { GetStaticPaths } from 'astro'; import type { GetStaticPaths } from "astro";
import { load } from 'cheerio'; import { load } from "cheerio";
import { tankCharacteristics } from '../../../../core/blitzkit/tankCharacteristics'; import { tankCharacteristics } from "../../../../core/blitzkit/tankCharacteristics";
import { getStrings } from '../../../../core/i18n/getStrings'; import { getStrings } from "../../../../core/i18n/getStrings";
import BaseLayout from '../../../../layouts/BaseLayout.astro'; import BaseLayout from "../../../../layouts/BaseLayout.astro";
import { genericDefaultEquipmentMatrix } from '../../../../stores/duel/constants'; import { genericDefaultEquipmentMatrix } from "../../../../stores/duel/constants";
import { getStaticPaths as parentGetStaticPaths } from '../index.astro'; import { getStaticPaths as parentGetStaticPaths } from "../index.astro";
import { Page } from './_index'; import { Page } from "./_index";
export const getStaticPaths = (async () => { export const getStaticPaths = (async () => {
const tankDefinitions = await fetchTankDefinitions(); const tankDefinitions = await fetchTankDefinitions();
@@ -32,13 +32,13 @@ export const getStaticPaths = (async () => {
parentPaths.map((parent) => ({ parentPaths.map((parent) => ({
params: { ...parent.params, slug: tank.slug }, params: { ...parent.params, slug: tank.slug },
props: { id: tank.id }, props: { id: tank.id },
})), }))
) )
.flat(); .flat();
}) satisfies GetStaticPaths; }) satisfies GetStaticPaths;
const { id } = Astro.props; const { id } = Astro.props;
const locale = Astro.params.locale ?? DEFAULT_LOCALE; const locale = Astro.params.locale;
const strings = getStrings(locale); const strings = getStrings(locale);
const tankDefinitions = await fetchTankDefinitions(); const tankDefinitions = await fetchTankDefinitions();
const skillDefinitions = await fetchSkillDefinitions(); const skillDefinitions = await fetchSkillDefinitions();
@@ -56,7 +56,7 @@ const title = literals(strings.website.tools.tankopedia.tank_seo_title, [
tank.nation as keyof typeof strings.common.nations_adjectives tank.nation as keyof typeof strings.common.nations_adjectives
], ],
strings.common.tank_class_short[tank.class], strings.common.tank_class_short[tank.class],
'BlitzKit', "BlitzKit",
strings.common.nations[tank.nation as keyof typeof strings.common.nations], strings.common.nations[tank.nation as keyof typeof strings.common.nations],
]); ]);
const url = import.meta.env.SITE + Astro.url.pathname; const url = import.meta.env.SITE + Astro.url.pathname;
@@ -87,7 +87,7 @@ const characteristics = tankCharacteristics(
track: tank.tracks.at(-1)!, track: tank.tracks.at(-1)!,
assaultDistance: 0, assaultDistance: 0,
}, },
{ equipmentDefinitions, provisionDefinitions, tankModelDefinition }, { equipmentDefinitions, provisionDefinitions, tankModelDefinition }
); );
const description = literals( const description = literals(
strings.website.tools.tankopedia.tank_seo_description, strings.website.tools.tankopedia.tank_seo_description,
@@ -98,7 +98,7 @@ const description = literals(
Math.round(characteristics.penetration).toLocaleString(locale), Math.round(characteristics.penetration).toLocaleString(locale),
Math.round(characteristics.speedForwards).toLocaleString(locale), Math.round(characteristics.speedForwards).toLocaleString(locale),
Math.round(characteristics.health).toLocaleString(locale), Math.round(characteristics.health).toLocaleString(locale),
], ]
); );
export interface TankGuide { export interface TankGuide {
@@ -113,8 +113,8 @@ const guideResponse = await fetch(guideUrl);
if (guideResponse.ok) { if (guideResponse.ok) {
const $ = await guideResponse.text().then(load); const $ = await guideResponse.text().then(load);
const description = $('.entry-content p').first().text(); const description = $(".entry-content p").first().text();
const image = $('.entry-content img').first().attr('src')?.toString(); const image = $(".entry-content img").first().attr("src")?.toString();
if (description !== undefined || image !== undefined) { if (description !== undefined || image !== undefined) {
guide = { guide = {