Compare commits

...
11 Commits
Author SHA1 Message Date
tresabhi 0e637d772e fix hac 2026-05-15 22:53:43 -05:00
tresabhi a834d48a38 update imports 2026-05-15 22:52:25 -05:00
tresabhi f550386fd9 simplify imports 2026-05-15 22:46:36 -05:00
tresabhi 0a4b81cde4 fix paths 2026-05-15 22:30:52 -05:00
tresabhi e1cc60ea5e some work on equipment 2026-05-15 21:58:30 -05:00
tresabhi a40860901b stock/upgrade buttons 2026-05-15 21:41:40 -05:00
tresabhi f3e96718eb exclusive alternate guns 2026-05-15 21:18:01 -05:00
tresabhi a00411919d patch da code 2026-05-15 18:43:08 -05:00
tresabhi b298874f0d reorganize some code 2026-05-15 18:31:17 -05:00
tresabhi 7011d4d20f bigger icons 2026-05-15 18:25:25 -05:00
tresabhi d9ce16b41a currency icons 2026-05-15 18:16:06 -05:00
111 changed files with 516 additions and 260 deletions

No files matched your search

+1
View File
@@ -53,3 +53,4 @@ dist-ssr
*.njsproj
*.sln
*.sw?
*.lscache
+1 -1
View File
@@ -1,5 +1,5 @@
{
"js/ts.experimental.useTsgo": true,
// "js/ts.experimental.useTsgo": true,
"protobuf.includes": ["${workspaceFolder}/path/to/protos"],
"cSpell.words": [
"AABBOX",
+4 -4
View File
@@ -4,16 +4,16 @@
"license": "BlitzKit License",
"private": true,
"scripts": {
"setup": "bun install && bun run build:protos && bun run build:proxyclient && bun run build:catalogitemaccesssor",
"dev": "bun run dev:website",
"dev:website": "cd packages/website-ue && bun run dev",
"build:game": "cd packages/game && bun run build",
"build:website": "cd packages/website-ue && bun run build",
"build:proxyclient": "cd packages/scripts && bun run build:proxyclient",
"build:catalogitemaccesssor": "cd packages/scripts && bun run build:catalogitemaccesssor",
"build:protos": "cd packages/scripts && bun run build:protos",
"dev": "bun run dev:website",
"dev:website": "cd packages/website-ue && bun run dev",
"lint": "tsc",
"lint:website": "cd packages/website-ue && bun run lint",
"setup": "bun install && bun run build:protos && bun run build:proxyclient && bun run build:catalogitemaccesssor"
"lint:website": "cd packages/website-ue && bun run lint"
},
"type": "module",
"workspaces": [
+1
View File
@@ -200,6 +200,7 @@
"tanks": {
"loadout": {
"modules": "Modules",
"equipment": "Equipment",
"alternative": "Alt"
},
-1
View File
@@ -46,7 +46,6 @@
"build:ratingleaderboard": "bun src/buildRatingLeaderboard.ts",
"build:proxyclient": "bun src/buildProxyClient.ts",
"build:catalogitemaccesssor": "bun src/buildCatalogItemAccessor.ts",
"prunestrings": "bun src/pruneStrings.ts",
"build:protos": "bun src/protos.ts",
"patchnotes": "bun src/patchNotes.ts"
},
@@ -1,6 +1,6 @@
import { readdir, readFile, writeFile } from "fs/promises";
const SOURCES = "../../packages/closed/protos/game/proto/legacy";
const SOURCES = "../../packages/closed/protos/blitz";
const TARGET = "../../packages/closed/src/unreal/catalogItemAccessor.ts";
const componentPattern = /^message (\w+)Component {/gm;
@@ -40,7 +40,7 @@ for (const file of files) {
let content = "";
for (const _import of imports) {
content += `import { ${_import.name}Component } from "@protos/game/proto/legacy/${_import.file}";\n`;
content += `import { ${_import.name}Component } from "@protos/${_import.file}";\n`;
}
content +=
+2 -2
View File
@@ -1,8 +1,8 @@
import { readFile, writeFile } from "fs/promises";
const IMPORT = "@protos/game/proto/legacy/auto_legacy_proxy_client";
const IMPORT = "@protos/auto_legacy_proxy_client";
const SOURCE =
"../../packages/closed/protos/game/proto/legacy/auto_legacy_proxy_client.proto";
"../../packages/closed/protos/blitz/auto_legacy_proxy_client.proto";
const TARGET = "../../packages/closed/src/unreal/methodPopulatedProxyClient.ts";
const requestPattern = /^message (\w+)Request {/gm;
+8 -7
View File
@@ -6,7 +6,7 @@ const TS_PROTO_EXECUTABLE_LOCATIONS = [
"./node_modules/.bin/protoc-gen-ts_proto",
"../../node_modules/.bin/protoc-gen-ts_proto",
];
const ROOT = "../../packages/closed/protos";
const ROOT = "../closed/protos";
let tsProtoExecutableLocation: string | undefined = undefined;
@@ -28,11 +28,10 @@ if (!tsProtoExecutableLocation) {
);
}
await mkdir("temp", { recursive: true });
await mkdir("../../temp", { recursive: true });
let args = "";
args += `-I=${ROOT}\n`;
args += `--plugin=${tsProtoExecutableLocation}\n`;
args += "--ts_proto_opt=esModuleInterop=true\n";
args += "--ts_proto_opt=oneof=unions-value\n";
@@ -40,6 +39,10 @@ args += "--ts_proto_opt=unrecognizedEnum=false\n";
args += "--ts_proto_opt=snakeToCamel=false\n";
args += `--ts_proto_out=${ROOT}\n`;
for (const dir of await readdir(ROOT)) {
args += `-I=${ROOT}/${dir}\n`;
}
const filesRaw = await readdir(`${ROOT}`, { recursive: true });
const files: string[] = [];
@@ -52,11 +55,9 @@ for (const file of filesRaw) {
if (file.endsWith(".ts")) await rm(`${ROOT}/${file}`);
}
await writeFile("temp/protoc.txt", args);
await writeFile("../../temp/protoc.txt", args);
// throw "";
execFile("protoc", ["@temp/protoc.txt"], (error, stdout, stderr) => {
execFile("protoc", ["@../../temp/protoc.txt"], (error, stdout, stderr) => {
if (error) throw new Error(error.message);
if (stderr) console.error(stderr);
if (stdout) console.log(stdout);
@@ -1,17 +1,17 @@
import type { MetadataAccessor } from "@blitzkit/closed";
import type { Strings } from "@blitzkit/i18n";
import locales from "@blitzkit/i18n/locales.json";
import type { Avatar } from "@protos/blitzkit/avatar";
import type { AvatarList } from "@protos/blitzkit/avatar_list";
import type { Avatars } from "@protos/blitzkit/avatars";
import type { Background } from "@protos/blitzkit/background";
import type { Backgrounds } from "@protos/blitzkit/backgrounds";
import type { PopularTanks } from "@protos/blitzkit/popular_tanks";
import type { Tank } from "@protos/blitzkit/tank";
import type { TankList } from "@protos/blitzkit/tank_list";
import type { Tanks } from "@protos/blitzkit/tanks";
import type { Tiers } from "@protos/blitzkit/tiers";
import type { TankUpgradePricePresetComponent } from "@protos/game/proto/legacy/blitz_static_tank_upgrade_price_preset_component";
import type { Avatar } from "@protos/avatar";
import type { AvatarList } from "@protos/avatar_list";
import type { Avatars } from "@protos/avatars";
import type { Background } from "@protos/background";
import type { Backgrounds } from "@protos/backgrounds";
import type { TankUpgradePricePresetComponent } from "@protos/blitz_static_tank_upgrade_price_preset_component";
import type { PopularTanks } from "@protos/popular_tanks";
import type { Tank } from "@protos/tank";
import type { TankList } from "@protos/tank_list";
import type { Tanks } from "@protos/tanks";
import type { Tiers } from "@protos/tiers";
export abstract class AbstractAPI {
abstract metadata: MetadataAccessor;
@@ -41,6 +41,8 @@ export abstract class AbstractAPI {
abstract background(id: string): Promise<Background>;
abstract backgrounds(): Promise<Backgrounds>;
abstract currencyIcon(id: string): Promise<string>;
private assertLocale(locale: string) {
const supported = locales.supported.find(
(supported) => supported.locale === locale,
@@ -1,11 +1,11 @@
import { fetchPB } from "@blitzkit/core";
import type { Strings } from "@blitzkit/i18n";
import { Avatars } from "@protos/blitzkit/avatars";
import { PopularTanks } from "@protos/blitzkit/popular_tanks";
import { TankList } from "@protos/blitzkit/tank_list";
import { Tanks } from "@protos/blitzkit/tanks";
import { Tiers } from "@protos/blitzkit/tiers";
import { TankUpgradePricePresetComponent } from "@protos/game/proto/legacy/blitz_static_tank_upgrade_price_preset_component";
import { Avatars } from "@protos/avatars";
import { TankUpgradePricePresetComponent } from "@protos/blitz_static_tank_upgrade_price_preset_component";
import { PopularTanks } from "@protos/popular_tanks";
import { TankList } from "@protos/tank_list";
import { Tanks } from "@protos/tanks";
import { Tiers } from "@protos/tiers";
import { AbstractAPI, Cache } from "./abstract";
const rejected = Promise.reject("Not implemented on client");
@@ -2,14 +2,14 @@ import type { MetadataAccessor } from "@blitzkit/closed";
import { assertSecret, sluggify } from "@blitzkit/core";
import type { Strings } from "@blitzkit/i18n";
import locales from "@blitzkit/i18n/locales.json";
import type { Avatar, DeepPartial } from "@protos/blitzkit/avatar";
import type { Background } from "@protos/blitzkit/background";
import type { PopularTanks } from "@protos/blitzkit/popular_tanks";
import type { Tank } from "@protos/blitzkit/tank";
import type { TankListEntry } from "@protos/blitzkit/tank_list";
import type { Tanks } from "@protos/blitzkit/tanks";
import type { Tiers } from "@protos/blitzkit/tiers";
import type { RemoteStorageComponent } from "@protos/game/proto/legacy/blitz_static_remote_storage_component";
import type { Avatar, DeepPartial } from "@protos/avatar";
import type { Background } from "@protos/background";
import type { RemoteStorageComponent } from "@protos/blitz_static_remote_storage_component";
import type { PopularTanks } from "@protos/popular_tanks";
import type { Tank } from "@protos/tank";
import type { TankListEntry } from "@protos/tank_list";
import type { Tanks } from "@protos/tanks";
import type { Tiers } from "@protos/tiers";
import { existsSync } from "fs";
import { mkdir, readFile, writeFile } from "fs/promises";
import { google } from "googleapis";
@@ -21,7 +21,7 @@ if (typeof window !== "undefined") {
throw new Error("ServerAPI is being evaluated in the browser");
}
const globbedStrings = import.meta.glob("../../../../i18n/strings/*.json", {
const globbedStrings = import.meta.glob("../../../i18n/strings/*.json", {
import: "default",
});
const tankSlugPattern = /^(\/\w+)?\/tanks\/([a-z0-9-]+)\/$/;
@@ -35,6 +35,40 @@ export class ServerAPI extends AbstractAPI {
super();
}
resolveRemoteUrl(remoteUrls: string[]) {
let remoteStorage: RemoteStorageComponent | undefined = undefined;
for (const remoteUrl of remoteUrls) {
const item = this.metadata.item(remoteUrl);
const candidate = item.RemoteStorage();
if (
remoteStorage === undefined ||
candidate.download_speed_weight > remoteStorage.download_speed_weight
) {
remoteStorage = candidate;
}
}
if (remoteStorage === undefined) {
throw new Error("No suitable production remote storage found");
}
return remoteStorage;
}
resolveClientConfig() {
const group = this.metadata.group("ClientConfigsEntity");
if (group.length !== 1) {
throw new RangeError(
`Don't know how to handle ${group.length} ClientConfigsEntities`,
);
}
return this.metadata.item(group[0].id);
}
@Cache()
async tankList() {
const group = this.metadata.group("TankEntity");
@@ -195,10 +229,10 @@ export class ServerAPI extends AbstractAPI {
@Cache(true)
async strings(locale: string) {
const localized = (await globbedStrings[
`../../../../i18n/strings/${locale}.json`
`../../../i18n/strings/${locale}.json`
]()) as DeepPartial<Strings>;
const defaults = (await globbedStrings[
`../../../../i18n/strings/${locales.default}.json`
`../../../i18n/strings/${locales.default}.json`
]()) as Strings;
const strings = merge({}, defaults, localized);
@@ -207,37 +241,14 @@ export class ServerAPI extends AbstractAPI {
@Cache()
async gameStrings(locale: string) {
const group = this.metadata.group("ClientConfigsEntity");
if (group.length !== 1) {
throw new RangeError(
`Don't know how to handle ${group.length} ClientConfigsEntities`,
);
}
const clientConfig = this.metadata.item(group[0].id);
const clientConfig = this.resolveClientConfig();
const localizationResources = clientConfig.LocalizationResources();
const strings: Record<string, string> = {};
for (const remoteStorageSettings of localizationResources.remote_storages) {
let remoteStorage: RemoteStorageComponent | undefined = undefined;
for (const remoteUrl of remoteStorageSettings.remote_urls) {
const item = this.metadata.item(remoteUrl);
const candidate = item.RemoteStorage();
if (
remoteStorage === undefined ||
candidate.download_speed_weight > remoteStorage.download_speed_weight
) {
remoteStorage = candidate;
}
}
if (remoteStorage === undefined) {
throw new Error("No suitable production remote storage found");
}
const remoteStorage = this.resolveRemoteUrl(
remoteStorageSettings.remote_urls,
);
const configPath = `${remoteStorage.url}${remoteStorage.relative_path}/config.yaml`;
const config = await fetch(configPath)
.then((response) => response.text())
@@ -344,4 +355,17 @@ export class ServerAPI extends AbstractAPI {
return { backgrounds };
}
@Cache()
async currencyIcon(id: string) {
const item = this.metadata.item(`CurrencyEntity.${id}`);
const stuffUI = item.StuffUI("UIComponent");
const config = this.resolveClientConfig();
const metroResources = config.MetroResources();
const remoteStorage = this.resolveRemoteUrl(
metroResources.remote_storage!.remote_urls,
);
return `${remoteStorage.url}${remoteStorage.relative_path}${stuffUI.icon!.value}`;
}
}
@@ -1,6 +1,6 @@
---
import type { CollectionEntry } from "astro:content";
import { api } from "../core/api/dynamic";
import { api } from "../api/dynamic";
import ApiDescription from "./ApiDescription.astro";
import { ApiTester } from "./ApiTester";
@@ -14,7 +14,7 @@ import {
type Symbol,
type TypeNode,
} from "typescript";
import { api } from "../core/api/dynamic";
import { api } from "../api/dynamic";
import { Code } from "./Code";
import HighlightedCodeBlock from "./HighlightedCodeBlock.astro";
import { Link } from "./Link";
@@ -1,11 +1,11 @@
import { literals } from "@blitzkit/i18n";
import type { Avatar } from "@protos/blitzkit/avatar";
import { Grade } from "@protos/game/proto/legacy/blitz_static_standard_grades_enum";
import type { Avatar } from "@protos/avatar";
import { Grade } from "@protos/blitz_static_standard_grades_enum";
import { DownloadIcon, StarFilledIcon } from "@radix-ui/react-icons";
import type { Color } from "../../core/ui/color";
import { useGameStrings } from "../../hooks/useGameStrings";
import { useStrings } from "../../hooks/useStrings";
import type { PropsWithSkeleton } from "../../types/propsWithSkeleton";
import type { Color } from "../../ui/color";
import { Badge } from "../Badge";
import { Button } from "../Button";
import { Dialog } from "../Dialog";
@@ -1,6 +1,6 @@
import fuzzysort from "fuzzysort";
import { useMemo } from "react";
import { api } from "../../core/api/dynamic";
import { api } from "../../api/dynamic";
import { useAwait } from "../../hooks/useAwait";
import { useGameStrings } from "../../hooks/useGameStrings";
import { useLocale } from "../../hooks/useLocale";
@@ -1,6 +1,6 @@
import type { ComponentProps } from "react";
import { classNames } from "../../core/ui/classNames";
import type { Color } from "../../core/ui/color";
import { classNames } from "../../ui/classNames";
import type { Color } from "../../ui/color";
import { LIGHT_TEXT_COLORS } from "../Button";
import styles from "./index.module.css";
@@ -14,7 +14,9 @@
color: var(--gray-1);
font-weight: var(--weight-medium);
.svg {
cursor: pointer;
svg {
width: 1em;
height: 1em;
}
@@ -32,6 +34,18 @@
background-color: var(--accent-3);
}
&[data-variant="inverted"] {
background-color: var(--accent-12);
color: var(--accent-1);
}
&[data-variant="ghost"] {
background: none;
color: var(--accent-11);
padding: 0;
}
&[data-variant="surface"] {
outline: var(--space-1) solid var(--accent-6);
}
@@ -1,12 +1,13 @@
import type { ComponentProps } from "react";
import { classNames } from "../../core/ui/classNames";
import type { Color } from "../../core/ui/color";
import { classNames } from "../../ui/classNames";
import type { Color } from "../../ui/color";
import styles from "./index.module.css";
export interface ButtonProps extends ComponentProps<"button"> {
color?: Color;
radius?: `${1 | 2 | 3}` | "max";
variant?: "solid" | "surface" | "soft";
variant?: "solid" | "surface" | "soft" | "inverted" | "ghost";
size?: "regular";
}
export const LIGHT_TEXT_COLORS = new Set<Color>([
@@ -30,6 +31,7 @@ export function Button({
variant = "solid",
style,
radius = "max",
size = "regular",
...props
}: ButtonProps) {
return (
@@ -39,6 +41,7 @@ export function Button({
data-variant={variant}
data-light-text={variant === "solid"}
data-radius={radius}
data-size={size}
{...props}
/>
);
@@ -1,6 +1,6 @@
---
import { ExclamationTriangleIcon } from "@radix-ui/react-icons";
import { api } from "../core/api/dynamic";
import { api } from "../api/dynamic";
import { Heading } from "./Heading";
import { Section } from "./Section";
import { Text } from "./Text";
@@ -1,5 +1,5 @@
import type { ComponentProps } from "react";
import { classNames } from "../../core/ui/classNames";
import { classNames } from "../../ui/classNames";
import styles from "./index.module.css";
export interface CodeProps extends ComponentProps<"code"> {
@@ -1,5 +1,5 @@
---
import type { Color } from "../core/ui/color";
import type { Color } from "../ui/color";
interface Props {
color: Color;
@@ -1,6 +1,6 @@
---
import * as colors from "@radix-ui/colors";
import type { Color } from "../core/ui/color";
import type { Color } from "../ui/color";
interface Props {
color: Color | AlphaOnlyColor;
@@ -1,7 +1,7 @@
---
import { DiscordLogoIcon, GitHubLogoIcon } from "@radix-ui/react-icons";
import packageJson from "../../../../package.json";
import { api } from "../core/api/dynamic";
import { api } from "../api/dynamic";
import { BlitzKitIcon } from "../icons/BlitzKit";
import { Code } from "./Code";
import { Link } from "./Link";
@@ -1,4 +1,4 @@
import { classNames } from "../../core/ui/classNames";
import { classNames } from "../../ui/classNames";
import { Text, type TextProps } from "../Text";
import "./index.css";
@@ -1,6 +1,6 @@
---
import { api } from "../core/api/dynamic";
import { tools } from "../core/tools/tools";
import { api } from "../api/dynamic";
import { tools } from "../config/tools";
import { Heading } from "./Heading";
import { Section } from "./Section";
import ToolCard from "./ToolCard.astro";
@@ -1,6 +1,6 @@
---
import { api } from "../core/api/dynamic";
import { tools } from "../core/tools/tools";
import { api } from "../api/dynamic";
import { tools } from "../config/tools";
import { Heading } from "./Heading";
import { Section } from "./Section";
import ToolCard from "./ToolCard.astro";
@@ -1,6 +1,6 @@
---
import { MagnifyingGlassIcon } from "@radix-ui/react-icons";
import { api } from "../core/api/dynamic";
import { api } from "../api/dynamic";
import { BlitzKitIcon } from "../icons/BlitzKit";
import { Code } from "./Code";
import { Text } from "./Text";
@@ -1,6 +1,6 @@
---
import { api } from "../core/api/dynamic";
import { tools } from "../core/tools/tools";
import { api } from "../api/dynamic";
import { tools } from "../config/tools";
import { Heading } from "./Heading";
import { Section } from "./Section";
import ToolCard from "./ToolCard.astro";
@@ -1,6 +1,6 @@
---
import { api } from "../core/api/dynamic";
import { tools } from "../core/tools/tools";
import { api } from "../api/dynamic";
import { tools } from "../config/tools";
import { Heading } from "./Heading";
import { HomeTanksPopular } from "./HomeTanksPopular";
import { Section } from "./Section";
@@ -1,4 +1,4 @@
import { api } from "../../core/api/dynamic";
import { api } from "../../api/dynamic";
import { useAwait } from "../../hooks/useAwait";
import {
LocaleProvider,
@@ -1,6 +1,6 @@
---
import { api } from "../core/api/dynamic";
import { tools } from "../core/tools/tools";
import { api } from "../api/dynamic";
import { tools } from "../config/tools";
import { Heading } from "./Heading";
import { Section } from "./Section";
import ToolCard from "./ToolCard.astro";
@@ -3,5 +3,5 @@
aspect-ratio: 1 / 1;
font-size: 2em;
font-size: var(--font-size-regular);
}
@@ -1,4 +1,4 @@
import { classNames } from "../../core/ui/classNames";
import { classNames } from "../../ui/classNames";
import { Button, type ButtonProps } from "../Button";
import styles from "./index.module.css";
@@ -1,4 +1,4 @@
import { classNames } from "../../core/ui/classNames";
import { classNames } from "../../ui/classNames";
import { Skeleton, type SkeletonProps } from "../Skeleton";
import "./index.css";
@@ -1,6 +1,6 @@
import type { ComponentProps } from "react";
import { classNames } from "../../core/ui/classNames";
import type { Color } from "../../core/ui/color";
import { classNames } from "../../ui/classNames";
import type { Color } from "../../ui/color";
import styles from "./index.module.css";
export interface LinkProps extends ComponentProps<"a"> {
@@ -1,6 +1,6 @@
import type { ComponentProps, FunctionComponent } from "react";
import Markdown from "react-markdown";
import { classNames } from "../../core/ui/classNames";
import { classNames } from "../../ui/classNames";
import { Code } from "../Code";
import { Text } from "../Text";
import styles from "./index.module.css";
@@ -1,9 +1,9 @@
import { formatCompact } from "@blitzkit/core";
import type { StandardPrice } from "@protos/game/proto/legacy/blitz_static_standard_price";
import type { StandardSinglePrice } from "@protos/game/proto/legacy/blitz_static_standard_single_price";
import type { StandardPrice } from "@protos/blitz_static_standard_price";
import type { StandardSinglePrice } from "@protos/blitz_static_standard_single_price";
import type { ComponentProps } from "react";
import { classNames } from "../../core/ui/classNames";
import { useLocale } from "../../hooks/useLocale";
import { classNames } from "../../ui/classNames";
import { Text } from "../Text";
import styles from "./index.module.css";
@@ -36,13 +36,12 @@ function PriceEntry({ entry }: PriceEntryProps) {
throw new Error("Unsupported price type");
}
const [, iconName] = entry.currency_price.currency_catalog_id.split(".");
return (
<Text size="minor" lowContrast className={styles.entry}>
<Text weight="light" size="minor" lowContrast className={styles.entry}>
<div className={styles.wrapper}>
<img
className={styles.icon}
src="https://static.vecteezy.com/system/resources/thumbnails/047/493/988/small/hairy-fluffy-cat-playing-png.png"
/>
<img className={styles.icon} src={`/api/currencies/${iconName}.webp`} />
{formatCompact(locale, entry.currency_price.amount)}
</div>
</Text>
@@ -1,6 +1,6 @@
import { useEffect, useRef, type ComponentProps } from "react";
import { clamp } from "three/src/math/MathUtils.js";
import { classNames } from "../../core/ui/classNames";
import { classNames } from "../../ui/classNames";
import styles from "./index.module.css";
interface ScrollerProps extends ComponentProps<"div"> {}
@@ -1,6 +1,6 @@
import type { ComponentProps } from "react";
import { classNames } from "../../core/ui/classNames";
import type { Space } from "../../types/space";
import { classNames } from "../../ui/classNames";
import styles from "./index.module.css";
export interface SectionProps extends ComponentProps<"div"> {
@@ -1,5 +1,5 @@
import type { ComponentProps } from "react";
import { classNames } from "../../core/ui/classNames";
import { classNames } from "../../ui/classNames";
import styles from "./index.module.css";
export interface SkeletonProps extends ComponentProps<"div"> {}
@@ -1,5 +1,5 @@
import { api } from "../../core/api/dynamic";
import { clientUnmounted } from "../../core/game/unmounted";
import { api } from "../../api/dynamic";
import { clientUnmounted } from "../../game/unmounted";
import { useAwait } from "../../hooks/useAwait";
import { useGameStrings } from "../../hooks/useGameStrings";
import { useLocale } from "../../hooks/useLocale";
@@ -1,6 +1,6 @@
import type { CharacteristicOutput } from "../core/tankopedia/characteristics";
import type { CharacteristicRenderConfig } from "../core/tankopedia/characteristicsOrder";
import { renderCharacteristic } from "../hooks/useCharacteristicRenderer";
import type { CharacteristicOutput } from "../tankopedia/characteristics";
import type { CharacteristicRenderConfig } from "../tankopedia/characteristicsOrder";
interface Props {
characteristic: CharacteristicOutput;
@@ -1,36 +1,54 @@
.lines {
.section {
display: flex;
flex-direction: column;
gap: var(--space-4);
gap: var(--space-3);
.line {
.header {
display: flex;
align-items: center;
gap: var(--space-3);
}
.lines {
display: flex;
flex-direction: column;
gap: var(--space-3);
.stage {
position: relative;
.line {
display: flex;
align-items: center;
.icon {
width: 1em;
height: 1em;
gap: var(--space-3);
transform: translateX(var(--space-1));
}
.stage {
position: relative;
.tier {
position: absolute;
left: var(--space-2);
top: var(--space-2);
}
padding: var(--space-3);
.price {
position: absolute;
left: 50%;
bottom: var(--space-2);
transform: translateX(-50%);
font-size: 2em;
.icon {
width: 1em;
height: 1em;
padding: var(--space-3) 0;
transform: translate(var(--space-1), calc(-1 * var(--space-1)));
}
.tier {
position: absolute;
left: var(--space-2);
top: var(--space-2);
}
.price {
position: absolute;
left: 50%;
bottom: var(--space-2);
transform: translateX(-50%);
}
}
}
}
@@ -1,13 +1,20 @@
import { romanize } from "@blitzkit/core";
import { Grade } from "@protos/game/proto/legacy/blitz_static_standard_grades_enum";
import type { StandardPrice } from "@protos/game/proto/legacy/blitz_static_standard_price";
import type { UpgradeLine } from "@protos/game/proto/legacy/blitz_static_tank_upgrade_line";
import type { StageParameters } from "@protos/game/proto/legacy/blitz_static_tank_upgrade_single_stage";
import { Grade } from "@protos/blitz_static_standard_grades_enum";
import type { StandardPrice } from "@protos/blitz_static_standard_price";
import type { UpgradeLine } from "@protos/blitz_static_tank_upgrade_line";
import type { StageParameters } from "@protos/blitz_static_tank_upgrade_single_stage";
import { DoubleArrowDownIcon, DoubleArrowUpIcon } from "@radix-ui/react-icons";
import { useMemo } from "react";
import {
alternativeLines,
isAlternativeLine,
originalLineName,
} from "../../config/alternativeLines";
import { useProtagonist } from "../../hooks/useProtagonist";
import { useStrings } from "../../hooks/useStrings";
import { useUpgradePreset } from "../../hooks/useUpgradePreset";
import { Tankopedia } from "../../stores/tankopedia";
import { Button } from "../Button";
import { Heading } from "../Heading";
import { IconButton } from "../IconButton";
import { Price } from "../Price";
@@ -16,13 +23,79 @@ import { Text } from "../Text";
import styles from "./index.module.css";
export function TankopediaLoadout() {
const strings = useStrings();
return (
<Section>
<Modules />
<Equipment />
</Section>
);
}
function Equipment() {
const strings = useStrings();
const tank = useProtagonist();
// const equipment = useEquipment(
// tank.tank!.equipment_preset_catalog_id,
// tank.tank!.equipment_price_preset_catalog_id,
// );
return (
<div className={styles.section}>
<div className={styles.header}>
<Heading size="4">{strings.tanks.loadout.equipment}</Heading>
</div>
preset: {tank.tank!.equipment_preset_catalog_id}
<br />
price: {tank.tank!.equipment_price_preset_catalog_id}
</div>
);
}
function Modules() {
const strings = useStrings();
const tank = useProtagonist();
return (
<Section>
<Heading size="3">{strings.tanks.loadout.modules}</Heading>
<div className={styles.section}>
<div className={styles.header}>
<Heading size="4">{strings.tanks.loadout.modules}</Heading>
<IconButton
onClick={() => {
Tankopedia.mutate((draft) => {
for (const line of tank.tank!.upgrade_lines) {
if (isAlternativeLine(line.name)) continue;
draft.protagonist.upgrades[line.name] = 0;
draft.protagonist.alternates[line.name] = false;
}
});
}}
color="tomato"
variant="ghost"
>
<DoubleArrowDownIcon />
</IconButton>
<IconButton
onClick={() => {
Tankopedia.mutate((draft) => {
for (const line of tank.tank!.upgrade_lines) {
draft.protagonist.upgrades[line.name] = line.stages.length - 1;
if (isAlternativeLine(line.name)) {
const original = originalLineName(line.name)!;
draft.protagonist.alternates[original] = true;
}
}
});
}}
color="jade"
variant="ghost"
>
<DoubleArrowUpIcon />
</IconButton>
</div>
<div className={styles.lines}>
{tank.tank!.upgrade_lines.map((line) => (
@@ -33,7 +106,7 @@ export function TankopediaLoadout() {
/>
))}
</div>
</Section>
</div>
);
}
@@ -42,17 +115,18 @@ interface LineProps {
lines: UpgradeLine[];
}
const mergeLines = {
alternative_guns: "guns",
} as Record<string, string>;
function Line({ name, lines }: LineProps) {
const combinedLines = useMemo(() => {
const names: string[] = [name];
for (const key in mergeLines) {
if (mergeLines[key] === name && lines.some((line) => line.name === key)) {
names.push(key);
for (const originalLine in alternativeLines) {
const alternativeLine = alternativeLines[originalLine];
if (
originalLine === name &&
lines.some((line) => line.name === alternativeLine)
) {
names.push(alternativeLine);
}
}
@@ -61,7 +135,7 @@ function Line({ name, lines }: LineProps) {
return (
<div className={styles.line}>
{!(name in mergeLines) &&
{!isAlternativeLine(name) &&
combinedLines.map((name) => (
<LineInner key={name} name={name} lines={lines} />
))}
@@ -85,6 +159,7 @@ interface LineElementProps {
function LineElement({ index, lineName, stage }: LineElementProps) {
const upgrades = Tankopedia.use((state) => state.protagonist.upgrades);
const alternates = Tankopedia.use((state) => state.protagonist.alternates);
const tank = useProtagonist();
const strings = useStrings();
const upgradePreset = useUpgradePreset(tank.tank!.tank_upgrade_preset);
@@ -114,24 +189,45 @@ function LineElement({ index, lineName, stage }: LineElementProps) {
price = override.price;
}
const isSelected = upgrades[lineName] === index;
let isSelected: boolean;
if (isAlternativeLine(lineName)) {
const originalLine = originalLineName(lineName);
isSelected = alternates[originalLine!];
} else {
if (alternates[lineName]) {
isSelected = false;
} else {
isSelected = upgrades[lineName] === index;
}
}
return (
<IconButton
<Button
color={isSelected ? undefined : "gray"}
variant={isSelected ? "surface" : "soft"}
radius="1"
className={styles.stage}
onClick={() => {
Tankopedia.mutate((draft) => {
draft.protagonist.upgrades[lineName] = index;
const tankData = tank.tank!;
if (isAlternativeLine(lineName)) {
const originalLine = originalLineName(lineName)!;
draft.protagonist.alternates[originalLine] = true;
draft.protagonist.upgrades[lineName] = index;
} else {
draft.protagonist.alternates[lineName] = false;
draft.protagonist.upgrades[lineName] = index;
}
for (const required of stage.required_upgrades) {
for (const line of tank.tank!.upgrade_lines) {
for (const line of tankData.upgrade_lines) {
let i = 0;
for (const stage of line.stages) {
if (stage.tech_name === required) {
for (const candidateStage of line.stages) {
if (candidateStage.tech_name === required) {
draft.protagonist.upgrades[line.name] = Math.max(
draft.protagonist.upgrades[line.name],
i,
@@ -143,16 +239,21 @@ function LineElement({ index, lineName, stage }: LineElementProps) {
}
}
for (const line of tank.tank!.upgrade_lines) {
for (const line of tankData.upgrade_lines) {
if (draft.protagonist.alternates[line.name]) {
continue;
}
let i = draft.protagonist.upgrades[line.name];
while (i > 0) {
const currentStage = line.stages[i];
const valid = currentStage.required_upgrades.every((required) => {
for (const line of tank.tank!.upgrade_lines) {
const idx = draft.protagonist.upgrades[line.name];
if (line.stages[idx]?.tech_name === required) {
const valid = currentStage.required_upgrades.every((required) => {
for (const otherLine of tankData.upgrade_lines) {
const idx = draft.protagonist.upgrades[otherLine.name];
if (otherLine.stages[idx]?.tech_name === required) {
return true;
}
}
@@ -176,13 +277,13 @@ function LineElement({ index, lineName, stage }: LineElementProps) {
/>
{/* {stage.display_name} */}
<Text lowContrast size="minor" className={styles.tier}>
{lineName in mergeLines
<Text weight="light" lowContrast size="minor" className={styles.tier}>
{isAlternativeLine(lineName)
? strings.tanks.loadout.alternative
: romanize(stage.number)}
</Text>
{price && <Price className={styles.price} price={price} />}
</IconButton>
</Button>
);
}
@@ -1,6 +1,6 @@
import type { ComponentProps } from "react";
import { classNames } from "../../core/ui/classNames";
import type { ColorWithBW } from "../../core/ui/color";
import { classNames } from "../../ui/classNames";
import type { ColorWithBW } from "../../ui/color";
import styles from "./index.module.css";
export interface TextProps extends ComponentProps<"span"> {
@@ -7,7 +7,7 @@ import {
type ComponentProps,
type ReactNode,
} from "react";
import { classNames } from "../../core/ui/classNames";
import { classNames } from "../../ui/classNames";
import styles from "./index.module.css";
export interface TextFieldProps extends ComponentProps<"input"> {
@@ -1,6 +1,6 @@
---
import { api } from "../core/api/dynamic";
import type { Tool } from "../core/tools/tools";
import { api } from "../api/dynamic";
import type { Tool } from "../config/tools";
import { Heading } from "./Heading";
import { Text } from "./Text";
@@ -1,7 +1,7 @@
---
import { CaretRightIcon } from "@radix-ui/react-icons";
import { api } from "../core/api/dynamic";
import { type Tool } from "../core/tools/tools";
import { api } from "../api/dynamic";
import { type Tool } from "../config/tools";
import { Button } from "./Button";
import { LinkI18n } from "./LinkI18n";
import { Text } from "./Text";
@@ -0,0 +1,21 @@
export const alternativeLines: Record<string, string> = {
guns: "alternative_guns",
};
export function isAlternativeLine(line: string) {
for (const key in alternativeLines) {
if (alternativeLines[key] === line) {
return true;
}
}
return false;
}
export function originalLineName(line: string) {
for (const key in alternativeLines) {
if (alternativeLines[key] === line) {
return key;
}
}
}
@@ -1,9 +1,9 @@
import { useMemo, type ReactNode } from "react";
import type { CharacteristicOutput } from "../core/tankopedia/characteristics";
import type { CharacteristicOutput } from "../tankopedia/characteristics";
import {
characteristicsOrder,
type CharacteristicRenderConfig,
} from "../core/tankopedia/characteristicsOrder";
} from "../tankopedia/characteristicsOrder";
import { useGameStrings } from "./useGameStrings";
import { useStrings } from "./useStrings";
@@ -0,0 +1,17 @@
import { api } from "../api/dynamic";
import { useAwait } from "./useAwait";
export function useEquipment(presetId: string, priceId: string) {
const [, presetName] = presetId.split(".");
const [, priceName] = priceId.split(".");
const preset = useAwait(
() => api.equipmentPreset(presetId),
`equipment-preset-${presetName}`,
);
const price = useAwait(
() => api.equipmentPricePreset(priceId),
`equipment-price-${priceName}`,
);
return { preset, price };
}
@@ -1,4 +1,4 @@
import { api } from "../core/api/dynamic";
import { api } from "../api/dynamic";
import { useAwait } from "./useAwait";
import { useLocale } from "./useLocale";
@@ -1,4 +1,4 @@
import { api } from "../core/api/dynamic";
import { api } from "../api/dynamic";
import { Tankopedia } from "../stores/tankopedia";
import { useAwait } from "./useAwait";
@@ -1,5 +1,5 @@
import { deburr } from "lodash-es";
import { api } from "../core/api/dynamic";
import { api } from "../api/dynamic";
import { useAwait } from "./useAwait";
import { useGameStrings } from "./useGameStrings";
+1 -1
View File
@@ -1,4 +1,4 @@
import { api } from "../core/api/dynamic";
import { api } from "../api/dynamic";
import { useAwait } from "./useAwait";
import { useLocale } from "./useLocale";
@@ -1,4 +1,4 @@
import { api } from "../core/api/dynamic";
import { api } from "../api/dynamic";
import { useAwait } from "./useAwait";
export function useTierCompare() {
@@ -1,4 +1,4 @@
import { api } from "../core/api/dynamic";
import { api } from "../api/dynamic";
import { useAwait } from "./useAwait";
export function useUpgradePreset(name: string) {
@@ -5,7 +5,7 @@ import ColorAlias from "../components/ColorAlias.astro";
import ColorScale from "../components/ColorScale.astro";
import Footer from "../components/Footer.astro";
import Navbar from "../components/Navbar.astro";
import type { Color } from "../core/ui/color";
import type { Color } from "../ui/color";
interface Props {
locale: string;
@@ -6,7 +6,7 @@ import ColorScale from "../../../components/ColorScale.astro";
import { Section } from "../../../components/Section";
import SyntaxStyles from "../../../components/SyntaxStyles.astro";
import ToolBanner from "../../../components/ToolBanner.astro";
import { tools } from "../../../core/tools/tools";
import { tools } from "../../../config/tools";
import BaseLayout from "../../../layouts/BaseLayout.astro";
export { getStaticPaths } from "../index.astro";
@@ -1,7 +1,7 @@
---
import ColorScale from "../../../components/ColorScale.astro";
import ToolBanner from "../../../components/ToolBanner.astro";
import { tools } from "../../../core/tools/tools";
import { tools } from "../../../config/tools";
import BaseLayout from "../../../layouts/BaseLayout.astro";
import { Page } from "./_index";
@@ -1,6 +1,6 @@
---
import { Grade } from "@protos/blitz_static_standard_grades_enum";
import { api } from "../../../core/api/dynamic";
import { api } from "../../../api/dynamic";
import BaseLayout from "../../../layouts/BaseLayout.astro";
export { getStaticPaths } from "../index.astro";
@@ -9,8 +9,8 @@ import HomeHero from "../../components/HomeHero.astro";
import HomePlayers from "../../components/HomePlayers.astro";
import HomeTanks from "../../components/HomeTanks.astro";
import HomeTechnical from "../../components/HomeTechnical.astro";
import { clientUnmounted } from "../../core/game/unmounted";
import { tools } from "../../core/tools/tools";
import { tools } from "../../config/tools";
import { clientUnmounted } from "../../game/unmounted";
import BaseLayout from "../../layouts/BaseLayout.astro";
export const getStaticPaths = (() => {
@@ -1,13 +1,13 @@
import { Fragment, useMemo } from "react";
import { api } from "../../../../api/dynamic";
import { TankopediaLoadout } from "../../../../components/TankopediaLoadout";
import { api } from "../../../../core/api/dynamic";
import { characteristicsOrder } from "../../../../core/tankopedia/characteristicsOrder";
import { computeCharacteristics } from "../../../../core/tankopedia/computeCharacteristics";
import { useAwait } from "../../../../hooks/useAwait";
import { useCharacteristicRenderer } from "../../../../hooks/useCharacteristicRenderer";
import { useGameStrings } from "../../../../hooks/useGameStrings";
import { LocaleProvider } from "../../../../hooks/useLocale";
import { Tankopedia } from "../../../../stores/tankopedia";
import { characteristicsOrder } from "../../../../tankopedia/characteristicsOrder";
import { computeCharacteristics } from "../../../../tankopedia/computeCharacteristics";
interface PageProps {
id: string;
@@ -1,7 +1,8 @@
---
import "@radix-ui/colors/violet-dark.css";
import { api } from "../../../../core/api/dynamic";
import { mixStaticPaths } from "../../../../core/astro/mixStaticPaths";
import { api } from "../../../../api/dynamic";
import { mixStaticPaths } from "../../../../astro/mixStaticPaths";
import ColorScale from "../../../../components/ColorScale.astro";
import BaseLayout from "../../../../layouts/BaseLayout.astro";
import { getStaticPaths as _getStaticPaths } from "../index.astro";
import { Page } from "./_index";
@@ -19,5 +20,8 @@ const { id, locale } = Astro.props;
---
<BaseLayout {locale} accent="violet">
<ColorScale color="tomato" />
<ColorScale color="jade" />
<Page {locale} {id} client:load />
</BaseLayout>
@@ -1,10 +1,10 @@
import fuzzysort from "fuzzysort";
import { useMemo } from "react";
import { api } from "../../../api/dynamic";
import { IncrementalLoader } from "../../../components/IncrementalLoader";
import { TankCard } from "../../../components/TankCard";
import { TankCards } from "../../../components/TankCards";
import { TankSearch } from "../../../components/TankSearch";
import { api } from "../../../core/api/dynamic";
import { useAwait } from "../../../hooks/useAwait";
import { LocaleProvider } from "../../../hooks/useLocale";
import { useSearchableTanks } from "../../../hooks/useSearchableTanks";
@@ -2,7 +2,7 @@
import "@radix-ui/colors/violet-dark.css";
import { Section } from "../../../components/Section";
import ToolBanner from "../../../components/ToolBanner.astro";
import { tools } from "../../../core/tools/tools";
import { tools } from "../../../config/tools";
import BaseLayout from "../../../layouts/BaseLayout.astro";
import { Page } from "./_index";
@@ -1,5 +1,5 @@
import type { APIContext, GetStaticPaths } from "astro";
import { api } from "../../../core/api/dynamic";
import { api } from "../../../api/dynamic";
export const getStaticPaths = (async () => {
const { avatars } = await api.avatars();
@@ -1,6 +1,6 @@
import type { APIContext } from "astro";
import { api } from "../../../core/api/dynamic";
import { imageProxy } from "../../../core/api/imageProxy";
import { api } from "../../../api/dynamic";
import { imageProxy } from "../../../api/imageProxy";
export { getStaticPaths } from "./[id].json";
@@ -1,4 +1,4 @@
import { api } from "../../../core/api/dynamic";
import { api } from "../../../api/dynamic";
/**
* Identical to `avatars/[id].json`, but returns data on all avatars at once,
@@ -1,5 +1,5 @@
import { Avatars } from "@protos/blitzkit/avatars";
import { api } from "../../../core/api/dynamic";
import { Avatars } from "@protos/avatars";
import { api } from "../../../api/dynamic";
export async function GET() {
const avatars = await api.avatars();
@@ -1,4 +1,4 @@
import { api } from "../../../core/api/dynamic";
import { api } from "../../../api/dynamic";
/**
* Returns a list of all avatars ids.
@@ -1,5 +1,5 @@
import type { APIContext, GetStaticPaths } from "astro";
import { api } from "../../../core/api/dynamic";
import { api } from "../../../api/dynamic";
export const getStaticPaths = (async () => {
const { backgrounds } = await api.backgrounds();
@@ -1,6 +1,6 @@
import type { APIContext } from "astro";
import { api } from "../../../core/api/dynamic";
import { imageProxy } from "../../../core/api/imageProxy";
import { api } from "../../../api/dynamic";
import { imageProxy } from "../../../api/imageProxy";
export { getStaticPaths } from "./[id].json";
@@ -1,4 +1,4 @@
import { api } from "../../../core/api/dynamic";
import { api } from "../../../api/dynamic";
export async function GET() {
const { backgrounds } = await api.backgrounds();
@@ -1,4 +1,4 @@
import { api } from "../../../core/api/dynamic";
import { api } from "../../../api/dynamic";
export async function GET() {
const { backgrounds } = await api.backgrounds();
@@ -0,0 +1,13 @@
import type { GetStaticPaths } from "astro";
import { api } from "../../../api/dynamic";
import { imageProxy } from "../../../api/imageProxy";
export const getStaticPaths = (async () => {
const group = api.metadata.group("CurrencyEntity");
return group.map(({ name }) => ({ params: { id: name } }));
}) satisfies GetStaticPaths;
export async function GET({ params }: { params: { id: string } }) {
const icon = await api.currencyIcon(params.id);
return await imageProxy(icon);
}
@@ -1,7 +1,7 @@
import { TankClass, TankType } from "@blitzkit/core";
import { Nation } from "@protos/blitz_static_tank_component";
import type { APIContext, GetStaticPaths } from "astro";
import { GunType } from "../../../core/tankopedia/characteristics";
import { GunType } from "../../../tankopedia/characteristics";
import { GET as _GET } from "./all.json";
export const ENUMS = {
@@ -1,6 +1,6 @@
import locales from "@blitzkit/i18n/locales.json";
import type { GetStaticPaths, GetStaticPathsResult } from "astro";
import { api } from "../../../../core/api/dynamic";
import { api } from "../../../../api/dynamic";
export const getStaticPaths = (async () => {
const paths: GetStaticPathsResult = [];
@@ -1,8 +1,8 @@
import { Nation } from "@protos/game/proto/legacy/blitz_static_tank_component";
import { Nation } from "@protos/blitz_static_tank_component";
import type { APIContext, GetStaticPaths } from "astro";
import { clientUnmountedResponse } from "../../../../core/api/responses";
import { game } from "../../../../core/game/game";
import { clientUnmounted } from "../../../../core/game/unmounted";
import { clientUnmountedResponse } from "../../../../api/responses";
import { game } from "../../../../game/game";
import { clientUnmounted } from "../../../../game/unmounted";
export const getStaticPaths = (async () => {
return Object.values(Nation)
@@ -1,6 +1,6 @@
import locales from "@blitzkit/i18n/locales.json";
import type { APIContext, GetStaticPaths } from "astro";
import { api } from "../../../core/api/dynamic";
import { api } from "../../../api/dynamic";
export const getStaticPaths = (() => {
return locales.supported.map(({ locale }) => ({ params: { locale } }));
@@ -1,5 +1,5 @@
import type { APIContext, GetStaticPaths } from "astro";
import { api } from "../../../core/api/dynamic";
import { api } from "../../../api/dynamic";
export const getStaticPaths = (async () => {
const { list } = await api.tankList();
@@ -1,11 +1,11 @@
import type { APIContext } from "astro";
import { api } from "../../../core/api/dynamic";
import { api } from "../../../api/dynamic";
import {
clientUnmountedResponse,
notFoundResponse,
} from "../../../core/api/responses";
import { game } from "../../../core/game/game";
import { clientUnmounted } from "../../../core/game/unmounted";
} from "../../../api/responses";
import { game } from "../../../game/game";
import { clientUnmounted } from "../../../game/unmounted";
export { getStaticPaths } from "./[id].json";
@@ -1,4 +1,4 @@
import { api } from "../../../core/api/dynamic";
import { api } from "../../../api/dynamic";
/**
* Literally all the tanks in one place lmao.
@@ -1,5 +1,5 @@
import { Tanks } from "@protos/blitzkit/tanks";
import { api } from "../../../core/api/dynamic";
import { Tanks } from "@protos/tanks";
import { api } from "../../../api/dynamic";
/**
* Literally all the tanks in one place lmao.
@@ -1,4 +1,4 @@
import { characteristicsOrder } from "../../../core/tankopedia/characteristicsOrder";
import { characteristicsOrder } from "../../../tankopedia/characteristicsOrder";
/**
* The naked man fears no pickpocket.
@@ -1,4 +1,4 @@
import { api } from "../../../core/api/dynamic";
import { api } from "../../../api/dynamic";
/**
* List!
@@ -1,5 +1,5 @@
import { TankList } from "@protos/blitzkit/tank_list";
import { api } from "../../../core/api/dynamic";
import { TankList } from "@protos/tank_list";
import { api } from "../../../api/dynamic";
/**
* List!!
@@ -1,4 +1,4 @@
import { api } from "../../../core/api/dynamic";
import { api } from "../../../api/dynamic";
export async function GET() {
const popular = await api.popularTanks();
@@ -1,5 +1,5 @@
import { PopularTanks } from "@protos/blitzkit/popular_tanks";
import { api } from "../../../core/api/dynamic";
import { PopularTanks } from "@protos/popular_tanks";
import { api } from "../../../api/dynamic";
export async function GET() {
const popular = await api.popularTanks();
@@ -1,6 +1,6 @@
import { TankUpgradePricePresetComponent } from "@protos/game/proto/legacy/blitz_static_tank_upgrade_price_preset_component";
import { TankUpgradePricePresetComponent } from "@protos/blitz_static_tank_upgrade_price_preset_component";
import type { APIContext, GetStaticPaths } from "astro";
import { api } from "../../../../../core/api/dynamic";
import { api } from "../../../../../api/dynamic";
export const getStaticPaths = (async () => {
return api.metadata
@@ -1,4 +1,4 @@
import { api } from "../../core/api/dynamic";
import { api } from "../../api/dynamic";
/**
* Woah! test.
@@ -1,5 +1,5 @@
import { Tiers } from "@protos/blitzkit/tiers";
import { api } from "../../core/api/dynamic";
import { Tiers } from "@protos/tiers";
import { api } from "../../api/dynamic";
/**
* Woah!
Loaded 100 of 111 files, more files were not shown because too many files have changed in this diff. Show more