diff --git a/bun.lockb b/bun.lockb index 90fba2261..00fca5d13 100755 Binary files a/bun.lockb and b/bun.lockb differ diff --git a/packages/i18n/src/unwrapper.ts b/packages/i18n/src/unwrapper.ts index 7c18ae5ba..d293dc9d4 100644 --- a/packages/i18n/src/unwrapper.ts +++ b/packages/i18n/src/unwrapper.ts @@ -1,12 +1,12 @@ -import { I18nString } from '@blitzkit/core'; -import { DEFAULT_LOCALE } from './strings'; +import { I18nString } from "@blitzkit/core"; +import locales from "@blitzkit/i18n/locales.json"; -export function unwrapper(locale: string) { +export function unwrapper(locale = locales.default) { return function (i18nString: I18nString) { if (locale in i18nString.locales) { return i18nString.locales[locale]; } - return i18nString.locales[DEFAULT_LOCALE]; + return i18nString.locales[locales.default]; }; } diff --git a/packages/website/package.json b/packages/website/package.json index b760100a3..8e33fa9f2 100644 --- a/packages/website/package.json +++ b/packages/website/package.json @@ -5,16 +5,19 @@ "dev": "astro dev", "build": "astro build", "preview": "astro preview", + "lint": "astro check", "astro": "astro" }, "dependencies": { "@astrojs/react": "^4.4.0", "@radix-ui/colors": "^3.0.0", + "@react-three/fiber": "^9.3.0", "@types/react": "^19.1.14", "@types/react-dom": "^19.1.9", "@vite-pwa/astro": "^1.1.0", "astro": "^5.14.1", "astro-favicons": "^3.1.5", + "fuzzysort": "^3.1.0", "react": "^19.1.1", "react-dom": "^19.1.1" } diff --git a/packages/website/src/components/Armor/components/ModelTankWrapper.tsx b/packages/website/src/components/Armor/components/ModelTankWrapper.tsx index 9d0a9bdfe..dc3a7934c 100644 --- a/packages/website/src/components/Armor/components/ModelTankWrapper.tsx +++ b/packages/website/src/components/Armor/components/ModelTankWrapper.tsx @@ -1,7 +1,8 @@ -import type { GroupProps } from '@react-three/fiber'; -import { forwardRef } from 'react'; -import { Group } from 'three'; +import { forwardRef, type ComponentProps } from "react"; +import { Group } from "three"; -export const ModelTankWrapper = forwardRef((props, ref) => { - return ; -}); +export const ModelTankWrapper = forwardRef>( + (props, ref) => { + return ; + } +); diff --git a/packages/website/src/components/Armor/components/PrimaryArmorScene.tsx b/packages/website/src/components/Armor/components/PrimaryArmorScene.tsx index b333781c0..5d016e978 100644 --- a/packages/website/src/components/Armor/components/PrimaryArmorScene.tsx +++ b/packages/website/src/components/Armor/components/PrimaryArmorScene.tsx @@ -1,19 +1,19 @@ -import { memo, useRef } from 'react'; -import { Group } from 'three'; -import { correctZYTuple } from '../../../core/blitz/correctZYTuple'; -import { nameToArmorId } from '../../../core/blitzkit/nameToArmorId'; -import { resolveArmor } from '../../../core/blitzkit/resolveThickness'; -import { useArmor } from '../../../hooks/useArmor'; -import { useTankModelDefinition } from '../../../hooks/useTankModelDefinition'; -import { useTankTransform } from '../../../hooks/useTankTransform'; -import { Duel } from '../../../stores/duel'; -import { ModelTankWrapper } from './ModelTankWrapper'; -import { PrimaryArmorSceneComponent } from './PrimaryArmorSceneComponent'; +import { memo, useRef } from "react"; +import { Group } from "three"; +import { correctZYTuple } from "../../../core/blitz/correctZYTuple"; +import { nameToArmorId } from "../../../core/blitzkit/nameToArmorId"; +import { resolveArmor } from "../../../core/blitzkit/resolveThickness"; +import { useArmor } from "../../../hooks/useArmor"; +import { useTankModelDefinition } from "../../../hooks/useTankModelDefinition"; +import { useTankTransform } from "../../../hooks/useTankTransform"; +import { Duel } from "../../../stores/duel"; +import { ModelTankWrapper } from "./ModelTankWrapper"; +import { PrimaryArmorSceneComponent } from "./PrimaryArmorSceneComponent"; export const PrimaryArmorScene = memo(() => { const wrapper = useRef(null); - const turretContainer = useRef(null); - const gunContainer = useRef(null); + const turretContainer = useRef(null!); + const gunContainer = useRef(null!); const tank = Duel.use((state) => state.protagonist.tank); const track = Duel.use((state) => state.protagonist.track); const turret = Duel.use((state) => state.protagonist.turret); @@ -28,7 +28,7 @@ export const PrimaryArmorScene = memo(() => { const turretOrigin = correctZYTuple(tankModelDefinition.turret_origin); const gunOrigin = correctZYTuple(turretModelDefinition.gun_origin); const isDynamicArmorActive = Duel.use((state) => - state.protagonist.consumables.includes(73), + state.protagonist.consumables.includes(73) ); useTankTransform(track, turret, turretContainer, gunContainer); @@ -37,20 +37,20 @@ export const PrimaryArmorScene = memo(() => { {armorNodes.map((node) => { - const isHull = node.name.startsWith('hull_'); + const isHull = node.name.startsWith("hull_"); const isVisible = isHull; const armorId = nameToArmorId(node.name); const { spaced, thickness } = resolveArmor( tankModelDefinition.armor, - armorId, + armorId ); if ( !isVisible || spaced || thickness === undefined || - (isDynamicArmorActive && node.name.includes('state_01')) || - (!isDynamicArmorActive && node.name.includes('state_00')) + (isDynamicArmorActive && node.name.includes("state_01")) || + (!isDynamicArmorActive && node.name.includes("state_00")) ) return null; @@ -67,21 +67,21 @@ export const PrimaryArmorScene = memo(() => { {armorNodes.map((node) => { 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 armorId = nameToArmorId(node.name); const { spaced, thickness } = resolveArmor( turretModelDefinition.armor, - armorId, + armorId ); if ( !isVisible || spaced || thickness === undefined || - (isDynamicArmorActive && node.name.includes('state_01')) || - (!isDynamicArmorActive && node.name.includes('state_00')) + (isDynamicArmorActive && node.name.includes("state_01")) || + (!isDynamicArmorActive && node.name.includes("state_00")) ) return null; @@ -101,21 +101,21 @@ export const PrimaryArmorScene = memo(() => { {armorNodes.map((node) => { 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 armorId = nameToArmorId(node.name); const { spaced, thickness } = resolveArmor( gunModelDefinition.armor, - armorId, + armorId ); if ( !isVisible || spaced || thickness === undefined || - (isDynamicArmorActive && node.name.includes('state_01')) || - (!isDynamicArmorActive && node.name.includes('state_00')) + (isDynamicArmorActive && node.name.includes("state_01")) || + (!isDynamicArmorActive && node.name.includes("state_00")) ) return null; diff --git a/packages/website/src/components/Armor/components/SpacedArmorScene.tsx b/packages/website/src/components/Armor/components/SpacedArmorScene.tsx index a6954b82e..50cc38348 100644 --- a/packages/website/src/components/Armor/components/SpacedArmorScene.tsx +++ b/packages/website/src/components/Armor/components/SpacedArmorScene.tsx @@ -1,15 +1,15 @@ -import { memo, useRef } from 'react'; -import { Group, Plane, Scene, Vector3 } from 'three'; -import { correctZYTuple } from '../../../core/blitz/correctZYTuple'; -import { nameToArmorId } from '../../../core/blitzkit/nameToArmorId'; -import { resolveArmor } from '../../../core/blitzkit/resolveThickness'; -import { useArmor } from '../../../hooks/useArmor'; -import { useModel } from '../../../hooks/useModel'; -import { useTankModelDefinition } from '../../../hooks/useTankModelDefinition'; -import { useTankTransform } from '../../../hooks/useTankTransform'; -import { Duel } from '../../../stores/duel'; -import { ModelTankWrapper } from './ModelTankWrapper'; -import { SpacedArmorSceneComponent } from './SpacedArmorSceneComponent'; +import { memo, useRef } from "react"; +import { Group, Plane, Scene, Vector3 } from "three"; +import { correctZYTuple } from "../../../core/blitz/correctZYTuple"; +import { nameToArmorId } from "../../../core/blitzkit/nameToArmorId"; +import { resolveArmor } from "../../../core/blitzkit/resolveThickness"; +import { useArmor } from "../../../hooks/useArmor"; +import { useModel } from "../../../hooks/useModel"; +import { useTankModelDefinition } from "../../../hooks/useTankModelDefinition"; +import { useTankTransform } from "../../../hooks/useTankTransform"; +import { Duel } from "../../../stores/duel"; +import { ModelTankWrapper } from "./ModelTankWrapper"; +import { SpacedArmorSceneComponent } from "./SpacedArmorSceneComponent"; export enum ArmorType { Primary, @@ -23,8 +23,8 @@ interface SpacedArmorSceneProps { export const SpacedArmorScene = memo(({ scene }) => { const wrapper = useRef(null); - const turretContainer = useRef(null); - const gunContainer = useRef(null); + const turretContainer = useRef(null!); + const gunContainer = useRef(null!); const tank = Duel.use((state) => state.protagonist.tank); const track = Duel.use((state) => state.protagonist.track); const turret = Duel.use((state) => state.protagonist.turret); @@ -45,7 +45,7 @@ export const SpacedArmorScene = memo(({ scene }) => { ? undefined : gunModelDefinition.mask + hullOrigin.y + turretOrigin.y + gunOrigin.y; const isDynamicArmorActive = Duel.use((state) => - state.protagonist.consumables.includes(73), + state.protagonist.consumables.includes(73) ); useTankTransform(track, turret, turretContainer, gunContainer); @@ -54,19 +54,19 @@ export const SpacedArmorScene = memo(({ scene }) => { {armorNodes.map((node) => { - const isHull = node.name.startsWith('hull_'); + const isHull = node.name.startsWith("hull_"); const isVisible = isHull; const armorId = nameToArmorId(node.name); const { spaced, thickness } = resolveArmor( tankModelDefinition.armor, - armorId, + armorId ); if ( !isVisible || thickness === undefined || - (isDynamicArmorActive && node.name.includes('state_00')) || - (!isDynamicArmorActive && node.name.includes('state_01')) + (isDynamicArmorActive && node.name.includes("state_00")) || + (!isDynamicArmorActive && node.name.includes("state_01")) ) return null; @@ -83,8 +83,8 @@ export const SpacedArmorScene = memo(({ scene }) => { {modelNodes.map((node) => { - const isWheel = node.name.startsWith('chassis_wheel_'); - const isTrack = node.name.startsWith('chassis_track_'); + const isWheel = node.name.startsWith("chassis_wheel_"); + const isTrack = node.name.startsWith("chassis_track_"); const isVisible = isWheel || isTrack; if (!isVisible) return null; @@ -104,20 +104,20 @@ export const SpacedArmorScene = memo(({ scene }) => { {armorNodes.map((node) => { 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 armorId = nameToArmorId(node.name); const { spaced, thickness } = resolveArmor( turretModelDefinition.armor, - armorId, + armorId ); if ( !isVisible || thickness === undefined || - (isDynamicArmorActive && node.name.includes('state_00')) || - (!isDynamicArmorActive && node.name.includes('state_01')) + (isDynamicArmorActive && node.name.includes("state_00")) || + (!isDynamicArmorActive && node.name.includes("state_01")) ) return null; @@ -139,20 +139,20 @@ export const SpacedArmorScene = memo(({ scene }) => { {armorNodes.map((node) => { 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 armorId = nameToArmorId(node.name); const { spaced, thickness } = resolveArmor( gunModelDefinition.armor, - armorId, + armorId ); if ( !isVisible || thickness === undefined || - (isDynamicArmorActive && node.name.includes('state_00')) || - (!isDynamicArmorActive && node.name.includes('state_01')) + (isDynamicArmorActive && node.name.includes("state_00")) || + (!isDynamicArmorActive && node.name.includes("state_01")) ) return null; @@ -173,7 +173,7 @@ export const SpacedArmorScene = memo(({ scene }) => { {modelNodes.map((node) => { const gunString = `gun_${gunModelDefinition.model_id .toString() - .padStart(2, '0')}`; + .padStart(2, "0")}`; const isCurrentGun = gunModelDefinition.mask ? node.name.startsWith(gunString) : node.name === gunString; diff --git a/packages/website/src/components/Armor/components/StaticArmor.tsx b/packages/website/src/components/Armor/components/StaticArmor.tsx index 5226d626d..efb7f5d4b 100644 --- a/packages/website/src/components/Armor/components/StaticArmor.tsx +++ b/packages/website/src/components/Armor/components/StaticArmor.tsx @@ -28,8 +28,8 @@ export interface ThicknessRange { export const StaticArmor = memo(({ thicknessRange }) => { const wrapper = useRef(null); - const turretContainer = useRef(null); - const gunContainer = useRef(null); + const turretContainer = useRef(null!); + const gunContainer = useRef(null!); const tank = Duel.use((state) => state.protagonist.tank); const track = Duel.use((state) => state.protagonist.track); const turret = Duel.use((state) => state.protagonist.turret); diff --git a/packages/website/src/components/Armor/components/StaticArmorSceneComponent.tsx b/packages/website/src/components/Armor/components/StaticArmorSceneComponent.tsx index 9db804df9..eef50a2da 100644 --- a/packages/website/src/components/Armor/components/StaticArmorSceneComponent.tsx +++ b/packages/website/src/components/Armor/components/StaticArmorSceneComponent.tsx @@ -1,8 +1,8 @@ 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 type { QuicklimeEvent } from "quicklime"; -import { useEffect, useMemo } from "react"; +import { useEffect, useMemo, type ComponentProps } from "react"; import { Box3, Color, @@ -19,8 +19,8 @@ import { import { unrotateDavaVector } from "../../../core/blitz/unrotateDavaVector"; import { jsxTree } from "../../../core/blitzkit/jsxTree"; import { - type ModelTransformEventData, modelTransformEvent, + type ModelTransformEventData, } from "../../../core/blitzkit/modelTransform"; import { discardClippingPlane } from "../../../core/three/discardClippingPlane"; import { Tankopedia } from "../../../stores/tankopedia"; @@ -36,7 +36,7 @@ type StaticArmorSceneComponentProps = { thickness: number; thicknessRange: ThicknessRange; node: Object3D; - onPointerDown?: MeshProps["onPointerDown"]; + onPointerDown?: ComponentProps<"mesh">["onPointerDown"]; } & ( | { type: Exclude; diff --git a/packages/website/src/components/Footer.astro b/packages/website/src/components/Footer.astro index 0e6be3083..7af82f8f4 100644 --- a/packages/website/src/components/Footer.astro +++ b/packages/website/src/components/Footer.astro @@ -1,15 +1,15 @@ --- -import { assertSecret, fetchGameDefinitions } from '@blitzkit/core'; -import { DEFAULT_LOCALE } from '@blitzkit/i18n'; -import { Box, Code, Flex, Heading, Link, Text } from '@radix-ui/themes'; -import packageJson from '../../../../package.json'; -import { getStrings } from '../core/i18n/getStrings'; -import { LinkI18n } from './LinkI18n'; -import { LocaleSwitcherThemeWrapper } from './LocaleSwitcher'; +import { assertSecret, fetchGameDefinitions } from "@blitzkit/core"; +import locales from "@blitzkit/i18n/locales.json"; +import { Box, Code, Flex, Heading, Link, Text } from "@radix-ui/themes"; +import packageJson from "../../../../package.json"; +import { getStrings } from "../core/i18n/getStrings"; +import { LinkI18n } from "./LinkI18n"; +import { LocaleSwitcherThemeWrapper } from "./LocaleSwitcher"; const gameDefinitions = await fetchGameDefinitions(); 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); --- @@ -28,13 +28,13 @@ const strings = getStrings(locale); flexGrow="1" gap="5" position="relative" - direction={{ initial: 'column', sm: 'row' }} + direction={{ initial: "column", sm: "row" }} > BlitzKit @@ -51,32 +51,32 @@ const strings = getStrings(locale); {strings.website.footer.about.title} @@ -106,12 +106,12 @@ const strings = getStrings(locale); direction="column" gap="1" flexGrow={{ - initial: '1', - sm: '0', + initial: "1", + sm: "0", }} flexBasis={{ - initial: '0', - sm: 'auto', + initial: "0", + sm: "auto", }} > {strings.website.footer.legal.title} @@ -127,11 +127,11 @@ const strings = getStrings(locale); - + BlitzKit { - PUBLIC_ASSET_BRANCH !== 'preview' && ( + PUBLIC_ASSET_BRANCH !== "preview" && ( WoTB @@ -145,7 +145,7 @@ const strings = getStrings(locale); {packageJson.version} { - PUBLIC_ASSET_BRANCH !== 'preview' && ( + PUBLIC_ASSET_BRANCH !== "preview" && ( {gameDefinitions.version} @@ -157,14 +157,14 @@ const strings = getStrings(locale); - + BlitzKit {packageJson.version} { - PUBLIC_ASSET_BRANCH !== 'preview' && ( + PUBLIC_ASSET_BRANCH !== "preview" && ( <> WoTB diff --git a/packages/website/src/components/Gallery/Card.tsx b/packages/website/src/components/Gallery/Card.tsx index 629de2051..133108d58 100644 --- a/packages/website/src/components/Gallery/Card.tsx +++ b/packages/website/src/components/Gallery/Card.tsx @@ -1,5 +1,5 @@ -import { asset, Avatar } from '@blitzkit/core'; -import { Cross1Icon, DownloadIcon } from '@radix-ui/react-icons'; +import { asset, Avatar } from "@blitzkit/core"; +import { Cross1Icon, DownloadIcon } from "@radix-ui/react-icons"; import { Dialog, Flex, @@ -7,11 +7,11 @@ import { Link, Skeleton, Text, -} from '@radix-ui/themes'; -import { useRef } from 'react'; -import { useIntersection } from '../../hooks/useIntersection'; -import { useLocale } from '../../hooks/useLocale'; -import type { MaybeSkeletonComponentProps } from '../../types/maybeSkeletonComponentProps'; +} from "@radix-ui/themes"; +import { useRef } from "react"; +import { useIntersection } from "../../hooks/useIntersection"; +import { useLocale } from "../../hooks/useLocale"; +import type { MaybeSkeletonComponentProps } from "../../types/maybeSkeletonComponentProps"; type GalleryCardProps = MaybeSkeletonComponentProps<{ avatar: Avatar; @@ -19,9 +19,9 @@ type GalleryCardProps = MaybeSkeletonComponentProps<{ export function GalleryCard(props: GalleryCardProps) { 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(null); + const card = useRef(null!); const { unwrap } = useLocale(); useIntersection(() => props.skeleton && props.onIntersection?.(), card, { @@ -35,7 +35,7 @@ export function GalleryCard(props: GalleryCardProps) { width="6rem" gap="1" ref={card} - style={{ cursor: 'pointer' }} + style={{ cursor: "pointer" }} > {props.skeleton && ( <> @@ -48,16 +48,16 @@ export function GalleryCard(props: GalleryCardProps) { <> {unwrap(props.avatar.name)} - + {unwrap(props.avatar.name)} @@ -94,7 +94,7 @@ export function GalleryCard(props: GalleryCardProps) { - + {unwrap(props.avatar.name)} diff --git a/packages/website/src/components/HelpingSpotLight.tsx b/packages/website/src/components/HelpingSpotLight.tsx index a965c772d..5250fa197 100644 --- a/packages/website/src/components/HelpingSpotLight.tsx +++ b/packages/website/src/components/HelpingSpotLight.tsx @@ -1,7 +1,6 @@ -import type { SpotLightProps } from '@react-three/fiber'; -import { memo } from 'react'; +import { memo, type ComponentProps } from "react"; -interface Props extends SpotLightProps { +interface Props extends ComponentProps<"spotLight"> { debug?: boolean; } diff --git a/packages/website/src/components/Home/HomeLocaleSwitcher.tsx b/packages/website/src/components/Home/HomeLocaleSwitcher.tsx index 39a3603ae..e17861a8d 100644 --- a/packages/website/src/components/Home/HomeLocaleSwitcher.tsx +++ b/packages/website/src/components/Home/HomeLocaleSwitcher.tsx @@ -1,12 +1,12 @@ -import { DEFAULT_LOCALE } from '@blitzkit/i18n'; -import { GlobeIcon } from '@radix-ui/react-icons'; -import { Flex, Text } from '@radix-ui/themes'; -import type { LocaleAcceptorProps } from '../../hooks/useLocale'; -import { BlitzKitTheme } from '../BlitzKitTheme'; -import { LocaleSwitcher } from '../LocaleSwitcher'; +import locales from "@blitzkit/i18n/locales.json"; +import { GlobeIcon } from "@radix-ui/react-icons"; +import { Flex, Text } from "@radix-ui/themes"; +import type { LocaleAcceptorProps } from "../../hooks/useLocale"; +import { BlitzKitTheme } from "../BlitzKitTheme"; +import { LocaleSwitcher } from "../LocaleSwitcher"; export function HomeLocaleSwitcher({ - locale = DEFAULT_LOCALE, + locale = locales.default, }: LocaleAcceptorProps) { return ( diff --git a/packages/website/src/components/LinkI18n.tsx b/packages/website/src/components/LinkI18n.tsx index 1a5c1936a..f076de7c9 100644 --- a/packages/website/src/components/LinkI18n.tsx +++ b/packages/website/src/components/LinkI18n.tsx @@ -1,14 +1,14 @@ -import { DEFAULT_LOCALE } from '@blitzkit/i18n'; -import { Link, type LinkProps } from '@radix-ui/themes'; -import type { LocaleAcceptorProps } from '../hooks/useLocale'; +import locales from "@blitzkit/i18n/locales.json"; +import { Link, type LinkProps } from "@radix-ui/themes"; +import type { LocaleAcceptorProps } from "../hooks/useLocale"; type LinkI18nProps = LinkProps & LocaleAcceptorProps; export function LinkI18n({ locale, href, ...props }: LinkI18nProps) { const prefix = - locale === undefined || locale === DEFAULT_LOCALE ? '' : `/${locale}`; + locale === undefined || locale === locales.default ? "" : `/${locale}`; return ( - + ); } diff --git a/packages/website/src/components/LocaleRedirector.astro b/packages/website/src/components/LocaleRedirector.astro index 371d7257c..d66b93723 100644 --- a/packages/website/src/components/LocaleRedirector.astro +++ b/packages/website/src/components/LocaleRedirector.astro @@ -1,12 +1,13 @@