mirror of
https://github.com/blitzkit/blitzkit.git
synced 2026-10-24 20:19:49 +02:00
Compare commits
17
Commits
851a1108d2
...
b8742bae66
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
b8742bae66 | ||
|
|
af58b4614d | ||
|
|
db6c4679b7 | ||
|
|
8169dfd85d | ||
|
|
e6d7f78ea4 | ||
|
|
f1f29b85b7 | ||
|
|
f587bc0983 | ||
|
|
7ef4e0b9af | ||
|
|
b52919ebfe | ||
|
|
84290b1c0e | ||
|
|
24297dcae8 | ||
|
|
c7ee3dbf7e | ||
|
|
dd769a9aa5 | ||
|
|
645cfacecb | ||
|
|
d2041d0ee6 | ||
|
|
ed7dd76ee5 | ||
|
|
bc2b9f1267 |
No files matched your search
@@ -1,83 +0,0 @@
|
||||
name: Assets
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: production
|
||||
|
||||
workflow_dispatch:
|
||||
inputs:
|
||||
asset_repo:
|
||||
type: choice
|
||||
required: false
|
||||
description: What asset repo to write to
|
||||
options:
|
||||
- blitzkit/assets
|
||||
- blitzkit/assets-preview
|
||||
- blitzkit/assets-dev
|
||||
default: blitzkit/assets
|
||||
|
||||
asset_source:
|
||||
type: string
|
||||
required: false
|
||||
description: "Archive URL or Steam to download (example: steam:APP_ID/DEPOT_ID or zip:URL_TO_ZIP)"
|
||||
default: "steam:444200/444202"
|
||||
|
||||
concurrency:
|
||||
group: ${{ github.workflow }}-${{ github.ref }}-${{ github.event.inputs.asset_repo }}
|
||||
cancel-in-progress: true
|
||||
|
||||
env:
|
||||
DISCORD_CLIENT_ID: ${{ secrets.DISCORD_CLIENT_ID }}
|
||||
DISCORD_TOKEN: ${{ secrets.DISCORD_TOKEN }}
|
||||
DATABASE_URL: ${{ secrets.DATABASE_URL }}
|
||||
VIDEOS_SHEET: ${{ secrets.VIDEOS_SHEET }}
|
||||
GOOGLE_APPLICATION_CREDENTIALS: ${{ secrets.GOOGLE_APPLICATION_CREDENTIALS }}
|
||||
WOTB_GLOSSARY: ${{ secrets.WOTB_GLOSSARY }}
|
||||
WOTB_DLC_CDN: ${{ secrets.WOTB_DLC_CDN }}
|
||||
PUBLIC_WARGAMING_APPLICATION_ID: ${{ secrets.PUBLIC_WARGAMING_APPLICATION_ID }}
|
||||
PUBLIC_ASSET_REPO: ${{ github.event.inputs.asset_repo != '' && github.event.inputs.asset_repo || secrets.PUBLIC_ASSET_REPO }}
|
||||
PUBLIC_ASSET_BRANCH: ${{ secrets.PUBLIC_ASSET_BRANCH }}
|
||||
WOTB_GLOSSARY_DOMAIN: ${{ secrets.WOTB_GLOSSARY_DOMAIN }}
|
||||
WOTB_GLOSSARY_PATH: ${{ secrets.WOTB_GLOSSARY_PATH }}
|
||||
PUBLIC_PROMOTE_OPENTEST: ${{ secrets.PUBLIC_PROMOTE_OPENTEST }}
|
||||
ALLOW_ROBOTS: true
|
||||
PUBLIC_GOOGLE_TAG_MANAGER_ID: ${{ secrets.PUBLIC_GOOGLE_TAG_MANAGER_ID }}
|
||||
PUBLIC_GOOGLE_ANALYTICS_PROPERTY_ID: ${{ secrets.PUBLIC_GOOGLE_ANALYTICS_PROPERTY_ID }}
|
||||
PUBLIC_PATREON_CLIENT_ID: ${{ secrets.PUBLIC_PATREON_CLIENT_ID }}
|
||||
PUBLIC_PATREON_REDIRECT_URI: ${{ secrets.PUBLIC_PATREON_REDIRECT_URI }}
|
||||
PATREON_CLIENT_SECRET: ${{ secrets.PATREON_CLIENT_SECRET }}
|
||||
PUBLIC_NITROPAY_ID: ${{ secrets.PUBLIC_NITROPAY_ID }}
|
||||
PUBLIC_DEBUG_MISSING_I18N: false
|
||||
PUBLIC_DISCORD_SERVER_ID: ${{ secrets.PUBLIC_DISCORD_SERVER_ID }}
|
||||
PUBLIC_ASSET_FAST_USER: blitzkit
|
||||
PUBLIC_ASSET_FAST_REPO: assets
|
||||
PUBLIC_ASSET_BASE: ${{ secrets.PUBLIC_ASSET_BASE }}
|
||||
GH_TOKEN: ${{ secrets.GH_TOKEN }}
|
||||
STEAM_USERNAME: ${{ secrets.STEAM_USERNAME }}
|
||||
STEAM_PASSWORD: ${{ secrets.STEAM_PASSWORD }}
|
||||
|
||||
jobs:
|
||||
build_assets:
|
||||
name: Build assets
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v6
|
||||
with:
|
||||
submodules: recursive
|
||||
token: ${{ secrets.GH_TOKEN }}
|
||||
- uses: arduino/setup-protoc@v3
|
||||
with:
|
||||
repo-token: ${{ secrets.GH_TOKEN }}
|
||||
- uses: oven-sh/setup-bun@v2
|
||||
|
||||
- run: bun run setup
|
||||
|
||||
- name: AppArmor hack
|
||||
run: echo 0 | sudo tee /proc/sys/kernel/apparmor_restrict_unprivileged_userns
|
||||
|
||||
- name: Install patches
|
||||
run: bun run setup:patches --source=${{ github.event.inputs.asset_source || 'steam:444200/444202' }}
|
||||
|
||||
- name: Build assets
|
||||
run: bun run build:assets --all-targets --source=${{ github.event.inputs.asset_source || 'steam:444200/444202' }}
|
||||
@@ -51,4 +51,5 @@ jobs:
|
||||
DATABASE_URL: ${{ secrets.DATABASE_URL }}
|
||||
VIDEOS_SHEET: ${{ secrets.VIDEOS_SHEET }}
|
||||
GOOGLE_APPLICATION_CREDENTIALS: ${{ secrets.GOOGLE_APPLICATION_CREDENTIALS }}
|
||||
|
||||
run: bun run build:averages --production
|
||||
+115
-35
@@ -9,64 +9,144 @@ on:
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
pages: write
|
||||
id-token: write
|
||||
|
||||
concurrency:
|
||||
group: ${{ github.workflow }}-${{ github.ref }}
|
||||
cancel-in-progress: ${{ github.ref == 'refs/heads/main' }}
|
||||
|
||||
env:
|
||||
PUBLIC_WARGAMING_APPLICATION_ID: ${{ secrets.PUBLIC_WARGAMING_APPLICATION_ID }}
|
||||
PUBLIC_PROMOTE_OPENTEST: ${{ secrets.PUBLIC_PROMOTE_OPENTEST }}
|
||||
ALLOW_ROBOTS: ${{ secrets.ALLOW_ROBOTS }}
|
||||
# blitzkit
|
||||
PUBLIC_BRANCH: main
|
||||
PUBLIC_PROMOTE_OPENTEST: false
|
||||
PUBLIC_STATIC_ASSET_BASE: https://assets.blitzkit.app
|
||||
PUBLIC_GUIDE_WEBSITE: https://guidesblitz.com
|
||||
|
||||
# blitz
|
||||
WOTB_GLOSSARY: ${{ secrets.WOTB_GLOSSARY }}
|
||||
PUBLIC_GOOGLE_TAG_MANAGER_ID: ${{ secrets.PUBLIC_GOOGLE_TAG_MANAGER_ID }}
|
||||
PUBLIC_GOOGLE_ANALYTICS_PROPERTY_ID: ${{ secrets.PUBLIC_GOOGLE_ANALYTICS_PROPERTY_ID }}
|
||||
GOOGLE_APPLICATION_CREDENTIALS: ${{ secrets.GOOGLE_APPLICATION_CREDENTIALS }}
|
||||
WOTB_GLOSSARY_DOMAIN: ${{ secrets.WOTB_GLOSSARY_DOMAIN }}
|
||||
WOTB_GLOSSARY_PATH: ${{ secrets.WOTB_GLOSSARY_PATH }}
|
||||
PUBLIC_DISCORD_SERVER_ID: ${{ secrets.PUBLIC_DISCORD_SERVER_ID }}
|
||||
PUBLIC_ASSET_BASE: ${{ secrets.PUBLIC_ASSET_BASE }}
|
||||
PUBLIC_BRANCH: ${{ secrets.PUBLIC_BRANCH }}
|
||||
PUBLIC_GUIDE_WEBSITE: ${{ secrets.PUBLIC_GUIDE_WEBSITE }}
|
||||
SERVICING: ${{ secrets.SERVICING }}
|
||||
GH_TOKEN: ${{ secrets.GH_TOKEN }}
|
||||
GAME_DIR: temp/game
|
||||
|
||||
# google
|
||||
PUBLIC_GOOGLE_TAG_MANAGER_ID: ${{ secrets.PUBLIC_GOOGLE_TAG_MANAGER_ID }}
|
||||
|
||||
# wargaming
|
||||
PUBLIC_WARGAMING_APPLICATION_ID: ${{ secrets.PUBLIC_WARGAMING_APPLICATION_ID }}
|
||||
|
||||
# steam
|
||||
STEAM_USERNAME: ${{ secrets.STEAM_USERNAME }}
|
||||
STEAM_PASSWORD: ${{ secrets.STEAM_PASSWORD }}
|
||||
STEAM_APP: 444200
|
||||
STEAM_OS: windows
|
||||
|
||||
jobs:
|
||||
build:
|
||||
name: Build website
|
||||
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
include:
|
||||
- chunk: default
|
||||
node: blitzkit/blitzkit.github.io
|
||||
path: dist/website
|
||||
|
||||
- chunk: api
|
||||
node: blitzkit/api
|
||||
path: dist/website/api
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v6
|
||||
- name: Free disk space
|
||||
uses: jlumbroso/free-disk-space@main
|
||||
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v6
|
||||
with:
|
||||
submodules: recursive
|
||||
token: ${{ secrets.GH_TOKEN }}
|
||||
- uses: oven-sh/setup-bun@v2
|
||||
- uses: arduino/setup-protoc@v3
|
||||
|
||||
- name: Setup bun
|
||||
uses: oven-sh/setup-bun@v2
|
||||
|
||||
- name: Setup protoc
|
||||
uses: arduino/setup-protoc@v3
|
||||
with:
|
||||
repo-token: ${{ secrets.GH_TOKEN }}
|
||||
- uses: actions/configure-pages@v6
|
||||
- run: bun run setup
|
||||
|
||||
- name: Build website
|
||||
run: bun run build:website
|
||||
- name: Configure pages
|
||||
uses: actions/configure-pages@v6
|
||||
|
||||
- name: Install dependencies
|
||||
run: bun install
|
||||
|
||||
- name: Setup DepotDownloader
|
||||
run: |
|
||||
REPO_USER="SteamRE"
|
||||
REPO_NAME="DepotDownloader"
|
||||
TEMP="temp"
|
||||
|
||||
OUT="$TEMP/$REPO_NAME"
|
||||
ZIP="$TEMP/$REPO_NAME.zip"
|
||||
|
||||
URL=$(
|
||||
curl -s "https://api.github.com/repos/$REPO_USER/$REPO_NAME/releases/latest" \
|
||||
| jq -r '.assets[]
|
||||
| select(.name | contains("linux-x64"))
|
||||
| .browser_download_url' \
|
||||
| head -n 1
|
||||
)
|
||||
|
||||
mkdir -p "$TEMP"
|
||||
curl -L "$URL" -o "$ZIP"
|
||||
unzip -p "$ZIP" "$REPO_NAME" > "$OUT"
|
||||
rm "$ZIP"
|
||||
|
||||
chmod +x "$OUT"
|
||||
|
||||
- name: Download game
|
||||
run: |
|
||||
TEMP="temp"
|
||||
|
||||
DEPOT_DOWNLOADER="$TEMP/DepotDownloader"
|
||||
GAME="$TEMP/game"
|
||||
|
||||
$DEPOT_DOWNLOADER -os $STEAM_OS -app $STEAM_APP -username $STEAM_USERNAME -password $STEAM_PASSWORD -dir $GAME
|
||||
|
||||
- name: Build
|
||||
run: bun run build
|
||||
env:
|
||||
BUILD_CHUNK: ${{ matrix.chunk }}
|
||||
|
||||
- name: Upload artifact
|
||||
uses: actions/upload-pages-artifact@v5
|
||||
id: upload
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
path: dist/website
|
||||
name: chunk-${{ matrix.chunk }}
|
||||
path: ${{ matrix.path }}
|
||||
|
||||
deploy-github-pages:
|
||||
if: ${{ github.ref == 'refs/heads/production' }}
|
||||
name: Deploy to GitHub Pages
|
||||
runs-on: ubuntu-latest
|
||||
needs: build
|
||||
environment:
|
||||
name: Production
|
||||
url: ${{ steps.deployment.outputs.page_url }}
|
||||
- name: Save artifact ID
|
||||
run: |
|
||||
echo "${{ steps.upload.outputs.artifact-id }}"
|
||||
|
||||
steps:
|
||||
- name: Deploy to GitHub Pages
|
||||
id: deployment
|
||||
uses: actions/deploy-pages@v5
|
||||
- name: Trigger deployment
|
||||
env:
|
||||
TOKEN: ${{ secrets.GH_NODE_DEPLOY_TOKEN }}
|
||||
ARTIFACT_ID: ${{ steps.upload.outputs.artifact-id }}
|
||||
TARGET_REPO: ${{ matrix.node }}
|
||||
run: |
|
||||
curl \
|
||||
-X POST \
|
||||
-H "Accept: application/vnd.github+json" \
|
||||
-H "Authorization: Bearer $TOKEN" \
|
||||
"https://api.github.com/repos/$TARGET_REPO/dispatches" \
|
||||
-d "{
|
||||
\"event_type\": \"deploy-pages\",
|
||||
\"client_payload\": {
|
||||
\"source_repo\": \"${{ github.repository }}\",
|
||||
\"run_id\": \"${{ github.run_id }}\",
|
||||
\"artifact_id\": \"$ARTIFACT_ID\",
|
||||
\"chunk\": \"${{ matrix.chunk }}\"
|
||||
}
|
||||
}"
|
||||
+4
-2
@@ -1,10 +1,12 @@
|
||||
{
|
||||
"name": "blitzkit",
|
||||
"version": "1.30.8",
|
||||
"version": "1.31.0",
|
||||
"license": "BlitzKit License",
|
||||
"private": true,
|
||||
"scripts": {
|
||||
"dev": "cd packages/website && bun run dev"
|
||||
"dev": "cd packages/website && bun run dev",
|
||||
"build": "cd packages/website && bun run build",
|
||||
"build:averages": "cd packages/scripts && bun run build:averages"
|
||||
},
|
||||
"type": "module",
|
||||
"workspaces": [
|
||||
|
||||
@@ -4,8 +4,8 @@ import type { BlitzGlossary } from "../types";
|
||||
export async function fetchGlossary(locale: string) {
|
||||
const response = await fetch(
|
||||
`${assertSecret(
|
||||
import.meta.env.WOTB_GLOSSARY_DOMAIN
|
||||
)}/${locale}${assertSecret(import.meta.env.WOTB_GLOSSARY_PATH)}`
|
||||
import.meta.env.WOTB_GLOSSARY_DOMAIN,
|
||||
)}/${locale}${assertSecret(import.meta.env.WOTB_GLOSSARY_PATH)}`,
|
||||
);
|
||||
return (await response.json()) as BlitzGlossary;
|
||||
}
|
||||
@@ -2,6 +2,7 @@ import {
|
||||
CamouflageDefinitions,
|
||||
ConsumableDefinitions,
|
||||
EquipmentDefinitions,
|
||||
Gallery,
|
||||
GameDefinitions,
|
||||
MapDefinitions,
|
||||
ModelDefinitions,
|
||||
@@ -20,4 +21,5 @@ export abstract class BlitzKitAPI {
|
||||
abstract camouflageDefinitions(): Promise<CamouflageDefinitions>;
|
||||
abstract tankDefinitions(): Promise<TankDefinitions>;
|
||||
abstract gameDefinitions(): Promise<GameDefinitions>;
|
||||
abstract galleryDefinitions(): Promise<Gallery>;
|
||||
}
|
||||
@@ -3,6 +3,7 @@ import {
|
||||
CamouflageDefinitions,
|
||||
ConsumableDefinitions,
|
||||
EquipmentDefinitions,
|
||||
Gallery,
|
||||
GameDefinitions,
|
||||
ModelDefinitions,
|
||||
ProvisionDefinitions,
|
||||
@@ -43,4 +44,8 @@ export class ClientBlitzKitAPI extends BlitzKitAPI {
|
||||
equipmentDefinitions() {
|
||||
return fetchPB("/api/definitions/equipment.pb", EquipmentDefinitions);
|
||||
}
|
||||
|
||||
galleryDefinitions() {
|
||||
return fetchPB("/api/definitions/gallery.pb", Gallery);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,67 @@
|
||||
import { Avatar, fetchGlossary, Gallery } from "@blitzkit/core";
|
||||
import { ServerBlitzKitAPI9 } from "@blitzkit/core/src/blitzkit/api/server/9_gameDefinitions";
|
||||
import locales from "@blitzkit/i18n/locales.json";
|
||||
import { extname } from "path";
|
||||
import { Cache } from "./0_base";
|
||||
|
||||
export abstract class ServerBlitzKitAPI10 extends ServerBlitzKitAPI9 {
|
||||
@Cache()
|
||||
async galleryDefinitions() {
|
||||
const avatars: Record<string, { avatar: Avatar; url: string }> = {};
|
||||
|
||||
await Promise.all(
|
||||
locales.supported.map(async (supported) => {
|
||||
const glossary = await fetchGlossary(
|
||||
supported.blitz ?? supported.locale,
|
||||
);
|
||||
|
||||
console.log(
|
||||
`Found ${Object.keys(glossary).length} things for ${supported.locale}`,
|
||||
);
|
||||
|
||||
for (const key in glossary) {
|
||||
const glossaryEntry = glossary[key];
|
||||
|
||||
if (
|
||||
!key.startsWith("avatar") ||
|
||||
key.endsWith("_part") ||
|
||||
glossaryEntry.image_url === null
|
||||
) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (key in avatars) {
|
||||
avatars[key].avatar.name!.locales[supported.locale] =
|
||||
glossaryEntry.title;
|
||||
} else {
|
||||
const extension = extname(glossaryEntry.image_url);
|
||||
|
||||
avatars[key] = {
|
||||
url: glossaryEntry.image_url,
|
||||
avatar: {
|
||||
id: key,
|
||||
name: { locales: { [supported.locale]: glossaryEntry.title } },
|
||||
extension,
|
||||
},
|
||||
};
|
||||
}
|
||||
}
|
||||
}),
|
||||
);
|
||||
|
||||
const gallery: Gallery = { avatars: [] };
|
||||
|
||||
await Promise.all(
|
||||
Object.entries(avatars).map(async ([key, { url, avatar }]) => {
|
||||
if (!(locales.default in avatars[key].avatar.name!.locales)) {
|
||||
console.warn(`Avatar ${key} has no ${locales.default} name`);
|
||||
return;
|
||||
}
|
||||
|
||||
gallery.avatars.push(avatar);
|
||||
}),
|
||||
);
|
||||
|
||||
return gallery;
|
||||
}
|
||||
}
|
||||
@@ -1,3 +1,3 @@
|
||||
import { ServerBlitzKitAPI9 } from "./9_gameDefinitions";
|
||||
import { ServerBlitzKitAPI10 } from "@blitzkit/core/src/blitzkit/api/server/10_galleryDefinitions";
|
||||
|
||||
export class ServerBlitzKitAPI extends ServerBlitzKitAPI9 {}
|
||||
export class ServerBlitzKitAPI extends ServerBlitzKitAPI10 {}
|
||||
@@ -2,7 +2,6 @@ import {
|
||||
AverageDefinitions,
|
||||
AverageDefinitionsAllStats,
|
||||
AverageDefinitionsEntry,
|
||||
type AverageDefinitionsManifest,
|
||||
type IndividualTankStats,
|
||||
REGIONS,
|
||||
type Region,
|
||||
@@ -23,14 +22,6 @@ interface DataPoint {
|
||||
w: number;
|
||||
}
|
||||
|
||||
type OptionalSecondLevel<T> = {
|
||||
[P in keyof T]: P extends "samples"
|
||||
? T[P]
|
||||
: {
|
||||
[K in keyof T[P]]?: T[P][K];
|
||||
};
|
||||
};
|
||||
|
||||
const MINUTE = 60 * 1000;
|
||||
const HOUR = 60 * MINUTE;
|
||||
const DAY = 24 * HOUR;
|
||||
@@ -223,26 +214,16 @@ async function postWork() {
|
||||
});
|
||||
|
||||
const time = Date.now();
|
||||
const latest = Math.round(time / DAY);
|
||||
const averageDefinitions = {
|
||||
averages,
|
||||
samples,
|
||||
time,
|
||||
} satisfies AverageDefinitions;
|
||||
|
||||
const manifest: AverageDefinitionsManifest = {
|
||||
version: 1,
|
||||
latest,
|
||||
};
|
||||
|
||||
await uploader.add({
|
||||
path: `averages/${latest}.pb`,
|
||||
path: "averages.pb",
|
||||
content: AverageDefinitions.encode(averageDefinitions).finish(),
|
||||
});
|
||||
await uploader.add({
|
||||
path: "averages/manifest.json",
|
||||
content: new TextEncoder().encode(JSON.stringify(manifest)),
|
||||
});
|
||||
|
||||
await uploader.flush();
|
||||
}
|
||||
@@ -1,43 +0,0 @@
|
||||
import { assertSecret } from "@blitzkit/core";
|
||||
import { AbstractVFS } from "@blitzkit/core/src/blitzkit/vfs/abstract";
|
||||
import { LocalVFS } from "@blitzkit/core/src/blitzkit/vfs/local";
|
||||
import { MixedVFS } from "@blitzkit/core/src/blitzkit/vfs/mixed";
|
||||
import { SteamVFS } from "@blitzkit/core/src/blitzkit/vfs/steam";
|
||||
import { ZipVFS } from "@blitzkit/core/src/blitzkit/vfs/zip";
|
||||
|
||||
export const PATCHES_ROOT = "../../temp/patches";
|
||||
|
||||
const steamPattern = /steam:(\d+)\/(\d+)/;
|
||||
const zipPattern = /zip:(.+)/;
|
||||
const localePattern = /local:"?(.+)"?/;
|
||||
|
||||
const source = Bun.argv
|
||||
.find((arg) => arg.startsWith("--source="))
|
||||
?.split("=")[1];
|
||||
|
||||
let resolved: AbstractVFS;
|
||||
|
||||
if (!source) {
|
||||
throw new Error("No source specified");
|
||||
} else if (steamPattern.test(source)) {
|
||||
const [, app, depot] = source.match(steamPattern)!.map(Number);
|
||||
|
||||
resolved = await new SteamVFS(
|
||||
assertSecret(import.meta.env.STEAM_USERNAME),
|
||||
assertSecret(import.meta.env.STEAM_PASSWORD),
|
||||
app,
|
||||
depot,
|
||||
).init();
|
||||
} else if (zipPattern.test(source)) {
|
||||
const [, url] = source.match(zipPattern)!;
|
||||
resolved = await new ZipVFS(url).init();
|
||||
} else if (localePattern.test(source)) {
|
||||
const [, path] = source.match(localePattern)!;
|
||||
resolved = await new LocalVFS(path).init();
|
||||
} else {
|
||||
throw new Error("No valid source specified");
|
||||
}
|
||||
|
||||
resolved = new MixedVFS([new LocalVFS(PATCHES_ROOT), resolved]);
|
||||
|
||||
export const vfs = resolved;
|
||||
@@ -1,73 +0,0 @@
|
||||
import sharp from "sharp";
|
||||
import { AssetUploader } from "../core/github/assetUploader";
|
||||
import { vfs } from "./constants";
|
||||
import { OptionalDevices } from "./definitions";
|
||||
|
||||
|
||||
|
||||
export async function equipmentIcons() {
|
||||
console.log("Building equipment icons...");
|
||||
|
||||
using uploader = new AssetUploader("equipment icons");
|
||||
const optionalDevices = await vfs.xml<{ root: OptionalDevices }>(
|
||||
`Data/XML/item_defs/vehicles/common/optional_devices.xml`,
|
||||
);
|
||||
const mappings = await vfs.yaml<Mappings>(
|
||||
`Data/UI/Screens3/Lobby/Inventory/OptionalDevices/OptionalDevicesItemImage.style.yaml`,
|
||||
);
|
||||
const image = sharp(
|
||||
await vfs.file(
|
||||
`Data/Gfx/UI/InventoryIcons/Big/OptionalDevices/texture0.packed.webp`,
|
||||
),
|
||||
);
|
||||
|
||||
for (const optionalDeviceKey in optionalDevices.root) {
|
||||
const optionalDevice = optionalDevices.root[optionalDeviceKey];
|
||||
|
||||
if (optionalDeviceKey === "nextAvailableId") continue;
|
||||
|
||||
const mapping = mappings.StyleSheets.find((mapping) =>
|
||||
mapping.selectors.includes(
|
||||
`.optional_device_item.${optionalDevice.icon} #Img`,
|
||||
),
|
||||
);
|
||||
|
||||
if (!mapping) {
|
||||
console.warn(`No mapping found for ${optionalDevice.icon}; skipping...`);
|
||||
continue;
|
||||
}
|
||||
|
||||
const configPathRaw = mapping.properties["bg-sprite"];
|
||||
const configPath = configPathRaw.replace("~res:/", "");
|
||||
|
||||
if (configPath.startsWith("Gfx/Lobby")) {
|
||||
const configPathWebp = configPath.replace(".txt", "");
|
||||
const image = sharp(await vfs.file(`Data/${configPathWebp}.packed.webp`));
|
||||
const content = await image.trim().toBuffer();
|
||||
|
||||
await uploader.add({
|
||||
path: `icons/equipment/${optionalDevice.id}.webp`,
|
||||
content,
|
||||
});
|
||||
} else {
|
||||
const config = await vfs.text(`Data/${configPath}`);
|
||||
const sizes = config.split("\n")[4].split(" ").map(Number);
|
||||
const content = await image
|
||||
.clone()
|
||||
.extract({
|
||||
left: sizes[0],
|
||||
top: sizes[1],
|
||||
width: sizes[2],
|
||||
height: sizes[3],
|
||||
})
|
||||
.toBuffer();
|
||||
|
||||
await uploader.add({
|
||||
path: `icons/equipment/${optionalDevice.id}.webp`,
|
||||
content,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
await uploader.flush();
|
||||
}
|
||||
@@ -1,64 +0,0 @@
|
||||
import { config } from "dotenv";
|
||||
import { argv } from "process";
|
||||
import { boosterIcons } from "./boosterIcons";
|
||||
import { camouflageIcons } from "./camouflageIcons";
|
||||
import { vfs } from "./constants";
|
||||
import { consumableProvisionIcons } from "./consumableProvisionIcons";
|
||||
import { currencies } from "./currencies";
|
||||
import { definitions } from "./definitions";
|
||||
import { equipmentIcons } from "./equipmentIcons";
|
||||
import { flags } from "./flags";
|
||||
import { gameModeBanners } from "./gameModeBanners";
|
||||
import { glossary } from "./glossary";
|
||||
import { migration } from "./migration";
|
||||
import { moduleIcons } from "./moduleIcons";
|
||||
import { popularTanks } from "./popularTanks";
|
||||
import { shellIcons } from "./shellIcons";
|
||||
import { skillIcons } from "./skillIcons";
|
||||
import { tankArmors } from "./tankArmors";
|
||||
import { tankIcons } from "./tankIcons";
|
||||
import { tankModels } from "./tankModels";
|
||||
|
||||
config();
|
||||
|
||||
const allTargets = argv.includes("--all-targets");
|
||||
const targets = argv
|
||||
.find((argument) => argument.startsWith("--target"))
|
||||
?.split("=")[1]
|
||||
.split(",");
|
||||
|
||||
if (!targets && !allTargets) throw new Error("No target(s) specified");
|
||||
|
||||
const methods = [
|
||||
definitions,
|
||||
tankIcons,
|
||||
tankModels,
|
||||
tankArmors,
|
||||
gameModeBanners,
|
||||
currencies,
|
||||
skillIcons,
|
||||
flags,
|
||||
shellIcons,
|
||||
moduleIcons,
|
||||
equipmentIcons,
|
||||
consumableProvisionIcons,
|
||||
camouflageIcons,
|
||||
boosterIcons,
|
||||
glossary,
|
||||
migration,
|
||||
popularTanks,
|
||||
];
|
||||
|
||||
for (const method of methods) {
|
||||
if (allTargets || targets?.includes(method.name)) {
|
||||
try {
|
||||
await method();
|
||||
} catch (error) {
|
||||
console.warn(`Failed method ${method.name}; skipping...`);
|
||||
console.error(error);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
vfs.dispose();
|
||||
process.exit(0);
|
||||
@@ -1,34 +0,0 @@
|
||||
import { toUniqueId } from "@blitzkit/core";
|
||||
import { AssetUploader } from "../core/github/assetUploader";
|
||||
import { vfs } from "./constants";
|
||||
import { VehicleDefinitionList } from "./definitions";
|
||||
|
||||
export async function migration() {
|
||||
console.log("Building migration map...");
|
||||
|
||||
using uploader = new AssetUploader("migration map");
|
||||
const map: Record<string, number> = {};
|
||||
const nations = await vfs
|
||||
.dir(`Data/XML/item_defs/vehicles`)
|
||||
.then((files) => files.filter((nation) => nation !== "common"));
|
||||
|
||||
for (const nation of nations) {
|
||||
const tankList = await vfs.xml<{ root: VehicleDefinitionList }>(
|
||||
`Data/XML/item_defs/vehicles/${nation}/list.xml`,
|
||||
);
|
||||
|
||||
for (const tankKey in tankList.root) {
|
||||
const tank = tankList.root[tankKey];
|
||||
const tankId = toUniqueId(nation, tank.id);
|
||||
const davaKey = `${nation}:${tankKey}`;
|
||||
|
||||
map[davaKey] = tankId;
|
||||
}
|
||||
}
|
||||
|
||||
await uploader.add({
|
||||
path: "definitions/migration.json",
|
||||
content: new TextEncoder().encode(JSON.stringify(map)),
|
||||
});
|
||||
await uploader.flush();
|
||||
}
|
||||
@@ -1,77 +0,0 @@
|
||||
import {
|
||||
assertSecret,
|
||||
fetchTankDefinitions,
|
||||
PopularTanks,
|
||||
} from "@blitzkit/core";
|
||||
import { google } from "googleapis";
|
||||
import { AssetUploader } from "../core/github/assetUploader";
|
||||
|
||||
export async function popularTanks() {
|
||||
using uploader = new AssetUploader("popular tanks");
|
||||
const tankDefinitions = await fetchTankDefinitions();
|
||||
|
||||
const auth = await google.auth.getClient({
|
||||
keyFile: import.meta.env.GOOGLE_APPLICATION_CREDENTIALS,
|
||||
scopes: ["https://www.googleapis.com/auth/analytics.readonly"],
|
||||
});
|
||||
const analytics = google.analyticsdata({ version: "v1beta", auth });
|
||||
const report = await analytics.properties.runReport({
|
||||
property: `properties/${assertSecret(
|
||||
import.meta.env.PUBLIC_GOOGLE_ANALYTICS_PROPERTY_ID,
|
||||
)}`,
|
||||
requestBody: {
|
||||
dateRanges: [{ startDate: "7daysAgo", endDate: "today" }],
|
||||
dimensions: [{ name: "pagePath" }],
|
||||
metrics: [{ name: "screenPageViews" }],
|
||||
orderBys: [{ metric: { metricName: "screenPageViews" }, desc: true }],
|
||||
dimensionFilter: {
|
||||
filter: {
|
||||
fieldName: "pagePath",
|
||||
stringFilter: {
|
||||
matchType: "BEGINS_WITH",
|
||||
value: "/tanks/",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
if (!report.data.rows) {
|
||||
throw new Error("No rows in report");
|
||||
}
|
||||
|
||||
const tanks = report.data.rows
|
||||
.filter(
|
||||
(row) =>
|
||||
row.dimensionValues &&
|
||||
row.dimensionValues[0].value &&
|
||||
row.dimensionValues[0].value !== "/tanks/" &&
|
||||
row.metricValues &&
|
||||
row.metricValues[0].value,
|
||||
)
|
||||
.map((row) => ({
|
||||
id: Number(
|
||||
row.dimensionValues![0].value!.match(
|
||||
/\/tools\/tankopedia\/(\d+)\/?/,
|
||||
)?.[1],
|
||||
),
|
||||
views: Number(row.metricValues![0].value!),
|
||||
}))
|
||||
.filter((row) => {
|
||||
if (!(row.id in tankDefinitions.tanks)) {
|
||||
console.warn("Skipping unknown popular tank", row.id);
|
||||
return false;
|
||||
}
|
||||
|
||||
return row.id in tankDefinitions.tanks;
|
||||
})
|
||||
.slice(0, 8)
|
||||
.map(({ id, views }) => ({ id, views }));
|
||||
const popularTanks: PopularTanks = { tanks };
|
||||
|
||||
await uploader.add({
|
||||
path: "definitions/popular-tanks.pb",
|
||||
content: PopularTanks.encode(popularTanks).finish(),
|
||||
});
|
||||
await uploader.flush();
|
||||
}
|
||||
@@ -1,64 +0,0 @@
|
||||
import { NATION_IDS } from "@blitzkit/core";
|
||||
import sharp from "sharp";
|
||||
import { parsePackedSpriteRect } from "../core/blitz/parsePackedSpriteRect";
|
||||
import { AssetUploader } from "../core/github/assetUploader";
|
||||
import { vfs } from "./constants";
|
||||
import type { VehicleDefinitionList } from "./definitions";
|
||||
|
||||
|
||||
export async function tankIcons() {
|
||||
console.log("Building tank icons...");
|
||||
|
||||
using uploader = new AssetUploader("tank icons");
|
||||
const nations = await vfs
|
||||
.dir(`Data/XML/item_defs/vehicles`)
|
||||
.then((files) => files.filter((nation) => nation !== "common"));
|
||||
|
||||
for (const nation of nations) {
|
||||
const tanks = await vfs.xml<{ root: VehicleDefinitionList }>(
|
||||
`Data/XML/item_defs/vehicles/${nation}/list.xml`,
|
||||
);
|
||||
|
||||
for (const tankKey in tanks.root) {
|
||||
const tank = tanks.root[tankKey];
|
||||
|
||||
if (tankKey.includes("tutorial_bot")) continue;
|
||||
|
||||
const nationVehicleId = tank.id;
|
||||
const id = (nationVehicleId << 8) + (NATION_IDS[nation] << 4) + 1;
|
||||
|
||||
const parameters = await vfs.yaml<TankParameters>(
|
||||
`Data/3d/Tanks/Parameters/${nation}/${tankKey}.yaml`,
|
||||
);
|
||||
const smallPath = `Data/${parameters.resourcesPath.smallIconPath
|
||||
.replace(/~res:\//, "")
|
||||
.replace(/\..+/, "")}.packed.webp`;
|
||||
const bigPath = `Data/${parameters.resourcesPath.bigIconPath
|
||||
.replace(/~res:\//, "")
|
||||
.replace(/\..+/, "")}.packed.webp`;
|
||||
const big = await extractPackedTankIcon(
|
||||
await vfs.file(bigPath),
|
||||
`tank ${tankKey} big`,
|
||||
);
|
||||
const small = await extractPackedTankIcon(
|
||||
await vfs.file(smallPath),
|
||||
`tank ${tankKey} small`,
|
||||
);
|
||||
|
||||
if (big) {
|
||||
await uploader.add({
|
||||
content: big,
|
||||
path: `icons/tanks/big/${id}.webp`,
|
||||
});
|
||||
}
|
||||
if (small) {
|
||||
await uploader.add({
|
||||
content: small,
|
||||
path: `icons/tanks/small/${id}.webp`,
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
await uploader.flush();
|
||||
}
|
||||
@@ -1,44 +0,0 @@
|
||||
import { toUniqueId } from "@blitzkit/core";
|
||||
import { NodeIO } from "@gltf-transform/core";
|
||||
import { ALL_EXTENSIONS } from "@gltf-transform/extensions";
|
||||
import { extractModel } from "../core/blitz/extractModel";
|
||||
import { AssetUploader } from "../core/github/assetUploader";
|
||||
import { vfs } from "./constants";
|
||||
import { VehicleDefinitionList } from "./definitions";
|
||||
import { TankParameters } from "./tankIcons";
|
||||
|
||||
export async function tankModels() {
|
||||
console.log("Building tank models...");
|
||||
|
||||
using uploader = new AssetUploader("tank models");
|
||||
const nodeIO = new NodeIO().registerExtensions(ALL_EXTENSIONS);
|
||||
const nations = await vfs
|
||||
.dir(`Data/XML/item_defs/vehicles`)
|
||||
.then((files) => files.filter((nation) => nation !== "common"));
|
||||
|
||||
for (const nationIndex in nations) {
|
||||
const nation = nations[nationIndex];
|
||||
const tanks = await vfs.xml<{ root: VehicleDefinitionList }>(
|
||||
`Data/XML/item_defs/vehicles/${nation}/list.xml`,
|
||||
);
|
||||
const entries = Object.entries(tanks.root);
|
||||
|
||||
for (const [tankKey, tank] of entries) {
|
||||
if (tankKey.includes("tutorial_bot")) continue;
|
||||
|
||||
const id = toUniqueId(nation, tank.id);
|
||||
const parameters = await vfs.yaml<TankParameters>(
|
||||
`Data/3d/Tanks/Parameters/${nation}/${tankKey}.yaml`,
|
||||
);
|
||||
const model = await extractModel(
|
||||
vfs,
|
||||
parameters.resourcesPath.blitzModelPath.replace(/\.sc2$/, ""),
|
||||
);
|
||||
const content = Buffer.from(await nodeIO.writeBinary(model));
|
||||
|
||||
await uploader.add({ path: `3d/tanks/models/${id}.glb`, content });
|
||||
}
|
||||
}
|
||||
|
||||
await uploader.flush();
|
||||
}
|
||||
@@ -1,4 +1,3 @@
|
||||
import node from "@astrojs/node";
|
||||
import react from "@astrojs/react";
|
||||
import { wrapper } from "@blitzkit/i18n";
|
||||
import locales from "@blitzkit/i18n/locales.json";
|
||||
@@ -10,14 +9,6 @@ import { defineConfig } from "astro/config";
|
||||
import packageJSON from "../../package.json";
|
||||
import { tools } from "./src/constants/tools";
|
||||
|
||||
const POSSIBLE_TARGETS = ["app", "web"];
|
||||
|
||||
const target = process.env.PUBLIC_TARGET;
|
||||
|
||||
if (!target || !POSSIBLE_TARGETS.includes(target)) {
|
||||
throw new Error("Invalid target");
|
||||
}
|
||||
|
||||
export default defineConfig({
|
||||
devToolbar: { enabled: false },
|
||||
|
||||
@@ -26,13 +17,12 @@ export default defineConfig({
|
||||
esbuild: { target: "es2022" },
|
||||
},
|
||||
|
||||
output: target === "web" ? "static" : "server",
|
||||
output: "static",
|
||||
site: "https://blitzkit.app",
|
||||
outDir: "../../dist/website",
|
||||
prefetch: { defaultStrategy: "hover", prefetchAll: true },
|
||||
|
||||
build: { concurrency: 4 },
|
||||
adapter: target === "app" ? node({ mode: "standalone" }) : undefined,
|
||||
|
||||
integrations: [
|
||||
favicons({
|
||||
|
||||
@@ -2,10 +2,10 @@
|
||||
"name": "@blitzkit/website",
|
||||
"type": "module",
|
||||
"scripts": {
|
||||
"dev": "PUBLIC_TARGET=web astro dev",
|
||||
"build": "PUBLIC_TARGET=web astro build",
|
||||
"preview": "PUBLIC_TARGET=web astro preview",
|
||||
"lint": "PUBLIC_TARGET=web astro check",
|
||||
"dev": "astro dev",
|
||||
"build": "astro build",
|
||||
"preview": "astro preview",
|
||||
"lint": "astro check",
|
||||
"astro": "astro"
|
||||
},
|
||||
"dependencies": {
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { Switch } from "@radix-ui/themes";
|
||||
import type { EmbedPreviewControllerProps } from "../../pages/[...locale]/embed/[embed]/_index";
|
||||
import type { EmbedPreviewControllerProps } from "../../pages/[...chunk_default]/[...locale]/embed/[embed]/_index";
|
||||
import { EmbedState } from "../../stores/embedState";
|
||||
|
||||
export function Boolean({ configKey }: EmbedPreviewControllerProps) {
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import type { EmbedPreviewControllerProps } from "../../pages/[...locale]/embed/[embed]/_index";
|
||||
import type { EmbedPreviewControllerProps } from "../../pages/[...chunk_default]/[...locale]/embed/[embed]/_index";
|
||||
import { EmbedState } from "../../stores/embedState";
|
||||
import { ColorControllerRaw } from "./ColorControllerRaw";
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { Select } from "@radix-ui/themes";
|
||||
import { useLocale } from "../../hooks/useLocale";
|
||||
import type { EmbedPreviewControllerProps } from "../../pages/[...locale]/embed/[embed]/_index";
|
||||
import type { EmbedPreviewControllerProps } from "../../pages/[...chunk_default]/[...locale]/embed/[embed]/_index";
|
||||
import { EmbedState } from "../../stores/embedState";
|
||||
import type {
|
||||
EmbedConfigItemType,
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { Box } from '@radix-ui/themes';
|
||||
import { useEffect, useRef } from 'react';
|
||||
import { embedPreviews } from '../../constants/embeds';
|
||||
import { useEmbedStateCurry } from '../../stores/embedState/utilities';
|
||||
import { Box } from "@radix-ui/themes";
|
||||
import { useEffect, useRef } from "react";
|
||||
import { embedPreviews } from "../../constants/embeds";
|
||||
import { useEmbedStateCurry } from "../../stores/embedState/utilities";
|
||||
|
||||
interface PreviewWrapperProps {
|
||||
name: keyof typeof embedPreviews;
|
||||
@@ -10,17 +10,20 @@ interface PreviewWrapperProps {
|
||||
|
||||
export function PreviewWrapper({ name, naked }: PreviewWrapperProps) {
|
||||
const { useEmbedState } = useEmbedStateCurry();
|
||||
const width = useEmbedState('width');
|
||||
const height = useEmbedState('height');
|
||||
|
||||
const width = useEmbedState("width");
|
||||
const height = useEmbedState("height");
|
||||
|
||||
const Preview = embedPreviews[name];
|
||||
|
||||
const wrapper = useRef<HTMLDivElement>(null);
|
||||
|
||||
useEffect(() => {
|
||||
if (!wrapper.current) return;
|
||||
|
||||
wrapper.current.classList.remove('preview-container-animated');
|
||||
wrapper.current.classList.remove("preview-container-animated");
|
||||
void wrapper.current.offsetWidth;
|
||||
wrapper.current.classList.add('preview-container-animated');
|
||||
wrapper.current.classList.add("preview-container-animated");
|
||||
}, [width, height]);
|
||||
|
||||
if (naked) {
|
||||
@@ -29,7 +32,7 @@ export function PreviewWrapper({ name, naked }: PreviewWrapperProps) {
|
||||
position="absolute"
|
||||
top="0"
|
||||
left="50%"
|
||||
style={{ transform: 'translate(-50%, 0) scale(0.75)' }}
|
||||
style={{ transform: "translate(-50%, 0) scale(0.75)" }}
|
||||
width={`${width}px`}
|
||||
height={`${height}px`}
|
||||
>
|
||||
@@ -44,7 +47,7 @@ export function PreviewWrapper({ name, naked }: PreviewWrapperProps) {
|
||||
top="50%"
|
||||
left="50%"
|
||||
overflow="hidden"
|
||||
style={{ transform: naked ? 'scale(0.25)' : 'translate(-50%, -50%)' }}
|
||||
style={{ transform: naked ? "scale(0.25)" : "translate(-50%, -50%)" }}
|
||||
ref={wrapper}
|
||||
className="preview-container-animated"
|
||||
width={`${width}px`}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { Slider } from "@radix-ui/themes";
|
||||
import type { EmbedPreviewControllerProps } from "../../pages/[...locale]/embed/[embed]/_index";
|
||||
import type { EmbedPreviewControllerProps } from "../../pages/[...chunk_default]/[...locale]/embed/[embed]/_index";
|
||||
import { EmbedState, type RadixRadius } from "../../stores/embedState";
|
||||
|
||||
export function Radius({ configKey }: EmbedPreviewControllerProps) {
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { FontBoldIcon, FontSizeIcon } from "@radix-ui/react-icons";
|
||||
import { Flex, Slider, Text } from "@radix-ui/themes";
|
||||
import type { EmbedPreviewControllerProps } from "../../pages/[...locale]/embed/[embed]/_index";
|
||||
import type { EmbedPreviewControllerProps } from "../../pages/[...chunk_default]/[...locale]/embed/[embed]/_index";
|
||||
import { EmbedState, type RadixSizeWithout0 } from "../../stores/embedState";
|
||||
import {
|
||||
radixTextWeights,
|
||||
@@ -12,7 +12,9 @@ import { ColorControllerRaw } from "./ColorControllerRaw";
|
||||
export function RichText({ configKey }: EmbedPreviewControllerProps) {
|
||||
const state = EmbedState.use(
|
||||
(state) =>
|
||||
state[configKey] as EmbedConfigItemType<EmbedItemType.RichText>["default"]
|
||||
state[
|
||||
configKey
|
||||
] as EmbedConfigItemType<EmbedItemType.RichText>["default"],
|
||||
);
|
||||
|
||||
return (
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { Slider } from "@radix-ui/themes";
|
||||
import type { EmbedPreviewControllerProps } from "../../pages/[...locale]/embed/[embed]/_index";
|
||||
import type { EmbedPreviewControllerProps } from "../../pages/[...chunk_default]/[...locale]/embed/[embed]/_index";
|
||||
import { EmbedState, type RadixSize } from "../../stores/embedState";
|
||||
|
||||
export function Size({ configKey }: EmbedPreviewControllerProps) {
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { Slider } from "@radix-ui/themes";
|
||||
import type { EmbedPreviewControllerProps } from "../../pages/[...locale]/embed/[embed]/_index";
|
||||
import type { EmbedPreviewControllerProps } from "../../pages/[...chunk_default]/[...locale]/embed/[embed]/_index";
|
||||
import { EmbedState, type RadixSizeWithout0 } from "../../stores/embedState";
|
||||
|
||||
export function SizeWithout0({ configKey }: EmbedPreviewControllerProps) {
|
||||
@@ -10,7 +10,7 @@ export function SizeWithout0({ configKey }: EmbedPreviewControllerProps) {
|
||||
max={9}
|
||||
value={[
|
||||
EmbedState.use((state) =>
|
||||
parseInt(state[configKey] as RadixSizeWithout0)
|
||||
parseInt(state[configKey] as RadixSizeWithout0),
|
||||
),
|
||||
]}
|
||||
onValueChange={([value]) => {
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { Slider as RadixSlider } from "@radix-ui/themes";
|
||||
import type { EmbedPreviewControllerProps } from "../../pages/[...locale]/embed/[embed]/_index";
|
||||
import type { EmbedPreviewControllerProps } from "../../pages/[...chunk_default]/[...locale]/embed/[embed]/_index";
|
||||
import { EmbedState, type RadixSize } from "../../stores/embedState";
|
||||
import type {
|
||||
EmbedConfigItemType,
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { TextField } from "@radix-ui/themes";
|
||||
import type { EmbedPreviewControllerProps } from "../../pages/[...locale]/embed/[embed]/_index";
|
||||
import type { EmbedPreviewControllerProps } from "../../pages/[...chunk_default]/[...locale]/embed/[embed]/_index";
|
||||
import { EmbedState } from "../../stores/embedState";
|
||||
|
||||
export function TextController({ configKey }: EmbedPreviewControllerProps) {
|
||||
|
||||
@@ -14,7 +14,7 @@ import { ContextMenu } from "@radix-ui/themes";
|
||||
import { useEffect, useMemo, useState } from "react";
|
||||
import { breakdownConfig } from "../../constants/embeds";
|
||||
import { awaitableAverageDefinitions } from "../../core/awaitables/averageDefinitions";
|
||||
import { awaitableTankDefinitions } from "../../core/awaitables/tankDefinitions";
|
||||
import { api } from "../../core/blitzkit/api";
|
||||
import { EmbedBreakdown } from "../../stores/embedBreakdown";
|
||||
import { useEmbedStateCurry } from "../../stores/embedState/utilities";
|
||||
import { BreakdownEmbedCard, BreakdownEmbedWrapper } from "../TanksEmbed";
|
||||
@@ -30,7 +30,8 @@ export const compositeStatsKeysOptions = compositeStatsKeys.map((value) => ({
|
||||
}));
|
||||
|
||||
const [tankDefinitions, averageDefinitions] = await Promise.all([
|
||||
awaitableTankDefinitions,
|
||||
api.tankDefinitions(),
|
||||
|
||||
awaitableAverageDefinitions,
|
||||
]);
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { asset, Avatar } from "@blitzkit/core";
|
||||
import { Avatar } from "@blitzkit/core";
|
||||
import { Cross1Icon, DownloadIcon } from "@radix-ui/react-icons";
|
||||
import {
|
||||
Dialog,
|
||||
@@ -18,9 +18,7 @@ type GalleryCardProps = MaybeSkeletonComponentProps<{
|
||||
}>;
|
||||
|
||||
export function GalleryCard(props: GalleryCardProps) {
|
||||
const src = asset(
|
||||
`gallery/avatars/${!props.skeleton && `${props.avatar.id}${props.avatar.extension}`}`,
|
||||
);
|
||||
const src = `/api/gallery/avatars/${!props.skeleton && `${props.avatar.id}${props.avatar.extension}`}`;
|
||||
const card = useRef<HTMLDivElement>(null!);
|
||||
const { unwrap } = useLocale();
|
||||
|
||||
|
||||
@@ -4,7 +4,7 @@ import { Flex, Text } from "@radix-ui/themes";
|
||||
import fuzzysort from "fuzzysort";
|
||||
import { times } from "lodash-es";
|
||||
import { useMemo, useState } from "react";
|
||||
import { awaitableGallery } from "../../core/awaitables/gallery";
|
||||
import { api } from "../../core/blitzkit/api";
|
||||
import { useLocale } from "../../hooks/useLocale";
|
||||
import { Gallery } from "../../stores/gallery";
|
||||
import type { MaybeSkeletonComponentProps } from "../../types/maybeSkeletonComponentProps";
|
||||
@@ -16,7 +16,7 @@ export interface Avatar {
|
||||
id: string;
|
||||
}
|
||||
|
||||
const gallery = await awaitableGallery;
|
||||
const gallery = await api.galleryDefinitions();
|
||||
|
||||
const DEFAULT_LOADED = 42;
|
||||
const PREVIEW_COUNT = 28;
|
||||
@@ -35,7 +35,7 @@ export function GalleryList({ skeleton }: MaybeSkeletonComponentProps) {
|
||||
.go(search, gallery.avatars, {
|
||||
keys: [
|
||||
...locales.supported.map(
|
||||
(supported) => `name.locales.${supported.locale}`
|
||||
(supported) => `name.locales.${supported.locale}`,
|
||||
),
|
||||
"id",
|
||||
],
|
||||
@@ -72,7 +72,7 @@ export function GalleryList({ skeleton }: MaybeSkeletonComponentProps) {
|
||||
skeleton
|
||||
onIntersection={() => setLoadedCards((state) => state + 2)}
|
||||
/>
|
||||
)
|
||||
),
|
||||
)}
|
||||
</Flex>
|
||||
</>
|
||||
|
||||
@@ -2,7 +2,7 @@ import { literals } from "@blitzkit/i18n/src/literals";
|
||||
import { EyeOpenIcon } from "@radix-ui/react-icons";
|
||||
import { Box, Flex, Heading, Text } from "@radix-ui/themes";
|
||||
import { awaitablePopularTanks } from "../core/awaitables/popularTanks";
|
||||
import { awaitableTankDefinitions } from "../core/awaitables/tankDefinitions";
|
||||
import { api } from "../core/blitzkit/api";
|
||||
import {
|
||||
LocaleProvider,
|
||||
useLocale,
|
||||
@@ -11,7 +11,7 @@ import {
|
||||
import { TankCard } from "./TankCard";
|
||||
|
||||
const [tankDefinitions, popularTanks] = await Promise.all([
|
||||
awaitableTankDefinitions,
|
||||
api.tankDefinitions(),
|
||||
awaitablePopularTanks,
|
||||
]);
|
||||
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
import { asset } from '@blitzkit/core';
|
||||
import { GenericTankComponentButton } from './GenericTankComponentButton';
|
||||
import type { TankComponentButtonProps } from './TankComponentButton';
|
||||
import { GenericTankComponentButton } from "./GenericTankComponentButton";
|
||||
import type { TankComponentButtonProps } from "./TankComponentButton";
|
||||
|
||||
interface ShellButtonProps extends TankComponentButtonProps {
|
||||
shell: string;
|
||||
@@ -9,7 +8,7 @@ interface ShellButtonProps extends TankComponentButtonProps {
|
||||
export function ShellButton({ shell, ...props }: ShellButtonProps) {
|
||||
return (
|
||||
<GenericTankComponentButton
|
||||
icon={asset(`icons/shells/${shell}.webp`)}
|
||||
icon={`/api/icons/shells/${shell}.webp`}
|
||||
{...props}
|
||||
/>
|
||||
);
|
||||
|
||||
+1
-2
@@ -1,4 +1,3 @@
|
||||
import { asset } from "@blitzkit/core";
|
||||
import { Flex, type FlexProps, Progress } from "@radix-ui/themes";
|
||||
import { useProgress } from "@react-three/drei";
|
||||
|
||||
@@ -12,7 +11,7 @@ export function TankSandboxLoader({ id, ...props }: TankSandboxLoaderProps) {
|
||||
return (
|
||||
<Flex width="100%" height="100%" align="center" justify="center" {...props}>
|
||||
<img
|
||||
src={asset(`icons/tanks/big/${id}.webp`)}
|
||||
src={`/api/tanks/${id}/icons/big.webp`}
|
||||
style={{ height: "75%", filter: "blur(1rem)" }}
|
||||
/>
|
||||
<Progress
|
||||
|
||||
@@ -1,16 +1,16 @@
|
||||
import { Flex, Table } from '@radix-ui/themes';
|
||||
import { useEffect, useRef } from 'react';
|
||||
import { awaitableTankDefinitions } from '../../../core/awaitables/tankDefinitions';
|
||||
import { TierList } from '../../../stores/tierList';
|
||||
import { tierListRowElements } from '../Table/constants';
|
||||
import { TierListTile } from '../Tile';
|
||||
import { Header } from './components/Header';
|
||||
import { Flex, Table } from "@radix-ui/themes";
|
||||
import { useEffect, useRef } from "react";
|
||||
import { api } from "../../../core/blitzkit/api";
|
||||
import { TierList } from "../../../stores/tierList";
|
||||
import { tierListRowElements } from "../Table/constants";
|
||||
import { TierListTile } from "../Tile";
|
||||
import { Header } from "./components/Header";
|
||||
|
||||
interface TierListRowProps {
|
||||
index: number;
|
||||
}
|
||||
|
||||
const tankDefinitions = await awaitableTankDefinitions;
|
||||
const tankDefinitions = await api.tankDefinitions();
|
||||
|
||||
export function TierListRow({ index }: TierListRowProps) {
|
||||
const tanks = TierList.use((state) => state.rows[index].tanks);
|
||||
|
||||
@@ -2,8 +2,7 @@ import { metaSortTank } from "@blitzkit/core";
|
||||
import { times } from "lodash-es";
|
||||
import { useMemo, useState } from "react";
|
||||
import usePromise from "react-promise-suspense";
|
||||
import { awaitableGameDefinitions } from "../../core/awaitables/gameDefinitions";
|
||||
import { awaitableTankDefinitions } from "../../core/awaitables/tankDefinitions";
|
||||
import { api } from "../../core/blitzkit/api";
|
||||
import { filterTanks } from "../../core/blitzkit/filterTanks";
|
||||
import { TankFilters } from "../../stores/tankFilters";
|
||||
import { TierList } from "../../stores/tierList";
|
||||
@@ -12,8 +11,8 @@ import { TankCardWrapper } from "../TankSearch/components/TankCardWrapper";
|
||||
import { TierListTile } from "./Tile";
|
||||
|
||||
const [tankDefinitions, gameDefinitions] = await Promise.all([
|
||||
awaitableTankDefinitions,
|
||||
awaitableGameDefinitions,
|
||||
api.tankDefinitions(),
|
||||
api.gameDefinitions(),
|
||||
]);
|
||||
|
||||
const tanks = Object.values(tankDefinitions.tanks);
|
||||
@@ -27,14 +26,14 @@ export function TierListTiles() {
|
||||
const filteredTanks = usePromise(
|
||||
() =>
|
||||
filterTanks(filters, tanks).then((tanks) =>
|
||||
tanks.filter(({ id }) => !placedTanks.has(id))
|
||||
tanks.filter(({ id }) => !placedTanks.has(id)),
|
||||
),
|
||||
// react-promise-suspense has awful type annotations
|
||||
[filters, placedTanks] as any
|
||||
[filters, placedTanks] as any,
|
||||
);
|
||||
const sorted = useMemo(
|
||||
() => metaSortTank(filteredTanks, gameDefinitions).reverse(),
|
||||
[filters, placedTanks]
|
||||
[filters, placedTanks],
|
||||
);
|
||||
const [loadedTiles, setLoadedTiles] = useState(DEFAULT_LOADED_CARDS);
|
||||
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
import { useEffect } from 'react';
|
||||
import { awaitableTankDefinitions } from '../../core/awaitables/tankDefinitions';
|
||||
import { generateTierListParams } from '../../core/blitzkit/generateTierListParams';
|
||||
import { TierList } from '../../stores/tierList';
|
||||
import { useEffect } from "react";
|
||||
import { api } from "../../core/blitzkit/api";
|
||||
import { generateTierListParams } from "../../core/blitzkit/generateTierListParams";
|
||||
import { TierList } from "../../stores/tierList";
|
||||
|
||||
const tankDefinitions = await awaitableTankDefinitions;
|
||||
const tankDefinitions = await api.tankDefinitions();
|
||||
|
||||
export function URLManager() {
|
||||
const rows = TierList.use((state) => state.rows);
|
||||
@@ -12,10 +12,10 @@ export function URLManager() {
|
||||
const params = new URLSearchParams(window.location.search);
|
||||
|
||||
params.forEach((value, key) => {
|
||||
if (key.startsWith('row-')) {
|
||||
if (key.startsWith("row-")) {
|
||||
const index = Number.parseInt(key.slice(4), 10);
|
||||
const values = value
|
||||
.split(',')
|
||||
.split(",")
|
||||
.map(Number)
|
||||
.filter((id) => id in tankDefinitions.tanks);
|
||||
|
||||
@@ -27,7 +27,7 @@ export function URLManager() {
|
||||
}, []);
|
||||
|
||||
useEffect(() => {
|
||||
window.history.replaceState(null, '', `?${generateTierListParams(rows)}`);
|
||||
window.history.replaceState(null, "", `?${generateTierListParams(rows)}`);
|
||||
}, [rows]);
|
||||
|
||||
return null;
|
||||
|
||||
@@ -1,16 +1,16 @@
|
||||
import { type CompositeStatsKey } from '@blitzkit/core';
|
||||
import { grayA, grayDark, grayDarkA } from '@radix-ui/colors';
|
||||
import type { ReactNode } from 'react';
|
||||
import { type CompositeStatsKey } from "@blitzkit/core";
|
||||
import { grayA, grayDark, grayDarkA } from "@radix-ui/colors";
|
||||
import type { ReactNode } from "react";
|
||||
import {
|
||||
BreakdownPreview,
|
||||
BreakdownRenderer,
|
||||
compositeStatsKeysOptions,
|
||||
} from '../components/Embeds/breakdown';
|
||||
} from "../components/Embeds/breakdown";
|
||||
import type {
|
||||
EmbedConfig,
|
||||
ExtractEmbedConfigTypes,
|
||||
} from '../stores/embedState';
|
||||
import { EmbedItemType } from '../stores/embedState/constants';
|
||||
} from "../stores/embedState";
|
||||
import { EmbedItemType } from "../stores/embedState/constants";
|
||||
|
||||
export const breakdownConfig = {
|
||||
width: { type: EmbedItemType.Slider, default: 320, min: 128, max: 640 },
|
||||
@@ -18,7 +18,7 @@ export const breakdownConfig = {
|
||||
|
||||
showTotal: { type: EmbedItemType.Boolean, default: true, pad: true },
|
||||
|
||||
listGap: { type: EmbedItemType.Size, default: '2' },
|
||||
listGap: { type: EmbedItemType.Size, default: "2" },
|
||||
listMaxTanks: {
|
||||
type: EmbedItemType.Slider,
|
||||
default: 4,
|
||||
@@ -27,15 +27,15 @@ export const breakdownConfig = {
|
||||
pad: true,
|
||||
},
|
||||
|
||||
cardRadius: { type: EmbedItemType.Radius, default: '2' },
|
||||
cardRadius: { type: EmbedItemType.Radius, default: "2" },
|
||||
cardHeaderBackgroundColor: {
|
||||
type: EmbedItemType.Color,
|
||||
default: grayDarkA.grayA3,
|
||||
},
|
||||
cardHeaderPadding: { type: EmbedItemType.Size, default: '1' },
|
||||
cardHeaderPadding: { type: EmbedItemType.Size, default: "1" },
|
||||
cardTitle: {
|
||||
type: EmbedItemType.RichText,
|
||||
default: { color: grayDark.gray12, weight: 'bold', size: '3' },
|
||||
default: { color: grayDark.gray12, weight: "bold", size: "3" },
|
||||
},
|
||||
cardTitleTypeColor: { type: EmbedItemType.Boolean, default: true },
|
||||
cardTitleClassIcon: { type: EmbedItemType.Boolean, default: true },
|
||||
@@ -45,45 +45,45 @@ export const breakdownConfig = {
|
||||
},
|
||||
cardBodyPadding: {
|
||||
type: EmbedItemType.Size,
|
||||
default: '2',
|
||||
default: "2",
|
||||
pad: true,
|
||||
},
|
||||
|
||||
columnGap: { type: EmbedItemType.Size, default: '0' },
|
||||
columnGap: { type: EmbedItemType.Size, default: "0" },
|
||||
columnValue: {
|
||||
type: EmbedItemType.RichText,
|
||||
default: { color: grayDark.gray12, size: '3', weight: 'regular' },
|
||||
default: { color: grayDark.gray12, size: "3", weight: "regular" },
|
||||
},
|
||||
columnLabel: {
|
||||
type: EmbedItemType.RichText,
|
||||
default: { color: grayDark.gray11, size: '2', weight: 'regular' },
|
||||
default: { color: grayDark.gray11, size: "2", weight: "regular" },
|
||||
pad: true,
|
||||
},
|
||||
|
||||
column1: {
|
||||
type: EmbedItemType.Enum,
|
||||
default: 'cumulative_battles' satisfies CompositeStatsKey,
|
||||
default: "cumulative_battles" satisfies CompositeStatsKey,
|
||||
options: compositeStatsKeysOptions,
|
||||
},
|
||||
column2: {
|
||||
type: EmbedItemType.Enum,
|
||||
default: 'normalized_wins' satisfies CompositeStatsKey,
|
||||
default: "normalized_wins" satisfies CompositeStatsKey,
|
||||
options: compositeStatsKeysOptions,
|
||||
},
|
||||
column3: {
|
||||
type: EmbedItemType.Enum,
|
||||
default: 'cumulative_wn8' satisfies CompositeStatsKey,
|
||||
default: "cumulative_wn8" satisfies CompositeStatsKey,
|
||||
options: compositeStatsKeysOptions,
|
||||
},
|
||||
column4: {
|
||||
type: EmbedItemType.Enum,
|
||||
default: 'normalized_damage_dealt' satisfies CompositeStatsKey,
|
||||
default: "normalized_damage_dealt" satisfies CompositeStatsKey,
|
||||
options: compositeStatsKeysOptions,
|
||||
},
|
||||
column1CustomLabel: { type: EmbedItemType.String, default: '' },
|
||||
column2CustomLabel: { type: EmbedItemType.String, default: '' },
|
||||
column3CustomLabel: { type: EmbedItemType.String, default: '' },
|
||||
column4CustomLabel: { type: EmbedItemType.String, default: '' },
|
||||
column1CustomLabel: { type: EmbedItemType.String, default: "" },
|
||||
column2CustomLabel: { type: EmbedItemType.String, default: "" },
|
||||
column3CustomLabel: { type: EmbedItemType.String, default: "" },
|
||||
column4CustomLabel: { type: EmbedItemType.String, default: "" },
|
||||
} satisfies EmbedConfig;
|
||||
|
||||
export const embedConfigurations = {
|
||||
@@ -93,6 +93,7 @@ export const embedConfigurations = {
|
||||
export const embedPreviews = {
|
||||
breakdown: BreakdownPreview,
|
||||
} satisfies Record<string, () => ReactNode>;
|
||||
|
||||
export function extractEmbedConfigDefaults<Config extends EmbedConfig>(
|
||||
config: Config,
|
||||
) {
|
||||
|
||||
@@ -1,3 +0,0 @@
|
||||
import { fetchGallery } from "@blitzkit/core";
|
||||
|
||||
export const awaitableGallery = fetchGallery();
|
||||
@@ -1,5 +1,4 @@
|
||||
export function isHalloween() {
|
||||
const data = new Date();
|
||||
return false;
|
||||
return data.getMonth() === 9 && data.getDate() === 31;
|
||||
}
|
||||
@@ -1,5 +1,4 @@
|
||||
import { assertSecret } from "@blitzkit/core";
|
||||
import { LocalVFS } from "@blitzkit/core/src/blitzkit/vfs/local";
|
||||
|
||||
export const vfs = new LocalVFS(
|
||||
"/run/media/tresabhi/Windows/Program Files/WindowsApps/7458BE2C.WorldofTanksBlitz_11.19.272.0_x64__x4tje2y229k00",
|
||||
);
|
||||
export const vfs = new LocalVFS(assertSecret(import.meta.env.GAME_DIR));
|
||||
@@ -1,15 +1,15 @@
|
||||
import { TankDefinition } from '@blitzkit/core';
|
||||
import { sumBy } from 'lodash-es';
|
||||
import { useMemo } from 'react';
|
||||
import { awaitableTankDefinitions } from '../core/awaitables/tankDefinitions';
|
||||
import { Duel } from '../stores/duel';
|
||||
import { TankDefinition } from "@blitzkit/core";
|
||||
import { sumBy } from "lodash-es";
|
||||
import { useMemo } from "react";
|
||||
import { api } from "../core/blitzkit/api";
|
||||
import { Duel } from "../stores/duel";
|
||||
|
||||
export enum UseEccentricityMode {
|
||||
Tier,
|
||||
Class,
|
||||
}
|
||||
|
||||
const tankDefinitions = await awaitableTankDefinitions;
|
||||
const tankDefinitions = await api.tankDefinitions();
|
||||
|
||||
export function useEccentricity(mode: UseEccentricityMode) {
|
||||
const tank = Duel.use((state) => state.protagonist.tank);
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { awaitableEquipmentDefinitions } from "../core/awaitables/equipmentDefinitions";
|
||||
import { api } from "../core/blitzkit/api";
|
||||
|
||||
const equipmentDefinitions = await awaitableEquipmentDefinitions;
|
||||
const equipmentDefinitions = await api.equipmentDefinitions();
|
||||
|
||||
export function useEquipmentPreset(preset: string) {
|
||||
return equipmentDefinitions.presets[preset];
|
||||
|
||||
@@ -0,0 +1,11 @@
|
||||
import { Gallery } from "@blitzkit/core";
|
||||
import { api } from "../../../core/blitzkit/api";
|
||||
|
||||
export { getStaticPaths } from "../_index";
|
||||
|
||||
export async function GET() {
|
||||
const definitions = await api.galleryDefinitions();
|
||||
const bytes = Gallery.encode(definitions).finish();
|
||||
|
||||
return new Response(bytes);
|
||||
}
|
||||
+21
-31
@@ -1,13 +1,13 @@
|
||||
import { Avatar, fetchGlossary, Gallery } from "@blitzkit/core";
|
||||
import { fetchGlossary, type Avatar } from "@blitzkit/core";
|
||||
import locales from "@blitzkit/i18n/locales.json";
|
||||
import type { APIContext, GetStaticPathsItem } from "astro";
|
||||
import { extname } from "path";
|
||||
import ProgressBar from "progress";
|
||||
import { AssetUploader } from "../core/github/assetUploader";
|
||||
import { mixStaticPaths } from "../../../../core/blitzkit/mixStaticPaths";
|
||||
import { getStaticPaths as _getStaticPaths } from "../../_index";
|
||||
|
||||
export async function glossary() {
|
||||
console.log("Building glossary...");
|
||||
export const getStaticPaths = mixStaticPaths(_getStaticPaths, async () => {
|
||||
const paths: GetStaticPathsItem[] = [];
|
||||
|
||||
using uploader = new AssetUploader("glossary");
|
||||
const avatars: Record<string, { avatar: Avatar; url: string }> = {};
|
||||
|
||||
await Promise.all(
|
||||
@@ -48,42 +48,32 @@ export async function glossary() {
|
||||
}),
|
||||
);
|
||||
|
||||
const gallery: Gallery = { avatars: [] };
|
||||
const totalCount = Object.keys(avatars).length;
|
||||
|
||||
const bar = new ProgressBar(
|
||||
`Fetching avatars of ${totalCount} things :bar`,
|
||||
totalCount,
|
||||
);
|
||||
|
||||
await Promise.all(
|
||||
Object.entries(avatars).map(async ([key, { url, avatar }]) => {
|
||||
if (!(locales.default in avatars[key].avatar.name!.locales)) {
|
||||
console.warn(`Avatar ${key} has no ${locales.default} name`);
|
||||
bar.tick();
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
gallery.avatars.push(avatar);
|
||||
const name = `${key}${avatar.extension}`;
|
||||
|
||||
const content = await fetch(url)
|
||||
.then((response) => response.arrayBuffer())
|
||||
.then((buffer) => new Uint8Array(buffer));
|
||||
|
||||
await uploader.add({
|
||||
path: `gallery/avatars/${key}${avatar.extension}`,
|
||||
content,
|
||||
paths.push({
|
||||
params: { name },
|
||||
props: { url },
|
||||
});
|
||||
|
||||
bar.tick();
|
||||
}),
|
||||
);
|
||||
|
||||
await uploader.add({
|
||||
path: "definitions/gallery.pb",
|
||||
content: Gallery.encode(gallery).finish(),
|
||||
});
|
||||
return paths;
|
||||
});
|
||||
|
||||
await uploader.flush();
|
||||
export async function GET({ props }: APIContext<{ url: string }>) {
|
||||
if (import.meta.env.DEV) {
|
||||
return Response.redirect(props.url);
|
||||
}
|
||||
|
||||
const response = await fetch(props.url);
|
||||
const buffer = await response.arrayBuffer();
|
||||
|
||||
return new Response(buffer);
|
||||
}
|
||||
@@ -105,7 +105,7 @@ async function extractModel(vfs: AbstractVFS, path: string) {
|
||||
}
|
||||
|
||||
if (textures) {
|
||||
const { image: baseColor, hasAlpha } = await readBaseColor(
|
||||
const baseColor = await readBaseColor(
|
||||
`Data/3d/${dirname(path)}/${textures.baseColorMap ?? textures.albedo}`,
|
||||
textures.miscMap
|
||||
? `Data/3d/${dirname(path)}/${textures.miscMap}`
|
||||
@@ -369,7 +369,6 @@ async function extractModel(vfs: AbstractVFS, path: string) {
|
||||
}
|
||||
|
||||
async function readBaseColor(path: string, occlusionPath?: string) {
|
||||
let hasAlpha = false;
|
||||
const baseRaw = await readTexture(path);
|
||||
const occlusionRaw = occlusionPath
|
||||
? await readTexture(occlusionPath)
|
||||
@@ -399,7 +398,6 @@ async function readBaseColor(path: string, occlusionPath?: string) {
|
||||
}
|
||||
|
||||
const alpha = base[i * 4 + 3];
|
||||
hasAlpha ||= alpha < 255;
|
||||
|
||||
combined[i * 4 + 0] = Math.round(base[i * 4 + 0] * c);
|
||||
combined[i * 4 + 1] = Math.round(base[i * 4 + 1] * c);
|
||||
@@ -413,7 +411,7 @@ async function readBaseColor(path: string, occlusionPath?: string) {
|
||||
.webp()
|
||||
.toBuffer();
|
||||
|
||||
return { hasAlpha, image };
|
||||
return image;
|
||||
}
|
||||
|
||||
async function readRoughnessMetallic(path: string) {
|
||||
|
||||
+1
-1
@@ -1,5 +1,5 @@
|
||||
import { useEffect } from "react";
|
||||
import { App } from "../../../../stores/app";
|
||||
import { App } from "../../../../../stores/app";
|
||||
|
||||
export const AUTH_PROVIDERS = ["wargaming"] as const;
|
||||
|
||||
|
||||
+3
-3
@@ -1,8 +1,8 @@
|
||||
---
|
||||
import { Flex, Heading, Text } from "@radix-ui/themes";
|
||||
import type { GetStaticPaths } from "astro";
|
||||
import { PageWrapper } from "../../../../components/PageWrapper";
|
||||
import BaseLayout from "../../../../layouts/BaseLayout.astro";
|
||||
import { PageWrapper } from "../../../../../components/PageWrapper";
|
||||
import BaseLayout from "../../../../../layouts/BaseLayout.astro";
|
||||
import { getStaticPaths as parentGetStaticPaths } from "../../index.astro";
|
||||
import { AUTH_PROVIDER_NAMES, AUTH_PROVIDERS, Authorize } from "./_index";
|
||||
|
||||
@@ -10,7 +10,7 @@ export const getStaticPaths = (() => {
|
||||
const parentPaths = parentGetStaticPaths();
|
||||
|
||||
return AUTH_PROVIDERS.map((provider) =>
|
||||
parentPaths.map((parent) => ({ params: { ...parent.params, provider } }))
|
||||
parentPaths.map((parent) => ({ params: { ...parent.params, provider } })),
|
||||
).flat();
|
||||
}) satisfies GetStaticPaths;
|
||||
|
||||
|
||||
+2
-2
@@ -1,5 +1,5 @@
|
||||
import { Markdown } from "../../../../../components/Markdown";
|
||||
import { PageWrapper } from "../../../../../components/PageWrapper";
|
||||
import { Markdown } from "../../../../../../components/Markdown";
|
||||
import { PageWrapper } from "../../../../../../components/PageWrapper";
|
||||
|
||||
interface PageProps {
|
||||
content: string;
|
||||
|
||||
+5
-5
@@ -2,14 +2,14 @@
|
||||
import { AstroSeo } from "@astrolib/seo";
|
||||
import type { GetStaticPaths } from "astro";
|
||||
import { readFile } from "fs/promises";
|
||||
import BaseLayout from "../../../../../layouts/BaseLayout.astro";
|
||||
import BaseLayout from "../../../../../../layouts/BaseLayout.astro";
|
||||
import { getStaticPaths as parentGetStaticPaths } from "../../../index.astro";
|
||||
import { Page } from "./_index";
|
||||
|
||||
export const getStaticPaths = (async () => {
|
||||
const parentPaths = parentGetStaticPaths();
|
||||
const ROOT = "../../../../../../../../docs/";
|
||||
const files = import.meta.glob("../../../../../../../../docs/**/*.md", {
|
||||
const ROOT = "../../../../../../../../../docs/";
|
||||
const files = import.meta.glob("../../../../../../../../../docs/**/*.md", {
|
||||
eager: true,
|
||||
});
|
||||
|
||||
@@ -19,7 +19,7 @@ export const getStaticPaths = (async () => {
|
||||
const couple = file.replace(ROOT, "").split("/");
|
||||
couple[1] = couple[1].replace(".md", "");
|
||||
const content = await readFile(
|
||||
`../../docs/${couple[0]}/${couple[1]}.md`
|
||||
`../../docs/${couple[0]}/${couple[1]}.md`,
|
||||
).then((buffer) => buffer.toString());
|
||||
|
||||
return parentPaths.map((parent) => ({
|
||||
@@ -30,7 +30,7 @@ export const getStaticPaths = (async () => {
|
||||
},
|
||||
props: { ...parent.props, content },
|
||||
}));
|
||||
})
|
||||
}),
|
||||
)
|
||||
).flat();
|
||||
}) satisfies GetStaticPaths;
|
||||
|
||||
@@ -3,21 +3,21 @@ import { AstroSeo } from "@astrolib/seo";
|
||||
import { MagicWandIcon, StarFilledIcon } from "@radix-ui/react-icons";
|
||||
import { Flex, Heading, Link } from "@radix-ui/themes";
|
||||
import { compareVersions } from "compare-versions";
|
||||
import { PageWrapper } from "../../../../components/PageWrapper";
|
||||
import { getStrings } from "../../../../core/i18n/getStrings";
|
||||
import BaseLayout from "../../../../layouts/BaseLayout.astro";
|
||||
import { PageWrapper } from "../../../../../components/PageWrapper";
|
||||
import { getStrings } from "../../../../../core/i18n/getStrings";
|
||||
import BaseLayout from "../../../../../layouts/BaseLayout.astro";
|
||||
|
||||
export { getStaticPaths } from "../../index.astro";
|
||||
|
||||
// this can't be used in template literal :(
|
||||
const ROOT = "../../../../../../../docs/changelogs/";
|
||||
const ROOT = "../../../../../../../../docs/changelogs/";
|
||||
|
||||
const { locale } = Astro.props;
|
||||
const strings = getStrings(locale);
|
||||
const versions = Object.keys(
|
||||
import.meta.glob("../../../../../../../docs/changelogs/*.md", {
|
||||
import.meta.glob("../../../../../../../../docs/changelogs/*.md", {
|
||||
eager: true,
|
||||
})
|
||||
}),
|
||||
)
|
||||
.map((file) => file.replace(ROOT, "").replace(".md", ""))
|
||||
.sort(compareVersions)
|
||||
|
||||
+20
-20
@@ -8,32 +8,32 @@ import {
|
||||
} from "@radix-ui/react-icons";
|
||||
import { Box, Button, Flex, Heading, ScrollArea, Text } from "@radix-ui/themes";
|
||||
import { useEffect, useRef, useState, type ReactNode } from "react";
|
||||
import { CopyButton } from "../../../../components/CopyButton";
|
||||
import { Boolean } from "../../../../components/Embeds/Boolean";
|
||||
import { Color } from "../../../../components/Embeds/Color";
|
||||
import { Enum } from "../../../../components/Embeds/Enum";
|
||||
import { GenerateURL } from "../../../../components/Embeds/GenerateURL";
|
||||
import { Import } from "../../../../components/Embeds/Import";
|
||||
import { PreviewWrapper } from "../../../../components/Embeds/PreviewWrapper";
|
||||
import { Radius } from "../../../../components/Embeds/Radius";
|
||||
import { RichText } from "../../../../components/Embeds/RichText";
|
||||
import { Size } from "../../../../components/Embeds/Size";
|
||||
import { SizeWithout0 } from "../../../../components/Embeds/SizeWithout0";
|
||||
import { Slider } from "../../../../components/Embeds/Slider";
|
||||
import { TextController } from "../../../../components/Embeds/TextController";
|
||||
import { PageWrapper } from "../../../../components/PageWrapper";
|
||||
import { CopyButton } from "../../../../../components/CopyButton";
|
||||
import { Boolean } from "../../../../../components/Embeds/Boolean";
|
||||
import { Color } from "../../../../../components/Embeds/Color";
|
||||
import { Enum } from "../../../../../components/Embeds/Enum";
|
||||
import { GenerateURL } from "../../../../../components/Embeds/GenerateURL";
|
||||
import { Import } from "../../../../../components/Embeds/Import";
|
||||
import { PreviewWrapper } from "../../../../../components/Embeds/PreviewWrapper";
|
||||
import { Radius } from "../../../../../components/Embeds/Radius";
|
||||
import { RichText } from "../../../../../components/Embeds/RichText";
|
||||
import { Size } from "../../../../../components/Embeds/Size";
|
||||
import { SizeWithout0 } from "../../../../../components/Embeds/SizeWithout0";
|
||||
import { Slider } from "../../../../../components/Embeds/Slider";
|
||||
import { TextController } from "../../../../../components/Embeds/TextController";
|
||||
import { PageWrapper } from "../../../../../components/PageWrapper";
|
||||
import {
|
||||
embedConfigurations,
|
||||
extractEmbedConfigDefaults,
|
||||
} from "../../../../constants/embeds";
|
||||
import { NAVBAR_HEIGHT } from "../../../../constants/navbar";
|
||||
} from "../../../../../constants/embeds";
|
||||
import { NAVBAR_HEIGHT } from "../../../../../constants/navbar";
|
||||
import {
|
||||
LocaleProvider,
|
||||
useLocale,
|
||||
type LocaleAcceptorProps,
|
||||
} from "../../../../hooks/useLocale";
|
||||
import { EmbedState, type EmbedConfig } from "../../../../stores/embedState";
|
||||
import { EmbedItemType } from "../../../../stores/embedState/constants";
|
||||
} from "../../../../../hooks/useLocale";
|
||||
import { EmbedState, type EmbedConfig } from "../../../../../stores/embedState";
|
||||
import { EmbedItemType } from "../../../../../stores/embedState/constants";
|
||||
|
||||
export interface EmbedPreviewControllerProps {
|
||||
configKey: string;
|
||||
@@ -58,7 +58,7 @@ export function Page({ embed, locale }: PageProps & LocaleAcceptorProps) {
|
||||
function Content({ embed }: PageProps) {
|
||||
const config = embedConfigurations[embed] as EmbedConfig;
|
||||
const [backgroundImage, setBackgroundImage] = useState(
|
||||
"/assets/images/backgrounds/embed-default.webp"
|
||||
"/assets/images/backgrounds/embed-default.webp",
|
||||
);
|
||||
const fileInput = useRef<HTMLInputElement>(null!);
|
||||
const { strings } = useLocale();
|
||||
|
||||
+5
-5
@@ -1,22 +1,22 @@
|
||||
import { Box } from "@radix-ui/themes";
|
||||
import { useMemo } from "react";
|
||||
import { parse } from "urlon";
|
||||
import { BlitzKitTheme } from "../../../../../components/BlitzKitTheme";
|
||||
import { BlitzKitTheme } from "../../../../../../components/BlitzKitTheme";
|
||||
import {
|
||||
embedConfigurations,
|
||||
embedRenderers,
|
||||
extractEmbedConfigDefaults,
|
||||
} from "../../../../../constants/embeds";
|
||||
} from "../../../../../../constants/embeds";
|
||||
import {
|
||||
LocaleProvider,
|
||||
type LocaleAcceptorProps,
|
||||
} from "../../../../../hooks/useLocale";
|
||||
} from "../../../../../../hooks/useLocale";
|
||||
import {
|
||||
EmbedState,
|
||||
type EmbedConfig,
|
||||
type ExtractEmbedConfigTypes,
|
||||
} from "../../../../../stores/embedState";
|
||||
import { useEmbedStateCurry } from "../../../../../stores/embedState/utilities";
|
||||
} from "../../../../../../stores/embedState";
|
||||
import { useEmbedStateCurry } from "../../../../../../stores/embedState/utilities";
|
||||
|
||||
interface PageProps {
|
||||
embed: keyof typeof embedConfigurations;
|
||||
|
||||
+1
-1
@@ -1,5 +1,5 @@
|
||||
---
|
||||
import EmbedLayout from "../../../../../layouts/EmbedLayout.astro";
|
||||
import EmbedLayout from "../../../../../../layouts/EmbedLayout.astro";
|
||||
import type { getStaticPaths } from "../index.astro";
|
||||
import { Page } from "./_index";
|
||||
|
||||
|
||||
@@ -2,8 +2,8 @@
|
||||
import { AstroSeo } from "@astrolib/seo";
|
||||
import type { GetStaticPaths } from "astro";
|
||||
import { capitalize } from "lodash-es";
|
||||
import { embedConfigurations } from "../../../../constants/embeds";
|
||||
import BaseLayout from "../../../../layouts/BaseLayout.astro";
|
||||
import { embedConfigurations } from "../../../../../constants/embeds";
|
||||
import BaseLayout from "../../../../../layouts/BaseLayout.astro";
|
||||
import { getStaticPaths as parentGetStaticPaths } from "../index.astro";
|
||||
import { Page } from "./_index";
|
||||
|
||||
@@ -17,7 +17,7 @@ export const getStaticPaths = (() => {
|
||||
...parent.params,
|
||||
embed: embed as keyof typeof embedConfigurations,
|
||||
},
|
||||
}))
|
||||
})),
|
||||
)
|
||||
.flat();
|
||||
}) satisfies GetStaticPaths;
|
||||
|
||||
@@ -1,14 +1,14 @@
|
||||
import { Box, Flex, Link, Text } from "@radix-ui/themes";
|
||||
import { PreviewWrapper } from "../../../components/Embeds/PreviewWrapper";
|
||||
import { LinkI18n } from "../../../components/LinkI18n";
|
||||
import { PageWrapper } from "../../../components/PageWrapper";
|
||||
import { embedConfigurations } from "../../../constants/embeds";
|
||||
import { Var } from "../../../core/radix/var";
|
||||
import { PreviewWrapper } from "../../../../components/Embeds/PreviewWrapper";
|
||||
import { LinkI18n } from "../../../../components/LinkI18n";
|
||||
import { PageWrapper } from "../../../../components/PageWrapper";
|
||||
import { embedConfigurations } from "../../../../constants/embeds";
|
||||
import { Var } from "../../../../core/radix/var";
|
||||
import {
|
||||
type LocaleAcceptorProps,
|
||||
LocaleProvider,
|
||||
useLocale,
|
||||
} from "../../../hooks/useLocale";
|
||||
} from "../../../../hooks/useLocale";
|
||||
|
||||
export function Page({ locale }: LocaleAcceptorProps) {
|
||||
return (
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
---
|
||||
import { tools } from "../../../constants/tools";
|
||||
import ToolLayout from "../../../layouts/ToolLayout.astro";
|
||||
import { tools } from "../../../../constants/tools";
|
||||
import ToolLayout from "../../../../layouts/ToolLayout.astro";
|
||||
import { Page } from "./_index";
|
||||
|
||||
export { getStaticPaths } from "../index.astro";
|
||||
|
||||
@@ -33,21 +33,21 @@ import {
|
||||
} from "@radix-ui/themes";
|
||||
import { debounce } from "lodash-es";
|
||||
import { useEffect, useMemo, useRef, useState } from "react";
|
||||
import { PageWrapper } from "../../../components/PageWrapper";
|
||||
import { StickyRowHeaderCell } from "../../../components/StickyRowHeaderCell";
|
||||
import { StickyTableRoot } from "../../../components/StickyTableRoot";
|
||||
import { TankRowHeaderCell } from "../../../components/TankRowHeaderCell";
|
||||
import { awaitableAverageDefinitions } from "../../../core/awaitables/averageDefinitions";
|
||||
import { awaitableTankDefinitions } from "../../../core/awaitables/tankDefinitions";
|
||||
import { PageWrapper } from "../../../../components/PageWrapper";
|
||||
import { StickyRowHeaderCell } from "../../../../components/StickyRowHeaderCell";
|
||||
import { StickyTableRoot } from "../../../../components/StickyTableRoot";
|
||||
import { TankRowHeaderCell } from "../../../../components/TankRowHeaderCell";
|
||||
import { awaitableAverageDefinitions } from "../../../../core/awaitables/averageDefinitions";
|
||||
import { api } from "../../../../core/blitzkit/api";
|
||||
import {
|
||||
type LocaleAcceptorProps,
|
||||
LocaleProvider,
|
||||
useLocale,
|
||||
} from "../../../hooks/useLocale";
|
||||
import { Session, type SessionTracking } from "../../../stores/session";
|
||||
} from "../../../../hooks/useLocale";
|
||||
import { Session, type SessionTracking } from "../../../../stores/session";
|
||||
|
||||
const [tankDefinitions, averageDefinitions] = await Promise.all([
|
||||
awaitableTankDefinitions,
|
||||
api.tankDefinitions(),
|
||||
awaitableAverageDefinitions,
|
||||
]);
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
---
|
||||
import { tools } from "../../../constants/tools";
|
||||
import ToolLayout from "../../../layouts/ToolLayout.astro";
|
||||
import { tools } from "../../../../constants/tools";
|
||||
import ToolLayout from "../../../../layouts/ToolLayout.astro";
|
||||
import type { getStaticPaths } from "../index.astro";
|
||||
import { Page } from "./_index";
|
||||
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
import { Flex, Switch, Text } from "@radix-ui/themes";
|
||||
import { LocaleSwitcher } from "../../../components/LocaleSwitcher";
|
||||
import { PageWrapper } from "../../../components/PageWrapper";
|
||||
import { LocaleSwitcher } from "../../../../components/LocaleSwitcher";
|
||||
import { PageWrapper } from "../../../../components/PageWrapper";
|
||||
import {
|
||||
LocaleProvider,
|
||||
useLocale,
|
||||
type LocaleAcceptorProps,
|
||||
} from "../../../hooks/useLocale";
|
||||
import { App } from "../../../stores/app";
|
||||
} from "../../../../hooks/useLocale";
|
||||
import { App } from "../../../../stores/app";
|
||||
|
||||
export function Page({ locale }: LocaleAcceptorProps) {
|
||||
return (
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
---
|
||||
import { AstroSeo } from "@astrolib/seo";
|
||||
import { getStrings } from "../../../core/i18n/getStrings";
|
||||
import BaseLayout from "../../../layouts/BaseLayout.astro";
|
||||
import { getStrings } from "../../../../core/i18n/getStrings";
|
||||
import BaseLayout from "../../../../layouts/BaseLayout.astro";
|
||||
import { Page } from "./_index";
|
||||
|
||||
export { getStaticPaths } from "../index.astro";
|
||||
|
||||
@@ -1,13 +1,13 @@
|
||||
import { PageWrapper } from "../../../components/PageWrapper";
|
||||
import { FilterControl } from "../../../components/TankSearch/components/FilterControl";
|
||||
import { TierListControls } from "../../../components/TierList/Controls";
|
||||
import { TierListTable } from "../../../components/TierList/Table";
|
||||
import { TierListTiles } from "../../../components/TierList/Tiles";
|
||||
import { URLManager } from "../../../components/TierList/URLManager";
|
||||
import { PageWrapper } from "../../../../components/PageWrapper";
|
||||
import { FilterControl } from "../../../../components/TankSearch/components/FilterControl";
|
||||
import { TierListControls } from "../../../../components/TierList/Controls";
|
||||
import { TierListTable } from "../../../../components/TierList/Table";
|
||||
import { TierListTiles } from "../../../../components/TierList/Tiles";
|
||||
import { URLManager } from "../../../../components/TierList/URLManager";
|
||||
import {
|
||||
LocaleProvider,
|
||||
type LocaleAcceptorProps,
|
||||
} from "../../../hooks/useLocale";
|
||||
} from "../../../../hooks/useLocale";
|
||||
|
||||
export function Page({ locale }: LocaleAcceptorProps) {
|
||||
return (
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
---
|
||||
import { tools } from "../../../constants/tools";
|
||||
import ToolLayout from "../../../layouts/ToolLayout.astro";
|
||||
import { tools } from "../../../../constants/tools";
|
||||
import ToolLayout from "../../../../layouts/ToolLayout.astro";
|
||||
import { Page } from "./_index";
|
||||
|
||||
export { getStaticPaths } from "../index.astro";
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
---
|
||||
import LegacyRedirect from "../../../../layouts/LegacyRedirect.astro";
|
||||
import LegacyRedirect from "../../../../../layouts/LegacyRedirect.astro";
|
||||
|
||||
export { getStaticPaths } from "../../index.astro";
|
||||
|
||||
|
||||
+3
-3
@@ -1,7 +1,7 @@
|
||||
---
|
||||
import type { GetStaticPaths } from "astro";
|
||||
import { embedConfigurations } from "../../../../../constants/embeds";
|
||||
import LegacyRedirect from "../../../../../layouts/LegacyRedirect.astro";
|
||||
import { embedConfigurations } from "../../../../../../constants/embeds";
|
||||
import LegacyRedirect from "../../../../../../layouts/LegacyRedirect.astro";
|
||||
import { getStaticPaths as parentGetStaticPaths } from "../index.astro";
|
||||
|
||||
export const getStaticPaths = (() => {
|
||||
@@ -14,7 +14,7 @@ export const getStaticPaths = (() => {
|
||||
...parent.params,
|
||||
embed: embed as keyof typeof embedConfigurations,
|
||||
},
|
||||
}))
|
||||
})),
|
||||
)
|
||||
.flat();
|
||||
}) satisfies GetStaticPaths;
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
---
|
||||
import LegacyRedirect from "../../../../layouts/LegacyRedirect.astro";
|
||||
import LegacyRedirect from "../../../../../layouts/LegacyRedirect.astro";
|
||||
|
||||
export { getStaticPaths } from "../../index.astro";
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
---
|
||||
import LegacyRedirect from "../../../../layouts/LegacyRedirect.astro";
|
||||
import LegacyRedirect from "../../../../../layouts/LegacyRedirect.astro";
|
||||
|
||||
export { getStaticPaths } from "../../index.astro";
|
||||
|
||||
|
||||
+1
-1
@@ -1,5 +1,5 @@
|
||||
---
|
||||
import LegacyRedirect from "../../../../layouts/LegacyRedirect.astro";
|
||||
import LegacyRedirect from "../../../../../layouts/LegacyRedirect.astro";
|
||||
|
||||
export { getStaticPaths } from "../../index.astro";
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
---
|
||||
import LegacyRedirect from "../../../../layouts/LegacyRedirect.astro";
|
||||
import LegacyRedirect from "../../../../../layouts/LegacyRedirect.astro";
|
||||
|
||||
export { getStaticPaths } from "../../index.astro";
|
||||
|
||||
|
||||
+4
-4
@@ -1,11 +1,11 @@
|
||||
---
|
||||
import { fetchTankDefinitions } from "@blitzkit/core";
|
||||
import type { GetStaticPaths } from "astro";
|
||||
import LegacyRedirect from "../../../../../layouts/LegacyRedirect.astro";
|
||||
import { api } from "../../../../../../core/blitzkit/api";
|
||||
import LegacyRedirect from "../../../../../../layouts/LegacyRedirect.astro";
|
||||
import { getStaticPaths as parentGetStaticPaths } from "../index.astro";
|
||||
|
||||
export const getStaticPaths = (async () => {
|
||||
const tankDefinitions = await fetchTankDefinitions();
|
||||
const tankDefinitions = await api.tankDefinitions();
|
||||
const parentPaths = parentGetStaticPaths();
|
||||
|
||||
return Object.values(tankDefinitions.tanks)
|
||||
@@ -20,7 +20,7 @@ export const getStaticPaths = (async () => {
|
||||
|
||||
const { id } = Astro.params;
|
||||
const { locale } = Astro.props;
|
||||
const tankDefinitions = await fetchTankDefinitions();
|
||||
const tankDefinitions = await api.tankDefinitions();
|
||||
const tank = tankDefinitions.tanks[id];
|
||||
---
|
||||
|
||||
|
||||
+1
-1
@@ -1,5 +1,5 @@
|
||||
---
|
||||
import LegacyRedirect from "../../../../layouts/LegacyRedirect.astro";
|
||||
import LegacyRedirect from "../../../../../layouts/LegacyRedirect.astro";
|
||||
|
||||
export { getStaticPaths } from "../../index.astro";
|
||||
|
||||
|
||||
+1
-1
@@ -1,5 +1,5 @@
|
||||
---
|
||||
import LegacyRedirect from "../../../../layouts/LegacyRedirect.astro";
|
||||
import LegacyRedirect from "../../../../../layouts/LegacyRedirect.astro";
|
||||
|
||||
export { getStaticPaths } from "../../index.astro";
|
||||
|
||||
|
||||
@@ -1,8 +1,15 @@
|
||||
import type { TextProps } from '@radix-ui/themes';
|
||||
import { EmbedState, type EmbedConfig, type ExtractEmbedConfigTypes } from '.';
|
||||
import type { EmbedConfigItemType, EmbedItemType } from './constants';
|
||||
import type { TextProps } from "@radix-ui/themes";
|
||||
import { EmbedState, type EmbedConfig, type ExtractEmbedConfigTypes } from ".";
|
||||
import {
|
||||
breakdownConfig,
|
||||
extractEmbedConfigDefaults,
|
||||
} from "../../constants/embeds";
|
||||
import type { EmbedConfigItemType, EmbedItemType } from "./constants";
|
||||
|
||||
export function useEmbedStateCurry<Config extends EmbedConfig>() {
|
||||
// TODO: find a way to initialize with the correct state preset
|
||||
EmbedState.useInitialization(extractEmbedConfigDefaults(breakdownConfig));
|
||||
|
||||
function useEmbedState<Key extends keyof Config>(key: Key) {
|
||||
return EmbedState.use((state) => {
|
||||
return (state as ExtractEmbedConfigTypes<Config>)[key];
|
||||
@@ -18,7 +25,7 @@ export function useEmbedStateCurry<Config extends EmbedConfig>() {
|
||||
>(key: Key) {
|
||||
const { color, ...state } = useEmbedState(
|
||||
key,
|
||||
) as EmbedConfigItemType<EmbedItemType.RichText>['default'];
|
||||
) as EmbedConfigItemType<EmbedItemType.RichText>["default"];
|
||||
|
||||
return {
|
||||
style: { color },
|
||||
|
||||
Reference in new issue
Block a user