mirror of
https://github.com/blitzkit/blitzkit.git
synced 2026-10-25 03:29:51 +01:00
Compare commits
183
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
830bde1169 | ||
|
|
dc6c528167 | ||
|
|
b4d5d4c16e | ||
|
|
f2f6d4ff49 | ||
|
|
cdbb7647f0 | ||
|
|
41e40de791 | ||
|
|
d55c9b4cd3 | ||
|
|
2ee72b40ab | ||
|
|
c85cd36818 | ||
|
|
5d2c63fed9 | ||
|
|
cead140855 | ||
|
|
63a0143d4f | ||
|
|
19f22993f1 | ||
|
|
b2eb74914f | ||
|
|
878ada0d10 | ||
|
|
b285e9f1d0 | ||
|
|
c292ddcd6a | ||
|
|
05572918b1 | ||
|
|
1cc8b26b16 | ||
|
|
a8e8d20cf1 | ||
|
|
55deb30607 | ||
|
|
03b8b89a17 | ||
|
|
3e421c7eb7 | ||
|
|
fc27caabdc | ||
|
|
3d35fae5ce | ||
|
|
81cc43bd08 | ||
|
|
f6dfc4f176 | ||
|
|
f41eeba25e | ||
|
|
fdbbe2f356 | ||
|
|
cdf2aee43f | ||
|
|
56933ddfac | ||
|
|
1df2e818be | ||
|
|
1e4d00ea34 | ||
|
|
1bde50e0a3 | ||
|
|
88290ec1ab | ||
|
|
e8325df832 | ||
|
|
394f28e6ed | ||
|
|
f5f170bcca | ||
|
|
2ffe3fc006 | ||
|
|
406d70b5b7 | ||
|
|
4e72ea567f | ||
|
|
f801e81c8b | ||
|
|
b572ac5ea8 | ||
|
|
7e2fba35d0 | ||
|
|
e6fa17a911 | ||
|
|
a7d5bd6c75 | ||
|
|
d424679257 | ||
|
|
4248e19f68 | ||
|
|
59ef527967 | ||
|
|
39aeba0766 | ||
|
|
a0e1d8cee0 | ||
|
|
c6f8c1e6a5 | ||
|
|
333c310d5b | ||
|
|
c6c0e02fea | ||
|
|
028f4230e5 | ||
|
|
cf31ad8f7a | ||
|
|
9418526897 | ||
|
|
dacdc9ae53 | ||
|
|
30296d020b | ||
|
|
43b7b4159f | ||
|
|
1aeae3b93b | ||
|
|
d657cd2360 | ||
|
|
222746be26 | ||
|
|
95dd73de52 | ||
|
|
c893fa0a03 | ||
|
|
c0e7f2f00a | ||
|
|
4dce8046cb | ||
|
|
7df2425f76 | ||
|
|
e3cf2d51cc | ||
|
|
91ac93670f | ||
|
|
8a9b02e584 | ||
|
|
c16ccc4b4c | ||
|
|
5dc11473bb | ||
|
|
2213f7d032 | ||
|
|
9d12c936b4 | ||
|
|
3f54e467d8 | ||
|
|
3dd0c4916d | ||
|
|
d2ee528c52 | ||
|
|
0531fbf3ef | ||
|
|
415aab3824 | ||
|
|
f16e508e59 | ||
|
|
3299ce069e | ||
|
|
6395dd3f3d | ||
|
|
9536cd2d39 | ||
|
|
61abddc41b | ||
|
|
b23f88b8a5 | ||
|
|
007ad3be15 | ||
|
|
218684b85c | ||
|
|
2e17ed16ed | ||
|
|
173c476fb4 | ||
|
|
e12ba1e78f | ||
|
|
648344d7cc | ||
|
|
3e0130a200 | ||
|
|
fc0f77a459 | ||
|
|
9ba6d3ca56 | ||
|
|
ba017936fb | ||
|
|
ac47f11460 | ||
|
|
507e6fe7f9 | ||
|
|
965acadc3f | ||
|
|
14a2658a83 | ||
|
|
5cbe08fe1c | ||
|
|
05dd4dbd98 | ||
|
|
a348e005f7 | ||
|
|
62b629fe3a | ||
|
|
f790d07ed6 | ||
|
|
c86b269cf2 | ||
|
|
a878a7a143 | ||
|
|
76fc900a15 | ||
|
|
667d8c8f7c | ||
|
|
9cc94635a8 | ||
|
|
39ffc6ae51 | ||
|
|
4b0035345e | ||
|
|
ef7e002e8c | ||
|
|
81e17317be | ||
|
|
333866a9d6 | ||
|
|
152e0a6680 | ||
|
|
417b717b63 | ||
|
|
c134131127 | ||
|
|
516df13f62 | ||
|
|
0c8bb4be21 | ||
|
|
1f204918a5 | ||
|
|
0507f63177 | ||
|
|
0f84ae45b6 | ||
|
|
ff16a26bd8 | ||
|
|
85ddedd481 | ||
|
|
125f6c721d | ||
|
|
4bad35239b | ||
|
|
ff7716ce6c | ||
|
|
231e4aad0e | ||
|
|
632989087c | ||
|
|
bb0b932d26 | ||
|
|
3714c74394 | ||
|
|
168e85d838 | ||
|
|
666f44d9e6 | ||
|
|
595db8709b | ||
|
|
18a6f30a4b | ||
|
|
9b8d4c4e3c | ||
|
|
73de6e3521 | ||
|
|
6aa14d2faf | ||
|
|
477b9a9630 | ||
|
|
b297babde5 | ||
|
|
c854e8f7cb | ||
|
|
06832e156f | ||
|
|
22b77398ad | ||
|
|
665d5c0f2d | ||
|
|
d9b22431fa | ||
|
|
0a186399b6 | ||
|
|
d2b4cc3e7d | ||
|
|
885c260605 | ||
|
|
f8a71feb46 | ||
|
|
0cb4aadec3 | ||
|
|
f58d06b3c3 | ||
|
|
2c44bd8374 | ||
|
|
699b445f79 | ||
|
|
26bb350709 | ||
|
|
6fb51e703d | ||
|
|
7a7c73d77b | ||
|
|
f945786e2f | ||
|
|
c678830fd2 | ||
|
|
a9a870c3e6 | ||
|
|
3d061a78de | ||
|
|
a188a01244 | ||
|
|
0828722876 | ||
|
|
0ccd9e45d8 | ||
|
|
2f745a16d1 | ||
|
|
100c7391fb | ||
|
|
4f42a31f53 | ||
|
|
0b2e322112 | ||
|
|
042a1afa74 | ||
|
|
3edf4a25be | ||
|
|
43237c2aee | ||
|
|
2fffdc3ef5 | ||
|
|
76e748f0ed | ||
|
|
c353119962 | ||
|
|
5fa4d3b242 | ||
|
|
068e0e26b0 | ||
|
|
f6ca77f8c8 | ||
|
|
4c7eda81ca | ||
|
|
3948af9e39 | ||
|
|
aec30e1944 | ||
|
|
4205b16769 | ||
|
|
4d13803b0c | ||
|
|
b950ac1318 |
No files matched your search
@@ -0,0 +1 @@
|
||||
indentSize: 2
|
||||
@@ -4,9 +4,6 @@ on:
|
||||
push:
|
||||
workflow_dispatch:
|
||||
|
||||
# schedule:
|
||||
# - cron: "0 4 * * *"
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
pages: write
|
||||
@@ -14,7 +11,7 @@ permissions:
|
||||
|
||||
concurrency:
|
||||
group: ${{ github.workflow }}-${{ github.ref }}
|
||||
cancel-in-progress: ${{ github.ref == 'refs/heads/main' }}
|
||||
cancel-in-progress: true
|
||||
|
||||
env:
|
||||
# blitz
|
||||
@@ -34,13 +31,17 @@ env:
|
||||
STEAM_OS: windows
|
||||
STEAM_FINGERPRINT: Manifest_UFSFiles_Win64.txt
|
||||
|
||||
# debug
|
||||
DOTNET_EnableDiagnostics: 1
|
||||
|
||||
jobs:
|
||||
build:
|
||||
name: Build chunk ${{ matrix.chunk }}
|
||||
runs-on: ubuntu-latest
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
chunk: [pages, api, media]
|
||||
chunk: [pages, api, media, models, textures]
|
||||
|
||||
steps:
|
||||
- name: Free disk space
|
||||
@@ -63,7 +64,7 @@ jobs:
|
||||
- name: Set up Dotnet
|
||||
uses: actions/setup-dotnet@v5
|
||||
with:
|
||||
dotnet-version: "10.0.x"
|
||||
dotnet-version: 9.0.x
|
||||
|
||||
- name: Set up Protoc
|
||||
uses: arduino/setup-protoc@v3
|
||||
@@ -75,37 +76,20 @@ jobs:
|
||||
bun run setup
|
||||
./scripts/setup_depot_downloader.sh
|
||||
|
||||
- name: Download fingerprint
|
||||
run: |
|
||||
./scripts/download_fingerprint.sh
|
||||
|
||||
- name: Download cached game
|
||||
uses: actions/cache@v5
|
||||
id: game-cache
|
||||
with:
|
||||
path: temp/game
|
||||
key: ${{ runner.os }}-${{ hashFiles(format('temp/game/{0}', env.FINGERPRINT)) }}
|
||||
|
||||
- name: Download Steam game
|
||||
if: steps.game-cache.outputs.cache-hit != 'true'
|
||||
run: scripts/download_game.sh
|
||||
|
||||
- name: Enable core dumps
|
||||
run: |
|
||||
./scripts/download_game.sh
|
||||
ulimit -c unlimited
|
||||
|
||||
# - name: Build
|
||||
# run: bun run build-website
|
||||
# env:
|
||||
# BUILD_CHUNK: ${{ matrix.chunk }}
|
||||
- name: Build
|
||||
run: bun run build-website
|
||||
env:
|
||||
BUILD_CHUNK: ${{ matrix.chunk }}
|
||||
|
||||
# - name: Upload artifact
|
||||
# id: upload
|
||||
# uses: actions/upload-pages-artifact@v4
|
||||
# with:
|
||||
# path: dist/website
|
||||
|
||||
# - name: Trigger target repository
|
||||
# run: |
|
||||
# curl -X POST \
|
||||
# -H "Authorization: token ${{ secrets.GH_TOKEN }}" \
|
||||
# -H "Accept: application/vnd.github.v3+json" \
|
||||
# https://github.com \
|
||||
# -d '{ "event_type": "deploy-pages", "client_payload": { "artifact_url": "${{ steps.upload.outputs.artifact_url }}" } }'
|
||||
- name: Upload artifact
|
||||
uses: actions/upload-pages-artifact@v5
|
||||
with:
|
||||
name: chunk-${{ matrix.chunk }}
|
||||
path: ${{ matrix.chunk == 'pages' && 'dist/website' || format('dist/website/{0}', matrix.chunk) }}
|
||||
@@ -0,0 +1,3 @@
|
||||
{
|
||||
"tabWidth": 2
|
||||
}
|
||||
Vendored
-4
@@ -1,4 +0,0 @@
|
||||
{
|
||||
"recommendations": ["astro-build.astro-vscode"],
|
||||
"unwantedRecommendations": []
|
||||
}
|
||||
Vendored
-11
@@ -1,11 +0,0 @@
|
||||
{
|
||||
"version": "0.2.0",
|
||||
"configurations": [
|
||||
{
|
||||
"command": "./node_modules/.bin/astro dev",
|
||||
"name": "Development server",
|
||||
"request": "launch",
|
||||
"type": "node-terminal"
|
||||
}
|
||||
]
|
||||
}
|
||||
Vendored
-270
@@ -1,270 +0,0 @@
|
||||
{
|
||||
// "js/ts.experimental.useTsgo": true,
|
||||
"protobuf.includes": ["${workspaceFolder}/path/to/protos"],
|
||||
"cSpell.words": [
|
||||
"AABBOX",
|
||||
"Abhi",
|
||||
"absarc",
|
||||
"accountinfo",
|
||||
"adsense",
|
||||
"aeson",
|
||||
"alphatest",
|
||||
"analyticsdata",
|
||||
"analyticsreporting",
|
||||
"APAC",
|
||||
"apcr",
|
||||
"appinfo",
|
||||
"applypatches",
|
||||
"artefacts",
|
||||
"astrojs",
|
||||
"astrolib",
|
||||
"atgm",
|
||||
"autocrop",
|
||||
"Autoloader",
|
||||
"Autoreloader",
|
||||
"AYUV",
|
||||
"battleresults",
|
||||
"bbox",
|
||||
"beforeinstallprompt",
|
||||
"bepaint",
|
||||
"betakrieg",
|
||||
"BINORMAL",
|
||||
"Binormals",
|
||||
"bkni",
|
||||
"BKRL",
|
||||
"BKRTS",
|
||||
"BKRTSMANIFEST",
|
||||
"bkwd",
|
||||
"blitzkit",
|
||||
"blitzrinth",
|
||||
"blitzstars",
|
||||
"bufbuild",
|
||||
"cacheable",
|
||||
"Callouts",
|
||||
"Camo",
|
||||
"Carro",
|
||||
"catalogitemaccessor",
|
||||
"CCPAOPTOUT",
|
||||
"CDON",
|
||||
"clanid",
|
||||
"classname",
|
||||
"cleandist",
|
||||
"closedkrieg",
|
||||
"cockroackdb",
|
||||
"Coef",
|
||||
"Combattimento",
|
||||
"cooldown",
|
||||
"corelations",
|
||||
"corsproxy",
|
||||
"CUBEMAP",
|
||||
"CUBETEXCOORD",
|
||||
"customperiod",
|
||||
"datasource",
|
||||
"Dava",
|
||||
"dbid",
|
||||
"Ddpf",
|
||||
"Ddsd",
|
||||
"deadrail",
|
||||
"DEBUFF",
|
||||
"debugflags",
|
||||
"deburr",
|
||||
"deburred",
|
||||
"decalmask",
|
||||
"decompressor",
|
||||
"décor",
|
||||
"dedup",
|
||||
"defence",
|
||||
"degressive",
|
||||
"devkrieg",
|
||||
"diacriticless",
|
||||
"DIDS",
|
||||
"donotremove",
|
||||
"drei",
|
||||
"Droodles",
|
||||
"dvpd",
|
||||
"dvpl",
|
||||
"DVPLCRC",
|
||||
"dvpm",
|
||||
"dxgi",
|
||||
"easimon",
|
||||
"echarts",
|
||||
"Everytime",
|
||||
"FASTNAME",
|
||||
"favicons",
|
||||
"filelist",
|
||||
"flexdirection",
|
||||
"fontsource",
|
||||
"FOURCC",
|
||||
"frameloop",
|
||||
"fsformat",
|
||||
"Fullscreen",
|
||||
"fullstats",
|
||||
"fuzzysort",
|
||||
"gamemode",
|
||||
"gameplay",
|
||||
"glsl",
|
||||
"GLTF",
|
||||
"GSOR",
|
||||
"gtag",
|
||||
"haha",
|
||||
"Herdbreaker",
|
||||
"Hetz",
|
||||
"highp",
|
||||
"iife",
|
||||
"imgur",
|
||||
"immer",
|
||||
"Inclusivity",
|
||||
"JOINTINDEX",
|
||||
"JOINTWEIGHT",
|
||||
"kranvagn",
|
||||
"krieg",
|
||||
"Leaderboard",
|
||||
"leaderboards",
|
||||
"lerp",
|
||||
"LINEARSIZE",
|
||||
"linktarget",
|
||||
"lmao",
|
||||
"loadouts",
|
||||
"loddist",
|
||||
"lods",
|
||||
"lossrate",
|
||||
"Maddoxkkm",
|
||||
"malum",
|
||||
"mantlets",
|
||||
"mediump",
|
||||
"metallicness",
|
||||
"metalness",
|
||||
"minitelrose",
|
||||
"Minotauro",
|
||||
"MIPMAPCOUNT",
|
||||
"mišek",
|
||||
"mmnow",
|
||||
"modeltransform",
|
||||
"MURICA",
|
||||
"nanostores",
|
||||
"NEGATIVEX",
|
||||
"NEGATIVEY",
|
||||
"NEGATIVEZ",
|
||||
"networkidle",
|
||||
"NITROPAY",
|
||||
"nivo",
|
||||
"nmatname",
|
||||
"noout",
|
||||
"normalmap",
|
||||
"oneof",
|
||||
"Oodle",
|
||||
"oopsies",
|
||||
"Oopsy",
|
||||
"opentest",
|
||||
"OPTML",
|
||||
"otemp",
|
||||
"outdir",
|
||||
"outfile",
|
||||
"ownedtanks",
|
||||
"padder",
|
||||
"partytown",
|
||||
"patchnotes",
|
||||
"PIXELFORMAT",
|
||||
"playerachievements",
|
||||
"playerinfo",
|
||||
"playform",
|
||||
"Playtest",
|
||||
"pngjs",
|
||||
"POSITIVEX",
|
||||
"POSITIVEY",
|
||||
"POSITIVEZ",
|
||||
"precompute",
|
||||
"Promisable",
|
||||
"proto",
|
||||
"protobuf",
|
||||
"protoc",
|
||||
"protos",
|
||||
"proxyclient",
|
||||
"prunestrings",
|
||||
"Pyogenics",
|
||||
"ratingleaderboard",
|
||||
"raycaster",
|
||||
"Redirector",
|
||||
"REGEN",
|
||||
"Relogin",
|
||||
"researchable",
|
||||
"Resvg",
|
||||
"rizz",
|
||||
"roboto",
|
||||
"rtsc",
|
||||
"RTSM",
|
||||
"SCPG",
|
||||
"scroller",
|
||||
"searchclans",
|
||||
"searchplayers",
|
||||
"searchtanks",
|
||||
"SHAREDEXP",
|
||||
"Skia",
|
||||
"SKLLD",
|
||||
"sluggify",
|
||||
"smoothstep",
|
||||
"Smri",
|
||||
"Specularity",
|
||||
"SSAO",
|
||||
"stackable",
|
||||
"startcase",
|
||||
"statkit",
|
||||
"statsfull",
|
||||
"steamapps",
|
||||
"Stringifying",
|
||||
"struct",
|
||||
"structs",
|
||||
"strvk",
|
||||
"subnation",
|
||||
"Synx",
|
||||
"tankaverages",
|
||||
"Tankerch",
|
||||
"tankmen",
|
||||
"tankopedia",
|
||||
"tankopedias",
|
||||
"tankstats",
|
||||
"tauri",
|
||||
"texconv",
|
||||
"TEXCOORD",
|
||||
"tresabhi",
|
||||
"tungstentip",
|
||||
"Turretless",
|
||||
"TYPELESS",
|
||||
"uasset",
|
||||
"ubjson",
|
||||
"Unicum",
|
||||
"UNLOCALIZED",
|
||||
"UNORM",
|
||||
"unpickled",
|
||||
"Unregistering",
|
||||
"unrotate",
|
||||
"unwrapper",
|
||||
"userns",
|
||||
"usmap",
|
||||
"vercel",
|
||||
"vickers",
|
||||
"vitepress",
|
||||
"Vovko",
|
||||
"wargaming",
|
||||
"webp",
|
||||
"wgpkg",
|
||||
"whitespaces",
|
||||
"WHSS",
|
||||
"winrate",
|
||||
"wireframe",
|
||||
"Woah",
|
||||
"wooorm",
|
||||
"WOTB",
|
||||
"wotblitz",
|
||||
"wotbreplay",
|
||||
"WOTINSPECTOR",
|
||||
"xffn",
|
||||
"xkdkw",
|
||||
"XMLDVPL",
|
||||
"YAMLDVPL",
|
||||
"yolo",
|
||||
"youtuber",
|
||||
"youtubers",
|
||||
"zoomable"
|
||||
]
|
||||
}
|
||||
@@ -1,47 +1,105 @@
|
||||
# BlitzKit
|
||||
|
||||
Tools for everything and anything, World of Tanks Blitz.
|
||||
Encyclopedia for World of Tanks Blitz.
|
||||
|
||||
This GitHub repository contains the code for BlitzKit and all its services. If you are here, looking to use BlitzKit, go to https://blitzkit.app/.
|
||||
## Development
|
||||
|
||||
If you intend to contribute to the code, note that you may need to check out sensitive, closed-source submodules to locally develop certain aspects of BlitzKit. Communicate with `@tresabhi` on Discord to get started or discuss sensitive content, such as environment variables or submodules.
|
||||
Setting up a local developer environment for BlitzKit is more complex than most projects, but this section will guide you through all the steps. If you're ever lost or confused, feel free to ask for help in [the official Discord server](https://discord.gg/nDt7AjGJQH).
|
||||
|
||||
## Packages
|
||||
### Prerequisites
|
||||
|
||||
| Package | Title | Source | Memo |
|
||||
| ------------------------------------ | -------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | ------------------------------------------------------------------------------------------------------------------------ |
|
||||
| [packages/app](packages/app) | BlitzKit | [Play Store](https://play.google.com/store/apps/details?id=com.tresabhi.blitzkit), [App Store](https://apps.apple.com/app/4321), [Microsoft Store](https://apps.microsoft.com/detail/zyxw) | The native app of BlitzKit for all platforms. Unavailable from stores at this time. |
|
||||
| [packages/bot](packages/bot) | BlitzKit Discord Bot | [Discord Application Directory](https://discord.com/discovery/applications/1097673957865443370) | The one-in-all Discord bot for statistics. |
|
||||
| [packages/core](packages/core) | | | Mutual internal code shared between all other packages. |
|
||||
| [packages/i18n](packages/i18n) | | [Crowdin](https://crowdin.com/project/blitzkrieg) | Translations served as JSON shared across all other packages, including some utility code. |
|
||||
| [packages/scripts](packages/scripts) | | | CLI utilities for the development and deployment of BlitzKit services. |
|
||||
| [packages/varuna](packages/varuna) | Varuna | [NPM](https://www.npmjs.com/package/varuna) | React and Astro-oriented state management library, awaiting separation from BlitzKit. Unavailable from NPM at this time. |
|
||||
| [packages/website](packages/website) | BlitzKit | https://blitzkit.app | The BlitzKit website provides a wide range of tools, APIs, and interconnects all other services. |
|
||||
Before you touch any code, you'll need the following.
|
||||
|
||||
## Submodules
|
||||
#### Linux
|
||||
|
||||
| Submodule | Title | Source | Memo |
|
||||
| ------------------------------------------------------ | --------- | ----------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
||||
| [submodules/blitzkit-closed](packages/blitzkit-closed) | ClosedKit | [blitzkit/closed](https://github.com/blitzkit/closed) | Closed source, sensitive code hidden from the public to prevent bad actors from abusing the game. Discuss with `@tresabhi` on Discord for **special permission** to access. |
|
||||
Because Node API for .NET doesn't resolve runtime-specific object files for libraries, the entirety of the BlitzKit project is "vendor-locked" to a single OS. GitHub Actions, responsible for BlitzKit CD/CI works best with Ubuntu, thus we must also use a Linux OS.
|
||||
|
||||
## Environment Variables
|
||||
#### Windows (Optional)
|
||||
|
||||
| Name | Source | BlitzKit Default | Memo |
|
||||
| ------------------------------------------------------------- | -------------------------------------------------------------------------------- | ----------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------- |
|
||||
| `PUBLIC_WARGAMING_APPLICATION_ID` | [Wargaming Developer's Room](https://developers.wargaming.net/) | | Application ID needed to communicate with Wargaming APIs. |
|
||||
| `PUBLIC_PROMOTE_OPENTEST` | | `false` | Optional boolean dictating whether the website advertises [the opentest subdomain of BlitzKit](https://opentest.blitzkit.app/). |
|
||||
| `ALLOW_ROBOTS` | | `true` | Toggles between `Allow: /` and `Disallow: /` in the website's `/robots.txt`. This is usually `false` for all BlitzKit's subdomains. |
|
||||
| `WOTB_GLOSSARY`, `WOTB_GLOSSARY_DOMAIN`, `WOTB_GLOSSARY_PATH` | | | |
|
||||
| `PUBLIC_GOOGLE_TAG_MANAGER_ID` | [Google Tag Manager](https://tagmanager.google.com/) | `G-GL2JVHCGPQ` | Google Tag Manager's unique identifier for analytical purposes. |
|
||||
| `PUBLIC_GOOGLE_ANALYTICS_PROPERTY_ID` | [Google Analytics](https://analytics.google.com/) | `430711767` | Google Analytics' unique property ID for [BlitzKit's apex domain](https://blitzkit.app/) and subdomains. |
|
||||
| `GOOGLE_APPLICATION_CREDENTIALS` | [Google Cloud](https://cloud.google.com/) | | Google Cloud's API key, primarily used for ranking popular tanks and finding relevant tank review videos in Tankopedia. |
|
||||
| `PUBLIC_DISCORD_SERVER_ID` | [BlitzKit Discord Server](https://discord.gg/nDt7AjGJQH) | `734786591205359697` | BlitzKit Discord Server's id. |
|
||||
| `PUBLIC_ASSET_BASE` | [blitzkit/assets](https://github.com/blitzkit/assets) | `https://blitzkit.github.io/assets` | The root domain and path that serves the external assets like tank models and icons. |
|
||||
| `PUBLIC_BRANCH` | | `main` | The branch that the website is operating on. This is completely nominal. |
|
||||
| `PUBLIC_GUIDE_WEBSITE` | [GuidesBlitz](https://guidesblitz.com/) | `https://guidesblitz.com` | The website that serves the encyclopedia-like content in BlitzKit. |
|
||||
| `SERVICING` | | `false` | Wether the website is down for servicing. |
|
||||
| `DISCORD_CLIENT_ID` | [Discord Developer Portal](https://discord.com/developers/applications) | `1097673957865443370` | The BlitzKit Discord Bot's user ID. |
|
||||
| `GH_TOKEN` | [GitHub Fine-Grained Tokens](https://github.com/settings/personal-access-tokens) | | The GitHub API key used for checking out private submodules and pushing content to the asset repository. |
|
||||
| `DISCORD_TOKEN` | [Discord Developer Portal](https://discord.com/developers/applications) | | The Discord API Key for the BlitzKit Discord Bot. |
|
||||
| `DATABASE_URL` | [CockroachDB](https://www.cockroachlabs.com/) | | The CockroachDB-SQL database URL used to link Wargaming and Discord users. |
|
||||
| `WOTB_DLC_CDN` | | | |
|
||||
...
|
||||
|
||||
#### Bun
|
||||
|
||||
https://bun.com/
|
||||
|
||||
BlitzKit is written mostly in TypeScript, with packages fetched from NPM, managed by Bun.
|
||||
|
||||
#### .NET
|
||||
|
||||
https://dotnet.microsoft.com/download/dotnet/9.0/
|
||||
|
||||
You'll need the .NET 9.0 SDK to build and run the interface layer between BlitzKit and your local installation of World of Tanks Blitz.
|
||||
|
||||
#### Protocol Buffers
|
||||
|
||||
https://protobuf.dev/installation/
|
||||
|
||||
Both BlitzKit and World of Tanks Blitz encode their APIs with Protocol Buffers.
|
||||
|
||||
#### World of Tanks Blitz
|
||||
|
||||
https://store.steampowered.com/app/444200/
|
||||
|
||||
You'll need an up-to-date installation of World of Tanks Blitz on your computer. You may use the same installation that you play, even on a Windows partition if you dual boot.
|
||||
|
||||
#### UE4SS
|
||||
|
||||
...
|
||||
|
||||
#### protodump
|
||||
|
||||
...
|
||||
|
||||
#### FModel (Optional)
|
||||
|
||||
...
|
||||
|
||||
### Set Up
|
||||
|
||||
Now we can start installing and initiating the code of BlitzKit.
|
||||
|
||||
#### Cloning
|
||||
|
||||
BlitzKit is a massive monorepo with a lot of submodules. You'll likely not need all the branches and commit history. So, clone with depth 1.
|
||||
|
||||
```bash
|
||||
git clone --depth 1 https://github.com/blitzkit/blitzkit.git
|
||||
cd blitzkit
|
||||
git submodule update --init --recursive --depth 1
|
||||
```
|
||||
|
||||
#### Proto Files
|
||||
|
||||
...
|
||||
|
||||
#### Mappings
|
||||
|
||||
...
|
||||
|
||||
#### Environment Variables
|
||||
|
||||
...
|
||||
|
||||
#### The Big One
|
||||
|
||||
...
|
||||
|
||||
### Modifying The Code
|
||||
|
||||
This is where you can start changing things and proposing them through pull requests.
|
||||
|
||||
#### Server
|
||||
|
||||
...
|
||||
|
||||
#### Building
|
||||
|
||||
...
|
||||
|
||||
#### Branches & Pull Requests
|
||||
|
||||
...
|
||||
|
||||
#### Updating
|
||||
|
||||
...
|
||||
@@ -5,6 +5,7 @@
|
||||
"": {
|
||||
"name": "blitzkit",
|
||||
"dependencies": {
|
||||
"prettier": "^3.8.3",
|
||||
"typescript": "^5.9.3",
|
||||
},
|
||||
},
|
||||
@@ -69,16 +70,15 @@
|
||||
"@types/bun": "^1.3.1",
|
||||
"@types/lodash-es": "^4.17.12",
|
||||
"@types/lz4js": "^0.2.1",
|
||||
"@types/three": "^0.180.0",
|
||||
"@types/three": "^0.184.1",
|
||||
"adm-zip": "^0.5.16",
|
||||
"crc": "^4.3.2",
|
||||
"dotenv": "^17.2.2",
|
||||
"fast-xml-parser": "^5.3.2",
|
||||
"lodash-es": "^4.17.21",
|
||||
"lz4js": "^0.2.0",
|
||||
"pickleparser": "^0.2.1",
|
||||
"protobufjs": "^7.5.4",
|
||||
"three": "^0.180.0",
|
||||
"three": "^0.184.0",
|
||||
"ts-proto": "^2.7.7",
|
||||
"yaml": "^2.8.1",
|
||||
},
|
||||
@@ -100,6 +100,7 @@
|
||||
"dependencies": {
|
||||
"@blitzkit/closed": "workspace:*",
|
||||
"@blitzkit/core": "workspace:*",
|
||||
"@blitzkit/game": "workspace:*",
|
||||
"@blitzkit/i18n": "workspace:*",
|
||||
"@gltf-transform/core": "^4.2.1",
|
||||
"@gltf-transform/extensions": "^4.2.1",
|
||||
@@ -121,7 +122,6 @@
|
||||
"fast-xml-parser": "^5.2.5",
|
||||
"googleapis": "^162.0.0",
|
||||
"lodash-es": "^4.17.21",
|
||||
"lz4js": "^0.2.0",
|
||||
"progress": "^2.0.3",
|
||||
"puppeteer": "^24.22.3",
|
||||
"sharp": "^0.34.4",
|
||||
@@ -187,54 +187,53 @@
|
||||
"packages/website-ue": {
|
||||
"name": "@blitzkit/website-ue",
|
||||
"dependencies": {
|
||||
"@astrojs/check": "^0.9.4",
|
||||
"@astrojs/node": "^9.4.4",
|
||||
"@astrojs/react": "^4.4.0",
|
||||
"@astrojs/check": "^0.9.9",
|
||||
"@astrojs/node": "^9.5.5",
|
||||
"@astrojs/react": "^4.4.2",
|
||||
"@astrolib/seo": "^1.0.0-beta.8",
|
||||
"@blitzkit/closed": "workspace:*",
|
||||
"@blitzkit/core": "workspace:*",
|
||||
"@blitzkit/game": "workspace:*",
|
||||
"@blitzkit/i18n": "workspace:*",
|
||||
"@bufbuild/protobuf": "^2.10.2",
|
||||
"@bufbuild/protobuf": "^2.12.0",
|
||||
"@fontsource-variable/jetbrains-mono": "^5.2.8",
|
||||
"@fontsource-variable/roboto-flex": "^5.2.8",
|
||||
"@fontsource-variable/roboto-mono": "^5.2.8",
|
||||
"@fontsource-variable/roboto-mono": "^5.2.9",
|
||||
"@gltf-transform/core": "^4.4.0",
|
||||
"@radix-ui/colors": "^3.0.0",
|
||||
"@radix-ui/react-icons": "^1.3.2",
|
||||
"@react-three/drei": "^10.7.6",
|
||||
"@react-three/fiber": "^9.4.0",
|
||||
"@react-three/drei": "^10.7.7",
|
||||
"@react-three/fiber": "^9.6.1",
|
||||
"@types/lodash-es": "^4.17.12",
|
||||
"@types/react": "^19.2.2",
|
||||
"@types/react-dom": "^19.2.2",
|
||||
"@types/three": "^0.180.0",
|
||||
"@vite-pwa/astro": "^1.1.0",
|
||||
"@types/three": "^0.184.1",
|
||||
"@vite-pwa/astro": "^1.2.0",
|
||||
"@wooorm/starry-night": "^3.9.0",
|
||||
"astro": "^5.14.4",
|
||||
"astro-favicons": "^3.1.5",
|
||||
"autoprefixer": "^10.4.23",
|
||||
"cssnano": "^7.1.2",
|
||||
"astro": "^5.18.2",
|
||||
"astro-favicons": "^3.1.6",
|
||||
"autoprefixer": "^10.5.0",
|
||||
"cssnano": "^7.1.9",
|
||||
"fuzzysort": "^3.1.0",
|
||||
"googleapis": "^171.1.0",
|
||||
"googleapis": "^171.4.0",
|
||||
"hast-util-to-jsx-runtime": "^2.3.6",
|
||||
"immer": "^10.1.3",
|
||||
"lodash-es": "^4.17.21",
|
||||
"postcss": "^8.5.6",
|
||||
"immer": "^10.2.0",
|
||||
"lodash-es": "^4.18.1",
|
||||
"postcss": "^8.5.15",
|
||||
"postcss-load-config": "^6.0.1",
|
||||
"postcss-nested": "^7.0.2",
|
||||
"postcss-preset-env": "^11.1.1",
|
||||
"postcss-preset-env": "^11.3.0",
|
||||
"quicklime": "^1.2.0",
|
||||
"react": "^19.2.6",
|
||||
"react-dom": "^19.2.6",
|
||||
"react-error-boundary": "^6.1.1",
|
||||
"react-error-boundary": "^6.1.2",
|
||||
"react-markdown": "^10.1.0",
|
||||
"react-promise-suspense": "^0.3.4",
|
||||
"sharp": "^0.34.5",
|
||||
"three": "^0.180.0",
|
||||
"three-stdlib": "^2.36.0",
|
||||
"three": "^0.184.0",
|
||||
"three-stdlib": "^2.36.1",
|
||||
"typescript": "^5.9.3",
|
||||
"varuna": "workspace:*",
|
||||
"vite": "^7.1.9",
|
||||
"yaml": "^2.8.1",
|
||||
"vite": "^7.3.3",
|
||||
"yaml": "^2.9.0",
|
||||
},
|
||||
},
|
||||
},
|
||||
@@ -469,17 +468,19 @@
|
||||
|
||||
"@blitzkit/website-ue": ["@blitzkit/website-ue@workspace:packages/website-ue"],
|
||||
|
||||
"@bufbuild/protobuf": ["@bufbuild/[email protected]1.0", "", {}, "sha512-sBXGT13cpmPR5BMgHE6UEEfEaShh5Ror6rfN3yEK5si7QVrtZg8LEPQb0VVhiLRUslD2yLnXtnRzG035J/mZXQ=="],
|
||||
"@bufbuild/protobuf": ["@bufbuild/[email protected]2.0", "", {}, "sha512-B/XlCaFIP8LOwzo+bz5uFzATYokcwCKQcghqnlfwSmM5eX/qTkvDBnDPs+gXtX/RyjxJ4DRikECcPJbyALA8FA=="],
|
||||
|
||||
"@capsizecss/unpack": ["@capsizecss/[email protected]", "", { "dependencies": { "fontkitten": "^1.0.0" } }, "sha512-VERIM64vtTP1C4mxQ5thVT9fK0apjPFobqybMtA1UdUujWka24ERHbRHFGmpbbhp73MhV+KSsHQH9C6uOTdEQA=="],
|
||||
|
||||
"@colordx/core": ["@colordx/[email protected]", "", {}, "sha512-kIxYSfA5T8HXjav55UaaH/o/cKivF6jCCGIb8eqtcsfI46wsvlSiT8jMDyrl779qLec3c2c2oHBZo4oAhvbjrQ=="],
|
||||
|
||||
"@csstools/cascade-layer-name-parser": ["@csstools/[email protected]", "", { "peerDependencies": { "@csstools/css-parser-algorithms": "^4.0.0", "@csstools/css-tokenizer": "^4.0.0" } }, "sha512-/3iksyevwRfSJx5yH0RkcrcYXwuhMQx3Juqf40t97PeEy2/Mz2TItZ/z/216qpe4GgOyFBP8MKIwVvytzHmfIQ=="],
|
||||
|
||||
"@csstools/color-helpers": ["@csstools/[email protected].1", "", {}, "sha512-NmXRccUJMk2AWA5A7e5a//3bCIMyOu2hAtdRYrhPPHjDxINuCwX1w6rnIZ4xjLcp0ayv6h8Pc3X0eJUGiAAXHQ=="],
|
||||
"@csstools/color-helpers": ["@csstools/[email protected].2", "", {}, "sha512-LMGQLS9EuADloEFkcTBR3BwV/CGHV7zyDxVRtVDTwdI2Ca4it0CCVTT9wCkxSgokjE5Ho41hEPgb8OEUwoXr6Q=="],
|
||||
|
||||
"@csstools/css-calc": ["@csstools/css-calc@3.1.1", "", { "peerDependencies": { "@csstools/css-parser-algorithms": "^4.0.0", "@csstools/css-tokenizer": "^4.0.0" } }, "sha512-HJ26Z/vmsZQqs/o3a6bgKslXGFAungXGbinULZO3eMsOyNJHeBBZfup5FiZInOghgoM4Hwnmw+OgbJCNg1wwUQ=="],
|
||||
"@csstools/css-calc": ["@csstools/css-calc@3.2.1", "", { "peerDependencies": { "@csstools/css-parser-algorithms": "^4.0.0", "@csstools/css-tokenizer": "^4.0.0" } }, "sha512-DtdHlgXh5ZkA43cwBcAm+huzgJiwx3ZTWVjBs94kwz2xKqSimDA3lBgCjphYgwgVUMWatSM0pDd8TILB1yrVVg=="],
|
||||
|
||||
"@csstools/css-color-parser": ["@csstools/css-color-parser@4.0.1", "", { "dependencies": { "@csstools/color-helpers": "^6.0.1", "@csstools/css-calc": "^3.0.0" }, "peerDependencies": { "@csstools/css-parser-algorithms": "^4.0.0", "@csstools/css-tokenizer": "^4.0.0" } }, "sha512-vYwO15eRBEkeF6xjAno/KQ61HacNhfQuuU/eGwH67DplL0zD5ZixUa563phQvUelA07yDczIXdtmYojCphKJcw=="],
|
||||
"@csstools/css-color-parser": ["@csstools/css-color-parser@4.1.1", "", { "dependencies": { "@csstools/color-helpers": "^6.0.2", "@csstools/css-calc": "^3.2.1" }, "peerDependencies": { "@csstools/css-parser-algorithms": "^4.0.0", "@csstools/css-tokenizer": "^4.0.0" } }, "sha512-eZ5XOtyhK+mggRafYUWzA0tvaYOFgdY8AkgQiCJF9qNAePnUo/zmsqqYubBBb3sQ8uNUaSKTY9s9klfRaAXL0g=="],
|
||||
|
||||
"@csstools/css-parser-algorithms": ["@csstools/[email protected]", "", { "peerDependencies": { "@csstools/css-tokenizer": "^4.0.0" } }, "sha512-+B87qS7fIG3L5h3qwJ/IFbjoVoOe/bpOdh9hAjXbvx0o8ImEmUsGXN0inFOnk2ChCFgqkkGFQ+TpM5rbhkKe4w=="],
|
||||
|
||||
@@ -487,39 +488,45 @@
|
||||
|
||||
"@csstools/media-query-list-parser": ["@csstools/[email protected]", "", { "peerDependencies": { "@csstools/css-parser-algorithms": "^4.0.0", "@csstools/css-tokenizer": "^4.0.0" } }, "sha512-T9lXmZOfnam3eMERPsszjY5NK0jX8RmThmmm99FZ8b7z8yMaFZWKwLWGZuTwdO3ddRY5fy13GmmEYZXB4I98Eg=="],
|
||||
|
||||
"@csstools/postcss-alpha-function": ["@csstools/[email protected].2", "", { "dependencies": { "@csstools/css-color-parser": "^4.0.1", "@csstools/css-parser-algorithms": "^4.0.0", "@csstools/css-tokenizer": "^4.0.0", "@csstools/postcss-progressive-custom-properties": "^5.0.0", "@csstools/utilities": "^3.0.0" }, "peerDependencies": { "postcss": "^8.4" } }, "sha512-EXdJC5fds0h1KqoioUBkcYPZvcNKR64jrGkbqlDNbMU3FP1MzLEr/QJR8bj/bu53TJFIgkc9WvKcpbwVqZ4WPg=="],
|
||||
"@csstools/postcss-alpha-function": ["@csstools/[email protected].5", "", { "dependencies": { "@csstools/css-color-parser": "^4.1.1", "@csstools/css-parser-algorithms": "^4.0.0", "@csstools/css-tokenizer": "^4.0.0", "@csstools/postcss-progressive-custom-properties": "^5.1.0", "@csstools/utilities": "^3.0.0" }, "peerDependencies": { "postcss": "^8.4" } }, "sha512-i2lNJ6b4GdMoybHlpUM07TIk8KQRXTTe7Qf8LfctQhjDRTIgaodWTQqzWU4fpWO/nxBWNkSloDM22Lw/30NBcg=="],
|
||||
|
||||
"@csstools/postcss-cascade-layers": ["@csstools/[email protected]", "", { "dependencies": { "@csstools/selector-specificity": "^6.0.0", "postcss-selector-parser": "^7.1.1" }, "peerDependencies": { "postcss": "^8.4" } }, "sha512-WhsECqmrEZQGqaPlBA7JkmF/CJ2/+wetL4fkL9sOPccKd32PQ1qToFM6gqSI5rkpmYqubvbxjEJhyMTHYK0vZQ=="],
|
||||
|
||||
"@csstools/postcss-color-function": ["@csstools/[email protected].1", "", { "dependencies": { "@csstools/css-color-parser": "^4.0.1", "@csstools/css-parser-algorithms": "^4.0.0", "@csstools/css-tokenizer": "^4.0.0", "@csstools/postcss-progressive-custom-properties": "^5.0.0", "@csstools/utilities": "^3.0.0" }, "peerDependencies": { "postcss": "^8.4" } }, "sha512-SNU4o63+oZpB7ufkTmj3FholvMtJwuyIWqTOVOxnZjNDFEg1hwdbnPjoytZVgKRQGkvkHdAS0uZWn0zH+ZwXCQ=="],
|
||||
"@csstools/postcss-color-function": ["@csstools/[email protected].4", "", { "dependencies": { "@csstools/css-color-parser": "^4.1.1", "@csstools/css-parser-algorithms": "^4.0.0", "@csstools/css-tokenizer": "^4.0.0", "@csstools/postcss-progressive-custom-properties": "^5.1.0", "@csstools/utilities": "^3.0.0" }, "peerDependencies": { "postcss": "^8.4" } }, "sha512-PhUu86ppxKcNHHqrJ43ZL1mYa2uHKGRoY0KPbZA9k8iOaanL3I+1zYqbgVumxj1UgNTDw5BE3BUQ1Dono6bD6g=="],
|
||||
|
||||
"@csstools/postcss-color-function-display-p3-linear": ["@csstools/[email protected].1", "", { "dependencies": { "@csstools/css-color-parser": "^4.0.1", "@csstools/css-parser-algorithms": "^4.0.0", "@csstools/css-tokenizer": "^4.0.0", "@csstools/postcss-progressive-custom-properties": "^5.0.0", "@csstools/utilities": "^3.0.0" }, "peerDependencies": { "postcss": "^8.4" } }, "sha512-blnzzMkMswoagp1u3JS1OiiTuQCW1F+lQEtlxu2BXhTUmEeKHhSgrrAceF7s4bwZOwKYbkxuw/FC9Ni/zxB7Xw=="],
|
||||
"@csstools/postcss-color-function-display-p3-linear": ["@csstools/[email protected].4", "", { "dependencies": { "@csstools/css-color-parser": "^4.1.1", "@csstools/css-parser-algorithms": "^4.0.0", "@csstools/css-tokenizer": "^4.0.0", "@csstools/postcss-progressive-custom-properties": "^5.1.0", "@csstools/utilities": "^3.0.0" }, "peerDependencies": { "postcss": "^8.4" } }, "sha512-xrGqSFj9pu6XbJYD4NNCxYK9WFbf0KMfXFaisnJezkIRDZCwefUB2azkU4Zr0dFmLtIb9LlshrSZ0be1/QVthQ=="],
|
||||
|
||||
"@csstools/postcss-color-mix-function": ["@csstools/[email protected].1", "", { "dependencies": { "@csstools/css-color-parser": "^4.0.1", "@csstools/css-parser-algorithms": "^4.0.0", "@csstools/css-tokenizer": "^4.0.0", "@csstools/postcss-progressive-custom-properties": "^5.0.0", "@csstools/utilities": "^3.0.0" }, "peerDependencies": { "postcss": "^8.4" } }, "sha512-B9XBCd8cmHVwnc5YTn2YVXOlNMTNwuPIpJQ87665vaNdfNorVWz8JhAAv7Vq0v66TA6htE7+QW0OidL/QV0tiA=="],
|
||||
"@csstools/postcss-color-mix-function": ["@csstools/[email protected].4", "", { "dependencies": { "@csstools/css-color-parser": "^4.1.1", "@csstools/css-parser-algorithms": "^4.0.0", "@csstools/css-tokenizer": "^4.0.0", "@csstools/postcss-progressive-custom-properties": "^5.1.0", "@csstools/utilities": "^3.0.0" }, "peerDependencies": { "postcss": "^8.4" } }, "sha512-zYS78MHBuih9f9qtPFcSvVXMKg9q/lNPeFJUjyw7+/W1VHRjubvs5MlzuC363UUeahAhrOvYdo2ZZhmlxZbj6w=="],
|
||||
|
||||
"@csstools/postcss-color-mix-variadic-function-arguments": ["@csstools/[email protected].1", "", { "dependencies": { "@csstools/css-color-parser": "^4.0.1", "@csstools/css-parser-algorithms": "^4.0.0", "@csstools/css-tokenizer": "^4.0.0", "@csstools/postcss-progressive-custom-properties": "^5.0.0", "@csstools/utilities": "^3.0.0" }, "peerDependencies": { "postcss": "^8.4" } }, "sha512-PV5nv9EHsEsvC5GlVqAHa1PznP/qZxFAIABImrkGJUbSoFUTwpnPch/dYSKw52CQ0aNnwCqMHoM29wDwmpVLqw=="],
|
||||
"@csstools/postcss-color-mix-variadic-function-arguments": ["@csstools/[email protected].4", "", { "dependencies": { "@csstools/css-color-parser": "^4.1.1", "@csstools/css-parser-algorithms": "^4.0.0", "@csstools/css-tokenizer": "^4.0.0", "@csstools/postcss-progressive-custom-properties": "^5.1.0", "@csstools/utilities": "^3.0.0" }, "peerDependencies": { "postcss": "^8.4" } }, "sha512-qlrABMEFPUqbCxX0aOsHcxQZo/8XgMqnEtqqtVUbdizcuTUtJyLdHike7hkoemwDspMSEotdIfRlUY4jhZaD+A=="],
|
||||
|
||||
"@csstools/postcss-content-alt-text": ["@csstools/postcss-content-alt-text@3.0.0", "", { "dependencies": { "@csstools/css-parser-algorithms": "^4.0.0", "@csstools/css-tokenizer": "^4.0.0", "@csstools/postcss-progressive-custom-properties": "^5.0.0", "@csstools/utilities": "^3.0.0" }, "peerDependencies": { "postcss": "^8.4" } }, "sha512-OHa+4aCcrJtHpPWB3zptScHwpS1TUbeLR4uO0ntIz0Su/zw9SoWkVu+tDMSySSAsNtNSI3kut4fTliFwIsrHxA=="],
|
||||
"@csstools/postcss-container-rule-prelude-list": ["@csstools/postcss-container-rule-prelude-list@1.0.1", "", { "dependencies": { "@csstools/css-parser-algorithms": "^4.0.0", "@csstools/css-tokenizer": "^4.0.0" }, "peerDependencies": { "postcss": "^8.4" } }, "sha512-c5qlevVGKHU+zDbVoUGSZl1Mw7Vl1gVRKv6cdIYnaoyM+9Ou23Ian0H5Gr2ZF+lsDWovPK03hOSAbkw6HS8aTg=="],
|
||||
|
||||
"@csstools/postcss-contrast-color-function": ["@csstools/postcss-contrast-color-function@3.0.1", "", { "dependencies": { "@csstools/css-color-parser": "^4.0.1", "@csstools/css-parser-algorithms": "^4.0.0", "@csstools/css-tokenizer": "^4.0.0", "@csstools/postcss-progressive-custom-properties": "^5.0.0", "@csstools/utilities": "^3.0.0" }, "peerDependencies": { "postcss": "^8.4" } }, "sha512-Zy2gyAPsUyoAUkmBjLbWcXJhglM+toBRpNegyJc/LTHpSpIbMKVmByGQ+VSw01E1Pov8Dk/fgEs9hd11xtGC8g=="],
|
||||
"@csstools/postcss-content-alt-text": ["@csstools/postcss-content-alt-text@3.0.1", "", { "dependencies": { "@csstools/css-parser-algorithms": "^4.0.0", "@csstools/css-tokenizer": "^4.0.0", "@csstools/postcss-progressive-custom-properties": "^5.1.0", "@csstools/utilities": "^3.0.0" }, "peerDependencies": { "postcss": "^8.4" } }, "sha512-mK5lCgzgV/ZC+LgnFy4rAQVMcXR6HsnX3D1+4Q5gshSQsst5TtcvHbxTdzKy1XTv09sNZHJX8CO4CEQF9zA4ug=="],
|
||||
|
||||
"@csstools/postcss-exponential-functions": ["@csstools/postcss-exponential-functions@3.0.0", "", { "dependencies": { "@csstools/css-calc": "^3.0.0", "@csstools/css-parser-algorithms": "^4.0.0", "@csstools/css-tokenizer": "^4.0.0" }, "peerDependencies": { "postcss": "^8.4" } }, "sha512-KCtnlZw1VrDCAbYxE44rUHONYAkjhh0/iS5T3L2K5OHuvoSEvxDjJO82pRwTmsRxVtSiC+syPjx2k2xsqHOM7w=="],
|
||||
"@csstools/postcss-contrast-color-function": ["@csstools/postcss-contrast-color[email protected].4", "", { "dependencies": { "@csstools/css-color-parser": "^4.1.1", "@csstools/css-parser-algorithms": "^4.0.0", "@csstools/css-tokenizer": "^4.0.0", "@csstools/postcss-progressive-custom-properties": "^5.1.0", "@csstools/utilities": "^3.0.0" }, "peerDependencies": { "postcss": "^8.4" } }, "sha512-EiTZzUICztGqEuYg8AVCUWH9vH2jDzO6RryxMja+PWluZHP6n3/iG6i1leTt5LiDQjDUQlCRbQtMNj7V7S+b4Q=="],
|
||||
|
||||
"@csstools/postcss-exponential-functions": ["@csstools/[email protected]", "", { "dependencies": { "@csstools/css-calc": "^3.2.1", "@csstools/css-parser-algorithms": "^4.0.0", "@csstools/css-tokenizer": "^4.0.0" }, "peerDependencies": { "postcss": "^8.4" } }, "sha512-mB/NoeHLBHh0LZiVSrFdRDA/NxSfmg4tSN9117IJH9bdC2BzSTVgc82h3Gu/sdBXay6kDH2sA7fbkTigMiEi2A=="],
|
||||
|
||||
"@csstools/postcss-font-format-keywords": ["@csstools/[email protected]", "", { "dependencies": { "@csstools/utilities": "^3.0.0", "postcss-value-parser": "^4.2.0" }, "peerDependencies": { "postcss": "^8.4" } }, "sha512-M1EjCe/J3u8fFhOZgRci74cQhJ7R0UFBX6T+WqoEvjrr8hVfMiV+HTYrzxLY5OW8YllvXYr5Q5t5OvJbsUSeDg=="],
|
||||
|
||||
"@csstools/postcss-gamut-mapping": ["@csstools/postcss-gamut-mapping@3.0.1", "", { "dependencies": { "@csstools/css-color-parser": "^4.0.1", "@csstools/css-parser-algorithms": "^4.0.0", "@csstools/css-tokenizer": "^4.0.0" }, "peerDependencies": { "postcss": "^8.4" } }, "sha512-0S7D+gArVXsgRDxjoNv8g2QlaIi/SegqdlTMgVwowaPSyxaZsVnwrhShvmlpoLOVHmpJfHKGiXzn1Hc1BcZCzQ=="],
|
||||
"@csstools/postcss-font-width-property": ["@csstools/postcss-font-width-property@1.0.0", "", { "dependencies": { "@csstools/utilities": "^3.0.0" }, "peerDependencies": { "postcss": "^8.4" } }, "sha512-AvmySApdijbjYQuXXh95tb7iVnqZBbJrv3oajO927ksE/mDmJBiszm+psW8orL2lRGR8j6ZU5Uv9/ou2Z5KRKA=="],
|
||||
|
||||
"@csstools/postcss-gradients-interpolation-method": ["@csstools/postcss-gradients-interpolation-method@6.0.1", "", { "dependencies": { "@csstools/css-color-parser": "^4.0.1", "@csstools/css-parser-algorithms": "^4.0.0", "@csstools/css-tokenizer": "^4.0.0", "@csstools/postcss-progressive-custom-properties": "^5.0.0", "@csstools/utilities": "^3.0.0" }, "peerDependencies": { "postcss": "^8.4" } }, "sha512-Y5dxOstuUCdmU1tuEB/EgKxDw+/DAZes4gQeitb/H0S5khmjT24CfbVa/l2ZelNCEEq9KjxqO2cjwDV2vqj62w=="],
|
||||
"@csstools/postcss-gamut-mapping": ["@csstools/postcss-gamut-mapping@3.0.4", "", { "dependencies": { "@csstools/css-color-parser": "^4.1.1", "@csstools/css-parser-algorithms": "^4.0.0", "@csstools/css-tokenizer": "^4.0.0" }, "peerDependencies": { "postcss": "^8.4" } }, "sha512-2dWGsxtxypKU9Ra862F2335W8xegRwl9ohQ6hk808PiQlEahSaFtt5fqsGmKDaSiaFUx+2X8GZxVo970Ajr2vQ=="],
|
||||
|
||||
"@csstools/postcss-hwb-function": ["@csstools/postcss-hwb-function@5.0.1", "", { "dependencies": { "@csstools/css-color-parser": "^4.0.1", "@csstools/css-parser-algorithms": "^4.0.0", "@csstools/css-tokenizer": "^4.0.0", "@csstools/postcss-progressive-custom-properties": "^5.0.0", "@csstools/utilities": "^3.0.0" }, "peerDependencies": { "postcss": "^8.4" } }, "sha512-9f8TA/B8iEpzF0y4Z6qPVfP9nMp2ti10OFbtyDtoBz3+eK0KPV4CCCjTwYIpPRopLgctFZt7xqmOxA7JgAJEug=="],
|
||||
"@csstools/postcss-gradients-interpolation-method": ["@csstools/postcss-gradients-interpolation-method@6.0.4", "", { "dependencies": { "@csstools/css-color-parser": "^4.1.1", "@csstools/css-parser-algorithms": "^4.0.0", "@csstools/css-tokenizer": "^4.0.0", "@csstools/postcss-progressive-custom-properties": "^5.1.0", "@csstools/utilities": "^3.0.0" }, "peerDependencies": { "postcss": "^8.4" } }, "sha512-sC/7dqVTtQTniLjPp/NagzeUn4sGinnMTicNBLDzirKq/GNXuJaApBOnvBmgNXjV6XPizfMhNRYCk5stn3q2nQ=="],
|
||||
|
||||
"@csstools/postcss-ic-unit": ["@csstools/postcss-ic-unit@5.0.0", "", { "dependencies": { "@csstools/postcss-progressive-custom-properties": "^5.0.0", "@csstools/utilities": "^3.0.0", "postcss-value-parser": "^4.2.0" }, "peerDependencies": { "postcss": "^8.4" } }, "sha512-/ws5d6c4uKqfM9zIL3ugcGI+3fvZEOOkJHNzAyTAGJIdZ+aSL9BVPNlHGV4QzmL0vqBSCOdU3+rhcMEj3+KzYw=="],
|
||||
"@csstools/postcss-hwb-function": ["@csstools/postcss-hwb-function@5.0.4", "", { "dependencies": { "@csstools/css-color-parser": "^4.1.1", "@csstools/css-parser-algorithms": "^4.0.0", "@csstools/css-tokenizer": "^4.0.0", "@csstools/postcss-progressive-custom-properties": "^5.1.0", "@csstools/utilities": "^3.0.0" }, "peerDependencies": { "postcss": "^8.4" } }, "sha512-cl0KPaaeYyAXNHO3pqK8adbpbAGmIU1cT1thyaEkmP8yvbJvmyztkpdGADGqziUUoh4dZQ0IhHxOxnKQ296T+A=="],
|
||||
|
||||
"@csstools/postcss-ic-unit": ["@csstools/[email protected]", "", { "dependencies": { "@csstools/postcss-progressive-custom-properties": "^5.1.0", "@csstools/utilities": "^3.0.0", "postcss-value-parser": "^4.2.0" }, "peerDependencies": { "postcss": "^8.4" } }, "sha512-jmsVLXPdMBTlaJAhiEijhIR3qL0j75MrlRfhJEs91DF1Wlt2kpJTDsbpXQpYFzn1nPFHZC/WEf+Mw0I/HXkHzQ=="],
|
||||
|
||||
"@csstools/postcss-image-function": ["@csstools/[email protected]", "", { "dependencies": { "@csstools/css-parser-algorithms": "^4.0.0", "@csstools/css-tokenizer": "^4.0.0", "@csstools/postcss-progressive-custom-properties": "^5.1.0", "@csstools/utilities": "^3.0.0" }, "peerDependencies": { "postcss": "^8.4" } }, "sha512-iuQztV6Cfeuc7NczazfickrzEhALOpxUS0yWgGkmRY1zZ0CKjBBFc/7WWSN9qupfpNAzHY7cPNcJCqUhtr+YMw=="],
|
||||
|
||||
"@csstools/postcss-initial": ["@csstools/[email protected]", "", { "peerDependencies": { "postcss": "^8.4" } }, "sha512-UVUrFmrTQyLomVepnjWlbBg7GoscLmXLwYFyjbcEnmpeGW7wde6lNpx5eM3eVwZI2M+7hCE3ykYnAsEPLcLa+Q=="],
|
||||
|
||||
"@csstools/postcss-is-pseudo-class": ["@csstools/[email protected]", "", { "dependencies": { "@csstools/selector-specificity": "^6.0.0", "postcss-selector-parser": "^7.1.1" }, "peerDependencies": { "postcss": "^8.4" } }, "sha512-1Hdy/ykg9RDo8vU8RiM2o+RaXO39WpFPaIkHxlAEJFofle/lc33tdQMKhBk3jR/Fe+uZNLOs3HlowFafyFptVw=="],
|
||||
|
||||
"@csstools/postcss-light-dark-function": ["@csstools/[email protected].0", "", { "dependencies": { "@csstools/css-parser-algorithms": "^4.0.0", "@csstools/css-tokenizer": "^4.0.0", "@csstools/postcss-progressive-custom-properties": "^5.0.0", "@csstools/utilities": "^3.0.0" }, "peerDependencies": { "postcss": "^8.4" } }, "sha512-s++V5/hYazeRUCYIn2lsBVzUsxdeC46gtwpgW6lu5U/GlPOS5UTDT14kkEyPgXmFbCvaWLREqV7YTMJq1K3G6w=="],
|
||||
"@csstools/postcss-light-dark-function": ["@csstools/[email protected].1", "", { "dependencies": { "@csstools/css-parser-algorithms": "^4.0.0", "@csstools/css-tokenizer": "^4.0.0", "@csstools/postcss-progressive-custom-properties": "^5.1.0", "@csstools/utilities": "^3.0.0" }, "peerDependencies": { "postcss": "^8.4" } }, "sha512-tD2MMJmZ6XXCHgDythLHcXQDNi5z7KEEWPe7JeB3vPcw+YMuMabpW5ugRqndhIrui+vduhc0Md7f7yGPCmOErg=="],
|
||||
|
||||
"@csstools/postcss-logical-float-and-clear": ["@csstools/[email protected]", "", { "peerDependencies": { "postcss": "^8.4" } }, "sha512-NGzdIRVj/VxOa/TjVdkHeyiJoDihONV0+uB0csUdgWbFFr8xndtfqK8iIGP9IKJzco+w0hvBF2SSk2sDSTAnOQ=="],
|
||||
|
||||
@@ -531,7 +538,7 @@
|
||||
|
||||
"@csstools/postcss-logical-viewport-units": ["@csstools/[email protected]", "", { "dependencies": { "@csstools/css-tokenizer": "^4.0.0", "@csstools/utilities": "^3.0.0" }, "peerDependencies": { "postcss": "^8.4" } }, "sha512-TA3AqVN/1IH3dKRC2UUWvprvwyOs2IeD7FDZk5Hz20w4q33yIuSg0i0gjyTUkcn90g8A4n7QpyZ2AgBrnYPnnA=="],
|
||||
|
||||
"@csstools/postcss-media-minmax": ["@csstools/[email protected].0", "", { "dependencies": { "@csstools/css-calc": "^3.0.0", "@csstools/css-parser-algorithms": "^4.0.0", "@csstools/css-tokenizer": "^4.0.0", "@csstools/media-query-list-parser": "^5.0.0" }, "peerDependencies": { "postcss": "^8.4" } }, "sha512-42szvyZ/oqG7NSvBQOGq1IaJaHR6mr/iXqqjW8/JuIajIHRs9HcJR5ExC4vbyCqk+fr7/DIOhm5ZrELBytLDsw=="],
|
||||
"@csstools/postcss-media-minmax": ["@csstools/[email protected].3", "", { "dependencies": { "@csstools/css-calc": "^3.2.1", "@csstools/css-parser-algorithms": "^4.0.0", "@csstools/css-tokenizer": "^4.0.0", "@csstools/media-query-list-parser": "^5.0.0" }, "peerDependencies": { "postcss": "^8.4" } }, "sha512-ch1tNS+1QayiHTGsyc53zv3AzrSd0zigjbkfLxoeuzzJyn32+P3V7em3u5vLVnqLMzBbEZK//GI13EVTIPRdDA=="],
|
||||
|
||||
"@csstools/postcss-media-queries-aspect-ratio-number-values": ["@csstools/[email protected]", "", { "dependencies": { "@csstools/css-parser-algorithms": "^4.0.0", "@csstools/css-tokenizer": "^4.0.0", "@csstools/media-query-list-parser": "^5.0.0" }, "peerDependencies": { "postcss": "^8.4" } }, "sha512-FDdC3lbrj8Vr0SkGIcSLTcRB7ApG6nlJFxOxkEF2C5hIZC1jtgjISFSGn/WjFdVkn8Dqe+Vx9QXI3axS2w1XHw=="],
|
||||
|
||||
@@ -541,31 +548,31 @@
|
||||
|
||||
"@csstools/postcss-normalize-display-values": ["@csstools/[email protected]", "", { "dependencies": { "postcss-value-parser": "^4.2.0" }, "peerDependencies": { "postcss": "^8.4" } }, "sha512-FcbEmoxDEGYvm2W3rQzVzcuo66+dDJjzzVDs+QwRmZLHYofGmMGwIKPqzF86/YW+euMDa7sh1xjWDvz/fzByZQ=="],
|
||||
|
||||
"@csstools/postcss-oklab-function": ["@csstools/[email protected].1", "", { "dependencies": { "@csstools/css-color-parser": "^4.0.1", "@csstools/css-parser-algorithms": "^4.0.0", "@csstools/css-tokenizer": "^4.0.0", "@csstools/postcss-progressive-custom-properties": "^5.0.0", "@csstools/utilities": "^3.0.0" }, "peerDependencies": { "postcss": "^8.4" } }, "sha512-Ql+X4zu29ITihxHKcCFEU84ww+Nkv44M2s0fT7Nv4iQYlQ4+liF6v9RL0ezeogeiLRNLLC6yh0ay1PHpmaNIgQ=="],
|
||||
"@csstools/postcss-oklab-function": ["@csstools/[email protected].4", "", { "dependencies": { "@csstools/css-color-parser": "^4.1.1", "@csstools/css-parser-algorithms": "^4.0.0", "@csstools/css-tokenizer": "^4.0.0", "@csstools/postcss-progressive-custom-properties": "^5.1.0", "@csstools/utilities": "^3.0.0" }, "peerDependencies": { "postcss": "^8.4" } }, "sha512-vIgrKe5ffW99it5SUIXOBczGLSiTaHBhU6afVr9KPwoZ4uq9H0E3Ehvi+xsUjmvnAyMTxOUSszNo04kEhbvYjQ=="],
|
||||
|
||||
"@csstools/postcss-position-area-property": ["@csstools/[email protected]", "", { "peerDependencies": { "postcss": "^8.4" } }, "sha512-TeEfzsJGB23Syv7yCm8AHCD2XTFujdjr9YYu9ebH64vnfCEvY4BG319jXAYSlNlf3Yc9PNJ6WnkDkUF5XVgSKQ=="],
|
||||
|
||||
"@csstools/postcss-progressive-custom-properties": ["@csstools/postcss-progressive-custom-properties@5.0.0", "", { "dependencies": { "postcss-value-parser": "^4.2.0" }, "peerDependencies": { "postcss": "^8.4" } }, "sha512-NsJoZ89rxmDrUsITf8QIk5w+lQZQ8Xw5K6cLFG+cfiffsLYHb3zcbOOrHLetGl1WIhjWWQ4Cr8MMrg46Q+oACg=="],
|
||||
"@csstools/postcss-progressive-custom-properties": ["@csstools/postcss-progressive-custom-properties@5.1.0", "", { "dependencies": { "postcss-value-parser": "^4.2.0" }, "peerDependencies": { "postcss": "^8.4" } }, "sha512-lt/4yHy2GdKcGVpK4OGhBdSIq+z2PXynSusSRggn/T4y7uFurYAhdHqo/aYM+xI37vNb8rJlEKchqKKvVCXROQ=="],
|
||||
|
||||
"@csstools/postcss-property-rule-prelude-list": ["@csstools/[email protected]", "", { "dependencies": { "@csstools/css-parser-algorithms": "^4.0.0", "@csstools/css-tokenizer": "^4.0.0" }, "peerDependencies": { "postcss": "^8.4" } }, "sha512-qcMAkc9AhpzHgmQCD8hoJgGYifcOAxd1exXjjxilMM6euwRE619xDa4UsKBCv/v4g+sS63sd6c29LPM8s2ylSQ=="],
|
||||
|
||||
"@csstools/postcss-random-function": ["@csstools/[email protected].0", "", { "dependencies": { "@csstools/css-calc": "^3.0.0", "@csstools/css-parser-algorithms": "^4.0.0", "@csstools/css-tokenizer": "^4.0.0" }, "peerDependencies": { "postcss": "^8.4" } }, "sha512-H/Zt5o9NAd8mowq3XRy8uU19wOEe8sbKyKOKxrzOdG0rz2maA4fLcXc9MQucdm3s4zMDfVJtCqvwrLP7lKWybA=="],
|
||||
"@csstools/postcss-random-function": ["@csstools/[email protected].3", "", { "dependencies": { "@csstools/css-calc": "^3.2.1", "@csstools/css-parser-algorithms": "^4.0.0", "@csstools/css-tokenizer": "^4.0.0" }, "peerDependencies": { "postcss": "^8.4" } }, "sha512-0EScyKxscGonwpi30Hj9DEAr0X8D2eDhOqqayQXE91gIqGli9UT+deLYqoogZLOy5GT+ncqltMqztc/q+0UkhA=="],
|
||||
|
||||
"@csstools/postcss-relative-color-syntax": ["@csstools/[email protected].1", "", { "dependencies": { "@csstools/css-color-parser": "^4.0.1", "@csstools/css-parser-algorithms": "^4.0.0", "@csstools/css-tokenizer": "^4.0.0", "@csstools/postcss-progressive-custom-properties": "^5.0.0", "@csstools/utilities": "^3.0.0" }, "peerDependencies": { "postcss": "^8.4" } }, "sha512-zRLO9xMGtCCT0FTpTsaGI6cmdzJKbwWjg92AuczlSDuriEAPEJL+ZJ4jDyw51p23DfoAFgK8soB/LyoY1kFOLQ=="],
|
||||
"@csstools/postcss-relative-color-syntax": ["@csstools/[email protected].4", "", { "dependencies": { "@csstools/css-color-parser": "^4.1.1", "@csstools/css-parser-algorithms": "^4.0.0", "@csstools/css-tokenizer": "^4.0.0", "@csstools/postcss-progressive-custom-properties": "^5.1.0", "@csstools/utilities": "^3.0.0" }, "peerDependencies": { "postcss": "^8.4" } }, "sha512-reFFKD9eS602We8621e5cAroKD7hH4104duLNBBhzwawGN7dhbnL1+c/DRHqwyq6eGK35HaKMMiifEZhAztlOA=="],
|
||||
|
||||
"@csstools/postcss-scope-pseudo-class": ["@csstools/[email protected]", "", { "dependencies": { "postcss-selector-parser": "^7.1.1" }, "peerDependencies": { "postcss": "^8.4" } }, "sha512-kBrBFJcAji3MSHS4qQIihPvJfJC5xCabXLbejqDMiQi+86HD4eMBiTayAo46Urg7tlEmZZQFymFiJt+GH6nvXw=="],
|
||||
|
||||
"@csstools/postcss-sign-functions": ["@csstools/[email protected].0", "", { "dependencies": { "@csstools/css-calc": "^3.0.0", "@csstools/css-parser-algorithms": "^4.0.0", "@csstools/css-tokenizer": "^4.0.0" }, "peerDependencies": { "postcss": "^8.4" } }, "sha512-32Bw7++8ToSLMEOSJUuxJsAJJdsIfgeD1dYPKRCk9/fTciVZ8MjkPXypwiXIo7xIJk0h5CJz6QUkDoc6dcAJ7Q=="],
|
||||
"@csstools/postcss-sign-functions": ["@csstools/[email protected].3", "", { "dependencies": { "@csstools/css-calc": "^3.2.1", "@csstools/css-parser-algorithms": "^4.0.0", "@csstools/css-tokenizer": "^4.0.0" }, "peerDependencies": { "postcss": "^8.4" } }, "sha512-2BCPwlpeQweTC/8S8oQFYhYD5kxYkiroLf3AUJV2kVoKkSZ+4WM4rSwySXlKrqXL8HfCryAwVrJg7B0jr/RnOw=="],
|
||||
|
||||
"@csstools/postcss-stepped-value-functions": ["@csstools/[email protected].0", "", { "dependencies": { "@csstools/css-calc": "^3.0.0", "@csstools/css-parser-algorithms": "^4.0.0", "@csstools/css-tokenizer": "^4.0.0" }, "peerDependencies": { "postcss": "^8.4" } }, "sha512-NueCSNbaq7QtAj6QwseMqOlM3C8nN2GWaPwd2Uw+IOYAbGvO/84BxUtNeZljeOmqJX61hwSNhLfwmgJXgY0W5A=="],
|
||||
"@csstools/postcss-stepped-value-functions": ["@csstools/[email protected].3", "", { "dependencies": { "@csstools/css-calc": "^3.2.1", "@csstools/css-parser-algorithms": "^4.0.0", "@csstools/css-tokenizer": "^4.0.0" }, "peerDependencies": { "postcss": "^8.4" } }, "sha512-nXMFQBz5Pi2LLG02iqm2k+scrqwtqJT9ta/gN8S79oBZ23M0E7O3wDJ20//3z5Q6HU5e+K0n+SmmxN6iWtbm6w=="],
|
||||
|
||||
"@csstools/postcss-syntax-descriptor-syntax-production": ["@csstools/[email protected]", "", { "dependencies": { "@csstools/css-tokenizer": "^4.0.0" }, "peerDependencies": { "postcss": "^8.4" } }, "sha512-elYcbdiBXAkPqvojB9kIBRuHY6htUhjSITtFQ+XiXnt6SvZCbNGxQmaaw6uZ7SPHu/+i/XVjzIt09/1k3SIerQ=="],
|
||||
|
||||
"@csstools/postcss-system-ui-font-family": ["@csstools/[email protected]", "", { "dependencies": { "@csstools/css-parser-algorithms": "^4.0.0", "@csstools/css-tokenizer": "^4.0.0" }, "peerDependencies": { "postcss": "^8.4" } }, "sha512-FyGZCgchFImFyiHS2x3rD5trAqatf/x23veBLTIgbaqyFfna6RNBD+Qf8HRSjt6HGMXOLhAjxJ3OoZg0bbn7Qw=="],
|
||||
|
||||
"@csstools/postcss-text-decoration-shorthand": ["@csstools/[email protected].2", "", { "dependencies": { "@csstools/color-helpers": "^6.0.1", "postcss-value-parser": "^4.2.0" }, "peerDependencies": { "postcss": "^8.4" } }, "sha512-0VUTt79lfQ2LGQLfyOBeqpinDLzOf3w+tlA1Re/KjSOc86H6tRz6TeXbISrBSJlfM1fYKNmBNw+ON8Ovy6aNeg=="],
|
||||
"@csstools/postcss-text-decoration-shorthand": ["@csstools/[email protected].3", "", { "dependencies": { "@csstools/color-helpers": "^6.0.2", "postcss-value-parser": "^4.2.0" }, "peerDependencies": { "postcss": "^8.4" } }, "sha512-62fjggvIM1YYfDJPcErMUDkEZB6CByG8neTJqexnZe1hRBgCjD4dnXDLoCSSurjs1LzjBq6irFDpDaOvDZfrlw=="],
|
||||
|
||||
"@csstools/postcss-trigonometric-functions": ["@csstools/[email protected].0", "", { "dependencies": { "@csstools/css-calc": "^3.0.0", "@csstools/css-parser-algorithms": "^4.0.0", "@csstools/css-tokenizer": "^4.0.0" }, "peerDependencies": { "postcss": "^8.4" } }, "sha512-isjkD3l1MVjanGuaS7RIYP/9txZKbZ8eQPaUHoxEWmySm3k6KutSepzPINL6MXyyi0ZUijZcktA++/L66IK71A=="],
|
||||
"@csstools/postcss-trigonometric-functions": ["@csstools/[email protected].3", "", { "dependencies": { "@csstools/css-calc": "^3.2.1", "@csstools/css-parser-algorithms": "^4.0.0", "@csstools/css-tokenizer": "^4.0.0" }, "peerDependencies": { "postcss": "^8.4" } }, "sha512-p9LTvLj+DFpl5RHbG/X9QGwg7BoMOBsRBZqsUAKKVvCw7MRCsk1P1llTUR/MW5nyZ4IsjFGDtDwTTj1reJjxvg=="],
|
||||
|
||||
"@csstools/postcss-unset-value": ["@csstools/[email protected]", "", { "peerDependencies": { "postcss": "^8.4" } }, "sha512-EoO54sS2KCIfesvHyFYAW99RtzwHdgaJzhl7cqKZSaMYKZv3fXSOehDjAQx8WZBKn1JrMd7xJJI1T1BxPF7/jA=="],
|
||||
|
||||
@@ -675,11 +682,11 @@
|
||||
|
||||
"@fontsource-variable/roboto-flex": ["@fontsource-variable/[email protected]", "", {}, "sha512-Q9zbz+P2VrDeIxBu9YAIG+eYpLmQF5FIJEEwAWn8En9Lao1TOISnoYcywGV+jSv7LGsHEndCR8hveXPnvCBEQQ=="],
|
||||
|
||||
"@fontsource-variable/roboto-mono": ["@fontsource-variable/[email protected].8", "", {}, "sha512-6M2U3wGIUxYNKRrUoKls8BRRIPDA57T8J0agqwyDkiEHrLEEAqptsxcUl3eTm6tnRNEn6yEm4pCefvtnujebDA=="],
|
||||
"@fontsource-variable/roboto-mono": ["@fontsource-variable/[email protected].9", "", {}, "sha512-OzFO2AXlSGcXl/NcXS3CGjImb6rczCByPJ1C+Dzp9kkYOrUPyrGTuAtqPcmA/d+nZGX5oyOWKXLk5BrwVLYqkw=="],
|
||||
|
||||
"@fontsource/inter": ["@fontsource/[email protected]", "", {}, "sha512-P6r5WnJoKiNVV+zvW2xM13gNdFhAEpQ9dQJHt3naLvfg+LkF2ldgSLiF4T41lf1SQCM9QmkqPTn4TH568IRagg=="],
|
||||
|
||||
"@gltf-transform/core": ["@gltf-transform/core@4.3.0", "", { "dependencies": { "property-graph": "^4.0.0" } }, "sha512-ZeaQfszGJ9LYwELszu45CuDQCsE26lJNNe36FVmN8xclaT6WDdCj7fwGpQXo0/l/YgAVAHX+uO7YNBW75/SRYw=="],
|
||||
"@gltf-transform/core": ["@gltf-transform/core@4.4.0", "", { "dependencies": { "property-graph": "^4.1.0" } }, "sha512-cOPxOhHFFz5hwmix+li1+Nnq5qMV/QD3fTCsVlApxxFACtFdjkt2R/juseD4gvZ7D2c/yl6OilKH0pvI735YyQ=="],
|
||||
|
||||
"@gltf-transform/extensions": ["@gltf-transform/[email protected]", "", { "dependencies": { "@gltf-transform/core": "^4.3.0", "ktx-parse": "^1.0.1" } }, "sha512-XDAjQPYVMHa/VDpSbfCBwI+/1muwRJCaXhUpLgnUzAjn0D//PgvIAcbNm1EwBl3LIWBSwjDUCn2LiMAjp+aXVw=="],
|
||||
|
||||
@@ -1003,7 +1010,7 @@
|
||||
|
||||
"@react-three/drei": ["@react-three/[email protected]", "", { "dependencies": { "@babel/runtime": "^7.26.0", "@mediapipe/tasks-vision": "0.10.17", "@monogrid/gainmap-js": "^3.0.6", "@use-gesture/react": "^10.3.1", "camera-controls": "^3.1.0", "cross-env": "^7.0.3", "detect-gpu": "^5.0.56", "glsl-noise": "^0.0.0", "hls.js": "^1.5.17", "maath": "^0.10.8", "meshline": "^3.3.1", "stats-gl": "^2.2.8", "stats.js": "^0.17.0", "suspend-react": "^0.1.3", "three-mesh-bvh": "^0.8.3", "three-stdlib": "^2.35.6", "troika-three-text": "^0.52.4", "tunnel-rat": "^0.1.2", "use-sync-external-store": "^1.4.0", "utility-types": "^3.11.0", "zustand": "^5.0.1" }, "peerDependencies": { "@react-three/fiber": "^9.0.0", "react": "^19", "react-dom": "^19", "three": ">=0.159" }, "optionalPeers": ["react-dom"] }, "sha512-ff+J5iloR0k4tC++QtD/j9u3w5fzfgFAWDtAGQah9pF2B1YgOq/5JxqY0/aVoQG5r3xSZz0cv5tk2YuBob4xEQ=="],
|
||||
|
||||
"@react-three/fiber": ["@react-three/fiber@9.5.0", "", { "dependencies": { "@babel/runtime": "^7.17.8", "@types/webxr": "*", "base64-js": "^1.5.1", "buffer": "^6.0.3", "its-fine": "^2.0.0", "react-use-measure": "^2.1.7", "scheduler": "^0.27.0", "suspend-react": "^0.1.3", "use-sync-external-store": "^1.4.0", "zustand": "^5.0.3" }, "peerDependencies": { "expo": ">=43.0", "expo-asset": ">=8.4", "expo-file-system": ">=11.0", "expo-gl": ">=11.0", "react": ">=19 <19.3", "react-dom": ">=19 <19.3", "react-native": ">=0.78", "three": ">=0.156" }, "optionalPeers": ["expo", "expo-asset", "expo-file-system", "expo-gl", "react-dom", "react-native"] }, "sha512-FiUzfYW4wB1+PpmsE47UM+mCads7j2+giRBltfwH7SNhah95rqJs3ltEs9V3pP8rYdS0QlNne+9Aj8dS/SiaIA=="],
|
||||
"@react-three/fiber": ["@react-three/fiber@9.6.1", "", { "dependencies": { "@babel/runtime": "^7.17.8", "@types/webxr": "*", "base64-js": "^1.5.1", "buffer": "^6.0.3", "its-fine": "^2.0.0", "react-use-measure": "^2.1.7", "scheduler": "^0.27.0", "suspend-react": "^0.1.3", "use-sync-external-store": "^1.4.0", "zustand": "^5.0.3" }, "peerDependencies": { "expo": ">=43.0", "expo-asset": ">=8.4", "expo-file-system": ">=11.0", "expo-gl": ">=11.0", "react": ">=19 <19.3", "react-dom": ">=19 <19.3", "react-native": ">=0.78", "three": ">=0.156" }, "optionalPeers": ["expo", "expo-asset", "expo-file-system", "expo-gl", "react-dom", "react-native"] }, "sha512-zF0rsKcVYpcJwbFEnv2HkHX9cvOEgsfQo/X8lwmR2dn13S4qEQJXir9fxf5js2LQFoXqxOY7MDkOkYx2uZ4gSg=="],
|
||||
|
||||
"@resvg/resvg-js": ["@resvg/[email protected]", "", { "optionalDependencies": { "@resvg/resvg-js-android-arm-eabi": "2.6.2", "@resvg/resvg-js-android-arm64": "2.6.2", "@resvg/resvg-js-darwin-arm64": "2.6.2", "@resvg/resvg-js-darwin-x64": "2.6.2", "@resvg/resvg-js-linux-arm-gnueabihf": "2.6.2", "@resvg/resvg-js-linux-arm64-gnu": "2.6.2", "@resvg/resvg-js-linux-arm64-musl": "2.6.2", "@resvg/resvg-js-linux-x64-gnu": "2.6.2", "@resvg/resvg-js-linux-x64-musl": "2.6.2", "@resvg/resvg-js-win32-arm64-msvc": "2.6.2", "@resvg/resvg-js-win32-ia32-msvc": "2.6.2", "@resvg/resvg-js-win32-x64-msvc": "2.6.2" } }, "sha512-xBaJish5OeGmniDj9cW5PRa/PtmuVU3ziqrbr5xJj901ZDN4TosrVaNZpEiLZAxdfnhAe7uQ7QFWfjPe9d9K2Q=="],
|
||||
|
||||
@@ -1221,7 +1228,7 @@
|
||||
|
||||
"@types/steamid": ["@types/[email protected]", "", {}, "sha512-LC0oaiNq3gqMI18MV935CnlyHmDooKRszK56jHv0+b7EbJwf5k++YsD52zWeJUD8nuYqP9LpIgpXGiYBOxpcYQ=="],
|
||||
|
||||
"@types/three": ["@types/[email protected]0.0", "", { "dependencies": { "@dimforge/rapier3d-compat": "~0.12.0", "@tweenjs/tween.js": "~23.1.3", "@types/stats.js": "*", "@types/webxr": "*", "@webgpu/types": "*", "fflate": "~0.8.2", "meshoptimizer": "~0.22.0" } }, "sha512-ykFtgCqNnY0IPvDro7h+9ZeLY+qjgUWv+qEvUt84grhenO60Hqd4hScHE7VTB9nOQ/3QM8lkbNE+4vKjEpUxKg=="],
|
||||
"@types/three": ["@types/[email protected]4.1", "", { "dependencies": { "@dimforge/rapier3d-compat": "~0.12.0", "@tweenjs/tween.js": "~23.1.3", "@types/stats.js": "*", "@types/webxr": ">=0.5.17", "fflate": "~0.8.2", "meshoptimizer": "~1.1.1" } }, "sha512-6q4VdiqVsrTRqmk62/BnlcAvIrnDM0zf2ZDVKI5kZiniWrSaOHaQzmbp+BNzoggc/8tgW412pL//wZIxu2PPTA=="],
|
||||
|
||||
"@types/trusted-types": ["@types/[email protected]", "", {}, "sha512-ScaPdn1dQczgbl0QFTeTOmVHFULt394XJgOQNoyVhZ6r2vLnMLJfBPd53SB52T/3G36VI1/g2MZaX0cwDuXsfw=="],
|
||||
|
||||
@@ -1311,7 +1318,7 @@
|
||||
|
||||
"at-least-node": ["[email protected]", "", {}, "sha512-+q/t7Ekv1EDY2l6Gda6LLiX14rU9TV20Wa3ofeQmwPFZbOMo9DXrLbOjFaaclkXKWidIaopwAObQDqwWtGUjqg=="],
|
||||
|
||||
"autoprefixer": ["autoprefixer@10.4.24", "", { "dependencies": { "browserslist": "^4.28.1", "caniuse-lite": "^1.0.30001766", "fraction.js": "^5.3.4", "picocolors": "^1.1.1", "postcss-value-parser": "^4.2.0" }, "peerDependencies": { "postcss": "^8.1.0" }, "bin": { "autoprefixer": "bin/autoprefixer" } }, "sha512-uHZg7N9ULTVbutaIsDRoUkoS8/h3bdsmVJYZ5l3wv8Cp/6UIIoRDm90hZ+BwxUj/hGBEzLxdHNSKuFpn8WOyZw=="],
|
||||
"autoprefixer": ["autoprefixer@10.5.0", "", { "dependencies": { "browserslist": "^4.28.2", "caniuse-lite": "^1.0.30001787", "fraction.js": "^5.3.4", "picocolors": "^1.1.1", "postcss-value-parser": "^4.2.0" }, "peerDependencies": { "postcss": "^8.1.0" }, "bin": { "autoprefixer": "bin/autoprefixer" } }, "sha512-FMhOoZV4+qR6aTUALKX2rEqGG+oyATvwBt9IIzVR5rMa2HRWPkxf+P+PAJLD1I/H5/II+HuZcBJYEFBpq39ong=="],
|
||||
|
||||
"available-typed-arrays": ["[email protected]", "", { "dependencies": { "possible-typed-array-names": "^1.0.0" } }, "sha512-wvUjBtSGN7+7SjNpq/9M2Tg350UZD3q62IFZLbRAR1bSMlCo1ZaeW+BJ+D090e4hIIZLBcTDWe4Mh4jvUDajzQ=="],
|
||||
|
||||
@@ -1347,7 +1354,7 @@
|
||||
|
||||
"base64-js": ["[email protected]", "", {}, "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA=="],
|
||||
|
||||
"baseline-browser-mapping": ["baseline-browser-mapping@2.9.19", "", { "bin": { "baseline-browser-mapping": "dist/cli.js" } }, "sha512-ipDqC8FrAl/76p2SSWKSI+H9tFwm7vYqXQrItCuiVPt26Km0jS+NzSsBWAaBusvSbQcfJG+JitdMm+wZAgTYqg=="],
|
||||
"baseline-browser-mapping": ["baseline-browser-mapping@2.10.32", "", { "bin": { "baseline-browser-mapping": "dist/cli.cjs" } }, "sha512-wbPvpyjJPC0zdfdKXxqEL3Ea+bOMD/87X4lftiJkkaBiuG6ALQy1SLmEd7BSmVCuwCQsBrCamgBoLyfFDD1EPg=="],
|
||||
|
||||
"basic-ftp": ["[email protected]", "", {}, "sha512-RkaJzeJKDbaDWTIPiJwubyljaEPwpVWkm9Rt5h9Nd6h7tEXTJ3VB4qxdZBioV7JO5yLUaOKwz7vDOzlncUsegw=="],
|
||||
|
||||
@@ -1373,7 +1380,7 @@
|
||||
|
||||
"brace-expansion": ["[email protected]", "", { "dependencies": { "balanced-match": "^4.0.2" } }, "sha512-Pdk8c9poy+YhOgVWw1JNN22/HcivgKWwpxKq04M/jTmHyCZn12WPJebZxdjSa5TmBqISrUSgNYU3eRORljfCCw=="],
|
||||
|
||||
"browserslist": ["[email protected].1", "", { "dependencies": { "baseline-browser-mapping": "^2.9.0", "caniuse-lite": "^1.0.30001759", "electron-to-chromium": "^1.5.263", "node-releases": "^2.0.27", "update-browserslist-db": "^1.2.0" }, "bin": { "browserslist": "cli.js" } }, "sha512-ZC5Bd0LgJXgwGqUknZY/vkUQ04r8NXnJZ3yYi4vDmSiZmC/pdSN0NbNRPxZpbtO4uAfDUAFffO8IZoM3Gj8IkA=="],
|
||||
"browserslist": ["[email protected].2", "", { "dependencies": { "baseline-browser-mapping": "^2.10.12", "caniuse-lite": "^1.0.30001782", "electron-to-chromium": "^1.5.328", "node-releases": "^2.0.36", "update-browserslist-db": "^1.2.3" }, "bin": { "browserslist": "cli.js" } }, "sha512-48xSriZYYg+8qXna9kwqjIVzuQxi+KYWp2+5nCYnYKPTr0LvD89Jqk2Or5ogxz0NUMfIjhh2lIUX/LyX9B4oIg=="],
|
||||
|
||||
"buffer": ["[email protected]", "", { "dependencies": { "base64-js": "^1.3.1", "ieee754": "^1.2.1" } }, "sha512-FTiCpNxtwiZZHEZbcbTIcZjERVICn9yq/pDFkTl95/AxzD1naBctN7YO68riM/gLSDY7sdrMby8hofADYuuqOA=="],
|
||||
|
||||
@@ -1411,7 +1418,7 @@
|
||||
|
||||
"caniuse-api": ["[email protected]", "", { "dependencies": { "browserslist": "^4.0.0", "caniuse-lite": "^1.0.0", "lodash.memoize": "^4.1.2", "lodash.uniq": "^4.5.0" } }, "sha512-bsTwuIg/BZZK/vreVTYYbSWoe2F+71P7K5QGEX+pT250DZbfU1MQ5prOKpPR+LL6uWKK3KMwMCAS74QB3Um1uw=="],
|
||||
|
||||
"caniuse-lite": ["[email protected]70", "", {}, "sha512-x/2CLQ1jHENRbHg5PSId2sXq1CIO1CISvwWAj027ltMVG2UNgW+w9oH2+HzgEIRFembL8bUlXtfbBHR1fCg2xw=="],
|
||||
"caniuse-lite": ["[email protected]93", "", {}, "sha512-iwSsYWaCOoh26cV8NwNRViHlrfUvYsHDfRVcbtmw0Kg6PJIZZXwMkj1442FYLBGkeUf1juAsU3DTfxW579mrPA=="],
|
||||
|
||||
"case-anything": ["[email protected]", "", {}, "sha512-zlOQ80VrQ2Ue+ymH5OuM/DlDq64mEm+B9UTdHULv5osUMD6HalNTblf2b1u/m6QecjsnOkBpqVZ+XPwIVsy7Ng=="],
|
||||
|
||||
@@ -1455,8 +1462,6 @@
|
||||
|
||||
"color-string": ["[email protected]", "", { "dependencies": { "color-name": "^1.0.0", "simple-swizzle": "^0.2.2" } }, "sha512-shrVawQFojnZv6xM40anx4CkoDP+fZsw/ZerEMsW/pyzsRbElpsL/DBVW7q3ExxwusdNXI3lXpuhEZkzs8p5Eg=="],
|
||||
|
||||
"colord": ["[email protected]", "", {}, "sha512-jeC1axXpnb0/2nn/Y1LPuLdgXBLH7aDcHu4KEKfqw3CUhX7ZpfBSlPKyqXE6btIgEzfWtrX3/tyBCaCvXvMkOw=="],
|
||||
|
||||
"comma-separated-tokens": ["[email protected]", "", {}, "sha512-Fu4hJdvzeylCfQPp9SGWidpzrMs7tTrlu6Vb8XGaRGck8QSNZJJp538Wrb60Lax4fPwR64ViY468OIUTbRlGZg=="],
|
||||
|
||||
"commander": ["[email protected]", "", {}, "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ=="],
|
||||
@@ -1517,15 +1522,15 @@
|
||||
|
||||
"css-what": ["[email protected]", "", {}, "sha512-u/O3vwbptzhMs3L1fQE82ZSLHQQfto5gyZzwteVIEyeaY5Fc7R4dapF/BvRoSYFeqfBk4m0V1Vafq5Pjv25wvA=="],
|
||||
|
||||
"cssdb": ["cssdb@8.7.1", "", {}, "sha512-+F6LKx48RrdGOtE4DT5jz7Uo+VeyKXpK797FAevIkzjV8bMHz6xTO5F7gNDcRCHmPgD5jj2g6QCsY9zmVrh38A=="],
|
||||
"cssdb": ["cssdb@8.9.0", "", {}, "sha512-J8jOU/hLjaXcO1LldOLraJSQpfLXRKof0I7mtbRyOy2AAXgqst0x9rlgi2qXeD6d0ou3ZLqcPAMqYVbpCbrxEw=="],
|
||||
|
||||
"cssesc": ["[email protected]", "", { "bin": { "cssesc": "bin/cssesc" } }, "sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg=="],
|
||||
|
||||
"cssnano": ["[email protected].2", "", { "dependencies": { "cssnano-preset-default": "^7.0.10", "lilconfig": "^3.1.3" }, "peerDependencies": { "postcss": "^8.4.32" } }, "sha512-HYOPBsNvoiFeR1eghKD5C3ASm64v9YVyJB4Ivnl2gqKoQYvjjN/G0rztvKQq8OxocUtC6sjqY8jwYngIB4AByA=="],
|
||||
"cssnano": ["[email protected].9", "", { "dependencies": { "cssnano-preset-default": "^7.0.17", "lilconfig": "^3.1.3" }, "peerDependencies": { "postcss": "^8.5.13" } }, "sha512-uPR75+5Dk/WJ/YSPR1/YDHdwMM9c5FsaARljfKWgeCKLKOtJ0we21xy/RcCjn53fZnD/f6yYEIZ8pu18+GnbNQ=="],
|
||||
|
||||
"cssnano-preset-default": ["[email protected]0", "", { "dependencies": { "browserslist": "^4.27.0", "css-declaration-sorter": "^7.2.0", "cssnano-utils": "^5.0.1", "postcss-calc": "^10.1.1", "postcss-colormin": "^7.0.5", "postcss-convert-values": "^7.0.8", "postcss-discard-comments": "^7.0.5", "postcss-discard-duplicates": "^7.0.2", "postcss-discard-empty": "^7.0.1", "postcss-discard-overridden": "^7.0.1", "postcss-merge-longhand": "^7.0.5", "postcss-merge-rules": "^7.0.7", "postcss-minify-font-values": "^7.0.1", "postcss-minify-gradients": "^7.0.1", "postcss-minify-params": "^7.0.5", "postcss-minify-selectors": "^7.0.5", "postcss-normalize-charset": "^7.0.1", "postcss-normalize-display-values": "^7.0.1", "postcss-normalize-positions": "^7.0.1", "postcss-normalize-repeat-style": "^7.0.1", "postcss-normalize-string": "^7.0.1", "postcss-normalize-timing-functions": "^7.0.1", "postcss-normalize-unicode": "^7.0.5", "postcss-normalize-url": "^7.0.1", "postcss-normalize-whitespace": "^7.0.1", "postcss-ordered-values": "^7.0.2", "postcss-reduce-initial": "^7.0.5", "postcss-reduce-transforms": "^7.0.1", "postcss-svgo": "^7.1.0", "postcss-unique-selectors": "^7.0.4" }, "peerDependencies": { "postcss": "^8.4.32" } }, "sha512-6ZBjW0Lf1K1Z+0OKUAUpEN62tSXmYChXWi2NAA0afxEVsj9a+MbcB1l5qel6BHJHmULai2fCGRthCeKSFbScpA=="],
|
||||
"cssnano-preset-default": ["[email protected]7", "", { "dependencies": { "browserslist": "^4.28.2", "css-declaration-sorter": "^7.2.0", "cssnano-utils": "^5.0.3", "postcss-calc": "^10.1.1", "postcss-colormin": "^7.0.10", "postcss-convert-values": "^7.0.12", "postcss-discard-comments": "^7.0.8", "postcss-discard-duplicates": "^7.0.4", "postcss-discard-empty": "^7.0.3", "postcss-discard-overridden": "^7.0.3", "postcss-merge-longhand": "^7.0.7", "postcss-merge-rules": "^7.0.11", "postcss-minify-font-values": "^7.0.3", "postcss-minify-gradients": "^7.0.5", "postcss-minify-params": "^7.0.9", "postcss-minify-selectors": "^7.1.2", "postcss-normalize-charset": "^7.0.3", "postcss-normalize-display-values": "^7.0.3", "postcss-normalize-positions": "^7.0.4", "postcss-normalize-repeat-style": "^7.0.4", "postcss-normalize-string": "^7.0.3", "postcss-normalize-timing-functions": "^7.0.3", "postcss-normalize-unicode": "^7.0.9", "postcss-normalize-url": "^7.0.3", "postcss-normalize-whitespace": "^7.0.3", "postcss-ordered-values": "^7.0.4", "postcss-reduce-initial": "^7.0.9", "postcss-reduce-transforms": "^7.0.3", "postcss-svgo": "^7.1.3", "postcss-unique-selectors": "^7.0.7" }, "peerDependencies": { "postcss": "^8.5.13" } }, "sha512-11qO63A+czwguQFJCaTdICvbaxn0pJzz/XghLlv+OT7WyToDxAMR0Xb3/26/l0y0hQJywwNbj/SLSQlGBHE1OA=="],
|
||||
|
||||
"cssnano-utils": ["[email protected].1", "", { "peerDependencies": { "postcss": "^8.4.32" } }, "sha512-ZIP71eQgG9JwjVZsTPSqhc6GHgEr53uJ7tK5///VfyWj6Xp2DBmixWHqJgPno+PqATzn48pL42ww9x5SSGmhZg=="],
|
||||
"cssnano-utils": ["[email protected].3", "", { "peerDependencies": { "postcss": "^8.5.13" } }, "sha512-ynIREMICLxkxm7e9bCR9sh75s4Q5drICi0ua1yxo5jH2XPBqSKkl4dOh4EbFqtUmnTMhRffHgYL0EKKkMjtJTg=="],
|
||||
|
||||
"csso": ["[email protected]", "", { "dependencies": { "css-tree": "~2.2.0" } }, "sha512-0LrrStPOdJj+SPCCrGhzryycLjwcgUSHBtxNA8aIDxf0GLsRh1cKYhB00Gd1lDOS4yGH69+SNn13+TWbVHETFQ=="],
|
||||
|
||||
@@ -1627,7 +1632,7 @@
|
||||
|
||||
"ejs": ["[email protected]", "", { "dependencies": { "jake": "^10.8.5" }, "bin": { "ejs": "bin/cli.js" } }, "sha512-UeJmFfOrAQS8OJWPZ4qtgHyWExa088/MtK5UEyoJGFH67cDEXkZSviOiKRCZ4Xij0zxI3JECgYs3oKx+AizQBA=="],
|
||||
|
||||
"electron-to-chromium": ["[email protected].286", "", {}, "sha512-9tfDXhJ4RKFNerfjdCcZfufu49vg620741MNs26a9+bhLThdB+plgMeou98CAaHu/WATj2iHOOHTp1hWtABj2A=="],
|
||||
"electron-to-chromium": ["[email protected].363", "", {}, "sha512-VjUKPyWzGnT1fujlkEGC/BvN70Hh70KXtAqcmniXviYlJC/ivcT+BWGPyxWVbJZLfvtKR6dqg1L7T7pgAMBtWA=="],
|
||||
|
||||
"emmet": ["[email protected]", "", { "dependencies": { "@emmetio/abbreviation": "^2.3.3", "@emmetio/css-abbreviation": "^2.1.8" } }, "sha512-23QPJB3moh/U9sT4rQzGgeyyGIrcM+GH5uVYg2C6wZIxAIJq7Ng3QLT79tl8FUwDXhyq9SusfknOrofAKqvgyQ=="],
|
||||
|
||||
@@ -2111,7 +2116,7 @@
|
||||
|
||||
"meshline": ["[email protected]", "", { "peerDependencies": { "three": ">=0.137" } }, "sha512-/TQj+JdZkeSUOl5Mk2J7eLcYTLiQm2IDzmlSvYm7ov15anEcDJ92GHqqazxTSreeNgfnYu24kiEvvv0WlbCdFQ=="],
|
||||
|
||||
"meshoptimizer": ["meshoptimizer@0.22.0", "", {}, "sha512-IebiK79sqIy+E4EgOr+CAw+Ke8hAspXKzBd0JdgEmPHiAwmvEj2S4h1rfvo+o/BnfEYd/jAOg5IeeIjzlzSnDg=="],
|
||||
"meshoptimizer": ["meshoptimizer@1.1.1", "", {}, "sha512-oRFNWJRDA/WTrVj7NWvqa5HqE1t9MYDj2VaWirQCzCCrAd2GHrqR/sQezCxiWATPNlKTcRaPRHPJwIRoPBAp5g=="],
|
||||
|
||||
"micromark": ["[email protected]", "", { "dependencies": { "@types/debug": "^4.0.0", "debug": "^4.0.0", "decode-named-character-reference": "^1.0.0", "devlop": "^1.0.0", "micromark-core-commonmark": "^2.0.0", "micromark-factory-space": "^2.0.0", "micromark-util-character": "^2.0.0", "micromark-util-chunked": "^2.0.0", "micromark-util-combine-extensions": "^2.0.0", "micromark-util-decode-numeric-character-reference": "^2.0.0", "micromark-util-encode": "^2.0.0", "micromark-util-normalize-identifier": "^2.0.0", "micromark-util-resolve-all": "^2.0.0", "micromark-util-sanitize-uri": "^2.0.0", "micromark-util-subtokenize": "^2.0.0", "micromark-util-symbol": "^2.0.0", "micromark-util-types": "^2.0.0" } }, "sha512-zpe98Q6kvavpCr1NPVSCMebCKfD7CA2NqZ+rykeNhONIJBpc1tFKt9hucLGwha3jNTNI8lHpctWJWoimVF4PfA=="],
|
||||
|
||||
@@ -2187,7 +2192,7 @@
|
||||
|
||||
"muggle-string": ["[email protected]", "", {}, "sha512-VNTrAak/KhO2i8dqqnqnAHOa3cYBwXEZe9h+D5h/1ZqFSTEFHdM65lR7RoIqq3tBBYavsOXV84NoHXZ0AkPyqQ=="],
|
||||
|
||||
"nanoid": ["[email protected]1", "", { "bin": { "nanoid": "bin/nanoid.cjs" } }, "sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w=="],
|
||||
"nanoid": ["[email protected]2", "", { "bin": { "nanoid": "bin/nanoid.cjs" } }, "sha512-ZB9RH/39qpq5Vu6Y+NmUaFhQR6pp+M2Xt76XBnEwDaGcVAqhlvxrl3B2bKS5D3NH3QR76v3aSrKaF/Kiy7lEtQ=="],
|
||||
|
||||
"ndarray": ["[email protected]", "", { "dependencies": { "iota-array": "^1.0.0", "is-buffer": "^1.0.2" } }, "sha512-B4JHA4vdyZU30ELBw3g7/p9bZupyew5a7tX1Y/gGeF2hafrPaQZhgrGQfsvgfYbgdFZjYwuEcnaobeM/WMW+HQ=="],
|
||||
|
||||
@@ -2215,7 +2220,7 @@
|
||||
|
||||
"node-mock-http": ["[email protected]", "", {}, "sha512-8DY+kFsDkNXy1sJglUfuODx1/opAGJGyrTuFqEoN90oRc2Vk0ZbD4K2qmKXBBEhZQzdKHIVfEJpDU8Ak2NJEvQ=="],
|
||||
|
||||
"node-releases": ["[email protected].27", "", {}, "sha512-nmh3lCkYZ3grZvqcCH+fjmQ7X+H0OeZgP40OierEaAptX4XofMh5kwNbWh7lBduUzCcV/8kZ+NDLCwm2iorIlA=="],
|
||||
"node-releases": ["[email protected].46", "", {}, "sha512-GYVXHE2KnrzAfsAjl4uP++evGFCrAU1jta4ubEjIG7YWt/64Gqv66a30yKwWczVjA6j3bM4nBwH7Pk1JmDHaxQ=="],
|
||||
|
||||
"normalize-path": ["[email protected]", "", {}, "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA=="],
|
||||
|
||||
@@ -2325,7 +2330,7 @@
|
||||
|
||||
"possible-typed-array-names": ["[email protected]", "", {}, "sha512-/+5VFTchJDoVj3bhoqi6UeymcD00DAwb1nJwamzPvHEszJ4FpF6SNNbUbOS8yI56qHzdV8eK0qEfOSiodkTdxg=="],
|
||||
|
||||
"postcss": ["[email protected].6", "", { "dependencies": { "nanoid": "^3.3.11", "picocolors": "^1.1.1", "source-map-js": "^1.2.1" } }, "sha512-3Ybi1tAuwAP9s0r1UQ2J4n5Y0G05bJkpUIO0/bI9MhwmD70S5aTWbXGBwxHrelT+XM1k6dM0pk+SwNkpTRN7Pg=="],
|
||||
"postcss": ["[email protected].15", "", { "dependencies": { "nanoid": "^3.3.12", "picocolors": "^1.1.1", "source-map-js": "^1.2.1" } }, "sha512-FfR8sjd4em2T6fb3I2MwAJU7HWVMr9zba+enmQeeWFfCbm+UOC/0X4DS8XtpUTMwWMGbjKYP7xjfNekzyGmB3A=="],
|
||||
|
||||
"postcss-attribute-case-insensitive": ["[email protected]", "", { "dependencies": { "postcss-selector-parser": "^7.1.1" }, "peerDependencies": { "postcss": "^8.4" } }, "sha512-fovIPEV35c2JzVXdmP+sp2xirbBMt54J+upU8u6TSj410kUU5+axgEzvBBSAX8KCybze8CFCelzFAw/FfWg2TA=="],
|
||||
|
||||
@@ -2333,33 +2338,33 @@
|
||||
|
||||
"postcss-clamp": ["[email protected]", "", { "dependencies": { "postcss-value-parser": "^4.2.0" }, "peerDependencies": { "postcss": "^8.4.6" } }, "sha512-ry4b1Llo/9zz+PKC+030KUnPITTJAHeOwjfAyyB60eT0AorGLdzp52s31OsPRHRf8NchkgFoG2y6fCfn1IV1Ow=="],
|
||||
|
||||
"postcss-color-functional-notation": ["[email protected].1", "", { "dependencies": { "@csstools/css-color-parser": "^4.0.1", "@csstools/css-parser-algorithms": "^4.0.0", "@csstools/css-tokenizer": "^4.0.0", "@csstools/postcss-progressive-custom-properties": "^5.0.0", "@csstools/utilities": "^3.0.0" }, "peerDependencies": { "postcss": "^8.4" } }, "sha512-f1itLOG10iAa9mBAAtIHj/wfDs3srsNv/vrAsiRrIOfTCjhjxHxL1g06vvpQ86he2BP5HwB4cN72EZQ8rkegpA=="],
|
||||
"postcss-color-functional-notation": ["[email protected].4", "", { "dependencies": { "@csstools/css-color-parser": "^4.1.1", "@csstools/css-parser-algorithms": "^4.0.0", "@csstools/css-tokenizer": "^4.0.0", "@csstools/postcss-progressive-custom-properties": "^5.1.0", "@csstools/utilities": "^3.0.0" }, "peerDependencies": { "postcss": "^8.4" } }, "sha512-Zn3yPgBFakVXthmA2n1NUMY7gdhuFUB/DrUJ0Eug/d0rl9wahMQZykp4NVTJLGzQrDUwZ2rzjiTeW5udxFNG8A=="],
|
||||
|
||||
"postcss-color-hex-alpha": ["[email protected]", "", { "dependencies": { "@csstools/utilities": "^3.0.0", "postcss-value-parser": "^4.2.0" }, "peerDependencies": { "postcss": "^8.4" } }, "sha512-NCGa6vjIyrjosz9GqRxVKbONBklz5TeipYqTJp3IqbnBWlBq5e5EMtG6MaX4vqk9LzocPfMQkuRK9tfk+OQuKg=="],
|
||||
|
||||
"postcss-color-rebeccapurple": ["[email protected]", "", { "dependencies": { "@csstools/utilities": "^3.0.0", "postcss-value-parser": "^4.2.0" }, "peerDependencies": { "postcss": "^8.4" } }, "sha512-g9561mx7cbdqx7XeO/L+lJzVlzu7bICyXr72efBVKZGxIhvBBJf9fGXn3Cb6U4Bwh3LbzQO2e9NWBLVYdX5Eag=="],
|
||||
|
||||
"postcss-colormin": ["[email protected].5", "", { "dependencies": { "browserslist": "^4.27.0", "caniuse-api": "^3.0.0", "colord": "^2.9.3", "postcss-value-parser": "^4.2.0" }, "peerDependencies": { "postcss": "^8.4.32" } }, "sha512-ekIBP/nwzRWhEMmIxHHbXHcMdzd1HIUzBECaj5KEdLz9DVP2HzT065sEhvOx1dkLjYW7jyD0CngThx6bpFi2fA=="],
|
||||
"postcss-colormin": ["[email protected].10", "", { "dependencies": { "@colordx/core": "^5.4.3", "browserslist": "^4.28.2", "caniuse-api": "^3.0.0", "postcss-value-parser": "^4.2.0" }, "peerDependencies": { "postcss": "^8.5.13" } }, "sha512-yFr6JezOolHLta/buLE71VKPh2mXursp4saVe98/ol8ZnEWhL+racShqPKlvd/DKWLre/39B6HhcMXf7RZ3hxg=="],
|
||||
|
||||
"postcss-convert-values": ["[email protected].8", "", { "dependencies": { "browserslist": "^4.27.0", "postcss-value-parser": "^4.2.0" }, "peerDependencies": { "postcss": "^8.4.32" } }, "sha512-+XNKuPfkHTCEo499VzLMYn94TiL3r9YqRE3Ty+jP7UX4qjewUONey1t7CG21lrlTLN07GtGM8MqFVp86D4uKJg=="],
|
||||
"postcss-convert-values": ["[email protected].12", "", { "dependencies": { "browserslist": "^4.28.2", "postcss-value-parser": "^4.2.0" }, "peerDependencies": { "postcss": "^8.5.13" } }, "sha512-xurKu5qqk4viR3Cp3p4xBR4KfnZm4w4ys6+UBwBmeuBSNkH7+DtLnYOYnOffgtE4yx8sH9S1VZ6RAAvROXzP2Q=="],
|
||||
|
||||
"postcss-custom-media": ["[email protected].0", "", { "dependencies": { "@csstools/cascade-layer-name-parser": "^3.0.0", "@csstools/css-parser-algorithms": "^4.0.0", "@csstools/css-tokenizer": "^4.0.0", "@csstools/media-query-list-parser": "^5.0.0" }, "peerDependencies": { "postcss": "^8.4" } }, "sha512-jIgEvqceN6ru2uQ0f75W1g+JDi0UyECFeJKjPG7UcSkW3+03LDKH2c6h+9C0XuDTV4y2pEHmD5AJtVBq1OGnZA=="],
|
||||
"postcss-custom-media": ["[email protected].1", "", { "dependencies": { "@csstools/cascade-layer-name-parser": "^3.0.0", "@csstools/css-parser-algorithms": "^4.0.0", "@csstools/css-tokenizer": "^4.0.0", "@csstools/media-query-list-parser": "^5.0.0" }, "peerDependencies": { "postcss": "^8.4" } }, "sha512-66syE14+VeqkUf0rRX0bvbTCbNRJF132jD+ceo8th1dap2YJEAqpdh5uG98CE3IbgHT7m9XM0GIlOazNWqQdeA=="],
|
||||
|
||||
"postcss-custom-properties": ["[email protected].0", "", { "dependencies": { "@csstools/cascade-layer-name-parser": "^3.0.0", "@csstools/css-parser-algorithms": "^4.0.0", "@csstools/css-tokenizer": "^4.0.0", "@csstools/utilities": "^3.0.0", "postcss-value-parser": "^4.2.0" }, "peerDependencies": { "postcss": "^8.4" } }, "sha512-FsD3VNtFr3qmspvIobDRszK9onKPHp8iHG4Aox2Nnm9SL93uw5GDw4z+NM7zWKiw6U+DSNm24JUm4coyIyanzQ=="],
|
||||
"postcss-custom-properties": ["[email protected].1", "", { "dependencies": { "@csstools/cascade-layer-name-parser": "^3.0.0", "@csstools/css-parser-algorithms": "^4.0.0", "@csstools/css-tokenizer": "^4.0.0", "@csstools/utilities": "^3.0.0", "postcss-value-parser": "^4.2.0" }, "peerDependencies": { "postcss": "^8.4" } }, "sha512-cuyq8sd8dLY0GLbelz1KB8IMIoDECo6RVXMeHeXY2Uw3Q05k/d1GVITdaKLsheqrHbnxlwxzSRZQQ5u+rNtbMg=="],
|
||||
|
||||
"postcss-custom-selectors": ["[email protected].0", "", { "dependencies": { "@csstools/cascade-layer-name-parser": "^3.0.0", "@csstools/css-parser-algorithms": "^4.0.0", "@csstools/css-tokenizer": "^4.0.0", "postcss-selector-parser": "^7.1.1" }, "peerDependencies": { "postcss": "^8.4" } }, "sha512-VuV5tLPAm6wq1u699dsrhGCzfLobKe0eD3G8bw3BcTJt6wqQ7RQdfaveJVsCAi23OaQbjIi3K1C7Fj3yZH3f1g=="],
|
||||
"postcss-custom-selectors": ["[email protected].1", "", { "dependencies": { "@csstools/cascade-layer-name-parser": "^3.0.0", "@csstools/css-parser-algorithms": "^4.0.0", "@csstools/css-tokenizer": "^4.0.0", "postcss-selector-parser": "^7.1.1" }, "peerDependencies": { "postcss": "^8.4" } }, "sha512-2XBELy4DmdVKimChfaZ2id9u9CSGYQhiJ53SvlfBvMTzLMW2VxuMb9rHsMSQw9kRq/zSbhT5x13EaK8JSmK8KQ=="],
|
||||
|
||||
"postcss-dir-pseudo-class": ["[email protected]", "", { "dependencies": { "postcss-selector-parser": "^7.1.1" }, "peerDependencies": { "postcss": "^8.4" } }, "sha512-DmtIzULpyC8XaH4b5AaUgt4Jic4QmrECqidNCdR7u7naQFdnxX80YI06u238a+ZVRXwURDxVzy0s/UQnWmpVeg=="],
|
||||
|
||||
"postcss-discard-comments": ["[email protected].5", "", { "dependencies": { "postcss-selector-parser": "^7.1.0" }, "peerDependencies": { "postcss": "^8.4.32" } }, "sha512-IR2Eja8WfYgN5n32vEGSctVQ1+JARfu4UH8M7bgGh1bC+xI/obsPJXaBpQF7MAByvgwZinhpHpdrmXtvVVlKcQ=="],
|
||||
"postcss-discard-comments": ["[email protected].8", "", { "dependencies": { "postcss-selector-parser": "^7.1.1" }, "peerDependencies": { "postcss": "^8.5.13" } }, "sha512-CvvS5S9WrXblFXCEJ9nVo+4z+eA7zSC7Z88V1HEJuwlQhlFnYTIjg1xJY+BCUiG2bvICap2tXii4mP22BD108Q=="],
|
||||
|
||||
"postcss-discard-duplicates": ["[email protected].2", "", { "peerDependencies": { "postcss": "^8.4.32" } }, "sha512-eTonaQvPZ/3i1ASDHOKkYwAybiM45zFIc7KXils4mQmHLqIswXD9XNOKEVxtTFnsmwYzF66u4LMgSr0abDlh5w=="],
|
||||
"postcss-discard-duplicates": ["[email protected].4", "", { "peerDependencies": { "postcss": "^8.5.13" } }, "sha512-VBNn1+EuMZkeGVVtz0gRfbNGtx9IFgAsAV+E2pHtXPrp4qfGBkhTIiAuE/wrb+Y6Pakg9NewAlfTpYIFAWODtw=="],
|
||||
|
||||
"postcss-discard-empty": ["[email protected].1", "", { "peerDependencies": { "postcss": "^8.4.32" } }, "sha512-cFrJKZvcg/uxB6Ijr4l6qmn3pXQBna9zyrPC+sK0zjbkDUZew+6xDltSF7OeB7rAtzaaMVYSdbod+sZOCWnMOg=="],
|
||||
"postcss-discard-empty": ["[email protected].3", "", { "peerDependencies": { "postcss": "^8.5.13" } }, "sha512-M2pyjQCU+/7cMHVtL6bKTHjv0lZnPLMpicgr67Dlth7AbuV9gjVTtUqaRwn6Pp6BwSDspUzhz8SaUrRykJU5Dw=="],
|
||||
|
||||
"postcss-discard-overridden": ["[email protected].1", "", { "peerDependencies": { "postcss": "^8.4.32" } }, "sha512-7c3MMjjSZ/qYrx3uc1940GSOzN1Iqjtlqe8uoSg+qdVPYyRb0TILSqqmtlSFuE4mTDECwsm397Ya7iXGzfF7lg=="],
|
||||
"postcss-discard-overridden": ["[email protected].3", "", { "peerDependencies": { "postcss": "^8.5.13" } }, "sha512-aNovXo9UsZuRNLzHJtp13lHIvinDPfiXBPePpXkSjCbgp++iU2FqE+YxvjIsg6EdyPZsASFbfu+JcBFVsErXIQ=="],
|
||||
|
||||
"postcss-double-position-gradients": ["[email protected].0", "", { "dependencies": { "@csstools/postcss-progressive-custom-properties": "^5.0.0", "@csstools/utilities": "^3.0.0", "postcss-value-parser": "^4.2.0" }, "peerDependencies": { "postcss": "^8.4" } }, "sha512-Msr/dxj8Os7KLJE5Hdhvprwm3K5Zrh1KTY0eFN3ngPKNkej/Usy4BM9JQmqE6CLAkDpHoQVsi4snbL72CPt6qg=="],
|
||||
"postcss-double-position-gradients": ["[email protected].1", "", { "dependencies": { "@csstools/postcss-progressive-custom-properties": "^5.1.0", "@csstools/utilities": "^3.0.0", "postcss-value-parser": "^4.2.0" }, "peerDependencies": { "postcss": "^8.4" } }, "sha512-M69I4EolEGwiYa0KmxKWg4zZp2DxhlNM0Bz12OvHCj930GXDVCvFhdWNGsRscz6BIijN6tFryzSFsy8kMLyD5Q=="],
|
||||
|
||||
"postcss-focus-visible": ["[email protected]", "", { "dependencies": { "postcss-selector-parser": "^7.1.1" }, "peerDependencies": { "postcss": "^8.4" } }, "sha512-VG1a9kBKizUBWS66t5xyB4uLONBnvZLCmZXxT40FALu8EF0QgVZBYy5ApC0KhmpHsv+pvHMJHB3agKHwmocWjw=="],
|
||||
|
||||
@@ -2371,49 +2376,49 @@
|
||||
|
||||
"postcss-image-set-function": ["[email protected]", "", { "dependencies": { "@csstools/utilities": "^3.0.0", "postcss-value-parser": "^4.2.0" }, "peerDependencies": { "postcss": "^8.4" } }, "sha512-rEGNkOkNusf4+IuMmfEoIdLuVmvbExGbmG+MIsyV6jR5UaWSoyPcAYHV/PxzVDCmudyF+2Nh/o6Ub2saqUdnuA=="],
|
||||
|
||||
"postcss-lab-function": ["[email protected].1", "", { "dependencies": { "@csstools/css-color-parser": "^4.0.1", "@csstools/css-parser-algorithms": "^4.0.0", "@csstools/css-tokenizer": "^4.0.0", "@csstools/postcss-progressive-custom-properties": "^5.0.0", "@csstools/utilities": "^3.0.0" }, "peerDependencies": { "postcss": "^8.4" } }, "sha512-Q/ANnuCYtanAc+2NnCaZrYu+GofYQUV603JXL0KB6GlcXxpnm/UerPAmpKQdb9pxYUkpKovGxfL43aOUnpF/Hg=="],
|
||||
"postcss-lab-function": ["[email protected].4", "", { "dependencies": { "@csstools/css-color-parser": "^4.1.1", "@csstools/css-parser-algorithms": "^4.0.0", "@csstools/css-tokenizer": "^4.0.0", "@csstools/postcss-progressive-custom-properties": "^5.1.0", "@csstools/utilities": "^3.0.0" }, "peerDependencies": { "postcss": "^8.4" } }, "sha512-dqcJSzVasdELD9xqJ1wfP95uzP57J6zFd80c7S3AWK127H9zwqR9Kbk5ZgyIfN2DiMStI7Vq8E7ablXNeTvpew=="],
|
||||
|
||||
"postcss-load-config": ["[email protected]", "", { "dependencies": { "lilconfig": "^3.1.1" }, "peerDependencies": { "jiti": ">=1.21.0", "postcss": ">=8.0.9", "tsx": "^4.8.1", "yaml": "^2.4.2" }, "optionalPeers": ["jiti", "postcss", "tsx", "yaml"] }, "sha512-oPtTM4oerL+UXmx+93ytZVN82RrlY/wPUV8IeDxFrzIjXOLF1pN+EmKPLbubvKHT2HC20xXsCAH2Z+CKV6Oz/g=="],
|
||||
|
||||
"postcss-logical": ["[email protected]", "", { "dependencies": { "postcss-value-parser": "^4.2.0" }, "peerDependencies": { "postcss": "^8.4" } }, "sha512-A4LNd9dk3q/juEUA9Gd8ALhBO3TeOeYurnyHLlf2aAToD94VHR8c5Uv7KNmf8YVRhTxvWsyug4c5fKtARzyIRQ=="],
|
||||
|
||||
"postcss-merge-longhand": ["[email protected].5", "", { "dependencies": { "postcss-value-parser": "^4.2.0", "stylehacks": "^7.0.5" }, "peerDependencies": { "postcss": "^8.4.32" } }, "sha512-Kpu5v4Ys6QI59FxmxtNB/iHUVDn9Y9sYw66D6+SZoIk4QTz1prC4aYkhIESu+ieG1iylod1f8MILMs1Em3mmIw=="],
|
||||
"postcss-merge-longhand": ["[email protected].7", "", { "dependencies": { "postcss-value-parser": "^4.2.0", "stylehacks": "^7.0.11" }, "peerDependencies": { "postcss": "^8.5.13" } }, "sha512-b3mfYUxR388u5Pt0HPcVIUtUDn/k15UfTY9M+ORW+meCR6JLNxoZffiYvXyOYQoRYQNZyX/UFkMCM/mNHxe1qA=="],
|
||||
|
||||
"postcss-merge-rules": ["[email protected].7", "", { "dependencies": { "browserslist": "^4.27.0", "caniuse-api": "^3.0.0", "cssnano-utils": "^5.0.1", "postcss-selector-parser": "^7.1.0" }, "peerDependencies": { "postcss": "^8.4.32" } }, "sha512-njWJrd/Ms6XViwowaaCc+/vqhPG3SmXn725AGrnl+BgTuRPEacjiLEaGq16J6XirMJbtKkTwnt67SS+e2WGoew=="],
|
||||
"postcss-merge-rules": ["[email protected].11", "", { "dependencies": { "browserslist": "^4.28.2", "caniuse-api": "^3.0.0", "cssnano-utils": "^5.0.3", "postcss-selector-parser": "^7.1.1" }, "peerDependencies": { "postcss": "^8.5.13" } }, "sha512-SJUPM18g2BmPhf8BVlbwqWz4aK3pLu6u6xjfwEzra7xL6IBR10sUaiB++EzqcVfadPHrKBSMlNdP+XieykhI+Q=="],
|
||||
|
||||
"postcss-minify-font-values": ["[email protected].1", "", { "dependencies": { "postcss-value-parser": "^4.2.0" }, "peerDependencies": { "postcss": "^8.4.32" } }, "sha512-2m1uiuJeTplll+tq4ENOQSzB8LRnSUChBv7oSyFLsJRtUgAAJGP6LLz0/8lkinTgxrmJSPOEhgY1bMXOQ4ZXhQ=="],
|
||||
"postcss-minify-font-values": ["[email protected].3", "", { "dependencies": { "postcss-value-parser": "^4.2.0" }, "peerDependencies": { "postcss": "^8.5.13" } }, "sha512-yilG/VOaNI74IylQvAQQxm3/wZVBkXyYUqNUAdxqwtbWUXPsbK1q8Ms0mL83v+f8YicgcyfYCRZtWACUdYajpA=="],
|
||||
|
||||
"postcss-minify-gradients": ["[email protected].1", "", { "dependencies": { "colord": "^2.9.3", "cssnano-utils": "^5.0.1", "postcss-value-parser": "^4.2.0" }, "peerDependencies": { "postcss": "^8.4.32" } }, "sha512-X9JjaysZJwlqNkJbUDgOclyG3jZEpAMOfof6PUZjPnPrePnPG62pS17CjdM32uT1Uq1jFvNSff9l7kNbmMSL2A=="],
|
||||
"postcss-minify-gradients": ["[email protected].5", "", { "dependencies": { "@colordx/core": "^5.4.3", "cssnano-utils": "^5.0.3", "postcss-value-parser": "^4.2.0" }, "peerDependencies": { "postcss": "^8.5.13" } }, "sha512-YraROyQRg3BI1+Hg8E05B/JPdnTm8EDSVu4P2BxdM+CRiOyfmou809+chGIqo6fQqwjPGQ947nbGncSjmTU1WQ=="],
|
||||
|
||||
"postcss-minify-params": ["[email protected].5", "", { "dependencies": { "browserslist": "^4.27.0", "cssnano-utils": "^5.0.1", "postcss-value-parser": "^4.2.0" }, "peerDependencies": { "postcss": "^8.4.32" } }, "sha512-FGK9ky02h6Ighn3UihsyeAH5XmLEE2MSGH5Tc4tXMFtEDx7B+zTG6hD/+/cT+fbF7PbYojsmmWjyTwFwW1JKQQ=="],
|
||||
"postcss-minify-params": ["[email protected].9", "", { "dependencies": { "browserslist": "^4.28.2", "cssnano-utils": "^5.0.3", "postcss-value-parser": "^4.2.0" }, "peerDependencies": { "postcss": "^8.5.13" } }, "sha512-R8itbB8BhlpoYyBm1ou0dD+vJnQ3F6adQipR4UnkCHUwlo+S9WXJaDRg1RHjC8YVAtIdrQzSWvJl40HnGDTKjA=="],
|
||||
|
||||
"postcss-minify-selectors": ["postcss-minify-selectors@7.0.5", "", { "dependencies": { "cssesc": "^3.0.0", "postcss-selector-parser": "^7.1.0" }, "peerDependencies": { "postcss": "^8.4.32" } }, "sha512-x2/IvofHcdIrAm9Q+p06ZD1h6FPcQ32WtCRVodJLDR+WMn8EVHI1kvLxZuGKz/9EY5nAmI6lIQIrpo4tBy5+ug=="],
|
||||
"postcss-minify-selectors": ["postcss-minify-selectors@7.1.2", "", { "dependencies": { "browserslist": "^4.28.1", "caniuse-api": "^3.0.0", "cssesc": "^3.0.0", "postcss-selector-parser": "^7.1.1" }, "peerDependencies": { "postcss": "^8.5.13" } }, "sha512-aQtrEWKwqafNlExcKHQvPGsXR2+vlUqqJtf5XsCQcgsSb5PL4wlujWBYDJuWsP4UnQX1YHDHU8qRlD+1PzTQ+Q=="],
|
||||
|
||||
"postcss-nested": ["[email protected]", "", { "dependencies": { "postcss-selector-parser": "^7.0.0" }, "peerDependencies": { "postcss": "^8.2.14" } }, "sha512-5osppouFc0VR9/VYzYxO03VaDa3e8F23Kfd6/9qcZTUI8P58GIYlArOET2Wq0ywSl2o2PjELhYOFI4W7l5QHKw=="],
|
||||
|
||||
"postcss-nesting": ["[email protected]", "", { "dependencies": { "@csstools/selector-resolve-nested": "^4.0.0", "@csstools/selector-specificity": "^6.0.0", "postcss-selector-parser": "^7.1.1" }, "peerDependencies": { "postcss": "^8.4" } }, "sha512-YGFOfVrjxYfeGTS5XctP1WCI5hu8Lr9SmntjfRC+iX5hCihEO+QZl9Ra+pkjqkgoVdDKvb2JccpElcowhZtzpw=="],
|
||||
|
||||
"postcss-normalize-charset": ["[email protected].1", "", { "peerDependencies": { "postcss": "^8.4.32" } }, "sha512-sn413ofhSQHlZFae//m9FTOfkmiZ+YQXsbosqOWRiVQncU2BA3daX3n0VF3cG6rGLSFVc5Di/yns0dFfh8NFgQ=="],
|
||||
"postcss-normalize-charset": ["[email protected].3", "", { "peerDependencies": { "postcss": "^8.5.13" } }, "sha512-NoBfZu8PR4c2NlmjvrqQTzCzLY79hwcSRgNQ3ZiNK0ABzf9kYKloE/jNj+/8GQY1wsm8pRRgANk6ydLH8cwo0Q=="],
|
||||
|
||||
"postcss-normalize-display-values": ["[email protected].1", "", { "dependencies": { "postcss-value-parser": "^4.2.0" }, "peerDependencies": { "postcss": "^8.4.32" } }, "sha512-E5nnB26XjSYz/mGITm6JgiDpAbVuAkzXwLzRZtts19jHDUBFxZ0BkXAehy0uimrOjYJbocby4FVswA/5noOxrQ=="],
|
||||
"postcss-normalize-display-values": ["[email protected].3", "", { "dependencies": { "postcss-value-parser": "^4.2.0" }, "peerDependencies": { "postcss": "^8.5.13" } }, "sha512-ldsCX0QIt05pKIOobZtVQ48wXJecr+czw4+e1/YjVhLMqslShgpVxgPtI2CefURR8oyVoYaU/l829MMwExDMLw=="],
|
||||
|
||||
"postcss-normalize-positions": ["[email protected].1", "", { "dependencies": { "postcss-value-parser": "^4.2.0" }, "peerDependencies": { "postcss": "^8.4.32" } }, "sha512-pB/SzrIP2l50ZIYu+yQZyMNmnAcwyYb9R1fVWPRxm4zcUFCY2ign7rcntGFuMXDdd9L2pPNUgoODDk91PzRZuQ=="],
|
||||
"postcss-normalize-positions": ["[email protected].4", "", { "dependencies": { "postcss-value-parser": "^4.2.0" }, "peerDependencies": { "postcss": "^8.5.13" } }, "sha512-VEvlpeGd3Ju1Hqa/oN4jaP3+ms4laYwkEL9N9u+B6k54PZjXbW1n6wI+aVprf1BQXlCYpS5+1pl/7/vHiKgARg=="],
|
||||
|
||||
"postcss-normalize-repeat-style": ["[email protected].1", "", { "dependencies": { "postcss-value-parser": "^4.2.0" }, "peerDependencies": { "postcss": "^8.4.32" } }, "sha512-NsSQJ8zj8TIDiF0ig44Byo3Jk9e4gNt9x2VIlJudnQQ5DhWAHJPF4Tr1ITwyHio2BUi/I6Iv0HRO7beHYOloYQ=="],
|
||||
"postcss-normalize-repeat-style": ["[email protected].4", "", { "dependencies": { "postcss-value-parser": "^4.2.0" }, "peerDependencies": { "postcss": "^8.5.13" } }, "sha512-6mPKlY/8cSaDHxX502wERADarJsccwlky6yIrOapHH2ZgfoKAV94SbiTKfKEs4EEpdazuc3J72WsqeYk7hp9+Q=="],
|
||||
|
||||
"postcss-normalize-string": ["[email protected].1", "", { "dependencies": { "postcss-value-parser": "^4.2.0" }, "peerDependencies": { "postcss": "^8.4.32" } }, "sha512-QByrI7hAhsoze992kpbMlJSbZ8FuCEc1OT9EFbZ6HldXNpsdpZr+YXC5di3UEv0+jeZlHbZcoCADgb7a+lPmmQ=="],
|
||||
"postcss-normalize-string": ["[email protected].3", "", { "dependencies": { "postcss-value-parser": "^4.2.0" }, "peerDependencies": { "postcss": "^8.5.13" } }, "sha512-HnEQPUchi1eznmDKEYrKUTqrprEq97SrpUYClgUkv7V2zRODD9DFoUsYU+m9ZOetmD5ku7fEMZB/lwy8IT6xVQ=="],
|
||||
|
||||
"postcss-normalize-timing-functions": ["[email protected].1", "", { "dependencies": { "postcss-value-parser": "^4.2.0" }, "peerDependencies": { "postcss": "^8.4.32" } }, "sha512-bHifyuuSNdKKsnNJ0s8fmfLMlvsQwYVxIoUBnowIVl2ZAdrkYQNGVB4RxjfpvkMjipqvbz0u7feBZybkl/6NJg=="],
|
||||
"postcss-normalize-timing-functions": ["[email protected].3", "", { "dependencies": { "postcss-value-parser": "^4.2.0" }, "peerDependencies": { "postcss": "^8.5.13" } }, "sha512-zmEzHdvpZBZu0OKlbJSfgASQvaayyAoVuWtvyr34IJ/LyS+DaOKvvR3EvFJ9RWWtNIx+CMvO125OVophaxNYew=="],
|
||||
|
||||
"postcss-normalize-unicode": ["[email protected].5", "", { "dependencies": { "browserslist": "^4.27.0", "postcss-value-parser": "^4.2.0" }, "peerDependencies": { "postcss": "^8.4.32" } }, "sha512-X6BBwiRxVaFHrb2WyBMddIeB5HBjJcAaUHyhLrM2FsxSq5TFqcHSsK7Zu1otag+o0ZphQGJewGH1tAyrD0zX1Q=="],
|
||||
"postcss-normalize-unicode": ["[email protected].9", "", { "dependencies": { "browserslist": "^4.28.2", "postcss-value-parser": "^4.2.0" }, "peerDependencies": { "postcss": "^8.5.13" } }, "sha512-DRAdWfeh/TjmhLJsw91vdiWCnUod9iwvM7xyS02/nF/sLsCR3A8l3pztrSUrWG8DSBqfX7yEk9FM0USaVJ2mSg=="],
|
||||
|
||||
"postcss-normalize-url": ["[email protected].1", "", { "dependencies": { "postcss-value-parser": "^4.2.0" }, "peerDependencies": { "postcss": "^8.4.32" } }, "sha512-sUcD2cWtyK1AOL/82Fwy1aIVm/wwj5SdZkgZ3QiUzSzQQofrbq15jWJ3BA7Z+yVRwamCjJgZJN0I9IS7c6tgeQ=="],
|
||||
"postcss-normalize-url": ["[email protected].3", "", { "dependencies": { "postcss-value-parser": "^4.2.0" }, "peerDependencies": { "postcss": "^8.5.13" } }, "sha512-CL93wmloq5qsffmFv+bw24MIRbmhHrp53qoh1LDAb/5TtjWEXI/np4xcP/Gw9oWCb2XyWnqHYLDUwiKRoJBA1Q=="],
|
||||
|
||||
"postcss-normalize-whitespace": ["[email protected].1", "", { "dependencies": { "postcss-value-parser": "^4.2.0" }, "peerDependencies": { "postcss": "^8.4.32" } }, "sha512-vsbgFHMFQrJBJKrUFJNZ2pgBeBkC2IvvoHjz1to0/0Xk7sII24T0qFOiJzG6Fu3zJoq/0yI4rKWi7WhApW+EFA=="],
|
||||
"postcss-normalize-whitespace": ["[email protected].3", "", { "dependencies": { "postcss-value-parser": "^4.2.0" }, "peerDependencies": { "postcss": "^8.5.13" } }, "sha512-FdHjjn+Ht5Z2ZRjNOmeCbNq6lq09sUYKpmlF/Aq0XjVNSLTL6fmHlA/3swN2wP2caY9GV/tjSDcIIyS7aN7W0A=="],
|
||||
|
||||
"postcss-opacity-percentage": ["[email protected]", "", { "peerDependencies": { "postcss": "^8.4" } }, "sha512-K6HGVzyxUxd/VgZdX04DCtdwWJ4NGLG212US4/LA1TLAbHgmAsTWVR86o+gGIbFtnTkfOpb9sCRBx8K7HO66qQ=="],
|
||||
|
||||
"postcss-ordered-values": ["[email protected].2", "", { "dependencies": { "cssnano-utils": "^5.0.1", "postcss-value-parser": "^4.2.0" }, "peerDependencies": { "postcss": "^8.4.32" } }, "sha512-AMJjt1ECBffF7CEON/Y0rekRLS6KsePU6PRP08UqYW4UGFRnTXNrByUzYK1h8AC7UWTZdQ9O3Oq9kFIhm0SFEw=="],
|
||||
"postcss-ordered-values": ["[email protected].4", "", { "dependencies": { "cssnano-utils": "^5.0.3", "postcss-value-parser": "^4.2.0" }, "peerDependencies": { "postcss": "^8.5.13" } }, "sha512-nubSi49hDHQk4E8KIj+IbLY8Bg+8OcSUEhgyolgM+atnOvXjV7EjaR6bac4YGZoFyPa9mWoAF3EaYbWdFkKqVg=="],
|
||||
|
||||
"postcss-overflow-shorthand": ["[email protected]", "", { "dependencies": { "postcss-value-parser": "^4.2.0" }, "peerDependencies": { "postcss": "^8.4" } }, "sha512-9SLpjoUdGRoRrzoOdX66HbUs0+uDwfIAiXsRa7piKGOqPd6F4ZlON9oaDSP5r1Qpgmzw5L9Ht0undIK6igJPMA=="],
|
||||
|
||||
@@ -2421,13 +2426,13 @@
|
||||
|
||||
"postcss-place": ["[email protected]", "", { "dependencies": { "postcss-value-parser": "^4.2.0" }, "peerDependencies": { "postcss": "^8.4" } }, "sha512-fAifpyjQ+fuDRp2nmF95WbotqbpjdazebedahXdfBxy5sHembOLpBQ1cHveZD9ZmjK26tYM8tikeNaUlp/KfHA=="],
|
||||
|
||||
"postcss-preset-env": ["postcss-preset-env@11.1.3", "", { "dependencies": { "@csstools/postcss-alpha-function": "^2.0.2", "@csstools/postcss-cascade-layers": "^6.0.0", "@csstools/postcss-color-function": "^5.0.1", "@csstools/postcss-color-function-display-p3-linear": "^2.0.1", "@csstools/postcss-color-mix-function": "^4.0.1", "@csstools/postcss-color-mix-variadic-function-arguments": "^2.0.1", "@csstools/postcss-content-alt-text": "^3.0.0", "@csstools/postcss-contrast-color-function": "^3.0.1", "@csstools/postcss-exponential-functions": "^3.0.0", "@csstools/postcss-font-format-keywords": "^5.0.0", "@csstools/postcss-gamut-mapping": "^3.0.1", "@csstools/postcss-gradients-interpolation-method": "^6.0.1", "@csstools/postcss-hwb-function": "^5.0.1", "@csstools/postcss-ic-unit": "^5.0.0", "@csstools/postcss-initial": "^3.0.0", "@csstools/postcss-is-pseudo-class": "^6.0.0", "@csstools/postcss-light-dark-function": "^3.0.0", "@csstools/postcss-logical-float-and-clear": "^4.0.0", "@csstools/postcss-logical-overflow": "^3.0.0", "@csstools/postcss-logical-overscroll-behavior": "^3.0.0", "@csstools/postcss-logical-resize": "^4.0.0", "@csstools/postcss-logical-viewport-units": "^4.0.0", "@csstools/postcss-media-minmax": "^3.0.0", "@csstools/postcss-media-queries-aspect-ratio-number-values": "^4.0.0", "@csstools/postcss-mixins": "^1.0.0", "@csstools/postcss-nested-calc": "^5.0.0", "@csstools/postcss-normalize-display-values": "^5.0.1", "@csstools/postcss-oklab-function": "^5.0.1", "@csstools/postcss-position-area-property": "^2.0.0", "@csstools/postcss-progressive-custom-properties": "^5.0.0", "@csstools/postcss-property-rule-prelude-list": "^2.0.0", "@csstools/postcss-random-function": "^3.0.0", "@csstools/postcss-relative-color-syntax": "^4.0.1", "@csstools/postcss-scope-pseudo-class": "^5.0.0", "@csstools/postcss-sign-functions": "^2.0.0", "@csstools/postcss-stepped-value-functions": "^5.0.0", "@csstools/postcss-syntax-descriptor-syntax-production": "^2.0.0", "@csstools/postcss-system-ui-font-family": "^2.0.0", "@csstools/postcss-text-decoration-shorthand": "^5.0.2", "@csstools/postcss-trigonometric-functions": "^5.0.0", "@csstools/postcss-unset-value": "^5.0.0", "autoprefixer": "^10.4.23", "browserslist": "^4.28.1", "css-blank-pseudo": "^8.0.1", "css-has-pseudo": "^8.0.0", "css-prefers-color-scheme": "^11.0.0", "cssdb": "^8.7.0", "postcss-attribute-case-insensitive": "^8.0.0", "postcss-clamp": "^4.1.0", "postcss-color-functional-notation": "^8.0.1", "postcss-color-hex-alpha": "^11.0.0", "postcss-color-rebeccapurple": "^11.0.0", "postcss-custom-media": "^12.0.0", "postcss-custom-properties": "^15.0.0", "postcss-custom-selectors": "^9.0.0", "postcss-dir-pseudo-class": "^10.0.0", "postcss-double-position-gradients": "^7.0.0", "postcss-focus-visible": "^11.0.0", "postcss-focus-within": "^10.0.0", "postcss-font-variant": "^5.0.0", "postcss-gap-properties": "^7.0.0", "postcss-image-set-function": "^8.0.0", "postcss-lab-function": "^8.0.1", "postcss-logical": "^9.0.0", "postcss-nesting": "^14.0.0", "postcss-opacity-percentage": "^3.0.0", "postcss-overflow-shorthand": "^7.0.0", "postcss-page-break": "^3.0.4", "postcss-place": "^11.0.0", "postcss-pseudo-class-any-link": "^11.0.0", "postcss-replace-overflow-wrap": "^4.0.0", "postcss-selector-not": "^9.0.0" }, "peerDependencies": { "postcss": "^8.4" } }, "sha512-kZOfgzUc52yq2fJRZig7sHgWaHJoDOLABBoswe6TPTHgW3581VkP3eRj+Silhc7cJTomMjZZsyRHNjQ+bW11Gg=="],
|
||||
"postcss-preset-env": ["postcss-preset-env@11.3.0", "", { "dependencies": { "@csstools/postcss-alpha-function": "^2.0.5", "@csstools/postcss-cascade-layers": "^6.0.0", "@csstools/postcss-color-function": "^5.0.4", "@csstools/postcss-color-function-display-p3-linear": "^2.0.4", "@csstools/postcss-color-mix-function": "^4.0.4", "@csstools/postcss-color-mix-variadic-function-arguments": "^2.0.4", "@csstools/postcss-container-rule-prelude-list": "^1.0.1", "@csstools/postcss-content-alt-text": "^3.0.1", "@csstools/postcss-contrast-color-function": "^3.0.4", "@csstools/postcss-exponential-functions": "^3.0.3", "@csstools/postcss-font-format-keywords": "^5.0.0", "@csstools/postcss-font-width-property": "^1.0.0", "@csstools/postcss-gamut-mapping": "^3.0.4", "@csstools/postcss-gradients-interpolation-method": "^6.0.4", "@csstools/postcss-hwb-function": "^5.0.4", "@csstools/postcss-ic-unit": "^5.0.1", "@csstools/postcss-image-function": "^1.0.0", "@csstools/postcss-initial": "^3.0.0", "@csstools/postcss-is-pseudo-class": "^6.0.0", "@csstools/postcss-light-dark-function": "^3.0.1", "@csstools/postcss-logical-float-and-clear": "^4.0.0", "@csstools/postcss-logical-overflow": "^3.0.0", "@csstools/postcss-logical-overscroll-behavior": "^3.0.0", "@csstools/postcss-logical-resize": "^4.0.0", "@csstools/postcss-logical-viewport-units": "^4.0.0", "@csstools/postcss-media-minmax": "^3.0.3", "@csstools/postcss-media-queries-aspect-ratio-number-values": "^4.0.0", "@csstools/postcss-mixins": "^1.0.0", "@csstools/postcss-nested-calc": "^5.0.0", "@csstools/postcss-normalize-display-values": "^5.0.1", "@csstools/postcss-oklab-function": "^5.0.4", "@csstools/postcss-position-area-property": "^2.0.0", "@csstools/postcss-progressive-custom-properties": "^5.1.0", "@csstools/postcss-property-rule-prelude-list": "^2.0.0", "@csstools/postcss-random-function": "^3.0.3", "@csstools/postcss-relative-color-syntax": "^4.0.4", "@csstools/postcss-scope-pseudo-class": "^5.0.0", "@csstools/postcss-sign-functions": "^2.0.3", "@csstools/postcss-stepped-value-functions": "^5.0.3", "@csstools/postcss-syntax-descriptor-syntax-production": "^2.0.0", "@csstools/postcss-system-ui-font-family": "^2.0.0", "@csstools/postcss-text-decoration-shorthand": "^5.0.3", "@csstools/postcss-trigonometric-functions": "^5.0.3", "@csstools/postcss-unset-value": "^5.0.0", "autoprefixer": "^10.5.0", "browserslist": "^4.28.1", "css-blank-pseudo": "^8.0.1", "css-has-pseudo": "^8.0.0", "css-prefers-color-scheme": "^11.0.0", "cssdb": "^8.9.0", "postcss-attribute-case-insensitive": "^8.0.0", "postcss-clamp": "^4.1.0", "postcss-color-functional-notation": "^8.0.4", "postcss-color-hex-alpha": "^11.0.0", "postcss-color-rebeccapurple": "^11.0.0", "postcss-custom-media": "^12.0.1", "postcss-custom-properties": "^15.0.1", "postcss-custom-selectors": "^9.0.1", "postcss-dir-pseudo-class": "^10.0.0", "postcss-double-position-gradients": "^7.0.1", "postcss-focus-visible": "^11.0.0", "postcss-focus-within": "^10.0.0", "postcss-font-variant": "^5.0.0", "postcss-gap-properties": "^7.0.0", "postcss-image-set-function": "^8.0.0", "postcss-lab-function": "^8.0.4", "postcss-logical": "^9.0.0", "postcss-nesting": "^14.0.0", "postcss-opacity-percentage": "^3.0.0", "postcss-overflow-shorthand": "^7.0.0", "postcss-page-break": "^3.0.4", "postcss-place": "^11.0.0", "postcss-pseudo-class-any-link": "^11.0.0", "postcss-replace-overflow-wrap": "^4.0.0", "postcss-selector-not": "^9.0.0" }, "peerDependencies": { "postcss": "^8.4" } }, "sha512-PpijTuY+NT35vvk7us0pw9lJVrsZZWukjONZsza2Kq1Gag8nrUXRkgdKdxyyhZPJ6R43L3/nLpspUK99TmU9xg=="],
|
||||
|
||||
"postcss-pseudo-class-any-link": ["[email protected]", "", { "dependencies": { "postcss-selector-parser": "^7.1.1" }, "peerDependencies": { "postcss": "^8.4" } }, "sha512-DNFZ4GMa3C3pU5dM+UCTG1CEeLtS1ZqV5DKSqCTJQMn1G5jnd/30fS8+A7H4o5bSD3MOcnx+VgI+xPE9Z5Wvig=="],
|
||||
|
||||
"postcss-reduce-initial": ["[email protected].5", "", { "dependencies": { "browserslist": "^4.27.0", "caniuse-api": "^3.0.0" }, "peerDependencies": { "postcss": "^8.4.32" } }, "sha512-RHagHLidG8hTZcnr4FpyMB2jtgd/OcyAazjMhoy5qmWJOx1uxKh4ntk0Pb46ajKM0rkf32lRH4C8c9qQiPR6IA=="],
|
||||
"postcss-reduce-initial": ["[email protected].9", "", { "dependencies": { "browserslist": "^4.28.2", "caniuse-api": "^3.0.0" }, "peerDependencies": { "postcss": "^8.5.13" } }, "sha512-ztTNPdIxXTxtBcG03E9u8v44M4ElXbMIRT7pf2onlquGula0Y83nKKxqM22FA/hMgkfCjN7ohevkVlaNwI8iOQ=="],
|
||||
|
||||
"postcss-reduce-transforms": ["[email protected].1", "", { "dependencies": { "postcss-value-parser": "^4.2.0" }, "peerDependencies": { "postcss": "^8.4.32" } }, "sha512-MhyEbfrm+Mlp/36hvZ9mT9DaO7dbncU0CvWI8V93LRkY6IYlu38OPg3FObnuKTUxJ4qA8HpurdQOo5CyqqO76g=="],
|
||||
"postcss-reduce-transforms": ["[email protected].3", "", { "dependencies": { "postcss-value-parser": "^4.2.0" }, "peerDependencies": { "postcss": "^8.5.13" } }, "sha512-FXsnN9ZwcZTT8Yf8cAHA8qIGUXcX6WfLd9JoYhrdDfmvsVhhfqkkv7m4AC3rwFOfz+GzkUa87OCKF9dUcicd+g=="],
|
||||
|
||||
"postcss-replace-overflow-wrap": ["[email protected]", "", { "peerDependencies": { "postcss": "^8.0.3" } }, "sha512-KmF7SBPphT4gPPcKZc7aDkweHiKEEO8cla/GjcBK+ckKxiZslIu3C4GCRW3DNfL0o7yW7kMQu9xlZ1kXRXLXtw=="],
|
||||
|
||||
@@ -2435,15 +2440,15 @@
|
||||
|
||||
"postcss-selector-parser": ["[email protected]", "", { "dependencies": { "cssesc": "^3.0.0", "util-deprecate": "^1.0.2" } }, "sha512-orRsuYpJVw8LdAwqqLykBj9ecS5/cRHlI5+nvTo8LcCKmzDmqVORXtOIYEEQuL9D4BxtA1lm5isAqzQZCoQ6Eg=="],
|
||||
|
||||
"postcss-svgo": ["[email protected].0", "", { "dependencies": { "postcss-value-parser": "^4.2.0", "svgo": "^4.0.0" }, "peerDependencies": { "postcss": "^8.4.32" } }, "sha512-KnAlfmhtoLz6IuU3Sij2ycusNs4jPW+QoFE5kuuUOK8awR6tMxZQrs5Ey3BUz7nFCzT3eqyFgqkyrHiaU2xx3w=="],
|
||||
"postcss-svgo": ["[email protected].3", "", { "dependencies": { "postcss-value-parser": "^4.2.0", "svgo": "^4.0.1" }, "peerDependencies": { "postcss": "^8.5.13" } }, "sha512-2QfoFOYMcj8lwcVEf9WeTlkVIAm7u2QvOEhMzkQU3KUhhGX/l8hVV9EtjMv4iq3E9iI3OeeMN0YoMLbGusuigw=="],
|
||||
|
||||
"postcss-unique-selectors": ["[email protected].4", "", { "dependencies": { "postcss-selector-parser": "^7.1.0" }, "peerDependencies": { "postcss": "^8.4.32" } }, "sha512-pmlZjsmEAG7cHd7uK3ZiNSW6otSZ13RHuZ/4cDN/bVglS5EpF2r2oxY99SuOHa8m7AWoBCelTS3JPpzsIs8skQ=="],
|
||||
"postcss-unique-selectors": ["[email protected].7", "", { "dependencies": { "postcss-selector-parser": "^7.1.1" }, "peerDependencies": { "postcss": "^8.5.13" } }, "sha512-d+sCkaRnSefghOUdH8CMJZV9yUQhj2ojpe8Nw/lA+LV1UOfeleGkLTl6XdCFFSai9UJ+DJPb69FFuqthXYsY8w=="],
|
||||
|
||||
"postcss-value-parser": ["[email protected]", "", {}, "sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ=="],
|
||||
|
||||
"potpack": ["[email protected]", "", {}, "sha512-choctRBIV9EMT9WGAZHn3V7t0Z2pMQyl0EZE6pFc/6ml3ssw7Dlf/oAOvFwjm1HVsqfQN8GfeFyJ+d8tRzqueQ=="],
|
||||
|
||||
"prettier": ["[email protected].1", "", { "bin": { "prettier": "bin/prettier.cjs" } }, "sha512-UOnG6LftzbdaHZcKoPFtOcCKztrQ57WkHDeRD9t/PTQtmT0NHSeWWepj6pS0z/N7+08BHFDQVUrfmfMRcZwbMg=="],
|
||||
"prettier": ["[email protected].3", "", { "bin": { "prettier": "bin/prettier.cjs" } }, "sha512-7igPTM53cGHMW8xWuVTydi2KO233VFiTNyF5hLJqpilHfmn8C8gPf+PS7dUT64YcXFbiMGZxS9pCSxL/Dxm/Jw=="],
|
||||
|
||||
"pretty-bytes": ["[email protected]", "", {}, "sha512-mQUvGU6aUFQ+rNvTIAcZuWGRT9a6f6Yrg9bHs4ImKF+HZCEK+plBvnAZYSIQztknZF2qnzNtr6F8s0+IuptdlQ=="],
|
||||
|
||||
@@ -2461,7 +2466,7 @@
|
||||
|
||||
"prompts": ["[email protected]", "", { "dependencies": { "kleur": "^3.0.3", "sisteransi": "^1.0.5" } }, "sha512-NxNv/kLguCA7p3jE8oL2aEBsrJWgAakBpgmgK6lpPWV+WuOmY6r2/zbAVnP+T8bQlA0nzHXSJSJW0Hq7ylaD2Q=="],
|
||||
|
||||
"property-graph": ["property-graph@4.0.0", "", {}, "sha512-I0hojAJfTbSCZy3y6xyK29eayxo14v1bj1VPiDkHjTdz33SV6RdfMz2AHnf4ai62Vng2mN5GkaKahkooBIo9gA=="],
|
||||
"property-graph": ["property-graph@4.1.0", "", {}, "sha512-AvPcP7XECNWy4LGmFQ77k7un4lSKM4eS29PTvW4ck95uYeLxXPWJM7hLuBqK91FaHqCcgJvIUCuNJjjxKE7VKQ=="],
|
||||
|
||||
"property-information": ["[email protected]", "", {}, "sha512-TwEZ+X+yCJmYfL7TPUOcvBZ4QfoT5YenQiJuX//0th53DE6w0xxLEtfK3iyryQFddXuvkIk51EEgrJQ0WJkOmQ=="],
|
||||
|
||||
@@ -2499,11 +2504,11 @@
|
||||
|
||||
"rc9": ["[email protected]", "", { "dependencies": { "defu": "^6.1.4", "destr": "^2.0.3" } }, "sha512-btXCnMmRIBINM2LDZoEmOogIZU7Qe7zn4BpomSKZ/ykbLObuBdvG+mFq11DL6fjH1DRwHhrlgtYWG96bJiC7Cg=="],
|
||||
|
||||
"react": ["[email protected].4", "", {}, "sha512-9nfp2hYpCwOjAN+8TZFGhtWEwgvWHXqESH8qT89AT/lWklpLON22Lc8pEtnpsZz7VmawabSU0gCjnj8aC0euHQ=="],
|
||||
"react": ["[email protected].6", "", {}, "sha512-sfWGGfavi0xr8Pg0sVsyHMAOziVYKgPLNrS7ig+ivMNb3wbCBw3KxtflsGBAwD3gYQlE/AEZsTLgToRrSCjb0Q=="],
|
||||
|
||||
"react-dom": ["[email protected].4", "", { "dependencies": { "scheduler": "^0.27.0" }, "peerDependencies": { "react": "^19.2.4" } }, "sha512-AXJdLo8kgMbimY95O2aKQqsz2iWi9jMgKJhRBAxECE4IFxfcazB2LmzloIoibJI3C12IlY20+KFaLv+71bUJeQ=="],
|
||||
"react-dom": ["[email protected].6", "", { "dependencies": { "scheduler": "^0.27.0" }, "peerDependencies": { "react": "^19.2.6" } }, "sha512-0prMI+hvBbPjsWnxDLxlCGyM8PN6UuWjEUCYmZhO67xIV9Xasa/r/vDnq+Xyq4Lo27g8QSbO5YzARu0D1Sps3g=="],
|
||||
|
||||
"react-error-boundary": ["[email protected].1", "", { "peerDependencies": { "react": "^18.0.0 || ^19.0.0" } }, "sha512-BrYwPOdXi5mqkk5lw+Uvt0ThHx32rCt3BkukS4X23A2AIWDPSGX6iaWTc0y9TU/mHDA/6qOSGel+B2ERkOvD1w=="],
|
||||
"react-error-boundary": ["[email protected].2", "", { "peerDependencies": { "react": "^18.0.0 || ^19.0.0" } }, "sha512-3DpCr5HVdZ0caUjYE/kIHBEJN0mNP3ZCgf16c48uJ5TbWjorKVp+YG8W3XqlJ7vJAVNw6wNIImyPXmFydwmyng=="],
|
||||
|
||||
"react-markdown": ["[email protected]", "", { "dependencies": { "@types/hast": "^3.0.0", "@types/mdast": "^4.0.0", "devlop": "^1.0.0", "hast-util-to-jsx-runtime": "^2.0.0", "html-url-attributes": "^3.0.0", "mdast-util-to-hast": "^13.0.0", "remark-parse": "^11.0.0", "remark-rehype": "^11.0.0", "unified": "^11.0.0", "unist-util-visit": "^5.0.0", "vfile": "^6.0.0" }, "peerDependencies": { "@types/react": ">=18", "react": ">=18" } }, "sha512-qKxVopLT/TyA6BX3Ue5NwabOsAzm0Q7kAPwq6L+wWDwisYs7R8vZ0nRXqq6rkueboxpkjvLGU9fWifiX/ZZFxQ=="],
|
||||
|
||||
@@ -2719,7 +2724,7 @@
|
||||
|
||||
"style-to-object": ["[email protected]", "", { "dependencies": { "inline-style-parser": "0.2.7" } }, "sha512-LIN7rULI0jBscWQYaSswptyderlarFkjQ+t79nzty8tcIAceVomEVlLzH5VP4Cmsv6MtKhs7qaAiwlcp+Mgaxw=="],
|
||||
|
||||
"stylehacks": ["[email protected].7", "", { "dependencies": { "browserslist": "^4.27.0", "postcss-selector-parser": "^7.1.0" }, "peerDependencies": { "postcss": "^8.4.32" } }, "sha512-bJkD0JkEtbRrMFtwgpJyBbFIwfDDONQ1Ov3sDLZQP8HuJ73kBOyx66H4bOcAbVWmnfLdvQ0AJwXxOMkpujcO6g=="],
|
||||
"stylehacks": ["[email protected].11", "", { "dependencies": { "browserslist": "^4.28.2", "postcss-selector-parser": "^7.1.1" }, "peerDependencies": { "postcss": "^8.5.13" } }, "sha512-iODNfhXVLqc5LADs+Y6Oh5wJuK5ZcHbVng8aiK3y9pjMQdc5hLrBW0eFU6FtnpNrE6PoEg/MmFTU4waotj5WNg=="],
|
||||
|
||||
"supports-preserve-symlinks-flag": ["[email protected]", "", {}, "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w=="],
|
||||
|
||||
@@ -2741,7 +2746,7 @@
|
||||
|
||||
"text-decoder": ["[email protected]", "", { "dependencies": { "b4a": "^1.6.4" } }, "sha512-vlLytXkeP4xvEq2otHeJfSQIRyWxo/oZGEbXrtEEF9Hnmrdly59sUbzZ/QgyWuLYHctCHxFF4tRQZNQ9k60ExQ=="],
|
||||
|
||||
"three": ["[email protected]0.0", "", {}, "sha512-o+qycAMZrh+TsE01GqWUxUIKR1AL0S8pq7zDkYOQw8GqfX8b8VoCKYUoHbhiX5j+7hr8XsuHDVU6+gkQJQKg9w=="],
|
||||
"three": ["[email protected]4.0", "", {}, "sha512-wtTRjG92pM5eUg/KuUnHsqSAlPM296brTOcLgMRqEeylYTh/CdtvKUvCyyCQTzFuStieWxvZb8mVTMvdPyUpxg=="],
|
||||
|
||||
"three-mesh-bvh": ["[email protected]", "", { "peerDependencies": { "three": ">= 0.159.0" } }, "sha512-4G5lBaF+g2auKX3P0yqx+MJC6oVt6sB5k+CchS6Ob0qvH0YIhuUk1eYr7ktsIpY+albCqE80/FVQGV190PmiAg=="],
|
||||
|
||||
@@ -3033,7 +3038,7 @@
|
||||
|
||||
"yallist": ["[email protected]", "", {}, "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g=="],
|
||||
|
||||
"yaml": ["yaml@2.8.2", "", { "bin": { "yaml": "bin.mjs" } }, "sha512-mplynKqc1C2hTVYxd0PU2xQAc22TI1vShAYGksCCfxbn/dFwnHTNi1bvYsBTkhdUNtGIf5xNOg938rrSSYvS9A=="],
|
||||
"yaml": ["yaml@2.9.0", "", { "bin": { "yaml": "bin.mjs" } }, "sha512-2AvhNX3mb8zd6Zy7INTtSpl1F15HW6Wnqj0srWlkKLcpYl/gMIMJiyuGq2KeI2YFxUPjdlB+3Lc10seMLtL4cA=="],
|
||||
|
||||
"yaml-language-server": ["[email protected]", "", { "dependencies": { "@vscode/l10n": "^0.0.18", "ajv": "^8.17.1", "ajv-draft-04": "^1.0.0", "lodash": "4.17.21", "prettier": "^3.5.0", "request-light": "^0.5.7", "vscode-json-languageservice": "4.1.8", "vscode-languageserver": "^9.0.0", "vscode-languageserver-textdocument": "^1.0.1", "vscode-languageserver-types": "^3.16.0", "vscode-uri": "^3.0.2", "yaml": "2.7.1" }, "bin": { "yaml-language-server": "bin/yaml-language-server" } }, "sha512-9F3myNmJzUN/679jycdMxqtydPSDRAarSj3wPiF7pchEPnO9Dg07Oc+gIYLqXR4L+g+FSEVXXv2+mr54StLFOg=="],
|
||||
|
||||
@@ -3063,8 +3068,12 @@
|
||||
|
||||
"zwitch": ["[email protected]", "", {}, "sha512-bXE4cR/kVZhKZX/RjPEflHaKVhUVl85noU3v6b8apfQEc1x4A+zBxjZ4lN8LqGd6WZ3dl98pY4o717VFmoPp+A=="],
|
||||
|
||||
"@astrojs/yaml2ts/yaml": ["[email protected]", "", { "bin": { "yaml": "bin.mjs" } }, "sha512-mplynKqc1C2hTVYxd0PU2xQAc22TI1vShAYGksCCfxbn/dFwnHTNi1bvYsBTkhdUNtGIf5xNOg938rrSSYvS9A=="],
|
||||
|
||||
"@babel/core/semver": ["[email protected]", "", { "bin": { "semver": "bin/semver.js" } }, "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA=="],
|
||||
|
||||
"@babel/helper-compilation-targets/browserslist": ["[email protected]", "", { "dependencies": { "baseline-browser-mapping": "^2.9.0", "caniuse-lite": "^1.0.30001759", "electron-to-chromium": "^1.5.263", "node-releases": "^2.0.27", "update-browserslist-db": "^1.2.0" }, "bin": { "browserslist": "cli.js" } }, "sha512-ZC5Bd0LgJXgwGqUknZY/vkUQ04r8NXnJZ3yYi4vDmSiZmC/pdSN0NbNRPxZpbtO4uAfDUAFffO8IZoM3Gj8IkA=="],
|
||||
|
||||
"@babel/helper-compilation-targets/lru-cache": ["[email protected]", "", { "dependencies": { "yallist": "^3.0.2" } }, "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w=="],
|
||||
|
||||
"@babel/helper-compilation-targets/semver": ["[email protected]", "", { "bin": { "semver": "bin/semver.js" } }, "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA=="],
|
||||
@@ -3077,20 +3086,42 @@
|
||||
|
||||
"@blitzkit/app/typescript": ["[email protected]", "", { "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" } }, "sha512-hjcS1mhfuyi4WW8IWtjP7brDrG2cuDZukyrYrSauoXGNgx0S7zceP07adYkJycEr56BOUTNPzbInooiN3fn1qw=="],
|
||||
|
||||
"@blitzkit/core/lodash-es": ["[email protected]", "", {}, "sha512-J8xewKD/Gk22OZbhpOVSwcs60zhd95ESDwezOFuA3/099925PdHJ7OFHNTGtajL3AlZkykD32HykiMo+BIBI8A=="],
|
||||
|
||||
"@blitzkit/scripts/@types/three": ["@types/[email protected]", "", { "dependencies": { "@dimforge/rapier3d-compat": "~0.12.0", "@tweenjs/tween.js": "~23.1.3", "@types/stats.js": "*", "@types/webxr": "*", "@webgpu/types": "*", "fflate": "~0.8.2", "meshoptimizer": "~0.22.0" } }, "sha512-ykFtgCqNnY0IPvDro7h+9ZeLY+qjgUWv+qEvUt84grhenO60Hqd4hScHE7VTB9nOQ/3QM8lkbNE+4vKjEpUxKg=="],
|
||||
|
||||
"@blitzkit/scripts/lodash-es": ["[email protected]", "", {}, "sha512-J8xewKD/Gk22OZbhpOVSwcs60zhd95ESDwezOFuA3/099925PdHJ7OFHNTGtajL3AlZkykD32HykiMo+BIBI8A=="],
|
||||
|
||||
"@blitzkit/scripts/three": ["[email protected]", "", {}, "sha512-o+qycAMZrh+TsE01GqWUxUIKR1AL0S8pq7zDkYOQw8GqfX8b8VoCKYUoHbhiX5j+7hr8XsuHDVU6+gkQJQKg9w=="],
|
||||
|
||||
"@blitzkit/website/@types/three": ["@types/[email protected]", "", { "dependencies": { "@dimforge/rapier3d-compat": "~0.12.0", "@tweenjs/tween.js": "~23.1.3", "@types/stats.js": "*", "@types/webxr": "*", "@webgpu/types": "*", "fflate": "~0.8.2", "meshoptimizer": "~0.22.0" } }, "sha512-ykFtgCqNnY0IPvDro7h+9ZeLY+qjgUWv+qEvUt84grhenO60Hqd4hScHE7VTB9nOQ/3QM8lkbNE+4vKjEpUxKg=="],
|
||||
|
||||
"@blitzkit/website/three": ["[email protected]", "", {}, "sha512-o+qycAMZrh+TsE01GqWUxUIKR1AL0S8pq7zDkYOQw8GqfX8b8VoCKYUoHbhiX5j+7hr8XsuHDVU6+gkQJQKg9w=="],
|
||||
|
||||
"@blitzkit/website/vite": ["[email protected]", "", { "dependencies": { "esbuild": "^0.27.0", "fdir": "^6.5.0", "picomatch": "^4.0.3", "postcss": "^8.5.6", "rollup": "^4.43.0", "tinyglobby": "^0.2.15" }, "optionalDependencies": { "fsevents": "~2.3.3" }, "peerDependencies": { "@types/node": "^20.19.0 || >=22.12.0", "jiti": ">=1.21.0", "less": "^4.0.0", "lightningcss": "^1.21.0", "sass": "^1.70.0", "sass-embedded": "^1.70.0", "stylus": ">=0.54.8", "sugarss": "^5.0.0", "terser": "^5.16.0", "tsx": "^4.8.1", "yaml": "^2.4.2" }, "optionalPeers": ["@types/node", "jiti", "less", "lightningcss", "sass", "sass-embedded", "stylus", "sugarss", "terser", "tsx", "yaml"], "bin": { "vite": "bin/vite.js" } }, "sha512-w+N7Hifpc3gRjZ63vYBXA56dvvRlNWRczTdmCBBa+CotUzAPf5b7YMdMR/8CQoeYE5LX3W4wj6RYTgonm1b9DA=="],
|
||||
|
||||
"@blitzkit/website-ue/@astrojs/check": ["@astrojs/[email protected]", "", { "dependencies": { "@astrojs/language-server": "^2.16.7", "chokidar": "^4.0.3", "kleur": "^4.1.5", "yargs": "^17.7.2" }, "peerDependencies": { "typescript": "^5.0.0 || ^6.0.0" }, "bin": { "astro-check": "bin/astro-check.js" } }, "sha512-A5UW8uIuErLWEoRQvzgXpO1gTjUFtK8r7nU2Z7GewAMxUb7bPvpk11qaKKgxqXlHJWlAvaaxy+Xg28A6bmQ1Tg=="],
|
||||
|
||||
"@blitzkit/website-ue/@astrojs/node": ["@astrojs/[email protected]", "", { "dependencies": { "@astrojs/internal-helpers": "0.7.6", "send": "^1.2.1", "server-destroy": "^1.0.1" }, "peerDependencies": { "astro": "^5.17.3" } }, "sha512-rtU2BGU5u3SfGURpANfMxVzCIoR86MkaN05ncza9rbtuMKJ/XnRJt/BbyVknDbOJ71hoci0SIsJwKcJR8vvi/A=="],
|
||||
|
||||
"@blitzkit/website-ue/astro": ["[email protected]", "", { "dependencies": { "@astrojs/compiler": "^2.13.0", "@astrojs/internal-helpers": "0.7.6", "@astrojs/markdown-remark": "6.3.11", "@astrojs/telemetry": "3.3.0", "@capsizecss/unpack": "^4.0.0", "@oslojs/encoding": "^1.1.0", "@rollup/pluginutils": "^5.3.0", "acorn": "^8.15.0", "aria-query": "^5.3.2", "axobject-query": "^4.1.0", "boxen": "8.0.1", "ci-info": "^4.3.1", "clsx": "^2.1.1", "common-ancestor-path": "^1.0.1", "cookie": "^1.1.1", "cssesc": "^3.0.0", "debug": "^4.4.3", "deterministic-object-hash": "^2.0.2", "devalue": "^5.6.2", "diff": "^8.0.3", "dlv": "^1.1.3", "dset": "^3.1.4", "es-module-lexer": "^1.7.0", "esbuild": "^0.27.3", "estree-walker": "^3.0.3", "flattie": "^1.1.1", "fontace": "~0.4.0", "github-slugger": "^2.0.0", "html-escaper": "3.0.3", "http-cache-semantics": "^4.2.0", "import-meta-resolve": "^4.2.0", "js-yaml": "^4.1.1", "magic-string": "^0.30.21", "magicast": "^0.5.1", "mrmime": "^2.0.1", "neotraverse": "^0.6.18", "p-limit": "^6.2.0", "p-queue": "^8.1.1", "package-manager-detector": "^1.6.0", "piccolore": "^0.1.3", "picomatch": "^4.0.3", "prompts": "^2.4.2", "rehype": "^13.0.2", "semver": "^7.7.3", "shiki": "^3.21.0", "smol-toml": "^1.6.0", "svgo": "^4.0.0", "tinyexec": "^1.0.2", "tinyglobby": "^0.2.15", "tsconfck": "^3.1.6", "ultrahtml": "^1.6.0", "unifont": "~0.7.3", "unist-util-visit": "^5.0.0", "unstorage": "^1.17.4", "vfile": "^6.0.3", "vite": "^6.4.1", "vitefu": "^1.1.1", "xxhash-wasm": "^1.1.0", "yargs-parser": "^21.1.1", "yocto-spinner": "^0.2.3", "zod": "^3.25.76", "zod-to-json-schema": "^3.25.1", "zod-to-ts": "^1.2.0" }, "optionalDependencies": { "sharp": "^0.34.0" }, "bin": { "astro": "astro.js" } }, "sha512-TnFwLnAXty5MXKPDGuKXqK4AMBXG+FH6RUdK7Oyc3gyfNoFIthT+4eRbzOK43bdRlLaZuxgciDSjgtggZ3OtGQ=="],
|
||||
|
||||
"@blitzkit/website-ue/astro-favicons": ["[email protected]", "", { "dependencies": { "favilib": "^1.0.5", "ultrahtml": "^1.5.3" }, "peerDependencies": { "astro": ">= 4.0.0" } }, "sha512-9YfNWaBEFz1nCHy4P1l4wfPRvuLe4qHuHovIcqD5HYfZeW82wyVG1+CZUVGhcjwbRCVkGRJ3G+CKTyX9BcoI5w=="],
|
||||
|
||||
"@blitzkit/website-ue/googleapis": ["[email protected]", "", { "dependencies": { "google-auth-library": "^10.2.0", "googleapis-common": "^8.0.0" } }, "sha512-xybFL2SmmUgIifgsbsRQYRdNrSAYwxWZDmkZTGjUIaRnX5jPqR8el/cEvo6rCqh7iaZx6MfEPS/lrDgZ0bymkg=="],
|
||||
|
||||
"@blitzkit/website-ue/react": ["[email protected]", "", {}, "sha512-sfWGGfavi0xr8Pg0sVsyHMAOziVYKgPLNrS7ig+ivMNb3wbCBw3KxtflsGBAwD3gYQlE/AEZsTLgToRrSCjb0Q=="],
|
||||
"@blitzkit/website-ue/lodash-es": ["[email protected]", "", {}, "sha512-J8xewKD/Gk22OZbhpOVSwcs60zhd95ESDwezOFuA3/099925PdHJ7OFHNTGtajL3AlZkykD32HykiMo+BIBI8A=="],
|
||||
|
||||
"@blitzkit/website-ue/react-dom": ["[email protected]", "", { "dependencies": { "scheduler": "^0.27.0" }, "peerDependencies": { "react": "^19.2.6" } }, "sha512-0prMI+hvBbPjsWnxDLxlCGyM8PN6UuWjEUCYmZhO67xIV9Xasa/r/vDnq+Xyq4Lo27g8QSbO5YzARu0D1Sps3g=="],
|
||||
|
||||
"@blitzkit/website-ue/vite": ["[email protected]", "", { "dependencies": { "esbuild": "^0.27.0", "fdir": "^6.5.0", "picomatch": "^4.0.3", "postcss": "^8.5.6", "rollup": "^4.43.0", "tinyglobby": "^0.2.15" }, "optionalDependencies": { "fsevents": "~2.3.3" }, "peerDependencies": { "@types/node": "^20.19.0 || >=22.12.0", "jiti": ">=1.21.0", "less": "^4.0.0", "lightningcss": "^1.21.0", "sass": "^1.70.0", "sass-embedded": "^1.70.0", "stylus": ">=0.54.8", "sugarss": "^5.0.0", "terser": "^5.16.0", "tsx": "^4.8.1", "yaml": "^2.4.2" }, "optionalPeers": ["@types/node", "jiti", "less", "lightningcss", "sass", "sass-embedded", "stylus", "sugarss", "terser", "tsx", "yaml"], "bin": { "vite": "bin/vite.js" } }, "sha512-w+N7Hifpc3gRjZ63vYBXA56dvvRlNWRczTdmCBBa+CotUzAPf5b7YMdMR/8CQoeYE5LX3W4wj6RYTgonm1b9DA=="],
|
||||
"@blitzkit/website-ue/vite": ["[email protected]", "", { "dependencies": { "esbuild": "^0.27.0", "fdir": "^6.5.0", "picomatch": "^4.0.3", "postcss": "^8.5.6", "rollup": "^4.43.0", "tinyglobby": "^0.2.15" }, "optionalDependencies": { "fsevents": "~2.3.3" }, "peerDependencies": { "@types/node": "^20.19.0 || >=22.12.0", "jiti": ">=1.21.0", "less": "^4.0.0", "lightningcss": "^1.21.0", "sass": "^1.70.0", "sass-embedded": "^1.70.0", "stylus": ">=0.54.8", "sugarss": "^5.0.0", "terser": "^5.16.0", "tsx": "^4.8.1", "yaml": "^2.4.2" }, "optionalPeers": ["@types/node", "jiti", "less", "lightningcss", "sass", "sass-embedded", "stylus", "sugarss", "terser", "tsx", "yaml"], "bin": { "vite": "bin/vite.js" } }, "sha512-/4XH147Ui7OGTjg3HbdWe5arnZQSbfuRzdr9Ec7TQi5I7R+ir0Rlc9GIvD4v0XZurELqA035KVXJXpR61xhiTA=="],
|
||||
|
||||
"@discordjs/rest/@discordjs/collection": ["@discordjs/[email protected]", "", {}, "sha512-LiSusze9Tc7qF03sLCujF5iZp7K+vRNEDBZ86FT9aQAv3vxMLihUvKvpsCWiQ2DJq1tVckopKm1rxomgNUc9hg=="],
|
||||
|
||||
"@discordjs/ws/@discordjs/collection": ["@discordjs/[email protected]", "", {}, "sha512-LiSusze9Tc7qF03sLCujF5iZp7K+vRNEDBZ86FT9aQAv3vxMLihUvKvpsCWiQ2DJq1tVckopKm1rxomgNUc9hg=="],
|
||||
|
||||
"@gltf-transform/extensions/@gltf-transform/core": ["@gltf-transform/[email protected]", "", { "dependencies": { "property-graph": "^4.0.0" } }, "sha512-ZeaQfszGJ9LYwELszu45CuDQCsE26lJNNe36FVmN8xclaT6WDdCj7fwGpQXo0/l/YgAVAHX+uO7YNBW75/SRYw=="],
|
||||
|
||||
"@gltf-transform/functions/@gltf-transform/core": ["@gltf-transform/[email protected]", "", { "dependencies": { "property-graph": "^4.0.0" } }, "sha512-ZeaQfszGJ9LYwELszu45CuDQCsE26lJNNe36FVmN8xclaT6WDdCj7fwGpQXo0/l/YgAVAHX+uO7YNBW75/SRYw=="],
|
||||
|
||||
"@jimp/core/file-type": ["[email protected]", "", { "dependencies": { "readable-web-to-node-stream": "^3.0.0", "strtok3": "^6.2.4", "token-types": "^4.1.1" } }, "sha512-/yFHK0aGjFEgDJjEKP0pWCplsPFPhwyfwevf/pVxiN0tmE4L9LmwWxWukdJSHdoCli4VgQLehjJtwQBnqmsKcw=="],
|
||||
|
||||
"@rollup/plugin-babel/@rollup/pluginutils": ["@rollup/[email protected]", "", { "dependencies": { "@types/estree": "0.0.39", "estree-walker": "^1.0.1", "picomatch": "^2.2.2" }, "peerDependencies": { "rollup": "^1.20.0||^2.0.0" } }, "sha512-GksZ6pr6TpIjHm8h9lSQ8pi8BE9VeubNT0OMJ3B5uZJ8pz73NPiqOtCog/x2/QzM1ENChPKxMDhiQuRHsqc+lg=="],
|
||||
@@ -3123,10 +3154,16 @@
|
||||
|
||||
"c12/dotenv": ["[email protected]", "", {}, "sha512-uBq4egWHTcTt33a72vpSG0z3HnPuIl6NqYcTrKEg2azoEyl2hpW0zqlxysq2pK9HlDIHyHyakeYaYnSAwd8bow=="],
|
||||
|
||||
"caniuse-api/browserslist": ["[email protected]", "", { "dependencies": { "baseline-browser-mapping": "^2.9.0", "caniuse-lite": "^1.0.30001759", "electron-to-chromium": "^1.5.263", "node-releases": "^2.0.27", "update-browserslist-db": "^1.2.0" }, "bin": { "browserslist": "cli.js" } }, "sha512-ZC5Bd0LgJXgwGqUknZY/vkUQ04r8NXnJZ3yYi4vDmSiZmC/pdSN0NbNRPxZpbtO4uAfDUAFffO8IZoM3Gj8IkA=="],
|
||||
|
||||
"caniuse-api/caniuse-lite": ["[email protected]", "", {}, "sha512-x/2CLQ1jHENRbHg5PSId2sXq1CIO1CISvwWAj027ltMVG2UNgW+w9oH2+HzgEIRFembL8bUlXtfbBHR1fCg2xw=="],
|
||||
|
||||
"cheerio/undici": ["[email protected]", "", {}, "sha512-RqslV2Us5BrllB+JeiZnK4peryVTndy9Dnqq62S3yYRRTj0tFQCwEniUy2167skdGOy3vqRzEvl1Dm4sV2ReDg=="],
|
||||
|
||||
"cliui/wrap-ansi": ["[email protected]", "", { "dependencies": { "ansi-styles": "^4.0.0", "string-width": "^4.1.0", "strip-ansi": "^6.0.0" } }, "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q=="],
|
||||
|
||||
"core-js-compat/browserslist": ["[email protected]", "", { "dependencies": { "baseline-browser-mapping": "^2.9.0", "caniuse-lite": "^1.0.30001759", "electron-to-chromium": "^1.5.263", "node-releases": "^2.0.27", "update-browserslist-db": "^1.2.0" }, "bin": { "browserslist": "cli.js" } }, "sha512-ZC5Bd0LgJXgwGqUknZY/vkUQ04r8NXnJZ3yYi4vDmSiZmC/pdSN0NbNRPxZpbtO4uAfDUAFffO8IZoM3Gj8IkA=="],
|
||||
|
||||
"csso/css-tree": ["[email protected]", "", { "dependencies": { "mdn-data": "2.0.28", "source-map-js": "^1.0.1" } }, "sha512-OA0mILzGc1kCOCSJerOeqDxDQ4HOh+G8NbOJFOTgOCzpw7fCBubk0fEyxp8AgOL/jvLgYA/uV0cMbe43ElF1JA=="],
|
||||
|
||||
"decompress-tarbz2/file-type": ["[email protected]", "", {}, "sha512-YPcTBDV+2Tm0VqjybVd32MHdlEGAtuxS3VAYsumFokDSMG+ROT5wawGlnHDoz7bfMcMDt9hxuXvXwoKUx2fkOg=="],
|
||||
@@ -3171,6 +3208,8 @@
|
||||
|
||||
"pixelmatch/pngjs": ["[email protected]", "", {}, "sha512-TRzzuFRRmEoSW/p1KVAmiOgPco2Irlah+bGFCeNfJXxxYGwSw7YwAOAcd7X28K/m5bjBWKsC29KyoMfHbypayg=="],
|
||||
|
||||
"postcss-svgo/svgo": ["[email protected]", "", { "dependencies": { "commander": "^11.1.0", "css-select": "^5.1.0", "css-tree": "^3.0.1", "css-what": "^6.1.0", "csso": "^5.0.5", "picocolors": "^1.1.1", "sax": "^1.5.0" }, "bin": "./bin/svgo.js" }, "sha512-XDpWUOPC6FEibaLzjfe0ucaV0YrOjYotGJO1WpF0Zd+n6ZGEQUsSugaoLq9QkEZtAfQIxT42UChcssDVPP3+/w=="],
|
||||
|
||||
"prompts/kleur": ["[email protected]", "", {}, "sha512-eTIzlVOSUR+JxdDFepEYcBMtZ9Qqdef+rnzWdRZuMbOywu5tO2w2N7rqjoANZ5k9vywhL6Br1VRjUIgTQx4E8w=="],
|
||||
|
||||
"proxy-agent/agent-base": ["[email protected]", "", {}, "sha512-MnA+YT8fwfJPgBx3m60MNqakm30XOkyIoH1y6huTQvC0PwZG7ki8NacLBcrPbNoo8vEZy7Jpuk7+jMO+CUovTQ=="],
|
||||
@@ -3193,6 +3232,8 @@
|
||||
|
||||
"simple-swizzle/is-arrayish": ["[email protected]", "", {}, "sha512-m6UrgzFVUYawGBh1dUsWR5M2Clqic9RVXC/9f8ceNlv2IcO9j9J/z8UoCLPqtsPBFNzEpfR3xftohbfqDx8EQA=="],
|
||||
|
||||
"stats-gl/@types/three": ["@types/[email protected]", "", { "dependencies": { "@dimforge/rapier3d-compat": "~0.12.0", "@tweenjs/tween.js": "~23.1.3", "@types/stats.js": "*", "@types/webxr": "*", "@webgpu/types": "*", "fflate": "~0.8.2", "meshoptimizer": "~0.22.0" } }, "sha512-ykFtgCqNnY0IPvDro7h+9ZeLY+qjgUWv+qEvUt84grhenO60Hqd4hScHE7VTB9nOQ/3QM8lkbNE+4vKjEpUxKg=="],
|
||||
|
||||
"stats-gl/three": ["[email protected]", "", {}, "sha512-FQK+LEpYc0fBD+J8g6oSEyyNzjp+Q7Ks1C568WWaoMRLW+TkNNWmenWeGgJjV105Gd+p/2ql1ZcjYvNiPZBhuQ=="],
|
||||
|
||||
"steam-appticket/@doctormckay/stdlib": ["@doctormckay/[email protected]", "", {}, "sha512-XhuUOzElz6fnNdt70IYNKqhPAEpGaL4JHOhAvklRh0hAhVPW+/wLxaWT3DWUbaG5Dta5YvIp7+cZK3GhIpAuug=="],
|
||||
@@ -3215,6 +3256,10 @@
|
||||
|
||||
"to-buffer/isarray": ["[email protected]", "", {}, "sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw=="],
|
||||
|
||||
"ts-proto/@bufbuild/protobuf": ["@bufbuild/[email protected]", "", {}, "sha512-sBXGT13cpmPR5BMgHE6UEEfEaShh5Ror6rfN3yEK5si7QVrtZg8LEPQb0VVhiLRUslD2yLnXtnRzG035J/mZXQ=="],
|
||||
|
||||
"ts-proto-descriptors/@bufbuild/protobuf": ["@bufbuild/[email protected]", "", {}, "sha512-sBXGT13cpmPR5BMgHE6UEEfEaShh5Ror6rfN3yEK5si7QVrtZg8LEPQb0VVhiLRUslD2yLnXtnRzG035J/mZXQ=="],
|
||||
|
||||
"tunnel-rat/zustand": ["[email protected]", "", { "dependencies": { "use-sync-external-store": "^1.2.2" }, "peerDependencies": { "@types/react": ">=16.8", "immer": ">=9.0.6", "react": ">=16.8" }, "optionalPeers": ["@types/react", "immer", "react"] }, "sha512-CHOUy7mu3lbD6o6LJLfllpjkzhHXSBlX8B9+qPddUsIfeF5S/UZ5q0kmCsnRqT1UHFQZchNFDDzMbQsuesHWlw=="],
|
||||
|
||||
"unbzip2-stream/buffer": ["[email protected]", "", { "dependencies": { "base64-js": "^1.3.1", "ieee754": "^1.1.13" } }, "sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ=="],
|
||||
@@ -3225,7 +3270,11 @@
|
||||
|
||||
"utif2/pako": ["[email protected]", "", {}, "sha512-4hLB8Py4zZce5s4yd9XzopqwVv/yGNhV1Bl8NTmCq1763HeK2+EwVTv+leGeL13Dnh2wfbqowVPXCIO0z4taYw=="],
|
||||
|
||||
"varuna/react": ["[email protected].6", "", {}, "sha512-sfWGGfavi0xr8Pg0sVsyHMAOziVYKgPLNrS7ig+ivMNb3wbCBw3KxtflsGBAwD3gYQlE/AEZsTLgToRrSCjb0Q=="],
|
||||
"varuna/@types/react": ["@types/[email protected].15", "", { "dependencies": { "csstype": "^3.2.2" } }, "sha512-eRwcGNHve+E8qtEQSSRl6urh+rFop4v8gm6O8rGv25CodbvFdLjA1vVQ1KkiFE0w0UPOnb8tDiFKL5lp0rtY5Q=="],
|
||||
|
||||
"varuna/lodash-es": ["[email protected]", "", {}, "sha512-J8xewKD/Gk22OZbhpOVSwcs60zhd95ESDwezOFuA3/099925PdHJ7OFHNTGtajL3AlZkykD32HykiMo+BIBI8A=="],
|
||||
|
||||
"vite/postcss": ["[email protected]", "", { "dependencies": { "nanoid": "^3.3.11", "picocolors": "^1.1.1", "source-map-js": "^1.2.1" } }, "sha512-3Ybi1tAuwAP9s0r1UQ2J4n5Y0G05bJkpUIO0/bI9MhwmD70S5aTWbXGBwxHrelT+XM1k6dM0pk+SwNkpTRN7Pg=="],
|
||||
|
||||
"vscode-json-languageservice/jsonc-parser": ["[email protected]", "", {}, "sha512-HUgH65KyejrUFPvHFPbqOY0rsFip3Bo5wb4ngvdi1EpCYWUQDC5V+Y7mZws+DLkr4M//zQJoanu1SP+87Dv1oQ=="],
|
||||
|
||||
@@ -3247,14 +3296,50 @@
|
||||
|
||||
"yaml-language-server/lodash": ["[email protected]", "", {}, "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg=="],
|
||||
|
||||
"yaml-language-server/prettier": ["[email protected]", "", { "bin": { "prettier": "bin/prettier.cjs" } }, "sha512-UOnG6LftzbdaHZcKoPFtOcCKztrQ57WkHDeRD9t/PTQtmT0NHSeWWepj6pS0z/N7+08BHFDQVUrfmfMRcZwbMg=="],
|
||||
|
||||
"yaml-language-server/request-light": ["[email protected]", "", {}, "sha512-3Zjgh+8b5fhRJBQZoy+zbVKpAQGLyka0MPgW3zruTF4dFFJ8Fqcfu9YsAvi/rvdcaTeWG3MkbZv4WKxAn/84Lg=="],
|
||||
|
||||
"yaml-language-server/yaml": ["[email protected]", "", { "bin": { "yaml": "bin.mjs" } }, "sha512-10ULxpnOCQXxJvBgxsn9ptjq6uviG/htZKk9veJGhlqn3w/DxQ631zFF+nlQXLwmImeS5amR2dl2U8sg6U9jsQ=="],
|
||||
|
||||
"@babel/helper-compilation-targets/browserslist/baseline-browser-mapping": ["[email protected]", "", { "bin": { "baseline-browser-mapping": "dist/cli.js" } }, "sha512-ipDqC8FrAl/76p2SSWKSI+H9tFwm7vYqXQrItCuiVPt26Km0jS+NzSsBWAaBusvSbQcfJG+JitdMm+wZAgTYqg=="],
|
||||
|
||||
"@babel/helper-compilation-targets/browserslist/caniuse-lite": ["[email protected]", "", {}, "sha512-x/2CLQ1jHENRbHg5PSId2sXq1CIO1CISvwWAj027ltMVG2UNgW+w9oH2+HzgEIRFembL8bUlXtfbBHR1fCg2xw=="],
|
||||
|
||||
"@babel/helper-compilation-targets/browserslist/electron-to-chromium": ["[email protected]", "", {}, "sha512-9tfDXhJ4RKFNerfjdCcZfufu49vg620741MNs26a9+bhLThdB+plgMeou98CAaHu/WATj2iHOOHTp1hWtABj2A=="],
|
||||
|
||||
"@babel/helper-compilation-targets/browserslist/node-releases": ["[email protected]", "", {}, "sha512-nmh3lCkYZ3grZvqcCH+fjmQ7X+H0OeZgP40OierEaAptX4XofMh5kwNbWh7lBduUzCcV/8kZ+NDLCwm2iorIlA=="],
|
||||
|
||||
"@blitzkit/scripts/@types/three/meshoptimizer": ["[email protected]", "", {}, "sha512-IebiK79sqIy+E4EgOr+CAw+Ke8hAspXKzBd0JdgEmPHiAwmvEj2S4h1rfvo+o/BnfEYd/jAOg5IeeIjzlzSnDg=="],
|
||||
|
||||
"@blitzkit/website-ue/@astrojs/check/@astrojs/language-server": ["@astrojs/[email protected]", "", { "dependencies": { "@astrojs/compiler": "^2.13.1", "@astrojs/yaml2ts": "^0.2.4", "@jridgewell/sourcemap-codec": "^1.5.5", "@volar/kit": "~2.4.28", "@volar/language-core": "~2.4.28", "@volar/language-server": "~2.4.28", "@volar/language-service": "~2.4.28", "muggle-string": "^0.4.1", "tinyglobby": "^0.2.16", "volar-service-css": "0.0.70", "volar-service-emmet": "0.0.70", "volar-service-html": "0.0.70", "volar-service-prettier": "0.0.70", "volar-service-typescript": "0.0.70", "volar-service-typescript-twoslash-queries": "0.0.70", "volar-service-yaml": "0.0.70", "vscode-html-languageservice": "^5.6.2", "vscode-uri": "^3.1.0" }, "peerDependencies": { "prettier": "^3.0.0", "prettier-plugin-astro": ">=0.11.0" }, "optionalPeers": ["prettier", "prettier-plugin-astro"], "bin": { "astro-ls": "./bin/nodeServer.js" } }, "sha512-87VQ/5GSdHlRnUA+hGuerYyIGAj+9RbZmATyuKLEUePinUXhQ5YkRnRrHhOD9sSi5JOErLjrLkHnfZFEvGrV8w=="],
|
||||
|
||||
"@blitzkit/website-ue/@astrojs/node/@astrojs/internal-helpers": ["@astrojs/[email protected]", "", {}, "sha512-GOle7smBWKfMSP8osUIGOlB5kaHdQLV3foCsf+5Q9Wsuu+C6Fs3Ez/ttXmhjZ1HkSgsogcM1RXSjjOVieHq16Q=="],
|
||||
|
||||
"@blitzkit/website-ue/astro/@astrojs/internal-helpers": ["@astrojs/[email protected]", "", {}, "sha512-GOle7smBWKfMSP8osUIGOlB5kaHdQLV3foCsf+5Q9Wsuu+C6Fs3Ez/ttXmhjZ1HkSgsogcM1RXSjjOVieHq16Q=="],
|
||||
|
||||
"@blitzkit/website-ue/astro/@astrojs/markdown-remark": ["@astrojs/[email protected]", "", { "dependencies": { "@astrojs/internal-helpers": "0.7.6", "@astrojs/prism": "3.3.0", "github-slugger": "^2.0.0", "hast-util-from-html": "^2.0.3", "hast-util-to-text": "^4.0.2", "import-meta-resolve": "^4.2.0", "js-yaml": "^4.1.1", "mdast-util-definitions": "^6.0.0", "rehype-raw": "^7.0.0", "rehype-stringify": "^10.0.1", "remark-gfm": "^4.0.1", "remark-parse": "^11.0.0", "remark-rehype": "^11.1.2", "remark-smartypants": "^3.0.2", "shiki": "^3.21.0", "smol-toml": "^1.6.0", "unified": "^11.0.5", "unist-util-remove-position": "^5.0.0", "unist-util-visit": "^5.0.0", "unist-util-visit-parents": "^6.0.2", "vfile": "^6.0.3" } }, "sha512-hcaxX/5aC6lQgHeGh1i+aauvSwIT6cfyFjKWvExYSxUhZZBBdvCliOtu06gbQyhbe0pGJNoNmqNlQZ5zYUuIyQ=="],
|
||||
|
||||
"@blitzkit/website-ue/astro/esbuild": ["[email protected]", "", { "optionalDependencies": { "@esbuild/aix-ppc64": "0.27.3", "@esbuild/android-arm": "0.27.3", "@esbuild/android-arm64": "0.27.3", "@esbuild/android-x64": "0.27.3", "@esbuild/darwin-arm64": "0.27.3", "@esbuild/darwin-x64": "0.27.3", "@esbuild/freebsd-arm64": "0.27.3", "@esbuild/freebsd-x64": "0.27.3", "@esbuild/linux-arm": "0.27.3", "@esbuild/linux-arm64": "0.27.3", "@esbuild/linux-ia32": "0.27.3", "@esbuild/linux-loong64": "0.27.3", "@esbuild/linux-mips64el": "0.27.3", "@esbuild/linux-ppc64": "0.27.3", "@esbuild/linux-riscv64": "0.27.3", "@esbuild/linux-s390x": "0.27.3", "@esbuild/linux-x64": "0.27.3", "@esbuild/netbsd-arm64": "0.27.3", "@esbuild/netbsd-x64": "0.27.3", "@esbuild/openbsd-arm64": "0.27.3", "@esbuild/openbsd-x64": "0.27.3", "@esbuild/openharmony-arm64": "0.27.3", "@esbuild/sunos-x64": "0.27.3", "@esbuild/win32-arm64": "0.27.3", "@esbuild/win32-ia32": "0.27.3", "@esbuild/win32-x64": "0.27.3" }, "bin": { "esbuild": "bin/esbuild" } }, "sha512-8VwMnyGCONIs6cWue2IdpHxHnAjzxnw2Zr7MkVxB2vjmQ2ivqGFb4LEG3SMnv0Gb2F/G/2yA8zUaiL1gywDCCg=="],
|
||||
|
||||
"@blitzkit/website-ue/astro/picomatch": ["[email protected]", "", {}, "sha512-QP88BAKvMam/3NxH6vj2o21R6MjxZUAd6nlwAS/pnGvN9IVLocLHxGYIzFhg6fUQ+5th6P4dv4eW9jX3DSIj7A=="],
|
||||
|
||||
"@blitzkit/website-ue/astro/tinyglobby": ["[email protected]", "", { "dependencies": { "fdir": "^6.5.0", "picomatch": "^4.0.4" } }, "sha512-pn99VhoACYR8nFHhxqix+uvsbXineAasWm5ojXoN8xEwK5Kd3/TrhNn1wByuD52UxWRLy8pu+kRMniEi6Eq9Zg=="],
|
||||
|
||||
"@blitzkit/website-ue/astro/vite": ["[email protected]", "", { "dependencies": { "esbuild": "^0.25.0", "fdir": "^6.4.4", "picomatch": "^4.0.2", "postcss": "^8.5.3", "rollup": "^4.34.9", "tinyglobby": "^0.2.13" }, "optionalDependencies": { "fsevents": "~2.3.3" }, "peerDependencies": { "@types/node": "^18.0.0 || ^20.0.0 || >=22.0.0", "jiti": ">=1.21.0", "less": "*", "lightningcss": "^1.21.0", "sass": "*", "sass-embedded": "*", "stylus": "*", "sugarss": "*", "terser": "^5.16.0", "tsx": "^4.8.1", "yaml": "^2.4.2" }, "optionalPeers": ["@types/node", "jiti", "less", "lightningcss", "sass", "sass-embedded", "stylus", "sugarss", "terser", "tsx", "yaml"], "bin": { "vite": "bin/vite.js" } }, "sha512-+Oxm7q9hDoLMyJOYfUYBuHQo+dkAloi33apOPP56pzj+vsdJDzr+j1NISE5pyaAuKL4A3UD34qd0lx5+kfKp2g=="],
|
||||
|
||||
"@blitzkit/website-ue/vite/esbuild": ["[email protected]", "", { "optionalDependencies": { "@esbuild/aix-ppc64": "0.27.3", "@esbuild/android-arm": "0.27.3", "@esbuild/android-arm64": "0.27.3", "@esbuild/android-x64": "0.27.3", "@esbuild/darwin-arm64": "0.27.3", "@esbuild/darwin-x64": "0.27.3", "@esbuild/freebsd-arm64": "0.27.3", "@esbuild/freebsd-x64": "0.27.3", "@esbuild/linux-arm": "0.27.3", "@esbuild/linux-arm64": "0.27.3", "@esbuild/linux-ia32": "0.27.3", "@esbuild/linux-loong64": "0.27.3", "@esbuild/linux-mips64el": "0.27.3", "@esbuild/linux-ppc64": "0.27.3", "@esbuild/linux-riscv64": "0.27.3", "@esbuild/linux-s390x": "0.27.3", "@esbuild/linux-x64": "0.27.3", "@esbuild/netbsd-arm64": "0.27.3", "@esbuild/netbsd-x64": "0.27.3", "@esbuild/openbsd-arm64": "0.27.3", "@esbuild/openbsd-x64": "0.27.3", "@esbuild/openharmony-arm64": "0.27.3", "@esbuild/sunos-x64": "0.27.3", "@esbuild/win32-arm64": "0.27.3", "@esbuild/win32-ia32": "0.27.3", "@esbuild/win32-x64": "0.27.3" }, "bin": { "esbuild": "bin/esbuild" } }, "sha512-8VwMnyGCONIs6cWue2IdpHxHnAjzxnw2Zr7MkVxB2vjmQ2ivqGFb4LEG3SMnv0Gb2F/G/2yA8zUaiL1gywDCCg=="],
|
||||
|
||||
"@blitzkit/website/@types/three/meshoptimizer": ["[email protected]", "", {}, "sha512-IebiK79sqIy+E4EgOr+CAw+Ke8hAspXKzBd0JdgEmPHiAwmvEj2S4h1rfvo+o/BnfEYd/jAOg5IeeIjzlzSnDg=="],
|
||||
|
||||
"@blitzkit/website/vite/esbuild": ["[email protected]", "", { "optionalDependencies": { "@esbuild/aix-ppc64": "0.27.3", "@esbuild/android-arm": "0.27.3", "@esbuild/android-arm64": "0.27.3", "@esbuild/android-x64": "0.27.3", "@esbuild/darwin-arm64": "0.27.3", "@esbuild/darwin-x64": "0.27.3", "@esbuild/freebsd-arm64": "0.27.3", "@esbuild/freebsd-x64": "0.27.3", "@esbuild/linux-arm": "0.27.3", "@esbuild/linux-arm64": "0.27.3", "@esbuild/linux-ia32": "0.27.3", "@esbuild/linux-loong64": "0.27.3", "@esbuild/linux-mips64el": "0.27.3", "@esbuild/linux-ppc64": "0.27.3", "@esbuild/linux-riscv64": "0.27.3", "@esbuild/linux-s390x": "0.27.3", "@esbuild/linux-x64": "0.27.3", "@esbuild/netbsd-arm64": "0.27.3", "@esbuild/netbsd-x64": "0.27.3", "@esbuild/openbsd-arm64": "0.27.3", "@esbuild/openbsd-x64": "0.27.3", "@esbuild/openharmony-arm64": "0.27.3", "@esbuild/sunos-x64": "0.27.3", "@esbuild/win32-arm64": "0.27.3", "@esbuild/win32-ia32": "0.27.3", "@esbuild/win32-x64": "0.27.3" }, "bin": { "esbuild": "bin/esbuild" } }, "sha512-8VwMnyGCONIs6cWue2IdpHxHnAjzxnw2Zr7MkVxB2vjmQ2ivqGFb4LEG3SMnv0Gb2F/G/2yA8zUaiL1gywDCCg=="],
|
||||
|
||||
"@blitzkit/website/vite/postcss": ["[email protected]", "", { "dependencies": { "nanoid": "^3.3.11", "picocolors": "^1.1.1", "source-map-js": "^1.2.1" } }, "sha512-3Ybi1tAuwAP9s0r1UQ2J4n5Y0G05bJkpUIO0/bI9MhwmD70S5aTWbXGBwxHrelT+XM1k6dM0pk+SwNkpTRN7Pg=="],
|
||||
|
||||
"@gltf-transform/extensions/@gltf-transform/core/property-graph": ["[email protected]", "", {}, "sha512-I0hojAJfTbSCZy3y6xyK29eayxo14v1bj1VPiDkHjTdz33SV6RdfMz2AHnf4ai62Vng2mN5GkaKahkooBIo9gA=="],
|
||||
|
||||
"@gltf-transform/functions/@gltf-transform/core/property-graph": ["[email protected]", "", {}, "sha512-I0hojAJfTbSCZy3y6xyK29eayxo14v1bj1VPiDkHjTdz33SV6RdfMz2AHnf4ai62Vng2mN5GkaKahkooBIo9gA=="],
|
||||
|
||||
"@rollup/plugin-babel/@rollup/pluginutils/@types/estree": ["@types/[email protected]", "", {}, "sha512-EYNwp3bU+98cpU4lAWYYL7Zz+2gryWH1qbdDTidVd6hkiR6weksdbMadyXKXNPEkQFhXM+hVO9ZygomHXp+AIw=="],
|
||||
|
||||
"@rollup/plugin-babel/@rollup/pluginutils/estree-walker": ["[email protected]", "", {}, "sha512-1fMXF3YP4pZZVozF8j/ZLfvnR8NSIljt56UhbZ5PeeDmmGHpgpdwQt7ITlGvYaQukCvuBRMLEiKiYC+oeIg4cg=="],
|
||||
@@ -3323,8 +3408,22 @@
|
||||
|
||||
"boxen/string-width/strip-ansi": ["[email protected]", "", { "dependencies": { "ansi-regex": "^6.0.1" } }, "sha512-gmBGslpoQJtgnMAvOVqGZpEz9dyoKTCzy2nfz/n8aIFhN/jCE/rCmcxabB6jOOHV+0WNnylOxaxBQPSvcWklhA=="],
|
||||
|
||||
"caniuse-api/browserslist/baseline-browser-mapping": ["[email protected]", "", { "bin": { "baseline-browser-mapping": "dist/cli.js" } }, "sha512-ipDqC8FrAl/76p2SSWKSI+H9tFwm7vYqXQrItCuiVPt26Km0jS+NzSsBWAaBusvSbQcfJG+JitdMm+wZAgTYqg=="],
|
||||
|
||||
"caniuse-api/browserslist/electron-to-chromium": ["[email protected]", "", {}, "sha512-9tfDXhJ4RKFNerfjdCcZfufu49vg620741MNs26a9+bhLThdB+plgMeou98CAaHu/WATj2iHOOHTp1hWtABj2A=="],
|
||||
|
||||
"caniuse-api/browserslist/node-releases": ["[email protected]", "", {}, "sha512-nmh3lCkYZ3grZvqcCH+fjmQ7X+H0OeZgP40OierEaAptX4XofMh5kwNbWh7lBduUzCcV/8kZ+NDLCwm2iorIlA=="],
|
||||
|
||||
"cliui/wrap-ansi/ansi-styles": ["[email protected]", "", { "dependencies": { "color-convert": "^2.0.1" } }, "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg=="],
|
||||
|
||||
"core-js-compat/browserslist/baseline-browser-mapping": ["[email protected]", "", { "bin": { "baseline-browser-mapping": "dist/cli.js" } }, "sha512-ipDqC8FrAl/76p2SSWKSI+H9tFwm7vYqXQrItCuiVPt26Km0jS+NzSsBWAaBusvSbQcfJG+JitdMm+wZAgTYqg=="],
|
||||
|
||||
"core-js-compat/browserslist/caniuse-lite": ["[email protected]", "", {}, "sha512-x/2CLQ1jHENRbHg5PSId2sXq1CIO1CISvwWAj027ltMVG2UNgW+w9oH2+HzgEIRFembL8bUlXtfbBHR1fCg2xw=="],
|
||||
|
||||
"core-js-compat/browserslist/electron-to-chromium": ["[email protected]", "", {}, "sha512-9tfDXhJ4RKFNerfjdCcZfufu49vg620741MNs26a9+bhLThdB+plgMeou98CAaHu/WATj2iHOOHTp1hWtABj2A=="],
|
||||
|
||||
"core-js-compat/browserslist/node-releases": ["[email protected]", "", {}, "sha512-nmh3lCkYZ3grZvqcCH+fjmQ7X+H0OeZgP40OierEaAptX4XofMh5kwNbWh7lBduUzCcV/8kZ+NDLCwm2iorIlA=="],
|
||||
|
||||
"csso/css-tree/mdn-data": ["[email protected]", "", {}, "sha512-aylIc7Z9y4yzHYAJNuESG3hfhC+0Ibp/MAMiaOZgNv4pmEdFyfZhhhny4MNiAfWdBQ1RQ2mfDWmM1x8SvGyp8g=="],
|
||||
|
||||
"favilib/sharp/@img/sharp-darwin-arm64": ["@img/[email protected]", "", { "optionalDependencies": { "@img/sharp-libvips-darwin-arm64": "1.0.4" }, "os": "darwin", "cpu": "arm64" }, "sha512-UT4p+iz/2H4twwAoLCqfA9UH5pI6DggwKEGuaPy7nCVQ8ZsiY5PIcrRvD1DzuY3qYL07NtIQcWnBSY/heikIFQ=="],
|
||||
@@ -3367,6 +3466,10 @@
|
||||
|
||||
"filelist/minimatch/brace-expansion": ["[email protected]", "", { "dependencies": { "balanced-match": "^1.0.0" } }, "sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ=="],
|
||||
|
||||
"postcss-svgo/svgo/commander": ["[email protected]", "", {}, "sha512-yPVavfyCcRhmorC7rWlkHn15b4wDVgVmBA7kV4QVBsF7kv/9TKJAbAXVTxvTnwP8HHKjRCJDClKbciiYS7p0DQ=="],
|
||||
|
||||
"postcss-svgo/svgo/sax": ["[email protected]", "", {}, "sha512-6R3J5M4AcbtLUdZmRv2SygeVaM7IhrLXu9BmnOGmmACak8fiUtOsYNWUS4uK7upbmHIBbLBeFeI//477BKLBzA=="],
|
||||
|
||||
"readable-web-to-node-stream/readable-stream/string_decoder": ["[email protected]", "", { "dependencies": { "safe-buffer": "~5.2.0" } }, "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA=="],
|
||||
|
||||
"rimraf/glob/jackspeak": ["[email protected]", "", { "dependencies": { "@isaacs/cliui": "^8.0.2" }, "optionalDependencies": { "@pkgjs/parseargs": "^0.11.0" } }, "sha512-OGlZQpz2yfahA/Rd1Y8Cd9SIEsqvXkLVoSw/cgwhnhFMDbsQFeZYoJJ7bIZBS9BcamUW96asq/npPWugM+RQBw=="],
|
||||
@@ -3375,12 +3478,16 @@
|
||||
|
||||
"rimraf/glob/path-scurry": ["[email protected]", "", { "dependencies": { "lru-cache": "^10.2.0", "minipass": "^5.0.0 || ^6.0.2 || ^7.0.0" } }, "sha512-Xa4Nw17FS9ApQFJ9umLiJS4orGjm7ZzwUrwamcGQuHSzDyth9boKDaycYdDcZDuqYATXw4HFXgaqWTctW/v1HA=="],
|
||||
|
||||
"stats-gl/@types/three/meshoptimizer": ["[email protected]", "", {}, "sha512-IebiK79sqIy+E4EgOr+CAw+Ke8hAspXKzBd0JdgEmPHiAwmvEj2S4h1rfvo+o/BnfEYd/jAOg5IeeIjzlzSnDg=="],
|
||||
|
||||
"steam-appticket/protobufjs/@types/long": ["@types/[email protected]", "", {}, "sha512-MqTGEo5bj5t157U6fA/BiDynNkn0YknVdh48CMPkTSpFTVmvao5UQmm7uEF6xBEo7qIMAlY/JSleYaE6VOdpaA=="],
|
||||
|
||||
"steam-appticket/protobufjs/long": ["[email protected]", "", {}, "sha512-XsP+KhQif4bjX1kbuSiySJFNAehNxgLb6hPRGJ9QsUr8ajHkuXGdrHmFUTUUXhDwVX2R5bY4JNZEwbUiMhV+MA=="],
|
||||
|
||||
"unstorage/chokidar/readdirp": ["[email protected]", "", {}, "sha512-9u/XQ1pvrQtYyMpZe7DXKv2p5CNvyVwzUB6uhLAnQwHMSgKMBR62lc7AHljaeteeHXn11XTAaLLUVZYVZyuRBQ=="],
|
||||
|
||||
"vite/postcss/nanoid": ["[email protected]", "", { "bin": { "nanoid": "bin/nanoid.cjs" } }, "sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w=="],
|
||||
|
||||
"widest-line/string-width/emoji-regex": ["[email protected]", "", {}, "sha512-toUI84YS5YmxW219erniWD0CIVOo46xGKColeNQRgOzDorgBi1v4D71/OFzgD9GO2UGKIv1C3Sp8DAn0+j5w7A=="],
|
||||
|
||||
"widest-line/string-width/strip-ansi": ["[email protected]", "", { "dependencies": { "ansi-regex": "^6.0.1" } }, "sha512-gmBGslpoQJtgnMAvOVqGZpEz9dyoKTCzy2nfz/n8aIFhN/jCE/rCmcxabB6jOOHV+0WNnylOxaxBQPSvcWklhA=="],
|
||||
@@ -3389,6 +3496,86 @@
|
||||
|
||||
"wrap-ansi/strip-ansi/ansi-regex": ["[email protected]", "", {}, "sha512-Bq3SmSpyFHaWjPk8If9yc6svM8c56dB5BAtW4Qbw5jHTwwXXcTLoRMkpDJp6VL0XzlWaCHTXrkFURMYmD0sLqg=="],
|
||||
|
||||
"@blitzkit/website-ue/@astrojs/check/@astrojs/language-server/@astrojs/yaml2ts": ["@astrojs/[email protected]", "", { "dependencies": { "yaml": "^2.8.3" } }, "sha512-8oddpOae35pJsXPQXhTkM0ypfKPskVsh2bCxRtbf7e+/Epw2nReakFYpLKjZMEr75CsoF203PMnCocpfz0s69A=="],
|
||||
|
||||
"@blitzkit/website-ue/@astrojs/check/@astrojs/language-server/tinyglobby": ["[email protected]", "", { "dependencies": { "fdir": "^6.5.0", "picomatch": "^4.0.4" } }, "sha512-pn99VhoACYR8nFHhxqix+uvsbXineAasWm5ojXoN8xEwK5Kd3/TrhNn1wByuD52UxWRLy8pu+kRMniEi6Eq9Zg=="],
|
||||
|
||||
"@blitzkit/website-ue/@astrojs/check/@astrojs/language-server/volar-service-css": ["[email protected]", "", { "dependencies": { "vscode-css-languageservice": "^6.3.0", "vscode-languageserver-textdocument": "^1.0.11", "vscode-uri": "^3.0.8" }, "peerDependencies": { "@volar/language-service": "~2.4.0" }, "optionalPeers": ["@volar/language-service"] }, "sha512-K1qyOvBpE3rzdAv3e4/6Rv5yizrYPy5R/ne3IWCAzLBuMO4qBMV3kSqWzj6KUVe6S0AnN6wxF7cRkiaKfYMYJw=="],
|
||||
|
||||
"@blitzkit/website-ue/@astrojs/check/@astrojs/language-server/volar-service-emmet": ["[email protected]", "", { "dependencies": { "@emmetio/css-parser": "^0.4.1", "@emmetio/html-matcher": "^1.3.0", "@vscode/emmet-helper": "^2.9.3", "vscode-uri": "^3.0.8" }, "peerDependencies": { "@volar/language-service": "~2.4.0" }, "optionalPeers": ["@volar/language-service"] }, "sha512-xi5bC4m/VyE3zy/n2CXspKeDZs3qA41tHLTw275/7dNWM/RqE2z3BnDICQybHIVp/6G1iOQj5c1qXMgQC08TNg=="],
|
||||
|
||||
"@blitzkit/website-ue/@astrojs/check/@astrojs/language-server/volar-service-html": ["[email protected]", "", { "dependencies": { "vscode-html-languageservice": "^5.3.0", "vscode-languageserver-textdocument": "^1.0.11", "vscode-uri": "^3.0.8" }, "peerDependencies": { "@volar/language-service": "~2.4.0" }, "optionalPeers": ["@volar/language-service"] }, "sha512-eR6vCgMdmYAo4n+gcT7DSyBQbwB8S3HZZvSagTf0sxNaD4WppMCFfpqWnkrlGStPKMZvMiejRRVmqsX9dYcTvQ=="],
|
||||
|
||||
"@blitzkit/website-ue/@astrojs/check/@astrojs/language-server/volar-service-prettier": ["[email protected]", "", { "dependencies": { "vscode-uri": "^3.0.8" }, "peerDependencies": { "@volar/language-service": "~2.4.0", "prettier": "^2.2 || ^3.0" }, "optionalPeers": ["@volar/language-service", "prettier"] }, "sha512-Z6BCFSpGVCd8BPAsZ785Kce1BGlWd5ODqmqZGVuB14MJvrR4+CYz6cDy4F+igmE1gMifqfvMhdgT8Aud4M5ngg=="],
|
||||
|
||||
"@blitzkit/website-ue/@astrojs/check/@astrojs/language-server/volar-service-typescript": ["[email protected]", "", { "dependencies": { "path-browserify": "^1.0.1", "semver": "^7.6.2", "typescript-auto-import-cache": "^0.3.5", "vscode-languageserver-textdocument": "^1.0.11", "vscode-nls": "^5.2.0", "vscode-uri": "^3.0.8" }, "peerDependencies": { "@volar/language-service": "~2.4.0" }, "optionalPeers": ["@volar/language-service"] }, "sha512-l46Bx4cokkUedTd74ojO5H/zqHZJ8SUuyZ0IB8JN4jfRqUM3bQFBHoOwlZCyZmOeO0A3RQNkMnFclxO4c++gsg=="],
|
||||
|
||||
"@blitzkit/website-ue/@astrojs/check/@astrojs/language-server/volar-service-typescript-twoslash-queries": ["[email protected]", "", { "dependencies": { "vscode-uri": "^3.0.8" }, "peerDependencies": { "@volar/language-service": "~2.4.0" }, "optionalPeers": ["@volar/language-service"] }, "sha512-IdD13Z9N2Bu8EM6CM0fDV1E69olEYGHDU25X51YXmq8Y0CmJ2LNj6gOiBJgpS5JGUqFzECVhMNBW7R0sPdRTMQ=="],
|
||||
|
||||
"@blitzkit/website-ue/@astrojs/check/@astrojs/language-server/volar-service-yaml": ["[email protected]", "", { "dependencies": { "vscode-uri": "^3.0.8", "yaml-language-server": "~1.20.0" }, "peerDependencies": { "@volar/language-service": "~2.4.0" }, "optionalPeers": ["@volar/language-service"] }, "sha512-0c8bXDBeoATF9F6iPIlOuYTuZAC4c+yi0siQo920u7eiBJk8oQmUmg9cDUbR4+Gl++bvGP4plj3fErbJuPqdcQ=="],
|
||||
|
||||
"@blitzkit/website-ue/@astrojs/check/@astrojs/language-server/vscode-html-languageservice": ["[email protected]", "", { "dependencies": { "@vscode/l10n": "^0.0.18", "vscode-languageserver-textdocument": "^1.0.12", "vscode-languageserver-types": "^3.17.5", "vscode-uri": "^3.1.0" } }, "sha512-ulCrSnFnfQ16YzvwnYUgEbUEl/ZG7u2eV27YhvLObSHKkb8fw1Z9cgsnUwjTEeDIdJDoTDTDpxuhQwoenoLNMg=="],
|
||||
|
||||
"@blitzkit/website-ue/astro/esbuild/@esbuild/aix-ppc64": ["@esbuild/[email protected]", "", { "os": "aix", "cpu": "ppc64" }, "sha512-9fJMTNFTWZMh5qwrBItuziu834eOCUcEqymSH7pY+zoMVEZg3gcPuBNxH1EvfVYe9h0x/Ptw8KBzv7qxb7l8dg=="],
|
||||
|
||||
"@blitzkit/website-ue/astro/esbuild/@esbuild/android-arm": ["@esbuild/[email protected]", "", { "os": "android", "cpu": "arm" }, "sha512-i5D1hPY7GIQmXlXhs2w8AWHhenb00+GxjxRncS2ZM7YNVGNfaMxgzSGuO8o8SJzRc/oZwU2bcScvVERk03QhzA=="],
|
||||
|
||||
"@blitzkit/website-ue/astro/esbuild/@esbuild/android-arm64": ["@esbuild/[email protected]", "", { "os": "android", "cpu": "arm64" }, "sha512-YdghPYUmj/FX2SYKJ0OZxf+iaKgMsKHVPF1MAq/P8WirnSpCStzKJFjOjzsW0QQ7oIAiccHdcqjbHmJxRb/dmg=="],
|
||||
|
||||
"@blitzkit/website-ue/astro/esbuild/@esbuild/android-x64": ["@esbuild/[email protected]", "", { "os": "android", "cpu": "x64" }, "sha512-IN/0BNTkHtk8lkOM8JWAYFg4ORxBkZQf9zXiEOfERX/CzxW3Vg1ewAhU7QSWQpVIzTW+b8Xy+lGzdYXV6UZObQ=="],
|
||||
|
||||
"@blitzkit/website-ue/astro/esbuild/@esbuild/darwin-arm64": ["@esbuild/[email protected]", "", { "os": "darwin", "cpu": "arm64" }, "sha512-Re491k7ByTVRy0t3EKWajdLIr0gz2kKKfzafkth4Q8A5n1xTHrkqZgLLjFEHVD+AXdUGgQMq+Godfq45mGpCKg=="],
|
||||
|
||||
"@blitzkit/website-ue/astro/esbuild/@esbuild/darwin-x64": ["@esbuild/[email protected]", "", { "os": "darwin", "cpu": "x64" }, "sha512-vHk/hA7/1AckjGzRqi6wbo+jaShzRowYip6rt6q7VYEDX4LEy1pZfDpdxCBnGtl+A5zq8iXDcyuxwtv3hNtHFg=="],
|
||||
|
||||
"@blitzkit/website-ue/astro/esbuild/@esbuild/freebsd-arm64": ["@esbuild/[email protected]", "", { "os": "freebsd", "cpu": "arm64" }, "sha512-ipTYM2fjt3kQAYOvo6vcxJx3nBYAzPjgTCk7QEgZG8AUO3ydUhvelmhrbOheMnGOlaSFUoHXB6un+A7q4ygY9w=="],
|
||||
|
||||
"@blitzkit/website-ue/astro/esbuild/@esbuild/freebsd-x64": ["@esbuild/[email protected]", "", { "os": "freebsd", "cpu": "x64" }, "sha512-dDk0X87T7mI6U3K9VjWtHOXqwAMJBNN2r7bejDsc+j03SEjtD9HrOl8gVFByeM0aJksoUuUVU9TBaZa2rgj0oA=="],
|
||||
|
||||
"@blitzkit/website-ue/astro/esbuild/@esbuild/linux-arm": ["@esbuild/[email protected]", "", { "os": "linux", "cpu": "arm" }, "sha512-s6nPv2QkSupJwLYyfS+gwdirm0ukyTFNl3KTgZEAiJDd+iHZcbTPPcWCcRYH+WlNbwChgH2QkE9NSlNrMT8Gfw=="],
|
||||
|
||||
"@blitzkit/website-ue/astro/esbuild/@esbuild/linux-arm64": ["@esbuild/[email protected]", "", { "os": "linux", "cpu": "arm64" }, "sha512-sZOuFz/xWnZ4KH3YfFrKCf1WyPZHakVzTiqji3WDc0BCl2kBwiJLCXpzLzUBLgmp4veFZdvN5ChW4Eq/8Fc2Fg=="],
|
||||
|
||||
"@blitzkit/website-ue/astro/esbuild/@esbuild/linux-ia32": ["@esbuild/[email protected]", "", { "os": "linux", "cpu": "ia32" }, "sha512-yGlQYjdxtLdh0a3jHjuwOrxQjOZYD/C9PfdbgJJF3TIZWnm/tMd/RcNiLngiu4iwcBAOezdnSLAwQDPqTmtTYg=="],
|
||||
|
||||
"@blitzkit/website-ue/astro/esbuild/@esbuild/linux-loong64": ["@esbuild/[email protected]", "", { "os": "linux", "cpu": "none" }, "sha512-WO60Sn8ly3gtzhyjATDgieJNet/KqsDlX5nRC5Y3oTFcS1l0KWba+SEa9Ja1GfDqSF1z6hif/SkpQJbL63cgOA=="],
|
||||
|
||||
"@blitzkit/website-ue/astro/esbuild/@esbuild/linux-mips64el": ["@esbuild/[email protected]", "", { "os": "linux", "cpu": "none" }, "sha512-APsymYA6sGcZ4pD6k+UxbDjOFSvPWyZhjaiPyl/f79xKxwTnrn5QUnXR5prvetuaSMsb4jgeHewIDCIWljrSxw=="],
|
||||
|
||||
"@blitzkit/website-ue/astro/esbuild/@esbuild/linux-ppc64": ["@esbuild/[email protected]", "", { "os": "linux", "cpu": "ppc64" }, "sha512-eizBnTeBefojtDb9nSh4vvVQ3V9Qf9Df01PfawPcRzJH4gFSgrObw+LveUyDoKU3kxi5+9RJTCWlj4FjYXVPEA=="],
|
||||
|
||||
"@blitzkit/website-ue/astro/esbuild/@esbuild/linux-riscv64": ["@esbuild/[email protected]", "", { "os": "linux", "cpu": "none" }, "sha512-3Emwh0r5wmfm3ssTWRQSyVhbOHvqegUDRd0WhmXKX2mkHJe1SFCMJhagUleMq+Uci34wLSipf8Lagt4LlpRFWQ=="],
|
||||
|
||||
"@blitzkit/website-ue/astro/esbuild/@esbuild/linux-s390x": ["@esbuild/[email protected]", "", { "os": "linux", "cpu": "s390x" }, "sha512-pBHUx9LzXWBc7MFIEEL0yD/ZVtNgLytvx60gES28GcWMqil8ElCYR4kvbV2BDqsHOvVDRrOxGySBM9Fcv744hw=="],
|
||||
|
||||
"@blitzkit/website-ue/astro/esbuild/@esbuild/linux-x64": ["@esbuild/[email protected]", "", { "os": "linux", "cpu": "x64" }, "sha512-Czi8yzXUWIQYAtL/2y6vogER8pvcsOsk5cpwL4Gk5nJqH5UZiVByIY8Eorm5R13gq+DQKYg0+JyQoytLQas4dA=="],
|
||||
|
||||
"@blitzkit/website-ue/astro/esbuild/@esbuild/netbsd-arm64": ["@esbuild/[email protected]", "", { "os": "none", "cpu": "arm64" }, "sha512-sDpk0RgmTCR/5HguIZa9n9u+HVKf40fbEUt+iTzSnCaGvY9kFP0YKBWZtJaraonFnqef5SlJ8/TiPAxzyS+UoA=="],
|
||||
|
||||
"@blitzkit/website-ue/astro/esbuild/@esbuild/netbsd-x64": ["@esbuild/[email protected]", "", { "os": "none", "cpu": "x64" }, "sha512-P14lFKJl/DdaE00LItAukUdZO5iqNH7+PjoBm+fLQjtxfcfFE20Xf5CrLsmZdq5LFFZzb5JMZ9grUwvtVYzjiA=="],
|
||||
|
||||
"@blitzkit/website-ue/astro/esbuild/@esbuild/openbsd-arm64": ["@esbuild/[email protected]", "", { "os": "openbsd", "cpu": "arm64" }, "sha512-AIcMP77AvirGbRl/UZFTq5hjXK+2wC7qFRGoHSDrZ5v5b8DK/GYpXW3CPRL53NkvDqb9D+alBiC/dV0Fb7eJcw=="],
|
||||
|
||||
"@blitzkit/website-ue/astro/esbuild/@esbuild/openbsd-x64": ["@esbuild/[email protected]", "", { "os": "openbsd", "cpu": "x64" }, "sha512-DnW2sRrBzA+YnE70LKqnM3P+z8vehfJWHXECbwBmH/CU51z6FiqTQTHFenPlHmo3a8UgpLyH3PT+87OViOh1AQ=="],
|
||||
|
||||
"@blitzkit/website-ue/astro/esbuild/@esbuild/openharmony-arm64": ["@esbuild/[email protected]", "", { "os": "none", "cpu": "arm64" }, "sha512-NinAEgr/etERPTsZJ7aEZQvvg/A6IsZG/LgZy+81wON2huV7SrK3e63dU0XhyZP4RKGyTm7aOgmQk0bGp0fy2g=="],
|
||||
|
||||
"@blitzkit/website-ue/astro/esbuild/@esbuild/sunos-x64": ["@esbuild/[email protected]", "", { "os": "sunos", "cpu": "x64" }, "sha512-PanZ+nEz+eWoBJ8/f8HKxTTD172SKwdXebZ0ndd953gt1HRBbhMsaNqjTyYLGLPdoWHy4zLU7bDVJztF5f3BHA=="],
|
||||
|
||||
"@blitzkit/website-ue/astro/esbuild/@esbuild/win32-arm64": ["@esbuild/[email protected]", "", { "os": "win32", "cpu": "arm64" }, "sha512-B2t59lWWYrbRDw/tjiWOuzSsFh1Y/E95ofKz7rIVYSQkUYBjfSgf6oeYPNWHToFRr2zx52JKApIcAS/D5TUBnA=="],
|
||||
|
||||
"@blitzkit/website-ue/astro/esbuild/@esbuild/win32-ia32": ["@esbuild/[email protected]", "", { "os": "win32", "cpu": "ia32" }, "sha512-QLKSFeXNS8+tHW7tZpMtjlNb7HKau0QDpwm49u0vUp9y1WOF+PEzkU84y9GqYaAVW8aH8f3GcBck26jh54cX4Q=="],
|
||||
|
||||
"@blitzkit/website-ue/astro/esbuild/@esbuild/win32-x64": ["@esbuild/[email protected]", "", { "os": "win32", "cpu": "x64" }, "sha512-4uJGhsxuptu3OcpVAzli+/gWusVGwZZHTlS63hh++ehExkVT8SgiEf7/uC/PclrPPkLhZqGgCTjd0VWLo6xMqA=="],
|
||||
|
||||
"@blitzkit/website-ue/astro/vite/esbuild": ["[email protected]", "", { "optionalDependencies": { "@esbuild/aix-ppc64": "0.25.12", "@esbuild/android-arm": "0.25.12", "@esbuild/android-arm64": "0.25.12", "@esbuild/android-x64": "0.25.12", "@esbuild/darwin-arm64": "0.25.12", "@esbuild/darwin-x64": "0.25.12", "@esbuild/freebsd-arm64": "0.25.12", "@esbuild/freebsd-x64": "0.25.12", "@esbuild/linux-arm": "0.25.12", "@esbuild/linux-arm64": "0.25.12", "@esbuild/linux-ia32": "0.25.12", "@esbuild/linux-loong64": "0.25.12", "@esbuild/linux-mips64el": "0.25.12", "@esbuild/linux-ppc64": "0.25.12", "@esbuild/linux-riscv64": "0.25.12", "@esbuild/linux-s390x": "0.25.12", "@esbuild/linux-x64": "0.25.12", "@esbuild/netbsd-arm64": "0.25.12", "@esbuild/netbsd-x64": "0.25.12", "@esbuild/openbsd-arm64": "0.25.12", "@esbuild/openbsd-x64": "0.25.12", "@esbuild/openharmony-arm64": "0.25.12", "@esbuild/sunos-x64": "0.25.12", "@esbuild/win32-arm64": "0.25.12", "@esbuild/win32-ia32": "0.25.12", "@esbuild/win32-x64": "0.25.12" }, "bin": { "esbuild": "bin/esbuild" } }, "sha512-bbPBYYrtZbkt6Os6FiTLCTFxvq4tt3JKall1vRwshA3fdVztsLAatFaZobhkBC8/BrPetoa0oksYoKXoG4ryJg=="],
|
||||
|
||||
"@blitzkit/website-ue/astro/vite/picomatch": ["[email protected]", "", {}, "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q=="],
|
||||
|
||||
"@blitzkit/website-ue/astro/vite/postcss": ["[email protected]", "", { "dependencies": { "nanoid": "^3.3.11", "picocolors": "^1.1.1", "source-map-js": "^1.2.1" } }, "sha512-3Ybi1tAuwAP9s0r1UQ2J4n5Y0G05bJkpUIO0/bI9MhwmD70S5aTWbXGBwxHrelT+XM1k6dM0pk+SwNkpTRN7Pg=="],
|
||||
|
||||
"@blitzkit/website-ue/astro/vite/tinyglobby": ["[email protected]", "", { "dependencies": { "fdir": "^6.5.0", "picomatch": "^4.0.3" } }, "sha512-j2Zq4NyQYG5XMST4cbs02Ak8iJUdxRM0XI5QyxXuZOzKOINmWurp3smXu3y5wDcJrptwpSjgXHzIQxR0omXljQ=="],
|
||||
|
||||
"@blitzkit/website-ue/vite/esbuild/@esbuild/aix-ppc64": ["@esbuild/[email protected]", "", { "os": "aix", "cpu": "ppc64" }, "sha512-9fJMTNFTWZMh5qwrBItuziu834eOCUcEqymSH7pY+zoMVEZg3gcPuBNxH1EvfVYe9h0x/Ptw8KBzv7qxb7l8dg=="],
|
||||
|
||||
"@blitzkit/website-ue/vite/esbuild/@esbuild/android-arm": ["@esbuild/[email protected]", "", { "os": "android", "cpu": "arm" }, "sha512-i5D1hPY7GIQmXlXhs2w8AWHhenb00+GxjxRncS2ZM7YNVGNfaMxgzSGuO8o8SJzRc/oZwU2bcScvVERk03QhzA=="],
|
||||
@@ -3493,6 +3680,8 @@
|
||||
|
||||
"@blitzkit/website/vite/esbuild/@esbuild/win32-x64": ["@esbuild/[email protected]", "", { "os": "win32", "cpu": "x64" }, "sha512-4uJGhsxuptu3OcpVAzli+/gWusVGwZZHTlS63hh++ehExkVT8SgiEf7/uC/PclrPPkLhZqGgCTjd0VWLo6xMqA=="],
|
||||
|
||||
"@blitzkit/website/vite/postcss/nanoid": ["[email protected]", "", { "bin": { "nanoid": "bin/nanoid.cjs" } }, "sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w=="],
|
||||
|
||||
"boxen/string-width/strip-ansi/ansi-regex": ["[email protected]", "", {}, "sha512-Bq3SmSpyFHaWjPk8If9yc6svM8c56dB5BAtW4Qbw5jHTwwXXcTLoRMkpDJp6VL0XzlWaCHTXrkFURMYmD0sLqg=="],
|
||||
|
||||
"filelist/minimatch/brace-expansion/balanced-match": ["[email protected]", "", {}, "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw=="],
|
||||
@@ -3505,6 +3694,12 @@
|
||||
|
||||
"widest-line/string-width/strip-ansi/ansi-regex": ["[email protected]", "", {}, "sha512-Bq3SmSpyFHaWjPk8If9yc6svM8c56dB5BAtW4Qbw5jHTwwXXcTLoRMkpDJp6VL0XzlWaCHTXrkFURMYmD0sLqg=="],
|
||||
|
||||
"@blitzkit/website-ue/@astrojs/check/@astrojs/language-server/tinyglobby/picomatch": ["[email protected]", "", {}, "sha512-QP88BAKvMam/3NxH6vj2o21R6MjxZUAd6nlwAS/pnGvN9IVLocLHxGYIzFhg6fUQ+5th6P4dv4eW9jX3DSIj7A=="],
|
||||
|
||||
"@blitzkit/website-ue/@astrojs/check/@astrojs/language-server/volar-service-yaml/yaml-language-server": ["[email protected]", "", { "dependencies": { "@vscode/l10n": "^0.0.18", "ajv": "^8.17.1", "ajv-draft-04": "^1.0.0", "prettier": "^3.5.0", "request-light": "^0.5.7", "vscode-json-languageservice": "4.1.8", "vscode-languageserver": "^9.0.0", "vscode-languageserver-textdocument": "^1.0.1", "vscode-languageserver-types": "^3.16.0", "vscode-uri": "^3.0.2", "yaml": "2.7.1" }, "bin": { "yaml-language-server": "bin/yaml-language-server" } }, "sha512-qhjK/bzSRZ6HtTvgeFvjNPJGWdZ0+x5NREV/9XZWFjIGezew2b4r5JPy66IfOhd5OA7KeFwk1JfmEbnTvev0cA=="],
|
||||
|
||||
"@blitzkit/website-ue/astro/vite/postcss/nanoid": ["[email protected]", "", { "bin": { "nanoid": "bin/nanoid.cjs" } }, "sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w=="],
|
||||
|
||||
"rimraf/glob/jackspeak/@isaacs/cliui/string-width": ["[email protected]", "", { "dependencies": { "eastasianwidth": "^0.2.0", "emoji-regex": "^9.2.2", "strip-ansi": "^7.0.1" } }, "sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA=="],
|
||||
|
||||
"rimraf/glob/jackspeak/@isaacs/cliui/strip-ansi": ["[email protected]", "", { "dependencies": { "ansi-regex": "^6.0.1" } }, "sha512-gmBGslpoQJtgnMAvOVqGZpEz9dyoKTCzy2nfz/n8aIFhN/jCE/rCmcxabB6jOOHV+0WNnylOxaxBQPSvcWklhA=="],
|
||||
@@ -3513,6 +3708,10 @@
|
||||
|
||||
"rimraf/glob/minimatch/brace-expansion/balanced-match": ["[email protected]", "", {}, "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw=="],
|
||||
|
||||
"@blitzkit/website-ue/@astrojs/check/@astrojs/language-server/volar-service-yaml/yaml-language-server/request-light": ["[email protected]", "", {}, "sha512-3Zjgh+8b5fhRJBQZoy+zbVKpAQGLyka0MPgW3zruTF4dFFJ8Fqcfu9YsAvi/rvdcaTeWG3MkbZv4WKxAn/84Lg=="],
|
||||
|
||||
"@blitzkit/website-ue/@astrojs/check/@astrojs/language-server/volar-service-yaml/yaml-language-server/yaml": ["[email protected]", "", { "bin": { "yaml": "bin.mjs" } }, "sha512-10ULxpnOCQXxJvBgxsn9ptjq6uviG/htZKk9veJGhlqn3w/DxQ631zFF+nlQXLwmImeS5amR2dl2U8sg6U9jsQ=="],
|
||||
|
||||
"rimraf/glob/jackspeak/@isaacs/cliui/string-width/emoji-regex": ["[email protected]", "", {}, "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg=="],
|
||||
|
||||
"rimraf/glob/jackspeak/@isaacs/cliui/strip-ansi/ansi-regex": ["[email protected]", "", {}, "sha512-Bq3SmSpyFHaWjPk8If9yc6svM8c56dB5BAtW4Qbw5jHTwwXXcTLoRMkpDJp6VL0XzlWaCHTXrkFURMYmD0sLqg=="],
|
||||
|
||||
+27
@@ -0,0 +1,27 @@
|
||||
{
|
||||
"words": [
|
||||
"gltf",
|
||||
"amogos",
|
||||
"Tankopedia",
|
||||
"uasset",
|
||||
"oodle",
|
||||
"blitzkit",
|
||||
"webp",
|
||||
"hocs",
|
||||
"cooldown",
|
||||
"Lods",
|
||||
"Skia",
|
||||
"RMAO",
|
||||
"Verts",
|
||||
"drei",
|
||||
"frameloop",
|
||||
"pointermove",
|
||||
"pointerup",
|
||||
"pointerdown"
|
||||
],
|
||||
"userWords": [
|
||||
"WOTB",
|
||||
"USMAP",
|
||||
"favicons"
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
# BlitzKit 1.30.3
|
||||
|
||||
Thank you to [GonnaHetzMe](https://github.com/karelpak1) for your contributions this update.
|
||||
|
||||
## Features
|
||||
|
||||
- [GonnaHetzMe] Added tooltips to the module selector in Tankopedia
|
||||
|
||||
## Fixes
|
||||
|
||||
- Added aggressive re-rendering for the Guess mini-game's score readout to make inspect-element harder
|
||||
- Removed tank visual and collision model caching
|
||||
- Guesser once again breaks streaks if not all tiers are selected
|
||||
- BlitzKit now properly unloads tank models from memory when visually hidden in Guesser
|
||||
- [GonnaHetzMe] Tanks with complex transparency like the Herdbreaker once again handle opacity correctly
|
||||
- [GonnaHetzMe] Pieces of tank models that have transparency now handle culling properly (they're visible from both sides)
|
||||
- [GonnaHetzMe] Tanks with "cardboard" textures have been fixed, thanks to better PVR file parsing
|
||||
- [GonnaHetzMe] Tank icons are now scaled correctly so small tanks are now properly zoomed out in contrast to bigger ones
|
||||
@@ -0,0 +1,5 @@
|
||||
# BlitzKit 1.30.4
|
||||
|
||||
## Fixes
|
||||
|
||||
- BlitzKit now correctly implements minor WoTB updates
|
||||
@@ -0,0 +1,8 @@
|
||||
# BlitzKit 1.30.5
|
||||
|
||||
## Features
|
||||
|
||||
- Reduced the amount of code that executes for every rendered frame, hopefully improving performance
|
||||
- Reduced the number of lights by 20% to decrease the amount of shadow calculations
|
||||
- Decreased the ground size by 80% for an equal reduction in shadow texture sizes
|
||||
- Added the ability for BlitzKit to dismount the components that handled the intro lighting animation when not animating, reducing checks running every frame
|
||||
@@ -0,0 +1,7 @@
|
||||
# BlitzKit 1.30.6
|
||||
|
||||
## Fixes
|
||||
|
||||
- Tanks no longer "randomly" appear dark in Tankopedia and Mixer
|
||||
- The ground is now as dark as other modes when Static Armor is selected in Tankopedia
|
||||
- Fixed some naming issues with the "equal" icon, improving performance a tiny tiny bit
|
||||
@@ -0,0 +1,13 @@
|
||||
{
|
||||
"version": 1,
|
||||
"isRoot": true,
|
||||
"tools": {
|
||||
"csharpier": {
|
||||
"version": "1.3.0",
|
||||
"commands": [
|
||||
"csharpier"
|
||||
],
|
||||
"rollForward": false
|
||||
}
|
||||
}
|
||||
}
|
||||
+3
-1
@@ -7,13 +7,15 @@
|
||||
"setup": "chmod a+x scripts/*.sh && ./scripts/setup.sh",
|
||||
"dev": "./scripts/dev.sh",
|
||||
"build-game": "./scripts/build_game.sh",
|
||||
"build-website": "./scripts/build_website.sh"
|
||||
"build-website": "./scripts/build_website.sh",
|
||||
"discover-servers": "./scripts/discover_servers.sh"
|
||||
},
|
||||
"type": "module",
|
||||
"workspaces": [
|
||||
"packages/*"
|
||||
],
|
||||
"dependencies": {
|
||||
"prettier": "^3.8.3",
|
||||
"typescript": "^5.9.3"
|
||||
}
|
||||
}
|
||||
@@ -1,18 +0,0 @@
|
||||
{
|
||||
"name": "@blitzkit/app",
|
||||
"private": true,
|
||||
"type": "module",
|
||||
"scripts": {
|
||||
"dev": "vite",
|
||||
"build": "tsc && vite build",
|
||||
"preview": "vite preview",
|
||||
"tauri": "tauri"
|
||||
},
|
||||
"dependencies": {
|
||||
"@tauri-apps/api": "^2",
|
||||
"@tauri-apps/plugin-opener": "^2",
|
||||
"@tauri-apps/cli": "^2",
|
||||
"vite": "^6.0.3",
|
||||
"typescript": "~5.6.2"
|
||||
}
|
||||
}
|
||||
@@ -1,7 +0,0 @@
|
||||
# Generated by Cargo
|
||||
# will have compiled files and executables
|
||||
/target/
|
||||
|
||||
# Generated by Tauri
|
||||
# will have schema files for capabilities auto-completion
|
||||
/gen/schemas
|
||||
Generated
-5286
File diff suppressed because it is too large.
Load diff
@@ -1,25 +0,0 @@
|
||||
[package]
|
||||
name = "blitzkit"
|
||||
version = "0.1.0"
|
||||
description = "A Tauri App"
|
||||
authors = ["you"]
|
||||
edition = "2021"
|
||||
|
||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
|
||||
[lib]
|
||||
# The `_lib` suffix may seem redundant but it is necessary
|
||||
# to make the lib name unique and wouldn't conflict with the bin name.
|
||||
# This seems to be only an issue on Windows, see https://github.com/rust-lang/cargo/issues/8519
|
||||
name = "blitzkit_lib"
|
||||
crate-type = ["staticlib", "cdylib", "rlib"]
|
||||
|
||||
[build-dependencies]
|
||||
tauri-build = { version = "2", features = [] }
|
||||
|
||||
[dependencies]
|
||||
tauri = { version = "2", features = [] }
|
||||
tauri-plugin-opener = "2"
|
||||
serde = { version = "1", features = ["derive"] }
|
||||
serde_json = "1"
|
||||
|
||||
@@ -1,3 +0,0 @@
|
||||
fn main() {
|
||||
tauri_build::build()
|
||||
}
|
||||
@@ -1,10 +0,0 @@
|
||||
{
|
||||
"$schema": "../gen/schemas/desktop-schema.json",
|
||||
"identifier": "default",
|
||||
"description": "Capability for the main window",
|
||||
"windows": ["main"],
|
||||
"permissions": [
|
||||
"core:default",
|
||||
"opener:default"
|
||||
]
|
||||
}
|
||||
@@ -1,14 +0,0 @@
|
||||
// Learn more about Tauri commands at https://tauri.app/develop/calling-rust/
|
||||
#[tauri::command]
|
||||
fn greet(name: &str) -> String {
|
||||
format!("Hello, {}! You've been greeted from Rust!", name)
|
||||
}
|
||||
|
||||
#[cfg_attr(mobile, tauri::mobile_entry_point)]
|
||||
pub fn run() {
|
||||
tauri::Builder::default()
|
||||
.plugin(tauri_plugin_opener::init())
|
||||
.invoke_handler(tauri::generate_handler![greet])
|
||||
.run(tauri::generate_context!())
|
||||
.expect("error while running tauri application");
|
||||
}
|
||||
@@ -1,27 +0,0 @@
|
||||
#![cfg_attr(not(debug_assertions), windows_subsystem = "windows")]
|
||||
|
||||
use std::process::{Command, Stdio};
|
||||
use tauri::Manager;
|
||||
|
||||
fn main() {
|
||||
tauri::Builder::default()
|
||||
.setup(|app| {
|
||||
let app_handle = app.handle();
|
||||
|
||||
let entry = app_handle
|
||||
.path_resolver()
|
||||
.resolve_resource("../../dist/website/server/entry.mjs")
|
||||
.expect("failed to resolve server.ts");
|
||||
|
||||
Command::new("bun")
|
||||
.arg("run")
|
||||
.arg(entry)
|
||||
.stderr(Stdio::null())
|
||||
.spawn()
|
||||
.expect("failed to start Bun server");
|
||||
|
||||
Ok(())
|
||||
})
|
||||
.run(tauri::generate_context!())
|
||||
.expect("error while running Tauri app");
|
||||
}
|
||||
@@ -1,38 +0,0 @@
|
||||
{
|
||||
"$schema": "https://schema.tauri.app/config/2",
|
||||
"productName": "blitzkit",
|
||||
"version": "0.1.0",
|
||||
"identifier": "com.tresabhi.blitzkit",
|
||||
"build": {
|
||||
"beforeDevCommand": "cd ../website && bun run dev",
|
||||
"_beforeBuildCommand": "cd ../website && bun run build",
|
||||
"frontendDist": "../../../dist/website/client",
|
||||
"devUrl": "http://localhost:4321"
|
||||
},
|
||||
"app": {
|
||||
"withGlobalTauri": true,
|
||||
"windows": [
|
||||
{
|
||||
"url": "http://localhost:4321",
|
||||
"title": "BlitzKit",
|
||||
"fullscreen": false,
|
||||
"resizable": true,
|
||||
"maximized": true
|
||||
}
|
||||
],
|
||||
"security": {
|
||||
"csp": null
|
||||
}
|
||||
},
|
||||
"bundle": {
|
||||
"active": true,
|
||||
"targets": "all",
|
||||
"icon": [
|
||||
"icons/32x32.png",
|
||||
"icons/128x128.png",
|
||||
"icons/[email protected]",
|
||||
"icons/icon.icns",
|
||||
"icons/icon.ico"
|
||||
]
|
||||
}
|
||||
}
|
||||
@@ -1,19 +0,0 @@
|
||||
{
|
||||
"extends": ["../../tsconfig.json"],
|
||||
"compilerOptions": {
|
||||
"target": "ES2020",
|
||||
"useDefineForClassFields": true,
|
||||
"module": "ESNext",
|
||||
"lib": ["ES2020", "DOM", "DOM.Iterable"],
|
||||
"skipLibCheck": true,
|
||||
"moduleResolution": "bundler",
|
||||
"allowImportingTsExtensions": true,
|
||||
"resolveJsonModule": true,
|
||||
"isolatedModules": true,
|
||||
"noEmit": true,
|
||||
"strict": true,
|
||||
"noUnusedLocals": true,
|
||||
"noUnusedParameters": true,
|
||||
"noFallthroughCasesInSwitch": true
|
||||
}
|
||||
}
|
||||
@@ -1,35 +0,0 @@
|
||||
{
|
||||
"name": "@blitzkit/bot",
|
||||
"dependencies": {
|
||||
"@blitzkit/core": "workspace:*",
|
||||
"@blitzkit/i18n": "workspace:*",
|
||||
"@radix-ui/colors": "^3.0.0",
|
||||
"@radix-ui/themes": "^3.3.0",
|
||||
"@resvg/resvg-js": "^2.6.2",
|
||||
"@types/adm-zip": "^0.5.7",
|
||||
"@types/bun": "^1.3.9",
|
||||
"@types/lodash-es": "^4.17.12",
|
||||
"@types/markdown-escape": "^1.1.3",
|
||||
"@types/react": "^19.2.14",
|
||||
"adm-zip": "^0.5.16",
|
||||
"bepaint": "^0.1.0-beta.3",
|
||||
"discord.js": "^14.25.1",
|
||||
"dotenv": "^17.3.1",
|
||||
"fuzzysort": "^3.1.0",
|
||||
"lodash-es": "^4.17.23",
|
||||
"markdown-escape": "^2.0.0",
|
||||
"pickleparser": "^0.2.1",
|
||||
"prisma": "^6.19.2",
|
||||
"protobufjs": "^7.5.4",
|
||||
"react": "^19.2.4",
|
||||
"satori": "^0.18.4",
|
||||
"sharp": "^0.34.5"
|
||||
},
|
||||
"private": true,
|
||||
"scripts": {
|
||||
"dev": "bun --watch src/main.ts",
|
||||
"start": "bun src/main.ts"
|
||||
},
|
||||
"type": "module",
|
||||
"types": "src/types.d.ts"
|
||||
}
|
||||
@@ -1,68 +0,0 @@
|
||||
import { createLocalizedCommand } from "../core/discord/createLocalizedCommand";
|
||||
import { translator } from "../core/localization/translator";
|
||||
import {
|
||||
commandsArray,
|
||||
type CommandRegistry,
|
||||
} from "../events/interactionCreate";
|
||||
|
||||
const subcommands = [
|
||||
"embeds",
|
||||
"introduction",
|
||||
"invite",
|
||||
"timezones",
|
||||
"credits",
|
||||
] as const;
|
||||
type Subcommand = (typeof subcommands)[number];
|
||||
|
||||
const DOCS: Record<Subcommand, string> = {
|
||||
embeds: "guide/embeds",
|
||||
introduction: "guide/introduction",
|
||||
invite: "guide/invite",
|
||||
timezones: "guide/timezones",
|
||||
credits: "about/credits",
|
||||
};
|
||||
|
||||
export const aboutCommand = new Promise<CommandRegistry>(async (resolve) => {
|
||||
resolve({
|
||||
command: createLocalizedCommand("about", [
|
||||
{ subcommand: "commands" },
|
||||
...subcommands.map((subcommand) => ({ subcommand })),
|
||||
]),
|
||||
|
||||
async handler(interaction) {
|
||||
const subcommand = interaction.options.getSubcommand();
|
||||
const { strings } = translator(interaction.locale);
|
||||
|
||||
if (subcommand === "commands") {
|
||||
return `${strings.bot.commands.about.subcommands.commands.body}${(
|
||||
await Promise.all(commandsArray)
|
||||
)
|
||||
.sort((a, b) =>
|
||||
(a.command.name_localizations?.[interaction.locale] ??
|
||||
a.command.name) <
|
||||
(b.command.name_localizations?.[interaction.locale] ??
|
||||
b.command.name)
|
||||
? -1
|
||||
: 1,
|
||||
)
|
||||
.map(
|
||||
(registry) =>
|
||||
`- \`/${
|
||||
registry.command.name_localizations?.[interaction.locale] ??
|
||||
registry.command.name
|
||||
}\`: ${
|
||||
registry.command.description_localizations?.[
|
||||
interaction.locale
|
||||
] ?? registry.command.description
|
||||
}`,
|
||||
)
|
||||
.join("\n")}`;
|
||||
}
|
||||
|
||||
const url = `https://raw.githubusercontent.com/tresabhi/blitzkit/main/docs/${DOCS[subcommand as Subcommand]}.md`;
|
||||
const content = fetch(url).then((response) => response.text());
|
||||
|
||||
return content;
|
||||
},
|
||||
});
|
||||
});
|
||||
@@ -1,65 +0,0 @@
|
||||
import { addPeriodicFilterOptions } from "../../core/discord/addPeriodicFilterOptions";
|
||||
import { addUsernameChoices } from "../../core/discord/addUsernameChoices";
|
||||
import { autocompleteTanks } from "../../core/discord/autocompleteTanks";
|
||||
import { autocompleteUsername } from "../../core/discord/autocompleteUsername";
|
||||
import { createLocalizedCommand } from "../../core/discord/createLocalizedCommand";
|
||||
import { getFiltersFromButton } from "../../core/discord/getFiltersFromButton";
|
||||
import { resolvePeriodFromButton } from "../../core/discord/resolvePeriodFromButton";
|
||||
import { resolvePlayerFromButton } from "../../core/discord/resolvePlayerFromButton";
|
||||
import { translator } from "../../core/localization/translator";
|
||||
import type { CommandRegistry } from "../../events/interactionCreate";
|
||||
import { renderBreakdown } from "./render";
|
||||
|
||||
export const breakdownCommand = new Promise<CommandRegistry>(
|
||||
async (resolve) => {
|
||||
resolve({
|
||||
command: await addPeriodicFilterOptions(
|
||||
createLocalizedCommand("breakdown"),
|
||||
(option) => option.addStringOption(addUsernameChoices),
|
||||
),
|
||||
|
||||
async handler(interaction) {
|
||||
const { strings } = translator(interaction.locale);
|
||||
return strings.bot.commands.dead;
|
||||
|
||||
// const player = await resolvePlayerFromCommand(interaction);
|
||||
// const period = resolvePeriodFromCommand(player.region, interaction);
|
||||
// const filters = await getFiltersFromCommand(interaction);
|
||||
// const path = commandToURL(interaction, {
|
||||
// ...player,
|
||||
// ...getCustomPeriodParams(interaction),
|
||||
// ...filters,
|
||||
// });
|
||||
|
||||
// return [
|
||||
// ...(await renderBreakdown(
|
||||
// player,
|
||||
// period,
|
||||
// filters,
|
||||
// interaction.locale,
|
||||
// )),
|
||||
// buttonRefresh(interaction, path),
|
||||
// await getBlitzStarsLinkButton(player.region, player.id),
|
||||
// ];
|
||||
},
|
||||
|
||||
autocomplete: (interaction) => {
|
||||
autocompleteUsername(interaction);
|
||||
autocompleteTanks(interaction);
|
||||
},
|
||||
|
||||
async button(interaction) {
|
||||
const player = await resolvePlayerFromButton(interaction);
|
||||
const period = resolvePeriodFromButton(player.region, interaction);
|
||||
const filters = getFiltersFromButton(interaction);
|
||||
|
||||
return await renderBreakdown(
|
||||
player,
|
||||
period,
|
||||
filters,
|
||||
interaction.locale,
|
||||
);
|
||||
},
|
||||
});
|
||||
},
|
||||
);
|
||||
@@ -1,295 +0,0 @@
|
||||
import {
|
||||
type BlitzStats,
|
||||
calculateWN8,
|
||||
getAccountInfo,
|
||||
getClanAccountInfo,
|
||||
getTankStats,
|
||||
getWN8Percentile,
|
||||
TankDefinition,
|
||||
} from "@blitzkit/core";
|
||||
import { literals } from "@blitzkit/i18n";
|
||||
import { Locale } from "discord.js";
|
||||
import { chunk } from "lodash-es";
|
||||
import * as Breakdown from "../../components/Breakdown";
|
||||
import { CommandWrapper } from "../../components/CommandWrapper";
|
||||
import { NoData } from "../../components/NoData";
|
||||
import { TitleBar } from "../../components/TitleBar";
|
||||
import { filtersToDescription } from "../../core/blitzkit/filtersToDescription";
|
||||
import {
|
||||
averageDefinitions,
|
||||
tankDefinitions,
|
||||
} from "../../core/blitzkit/nonBlockingPromises";
|
||||
import { UserError } from "../../core/blitzkit/userError";
|
||||
import {
|
||||
filterStats,
|
||||
type StatFilters,
|
||||
} from "../../core/blitzstars/filterStats";
|
||||
import { getStatsInPeriod } from "../../core/blitzstars/getStatsInPeriod";
|
||||
import type { ResolvedPeriod } from "../../core/discord/resolvePeriodFromCommand";
|
||||
import type { ResolvedPlayer } from "../../core/discord/resolvePlayerFromCommand";
|
||||
import { translator } from "../../core/localization/translator";
|
||||
|
||||
const ROWS_PER_PAGE = 8;
|
||||
const MAX_PAGES = 9;
|
||||
|
||||
export async function renderBreakdown(
|
||||
{ region, id }: ResolvedPlayer,
|
||||
{ start, end, name }: ResolvedPeriod,
|
||||
filters: StatFilters,
|
||||
locale: Locale,
|
||||
) {
|
||||
const { strings, unwrap } = translator(locale);
|
||||
const awaitedTankDefinitions = await tankDefinitions;
|
||||
const awaitedTankAverages = await averageDefinitions;
|
||||
const statsInPeriod = await getStatsInPeriod(region, id, start, end, locale);
|
||||
const { filteredOrder } = await filterStats(statsInPeriod, filters);
|
||||
const accountInfo = await getAccountInfo(region, id);
|
||||
const clanData = await getClanAccountInfo(region, id, ["clan"]);
|
||||
const tankStats = await getTankStats(region, id);
|
||||
const filterDescriptions = await filtersToDescription(filters, locale);
|
||||
const orderedCurrentStats: BlitzStats[] = [];
|
||||
const orderedCareerStats: BlitzStats[] = [];
|
||||
const orderedCurrentWN8: (number | undefined)[] = [];
|
||||
const orderedCareerWN8: (number | undefined)[] = [];
|
||||
const orderedCareerWN8Full: (number | undefined)[] = [];
|
||||
|
||||
if (tankStats === null) {
|
||||
throw new UserError(strings.bot.common.errors.no_tank_stats);
|
||||
}
|
||||
|
||||
filteredOrder.forEach((id) => {
|
||||
const tankAveragesEntry = awaitedTankAverages.averages[id];
|
||||
const current = statsInPeriod.diff[id];
|
||||
const career = tankStats.find((tank) => tank.tank_id === id)!.all;
|
||||
const currentWN8 = tankAveragesEntry
|
||||
? calculateWN8(tankAveragesEntry.mu, current)
|
||||
: undefined;
|
||||
const careerWN8 = tankAveragesEntry
|
||||
? calculateWN8(tankAveragesEntry.mu, career)
|
||||
: undefined;
|
||||
|
||||
orderedCurrentStats.push(current);
|
||||
orderedCareerStats.push(career);
|
||||
orderedCurrentWN8.push(currentWN8);
|
||||
orderedCareerWN8.push(careerWN8);
|
||||
});
|
||||
tankStats.forEach((tank) => {
|
||||
const tankAveragesEntry = awaitedTankAverages.averages[tank.tank_id];
|
||||
|
||||
orderedCareerWN8Full.push(
|
||||
tankAveragesEntry
|
||||
? calculateWN8(tankAveragesEntry.mu, tank.all)
|
||||
: undefined,
|
||||
);
|
||||
});
|
||||
|
||||
const currentBattles = orderedCurrentStats.reduce(
|
||||
(accumulator, current) => accumulator + current.battles,
|
||||
0,
|
||||
);
|
||||
const careerBattles = tankStats.reduce(
|
||||
(accumulator, current) => accumulator + current.all.battles,
|
||||
0,
|
||||
);
|
||||
const currentWinrate =
|
||||
orderedCurrentStats.reduce(
|
||||
(accumulator, current) => accumulator + current.wins,
|
||||
0,
|
||||
) / currentBattles;
|
||||
const careerWinrate =
|
||||
tankStats.reduce(
|
||||
(accumulator, current) => accumulator + current.all.wins,
|
||||
0,
|
||||
) / careerBattles;
|
||||
const currentWN8 =
|
||||
orderedCurrentWN8.reduce<number>(
|
||||
(accumulator, current, index) =>
|
||||
accumulator + (current ?? 0) * orderedCurrentStats[index].battles,
|
||||
0,
|
||||
) /
|
||||
orderedCurrentStats.reduce(
|
||||
(accumulator, current, index) =>
|
||||
accumulator +
|
||||
(orderedCurrentWN8[index] === undefined ? 0 : current.battles),
|
||||
0,
|
||||
);
|
||||
const careerWN8 =
|
||||
orderedCareerWN8Full.reduce<number>(
|
||||
(accumulator, current) => accumulator + (current ?? 0),
|
||||
0,
|
||||
) /
|
||||
tankStats.reduce(
|
||||
(accumulator, current, index) =>
|
||||
accumulator +
|
||||
(orderedCareerWN8Full[index] === undefined ? 0 : current.all.battles),
|
||||
0,
|
||||
);
|
||||
const currentDamage =
|
||||
orderedCurrentStats.reduce(
|
||||
(accumulator, current) => accumulator + current.damage_dealt,
|
||||
0,
|
||||
) / currentBattles;
|
||||
const careerDamage =
|
||||
tankStats.reduce(
|
||||
(accumulator, current) => accumulator + current.all.damage_dealt,
|
||||
0,
|
||||
) / careerBattles;
|
||||
|
||||
const children: React.JSX.Element[] = [];
|
||||
|
||||
if (filteredOrder.length > 0) {
|
||||
children.push(
|
||||
<Breakdown.Row
|
||||
key={id}
|
||||
displayType="summary"
|
||||
title={strings.bot.commands.breakdown.body.total}
|
||||
stats={[
|
||||
{
|
||||
title: strings.bot.commands.breakdown.body.battles,
|
||||
current: currentBattles,
|
||||
career: careerBattles,
|
||||
},
|
||||
{
|
||||
title: strings.bot.commands.breakdown.body.winrate,
|
||||
current: `${(100 * currentWinrate).toFixed(2)}%`,
|
||||
career: `${(100 * careerWinrate).toFixed(2)}%`,
|
||||
delta: currentWinrate - careerWinrate,
|
||||
},
|
||||
{
|
||||
title: strings.bot.commands.breakdown.body.wn8,
|
||||
current:
|
||||
currentWN8 === undefined
|
||||
? undefined
|
||||
: Math.round(currentWN8).toLocaleString(),
|
||||
career:
|
||||
careerWN8 === undefined
|
||||
? undefined
|
||||
: Math.round(careerWN8).toLocaleString(),
|
||||
percentile:
|
||||
currentWN8 === undefined
|
||||
? undefined
|
||||
: getWN8Percentile(currentWN8),
|
||||
},
|
||||
{
|
||||
title: strings.bot.commands.breakdown.body.damage,
|
||||
current: Math.round(currentDamage).toLocaleString(),
|
||||
career: Math.round(careerDamage).toLocaleString(),
|
||||
delta: currentDamage - careerDamage,
|
||||
},
|
||||
]}
|
||||
/>,
|
||||
);
|
||||
|
||||
filteredOrder.forEach((id, index) => {
|
||||
const tankDefinition = awaitedTankDefinitions.tanks[id] as
|
||||
| TankDefinition
|
||||
| undefined;
|
||||
const current = orderedCurrentStats[index];
|
||||
const career = orderedCareerStats[index];
|
||||
const currentWN8 = orderedCurrentWN8[index];
|
||||
const careerWN8 = orderedCareerWN8[index];
|
||||
|
||||
children.push(
|
||||
<Breakdown.Row
|
||||
key={id}
|
||||
displayType="tank"
|
||||
class={tankDefinition?.class}
|
||||
type={tankDefinition?.type}
|
||||
title={
|
||||
tankDefinition
|
||||
? unwrap(tankDefinition.name)
|
||||
: literals(strings.bot.commands.breakdown.body.unknown_tank, {
|
||||
id,
|
||||
})
|
||||
}
|
||||
stats={[
|
||||
{
|
||||
title: strings.bot.commands.breakdown.body.battles,
|
||||
current: current.battles.toLocaleString(),
|
||||
career: career.battles.toLocaleString(),
|
||||
},
|
||||
{
|
||||
title: strings.bot.commands.breakdown.body.winrate,
|
||||
current: `${(100 * (current.wins / current.battles)).toFixed(
|
||||
2,
|
||||
)}%`,
|
||||
career: `${(100 * (career.wins / career.battles)).toFixed(2)}%`,
|
||||
delta:
|
||||
current.wins / current.battles - career.wins / career.battles,
|
||||
},
|
||||
{
|
||||
title: strings.bot.commands.breakdown.body.wn8,
|
||||
current:
|
||||
currentWN8 === undefined
|
||||
? undefined
|
||||
: Math.round(currentWN8).toLocaleString(),
|
||||
career:
|
||||
careerWN8 === undefined
|
||||
? undefined
|
||||
: Math.round(careerWN8).toLocaleString(),
|
||||
percentile:
|
||||
currentWN8 === undefined
|
||||
? undefined
|
||||
: getWN8Percentile(currentWN8),
|
||||
},
|
||||
{
|
||||
title: strings.bot.commands.breakdown.body.damage,
|
||||
current: Math.round(
|
||||
current.damage_dealt / current.battles,
|
||||
).toLocaleString(),
|
||||
career: Math.round(
|
||||
career.damage_dealt / career.battles,
|
||||
).toLocaleString(),
|
||||
delta:
|
||||
current.damage_dealt / current.battles -
|
||||
career.damage_dealt / career.battles,
|
||||
},
|
||||
]}
|
||||
/>,
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
const pages = chunk(
|
||||
children,
|
||||
Math.max(Math.ceil(children.length / MAX_PAGES), ROWS_PER_PAGE),
|
||||
);
|
||||
|
||||
if (filteredOrder.length > 0) {
|
||||
return pages
|
||||
.map((page, index) => (
|
||||
<CommandWrapper>
|
||||
{index === 0 && (
|
||||
<TitleBar
|
||||
title={accountInfo.nickname}
|
||||
image={
|
||||
clanData?.clan
|
||||
? `https://wotblitz-gc.gcdn.co/icons/clanEmblems1x/clan-icon-v2-${clanData?.clan?.emblem_set_id}.png`
|
||||
: undefined
|
||||
}
|
||||
description={`${name} • ${filterDescriptions}`}
|
||||
/>
|
||||
)}
|
||||
|
||||
<Breakdown.Root>{page}</Breakdown.Root>
|
||||
</CommandWrapper>
|
||||
))
|
||||
.reverse();
|
||||
} else {
|
||||
return [
|
||||
<CommandWrapper>
|
||||
<TitleBar
|
||||
title={accountInfo.nickname}
|
||||
image={
|
||||
clanData?.clan
|
||||
? `https://wotblitz-gc.gcdn.co/icons/clanEmblems1x/clan-icon-v2-${clanData?.clan?.emblem_set_id}.png`
|
||||
: undefined
|
||||
}
|
||||
description={`${name} • ${filterDescriptions}`}
|
||||
/>
|
||||
|
||||
<NoData type="battles_in_period" locale={locale} />
|
||||
</CommandWrapper>,
|
||||
];
|
||||
}
|
||||
}
|
||||
@@ -1,37 +0,0 @@
|
||||
import packageJSON from "../../../../package.json";
|
||||
import { client } from "../core/discord/client";
|
||||
import { createLocalizedCommand } from "../core/discord/createLocalizedCommand";
|
||||
import { translator } from "../core/localization/translator";
|
||||
import type { CommandRegistry } from "../events/interactionCreate";
|
||||
|
||||
const executionStart = new Date().getTime();
|
||||
|
||||
export const debugCommand = new Promise<CommandRegistry>((resolve) => {
|
||||
resolve({
|
||||
command: createLocalizedCommand("debug"),
|
||||
|
||||
async handler(interaction) {
|
||||
const { strings } = translator(interaction.locale);
|
||||
const currentTime = new Date().getTime();
|
||||
const uptime = currentTime - executionStart;
|
||||
const list = [
|
||||
[strings.bot.commands.debug.body.version, packageJSON.version],
|
||||
[
|
||||
strings.bot.commands.debug.body.shard.label,
|
||||
client.shard?.ids[0] ?? strings.bot.commands.debug.body.shard.default,
|
||||
],
|
||||
[
|
||||
strings.bot.commands.debug.body.uptime,
|
||||
`${Math.floor((uptime / 1000 / 60 / 60) % 24)}h ${Math.floor(
|
||||
(uptime / 1000 / 60) % 60
|
||||
)}m ${Math.floor((uptime / 1000) % 60)}s ${Math.floor(
|
||||
uptime % 1000
|
||||
)}ms`,
|
||||
],
|
||||
];
|
||||
return `${strings.bot.commands.debug.body.title}${list
|
||||
.map(([key, value]) => `- ${key}: ${value}`)
|
||||
.join("\n")}`;
|
||||
},
|
||||
});
|
||||
});
|
||||
@@ -1,182 +0,0 @@
|
||||
import { emblemURL, getAccountInfo, getClanAccountInfo } from "@blitzkit/core";
|
||||
import { Locale, SlashCommandSubcommandGroupBuilder } from "discord.js";
|
||||
import { CommandWrapper } from "../components/CommandWrapper";
|
||||
import * as Graph from "../components/Graph";
|
||||
import { LineColor } from "../components/Graph/components/Line/constants";
|
||||
import { NoData } from "../components/NoData";
|
||||
import { TitleBar } from "../components/TitleBar";
|
||||
import { getPlayerHistories } from "../core/blitzstars/getPlayerHistories";
|
||||
import { getTankHistories } from "../core/blitzstars/getTankHistories";
|
||||
import { addPeriodSubCommands } from "../core/discord/addPeriodSubCommands";
|
||||
import { addTankChoices } from "../core/discord/addTankChoices";
|
||||
import { addUsernameChoices } from "../core/discord/addUsernameChoices";
|
||||
import { autocompleteTanks } from "../core/discord/autocompleteTanks";
|
||||
import { autocompleteUsername } from "../core/discord/autocompleteUsername";
|
||||
import { createLocalizedCommand } from "../core/discord/createLocalizedCommand";
|
||||
import { resolvePeriodFromButton } from "../core/discord/resolvePeriodFromButton";
|
||||
import { type ResolvedPeriod } from "../core/discord/resolvePeriodFromCommand";
|
||||
import { resolvePlayerFromButton } from "../core/discord/resolvePlayerFromButton";
|
||||
import { type ResolvedPlayer } from "../core/discord/resolvePlayerFromCommand";
|
||||
import { translator } from "../core/localization/translator";
|
||||
import type { CommandRegistry } from "../events/interactionCreate";
|
||||
|
||||
type EvolutionStatType = "player" | "tank";
|
||||
|
||||
async function render(
|
||||
{ region, id }: ResolvedPlayer,
|
||||
{ start, end, name }: ResolvedPeriod,
|
||||
type: "player" | "tank",
|
||||
tankId: number | null,
|
||||
locale: Locale,
|
||||
) {
|
||||
const accountInfo = await getAccountInfo(region, id);
|
||||
const clan = (await getClanAccountInfo(region, id, ["clan"]))?.clan;
|
||||
const logo = clan ? emblemURL(clan.emblem_set_id) : undefined;
|
||||
const histories = await (type === "player"
|
||||
? getPlayerHistories(region, id, {
|
||||
start,
|
||||
end,
|
||||
includeLatestHistories: true,
|
||||
includePreviousHistories: true,
|
||||
})
|
||||
: getTankHistories(region, id, locale, {
|
||||
tankId: tankId!,
|
||||
start,
|
||||
end,
|
||||
includeLatestHistories: true,
|
||||
includePreviousHistories: true,
|
||||
}));
|
||||
const plot = histories.map(
|
||||
(history) =>
|
||||
[
|
||||
history.all.battles,
|
||||
(history.all.wins / history.all.battles) * 100,
|
||||
] as Graph.PlotItem,
|
||||
);
|
||||
const times = histories.map((history) => history.last_battle_time);
|
||||
const minTime = Math.min(...times);
|
||||
const maxTime = Math.max(...times);
|
||||
const ys = plot.map(([, y]) => y);
|
||||
const xs = plot.map(([x]) => x);
|
||||
const maxY = Math.max(...ys);
|
||||
const minY = Math.min(...ys);
|
||||
const maxX = Math.max(...xs);
|
||||
const minX = Math.min(...xs);
|
||||
|
||||
return (
|
||||
<CommandWrapper>
|
||||
<TitleBar title={accountInfo.nickname} image={logo} description={name} />
|
||||
|
||||
{plot.length > 0 && (
|
||||
<Graph.Root
|
||||
verticalMargin={{
|
||||
min: minY,
|
||||
max: maxY,
|
||||
suffix: "%",
|
||||
precision: 2,
|
||||
}}
|
||||
horizontalMargin={{
|
||||
min: minX,
|
||||
max: maxX,
|
||||
precision: 0,
|
||||
}}
|
||||
xMinLabel={new Date(minTime * 1000).toLocaleDateString(locale)}
|
||||
xMaxLabel={new Date(maxTime * 1000).toLocaleDateString(locale)}
|
||||
>
|
||||
{Graph.Line({
|
||||
color: LineColor.Red,
|
||||
plot: plot,
|
||||
minY,
|
||||
maxY,
|
||||
})}
|
||||
</Graph.Root>
|
||||
)}
|
||||
|
||||
{plot.length === 0 && <NoData type="battles_in_period" locale={locale} />}
|
||||
</CommandWrapper>
|
||||
);
|
||||
}
|
||||
|
||||
export const evolutionCommand = new Promise<CommandRegistry>(
|
||||
async (resolve) => {
|
||||
resolve({
|
||||
command: createLocalizedCommand("evolution", [
|
||||
{
|
||||
group: "player",
|
||||
modify(option: SlashCommandSubcommandGroupBuilder) {
|
||||
addPeriodSubCommands(option, (option) =>
|
||||
option.addStringOption(addUsernameChoices),
|
||||
);
|
||||
},
|
||||
},
|
||||
{
|
||||
group: "tank",
|
||||
modify(option: SlashCommandSubcommandGroupBuilder) {
|
||||
addPeriodSubCommands(option, (option) =>
|
||||
option
|
||||
.addStringOption(addTankChoices)
|
||||
.addStringOption(addUsernameChoices),
|
||||
);
|
||||
},
|
||||
},
|
||||
]),
|
||||
|
||||
async handler(interaction) {
|
||||
const { strings } = translator(interaction.locale);
|
||||
return strings.bot.commands.dead;
|
||||
|
||||
// const commandGroup =
|
||||
// interaction.options.getSubcommandGroup() as EvolutionStatType;
|
||||
// const player = await resolvePlayerFromCommand(interaction);
|
||||
// const period = resolvePeriodFromCommand(player.region, interaction);
|
||||
// const tankIdRaw = interaction.options.getString("tank")!;
|
||||
// const tankId =
|
||||
// commandGroup === "tank"
|
||||
// ? await resolveTankId(tankIdRaw, interaction.locale)
|
||||
// : null;
|
||||
// const path = commandToURL(interaction, {
|
||||
// ...player,
|
||||
// ...getCustomPeriodParams(interaction),
|
||||
// tankId,
|
||||
// });
|
||||
|
||||
// return [
|
||||
// await render(
|
||||
// player,
|
||||
// period,
|
||||
// commandGroup,
|
||||
// tankId,
|
||||
// interaction.locale
|
||||
// ),
|
||||
// buttonRefresh(interaction, path),
|
||||
// await getBlitzStarsLinkButton(
|
||||
// player.region,
|
||||
// player.id,
|
||||
// tankId ?? undefined
|
||||
// ),
|
||||
// ];
|
||||
},
|
||||
|
||||
autocomplete: (interaction) => {
|
||||
autocompleteUsername(interaction);
|
||||
autocompleteTanks(interaction);
|
||||
},
|
||||
|
||||
async button(interaction) {
|
||||
const url = new URL(`https://example.com/${interaction.customId}`);
|
||||
const path = url.pathname.split("/");
|
||||
const commandGroup = path[2] as EvolutionStatType;
|
||||
const player = await resolvePlayerFromButton(interaction);
|
||||
const period = resolvePeriodFromButton(player.region, interaction);
|
||||
|
||||
return await render(
|
||||
player,
|
||||
period,
|
||||
commandGroup,
|
||||
parseInt(url.searchParams.get("tankId") ?? "0") || null,
|
||||
interaction.locale,
|
||||
);
|
||||
},
|
||||
});
|
||||
},
|
||||
);
|
||||
@@ -1,117 +0,0 @@
|
||||
import {
|
||||
emblemURL,
|
||||
getAccountInfo,
|
||||
getClanAccountInfo,
|
||||
getTierWeights,
|
||||
} from "@blitzkit/core";
|
||||
import { Locale } from "discord.js";
|
||||
import { CommandWrapper } from "../components/CommandWrapper";
|
||||
import { GenericAllStats } from "../components/GenericAllStats";
|
||||
import { NoData } from "../components/NoData";
|
||||
import { TierWeights } from "../components/TierWeights";
|
||||
import { TitleBar } from "../components/TitleBar";
|
||||
import { filtersToDescription } from "../core/blitzkit/filtersToDescription";
|
||||
import { filterStats, type StatFilters } from "../core/blitzstars/filterStats";
|
||||
import { getStatsInPeriod } from "../core/blitzstars/getStatsInPeriod";
|
||||
import { addPeriodicFilterOptions } from "../core/discord/addPeriodicFilterOptions";
|
||||
import { addUsernameChoices } from "../core/discord/addUsernameChoices";
|
||||
import { autocompleteTanks } from "../core/discord/autocompleteTanks";
|
||||
import { autocompleteUsername } from "../core/discord/autocompleteUsername";
|
||||
import { createLocalizedCommand } from "../core/discord/createLocalizedCommand";
|
||||
import { getFiltersFromButton } from "../core/discord/getFiltersFromButton";
|
||||
import { resolvePeriodFromButton } from "../core/discord/resolvePeriodFromButton";
|
||||
import { type ResolvedPeriod } from "../core/discord/resolvePeriodFromCommand";
|
||||
import { resolvePlayerFromButton } from "../core/discord/resolvePlayerFromButton";
|
||||
import { type ResolvedPlayer } from "../core/discord/resolvePlayerFromCommand";
|
||||
import { translator } from "../core/localization/translator";
|
||||
import type { CommandRegistry } from "../events/interactionCreate";
|
||||
|
||||
async function render(
|
||||
{ region, id }: ResolvedPlayer,
|
||||
{ start, end, name }: ResolvedPeriod,
|
||||
filters: StatFilters,
|
||||
locale: Locale,
|
||||
) {
|
||||
const { nickname } = await getAccountInfo(region, id);
|
||||
const clan = (await getClanAccountInfo(region, id, ["clan"]))?.clan;
|
||||
const clanImage = clan ? emblemURL(clan.emblem_set_id) : undefined;
|
||||
const diffedTankStats = await getStatsInPeriod(
|
||||
region,
|
||||
id,
|
||||
start,
|
||||
end,
|
||||
locale,
|
||||
);
|
||||
const { stats, supplementary, filteredOrder } = await filterStats(
|
||||
diffedTankStats,
|
||||
filters,
|
||||
);
|
||||
const filterDescriptions = await filtersToDescription(filters, locale);
|
||||
const tierWeights = await getTierWeights(diffedTankStats.diff, filteredOrder);
|
||||
|
||||
return (
|
||||
<CommandWrapper>
|
||||
<TitleBar
|
||||
title={nickname}
|
||||
image={clanImage}
|
||||
description={`${name} • ${filterDescriptions}`}
|
||||
/>
|
||||
|
||||
{stats.battles === 0 && (
|
||||
<NoData type="battles_in_period" locale={locale} />
|
||||
)}
|
||||
{stats.battles > 0 && <TierWeights weights={tierWeights!} />}
|
||||
{stats.battles > 0 && (
|
||||
<GenericAllStats
|
||||
stats={stats}
|
||||
supplementaryStats={supplementary}
|
||||
locale={locale}
|
||||
/>
|
||||
)}
|
||||
</CommandWrapper>
|
||||
);
|
||||
}
|
||||
|
||||
export const fullStatsCommand = new Promise<CommandRegistry>(
|
||||
async (resolve) => {
|
||||
resolve({
|
||||
command: await addPeriodicFilterOptions(
|
||||
createLocalizedCommand("full-stats"),
|
||||
(option) => option.addStringOption(addUsernameChoices),
|
||||
),
|
||||
|
||||
async handler(interaction) {
|
||||
const { strings } = translator(interaction.locale);
|
||||
return strings.bot.commands.dead;
|
||||
|
||||
// const player = await resolvePlayerFromCommand(interaction);
|
||||
// const period = resolvePeriodFromCommand(player.region, interaction);
|
||||
// const filters = await getFiltersFromCommand(interaction);
|
||||
// const path = commandToURL(interaction, {
|
||||
// ...player,
|
||||
// ...getCustomPeriodParams(interaction),
|
||||
// ...filters,
|
||||
// });
|
||||
|
||||
// return Promise.all([
|
||||
// render(player, period, filters, interaction.locale),
|
||||
// buttonRefresh(interaction, path),
|
||||
// getBlitzStarsLinkButton(player.region, player.id),
|
||||
// ]);
|
||||
},
|
||||
|
||||
autocomplete: (interaction) => {
|
||||
autocompleteUsername(interaction);
|
||||
autocompleteTanks(interaction);
|
||||
},
|
||||
|
||||
async button(interaction) {
|
||||
const player = await resolvePlayerFromButton(interaction);
|
||||
const period = resolvePeriodFromButton(player.region, interaction);
|
||||
const filters = getFiltersFromButton(interaction);
|
||||
|
||||
return await render(player, period, filters, interaction.locale);
|
||||
},
|
||||
});
|
||||
},
|
||||
);
|
||||
@@ -1,96 +0,0 @@
|
||||
import { getAccountInfo, getClanInfo } from "@blitzkit/core";
|
||||
import { literals } from "@blitzkit/i18n";
|
||||
import { Locale } from "discord.js";
|
||||
import { CommandWrapper } from "../components/CommandWrapper";
|
||||
import { GenericStats } from "../components/GenericStats";
|
||||
import { NoData } from "../components/NoData";
|
||||
import { TitleBar } from "../components/TitleBar";
|
||||
import { addClanChoices } from "../core/discord/addClanChoices";
|
||||
import { autocompleteClan } from "../core/discord/autocompleteClan";
|
||||
import { createLocalizedCommand } from "../core/discord/createLocalizedCommand";
|
||||
import { localizationObject } from "../core/discord/localizationObject";
|
||||
import { resolveClanFromCommand } from "../core/discord/resolveClanFromCommand";
|
||||
import { translator } from "../core/localization/translator";
|
||||
import type { CommandRegistry } from "../events/interactionCreate";
|
||||
|
||||
const DEFAULT_THRESHOLD = 7;
|
||||
|
||||
export const inactiveCommand = new Promise<CommandRegistry>((resolve) => {
|
||||
resolve({
|
||||
command: createLocalizedCommand("inactive")
|
||||
.addStringOption(addClanChoices)
|
||||
.addNumberOption((option) => {
|
||||
const { strings } = translator(Locale.EnglishUS);
|
||||
|
||||
return option
|
||||
.setName("threshold")
|
||||
.setNameLocalizations(
|
||||
localizationObject(
|
||||
(strings) => strings.bot.commands.inactive.options.threshold.name,
|
||||
undefined,
|
||||
true
|
||||
)
|
||||
)
|
||||
.setDescription(
|
||||
strings.bot.commands.inactive.options.threshold.description
|
||||
)
|
||||
.setDescriptionLocalizations(
|
||||
localizationObject(
|
||||
(strings) =>
|
||||
strings.bot.commands.inactive.options.threshold.description
|
||||
)
|
||||
)
|
||||
.setMinValue(0);
|
||||
}),
|
||||
|
||||
async handler(interaction) {
|
||||
const { strings } = translator(interaction.locale);
|
||||
const { region, id } = await resolveClanFromCommand(interaction);
|
||||
const threshold =
|
||||
interaction.options.getNumber("threshold")! ?? DEFAULT_THRESHOLD;
|
||||
const time = new Date().getTime() / 1000;
|
||||
const clanInfo = await getClanInfo(region, id);
|
||||
const accountInfo = await getAccountInfo(region, clanInfo.members_ids);
|
||||
const inactive = accountInfo
|
||||
.map(
|
||||
(account) =>
|
||||
[
|
||||
account.nickname,
|
||||
(time - account.last_battle_time) / 60 / 60 / 24,
|
||||
] as [string, number]
|
||||
)
|
||||
.filter(([, inactiveDays]) => inactiveDays >= threshold)
|
||||
.sort((a, b) => b[1] - a[1])
|
||||
.map(
|
||||
([name, days]) =>
|
||||
[
|
||||
name,
|
||||
literals(strings.bot.commands.inactive.body.listing, {
|
||||
days: days.toFixed(0),
|
||||
}),
|
||||
] as [string, string]
|
||||
);
|
||||
const hasInactiveMembers = inactive.length > 0;
|
||||
|
||||
return (
|
||||
<CommandWrapper>
|
||||
<TitleBar
|
||||
title={clanInfo.name}
|
||||
image={`https://wotblitz-gc.gcdn.co/icons/clanEmblems1x/clan-icon-v2-${clanInfo.emblem_set_id}.png`}
|
||||
description={`${literals(
|
||||
strings.bot.commands.inactive.body.subtitle,
|
||||
{ days: threshold }
|
||||
)} • ${new Date().toLocaleDateString(interaction.locale)}`}
|
||||
/>
|
||||
|
||||
{!hasInactiveMembers && (
|
||||
<NoData type="players_in_period" locale={interaction.locale} />
|
||||
)}
|
||||
{hasInactiveMembers && <GenericStats stats={inactive} />}
|
||||
</CommandWrapper>
|
||||
);
|
||||
},
|
||||
|
||||
autocomplete: autocompleteClan,
|
||||
});
|
||||
});
|
||||
@@ -1,193 +0,0 @@
|
||||
import { getAccountInfo, getClanAccountInfo } from '@blitzkit/core';
|
||||
import { teal } from '@radix-ui/colors';
|
||||
import { Glow } from '../components/AllStatsOverview/components/HeroStat/components/Glow';
|
||||
import { CommandWrapper } from '../components/CommandWrapper';
|
||||
import { linkBlitzAndDiscord } from '../core/db/linkBlitzAndDiscord';
|
||||
import { addUsernameChoices } from '../core/discord/addUsernameChoices';
|
||||
import { autocompleteUsername } from '../core/discord/autocompleteUsername';
|
||||
import { createLocalizedCommand } from '../core/discord/createLocalizedCommand';
|
||||
import { embedInfo } from '../core/discord/embedInfo';
|
||||
import { resolvePlayerFromCommand } from '../core/discord/resolvePlayerFromCommand';
|
||||
import { translator } from '../core/localization/translator';
|
||||
import type { CommandRegistry } from '../events/interactionCreate';
|
||||
import { theme } from '../stitches.config';
|
||||
|
||||
export const verifyCommand = new Promise<CommandRegistry>((resolve) => {
|
||||
resolve({
|
||||
command: createLocalizedCommand('link').addStringOption((option) =>
|
||||
addUsernameChoices(option).setRequired(true),
|
||||
),
|
||||
|
||||
async handler(interaction) {
|
||||
const { strings } = translator(interaction.locale);
|
||||
const { id, region } = await resolvePlayerFromCommand(interaction);
|
||||
const discordId = BigInt(interaction.user.id);
|
||||
const accountInfo = await getAccountInfo(region, id);
|
||||
const clanAccountInfo = await getClanAccountInfo(region, id, ['clan']);
|
||||
|
||||
await linkBlitzAndDiscord(discordId, id);
|
||||
|
||||
return [
|
||||
<CommandWrapper fat>
|
||||
<div
|
||||
style={{
|
||||
display: 'flex',
|
||||
alignItems: 'center',
|
||||
justifyContent: 'space-between',
|
||||
}}
|
||||
>
|
||||
<Glow color={teal.teal9} rotation={90} />
|
||||
|
||||
<div
|
||||
style={{
|
||||
display: 'flex',
|
||||
flexDirection: 'column',
|
||||
alignItems: 'center',
|
||||
justifyContent: 'center',
|
||||
gap: 16,
|
||||
}}
|
||||
>
|
||||
<div
|
||||
style={{
|
||||
display: 'flex',
|
||||
gap: 8,
|
||||
alignItems: 'center',
|
||||
justifyContent: 'center',
|
||||
}}
|
||||
>
|
||||
<img
|
||||
alt="avatar"
|
||||
src={
|
||||
interaction.user.avatarURL({ extension: 'png' }) ??
|
||||
'https://i.stack.imgur.com/l60Hf.png'
|
||||
}
|
||||
style={{
|
||||
width: 64,
|
||||
height: 64,
|
||||
borderRadius: 32,
|
||||
objectFit: 'cover',
|
||||
}}
|
||||
/>
|
||||
|
||||
<div
|
||||
style={{
|
||||
display: 'flex',
|
||||
flexDirection: 'column',
|
||||
gap: 4,
|
||||
}}
|
||||
>
|
||||
<span
|
||||
style={{
|
||||
fontSize: 32,
|
||||
color: theme.colors.textHighContrast,
|
||||
fontWeight: 900,
|
||||
maxWidth: 240,
|
||||
overflow: 'hidden',
|
||||
textOverflow: 'ellipsis',
|
||||
whiteSpace: 'nowrap',
|
||||
}}
|
||||
>
|
||||
{interaction.user.displayName}
|
||||
</span>
|
||||
<span
|
||||
style={{
|
||||
fontSize: 16,
|
||||
color: theme.colors.textLowContrast,
|
||||
}}
|
||||
>
|
||||
@{interaction.user.username}
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div
|
||||
style={{
|
||||
display: 'flex',
|
||||
alignItems: 'center',
|
||||
justifyContent: 'center',
|
||||
gap: 4,
|
||||
color: theme.colors.textLowContrast_teal,
|
||||
}}
|
||||
>
|
||||
<img
|
||||
alt="accounts linked"
|
||||
src="https://i.imgur.com/jIcRgog.png"
|
||||
style={{
|
||||
width: 16,
|
||||
height: 16,
|
||||
}}
|
||||
/>
|
||||
<span style={{ fontSize: 16 }}>
|
||||
{strings.bot.commands.link.body.accounts_linked}
|
||||
</span>
|
||||
</div>
|
||||
|
||||
<div
|
||||
style={{
|
||||
display: 'flex',
|
||||
gap: 8,
|
||||
alignItems: 'center',
|
||||
justifyContent: 'center',
|
||||
}}
|
||||
>
|
||||
{clanAccountInfo?.clan ? (
|
||||
<img
|
||||
alt="clan emblem"
|
||||
style={{
|
||||
width: 64,
|
||||
height: 64,
|
||||
borderRadius: 32,
|
||||
objectFit: 'cover',
|
||||
}}
|
||||
src={`https://wotblitz-gc.gcdn.co/icons/clanEmblems1x/clan-icon-v2-${clanAccountInfo?.clan?.emblem_set_id}.png`}
|
||||
/>
|
||||
) : null}
|
||||
<div
|
||||
style={{
|
||||
display: 'flex',
|
||||
flexDirection: 'column',
|
||||
gap: 4,
|
||||
}}
|
||||
>
|
||||
<span
|
||||
style={{
|
||||
fontSize: 32,
|
||||
color: theme.colors.textHighContrast,
|
||||
fontWeight: 900,
|
||||
maxWidth: 240,
|
||||
overflow: 'hidden',
|
||||
textOverflow: 'ellipsis',
|
||||
whiteSpace: 'nowrap',
|
||||
}}
|
||||
>
|
||||
{accountInfo.nickname}
|
||||
</span>
|
||||
<span
|
||||
style={{
|
||||
fontSize: 16,
|
||||
color: theme.colors.textLowContrast,
|
||||
}}
|
||||
>
|
||||
{clanAccountInfo?.clan
|
||||
? `[${clanAccountInfo?.clan?.tag}] • `
|
||||
: ''}
|
||||
{strings.common.regions.normal[region]}
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<Glow color={teal.teal9} rotation={-90} />
|
||||
</div>
|
||||
</CommandWrapper>,
|
||||
|
||||
embedInfo(
|
||||
strings.bot.commands.link.embed.title,
|
||||
strings.bot.commands.link.embed.description,
|
||||
),
|
||||
];
|
||||
},
|
||||
|
||||
autocomplete: autocompleteUsername,
|
||||
});
|
||||
});
|
||||
@@ -1,90 +0,0 @@
|
||||
import {
|
||||
TANK_CLASSES,
|
||||
TIER_ROMAN_NUMERALS,
|
||||
TankDefinition,
|
||||
flags,
|
||||
getAccountInfo,
|
||||
getTankStats,
|
||||
} from "@blitzkit/core";
|
||||
import { literals } from "@blitzkit/i18n";
|
||||
import markdownEscape from "markdown-escape";
|
||||
import {
|
||||
gameDefinitions,
|
||||
tankDefinitions,
|
||||
} from "../core/blitzkit/nonBlockingPromises";
|
||||
import { addTierChoices } from "../core/discord/addTierChoices";
|
||||
import { addUsernameChoices } from "../core/discord/addUsernameChoices";
|
||||
import { autocompleteUsername } from "../core/discord/autocompleteUsername";
|
||||
import { chunkLines } from "../core/discord/chunkLines";
|
||||
import { createLocalizedCommand } from "../core/discord/createLocalizedCommand";
|
||||
import { resolvePlayerFromCommand } from "../core/discord/resolvePlayerFromCommand";
|
||||
import { translator } from "../core/localization/translator";
|
||||
import { type CommandRegistry } from "../events/interactionCreate";
|
||||
|
||||
export const ownedTanksCommand = new Promise<CommandRegistry>((resolve) => {
|
||||
resolve({
|
||||
command: createLocalizedCommand("owned-tanks")
|
||||
.addStringOption(addTierChoices)
|
||||
.addStringOption(addUsernameChoices),
|
||||
|
||||
async handler(interaction) {
|
||||
const { strings, unwrap } = translator(interaction.locale);
|
||||
const tier = Number(interaction.options.getString("tier"));
|
||||
const { id, region } = await resolvePlayerFromCommand(interaction);
|
||||
const accountInfo = await getAccountInfo(region, id);
|
||||
const tankStats = await getTankStats(region, id);
|
||||
|
||||
if (tankStats === null) {
|
||||
return strings.bot.common.errors.no_tank_stats;
|
||||
}
|
||||
|
||||
const filteredTanks = (
|
||||
await Promise.all(
|
||||
tankStats.map(async (tankData) => ({
|
||||
tankDefinitions: (await tankDefinitions).tanks[tankData.tank_id]!,
|
||||
id: tankData.tank_id,
|
||||
})),
|
||||
)
|
||||
).filter((tank) => tank.tankDefinitions?.tier === tier);
|
||||
const groupedTanks: Record<string, TankDefinition[]> = {};
|
||||
const nations: string[] = [];
|
||||
|
||||
filteredTanks.forEach((tank) => {
|
||||
if (groupedTanks[tank.tankDefinitions.nation] === undefined) {
|
||||
groupedTanks[tank.tankDefinitions.nation] = [tank.tankDefinitions];
|
||||
nations.push(tank.tankDefinitions.nation);
|
||||
} else {
|
||||
groupedTanks[tank.tankDefinitions.nation].push(tank.tankDefinitions);
|
||||
}
|
||||
});
|
||||
|
||||
const awaitedTankDefinitions = await tankDefinitions;
|
||||
const awaitedGameDefinitions = await gameDefinitions;
|
||||
const title = literals(strings.bot.commands.owned_tanks.body.title, {
|
||||
name: markdownEscape(accountInfo.nickname),
|
||||
tier: TIER_ROMAN_NUMERALS[tier],
|
||||
});
|
||||
const tankList = tankStats
|
||||
.map(({ tank_id }) => awaitedTankDefinitions.tanks[tank_id])
|
||||
.filter((tank) => tank.tier === tier)
|
||||
.sort(
|
||||
(a, b) =>
|
||||
TANK_CLASSES.indexOf(a.class) - TANK_CLASSES.indexOf(b.class),
|
||||
)
|
||||
.sort(
|
||||
(a, b) =>
|
||||
awaitedGameDefinitions.nations.indexOf(a.nation) -
|
||||
awaitedGameDefinitions.nations.indexOf(b.nation),
|
||||
)
|
||||
.map(
|
||||
(tank) =>
|
||||
`[${flags[tank.nation]} ${markdownEscape(unwrap(tank.name!))}](<https://blitzkit.app/tanks/${tank.slug}>)`,
|
||||
);
|
||||
const lines = [title, ...tankList];
|
||||
|
||||
return chunkLines(lines);
|
||||
},
|
||||
|
||||
autocomplete: autocompleteUsername,
|
||||
});
|
||||
});
|
||||
@@ -1,46 +0,0 @@
|
||||
import { literals } from "@blitzkit/i18n";
|
||||
import { createLocalizedCommand } from "../core/discord/createLocalizedCommand";
|
||||
import { translator } from "../core/localization/translator";
|
||||
import { CommandRegistry } from "../events/interactionCreate";
|
||||
|
||||
export const permissionsCommand = new Promise<CommandRegistry>((resolve) => {
|
||||
resolve({
|
||||
command: createLocalizedCommand("permissions"),
|
||||
|
||||
async handler(interaction) {
|
||||
const { strings } = translator(interaction.locale);
|
||||
// friday the 13th permissions easter egg
|
||||
const isFridayThe13th =
|
||||
new Date().getDay() === 5 && new Date().getDate() === 13;
|
||||
const permissions = [
|
||||
[
|
||||
interaction.appPermissions?.has("ViewChannel"),
|
||||
strings.bot.commands.permissions.body.view_channels,
|
||||
],
|
||||
[
|
||||
interaction.appPermissions?.has("ReadMessageHistory"),
|
||||
strings.bot.commands.permissions.body.read_message_history,
|
||||
],
|
||||
[
|
||||
interaction.appPermissions?.has("AttachFiles"),
|
||||
strings.bot.commands.permissions.body.attach_files,
|
||||
],
|
||||
[
|
||||
interaction.appPermissions?.has("UseExternalEmojis"),
|
||||
strings.bot.commands.permissions.body.external_emojis,
|
||||
],
|
||||
];
|
||||
const body = permissions
|
||||
.map(([hasPermission, description]) => {
|
||||
if (hasPermission) {
|
||||
return `${isFridayThe13th ? "😇" : "✅"} ${description}`;
|
||||
} else {
|
||||
return `${isFridayThe13th ? "💀" : "❌"} ${description}`;
|
||||
}
|
||||
})
|
||||
.join("\n");
|
||||
|
||||
return literals(strings.bot.commands.permissions.body.title, { body });
|
||||
},
|
||||
});
|
||||
});
|
||||
@@ -1,34 +0,0 @@
|
||||
import { literals } from "@blitzkit/i18n";
|
||||
import { createLocalizedCommand } from "../core/discord/createLocalizedCommand";
|
||||
import { translator } from "../core/localization/translator";
|
||||
import type { CommandRegistry } from "../events/interactionCreate";
|
||||
|
||||
export const pingCommand = new Promise<CommandRegistry>((resolve) => {
|
||||
resolve({
|
||||
handlesInteraction: true,
|
||||
|
||||
command: createLocalizedCommand("ping", [
|
||||
{ subcommand: "blitzkit" },
|
||||
{ subcommand: "wotb" },
|
||||
]),
|
||||
|
||||
async handler(interaction) {
|
||||
const { strings } = translator(interaction.locale);
|
||||
const subcommand = interaction.options.getSubcommand();
|
||||
const executionStart = Date.now();
|
||||
|
||||
if (subcommand === "blitzkit") {
|
||||
await interaction.editReply(strings.bot.commands.ping.body.pong);
|
||||
} else {
|
||||
await fetch("https://api.wotblitz.com/");
|
||||
}
|
||||
|
||||
const executionTime = Date.now() - executionStart;
|
||||
interaction.editReply(
|
||||
literals(strings.bot.commands.ping.body.pong_with_time, {
|
||||
time: executionTime.toFixed(0),
|
||||
})
|
||||
);
|
||||
},
|
||||
});
|
||||
});
|
||||
@@ -1,69 +0,0 @@
|
||||
import { getAccountInfo } from "@blitzkit/core";
|
||||
import { literals } from "@blitzkit/i18n";
|
||||
import markdownEscape from "markdown-escape";
|
||||
import { addUsernameChoices } from "../core/discord/addUsernameChoices";
|
||||
import { autocompleteUsername } from "../core/discord/autocompleteUsername";
|
||||
import { createLocalizedCommand } from "../core/discord/createLocalizedCommand";
|
||||
import { embedInfo } from "../core/discord/embedInfo";
|
||||
import { markdownTable } from "../core/discord/markdownTable";
|
||||
import { resolvePlayerFromCommand } from "../core/discord/resolvePlayerFromCommand";
|
||||
import { translator } from "../core/localization/translator";
|
||||
import { CommandRegistry } from "../events/interactionCreate";
|
||||
|
||||
export const playerInfoCommand = new Promise<CommandRegistry>((resolve) => {
|
||||
resolve({
|
||||
command:
|
||||
createLocalizedCommand("player-info").addStringOption(addUsernameChoices),
|
||||
|
||||
async handler(interaction) {
|
||||
const { strings } = translator(interaction.locale);
|
||||
const account = await resolvePlayerFromCommand(interaction);
|
||||
const { id, region: region } = account;
|
||||
const accountInfo = await getAccountInfo(region, id);
|
||||
|
||||
return embedInfo(
|
||||
literals(strings.bot.commands.player_info.body.title, {
|
||||
name: markdownEscape(accountInfo.nickname),
|
||||
}),
|
||||
|
||||
markdownTable([
|
||||
[
|
||||
strings.bot.commands.player_info.body.nickname,
|
||||
`${accountInfo.nickname}`,
|
||||
],
|
||||
[
|
||||
strings.bot.commands.player_info.body.battles,
|
||||
`${accountInfo.statistics.all.battles}`,
|
||||
],
|
||||
[
|
||||
strings.bot.commands.player_info.body.winrate,
|
||||
`${(
|
||||
100 *
|
||||
(accountInfo.statistics.all.wins /
|
||||
accountInfo.statistics.all.battles)
|
||||
).toFixed(2)}%`,
|
||||
],
|
||||
[],
|
||||
[
|
||||
strings.bot.commands.player_info.body.account_id,
|
||||
`${accountInfo.account_id}`,
|
||||
],
|
||||
[
|
||||
strings.bot.commands.player_info.body.created,
|
||||
new Date(accountInfo.created_at * 1000).toLocaleDateString(
|
||||
interaction.locale
|
||||
),
|
||||
],
|
||||
[
|
||||
strings.bot.commands.player_info.body.last_battle,
|
||||
new Date(accountInfo.last_battle_time * 1000).toLocaleDateString(
|
||||
interaction.locale
|
||||
),
|
||||
],
|
||||
])
|
||||
);
|
||||
},
|
||||
|
||||
autocomplete: autocompleteUsername,
|
||||
});
|
||||
});
|
||||
@@ -1,535 +0,0 @@
|
||||
import {
|
||||
deltaBkrlBlitzStats,
|
||||
emblemURL,
|
||||
getAccountInfo,
|
||||
getArchivedRatingLeaderboard,
|
||||
getClanAccountInfo,
|
||||
getLeagueFromScore,
|
||||
getRatingInfo,
|
||||
getRatingNeighbors,
|
||||
imgur,
|
||||
} from "@blitzkit/core";
|
||||
import { literals } from "@blitzkit/i18n";
|
||||
import { SlashCommandSubcommandBuilder } from "discord.js";
|
||||
import markdownEscape from "markdown-escape";
|
||||
import { Glow } from "../components/AllStatsOverview/components/HeroStat/components/Glow";
|
||||
import { CommandWrapper } from "../components/CommandWrapper";
|
||||
import { DeltaCaret } from "../components/DeltaCaret";
|
||||
import { TitleBar } from "../components/TitleBar";
|
||||
import { normalizeLeagueIcon } from "../core/blitz/normalizeLeagueIcon";
|
||||
import { iconPng } from "../core/blitzkit/iconPng";
|
||||
import { addUsernameChoices } from "../core/discord/addUsernameChoices";
|
||||
import { createLocalizedCommand } from "../core/discord/createLocalizedCommand";
|
||||
import { resolvePlayerFromCommand } from "../core/discord/resolvePlayerFromCommand";
|
||||
import { translator } from "../core/localization/translator";
|
||||
import type { CommandRegistry } from "../events/interactionCreate";
|
||||
import { theme } from "../stitches.config";
|
||||
|
||||
const LEAGUE_ACCENT = [
|
||||
"_purple",
|
||||
"_sand",
|
||||
"_amber",
|
||||
"_mauve",
|
||||
"_brown",
|
||||
] as const;
|
||||
|
||||
export const ratingCommand = new Promise<CommandRegistry>((resolve) => {
|
||||
resolve({
|
||||
command: createLocalizedCommand("rating", [
|
||||
{
|
||||
subcommand: "today",
|
||||
modify(option: SlashCommandSubcommandBuilder) {
|
||||
option.addStringOption(addUsernameChoices);
|
||||
},
|
||||
},
|
||||
{
|
||||
subcommand: "season",
|
||||
modify(option: SlashCommandSubcommandBuilder) {
|
||||
option.addStringOption(addUsernameChoices);
|
||||
},
|
||||
},
|
||||
]),
|
||||
|
||||
async handler(interaction) {
|
||||
const subcommand = interaction.options.getSubcommand(true) as
|
||||
| "season"
|
||||
| "today";
|
||||
const { strings } = translator(interaction.locale);
|
||||
const { id, region } = await resolvePlayerFromCommand(interaction);
|
||||
const clan = (await getClanAccountInfo(region, id, ["clan"]))?.clan;
|
||||
const clanImage = clan ? emblemURL(clan.emblem_set_id) : undefined;
|
||||
|
||||
const ratingInfo = await getRatingInfo(region);
|
||||
|
||||
if (ratingInfo.detail) {
|
||||
throw new Error(`Rating info not available for ${region}`);
|
||||
}
|
||||
|
||||
const leaderboard = await getArchivedRatingLeaderboard(
|
||||
region,
|
||||
ratingInfo.current_season - (subcommand === "today" ? 0 : 1)
|
||||
);
|
||||
|
||||
if (leaderboard.version!.$case === "v1") {
|
||||
throw new Error(
|
||||
"Encountered bkrl minimal format in latest season. Wait till next cron?"
|
||||
);
|
||||
}
|
||||
|
||||
const accountInfo = await getAccountInfo(region, id, [
|
||||
"statistics.rating",
|
||||
]);
|
||||
const statsIndex = leaderboard.version!.value.entries.findIndex(
|
||||
(entry) => entry.id === id
|
||||
);
|
||||
const statsA = leaderboard
|
||||
? leaderboard.version!.value.entries[statsIndex!]
|
||||
: null;
|
||||
const positionA = leaderboard ? statsIndex! + 1 : undefined;
|
||||
const statsB1 = accountInfo.statistics.rating!;
|
||||
const statsB2Array = (await getRatingNeighbors(region, id, 0)).neighbors;
|
||||
|
||||
if (statsB2Array === undefined) {
|
||||
return literals(strings.bot.commands.rating.errors.no_participation, {
|
||||
name: markdownEscape(accountInfo.nickname),
|
||||
});
|
||||
}
|
||||
|
||||
const [statsB2] = statsB2Array;
|
||||
const league = getLeagueFromScore(statsB2.score);
|
||||
|
||||
if (!statsA) {
|
||||
return strings.bot.commands.rating.errors.unrecorded_stats;
|
||||
}
|
||||
if (!statsB1) {
|
||||
return literals(strings.bot.commands.rating.errors.no_participation, {
|
||||
name: markdownEscape(accountInfo.nickname),
|
||||
});
|
||||
}
|
||||
|
||||
const reward = ratingInfo.rewards.find(
|
||||
(reward) =>
|
||||
statsB2.number >= reward.from_position &&
|
||||
statsB2.number <= reward.to_position
|
||||
);
|
||||
const positionDelta = leaderboard
|
||||
? statsB2.number - positionA!
|
||||
: undefined;
|
||||
const delta = deltaBkrlBlitzStats(
|
||||
statsA,
|
||||
accountInfo.statistics.rating!,
|
||||
statsB2
|
||||
);
|
||||
const leagueTheme = LEAGUE_ACCENT[league.index];
|
||||
let rewardImage = reward
|
||||
? reward.type === "vehicle"
|
||||
? reward.vehicle.preview_image_url
|
||||
: reward.stuff.image_url
|
||||
: undefined;
|
||||
|
||||
if (rewardImage) {
|
||||
const { ok } = await fetch(rewardImage);
|
||||
|
||||
if (!ok) {
|
||||
rewardImage = imgur("kP88vqr");
|
||||
}
|
||||
}
|
||||
|
||||
return (
|
||||
<CommandWrapper>
|
||||
<TitleBar
|
||||
title={accountInfo.nickname}
|
||||
image={clanImage}
|
||||
description={`${
|
||||
strings.bot.commands.rating.body.subtitle[subcommand]
|
||||
} • ${new Date().toLocaleDateString(interaction.locale)}`}
|
||||
/>
|
||||
|
||||
<div
|
||||
style={{
|
||||
position: "relative",
|
||||
display: "flex",
|
||||
overflow: "hidden",
|
||||
}}
|
||||
>
|
||||
<div
|
||||
style={{
|
||||
position: "relative",
|
||||
padding: 16,
|
||||
backgroundColor: theme.colors[`appBackground2${leagueTheme}`],
|
||||
borderRadius: 4,
|
||||
border: `1px solid ${
|
||||
theme.colors[`componentInteractive${leagueTheme}`]
|
||||
}`,
|
||||
display: "flex",
|
||||
alignItems: "center",
|
||||
justifyContent: "space-between",
|
||||
width: "100%",
|
||||
}}
|
||||
>
|
||||
{reward === undefined && (
|
||||
<Glow
|
||||
endOpacity={3 / 4}
|
||||
color={theme.colors[`solidBackground${leagueTheme}`]}
|
||||
style={{
|
||||
transform: "translateX(-16px) rotate(90deg)",
|
||||
}}
|
||||
/>
|
||||
)}
|
||||
|
||||
<div
|
||||
style={{
|
||||
display: "flex",
|
||||
gap: 8,
|
||||
justifyContent: "center",
|
||||
alignItems: "center",
|
||||
}}
|
||||
>
|
||||
<img
|
||||
alt={`League ${league.name}`}
|
||||
style={{
|
||||
width: 64,
|
||||
height: 64,
|
||||
objectFit: "contain",
|
||||
}}
|
||||
src={normalizeLeagueIcon(
|
||||
ratingInfo.leagues[league.index].big_icon
|
||||
)}
|
||||
/>
|
||||
|
||||
<div
|
||||
style={{
|
||||
display: "flex",
|
||||
flexDirection: "column",
|
||||
}}
|
||||
>
|
||||
<div
|
||||
style={{
|
||||
display: "flex",
|
||||
alignItems: "center",
|
||||
justifyContent: "flex-start",
|
||||
}}
|
||||
>
|
||||
<span
|
||||
style={{
|
||||
color: theme.colors[`textHighContrast${leagueTheme}`],
|
||||
fontSize: 24,
|
||||
fontWeight: 900,
|
||||
}}
|
||||
>
|
||||
{statsB2.score.toLocaleString(interaction.locale)}
|
||||
</span>
|
||||
{delta.score !== 0 && (
|
||||
<>
|
||||
<DeltaCaret delta={delta.score} />
|
||||
<span
|
||||
style={{
|
||||
color:
|
||||
delta.score > 0
|
||||
? theme.colors.textLowContrast_green
|
||||
: theme.colors.textLowContrast_red,
|
||||
fontSize: 16,
|
||||
}}
|
||||
>
|
||||
{Math.abs(delta.score).toLocaleString(
|
||||
interaction.locale
|
||||
)}
|
||||
</span>
|
||||
</>
|
||||
)}
|
||||
</div>
|
||||
|
||||
<div
|
||||
style={{
|
||||
display: "flex",
|
||||
alignItems: "center",
|
||||
justifyContent: "flex-start",
|
||||
}}
|
||||
>
|
||||
<span
|
||||
style={{
|
||||
color: theme.colors[`textLowContrast${leagueTheme}`],
|
||||
fontSize: 16,
|
||||
}}
|
||||
>
|
||||
#{statsB2.number.toLocaleString(interaction.locale)}
|
||||
</span>
|
||||
{positionDelta !== undefined && positionDelta !== 0 && (
|
||||
<>
|
||||
<DeltaCaret delta={-positionDelta} />
|
||||
<span
|
||||
style={{
|
||||
color:
|
||||
positionDelta > 0
|
||||
? theme.colors.textLowContrast_red
|
||||
: theme.colors.textLowContrast_green,
|
||||
fontSize: 16,
|
||||
}}
|
||||
>
|
||||
{Math.abs(positionDelta).toLocaleString(
|
||||
interaction.locale
|
||||
)}
|
||||
</span>
|
||||
</>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{reward && (
|
||||
<div
|
||||
style={{
|
||||
display: "flex",
|
||||
gap: 8,
|
||||
justifyContent: "center",
|
||||
alignItems: "center",
|
||||
}}
|
||||
>
|
||||
<div
|
||||
style={{
|
||||
display: "flex",
|
||||
flexDirection: "column",
|
||||
}}
|
||||
>
|
||||
<div
|
||||
style={{
|
||||
display: "flex",
|
||||
alignItems: "center",
|
||||
justifyContent: "flex-end",
|
||||
}}
|
||||
>
|
||||
<span
|
||||
style={{
|
||||
color: theme.colors[`textHighContrast${leagueTheme}`],
|
||||
fontSize: 16,
|
||||
maxWidth: 136,
|
||||
textAlign: "right",
|
||||
whiteSpace: "nowrap",
|
||||
textOverflow: "ellipsis",
|
||||
overflow: "hidden",
|
||||
}}
|
||||
>
|
||||
{reward.type === "vehicle"
|
||||
? reward.vehicle.user_string
|
||||
: reward.stuff.title}
|
||||
</span>
|
||||
</div>
|
||||
|
||||
<div
|
||||
style={{
|
||||
display: "flex",
|
||||
alignItems: "center",
|
||||
justifyContent: "flex-end",
|
||||
}}
|
||||
>
|
||||
<span
|
||||
style={{
|
||||
color: theme.colors[`textLowContrast${leagueTheme}`],
|
||||
fontSize: 16,
|
||||
}}
|
||||
>
|
||||
Reward
|
||||
{reward.type === "stuff" ? ` x${reward.count}` : ""}
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<img
|
||||
style={{
|
||||
width: 64,
|
||||
height: 64,
|
||||
objectFit: "cover",
|
||||
}}
|
||||
src={await iconPng(rewardImage!)}
|
||||
/>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{reward === undefined && (
|
||||
<Glow
|
||||
endOpacity={3 / 4}
|
||||
color={theme.colors[`solidBackground${leagueTheme}`]}
|
||||
style={{
|
||||
transform: "translateX(16px) rotate(-90deg)",
|
||||
}}
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
|
||||
{/* separated because fragment middle man invalidates relative parent: https://github.com/vercel/satori/issues/605 */}
|
||||
{reward && (
|
||||
<Glow
|
||||
direction="reverse"
|
||||
color={theme.colors[`solidBackground${leagueTheme}`]}
|
||||
style={{
|
||||
position: "absolute",
|
||||
top: -40,
|
||||
left: "50%",
|
||||
transform: "translateX(-50%)",
|
||||
}}
|
||||
/>
|
||||
)}
|
||||
{reward && (
|
||||
<Glow
|
||||
color={theme.colors[`solidBackground${leagueTheme}`]}
|
||||
style={{
|
||||
position: "absolute",
|
||||
bottom: -40,
|
||||
left: "50%",
|
||||
transform: "translateX(-50%)",
|
||||
}}
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
|
||||
{delta.battles > 0 && (
|
||||
<div style={{ padding: "8px 0", display: "flex" }}>
|
||||
<div
|
||||
style={{
|
||||
display: "flex",
|
||||
alignItems: "center",
|
||||
justifyContent: "center",
|
||||
gap: 4,
|
||||
flex: 1,
|
||||
flexDirection: "column",
|
||||
}}
|
||||
>
|
||||
<span
|
||||
style={{
|
||||
fontSize: 24,
|
||||
color: theme.colors.textHighContrast,
|
||||
fontWeight: "bold",
|
||||
}}
|
||||
>
|
||||
{delta.battles.toLocaleString(interaction.locale)}
|
||||
</span>
|
||||
<span
|
||||
style={{
|
||||
fontSize: 16,
|
||||
color: theme.colors.textLowContrast,
|
||||
}}
|
||||
>
|
||||
Battles
|
||||
</span>
|
||||
</div>
|
||||
<div
|
||||
style={{
|
||||
display: "flex",
|
||||
alignItems: "center",
|
||||
justifyContent: "center",
|
||||
gap: 4,
|
||||
flex: 1,
|
||||
flexDirection: "column",
|
||||
}}
|
||||
>
|
||||
<span
|
||||
style={{
|
||||
fontSize: 24,
|
||||
color: theme.colors.textHighContrast,
|
||||
fontWeight: "bold",
|
||||
}}
|
||||
>
|
||||
{(100 * (delta.wins / delta.battles)).toFixed(0)}%
|
||||
</span>
|
||||
<span
|
||||
style={{
|
||||
fontSize: 16,
|
||||
color: theme.colors.textLowContrast,
|
||||
}}
|
||||
>
|
||||
Winrate
|
||||
</span>
|
||||
</div>
|
||||
<div
|
||||
style={{
|
||||
display: "flex",
|
||||
alignItems: "center",
|
||||
justifyContent: "center",
|
||||
gap: 4,
|
||||
flex: 1,
|
||||
flexDirection: "column",
|
||||
}}
|
||||
>
|
||||
<span
|
||||
style={{
|
||||
fontSize: 24,
|
||||
color: theme.colors.textHighContrast,
|
||||
fontWeight: "bold",
|
||||
}}
|
||||
>
|
||||
{Math.round(delta.damage / delta.battles).toLocaleString(
|
||||
interaction.locale
|
||||
)}
|
||||
</span>
|
||||
<span
|
||||
style={{
|
||||
fontSize: 16,
|
||||
color: theme.colors.textLowContrast,
|
||||
}}
|
||||
>
|
||||
Damage
|
||||
</span>
|
||||
</div>
|
||||
<div
|
||||
style={{
|
||||
display: "flex",
|
||||
alignItems: "center",
|
||||
justifyContent: "center",
|
||||
gap: 4,
|
||||
flex: 1,
|
||||
flexDirection: "column",
|
||||
}}
|
||||
>
|
||||
<span
|
||||
style={{
|
||||
fontSize: 24,
|
||||
color: theme.colors.textHighContrast,
|
||||
fontWeight: "bold",
|
||||
}}
|
||||
>
|
||||
{(100 * (delta.survived / delta.battles)).toFixed(0)}%
|
||||
</span>
|
||||
<span
|
||||
style={{
|
||||
fontSize: 16,
|
||||
color: theme.colors.textLowContrast,
|
||||
}}
|
||||
>
|
||||
Survival
|
||||
</span>
|
||||
</div>
|
||||
<div
|
||||
style={{
|
||||
display: "flex",
|
||||
alignItems: "center",
|
||||
justifyContent: "center",
|
||||
gap: 4,
|
||||
flex: 1,
|
||||
flexDirection: "column",
|
||||
}}
|
||||
>
|
||||
<span
|
||||
style={{
|
||||
fontSize: 24,
|
||||
color: theme.colors.textHighContrast,
|
||||
fontWeight: "bold",
|
||||
}}
|
||||
>
|
||||
{(delta.kills / delta.battles).toFixed(2)}
|
||||
</span>
|
||||
<span
|
||||
style={{
|
||||
fontSize: 16,
|
||||
color: theme.colors.textLowContrast,
|
||||
}}
|
||||
>
|
||||
Kills
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
</CommandWrapper>
|
||||
);
|
||||
},
|
||||
});
|
||||
});
|
||||
@@ -1,468 +0,0 @@
|
||||
import {
|
||||
FIRST_MINIMAL_ARCHIVED_RATING_SEASON,
|
||||
getAccountInfo,
|
||||
getArchivedLatestSeasonNumber,
|
||||
getArchivedRatingLeaderboard,
|
||||
getClanAccountInfo,
|
||||
getRatingInfo,
|
||||
getRatingLeague,
|
||||
getRatingNeighbors,
|
||||
imgur,
|
||||
isOnGoingRatingSeason,
|
||||
LEAGUES,
|
||||
type RatingInfo,
|
||||
RatingLeaderboard,
|
||||
type Region,
|
||||
} from "@blitzkit/core";
|
||||
import { literals } from "@blitzkit/i18n";
|
||||
import {
|
||||
type APIApplicationCommandOptionChoice,
|
||||
Locale,
|
||||
SlashCommandSubcommandBuilder,
|
||||
} from "discord.js";
|
||||
import { range } from "lodash-es";
|
||||
import markdownEscape from "markdown-escape";
|
||||
import { CommandWrapper } from "../components/CommandWrapper";
|
||||
import * as Leaderboard from "../components/Leaderboard";
|
||||
import { TitleBar } from "../components/TitleBar";
|
||||
import { UserError } from "../core/blitzkit/userError";
|
||||
import { addRegionChoices } from "../core/discord/addRegionChoices";
|
||||
import { addUsernameChoices } from "../core/discord/addUsernameChoices";
|
||||
import { autocompleteUsername } from "../core/discord/autocompleteUsername";
|
||||
import { createLocalizedCommand } from "../core/discord/createLocalizedCommand";
|
||||
import { localizationObject } from "../core/discord/localizationObject";
|
||||
import { resolvePlayerFromCommand } from "../core/discord/resolvePlayerFromCommand";
|
||||
import { translator } from "../core/localization/translator";
|
||||
import type { CommandRegistry } from "../events/interactionCreate";
|
||||
|
||||
interface SimplifiedPlayer {
|
||||
id: number;
|
||||
score: number;
|
||||
position: number;
|
||||
clan: string | undefined;
|
||||
nickname: string;
|
||||
}
|
||||
|
||||
const DEFAULT_LIMIT = 10;
|
||||
|
||||
export const ratingLeaderboardCommand = new Promise<CommandRegistry>(
|
||||
async (resolve) => {
|
||||
const latestArchivedSeasonNumber = await getArchivedLatestSeasonNumber();
|
||||
const onGoingSeason = await isOnGoingRatingSeason();
|
||||
const seasonNumbers = range(
|
||||
FIRST_MINIMAL_ARCHIVED_RATING_SEASON,
|
||||
latestArchivedSeasonNumber + (onGoingSeason ? 1 : 0) + 1
|
||||
).slice(-25);
|
||||
|
||||
function addOptions(option: SlashCommandSubcommandBuilder) {
|
||||
const { strings } = translator(Locale.EnglishUS);
|
||||
|
||||
return option
|
||||
.addIntegerOption((option) =>
|
||||
option
|
||||
.setName(strings.bot.commands.rating_leaderboard.options.limit.name)
|
||||
.setNameLocalizations(
|
||||
localizationObject(
|
||||
(strings) =>
|
||||
strings.bot.commands.rating_leaderboard.options.limit.name,
|
||||
undefined,
|
||||
true
|
||||
)
|
||||
)
|
||||
.setDescription(
|
||||
literals(
|
||||
strings.bot.commands.rating_leaderboard.options.limit
|
||||
.description,
|
||||
{ count: DEFAULT_LIMIT }
|
||||
)
|
||||
)
|
||||
.setDescriptionLocalizations(
|
||||
localizationObject(
|
||||
(strings) =>
|
||||
strings.bot.commands.rating_leaderboard.options.limit
|
||||
.description,
|
||||
{ count: DEFAULT_LIMIT }
|
||||
)
|
||||
)
|
||||
.setRequired(false)
|
||||
.setMinValue(5)
|
||||
.setMaxValue(30)
|
||||
)
|
||||
.addStringOption((option) =>
|
||||
option
|
||||
.setName(
|
||||
strings.bot.commands.rating_leaderboard.options.season.name
|
||||
)
|
||||
.setNameLocalizations(
|
||||
localizationObject(
|
||||
(strings) =>
|
||||
strings.bot.commands.rating_leaderboard.options.season.name,
|
||||
undefined,
|
||||
true
|
||||
)
|
||||
)
|
||||
.setDescription(
|
||||
strings.bot.commands.rating_leaderboard.options.season.description
|
||||
)
|
||||
.setDescriptionLocalizations(
|
||||
localizationObject(
|
||||
(strings) =>
|
||||
strings.bot.commands.rating_leaderboard.options.season
|
||||
.description
|
||||
)
|
||||
)
|
||||
.setRequired(false)
|
||||
.addChoices(
|
||||
...seasonNumbers
|
||||
.map((number, index) => {
|
||||
const current =
|
||||
index === seasonNumbers.length - 1 && onGoingSeason;
|
||||
|
||||
return {
|
||||
name: current
|
||||
? literals(
|
||||
strings.bot.commands.rating_leaderboard.options.season
|
||||
.choices.current,
|
||||
{ season: number }
|
||||
)
|
||||
: `${number}`,
|
||||
value: `${number}`,
|
||||
name_localizations: current
|
||||
? localizationObject(
|
||||
(strings) =>
|
||||
strings.bot.commands.rating_leaderboard.options
|
||||
.season.choices.current,
|
||||
{ season: number }
|
||||
)
|
||||
: undefined,
|
||||
} satisfies APIApplicationCommandOptionChoice<string>;
|
||||
})
|
||||
.reverse()
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
resolve({
|
||||
command: createLocalizedCommand("rating-leaderboard", [
|
||||
{
|
||||
subcommand: "neighbors",
|
||||
modify(option: SlashCommandSubcommandBuilder) {
|
||||
option.addStringOption(addUsernameChoices);
|
||||
addOptions(option);
|
||||
},
|
||||
},
|
||||
{
|
||||
subcommand: "league",
|
||||
modify(option: SlashCommandSubcommandBuilder) {
|
||||
option
|
||||
.addStringOption((option) => {
|
||||
const { strings } = translator(Locale.EnglishUS);
|
||||
|
||||
return option
|
||||
.setName(
|
||||
strings.bot.commands.rating_leaderboard.options.league.name
|
||||
)
|
||||
.setNameLocalizations(
|
||||
localizationObject(
|
||||
(strings) =>
|
||||
strings.bot.commands.rating_leaderboard.options.league
|
||||
.name,
|
||||
undefined,
|
||||
true
|
||||
)
|
||||
)
|
||||
.setDescription(
|
||||
strings.bot.commands.rating_leaderboard.options.league
|
||||
.description
|
||||
)
|
||||
.setDescriptionLocalizations(
|
||||
localizationObject(
|
||||
(strings) =>
|
||||
strings.bot.commands.rating_leaderboard.options.league
|
||||
.description
|
||||
)
|
||||
)
|
||||
.addChoices(
|
||||
...LEAGUES.map(
|
||||
({ name }, value) =>
|
||||
({
|
||||
name: (
|
||||
strings.common.leagues as Record<string, string>
|
||||
)[name],
|
||||
value: `${value}`,
|
||||
name_localizations: localizationObject(
|
||||
(strings) =>
|
||||
(
|
||||
strings.common.leagues as Record<string, string>
|
||||
)[name]
|
||||
),
|
||||
} satisfies APIApplicationCommandOptionChoice<string>)
|
||||
)
|
||||
)
|
||||
.setRequired(true);
|
||||
})
|
||||
.addStringOption(addRegionChoices);
|
||||
addOptions(option);
|
||||
},
|
||||
},
|
||||
]),
|
||||
|
||||
// BIG TODO: title seems to be in english
|
||||
|
||||
async handler(interaction) {
|
||||
const { strings } = translator(interaction.locale);
|
||||
const subcommand = interaction.options.getSubcommand(true) as
|
||||
| "league"
|
||||
| "neighbors";
|
||||
const limit = interaction.options.getInteger("limit") ?? DEFAULT_LIMIT;
|
||||
const seasonOption = interaction.options.getString("season");
|
||||
const season = seasonOption
|
||||
? parseInt(seasonOption)
|
||||
: onGoingSeason
|
||||
? latestArchivedSeasonNumber + 1
|
||||
: latestArchivedSeasonNumber;
|
||||
const isCurrentSeason = season === latestArchivedSeasonNumber + 1;
|
||||
let titleName: string;
|
||||
let titleImage: string | undefined;
|
||||
let titleDescription: string;
|
||||
let playersAfter: number;
|
||||
let players: SimplifiedPlayer[] | undefined;
|
||||
let archivedLeaderboard: RatingLeaderboard | null;
|
||||
let playerId: number | undefined;
|
||||
let regionRatingInfo: RatingInfo | null;
|
||||
|
||||
if (subcommand === "league") {
|
||||
const leagueIndex = parseInt(
|
||||
interaction.options.getString("league")!
|
||||
);
|
||||
const region = interaction.options.getString("region") as Region;
|
||||
regionRatingInfo = await (isCurrentSeason
|
||||
? getRatingInfo(region)
|
||||
: null);
|
||||
|
||||
if (
|
||||
regionRatingInfo !== null &&
|
||||
regionRatingInfo.detail !== undefined
|
||||
) {
|
||||
return strings.bot.commands.rating_leaderboard.body
|
||||
.no_ongoing_season;
|
||||
}
|
||||
|
||||
const result = isCurrentSeason
|
||||
? await getRatingLeague(region, leagueIndex).then(async (result) =>
|
||||
result.slice(0, limit).map(
|
||||
(player) =>
|
||||
({
|
||||
id: player.spa_id,
|
||||
score: player.score,
|
||||
position: player.number,
|
||||
clan: player.clan_tag,
|
||||
nickname: player.nickname,
|
||||
} satisfies SimplifiedPlayer)
|
||||
)
|
||||
)
|
||||
: await getArchivedRatingLeaderboard(region, season!).then(
|
||||
async (players) => {
|
||||
const firstPlayerIndex =
|
||||
leagueIndex === 0
|
||||
? 0
|
||||
: players.version!.value.entries.findIndex(
|
||||
(player) =>
|
||||
player.score < LEAGUES[leagueIndex - 1].minScore
|
||||
);
|
||||
const lastPlayerIndex = firstPlayerIndex + limit - 1;
|
||||
const trimmed = players.version!.value.entries.slice(
|
||||
firstPlayerIndex,
|
||||
lastPlayerIndex + 1
|
||||
);
|
||||
const clanData = await getClanAccountInfo(
|
||||
region,
|
||||
trimmed.map(({ id }) => id),
|
||||
["clan"]
|
||||
);
|
||||
|
||||
return trimmed.map(
|
||||
(player, index) =>
|
||||
({
|
||||
id: player.id,
|
||||
score: player.score,
|
||||
position: firstPlayerIndex + index + 1,
|
||||
clan: clanData[player.id]?.clan?.tag,
|
||||
nickname:
|
||||
clanData[index]?.account_name ??
|
||||
literals(
|
||||
strings.bot.commands.rating_leaderboard.body
|
||||
.deleted_player,
|
||||
{ id: player.id }
|
||||
),
|
||||
} satisfies SimplifiedPlayer)
|
||||
);
|
||||
}
|
||||
);
|
||||
const leagueInfo = LEAGUES[leagueIndex];
|
||||
archivedLeaderboard = await getArchivedRatingLeaderboard(
|
||||
region,
|
||||
season
|
||||
);
|
||||
|
||||
players = result;
|
||||
playersAfter =
|
||||
(regionRatingInfo === null
|
||||
? archivedLeaderboard.version!.value.entries.length
|
||||
: regionRatingInfo.count) - result[result.length - 1].position;
|
||||
titleName = `${
|
||||
leagueInfo
|
||||
? (strings.common.leagues as Record<string, string>)[
|
||||
LEAGUES[leagueInfo.index].name
|
||||
]
|
||||
: ""
|
||||
} - ${strings.common.regions.short[region]}`;
|
||||
titleImage = imgur(leagueInfo.icon);
|
||||
titleDescription = literals(
|
||||
strings.bot.commands.rating_leaderboard.body.top_players,
|
||||
{ count: limit }
|
||||
);
|
||||
} else {
|
||||
const { region, id } = await resolvePlayerFromCommand(interaction);
|
||||
regionRatingInfo = isCurrentSeason
|
||||
? await getRatingInfo(region)
|
||||
: null;
|
||||
|
||||
if (
|
||||
regionRatingInfo !== null &&
|
||||
regionRatingInfo.detail !== undefined
|
||||
) {
|
||||
return strings.bot.commands.rating_leaderboard.body
|
||||
.no_ongoing_season;
|
||||
}
|
||||
|
||||
const accountInfo = await getAccountInfo(region, id);
|
||||
const clan = (await getClanAccountInfo(region, id, ["clan"]))?.clan;
|
||||
const neighbors = isCurrentSeason
|
||||
? await getRatingNeighbors(region, id, Math.round(limit / 2)).then(
|
||||
(players) =>
|
||||
players.neighbors.map(
|
||||
(player) =>
|
||||
({
|
||||
id: player.spa_id,
|
||||
position: player.number,
|
||||
score: player.score,
|
||||
clan: player.clan_tag,
|
||||
nickname: player.nickname,
|
||||
} satisfies SimplifiedPlayer)
|
||||
)
|
||||
)
|
||||
: await getArchivedRatingLeaderboard(region, season!).then(
|
||||
async (players) => {
|
||||
const playerIndex = players.version!.value.entries.findIndex(
|
||||
(player) => player.id === id
|
||||
);
|
||||
|
||||
if (playerIndex === -1) {
|
||||
throw new UserError(
|
||||
literals(
|
||||
strings.bot.commands.rating_leaderboard.body
|
||||
.no_participation,
|
||||
{ player: markdownEscape(accountInfo.nickname), season }
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
const halfRange = Math.round(limit / 2);
|
||||
const trimmed = players.version!.value.entries.slice(
|
||||
playerIndex - halfRange,
|
||||
playerIndex + halfRange + 1
|
||||
);
|
||||
const clanData = await getClanAccountInfo(
|
||||
region,
|
||||
trimmed.map((player) => player.id),
|
||||
["clan"]
|
||||
);
|
||||
|
||||
return trimmed.map((player, index) => ({
|
||||
id: player.id,
|
||||
score: player.score,
|
||||
position: playerIndex + index + 1,
|
||||
clan: clanData[index]?.clan?.tag,
|
||||
nickname: clanData[index]
|
||||
? clanData[index]!.account_name
|
||||
: `Deleted ${player.id}`,
|
||||
}));
|
||||
}
|
||||
);
|
||||
archivedLeaderboard = await getArchivedRatingLeaderboard(
|
||||
region,
|
||||
season
|
||||
);
|
||||
|
||||
players = neighbors;
|
||||
titleImage = clan
|
||||
? `https://wotblitz-gc.gcdn.co/icons/clanEmblems1x/clan-icon-v2-${clan.emblem_set_id}.png`
|
||||
: undefined;
|
||||
titleName = neighbors ? accountInfo.nickname : "";
|
||||
titleDescription =
|
||||
strings.bot.commands.rating_leaderboard.body.neighbors;
|
||||
playersAfter =
|
||||
(regionRatingInfo === null
|
||||
? archivedLeaderboard.version!.value.entries.length
|
||||
: regionRatingInfo.count) -
|
||||
neighbors[neighbors.length - 1].position;
|
||||
playerId = id;
|
||||
}
|
||||
|
||||
const items = players.map((player) => {
|
||||
const midnightIndex =
|
||||
archivedLeaderboard?.version!.value.entries.findIndex(
|
||||
(item) => item.id === player.id
|
||||
);
|
||||
const midnightScore =
|
||||
midnightIndex === undefined
|
||||
? player.score
|
||||
: archivedLeaderboard!.version!.value.entries[midnightIndex]
|
||||
.score;
|
||||
const midnightPosition =
|
||||
midnightIndex === undefined ? player.position : midnightIndex + 1;
|
||||
|
||||
return (
|
||||
<Leaderboard.Item
|
||||
nickname={player.nickname}
|
||||
score={player.score}
|
||||
position={player.position}
|
||||
clan={player.clan}
|
||||
deltaScore={player.score - midnightScore}
|
||||
deltaPosition={midnightPosition - player.position}
|
||||
key={player.id}
|
||||
highlight={player.id === playerId}
|
||||
/>
|
||||
);
|
||||
});
|
||||
|
||||
return (
|
||||
<CommandWrapper>
|
||||
<TitleBar
|
||||
title={titleName}
|
||||
image={titleImage}
|
||||
description={titleDescription}
|
||||
/>
|
||||
|
||||
{items && (
|
||||
<Leaderboard.Root>
|
||||
{items}
|
||||
{playersAfter > 0 && (
|
||||
<Leaderboard.Gap
|
||||
message={literals(
|
||||
strings.bot.commands.rating_leaderboard.body.more,
|
||||
{ count: playersAfter.toLocaleString(interaction.locale) }
|
||||
)}
|
||||
/>
|
||||
)}
|
||||
</Leaderboard.Root>
|
||||
)}
|
||||
</CommandWrapper>
|
||||
);
|
||||
},
|
||||
|
||||
autocomplete: autocompleteUsername,
|
||||
});
|
||||
}
|
||||
);
|
||||
@@ -1,592 +0,0 @@
|
||||
import {
|
||||
calculateWN8,
|
||||
emblemURL,
|
||||
getClanAccountInfo,
|
||||
idToRegion,
|
||||
tankIcon,
|
||||
TIER_ROMAN_NUMERALS,
|
||||
} from "@blitzkit/core";
|
||||
import { Locale } from "discord.js";
|
||||
import { clamp } from "lodash-es";
|
||||
import { CommandWrapper } from "../components/CommandWrapper";
|
||||
import { TitleBar } from "../components/TitleBar";
|
||||
import { iconPng } from "../core/blitzkit/iconPng";
|
||||
import {
|
||||
averageDefinitions,
|
||||
mapDefinitions,
|
||||
tankDefinitions,
|
||||
} from "../core/blitzkit/nonBlockingPromises";
|
||||
import { RenderConfiguration } from "../core/blitzkit/renderConfiguration";
|
||||
import { buttonLink } from "../core/discord/buttonLink";
|
||||
import { createLocalizedCommand } from "../core/discord/createLocalizedCommand";
|
||||
import { localizationObject } from "../core/discord/localizationObject";
|
||||
import { translator } from "../core/localization/translator";
|
||||
import { type CommandRegistry } from "../events/interactionCreate";
|
||||
import { theme } from "../stitches.config";
|
||||
|
||||
type WotInspectorReplaySubmission =
|
||||
| { status: "error"; data: unknown; error: { message: string } }
|
||||
| {
|
||||
status: "ok";
|
||||
data: {
|
||||
download_url: string;
|
||||
view_url: string;
|
||||
summary: {
|
||||
battle_start_time: string;
|
||||
map_name: string;
|
||||
battle_start_timestamp: number;
|
||||
battle_duration: number;
|
||||
title: string;
|
||||
arena_unique_id: string;
|
||||
allies: number[];
|
||||
enemies: number[];
|
||||
protagonist: number;
|
||||
player_name: string;
|
||||
vehicle: string;
|
||||
exp_base: number;
|
||||
exp_total: number;
|
||||
credits_base: number;
|
||||
credits_total: number;
|
||||
room_type: number;
|
||||
battle_type: number;
|
||||
mastery_badge: number;
|
||||
battle_result: number;
|
||||
vehicle_tier: number;
|
||||
vehicle_type: number;
|
||||
protagonist_team: number;
|
||||
winner_team: number;
|
||||
details: {
|
||||
achievements: unknown[];
|
||||
base_capture_points: number;
|
||||
base_defend_points: number;
|
||||
chassis_id: unknown | null;
|
||||
clan_tag: string;
|
||||
clanid: number;
|
||||
credits: number;
|
||||
damage_assisted: number;
|
||||
damage_assisted_track: number;
|
||||
damage_blocked: unknown | null;
|
||||
damage_made: number;
|
||||
damage_received: number;
|
||||
dbid: number;
|
||||
death_reason: number;
|
||||
distance_travelled: number;
|
||||
enemies_damaged: number;
|
||||
enemies_destroyed: number;
|
||||
enemies_spotted: number;
|
||||
entity_id: number;
|
||||
exp: number;
|
||||
exp_for_assist: number;
|
||||
exp_for_damage: number;
|
||||
exp_team_bonus: number;
|
||||
gun_id: unknown | null;
|
||||
hero_bonus_credits: number;
|
||||
hero_bonus_exp: number;
|
||||
hitpoints_left: number;
|
||||
hits_bounced: number;
|
||||
hits_pen: number;
|
||||
hits_received: number;
|
||||
hits_splash: number;
|
||||
killed_by: number;
|
||||
name: string;
|
||||
shots_hit: number;
|
||||
shots_made: number;
|
||||
shots_pen: number;
|
||||
shots_splash: number;
|
||||
squad_index: number;
|
||||
team: number;
|
||||
time_alive: number;
|
||||
turret_id: unknown | null;
|
||||
vehicle_descr: number;
|
||||
wp_points_earned: number;
|
||||
wp_points_stolen: number;
|
||||
};
|
||||
};
|
||||
};
|
||||
error: {};
|
||||
};
|
||||
|
||||
interface WotInspectorReplay {
|
||||
id: string;
|
||||
map_id: number;
|
||||
battle_duration: number;
|
||||
title: unknown | null;
|
||||
player_name: string;
|
||||
protagonist: number;
|
||||
vehicle_descr: number;
|
||||
mastery_badge: number;
|
||||
exp_base: number;
|
||||
enemies_spotted: number;
|
||||
enemies_destroyed: number;
|
||||
damage_assisted: number;
|
||||
damage_made: number;
|
||||
details_url: string;
|
||||
download_url: string;
|
||||
game_version: {
|
||||
name: string;
|
||||
package: string;
|
||||
};
|
||||
arena_unique_id: string;
|
||||
download_count: number;
|
||||
data_version: number;
|
||||
private: boolean;
|
||||
private_clan: boolean;
|
||||
battle_start_time: Date;
|
||||
upload_time: Date;
|
||||
allies: number[];
|
||||
enemies: number[];
|
||||
protagonist_clan: number;
|
||||
protagonist_team: number;
|
||||
battle_result: number;
|
||||
credits_base: number;
|
||||
tags: number[];
|
||||
battle_type: number;
|
||||
room_type: number;
|
||||
last_accessed_time: Date;
|
||||
winner_team: number;
|
||||
finish_reason: number;
|
||||
players_data: WotInspectorReplayPlayerData[];
|
||||
exp_total: number;
|
||||
credits_total: number;
|
||||
repair_cost: number;
|
||||
exp_free: number;
|
||||
exp_free_base: number;
|
||||
exp_penalty: number;
|
||||
credits_penalty: number;
|
||||
credits_contribution_in: number;
|
||||
credits_contribution_out: number;
|
||||
camouflage_id: number;
|
||||
}
|
||||
|
||||
export interface WotInspectorReplayPlayerData {
|
||||
team: number;
|
||||
name: string;
|
||||
entity_id: number;
|
||||
dbid: number;
|
||||
clanid: number | null;
|
||||
clan_tag: null | string;
|
||||
hitpoints_left: number;
|
||||
credits: number;
|
||||
exp: number;
|
||||
shots_made: number;
|
||||
shots_hit: number;
|
||||
shots_splash: number;
|
||||
shots_pen: number;
|
||||
damage_made: number;
|
||||
damage_received: number;
|
||||
damage_assisted: number;
|
||||
damage_assisted_track: number;
|
||||
hits_received: number;
|
||||
hits_bounced: number;
|
||||
hits_splash: number;
|
||||
hits_pen: number;
|
||||
enemies_spotted: number;
|
||||
enemies_damaged: number;
|
||||
enemies_destroyed: number;
|
||||
time_alive: number;
|
||||
distance_travelled: number;
|
||||
killed_by: number;
|
||||
base_capture_points: number;
|
||||
base_defend_points: number;
|
||||
exp_for_damage: number;
|
||||
exp_for_assist: number;
|
||||
exp_team_bonus: number;
|
||||
wp_points_earned: number;
|
||||
wp_points_stolen: number;
|
||||
hero_bonus_credits: number;
|
||||
hero_bonus_exp: number;
|
||||
death_reason: number;
|
||||
achievements: any[];
|
||||
vehicle_descr: number;
|
||||
turret_id: number;
|
||||
gun_id: number;
|
||||
chassis_id: number;
|
||||
squad_index: number;
|
||||
damage_blocked: number;
|
||||
}
|
||||
|
||||
function stat(value: string | number, flex = 2) {
|
||||
return (
|
||||
<div
|
||||
style={{
|
||||
flex,
|
||||
display: "flex",
|
||||
alignItems: "center",
|
||||
justifyContent: "center",
|
||||
}}
|
||||
>
|
||||
<span style={{ fontSize: 16 }}>{value}</span>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
async function playerListing(
|
||||
locale: Locale,
|
||||
player: WotInspectorReplayPlayerData,
|
||||
protagonistTeam: boolean,
|
||||
winningTeam: number,
|
||||
recordingPlayer = false,
|
||||
) {
|
||||
const { unwrap } = translator(locale);
|
||||
const awaitedTankAverages = await averageDefinitions;
|
||||
const awaitedTankDefinitions = await tankDefinitions;
|
||||
const tank = awaitedTankDefinitions.tanks[player.vehicle_descr];
|
||||
const blockAccent = recordingPlayer ? "_amber" : "";
|
||||
const healthAccent = protagonistTeam
|
||||
? recordingPlayer
|
||||
? "_amber"
|
||||
: "_green"
|
||||
: "_red";
|
||||
|
||||
// our turret ids are always off by 1 or 2 lol so imma just grab the closest
|
||||
// TODO: 💀
|
||||
const turret = tank.turrets.sort(
|
||||
(a, b) =>
|
||||
Math.abs(a.id - player.turret_id) - Math.abs(b.id - player.turret_id),
|
||||
)[0];
|
||||
const totalHealth = turret.health + tank.health;
|
||||
const healthLeft = clamp(player.hitpoints_left / totalHealth, 0, 1);
|
||||
const tankAveragesEntry = awaitedTankAverages.averages[player.vehicle_descr];
|
||||
const wn8 =
|
||||
tankAveragesEntry === undefined
|
||||
? -1
|
||||
: calculateWN8(tankAveragesEntry.mu, {
|
||||
battles: 1,
|
||||
damage_dealt: player.damage_made,
|
||||
dropped_capture_points: player.base_defend_points,
|
||||
frags: player.enemies_destroyed,
|
||||
spotted: player.enemies_spotted,
|
||||
wins: winningTeam === player.team ? 1 : 0,
|
||||
});
|
||||
|
||||
return (
|
||||
<div
|
||||
key={player.entity_id}
|
||||
style={{
|
||||
display: "flex",
|
||||
alignItems: "center",
|
||||
gap: 8,
|
||||
backgroundColor: theme.colors[`appBackground2${blockAccent}`],
|
||||
padding: 8,
|
||||
}}
|
||||
>
|
||||
<div
|
||||
style={{
|
||||
display: "flex",
|
||||
gap: 8,
|
||||
flex: 1,
|
||||
overflow: "hidden",
|
||||
alignItems: "center",
|
||||
}}
|
||||
>
|
||||
<img
|
||||
alt={unwrap(tank.name!)}
|
||||
src={await iconPng(tankIcon(tank.id))}
|
||||
style={{
|
||||
width: 32,
|
||||
height: 32,
|
||||
objectFit: "contain",
|
||||
}}
|
||||
/>
|
||||
|
||||
<div
|
||||
style={{
|
||||
display: "flex",
|
||||
flexDirection: "column",
|
||||
// align
|
||||
}}
|
||||
>
|
||||
<div
|
||||
style={{
|
||||
display: "flex",
|
||||
gap: 4,
|
||||
alignItems: "center",
|
||||
}}
|
||||
>
|
||||
<span
|
||||
style={{
|
||||
color: theme.colors[`textLowContrast${blockAccent}`],
|
||||
fontSize: 12,
|
||||
}}
|
||||
>
|
||||
{TIER_ROMAN_NUMERALS[tank.tier]}
|
||||
</span>
|
||||
<span
|
||||
style={{
|
||||
color: theme.colors[`textHighContrast${blockAccent}`],
|
||||
fontSize: 16,
|
||||
}}
|
||||
>
|
||||
{unwrap(tank.name!)}
|
||||
</span>
|
||||
</div>
|
||||
|
||||
<span
|
||||
style={{
|
||||
fontSize: 16,
|
||||
color: theme.colors[`textLowContrast${blockAccent}`],
|
||||
whiteSpace: "nowrap",
|
||||
}}
|
||||
>
|
||||
{player.name}
|
||||
{player.clan_tag ? ` [${player.clan_tag}]` : ""}
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div
|
||||
style={{
|
||||
display: "flex",
|
||||
flex: 1,
|
||||
}}
|
||||
>
|
||||
{stat(player.damage_made.toLocaleString())}
|
||||
{stat(wn8 === -1 ? "--" : Math.round(wn8).toLocaleString())}
|
||||
{stat(player.exp.toLocaleString())}
|
||||
{stat(player.enemies_destroyed, 1)}
|
||||
</div>
|
||||
|
||||
<div
|
||||
style={{
|
||||
borderRadius: 2,
|
||||
backgroundColor: theme.colors[`componentInteractive${healthAccent}`],
|
||||
display: "flex",
|
||||
width: 4,
|
||||
height: "100%",
|
||||
transform: "scaleY(-1)",
|
||||
}}
|
||||
>
|
||||
<div
|
||||
style={{
|
||||
width: "100%",
|
||||
height: `${healthLeft * 100}%`,
|
||||
borderRadius: 2,
|
||||
backgroundColor: theme.colors[`solidBackground${healthAccent}`],
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
function Header() {
|
||||
return (
|
||||
<div
|
||||
style={{
|
||||
padding: 8,
|
||||
display: "flex",
|
||||
alignItems: "center",
|
||||
gap: 8,
|
||||
}}
|
||||
>
|
||||
<div style={{ flex: 1 }} />
|
||||
|
||||
<div
|
||||
style={{
|
||||
display: "flex",
|
||||
flex: 1,
|
||||
}}
|
||||
>
|
||||
<div
|
||||
style={{
|
||||
flex: 2,
|
||||
display: "flex",
|
||||
alignItems: "center",
|
||||
justifyContent: "center",
|
||||
}}
|
||||
>
|
||||
<span
|
||||
style={{
|
||||
fontSize: 16,
|
||||
color: theme.colors.textLowContrast,
|
||||
}}
|
||||
>
|
||||
Damage
|
||||
</span>
|
||||
</div>
|
||||
<div
|
||||
style={{
|
||||
flex: 2,
|
||||
display: "flex",
|
||||
alignItems: "center",
|
||||
justifyContent: "center",
|
||||
}}
|
||||
>
|
||||
<span
|
||||
style={{
|
||||
fontSize: 16,
|
||||
color: theme.colors.textLowContrast,
|
||||
}}
|
||||
>
|
||||
WN8
|
||||
</span>
|
||||
</div>
|
||||
<div
|
||||
style={{
|
||||
flex: 2,
|
||||
display: "flex",
|
||||
alignItems: "center",
|
||||
justifyContent: "center",
|
||||
}}
|
||||
>
|
||||
<span
|
||||
style={{
|
||||
fontSize: 16,
|
||||
color: theme.colors.textLowContrast,
|
||||
}}
|
||||
>
|
||||
XP
|
||||
</span>
|
||||
</div>
|
||||
<div
|
||||
style={{
|
||||
flex: 1,
|
||||
display: "flex",
|
||||
alignItems: "center",
|
||||
justifyContent: "center",
|
||||
}}
|
||||
>
|
||||
<span
|
||||
style={{
|
||||
fontSize: 16,
|
||||
color: theme.colors.textLowContrast,
|
||||
}}
|
||||
>
|
||||
Kills
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
export const replayCommand = new Promise<CommandRegistry>((resolve) => {
|
||||
const { strings } = translator(Locale.EnglishUS);
|
||||
|
||||
resolve({
|
||||
command: createLocalizedCommand("replay").addAttachmentOption((option) =>
|
||||
option
|
||||
.setName(strings.bot.commands.replay.options.file.name)
|
||||
.setNameLocalizations(
|
||||
localizationObject(
|
||||
(strings) => strings.bot.commands.replay.options.file.name,
|
||||
undefined,
|
||||
true,
|
||||
),
|
||||
)
|
||||
.setDescription(strings.bot.commands.replay.options.file.description)
|
||||
.setDescriptionLocalizations(
|
||||
localizationObject(
|
||||
(strings) => strings.bot.commands.replay.options.file.description,
|
||||
),
|
||||
)
|
||||
.setRequired(true),
|
||||
),
|
||||
|
||||
async handler(interaction) {
|
||||
const awaitedMapDefinitions = await mapDefinitions;
|
||||
const file = interaction.options.getAttachment("file")!;
|
||||
const submissionData = (await fetch(
|
||||
`https://wotinspector.com/api/replay/upload/?url=${encodeURIComponent(
|
||||
file.url,
|
||||
)}`,
|
||||
).then((response) => response.json())) as WotInspectorReplaySubmission;
|
||||
|
||||
if (submissionData.status === "error") {
|
||||
return `# Uh oh! WoT Inspector didn't like that.\n\nThere was an error processing your replay. Get help on [the official Discord server](https://discord.gg/nDt7AjGJQH).`;
|
||||
}
|
||||
|
||||
const replayId = submissionData.data.download_url.split("/").at(-1)!;
|
||||
const replayData = (await fetch(
|
||||
`https://api.wotinspector.com/v2/blitz/replays/${replayId}/`,
|
||||
).then((response) => response.json())) as WotInspectorReplay;
|
||||
const antagonistTeamId = 3 - replayData.protagonist_team;
|
||||
const players = replayData.players_data.sort(
|
||||
(a, b) => b.damage_made - a.damage_made,
|
||||
);
|
||||
const clan = (
|
||||
await getClanAccountInfo(
|
||||
idToRegion(replayData.protagonist),
|
||||
replayData.protagonist,
|
||||
["clan"],
|
||||
)
|
||||
)?.clan;
|
||||
const clanImage = clan ? emblemURL(clan.emblem_set_id) : undefined;
|
||||
|
||||
return [
|
||||
new RenderConfiguration({ width: 960 }),
|
||||
<CommandWrapper>
|
||||
<TitleBar
|
||||
title={replayData.player_name}
|
||||
image={clanImage}
|
||||
description={`${
|
||||
replayData.protagonist_team === replayData.winner_team
|
||||
? "Victory"
|
||||
: "Defeat"
|
||||
} • ${awaitedMapDefinitions.maps[replayData.map_id].name}`}
|
||||
/>
|
||||
|
||||
<div
|
||||
style={{
|
||||
display: "flex",
|
||||
gap: 8,
|
||||
}}
|
||||
>
|
||||
<div
|
||||
style={{
|
||||
flex: 1,
|
||||
display: "flex",
|
||||
flexDirection: "column",
|
||||
gap: 4,
|
||||
}}
|
||||
>
|
||||
<Header />
|
||||
|
||||
{await Promise.all(
|
||||
players
|
||||
.filter(
|
||||
(player) => player.team === replayData.protagonist_team,
|
||||
)
|
||||
.map((player) =>
|
||||
playerListing(
|
||||
interaction.locale,
|
||||
player,
|
||||
true,
|
||||
replayData.winner_team,
|
||||
player.dbid === replayData.protagonist,
|
||||
),
|
||||
),
|
||||
)}
|
||||
</div>
|
||||
|
||||
<div
|
||||
style={{
|
||||
flex: 1,
|
||||
display: "flex",
|
||||
flexDirection: "column",
|
||||
gap: 4,
|
||||
}}
|
||||
>
|
||||
<Header />
|
||||
|
||||
{await Promise.all(
|
||||
players
|
||||
.filter((player) => player.team === antagonistTeamId)
|
||||
.map((player) =>
|
||||
playerListing(
|
||||
interaction.locale,
|
||||
player,
|
||||
false,
|
||||
replayData.winner_team,
|
||||
),
|
||||
),
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
</CommandWrapper>,
|
||||
buttonLink(submissionData.data.view_url, "WoT Inspector"),
|
||||
buttonLink(submissionData.data.download_url, "Download"),
|
||||
];
|
||||
},
|
||||
});
|
||||
});
|
||||
@@ -1,626 +0,0 @@
|
||||
import {
|
||||
asset,
|
||||
emblemURL,
|
||||
equipmentPriceMatrix,
|
||||
getAccountInfo,
|
||||
getClanAccountInfo,
|
||||
getTankStats,
|
||||
TANK_ICONS,
|
||||
TankType,
|
||||
TIER_ROMAN_NUMERALS,
|
||||
} from "@blitzkit/core";
|
||||
import { literals } from "@blitzkit/i18n";
|
||||
import { escapeMarkdown, Locale } from "discord.js";
|
||||
import { CommandWrapper } from "../components/CommandWrapper";
|
||||
import { TitleBar } from "../components/TitleBar";
|
||||
import { resolveTankId } from "../core/blitz/resolveTankId";
|
||||
import { buildTechTreeLine } from "../core/blitzkit/buildTechTreeLine";
|
||||
import { iconPng } from "../core/blitzkit/iconPng";
|
||||
import { tankDefinitions } from "../core/blitzkit/nonBlockingPromises";
|
||||
import { resolveAncestry } from "../core/blitzkit/resolveAncestry";
|
||||
import { tankIconPng } from "../core/blitzkit/tankIconPng";
|
||||
import { addUsernameChoices } from "../core/discord/addUsernameChoices";
|
||||
import { autocompleteTanks } from "../core/discord/autocompleteTanks";
|
||||
import { createLocalizedCommand } from "../core/discord/createLocalizedCommand";
|
||||
import { localizationObject } from "../core/discord/localizationObject";
|
||||
import { resolvePlayerFromCommand } from "../core/discord/resolvePlayerFromCommand";
|
||||
import { translator } from "../core/localization/translator";
|
||||
import { type CommandRegistry } from "../events/interactionCreate";
|
||||
import { theme } from "../stitches.config";
|
||||
|
||||
export const researchCommand = new Promise<CommandRegistry>((resolve) => {
|
||||
const { strings } = translator(Locale.EnglishUS);
|
||||
|
||||
resolve({
|
||||
command: createLocalizedCommand("research")
|
||||
.addStringOption((option) =>
|
||||
option
|
||||
.setName(strings.bot.commands.research.options.target_tank.name!)
|
||||
.setNameLocalizations(
|
||||
localizationObject(
|
||||
(strings) =>
|
||||
strings.bot.commands.research.options.target_tank.name,
|
||||
undefined,
|
||||
true,
|
||||
),
|
||||
)
|
||||
.setDescription(
|
||||
strings.bot.commands.research.options.target_tank.description,
|
||||
)
|
||||
.setDescriptionLocalizations(
|
||||
localizationObject(
|
||||
(strings) =>
|
||||
strings.bot.commands.research.options.target_tank.description,
|
||||
),
|
||||
)
|
||||
.setAutocomplete(true)
|
||||
.setRequired(true),
|
||||
)
|
||||
.addStringOption((option) =>
|
||||
option
|
||||
.setName(strings.bot.commands.research.options.starting_tank.name!)
|
||||
.setNameLocalizations(
|
||||
localizationObject(
|
||||
(strings) =>
|
||||
strings.bot.commands.research.options.starting_tank.name,
|
||||
undefined,
|
||||
true,
|
||||
),
|
||||
)
|
||||
.setDescription(
|
||||
strings.bot.commands.research.options.starting_tank.description,
|
||||
)
|
||||
.setDescriptionLocalizations(
|
||||
localizationObject(
|
||||
(strings) =>
|
||||
strings.bot.commands.research.options.starting_tank.description,
|
||||
),
|
||||
)
|
||||
.setAutocomplete(true)
|
||||
.setRequired(false),
|
||||
)
|
||||
.addStringOption(addUsernameChoices),
|
||||
|
||||
async handler(interaction) {
|
||||
const { strings, unwrap } = translator(interaction.locale);
|
||||
const awaitedTankDefinitions = await tankDefinitions;
|
||||
const targetTankId = await resolveTankId(
|
||||
interaction.options.getString("target-tank", true),
|
||||
interaction.locale,
|
||||
true,
|
||||
);
|
||||
const startingTankRaw = interaction.options.getString("starting-tank");
|
||||
const targetTank = awaitedTankDefinitions.tanks[targetTankId];
|
||||
const { id, region } = await resolvePlayerFromCommand(interaction);
|
||||
let startingTankId: number;
|
||||
const targetTankAncestry = await resolveAncestry(targetTankId);
|
||||
|
||||
if (startingTankRaw) {
|
||||
startingTankId = await resolveTankId(
|
||||
startingTankRaw,
|
||||
interaction.locale,
|
||||
true,
|
||||
);
|
||||
|
||||
if (targetTankId === startingTankId) {
|
||||
return literals(
|
||||
strings.bot.commands.research.errors.start_end_equal,
|
||||
{ tank: escapeMarkdown(unwrap(targettank.name!)) },
|
||||
);
|
||||
}
|
||||
|
||||
const startingTank = awaitedTankDefinitions.tanks[startingTankId];
|
||||
|
||||
if (startingTank.tier > targetTank.tier) {
|
||||
return literals(strings.bot.commands.research.errors.unordered, {
|
||||
tank_1: escapeMarkdown(unwrap(startingtank.name!)),
|
||||
tank_2: escapeMarkdown(unwrap(targettank.name!)),
|
||||
});
|
||||
}
|
||||
|
||||
if (!targetTankAncestry.includes(startingTankId)) {
|
||||
return literals(
|
||||
strings.bot.commands.research.errors.tanks_not_on_line,
|
||||
{
|
||||
tank_1: escapeMarkdown(unwrap(targettank.name!)),
|
||||
tank_2: escapeMarkdown(unwrap(startingtank.name!)),
|
||||
},
|
||||
);
|
||||
}
|
||||
} else {
|
||||
if (targetTank.type !== TankType.TANK_TYPE_RESEARCHABLE) {
|
||||
return literals(strings.bot.commands.research.errors.non_tech_tree, {
|
||||
tank: escapeMarkdown(unwrap(targettank.name!)),
|
||||
});
|
||||
}
|
||||
|
||||
if (targetTank.tier === 1) {
|
||||
return literals(strings.bot.commands.research.errors.tier_1, {
|
||||
tank: escapeMarkdown(unwrap(targettank.name!)),
|
||||
});
|
||||
}
|
||||
|
||||
const tankStats = await getTankStats(region, id);
|
||||
|
||||
if (tankStats === null) {
|
||||
return strings.bot.common.errors.no_tank_stats;
|
||||
}
|
||||
|
||||
if (tankStats.some(({ tank_id }) => tank_id === targetTankId)) {
|
||||
return literals(
|
||||
strings.bot.commands.research.errors.already_researched,
|
||||
{ tank: escapeMarkdown(unwrap(targettank.name!)) },
|
||||
);
|
||||
}
|
||||
|
||||
const foundAncestor = targetTankAncestry.find(
|
||||
(id) =>
|
||||
awaitedTankDefinitions.tanks[id].tier === 1 ||
|
||||
tankStats.some(({ tank_id }) => tank_id === id),
|
||||
);
|
||||
|
||||
if (foundAncestor === undefined) {
|
||||
throw new Error("No first owned tech tree found.");
|
||||
}
|
||||
|
||||
startingTankId = foundAncestor;
|
||||
}
|
||||
|
||||
const techTreeLine = await buildTechTreeLine(
|
||||
startingTankId,
|
||||
targetTankId,
|
||||
);
|
||||
|
||||
const line = [...techTreeLine, startingTankId].reverse();
|
||||
const { nickname } = await getAccountInfo(region, id);
|
||||
const clan = (await getClanAccountInfo(region, id, ["clan"]))?.clan;
|
||||
const clanImage = clan ? emblemURL(clan.emblem_set_id) : undefined;
|
||||
const costs = await Promise.all(
|
||||
line.map(async (id) => {
|
||||
const tank = awaitedTankDefinitions.tanks[id];
|
||||
const turretXps = new Map<number, number>();
|
||||
const gunXps = new Map<number, number>();
|
||||
const engineXps = new Map<number, number>();
|
||||
const trackXps = new Map<number, number>();
|
||||
|
||||
tank.turrets.forEach((turret) => {
|
||||
if (
|
||||
turret.research_cost !== undefined &&
|
||||
typeof turret.research_cost.research_cost_type!.value === "number"
|
||||
) {
|
||||
turretXps.set(
|
||||
turret.id,
|
||||
turret.research_cost.research_cost_type!.value,
|
||||
);
|
||||
}
|
||||
|
||||
turret.guns.forEach((gun) => {
|
||||
if (
|
||||
gun.research_cost !== undefined &&
|
||||
typeof gun.research_cost.research_cost_type!.value === "number"
|
||||
) {
|
||||
gunXps.set(gun.id, gun.research_cost.research_cost_type!.value);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
tank.engines.forEach((engine) => {
|
||||
if (
|
||||
engine.research_cost !== undefined &&
|
||||
typeof engine.research_cost.research_cost_type!.value === "number"
|
||||
) {
|
||||
engineXps.set(
|
||||
engine.id,
|
||||
engine.research_cost.research_cost_type!.value,
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
tank.tracks.forEach((track) => {
|
||||
if (
|
||||
track.research_cost !== undefined &&
|
||||
typeof track.research_cost.research_cost_type!.value === "number"
|
||||
) {
|
||||
trackXps.set(
|
||||
track.id,
|
||||
track.research_cost.research_cost_type!.value,
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
let moduleXp = 0;
|
||||
turretXps.forEach((value) => {
|
||||
moduleXp += value;
|
||||
});
|
||||
gunXps.forEach((value) => {
|
||||
moduleXp += value;
|
||||
});
|
||||
engineXps.forEach((value) => {
|
||||
moduleXp += value;
|
||||
});
|
||||
trackXps.forEach((value) => {
|
||||
moduleXp += value;
|
||||
});
|
||||
|
||||
return {
|
||||
research: tank.research_cost!.research_cost_type!.value as number,
|
||||
upgrades: moduleXp,
|
||||
purchase: tank.price!.value,
|
||||
equipment: equipmentPriceMatrix[tank.tier].reduce(
|
||||
(a, b) => a + 3 * b,
|
||||
0,
|
||||
),
|
||||
};
|
||||
}),
|
||||
);
|
||||
|
||||
const image = (
|
||||
<CommandWrapper>
|
||||
<TitleBar
|
||||
title={nickname}
|
||||
image={clanImage}
|
||||
description={`${strings.bot.commands.research.body.subtitle} • ${
|
||||
targetTank.name
|
||||
}`}
|
||||
/>
|
||||
|
||||
<div
|
||||
style={{
|
||||
display: "flex",
|
||||
flexDirection: "column",
|
||||
gap: 8,
|
||||
}}
|
||||
>
|
||||
<div
|
||||
style={{
|
||||
display: "flex",
|
||||
borderRadius: 4,
|
||||
backgroundColor: theme.colors.appBackground2,
|
||||
border: theme.borderStyles.subtle,
|
||||
}}
|
||||
>
|
||||
<div style={{ width: 48 }}></div>
|
||||
|
||||
<div
|
||||
style={{
|
||||
flex: 1,
|
||||
display: "flex",
|
||||
alignItems: "center",
|
||||
justifyContent: "center",
|
||||
position: "relative",
|
||||
right: 24,
|
||||
}}
|
||||
>
|
||||
<span
|
||||
style={{
|
||||
color: theme.colors.textHighContrast,
|
||||
}}
|
||||
>
|
||||
{strings.bot.commands.research.body.total}
|
||||
</span>
|
||||
</div>
|
||||
|
||||
<div
|
||||
style={{
|
||||
flex: 1,
|
||||
display: "flex",
|
||||
flexDirection: "column",
|
||||
justifyContent: "center",
|
||||
gap: 8,
|
||||
padding: "16px 0",
|
||||
}}
|
||||
>
|
||||
<div
|
||||
style={{
|
||||
display: "flex",
|
||||
gap: 4,
|
||||
alignItems: "center",
|
||||
}}
|
||||
>
|
||||
<img
|
||||
alt="XP icon"
|
||||
src={await iconPng(asset("icons/currencies/xp.webp"))}
|
||||
width={16}
|
||||
height={16}
|
||||
/>
|
||||
<span
|
||||
style={{
|
||||
fontSize: 16,
|
||||
color: theme.colors.textHighContrast,
|
||||
}}
|
||||
>
|
||||
Experience:{" "}
|
||||
{costs
|
||||
.reduce((a, b) => a + (b.research ?? 0) + b.upgrades, 0)
|
||||
.toLocaleString(interaction.locale)}
|
||||
</span>
|
||||
</div>
|
||||
|
||||
<div
|
||||
style={{
|
||||
display: "flex",
|
||||
gap: 4,
|
||||
alignItems: "center",
|
||||
}}
|
||||
>
|
||||
<img
|
||||
alt="Silver icon"
|
||||
src={await iconPng(asset("icons/currencies/silver.webp"))}
|
||||
width={16}
|
||||
height={16}
|
||||
/>
|
||||
<span
|
||||
style={{
|
||||
fontSize: 16,
|
||||
color: theme.colors.textHighContrast,
|
||||
}}
|
||||
>
|
||||
Purchase:{" "}
|
||||
{costs
|
||||
.reduce((a, b) => a + b.purchase, 0)
|
||||
.toLocaleString(interaction.locale)}
|
||||
</span>
|
||||
</div>
|
||||
|
||||
<div
|
||||
style={{
|
||||
display: "flex",
|
||||
gap: 4,
|
||||
alignItems: "center",
|
||||
}}
|
||||
>
|
||||
<img
|
||||
alt="Silver icon"
|
||||
src={await iconPng(asset("icons/currencies/silver.webp"))}
|
||||
width={16}
|
||||
height={16}
|
||||
/>
|
||||
<span
|
||||
style={{
|
||||
fontSize: 16,
|
||||
color: theme.colors.textHighContrast,
|
||||
}}
|
||||
>
|
||||
Equipment:{" "}
|
||||
{costs
|
||||
.reduce((a, b) => a + b.equipment, 0)
|
||||
.toLocaleString(interaction.locale)}
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{await Promise.all(
|
||||
line.map(async (id, index) => {
|
||||
const tank = awaitedTankDefinitions.tanks[id];
|
||||
|
||||
return (
|
||||
<div
|
||||
key={id}
|
||||
style={{
|
||||
display: "flex",
|
||||
borderRadius: 4,
|
||||
backgroundColor: theme.colors.appBackground2,
|
||||
border: theme.borderStyles.subtle,
|
||||
}}
|
||||
>
|
||||
<div
|
||||
style={{
|
||||
width: 48,
|
||||
display: "flex",
|
||||
alignItems: "center",
|
||||
justifyContent: "center",
|
||||
}}
|
||||
>
|
||||
<span
|
||||
style={{
|
||||
color: theme.colors.textLowContrast,
|
||||
fontSize: 16,
|
||||
}}
|
||||
>
|
||||
{TIER_ROMAN_NUMERALS[tank.tier]}
|
||||
</span>
|
||||
</div>
|
||||
|
||||
<div
|
||||
style={{
|
||||
flex: 1,
|
||||
display: "flex",
|
||||
position: "relative",
|
||||
right: "5%",
|
||||
}}
|
||||
>
|
||||
<img
|
||||
alt="Tank icon"
|
||||
src={await tankIconPng(id)}
|
||||
style={{
|
||||
height: 100,
|
||||
width: 100,
|
||||
objectFit: "contain",
|
||||
position: "absolute",
|
||||
left: "25%",
|
||||
top: 0,
|
||||
}}
|
||||
/>
|
||||
|
||||
<div
|
||||
style={{
|
||||
display: "flex",
|
||||
gap: 4,
|
||||
alignItems: "center",
|
||||
justifyContent: "center",
|
||||
position: "absolute",
|
||||
bottom: 8,
|
||||
left: "50%",
|
||||
transform: "translateX(-50%)",
|
||||
}}
|
||||
>
|
||||
<img
|
||||
alt={unwrap(tank.name!)}
|
||||
src={TANK_ICONS[tank.class]}
|
||||
width={16}
|
||||
height={16}
|
||||
/>
|
||||
|
||||
<span
|
||||
style={{
|
||||
color: theme.colors.textHighContrast,
|
||||
}}
|
||||
>
|
||||
{unwrap(tank.name!)}
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div
|
||||
style={{
|
||||
flex: 1,
|
||||
display: "flex",
|
||||
flexDirection: "column",
|
||||
justifyContent: "center",
|
||||
gap: 8,
|
||||
padding: "16px 0",
|
||||
}}
|
||||
>
|
||||
<div
|
||||
style={{
|
||||
display: "flex",
|
||||
gap: 4,
|
||||
alignItems: "center",
|
||||
}}
|
||||
>
|
||||
<img
|
||||
alt="XP icon"
|
||||
src={await iconPng(asset("icons/currencies/xp.webp"))}
|
||||
width={16}
|
||||
height={16}
|
||||
/>
|
||||
<span
|
||||
style={{
|
||||
fontSize: 16,
|
||||
color: theme.colors.textHighContrast,
|
||||
}}
|
||||
>
|
||||
{literals(
|
||||
strings.bot.commands.research.body.research,
|
||||
{
|
||||
cost: costs[index].research?.toLocaleString(
|
||||
interaction.locale,
|
||||
),
|
||||
},
|
||||
)}
|
||||
</span>
|
||||
</div>
|
||||
|
||||
{costs[index].upgrades > 0 && (
|
||||
<div
|
||||
style={{
|
||||
display: "flex",
|
||||
gap: 4,
|
||||
alignItems: "center",
|
||||
}}
|
||||
>
|
||||
<img
|
||||
alt="Free XP icon"
|
||||
src={await iconPng(
|
||||
asset("icons/currencies/free-xp.webp"),
|
||||
)}
|
||||
width={16}
|
||||
height={16}
|
||||
/>
|
||||
<span
|
||||
style={{
|
||||
fontSize: 16,
|
||||
color: theme.colors.textHighContrast,
|
||||
}}
|
||||
>
|
||||
{literals(
|
||||
strings.bot.commands.research.body.upgrades,
|
||||
{ cost: costs[index].upgrades.toLocaleString() },
|
||||
)}
|
||||
</span>
|
||||
</div>
|
||||
)}
|
||||
|
||||
<div
|
||||
style={{
|
||||
display: "flex",
|
||||
gap: 4,
|
||||
alignItems: "center",
|
||||
}}
|
||||
>
|
||||
<img
|
||||
alt="Silver icon"
|
||||
src={await iconPng(
|
||||
asset("icons/currencies/silver.webp"),
|
||||
)}
|
||||
width={16}
|
||||
height={16}
|
||||
/>
|
||||
<span
|
||||
style={{
|
||||
fontSize: 16,
|
||||
color: theme.colors.textHighContrast,
|
||||
}}
|
||||
>
|
||||
{literals(
|
||||
strings.bot.commands.research.body.purchase,
|
||||
{
|
||||
cost: costs[index].purchase.toLocaleString(
|
||||
interaction.locale,
|
||||
),
|
||||
},
|
||||
)}
|
||||
</span>
|
||||
</div>
|
||||
|
||||
<div
|
||||
style={{
|
||||
display: "flex",
|
||||
gap: 4,
|
||||
alignItems: "center",
|
||||
}}
|
||||
>
|
||||
<img
|
||||
alt="Silver icon"
|
||||
src={await iconPng(
|
||||
asset("icons/currencies/silver.webp"),
|
||||
)}
|
||||
width={16}
|
||||
height={16}
|
||||
/>
|
||||
<span
|
||||
style={{
|
||||
fontSize: 16,
|
||||
color: theme.colors.textHighContrast,
|
||||
}}
|
||||
>
|
||||
{literals(
|
||||
strings.bot.commands.research.body.equipment,
|
||||
{
|
||||
cost: costs[index].equipment.toLocaleString(
|
||||
interaction.locale,
|
||||
),
|
||||
},
|
||||
)}
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}),
|
||||
)}
|
||||
</div>
|
||||
</CommandWrapper>
|
||||
);
|
||||
|
||||
return startingTankRaw
|
||||
? image
|
||||
: [strings.bot.commands.research.body.estimation, image];
|
||||
},
|
||||
|
||||
autocomplete(interaction) {
|
||||
autocompleteTanks(interaction, true, ["target-tank", "starting-tank"]);
|
||||
},
|
||||
});
|
||||
});
|
||||
@@ -1,74 +0,0 @@
|
||||
import { type ClanList, fetchBlitz, type Region } from "@blitzkit/core";
|
||||
import { literals } from "@blitzkit/i18n";
|
||||
import { Locale } from "discord.js";
|
||||
import markdownEscape from "markdown-escape";
|
||||
import { addClanChoices } from "../core/discord/addClanChoices";
|
||||
import { addRegionChoices } from "../core/discord/addRegionChoices";
|
||||
import { createLocalizedCommand } from "../core/discord/createLocalizedCommand";
|
||||
import { embedInfo } from "../core/discord/embedInfo";
|
||||
import { localizationObject } from "../core/discord/localizationObject";
|
||||
import { translator } from "../core/localization/translator";
|
||||
import type { CommandRegistry } from "../events/interactionCreate";
|
||||
|
||||
const DEFAULT_LIMIT = 25;
|
||||
|
||||
export const searchClansCommand = new Promise<CommandRegistry>((resolve) => {
|
||||
resolve({
|
||||
command: createLocalizedCommand("search-clans")
|
||||
.addStringOption(addRegionChoices)
|
||||
.addStringOption((option) =>
|
||||
addClanChoices(option).setAutocomplete(false)
|
||||
)
|
||||
.addIntegerOption((option) => {
|
||||
const { strings } = translator(Locale.EnglishUS);
|
||||
|
||||
return option
|
||||
.setName(strings.bot.commands.search_clans.options.limit.name)
|
||||
.setNameLocalizations(
|
||||
localizationObject(
|
||||
(strings) => strings.bot.commands.search_clans.options.limit.name,
|
||||
undefined,
|
||||
true
|
||||
)
|
||||
)
|
||||
.setDescription(
|
||||
literals(
|
||||
strings.bot.commands.search_clans.options.limit.description,
|
||||
{ limit: DEFAULT_LIMIT }
|
||||
)
|
||||
)
|
||||
.setDescriptionLocalizations(
|
||||
localizationObject(
|
||||
(strings) =>
|
||||
strings.bot.commands.search_clans.options.limit.description,
|
||||
{ limit: DEFAULT_LIMIT }
|
||||
)
|
||||
)
|
||||
.setMinValue(1)
|
||||
.setMaxValue(100);
|
||||
}),
|
||||
|
||||
async handler(interaction) {
|
||||
const { strings } = translator(interaction.locale);
|
||||
const region = interaction.options.getString("region") as Region;
|
||||
const clan = interaction.options.getString("clan")!;
|
||||
const limit = interaction.options.getInteger("limit") ?? DEFAULT_LIMIT;
|
||||
const clanList = await fetchBlitz<ClanList>(region, "clans/list", {
|
||||
search: clan,
|
||||
limit,
|
||||
});
|
||||
|
||||
return embedInfo(
|
||||
literals(strings.bot.commands.search_clans.body.title, {
|
||||
search: markdownEscape(clan),
|
||||
region: strings.common.regions.normal[region],
|
||||
}),
|
||||
clanList.length === 0
|
||||
? strings.bot.commands.search_clans.body.no_results
|
||||
: `\`\`\`\n${clanList
|
||||
.map((clan) => `${clan.name} [${clan.tag}]`)
|
||||
.join("\n")}\n\`\`\``
|
||||
);
|
||||
},
|
||||
});
|
||||
});
|
||||
@@ -1,83 +0,0 @@
|
||||
import {
|
||||
type AccountList,
|
||||
fetchBlitz,
|
||||
type Region,
|
||||
usernamePattern,
|
||||
} from "@blitzkit/core";
|
||||
import { literals } from "@blitzkit/i18n";
|
||||
import { Locale } from "discord.js";
|
||||
import markdownEscape from "markdown-escape";
|
||||
import { addRegionChoices } from "../core/discord/addRegionChoices";
|
||||
import { addUsernameChoices } from "../core/discord/addUsernameChoices";
|
||||
import { createLocalizedCommand } from "../core/discord/createLocalizedCommand";
|
||||
import { embedInfo } from "../core/discord/embedInfo";
|
||||
import { localizationObject } from "../core/discord/localizationObject";
|
||||
import { translator } from "../core/localization/translator";
|
||||
import type { CommandRegistry } from "../events/interactionCreate";
|
||||
|
||||
const DEFAULT_LIMIT = 25;
|
||||
|
||||
export const searchPlayersCommand = new Promise<CommandRegistry>((resolve) => {
|
||||
const { strings } = translator(Locale.EnglishUS);
|
||||
|
||||
resolve({
|
||||
command: createLocalizedCommand("search-players")
|
||||
.addStringOption(addRegionChoices)
|
||||
.addStringOption((option) =>
|
||||
addUsernameChoices(option).setAutocomplete(false).setRequired(true)
|
||||
)
|
||||
.addIntegerOption((option) =>
|
||||
option
|
||||
.setName(strings.bot.commands.search_players.options.limit.name)
|
||||
.setNameLocalizations(
|
||||
localizationObject(
|
||||
(strings) =>
|
||||
strings.bot.commands.search_players.options.limit.name,
|
||||
undefined,
|
||||
true
|
||||
)
|
||||
)
|
||||
.setDescription(
|
||||
literals(
|
||||
strings.bot.commands.search_players.options.limit.description,
|
||||
{ limit: DEFAULT_LIMIT }
|
||||
)
|
||||
)
|
||||
.setDescriptionLocalizations(
|
||||
localizationObject(
|
||||
(strings) =>
|
||||
strings.bot.commands.search_players.options.limit.description,
|
||||
{ limit: DEFAULT_LIMIT }
|
||||
)
|
||||
)
|
||||
.setMinValue(1)
|
||||
.setMaxValue(100)
|
||||
),
|
||||
|
||||
async handler(interaction) {
|
||||
const { strings } = translator(interaction.locale);
|
||||
const region = interaction.options.getString("region") as Region;
|
||||
const name = interaction.options.getString("username")!;
|
||||
const limit = interaction.options.getInteger("limit") ?? 25;
|
||||
const trimmedSearch = name.trim();
|
||||
const players = usernamePattern.test(trimmedSearch)
|
||||
? await fetchBlitz<AccountList>(region, "account/list", {
|
||||
search: trimmedSearch,
|
||||
limit,
|
||||
})
|
||||
: [];
|
||||
|
||||
return embedInfo(
|
||||
literals(strings.bot.commands.search_players.body.title, {
|
||||
search: markdownEscape(trimmedSearch),
|
||||
region: strings.common.regions.normal[region],
|
||||
}),
|
||||
`\`\`\`${
|
||||
players.length === 0
|
||||
? strings.bot.commands.search_players.body.no_results
|
||||
: players.map((player) => player.nickname).join("\n")
|
||||
}\`\`\``
|
||||
);
|
||||
},
|
||||
});
|
||||
});
|
||||
@@ -1,102 +0,0 @@
|
||||
import { emblemURL, getAccountInfo, getClanAccountInfo } from "@blitzkit/core";
|
||||
import { Locale } from "discord.js";
|
||||
import { AllStatsOverview } from "../components/AllStatsOverview";
|
||||
import { CommandWrapper } from "../components/CommandWrapper";
|
||||
import { NoData } from "../components/NoData";
|
||||
import { TitleBar } from "../components/TitleBar";
|
||||
import { filtersToDescription } from "../core/blitzkit/filtersToDescription";
|
||||
import { filterStats, type StatFilters } from "../core/blitzstars/filterStats";
|
||||
import { getStatsInPeriod } from "../core/blitzstars/getStatsInPeriod";
|
||||
import { addPeriodicFilterOptions } from "../core/discord/addPeriodicFilterOptions";
|
||||
import { addUsernameChoices } from "../core/discord/addUsernameChoices";
|
||||
import { autocompleteTanks } from "../core/discord/autocompleteTanks";
|
||||
import { autocompleteUsername } from "../core/discord/autocompleteUsername";
|
||||
import { createLocalizedCommand } from "../core/discord/createLocalizedCommand";
|
||||
import { getFiltersFromButton } from "../core/discord/getFiltersFromButton";
|
||||
import { resolvePeriodFromButton } from "../core/discord/resolvePeriodFromButton";
|
||||
import { type ResolvedPeriod } from "../core/discord/resolvePeriodFromCommand";
|
||||
import { resolvePlayerFromButton } from "../core/discord/resolvePlayerFromButton";
|
||||
import { type ResolvedPlayer } from "../core/discord/resolvePlayerFromCommand";
|
||||
import { translator } from "../core/localization/translator";
|
||||
import type { CommandRegistry } from "../events/interactionCreate";
|
||||
|
||||
async function render(
|
||||
{ region, id }: ResolvedPlayer,
|
||||
{ start, end, name }: ResolvedPeriod,
|
||||
filters: StatFilters,
|
||||
locale: Locale,
|
||||
) {
|
||||
const { nickname } = await getAccountInfo(region, id);
|
||||
const clan = (await getClanAccountInfo(region, id, ["clan"]))?.clan;
|
||||
const clanImage = clan ? emblemURL(clan.emblem_set_id) : undefined;
|
||||
const diffedTankStats = await getStatsInPeriod(
|
||||
region,
|
||||
id,
|
||||
start,
|
||||
end,
|
||||
locale,
|
||||
);
|
||||
const { stats, supplementary } = await filterStats(diffedTankStats, filters);
|
||||
const filterDescriptions = await filtersToDescription(filters, locale);
|
||||
|
||||
return (
|
||||
<CommandWrapper>
|
||||
<TitleBar
|
||||
title={nickname}
|
||||
image={clanImage}
|
||||
description={`${name} • ${filterDescriptions}`}
|
||||
/>
|
||||
|
||||
{!stats.battles && <NoData type="battles_in_period" locale={locale} />}
|
||||
{stats.battles > 0 && (
|
||||
<AllStatsOverview
|
||||
locale={locale}
|
||||
stats={stats}
|
||||
supplementaryStats={supplementary}
|
||||
/>
|
||||
)}
|
||||
</CommandWrapper>
|
||||
);
|
||||
}
|
||||
|
||||
export const statsCommand = new Promise<CommandRegistry>(async (resolve) => {
|
||||
resolve({
|
||||
command: await addPeriodicFilterOptions(
|
||||
createLocalizedCommand("stats"),
|
||||
(option) => option.addStringOption(addUsernameChoices),
|
||||
),
|
||||
|
||||
async handler(interaction) {
|
||||
const { strings } = translator(interaction.locale);
|
||||
return strings.bot.commands.dead;
|
||||
|
||||
// const player = await resolvePlayerFromCommand(interaction);
|
||||
// const period = resolvePeriodFromCommand(player.region, interaction);
|
||||
// const filters = await getFiltersFromCommand(interaction);
|
||||
// const path = commandToURL(interaction, {
|
||||
// ...player,
|
||||
// ...getCustomPeriodParams(interaction),
|
||||
// ...filters,
|
||||
// });
|
||||
|
||||
// return Promise.all([
|
||||
// render(player, period, filters, interaction.locale),
|
||||
// buttonRefresh(interaction, path),
|
||||
// getBlitzStarsLinkButton(player.region, player.id),
|
||||
// ]);
|
||||
},
|
||||
|
||||
autocomplete: (interaction) => {
|
||||
autocompleteUsername(interaction);
|
||||
autocompleteTanks(interaction);
|
||||
},
|
||||
|
||||
async button(interaction) {
|
||||
const player = await resolvePlayerFromButton(interaction);
|
||||
const period = resolvePeriodFromButton(player.region, interaction);
|
||||
const filters = getFiltersFromButton(interaction);
|
||||
|
||||
return await render(player, period, filters, interaction.locale);
|
||||
},
|
||||
});
|
||||
});
|
||||
@@ -1,60 +0,0 @@
|
||||
import { gameDefinitions } from "../core/blitzkit/nonBlockingPromises";
|
||||
import { addFilterOptions } from "../core/discord/addFilterOptions";
|
||||
import { addUsernameChoices } from "../core/discord/addUsernameChoices";
|
||||
import { autocompleteTanks } from "../core/discord/autocompleteTanks";
|
||||
import { autocompleteUsername } from "../core/discord/autocompleteUsername";
|
||||
import { createLocalizedCommand } from "../core/discord/createLocalizedCommand";
|
||||
import { getFiltersFromButton } from "../core/discord/getFiltersFromButton";
|
||||
import { resolvePeriodFromButton } from "../core/discord/resolvePeriodFromButton";
|
||||
import { resolvePlayerFromButton } from "../core/discord/resolvePlayerFromButton";
|
||||
import { translator } from "../core/localization/translator";
|
||||
import { type CommandRegistry } from "../events/interactionCreate";
|
||||
import { renderBreakdown } from "./breakdown/render";
|
||||
|
||||
export const todayCommand = new Promise<CommandRegistry>(async (resolve) => {
|
||||
const awaitedGameDefinitions = await gameDefinitions;
|
||||
|
||||
resolve({
|
||||
command: addFilterOptions(
|
||||
createLocalizedCommand("today"),
|
||||
awaitedGameDefinitions.nations,
|
||||
).addStringOption(addUsernameChoices),
|
||||
|
||||
async handler(interaction) {
|
||||
const { strings } = translator(interaction.locale);
|
||||
return strings.bot.commands.dead;
|
||||
|
||||
// const player = await resolvePlayerFromCommand(interaction);
|
||||
// const period = resolvePeriodFromCommand(
|
||||
// player.region,
|
||||
// interaction,
|
||||
// 'today',
|
||||
// );
|
||||
// const filters = await getFiltersFromCommand(interaction);
|
||||
// const path = commandToURL(interaction, {
|
||||
// ...player,
|
||||
// ...getCustomPeriodParams(interaction, true),
|
||||
// ...filters,
|
||||
// });
|
||||
|
||||
// return [
|
||||
// ...(await renderBreakdown(player, period, filters, interaction.locale)),
|
||||
// buttonRefresh(interaction, path),
|
||||
// await getBlitzStarsLinkButton(player.region, player.id),
|
||||
// ];
|
||||
},
|
||||
|
||||
autocomplete: (interaction) => {
|
||||
autocompleteUsername(interaction);
|
||||
autocompleteTanks(interaction);
|
||||
},
|
||||
|
||||
async button(interaction) {
|
||||
const player = await resolvePlayerFromButton(interaction);
|
||||
const period = resolvePeriodFromButton(player.region, interaction);
|
||||
const filters = getFiltersFromButton(interaction);
|
||||
|
||||
return await renderBreakdown(player, period, filters, interaction.locale);
|
||||
},
|
||||
});
|
||||
});
|
||||
@@ -1,50 +0,0 @@
|
||||
import { type ComponentProps } from "react";
|
||||
|
||||
export interface GlowProps extends ComponentProps<"div"> {
|
||||
color: string;
|
||||
direction?: "default" | "reverse";
|
||||
rotation?: number;
|
||||
startOpacity?: number;
|
||||
endOpacity?: number;
|
||||
}
|
||||
|
||||
const width = 16;
|
||||
|
||||
export function Glow({
|
||||
color,
|
||||
direction = "default",
|
||||
rotation = 0,
|
||||
style,
|
||||
startOpacity = 0,
|
||||
endOpacity = 1,
|
||||
...props
|
||||
}: GlowProps) {
|
||||
const color1 = `${color}${Math.round(endOpacity * 255)
|
||||
.toString(16)
|
||||
.padStart(2, "0")}`;
|
||||
const color2 = `${color}${Math.round(startOpacity * 255)
|
||||
.toString(16)
|
||||
.padStart(2, "0")}`;
|
||||
const background = `linear-gradient(${
|
||||
direction === "default" ? 0 : 180
|
||||
}deg, ${color1} 0%, ${color2} 100%)`;
|
||||
|
||||
return (
|
||||
<div
|
||||
style={{
|
||||
display: "flex",
|
||||
alignItems: direction === "default" ? "flex-end" : "flex-start",
|
||||
justifyContent: "center",
|
||||
transform: `rotate(${rotation}deg)`,
|
||||
...style,
|
||||
}}
|
||||
{...props}
|
||||
>
|
||||
<div style={{ height: 54, width, background }} />
|
||||
<div style={{ height: 72, width, background }} />
|
||||
<div style={{ height: 80, width, background }} />
|
||||
<div style={{ height: 72, width, background }} />
|
||||
<div style={{ height: 54, width, background }} />
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@@ -1,72 +0,0 @@
|
||||
import { theme } from '../../../../stitches.config';
|
||||
import { Glow } from './components/Glow';
|
||||
|
||||
export interface WN8DisplayProps {
|
||||
subtitle: string;
|
||||
color: string;
|
||||
value: string | number;
|
||||
}
|
||||
|
||||
export function HeroStat({ color, subtitle, value }: WN8DisplayProps) {
|
||||
return (
|
||||
<div
|
||||
style={{
|
||||
width: 128 * 2, // idk why twice the width turns into the correct width
|
||||
display: 'flex',
|
||||
flexDirection: 'column',
|
||||
alignItems: 'center',
|
||||
justifyContent: 'center',
|
||||
}}
|
||||
>
|
||||
<Glow color={color} style={{ marginBottom: -16 }} />
|
||||
|
||||
<div
|
||||
style={{
|
||||
width: 128,
|
||||
height: 80,
|
||||
backgroundColor: color,
|
||||
borderRadius: 40,
|
||||
display: 'flex',
|
||||
flexDirection: 'column',
|
||||
alignItems: 'center',
|
||||
justifyContent: 'center',
|
||||
}}
|
||||
>
|
||||
<div
|
||||
style={{
|
||||
display: 'flex',
|
||||
flexDirection: 'column',
|
||||
alignItems: 'center',
|
||||
justifyContent: 'center',
|
||||
gap: 2,
|
||||
}}
|
||||
>
|
||||
<span
|
||||
style={{
|
||||
display: 'block',
|
||||
fontWeight: 900,
|
||||
fontSize: 32,
|
||||
color: theme.colors.textHighContrast,
|
||||
lineHeight: '26px',
|
||||
letterSpacing: '-0.03em',
|
||||
}}
|
||||
>
|
||||
{value}
|
||||
</span>
|
||||
<span
|
||||
style={{
|
||||
display: 'block',
|
||||
fontSize: 16,
|
||||
lineHeight: '16px',
|
||||
color: theme.colors.textHighContrast,
|
||||
}}
|
||||
>
|
||||
{subtitle}
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<Glow color={color} direction="reverse" style={{ marginTop: -16 }} />
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@@ -1,47 +0,0 @@
|
||||
import { theme } from '../../../stitches.config';
|
||||
|
||||
export enum WN8SurroundingStatAlign {
|
||||
Left,
|
||||
Right,
|
||||
}
|
||||
|
||||
export interface WN8SurroundingStatProps {
|
||||
label: string;
|
||||
value: string | number;
|
||||
align?: WN8SurroundingStatAlign;
|
||||
padded?: boolean;
|
||||
}
|
||||
|
||||
export function WN8SurroundingStat({
|
||||
label,
|
||||
value,
|
||||
align = WN8SurroundingStatAlign.Left,
|
||||
padded = false,
|
||||
}: WN8SurroundingStatProps) {
|
||||
return (
|
||||
<div
|
||||
style={{
|
||||
display: 'flex',
|
||||
flexDirection: 'column',
|
||||
alignItems:
|
||||
align === WN8SurroundingStatAlign.Left ? 'flex-start' : 'flex-end',
|
||||
paddingLeft: padded && align === WN8SurroundingStatAlign.Left ? 32 : 0,
|
||||
paddingRight:
|
||||
padded && align === WN8SurroundingStatAlign.Right ? 32 : 0,
|
||||
}}
|
||||
>
|
||||
<span
|
||||
style={{
|
||||
color: theme.colors.textHighContrast,
|
||||
fontSize: 24,
|
||||
fontWeight: 700,
|
||||
}}
|
||||
>
|
||||
{value}
|
||||
</span>
|
||||
<span style={{ color: theme.colors.textLowContrast, fontSize: 16 }}>
|
||||
{label}
|
||||
</span>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@@ -1,130 +0,0 @@
|
||||
import {
|
||||
getWN8Percentile,
|
||||
Percentile,
|
||||
type SupplementaryStats,
|
||||
} from '@blitzkit/core';
|
||||
import { Locale } from 'discord.js';
|
||||
import { translator } from '../../core/localization/translator';
|
||||
import { PERCENTILE_COLORS } from '../PercentileIndicator/constants';
|
||||
import { HeroStat } from './components/HeroStat';
|
||||
import {
|
||||
WN8SurroundingStat,
|
||||
WN8SurroundingStatAlign,
|
||||
} from './components/WN8SurroundingStat';
|
||||
|
||||
export interface AllStatsOverviewProps {
|
||||
stats: {
|
||||
battles: number;
|
||||
wins: number;
|
||||
damage_dealt: number;
|
||||
damage_received: number;
|
||||
survived_battles: number;
|
||||
hits: number;
|
||||
shots: number;
|
||||
frags: number;
|
||||
};
|
||||
supplementaryStats: SupplementaryStats;
|
||||
locale: Locale;
|
||||
}
|
||||
|
||||
export function AllStatsOverview({
|
||||
stats,
|
||||
locale,
|
||||
supplementaryStats,
|
||||
}: AllStatsOverviewProps) {
|
||||
const { strings } = translator(locale);
|
||||
const percentile =
|
||||
typeof supplementaryStats.WN8 === 'number'
|
||||
? getWN8Percentile(supplementaryStats.WN8)
|
||||
: Percentile.VeryBad;
|
||||
const color = PERCENTILE_COLORS[percentile];
|
||||
|
||||
const heroStat =
|
||||
typeof supplementaryStats.WN8 === 'number'
|
||||
? supplementaryStats.WN8.toFixed(0)
|
||||
: '--';
|
||||
|
||||
return (
|
||||
<div
|
||||
style={{
|
||||
display: 'flex',
|
||||
alignItems: 'center',
|
||||
gap: -64,
|
||||
width: '100%',
|
||||
}}
|
||||
>
|
||||
<div
|
||||
style={{
|
||||
display: 'flex',
|
||||
flexDirection: 'column',
|
||||
gap: 8,
|
||||
alignItems: 'flex-end',
|
||||
flex: 1,
|
||||
}}
|
||||
>
|
||||
<WN8SurroundingStat
|
||||
label={strings.bot.common.hero_stats.battles}
|
||||
value={stats.battles.toLocaleString()}
|
||||
align={WN8SurroundingStatAlign.Right}
|
||||
/>
|
||||
<WN8SurroundingStat
|
||||
label={strings.bot.common.hero_stats.winrate}
|
||||
value={`${(100 * (stats.wins / stats.battles)).toFixed(2)}%`}
|
||||
align={WN8SurroundingStatAlign.Right}
|
||||
padded
|
||||
/>
|
||||
<WN8SurroundingStat
|
||||
label={strings.bot.common.hero_stats.damage}
|
||||
value={Math.round(
|
||||
stats.damage_dealt / stats.battles,
|
||||
).toLocaleString()}
|
||||
align={WN8SurroundingStatAlign.Right}
|
||||
padded
|
||||
/>
|
||||
<WN8SurroundingStat
|
||||
label={strings.bot.common.hero_stats.damage_ratio}
|
||||
value={(stats.damage_dealt / stats.damage_received).toFixed(2)}
|
||||
align={WN8SurroundingStatAlign.Right}
|
||||
/>
|
||||
</div>
|
||||
|
||||
<HeroStat
|
||||
value={heroStat}
|
||||
subtitle={strings.common.wn8_percentile[percentile]}
|
||||
color={color}
|
||||
/>
|
||||
|
||||
<div
|
||||
style={{
|
||||
display: 'flex',
|
||||
flexDirection: 'column',
|
||||
gap: 8,
|
||||
flex: 1,
|
||||
}}
|
||||
>
|
||||
<WN8SurroundingStat
|
||||
label={strings.bot.common.hero_stats.tier}
|
||||
value={
|
||||
supplementaryStats.tier ? supplementaryStats.tier.toFixed(2) : '--'
|
||||
}
|
||||
/>
|
||||
<WN8SurroundingStat
|
||||
label={strings.bot.common.hero_stats.survival}
|
||||
value={`${(100 * (stats.survived_battles / stats.battles)).toFixed(
|
||||
2,
|
||||
)}%`}
|
||||
padded
|
||||
/>
|
||||
<WN8SurroundingStat
|
||||
label={strings.bot.common.hero_stats.accuracy}
|
||||
value={`${(100 * (stats.hits / stats.shots)).toFixed(2)}%`}
|
||||
padded
|
||||
/>
|
||||
<WN8SurroundingStat
|
||||
label={strings.bot.common.hero_stats.kills}
|
||||
value={(stats.frags / stats.battles).toFixed(2)}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@@ -1,16 +0,0 @@
|
||||
import { type ReactNode } from "react";
|
||||
|
||||
interface RootProps {
|
||||
children: ReactNode;
|
||||
}
|
||||
|
||||
export function Root({ children }: RootProps) {
|
||||
return (
|
||||
<div
|
||||
className="session-tracker-root"
|
||||
style={{ display: "flex", flexDirection: "column", gap: 8 }}
|
||||
>
|
||||
{children}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@@ -1,126 +0,0 @@
|
||||
import {
|
||||
Percentile,
|
||||
TankClass,
|
||||
TankType,
|
||||
TREE_TYPE_ICONS,
|
||||
} from "@blitzkit/core";
|
||||
import { createColors } from "bepaint";
|
||||
import {
|
||||
type AccentColor,
|
||||
type GrayColor,
|
||||
PALETTES,
|
||||
} from "../../../core/radix/radixColors";
|
||||
import { RowStat } from "./RowStat";
|
||||
|
||||
export interface RowStatItem {
|
||||
title: string;
|
||||
current?: number | string;
|
||||
career?: number | string;
|
||||
delta?: number;
|
||||
percentile?: Percentile;
|
||||
}
|
||||
|
||||
interface RowProps {
|
||||
displayType?: "tank" | "summary";
|
||||
naked?: boolean;
|
||||
title: string;
|
||||
minimized?: boolean;
|
||||
type?: TankType;
|
||||
class?: TankClass;
|
||||
color?: AccentColor | GrayColor;
|
||||
stats: (RowStatItem | undefined)[];
|
||||
}
|
||||
|
||||
export function Row({
|
||||
color = "slate",
|
||||
stats,
|
||||
title,
|
||||
minimized,
|
||||
class: tankClass,
|
||||
type,
|
||||
naked = false,
|
||||
displayType,
|
||||
}: RowProps) {
|
||||
const palette = PALETTES[`${color}Dark`];
|
||||
const theme = createColors(palette);
|
||||
|
||||
return (
|
||||
<div
|
||||
className="session-tracker-row"
|
||||
style={{
|
||||
maxWidth: naked ? 600 : Infinity,
|
||||
display: "flex",
|
||||
flexDirection: "column",
|
||||
borderRadius: 4,
|
||||
backgroundColor: naked
|
||||
? `${theme.appBackground2}c0`
|
||||
: theme.appBackground2,
|
||||
overflow: "hidden",
|
||||
}}
|
||||
>
|
||||
<div
|
||||
style={{
|
||||
display: "flex",
|
||||
alignItems: "center",
|
||||
justifyContent: "center",
|
||||
padding: 8,
|
||||
gap: 4,
|
||||
backgroundColor: naked
|
||||
? `${theme.componentInteractive}c0`
|
||||
: theme.componentInteractive,
|
||||
}}
|
||||
>
|
||||
{displayType === "tank" && tankClass !== undefined && (
|
||||
<img
|
||||
alt={TankClass[tankClass]}
|
||||
src={
|
||||
TREE_TYPE_ICONS[type ?? TankType.TANK_TYPE_RESEARCHABLE][
|
||||
tankClass
|
||||
]
|
||||
}
|
||||
style={{ width: 16, height: 16 }}
|
||||
/>
|
||||
)}
|
||||
|
||||
<span
|
||||
style={{
|
||||
color:
|
||||
displayType === "tank"
|
||||
? type === TankType.TANK_TYPE_COLLECTOR
|
||||
? theme.textLowContrast_blue
|
||||
: type === TankType.TANK_TYPE_PREMIUM
|
||||
? theme.textLowContrast_amber
|
||||
: theme.textHighContrast
|
||||
: theme.textLowContrast,
|
||||
fontWeight: 900,
|
||||
fontSize: 16,
|
||||
}}
|
||||
>
|
||||
{title}
|
||||
</span>
|
||||
</div>
|
||||
|
||||
<div
|
||||
style={{
|
||||
display: "flex",
|
||||
paddingTop: 8,
|
||||
paddingBottom: 8,
|
||||
}}
|
||||
>
|
||||
{stats.map(
|
||||
(row, index) =>
|
||||
row && (
|
||||
<RowStat
|
||||
minimized={minimized}
|
||||
key={index}
|
||||
name={`${row.title} • ${row.career ?? "--"}`}
|
||||
value={row.current ?? "--"}
|
||||
delta={row.delta}
|
||||
percentile={row.percentile}
|
||||
/>
|
||||
),
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@@ -1,89 +0,0 @@
|
||||
import { Percentile } from "@blitzkit/core";
|
||||
import { createColors } from "bepaint";
|
||||
import {
|
||||
type AccentColor,
|
||||
type GrayColor,
|
||||
PALETTES,
|
||||
} from "../../../core/radix/radixColors";
|
||||
import { PercentileIndicator } from "../../PercentileIndicator";
|
||||
|
||||
interface RowStatProps {
|
||||
name: string;
|
||||
value?: string | number;
|
||||
delta?: number;
|
||||
percentile?: Percentile;
|
||||
minimized?: boolean;
|
||||
color?: AccentColor | GrayColor;
|
||||
}
|
||||
|
||||
export function RowStat({
|
||||
name,
|
||||
value,
|
||||
delta,
|
||||
percentile,
|
||||
minimized = false,
|
||||
color = "slate",
|
||||
}: RowStatProps) {
|
||||
const theme = createColors(PALETTES[`${color}Dark`]);
|
||||
|
||||
return (
|
||||
<div
|
||||
className="session-tracker-row-stat"
|
||||
style={{
|
||||
display: "flex",
|
||||
flexDirection: "column",
|
||||
gap: 4,
|
||||
alignItems: "center",
|
||||
justifyContent: "center",
|
||||
flex: 1,
|
||||
}}
|
||||
>
|
||||
<div
|
||||
style={{
|
||||
display: "flex",
|
||||
gap: 4,
|
||||
alignItems: "center",
|
||||
justifyContent: "center",
|
||||
}}
|
||||
>
|
||||
{percentile === undefined && delta !== undefined && delta !== 0 && (
|
||||
<img
|
||||
alt={delta > 0 ? "Increase" : "Decrease"}
|
||||
src={
|
||||
(delta ?? 0) > 0
|
||||
? "https://i.imgur.com/qbjiXa1.png"
|
||||
: "https://i.imgur.com/3uyNhun.png"
|
||||
}
|
||||
style={{ width: 12, height: 12 }}
|
||||
/>
|
||||
)}
|
||||
{percentile !== undefined && (
|
||||
<PercentileIndicator percentile={percentile} />
|
||||
)}
|
||||
|
||||
<span
|
||||
style={{
|
||||
color: theme.textHighContrast,
|
||||
fontWeight: 700,
|
||||
fontSize: 16,
|
||||
textAlign: "center",
|
||||
}}
|
||||
>
|
||||
{value}
|
||||
</span>
|
||||
</div>
|
||||
|
||||
{!minimized && (
|
||||
<span
|
||||
style={{
|
||||
color: theme.textLowContrast,
|
||||
textAlign: "center",
|
||||
fontSize: 12,
|
||||
}}
|
||||
>
|
||||
{name}
|
||||
</span>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@@ -1,3 +0,0 @@
|
||||
export * from './components/Root';
|
||||
export * from './components/Row';
|
||||
export * from './components/RowStat';
|
||||
@@ -1,26 +0,0 @@
|
||||
import { type ReactNode } from "react";
|
||||
import { theme } from "../stitches.config";
|
||||
|
||||
interface CommandWrapperProps {
|
||||
children: ReactNode;
|
||||
fat?: boolean;
|
||||
}
|
||||
|
||||
export function CommandWrapper({ children, fat }: CommandWrapperProps) {
|
||||
return (
|
||||
<div
|
||||
style={{
|
||||
display: "flex",
|
||||
flexDirection: "column",
|
||||
padding: `16px ${fat ? 0 : 16}px`,
|
||||
gap: 16,
|
||||
width: "100%",
|
||||
color: theme.colors.textHighContrast,
|
||||
backgroundColor: theme.colors.appBackground1,
|
||||
position: "relative",
|
||||
}}
|
||||
>
|
||||
{children}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@@ -1,21 +0,0 @@
|
||||
interface DeltaCaretProps {
|
||||
delta: number;
|
||||
}
|
||||
|
||||
export function DeltaCaret({ delta }: DeltaCaretProps) {
|
||||
return (
|
||||
<img
|
||||
alt={delta > 0 ? 'Increase' : 'Decrease'}
|
||||
style={{
|
||||
width: 16,
|
||||
height: 16,
|
||||
objectFit: 'contain',
|
||||
}}
|
||||
src={
|
||||
delta > 0
|
||||
? 'https://i.imgur.com/gjI4a5f.png'
|
||||
: 'https://i.imgur.com/lLGZygN.png'
|
||||
}
|
||||
/>
|
||||
);
|
||||
}
|
||||
@@ -1,19 +0,0 @@
|
||||
import { asset } from '@blitzkit/core';
|
||||
|
||||
interface FlagProps {
|
||||
nation: string;
|
||||
}
|
||||
|
||||
export function Flag({ nation }: FlagProps) {
|
||||
return (
|
||||
<div
|
||||
style={{
|
||||
width: 22,
|
||||
height: 22,
|
||||
overflow: 'hidden',
|
||||
}}
|
||||
>
|
||||
<img alt={nation} src={asset(`flags/circle/${nation}.webp`)} />
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@@ -1,95 +0,0 @@
|
||||
import { Percentile } from '@blitzkit/core';
|
||||
import { theme } from '../../../stitches.config';
|
||||
import { PercentileIndicator } from '../../PercentileIndicator';
|
||||
|
||||
interface CardItem {
|
||||
label: string;
|
||||
value: string | number | undefined;
|
||||
percentile?: Percentile;
|
||||
}
|
||||
|
||||
interface CardProps {
|
||||
items: CardItem[];
|
||||
title: string;
|
||||
}
|
||||
|
||||
export function Card({ items, title }: CardProps) {
|
||||
return (
|
||||
<div
|
||||
style={{
|
||||
display: 'flex',
|
||||
flexDirection: 'column',
|
||||
gap: 16,
|
||||
flex: 1,
|
||||
borderRadius: 4,
|
||||
backgroundColor: theme.colors.componentInteractive,
|
||||
padding: 8,
|
||||
}}
|
||||
>
|
||||
<span
|
||||
style={{
|
||||
color: theme.colors.textHighContrast,
|
||||
fontSize: 24,
|
||||
}}
|
||||
>
|
||||
{title}
|
||||
</span>
|
||||
|
||||
<div
|
||||
style={{
|
||||
display: 'flex',
|
||||
flexDirection: 'column',
|
||||
gap: 8,
|
||||
}}
|
||||
>
|
||||
{items.map((item) => (
|
||||
<div
|
||||
key={item.label}
|
||||
style={{
|
||||
display: 'flex',
|
||||
gap: 8,
|
||||
alignItems: 'center',
|
||||
justifyContent: 'center',
|
||||
}}
|
||||
>
|
||||
<span style={{ fontSize: 16, color: theme.colors.textLowContrast }}>
|
||||
{item.label}
|
||||
</span>
|
||||
|
||||
<div
|
||||
style={{
|
||||
flex: 1,
|
||||
height: 1,
|
||||
borderRadius: 0.5,
|
||||
backgroundColor: theme.colors.borderNonInteractive,
|
||||
}}
|
||||
/>
|
||||
|
||||
<div
|
||||
style={{
|
||||
display: 'flex',
|
||||
gap: 4,
|
||||
alignItems: 'center',
|
||||
justifyContent: 'center',
|
||||
}}
|
||||
>
|
||||
{item.percentile !== undefined && (
|
||||
<PercentileIndicator percentile={item.percentile} />
|
||||
)}
|
||||
<span
|
||||
style={{
|
||||
fontSize: 16,
|
||||
color: theme.colors.textHighContrast,
|
||||
}}
|
||||
>
|
||||
{item.value === undefined || Number.isNaN(item.value)
|
||||
? '--'
|
||||
: item.value}
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@@ -1,17 +0,0 @@
|
||||
interface RootProps {
|
||||
children: React.ReactNode;
|
||||
}
|
||||
|
||||
export function Root({ children }: RootProps) {
|
||||
return (
|
||||
<div
|
||||
style={{
|
||||
display: 'flex',
|
||||
flexDirection: 'column',
|
||||
gap: 8,
|
||||
}}
|
||||
>
|
||||
{children}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@@ -1,7 +0,0 @@
|
||||
interface RowProps {
|
||||
children: React.ReactNode;
|
||||
}
|
||||
|
||||
export function Row({ children }: RowProps) {
|
||||
return <div style={{ display: 'flex', gap: 8 }}>{children}</div>;
|
||||
}
|
||||
@@ -1,149 +0,0 @@
|
||||
import {
|
||||
type BlitzStats,
|
||||
getWN8Percentile,
|
||||
isNumber,
|
||||
type SupplementaryStats,
|
||||
} from '@blitzkit/core';
|
||||
import { Locale } from 'discord.js';
|
||||
import { translator } from '../../core/localization/translator';
|
||||
import { Card } from './components/Card';
|
||||
import { Root } from './components/Root';
|
||||
import { Row } from './components/Row';
|
||||
|
||||
interface GenericAllStatsProps {
|
||||
stats: BlitzStats;
|
||||
supplementaryStats?: SupplementaryStats;
|
||||
locale: Locale;
|
||||
}
|
||||
|
||||
export function GenericAllStats({
|
||||
stats,
|
||||
supplementaryStats,
|
||||
locale,
|
||||
}: GenericAllStatsProps) {
|
||||
const { strings } = translator(locale);
|
||||
const damageRatio = stats.damage_dealt / stats.damage_received;
|
||||
const killsToDeathRatio =
|
||||
stats.frags / (stats.battles - stats.survived_battles);
|
||||
|
||||
return (
|
||||
<Root>
|
||||
<Row>
|
||||
<Card
|
||||
title={strings.bot.commands.full_stats.body.cards.games.title}
|
||||
items={[
|
||||
{
|
||||
label: strings.bot.commands.full_stats.body.cards.games.winrate,
|
||||
value: `${(100 * (stats.wins / stats.battles)).toFixed(2)}%`,
|
||||
},
|
||||
{
|
||||
label: strings.bot.commands.full_stats.body.cards.games.battles,
|
||||
value: stats.battles,
|
||||
},
|
||||
{
|
||||
label:
|
||||
strings.bot.commands.full_stats.body.cards.games.wins_losses,
|
||||
value: `${stats.wins} / ${stats.losses}`,
|
||||
},
|
||||
]}
|
||||
/>
|
||||
<Card
|
||||
title={strings.bot.commands.full_stats.body.cards.efficiency.title}
|
||||
items={[
|
||||
{
|
||||
label: strings.bot.commands.full_stats.body.cards.efficiency.wn8,
|
||||
value:
|
||||
supplementaryStats && isNumber(supplementaryStats.WN8)
|
||||
? supplementaryStats.WN8!.toFixed(0)
|
||||
: undefined,
|
||||
percentile: isNumber(supplementaryStats?.WN8)
|
||||
? getWN8Percentile(supplementaryStats!.WN8!)
|
||||
: undefined,
|
||||
},
|
||||
{
|
||||
label:
|
||||
strings.bot.commands.full_stats.body.cards.efficiency.survival,
|
||||
value: `${(
|
||||
100 *
|
||||
(stats.survived_battles / stats.battles)
|
||||
).toFixed(2)}%`,
|
||||
},
|
||||
{
|
||||
label:
|
||||
strings.bot.commands.full_stats.body.cards.efficiency.accuracy,
|
||||
value: `${((stats.hits / stats.shots) * 100).toFixed(2)}%`,
|
||||
},
|
||||
]}
|
||||
/>
|
||||
</Row>
|
||||
<Row>
|
||||
<Card
|
||||
title={strings.bot.commands.full_stats.body.cards.lethality.title}
|
||||
items={[
|
||||
{
|
||||
label:
|
||||
strings.bot.commands.full_stats.body.cards.lethality
|
||||
.average_damage,
|
||||
value: (stats.damage_dealt / stats.battles).toFixed(0),
|
||||
},
|
||||
{
|
||||
label:
|
||||
strings.bot.commands.full_stats.body.cards.lethality
|
||||
.damage_per_tier,
|
||||
value: supplementaryStats?.tier
|
||||
? (
|
||||
stats.damage_dealt /
|
||||
stats.battles /
|
||||
supplementaryStats.tier
|
||||
).toFixed(0)
|
||||
: undefined,
|
||||
},
|
||||
{
|
||||
label:
|
||||
strings.bot.commands.full_stats.body.cards.lethality
|
||||
.damage_ratio,
|
||||
value: isFinite(damageRatio) ? damageRatio.toFixed(2) : undefined,
|
||||
},
|
||||
{
|
||||
label:
|
||||
strings.bot.commands.full_stats.body.cards.lethality
|
||||
.average_kills,
|
||||
value: (stats.frags / stats.battles).toFixed(0),
|
||||
},
|
||||
]}
|
||||
/>
|
||||
<Card
|
||||
title={strings.bot.commands.full_stats.body.cards.miscellaneous.title}
|
||||
items={[
|
||||
{
|
||||
label:
|
||||
strings.bot.commands.full_stats.body.cards.miscellaneous
|
||||
.average_tier,
|
||||
value: supplementaryStats?.tier?.toFixed(2),
|
||||
},
|
||||
{
|
||||
label:
|
||||
strings.bot.commands.full_stats.body.cards.miscellaneous
|
||||
.average_spots,
|
||||
value: (stats.spotted / stats.battles).toFixed(2),
|
||||
},
|
||||
{
|
||||
label:
|
||||
strings.bot.commands.full_stats.body.cards.miscellaneous
|
||||
.average_xp,
|
||||
value: (stats.xp / stats.battles).toFixed(0),
|
||||
},
|
||||
{
|
||||
label:
|
||||
strings.bot.commands.full_stats.body.cards.miscellaneous
|
||||
.kills_to_death_ratio,
|
||||
value: isFinite(killsToDeathRatio)
|
||||
? killsToDeathRatio.toFixed(2)
|
||||
: undefined,
|
||||
},
|
||||
]}
|
||||
/>
|
||||
</Row>
|
||||
</Root>
|
||||
);
|
||||
}
|
||||
@@ -1,16 +0,0 @@
|
||||
import { type GenericStat } from "..";
|
||||
import { GenericStatsRow } from "./GenericStatsRow";
|
||||
|
||||
interface GenericStatsColumnProps {
|
||||
stats: GenericStat[];
|
||||
}
|
||||
|
||||
export function GenericStatsColumn({ stats }: GenericStatsColumnProps) {
|
||||
return (
|
||||
<div style={{ flex: 1, display: "flex", flexDirection: "column", gap: 8 }}>
|
||||
{stats.map((stat) => (
|
||||
<GenericStatsRow key={stat[0]} stat={stat} />
|
||||
))}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@@ -1,46 +0,0 @@
|
||||
import { type GenericStat } from "..";
|
||||
import { theme } from "../../../stitches.config";
|
||||
import { PercentileIndicator } from "../../PercentileIndicator";
|
||||
|
||||
interface GenericStatsRowProps {
|
||||
stat: GenericStat;
|
||||
}
|
||||
|
||||
export function GenericStatsRow({ stat }: GenericStatsRowProps) {
|
||||
return (
|
||||
<div
|
||||
style={{
|
||||
display: "flex",
|
||||
justifyContent: "space-between",
|
||||
alignItems: "center",
|
||||
}}
|
||||
>
|
||||
<span
|
||||
style={{
|
||||
color: theme.colors.textLowContrast,
|
||||
fontSize: 16,
|
||||
whiteSpace: "nowrap",
|
||||
maxWidth: 128,
|
||||
overflow: "hidden",
|
||||
}}
|
||||
>
|
||||
{stat[0]}
|
||||
</span>
|
||||
|
||||
<span
|
||||
style={{
|
||||
color: theme.colors.textHighContrast,
|
||||
fontWeight: 700,
|
||||
fontSize: 16,
|
||||
display: "flex",
|
||||
alignItems: "center",
|
||||
justifyContent: "center",
|
||||
gap: 4,
|
||||
}}
|
||||
>
|
||||
{stat[2] !== undefined && <PercentileIndicator percentile={stat[2]} />}
|
||||
{stat[1]}
|
||||
</span>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@@ -1,34 +0,0 @@
|
||||
import { Percentile } from '@blitzkit/core';
|
||||
import { GenericStatsColumn } from './components/GenericStatsColumn';
|
||||
|
||||
export type GenericStat =
|
||||
| [string, string | number | undefined]
|
||||
| [string, string | number | undefined, Percentile | undefined];
|
||||
|
||||
export interface GenericStatsProps {
|
||||
stats: GenericStat[];
|
||||
columnCount?: number;
|
||||
}
|
||||
|
||||
export function GenericStats({ stats, columnCount = 2 }: GenericStatsProps) {
|
||||
const filteredStats = stats.filter(([, value]) => value !== undefined);
|
||||
const itemsPerRow = Math.ceil(filteredStats.length / columnCount);
|
||||
const columns: GenericStat[][] = [];
|
||||
|
||||
filteredStats.forEach((stat, index) => {
|
||||
const column = Math.floor(index / itemsPerRow);
|
||||
if (!columns[column]) columns[column] = [];
|
||||
columns[column].push(stat);
|
||||
});
|
||||
|
||||
return (
|
||||
<div style={{ display: 'flex', gap: 32 }}>
|
||||
{columns.map((stats) => (
|
||||
<GenericStatsColumn
|
||||
key={stats.map((stat) => stat[0]).join('-')}
|
||||
stats={stats}
|
||||
/>
|
||||
))}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@@ -1,11 +0,0 @@
|
||||
export enum LineColor {
|
||||
Red,
|
||||
Green,
|
||||
Blue,
|
||||
White,
|
||||
}
|
||||
export enum LineStyle {
|
||||
Solid,
|
||||
Dashes,
|
||||
DashesAndDots,
|
||||
}
|
||||
@@ -1,65 +0,0 @@
|
||||
import { blue, green, red, slateDark } from '@radix-ui/colors';
|
||||
import { GRAPH_HEIGHT, GRAPH_WIDTH } from '../Root/constants';
|
||||
import { LineColor, LineStyle } from './constants';
|
||||
|
||||
const LINE_COLORS = {
|
||||
[LineColor.Red]: red.red9,
|
||||
[LineColor.Green]: green.green9,
|
||||
[LineColor.Blue]: blue.blue9,
|
||||
[LineColor.White]: slateDark.slate11,
|
||||
};
|
||||
|
||||
const LINE_STYLES = {
|
||||
[LineStyle.Solid]: undefined,
|
||||
[LineStyle.Dashes]: '8, 8',
|
||||
[LineStyle.DashesAndDots]: '1, 4, 8, 4',
|
||||
};
|
||||
|
||||
export type PlotItem = [number, number];
|
||||
type Plot = PlotItem[];
|
||||
|
||||
interface LineProps {
|
||||
plot: Plot;
|
||||
minY?: number;
|
||||
maxY?: number;
|
||||
color?: LineColor;
|
||||
style?: LineStyle;
|
||||
lineWidth?: number;
|
||||
}
|
||||
|
||||
export function Line({
|
||||
plot,
|
||||
minY: providedMinY,
|
||||
maxY: providedMaxY,
|
||||
color = LineColor.Red,
|
||||
style = LineStyle.Solid,
|
||||
lineWidth = 2,
|
||||
}: LineProps) {
|
||||
const xs = plot.map(([x]) => x);
|
||||
const minX = Math.min(...xs);
|
||||
const maxX = Math.max(...xs);
|
||||
const ys = plot.map(([, y]) => y);
|
||||
const minY = providedMinY ?? Math.min(...ys);
|
||||
const maxY = providedMaxY ?? Math.max(...ys);
|
||||
const rangeX = maxX - minX;
|
||||
const rangeY = maxY - minY;
|
||||
const points = plot
|
||||
.map(
|
||||
([x, y]) =>
|
||||
`${(x - minX) * (GRAPH_WIDTH / rangeX)},${
|
||||
GRAPH_HEIGHT - (y - minY) * (GRAPH_HEIGHT / rangeY)
|
||||
}`,
|
||||
)
|
||||
.join(' ');
|
||||
|
||||
return (
|
||||
<polyline
|
||||
vector-effect="non-scaling-stroke"
|
||||
fill="none"
|
||||
stroke={LINE_COLORS[color]}
|
||||
strokeWidth={lineWidth}
|
||||
stroke-dasharray={LINE_STYLES[style]}
|
||||
points={points}
|
||||
/>
|
||||
);
|
||||
}
|
||||
@@ -1,4 +0,0 @@
|
||||
export enum MarginOrientation {
|
||||
Vertical,
|
||||
Horizontal,
|
||||
}
|
||||
@@ -1,49 +0,0 @@
|
||||
import { times } from 'lodash-es';
|
||||
import { theme } from '../../../../stitches.config';
|
||||
import { type MarginInputProps } from '../Root';
|
||||
import { MarginOrientation } from './constants';
|
||||
|
||||
interface MarginProps extends MarginInputProps {
|
||||
verticalSeparations: number;
|
||||
orientation?: MarginOrientation;
|
||||
}
|
||||
|
||||
export function Margin({
|
||||
verticalSeparations,
|
||||
max,
|
||||
min,
|
||||
suffix,
|
||||
precision = 0,
|
||||
orientation = MarginOrientation.Vertical,
|
||||
}: MarginProps) {
|
||||
const isVertical = orientation === MarginOrientation.Vertical;
|
||||
|
||||
return (
|
||||
<div
|
||||
style={{
|
||||
paddingLeft: isVertical ? 0 : 64,
|
||||
width: isVertical ? 48 : '100%',
|
||||
display: 'flex',
|
||||
flexDirection: isVertical ? 'column' : 'row-reverse',
|
||||
justifyContent: 'space-between',
|
||||
}}
|
||||
>
|
||||
{times(verticalSeparations, (index) => (
|
||||
<span
|
||||
key={index}
|
||||
style={{
|
||||
fontSize: 16,
|
||||
color: theme.colors.textHighContrast,
|
||||
}}
|
||||
>
|
||||
{`${(
|
||||
(max - min) *
|
||||
((verticalSeparations - (index + 1)) /
|
||||
(verticalSeparations - 1)) +
|
||||
min
|
||||
).toFixed(precision)}${suffix ?? ''}`}
|
||||
</span>
|
||||
))}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@@ -1,2 +0,0 @@
|
||||
export const GRAPH_WIDTH = 384;
|
||||
export const GRAPH_HEIGHT = 320;
|
||||
@@ -1,109 +0,0 @@
|
||||
import { times } from "lodash-es";
|
||||
import { type ReactNode } from "react";
|
||||
import { theme } from "../../../../stitches.config";
|
||||
import { Margin } from "../Margin";
|
||||
import { MarginOrientation } from "../Margin/constants";
|
||||
import { GRAPH_HEIGHT, GRAPH_WIDTH } from "./constants";
|
||||
|
||||
export interface MarginInputProps {
|
||||
min: number;
|
||||
max: number;
|
||||
suffix?: string;
|
||||
precision?: number;
|
||||
}
|
||||
|
||||
interface RootProps {
|
||||
children: ReactNode;
|
||||
verticalMargin?: MarginInputProps;
|
||||
horizontalMargin?: MarginInputProps;
|
||||
separations?: number;
|
||||
xMinLabel: string;
|
||||
xMaxLabel: string;
|
||||
xTitle?: string;
|
||||
}
|
||||
|
||||
export function Root({
|
||||
children,
|
||||
verticalMargin,
|
||||
horizontalMargin,
|
||||
separations = 5,
|
||||
xMinLabel,
|
||||
xMaxLabel,
|
||||
xTitle,
|
||||
}: RootProps) {
|
||||
return (
|
||||
<div style={{ display: "flex", flexDirection: "column", gap: 16 }}>
|
||||
<div
|
||||
style={{
|
||||
paddingLeft: 64,
|
||||
display: "flex",
|
||||
justifyContent: "space-between",
|
||||
}}
|
||||
>
|
||||
<span style={{ fontSize: 16, color: theme.colors.textHighContrast }}>
|
||||
{xMinLabel}
|
||||
</span>
|
||||
<span style={{ fontSize: 16, color: theme.colors.textHighContrast }}>
|
||||
{xMaxLabel}
|
||||
</span>
|
||||
</div>
|
||||
|
||||
<div style={{ display: "flex", gap: 16 }}>
|
||||
{verticalMargin && (
|
||||
<Margin {...verticalMargin} verticalSeparations={separations} />
|
||||
)}
|
||||
|
||||
<svg
|
||||
viewBox={`0 0 ${GRAPH_WIDTH} ${GRAPH_HEIGHT}`}
|
||||
preserveAspectRatio="none"
|
||||
style={{
|
||||
flex: 1,
|
||||
backgroundColor: theme.colors.appBackground2,
|
||||
borderRadius: 4,
|
||||
border: theme.borderStyles.nonInteractive,
|
||||
}}
|
||||
>
|
||||
{times(separations - 2, (index) => {
|
||||
const y = GRAPH_HEIGHT * ((index + 1) / (separations - 1));
|
||||
|
||||
return (
|
||||
<polyline
|
||||
key={index}
|
||||
vector-effect="non-scaling-stroke"
|
||||
fill="none"
|
||||
stroke={theme.colors.borderNonInteractive}
|
||||
strokeWidth="2"
|
||||
points={`0,${y}, ${GRAPH_WIDTH},${y}`}
|
||||
/>
|
||||
);
|
||||
})}
|
||||
|
||||
{children}
|
||||
</svg>
|
||||
</div>
|
||||
|
||||
{horizontalMargin && (
|
||||
<Margin
|
||||
{...horizontalMargin}
|
||||
verticalSeparations={separations}
|
||||
orientation={MarginOrientation.Horizontal}
|
||||
/>
|
||||
)}
|
||||
|
||||
{xTitle !== undefined && (
|
||||
<div
|
||||
style={{
|
||||
paddingLeft: 64,
|
||||
display: "flex",
|
||||
alignItems: "center",
|
||||
justifyContent: "center",
|
||||
}}
|
||||
>
|
||||
<span style={{ fontSize: 16, color: theme.colors.textLowContrast }}>
|
||||
{xTitle}
|
||||
</span>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@@ -1,3 +0,0 @@
|
||||
export * from './components/Line';
|
||||
export * from './components/Margin';
|
||||
export * from './components/Root';
|
||||
@@ -1,29 +0,0 @@
|
||||
import { theme } from '../../../stitches.config';
|
||||
|
||||
interface GapProps {
|
||||
message: string;
|
||||
}
|
||||
|
||||
export function Gap({ message: number }: GapProps) {
|
||||
return (
|
||||
<div
|
||||
style={{
|
||||
display: 'flex',
|
||||
padding: 8,
|
||||
backgroundColor: theme.colors.componentNonInteractive,
|
||||
borderRadius: 4,
|
||||
alignItems: 'center',
|
||||
justifyContent: 'center',
|
||||
}}
|
||||
>
|
||||
<span
|
||||
style={{
|
||||
color: theme.colors.textLowContrast,
|
||||
fontSize: 16,
|
||||
}}
|
||||
>
|
||||
{number.toLocaleString()}
|
||||
</span>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@@ -1,171 +0,0 @@
|
||||
import { type ComponentProps } from "react";
|
||||
import { theme } from "../../../stitches.config";
|
||||
|
||||
interface ItemProps extends ComponentProps<"div"> {
|
||||
position: number;
|
||||
deltaPosition?: number;
|
||||
score?: number;
|
||||
deltaScore?: number;
|
||||
nickname: string;
|
||||
clan?: string;
|
||||
highlight?: boolean;
|
||||
}
|
||||
|
||||
export function Item({
|
||||
position,
|
||||
deltaPosition,
|
||||
score,
|
||||
deltaScore,
|
||||
nickname,
|
||||
clan,
|
||||
highlight,
|
||||
...props
|
||||
}: ItemProps) {
|
||||
return (
|
||||
<div
|
||||
{...props}
|
||||
style={{
|
||||
cursor: "pointer",
|
||||
display: "flex",
|
||||
padding: 8,
|
||||
backgroundColor: highlight
|
||||
? theme.colors.componentInteractive_blue
|
||||
: theme.colors.componentInteractive,
|
||||
borderRadius: 4,
|
||||
alignItems: "center",
|
||||
justifyContent: "center",
|
||||
gap: 8,
|
||||
}}
|
||||
>
|
||||
<span
|
||||
style={{
|
||||
color: highlight
|
||||
? theme.colors.textLowContrast_blue
|
||||
: theme.colors.textLowContrast,
|
||||
fontSize: 16,
|
||||
}}
|
||||
>
|
||||
{position.toLocaleString()}.
|
||||
</span>
|
||||
|
||||
<div
|
||||
style={{
|
||||
display: "flex",
|
||||
alignItems: "center",
|
||||
justifyContent: "center",
|
||||
gap: 4,
|
||||
}}
|
||||
>
|
||||
<span
|
||||
style={{
|
||||
color: highlight
|
||||
? theme.colors.textHighContrast_blue
|
||||
: theme.colors.textHighContrast,
|
||||
fontSize: 16,
|
||||
}}
|
||||
>
|
||||
{nickname}
|
||||
</span>
|
||||
{clan && (
|
||||
<span
|
||||
style={{
|
||||
color: highlight
|
||||
? theme.colors.textLowContrast_blue
|
||||
: theme.colors.textLowContrast,
|
||||
fontSize: 16,
|
||||
}}
|
||||
>
|
||||
[{clan}]
|
||||
</span>
|
||||
)}
|
||||
</div>
|
||||
|
||||
{deltaPosition !== undefined && deltaPosition !== 0 && (
|
||||
<div
|
||||
style={{
|
||||
display: "flex",
|
||||
alignItems: "center",
|
||||
justifyContent: "center",
|
||||
gap: 4,
|
||||
}}
|
||||
>
|
||||
<img
|
||||
alt={deltaPosition > 0 ? "Increase" : "Decrease"}
|
||||
style={{
|
||||
width: 8,
|
||||
height: 8,
|
||||
}}
|
||||
src={
|
||||
deltaPosition > 0
|
||||
? "https://i.imgur.com/qbjiXa1.png"
|
||||
: "https://i.imgur.com/3uyNhun.png"
|
||||
}
|
||||
/>
|
||||
<span
|
||||
style={{
|
||||
color: highlight
|
||||
? theme.colors.textLowContrast_blue
|
||||
: theme.colors.textLowContrast,
|
||||
fontSize: 16,
|
||||
}}
|
||||
>
|
||||
{Math.abs(deltaPosition).toLocaleString()}
|
||||
</span>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{/* TODO: lol remove this spacer div for a better solution */}
|
||||
<div style={{ flex: 1 }} />
|
||||
|
||||
<div
|
||||
style={{
|
||||
display: "flex",
|
||||
gap: 4,
|
||||
alignItems: "center",
|
||||
width: 96,
|
||||
justifyContent: "flex-end",
|
||||
}}
|
||||
>
|
||||
{deltaScore !== 0 && deltaScore !== undefined && (
|
||||
<span
|
||||
style={{
|
||||
color: highlight
|
||||
? theme.colors.textLowContrast_blue
|
||||
: theme.colors.textLowContrast,
|
||||
fontSize: 16,
|
||||
}}
|
||||
>
|
||||
{Math.abs(deltaScore).toLocaleString()}
|
||||
</span>
|
||||
)}
|
||||
{deltaScore !== 0 && deltaScore !== undefined && (
|
||||
<img
|
||||
alt={deltaScore > 0 ? "Increase" : "Decrease"}
|
||||
style={{
|
||||
width: 8,
|
||||
height: 8,
|
||||
}}
|
||||
src={
|
||||
deltaScore > 0
|
||||
? "https://i.imgur.com/qbjiXa1.png"
|
||||
: "https://i.imgur.com/3uyNhun.png"
|
||||
}
|
||||
/>
|
||||
)}
|
||||
|
||||
{score !== undefined && (
|
||||
<span
|
||||
style={{
|
||||
color: highlight
|
||||
? theme.colors.textHighContrast_blue
|
||||
: theme.colors.textHighContrast,
|
||||
fontSize: 16,
|
||||
}}
|
||||
>
|
||||
{score.toLocaleString()}
|
||||
</span>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@@ -1,13 +0,0 @@
|
||||
import { type ReactNode } from 'react';
|
||||
|
||||
interface RootProps {
|
||||
children: ReactNode;
|
||||
}
|
||||
|
||||
export function Root({ children }: RootProps) {
|
||||
return (
|
||||
<div style={{ display: 'flex', flexDirection: 'column', gap: 8 }}>
|
||||
{children}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@@ -1,3 +0,0 @@
|
||||
export * from './components/Gap';
|
||||
export * from './components/Item';
|
||||
export * from './components/Root';
|
||||
@@ -1,5 +0,0 @@
|
||||
export enum NoDataType {
|
||||
BattlesInPeriod,
|
||||
PlayersInPeriod,
|
||||
TanksFound,
|
||||
}
|
||||
@@ -1,30 +0,0 @@
|
||||
import { Locale } from 'discord.js';
|
||||
import { translator } from '../../core/localization/translator';
|
||||
import { theme } from '../../stitches.config';
|
||||
|
||||
interface NoDataProps {
|
||||
type:
|
||||
| 'battles_in_period'
|
||||
| 'players_in_period'
|
||||
| 'tanks_found'
|
||||
| 'battles_in_season';
|
||||
locale: Locale;
|
||||
}
|
||||
|
||||
export function NoData({ type, locale }: NoDataProps) {
|
||||
const { strings } = translator(locale);
|
||||
|
||||
return (
|
||||
<div
|
||||
style={{
|
||||
display: 'flex',
|
||||
alignItems: 'center',
|
||||
justifyContent: 'center',
|
||||
}}
|
||||
>
|
||||
<span style={{ fontSize: 16, color: theme.colors.textLowContrast }}>
|
||||
{strings.bot.common.no_data[type]}
|
||||
</span>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@@ -1,26 +0,0 @@
|
||||
import { Percentile } from '@blitzkit/core';
|
||||
import {
|
||||
amber,
|
||||
blue,
|
||||
green,
|
||||
lime,
|
||||
orange,
|
||||
pink,
|
||||
purple,
|
||||
red,
|
||||
slate,
|
||||
teal,
|
||||
} from '@radix-ui/colors';
|
||||
|
||||
export const PERCENTILE_COLORS = {
|
||||
[Percentile.VeryBad]: slate.slate9,
|
||||
[Percentile.Bad]: red.red9,
|
||||
[Percentile.BelowAverage]: orange.orange9,
|
||||
[Percentile.Average]: amber.amber10,
|
||||
[Percentile.AboveAverage]: lime.lime8,
|
||||
[Percentile.Good]: green.green9,
|
||||
[Percentile.VeryGood]: teal.teal9,
|
||||
[Percentile.Great]: blue.blue9,
|
||||
[Percentile.Unicum]: pink.pink9,
|
||||
[Percentile.SuperUnicum]: purple.purple9,
|
||||
};
|
||||
@@ -1,19 +0,0 @@
|
||||
import { Percentile } from '@blitzkit/core';
|
||||
import { PERCENTILE_COLORS } from './constants';
|
||||
|
||||
interface PercentileIndicatorProps {
|
||||
percentile: Percentile;
|
||||
}
|
||||
|
||||
export function PercentileIndicator({ percentile }: PercentileIndicatorProps) {
|
||||
return (
|
||||
<div
|
||||
style={{
|
||||
width: 8,
|
||||
height: 8,
|
||||
borderRadius: 4,
|
||||
backgroundColor: PERCENTILE_COLORS[percentile],
|
||||
}}
|
||||
/>
|
||||
);
|
||||
}
|
||||
@@ -1,20 +0,0 @@
|
||||
import { type ReactNode } from 'react';
|
||||
|
||||
interface ColumnProps {
|
||||
children: ReactNode;
|
||||
}
|
||||
|
||||
export function Column({ children }: ColumnProps) {
|
||||
return (
|
||||
<div
|
||||
style={{
|
||||
display: 'flex',
|
||||
flexDirection: 'column',
|
||||
gap: 8,
|
||||
flex: 1,
|
||||
}}
|
||||
>
|
||||
{children}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@@ -1,75 +0,0 @@
|
||||
import { TankClass, TankType, TREE_TYPE_ICONS } from "@blitzkit/core";
|
||||
import { theme } from "../../../../stitches.config";
|
||||
|
||||
export interface ItemProps {
|
||||
tankClass?: TankClass;
|
||||
name: string;
|
||||
tankType: TankType;
|
||||
}
|
||||
|
||||
const TREE_TYPE_COLOR = {
|
||||
[TankType.TANK_TYPE_RESEARCHABLE]: "",
|
||||
[TankType.TANK_TYPE_PREMIUM]: "_amber",
|
||||
[TankType.TANK_TYPE_COLLECTOR]: "_blue",
|
||||
} as const;
|
||||
|
||||
export function Item({
|
||||
tankClass: tankType,
|
||||
name,
|
||||
tankType: treeType,
|
||||
}: ItemProps) {
|
||||
return (
|
||||
<div
|
||||
style={{
|
||||
display: "flex",
|
||||
height: 32,
|
||||
paddingLeft: 8,
|
||||
paddingRight: 8,
|
||||
overflow: "hidden",
|
||||
alignItems: "center",
|
||||
borderRadius: 4,
|
||||
backgroundColor:
|
||||
theme.colors[`componentInteractive${TREE_TYPE_COLOR[treeType]}`],
|
||||
}}
|
||||
>
|
||||
<div
|
||||
style={{
|
||||
display: "flex",
|
||||
gap: 4,
|
||||
flex: 1,
|
||||
alignItems: "center",
|
||||
justifyContent: "flex-start",
|
||||
overflow: "hidden",
|
||||
}}
|
||||
>
|
||||
{tankType && (
|
||||
<img
|
||||
alt={TankType[tankType]}
|
||||
src={TREE_TYPE_ICONS[treeType][tankType]}
|
||||
style={{ width: 14, height: 14 }}
|
||||
/>
|
||||
)}
|
||||
<span
|
||||
style={{
|
||||
fontSize: 16,
|
||||
whiteSpace: "nowrap",
|
||||
color: theme.colors[`textLowContrast${TREE_TYPE_COLOR[treeType]}`],
|
||||
}}
|
||||
>
|
||||
{name}
|
||||
</span>
|
||||
</div>
|
||||
|
||||
{/* {image && (
|
||||
// TODO: remove hardcoded dimensions when satori fixes non-width unloadable images
|
||||
<img
|
||||
alt={name}
|
||||
src={image}
|
||||
width={106}
|
||||
height={32}
|
||||
style={{ objectFit: 'cover' }}
|
||||
/>
|
||||
)} */}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@@ -1,19 +0,0 @@
|
||||
import { type ReactNode } from "react";
|
||||
|
||||
interface RootProps {
|
||||
children: ReactNode;
|
||||
}
|
||||
|
||||
export function Root({ children }: RootProps) {
|
||||
return (
|
||||
<div
|
||||
style={{
|
||||
display: "flex",
|
||||
flexDirection: "column",
|
||||
gap: 16,
|
||||
}}
|
||||
>
|
||||
{children}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@@ -1,18 +0,0 @@
|
||||
import { type ReactNode } from "react";
|
||||
|
||||
interface RowProps {
|
||||
children: ReactNode;
|
||||
}
|
||||
|
||||
export function Row({ children }: RowProps) {
|
||||
return (
|
||||
<div
|
||||
style={{
|
||||
display: "flex",
|
||||
gap: 8,
|
||||
}}
|
||||
>
|
||||
{children}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@@ -1,19 +0,0 @@
|
||||
import { theme } from '../../../stitches.config';
|
||||
|
||||
interface TitleProps {
|
||||
children: string;
|
||||
}
|
||||
|
||||
export function Title({ children }: TitleProps) {
|
||||
return (
|
||||
<span
|
||||
style={{
|
||||
fontWeight: 900,
|
||||
color: theme.colors.textHighContrast,
|
||||
fontSize: 24,
|
||||
}}
|
||||
>
|
||||
{children}
|
||||
</span>
|
||||
);
|
||||
}
|
||||
@@ -1,5 +0,0 @@
|
||||
export * from './components/Column';
|
||||
export * from './components/Item';
|
||||
export * from './components/Root';
|
||||
export * from './components/Row';
|
||||
export * from './components/Title';
|
||||
@@ -1,32 +0,0 @@
|
||||
import type { TierWeightsRecord } from "@blitzkit/core";
|
||||
import { theme } from "../stitches.config";
|
||||
|
||||
interface TierWeightsProps {
|
||||
weights: TierWeightsRecord;
|
||||
}
|
||||
|
||||
export function TierWeights({ weights }: TierWeightsProps) {
|
||||
return (
|
||||
<div style={{ display: "flex", gap: 8 }}>
|
||||
{Object.entries(weights).map(([tier, weight]) => (
|
||||
<div
|
||||
key={tier}
|
||||
style={{
|
||||
backgroundColor: theme.colors.appBackground1_light,
|
||||
flex: weight,
|
||||
color: theme.colors.textHighContrast_light,
|
||||
display: "flex",
|
||||
alignItems: "center",
|
||||
justifyContent: "center",
|
||||
fontSize: 16,
|
||||
overflow: "hidden",
|
||||
borderRadius: 8,
|
||||
minWidth: 16,
|
||||
}}
|
||||
>
|
||||
{tier}
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@@ -1,54 +0,0 @@
|
||||
import { theme } from '../stitches.config';
|
||||
|
||||
interface TitleBarProps {
|
||||
title: string;
|
||||
image?: string;
|
||||
description?: string;
|
||||
}
|
||||
|
||||
export function TitleBar({ title, image, description }: TitleBarProps) {
|
||||
return (
|
||||
<div
|
||||
style={{
|
||||
gap: 4,
|
||||
display: 'flex',
|
||||
flexDirection: 'column',
|
||||
justifyContent: 'center',
|
||||
alignItems: 'center',
|
||||
padding: '8px 0px',
|
||||
}}
|
||||
>
|
||||
<div
|
||||
style={{
|
||||
gap: 4,
|
||||
display: 'flex',
|
||||
justifyContent: 'center',
|
||||
alignItems: 'center',
|
||||
}}
|
||||
>
|
||||
{image && (
|
||||
<img
|
||||
alt={title}
|
||||
style={{ width: 32, height: 32, objectFit: 'contain' }}
|
||||
src={image}
|
||||
/>
|
||||
)}
|
||||
|
||||
<span
|
||||
style={{
|
||||
fontSize: 32,
|
||||
fontWeight: 900,
|
||||
background: `linear-gradient(180deg, ${theme.colors.textHighContrast} 0%, ${theme.colors.textLowContrast} 100%)`,
|
||||
backgroundClip: 'text',
|
||||
}}
|
||||
>
|
||||
{title}
|
||||
</span>
|
||||
</div>
|
||||
|
||||
<span style={{ color: theme.colors.textLowContrast, fontSize: 16 }}>
|
||||
{description}
|
||||
</span>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@@ -1,3 +0,0 @@
|
||||
export function normalizeLeagueIcon(url: string) {
|
||||
return url.startsWith('http') ? url : `https:${url}`;
|
||||
}
|
||||
@@ -1,48 +0,0 @@
|
||||
import { SEARCH_KEYS } from "@blitzkit/core";
|
||||
import { literals } from "@blitzkit/i18n";
|
||||
import { Locale } from "discord.js";
|
||||
import { go } from "fuzzysort";
|
||||
import markdownEscape from "markdown-escape";
|
||||
import { tankDefinitions, tankNames } from "../blitzkit/nonBlockingPromises";
|
||||
import { UserError } from "../blitzkit/userError";
|
||||
import { tankNamesTechTreeOnly } from "../discord/autocompleteTanks";
|
||||
import { translator } from "../localization/translator";
|
||||
|
||||
export async function resolveTankId(
|
||||
tank: string | number,
|
||||
locale: Locale,
|
||||
techTreeOnly = false
|
||||
) {
|
||||
const { strings } = translator(locale);
|
||||
const number = typeof tank === "string" ? Number(tank) : tank;
|
||||
|
||||
if (Number.isNaN(number)) {
|
||||
const searchResult = go(
|
||||
`${tank}`,
|
||||
await (techTreeOnly ? tankNamesTechTreeOnly : tankNames),
|
||||
{ keys: SEARCH_KEYS, limit: 1 }
|
||||
);
|
||||
|
||||
if (searchResult.length === 0) {
|
||||
throw new UserError(
|
||||
literals(strings.bot.common.errors.tank_name_not_found, {
|
||||
search: markdownEscape(`${tank}`),
|
||||
})
|
||||
);
|
||||
} else {
|
||||
return searchResult[0].obj.id;
|
||||
}
|
||||
} else {
|
||||
const awaitedTankDefinitions = await tankDefinitions;
|
||||
|
||||
if (awaitedTankDefinitions.tanks[number]) {
|
||||
return number;
|
||||
} else {
|
||||
throw new UserError(
|
||||
literals(strings.bot.common.errors.tank_id_not_found, {
|
||||
search: number,
|
||||
})
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,23 +0,0 @@
|
||||
import { searchClansAcrossRegions } from '@blitzkit/core';
|
||||
import { Locale } from 'discord.js';
|
||||
import { UserError } from '../blitzkit/userError';
|
||||
import { translator } from '../localization/translator';
|
||||
|
||||
export async function searchClansAcrossRegionsBotWrapper(
|
||||
search: string,
|
||||
locale: Locale,
|
||||
limit?: number,
|
||||
) {
|
||||
const { strings } = translator(locale);
|
||||
const trimmed = search.trim();
|
||||
|
||||
if (trimmed.length < 3) {
|
||||
throw new UserError(strings.bot.common.errors.query_too_small);
|
||||
}
|
||||
|
||||
if (trimmed.length > 100) {
|
||||
throw new UserError(strings.bot.common.errors.query_too_long);
|
||||
}
|
||||
|
||||
return await searchClansAcrossRegions(trimmed, limit);
|
||||
}
|
||||
@@ -1,23 +0,0 @@
|
||||
import { searchPlayersAcrossRegions } from '@blitzkit/core';
|
||||
import { Locale } from 'discord.js';
|
||||
import { UserError } from '../blitzkit/userError';
|
||||
import { translator } from '../localization/translator';
|
||||
|
||||
export async function searchPlayersAcrossRegionsBotWrapper(
|
||||
search: string,
|
||||
locale: Locale,
|
||||
limit?: number,
|
||||
) {
|
||||
const { strings } = translator(locale);
|
||||
const trimmed = search.trim();
|
||||
|
||||
if (trimmed.length < 3) {
|
||||
throw new UserError(strings.bot.common.errors.query_too_small);
|
||||
}
|
||||
|
||||
if (trimmed.length > 100) {
|
||||
throw new UserError(strings.bot.common.errors.query_too_long);
|
||||
}
|
||||
|
||||
return await searchPlayersAcrossRegions(trimmed, limit);
|
||||
}
|
||||
@@ -1,20 +0,0 @@
|
||||
import { fetchTankDefinitions } from '@blitzkit/core';
|
||||
import { resolveAncestry } from './resolveAncestry';
|
||||
|
||||
export async function buildTechTreeLine(start: number, end: number) {
|
||||
const tankDefinitions = await fetchTankDefinitions();
|
||||
const endTank = tankDefinitions.tanks[end];
|
||||
if (!endTank.ancestors) throw new Error('End tank has no ancestors');
|
||||
const line = [end];
|
||||
|
||||
if (start === end) return line;
|
||||
for (const ancestorId of endTank.ancestors) {
|
||||
if ((await resolveAncestry(ancestorId)).includes(start)) {
|
||||
const ancestorTree = await buildTechTreeLine(start, ancestorId);
|
||||
line.push(...ancestorTree);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return line;
|
||||
}
|
||||
@@ -1,30 +0,0 @@
|
||||
import { fetchTankDefinitions, TIER_ROMAN_NUMERALS } from "@blitzkit/core";
|
||||
import { literals } from "@blitzkit/i18n";
|
||||
import { Locale } from "discord.js";
|
||||
import { type StatFilters } from "../blitzstars/filterStats";
|
||||
import { translator } from "../localization/translator";
|
||||
|
||||
export async function filtersToDescription(
|
||||
{ nation, tier, type, class: tankClass, tank }: StatFilters,
|
||||
locale: Locale,
|
||||
) {
|
||||
const { strings, bkLocale } = translator(locale);
|
||||
const awaitedTankDefinitions = await fetchTankDefinitions();
|
||||
const info: string[] = [];
|
||||
|
||||
// TODO: somehow localize tank names?
|
||||
if (tank) return awaitedTankDefinitions.tanks[tank].name!.locales[bkLocale];
|
||||
if (nation)
|
||||
info.push((strings.common.nations as Record<string, string>)[nation]);
|
||||
if (tier) {
|
||||
info.push(
|
||||
literals(strings.bot.common.filters.tier, {
|
||||
tier: TIER_ROMAN_NUMERALS[tier],
|
||||
}),
|
||||
);
|
||||
}
|
||||
if (tankClass) info.push(strings.common.tank_class_short[tankClass]);
|
||||
if (type) info.push(strings.common.tree_type[type]);
|
||||
|
||||
return info.length === 0 ? strings.bot.common.filters.none : info.join(", ");
|
||||
}
|
||||
@@ -1,16 +0,0 @@
|
||||
import { idToRegion } from '@blitzkit/core';
|
||||
import { flagUserActivity } from '../db/flagUserActivity';
|
||||
import { usersDatabase } from '../db/users';
|
||||
|
||||
export async function getBlitzFromDiscord(discordId: bigint) {
|
||||
const unique = await usersDatabase.discordUser.findUnique({
|
||||
where: { discord_id: discordId },
|
||||
});
|
||||
|
||||
if (unique === null) return null;
|
||||
|
||||
const id = Number(unique.blitz_id);
|
||||
|
||||
await flagUserActivity(id);
|
||||
return { id, region: idToRegion(id) };
|
||||
}
|
||||
@@ -1,3 +0,0 @@
|
||||
export function getPeriodNow() {
|
||||
return Date.now() / 1000;
|
||||
}
|
||||
@@ -1,8 +0,0 @@
|
||||
import { getTimeDaysAgo, type Region } from '@blitzkit/core';
|
||||
import type { PeriodSize } from '../discord/addPeriodSubCommands';
|
||||
|
||||
export function getPeriodStart(region: Region, period: PeriodSize) {
|
||||
if (period === 'career') return 0;
|
||||
if (period === 'today') return getTimeDaysAgo(region, 1);
|
||||
return getTimeDaysAgo(region, parseInt(period));
|
||||
}
|
||||
@@ -1,16 +0,0 @@
|
||||
import sharp from "sharp";
|
||||
|
||||
const cache: Record<string, Buffer> = {};
|
||||
|
||||
export async function iconPng(url: string) {
|
||||
if (!url.endsWith(".webp")) return url;
|
||||
|
||||
if (!cache[url]) {
|
||||
const imageResponse = await fetch(url);
|
||||
const imageBufferWEBP = await imageResponse.arrayBuffer();
|
||||
const imageBufferPNG = await sharp(imageBufferWEBP).png().toBuffer();
|
||||
cache[url] = imageBufferPNG;
|
||||
}
|
||||
|
||||
return `data:image/png;base64,${cache[url].toString("base64")}`;
|
||||
}
|
||||
@@ -1,9 +0,0 @@
|
||||
import { jsxToSvg } from "./jsxToSvg";
|
||||
import { svgToPng } from "./svgToPng";
|
||||
|
||||
export async function jsxToPng(jsx: React.JSX.Element) {
|
||||
const svg = await jsxToSvg(jsx);
|
||||
const png = svgToPng(svg);
|
||||
|
||||
return png;
|
||||
}
|
||||
@@ -1,12 +0,0 @@
|
||||
import { jsxToSvg } from "./jsxToSvg";
|
||||
import { RenderConfiguration } from "./renderConfiguration";
|
||||
import { svgToPngThreaded } from "./svgToPngThreaded";
|
||||
|
||||
export async function jsxToPngThreaded(
|
||||
jsx: React.JSX.Element,
|
||||
renderConfiguration: RenderConfiguration
|
||||
) {
|
||||
const svg = await jsxToSvg(jsx, renderConfiguration);
|
||||
const png = await svgToPngThreaded(svg);
|
||||
return png;
|
||||
}
|
||||
Binary file not shown.
Loaded 100 of 830 files, more files were not shown because too many files have changed in this diff.
Show more
Reference in new issue
Block a user