mirror of
https://github.com/blitzkit/blitzkit.git
synced 2026-10-24 20:19:49 +02:00
Compare commits
11
Commits
f0e0d849d5
...
0e637d772e
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
0e637d772e | ||
|
|
a834d48a38 | ||
|
|
f550386fd9 | ||
|
|
0a4b81cde4 | ||
|
|
e1cc60ea5e | ||
|
|
a40860901b | ||
|
|
f3e96718eb | ||
|
|
a00411919d | ||
|
|
b298874f0d | ||
|
|
7011d4d20f | ||
|
|
d9ce16b41a |
No files matched your search
@@ -53,3 +53,4 @@ dist-ssr
|
||||
*.njsproj
|
||||
*.sln
|
||||
*.sw?
|
||||
*.lscache
|
||||
Vendored
+1
-1
@@ -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
@@ -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
-1
Submodule packages/closed updated: cc81b43447...ea13d6f193.
@@ -200,6 +200,7 @@
|
||||
"tanks": {
|
||||
"loadout": {
|
||||
"modules": "Modules",
|
||||
"equipment": "Equipment",
|
||||
"alternative": "Alt"
|
||||
},
|
||||
|
||||
|
||||
@@ -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 +=
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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);
|
||||
|
||||
+13
-11
@@ -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");
|
||||
File renamed without changes.
File renamed without changes.
File renamed without changes.
+62
-38
@@ -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}`;
|
||||
}
|
||||
}
|
||||
File renamed without changes.
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
File renamed without changes.
File renamed without changes.
File renamed without changes.
@@ -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,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
Reference in new issue
Block a user