Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
f0e0d849d5 | ||
|
|
6d2573ee95 | ||
|
|
4c77cc2282 | ||
|
|
32f6916266 | ||
|
|
3a91e082d5 | ||
|
|
2184c1c703 | ||
|
|
95ad6bade7 | ||
|
|
8bda4a5331 | ||
|
|
16c77f587a | ||
|
|
a218c791a9 | ||
|
|
dccdf55bfc | ||
|
|
1ba6e70c56 | ||
|
|
0e76184813 | ||
|
|
c674da29d5 | ||
|
|
ba4e6dfd68 | ||
|
|
980fd6e50e | ||
|
|
44e7cd7505 | ||
|
|
3a60535564 | ||
|
|
9abfeb749c | ||
|
|
0442c789f1 | ||
|
|
76dc9f0742 | ||
|
|
ff56f1441e | ||
|
|
e3db886923 | ||
|
|
249f62759e | ||
|
|
7767481633 | ||
|
|
a97b1383d8 | ||
|
|
1b224b3949 | ||
|
|
018aa33a7f | ||
|
|
4b7b8b3392 | ||
|
|
272824a72f | ||
|
|
ac02d65db0 | ||
|
|
9bcaff9fd3 | ||
|
|
7b650bf39b | ||
|
|
ee1ecb83b7 | ||
|
|
d6e37119a8 | ||
|
|
385cc3b6d2 | ||
|
|
b4936bf13b | ||
|
|
e1e9403c60 | ||
|
|
0828d50830 | ||
|
|
0817ba18bd | ||
|
|
121a80d079 | ||
|
|
932c414b0c | ||
|
|
3a38441d42 | ||
|
|
3e039d34c2 | ||
|
|
2bae132d18 | ||
|
|
bc0004574a | ||
|
|
2e208507c3 | ||
|
|
33209a6d31 | ||
|
|
13311245a5 | ||
|
|
4067357b54 | ||
|
|
fd6b69edc1 | ||
|
|
2504833a29 | ||
|
|
6d31dcb74b | ||
|
|
a149af50fd | ||
|
|
13927927b3 | ||
|
|
68edf520c5 | ||
|
|
f7933a1295 | ||
|
|
9a1c09490f | ||
|
|
c8b5c216e3 | ||
|
|
344954513a | ||
|
|
f8029bdf67 | ||
|
|
d9c7d31017 | ||
|
|
79dba0fe2c | ||
|
|
c0376182f8 | ||
|
|
8e3b5de249 | ||
|
|
44711a58c7 | ||
|
|
e7337145d2 | ||
|
|
c116b40dfc | ||
|
|
d88f7ad539 | ||
|
|
b5d61cebb3 | ||
|
|
551108e047 | ||
|
|
5feec9bf1e | ||
|
|
313691d3e9 | ||
|
|
950c99d3d7 | ||
|
|
80cc74a945 | ||
|
|
4e586253c0 | ||
|
|
08980158e4 | ||
|
|
1e917c7b89 | ||
|
|
8d3678ddcb | ||
|
|
6a58c5ea1d | ||
|
|
b9bbf22f2c | ||
|
|
c99ed0cb53 | ||
|
|
cef18d4f64 | ||
|
|
824169fc25 | ||
|
|
841b5708ae | ||
|
|
8ad110f73b | ||
|
|
0869ea09c8 | ||
|
|
0e57943d33 | ||
|
|
8b01b7c192 | ||
|
|
a7bd671309 | ||
|
|
406ad52c8d | ||
|
|
b6c4c4e852 | ||
|
|
f193d5c503 | ||
|
|
6a06cb17a3 | ||
|
|
bf218b0975 | ||
|
|
5412c479c8 | ||
|
|
ccb86ae824 | ||
|
|
001709c25c | ||
|
|
e50b8d11bf | ||
|
|
ea782af079 | ||
|
|
0ebf9f6c3d | ||
|
|
6fec467ec8 | ||
|
|
8b0f1cdfed | ||
|
|
f6008bd288 | ||
|
|
1776c8fc15 | ||
|
|
99f41b9805 | ||
|
|
d4f11fc52a | ||
|
|
750aeb39c9 | ||
|
|
0f355bc2fc | ||
|
|
6ebd3063ed | ||
|
|
b070cad92a | ||
|
|
204fbbff59 | ||
|
|
98e7760142 | ||
|
|
6c1c088d44 | ||
|
|
0b7f717057 | ||
|
|
728cb43f05 | ||
|
|
ff02f06cbc | ||
|
|
7a817cbe8c | ||
|
|
58e0876aa0 | ||
|
|
f84f846e76 | ||
|
|
ddb869e767 | ||
|
|
015d457d23 | ||
|
|
ba6a83a9cb | ||
|
|
689985ed93 | ||
|
|
bf9262f1f1 | ||
|
|
821bd363ad | ||
|
|
4a9fc65e71 | ||
|
|
81877f5abd | ||
|
|
01eed3e045 | ||
|
|
7bc423b570 | ||
|
|
dba56f8946 | ||
|
|
c1f765d5f7 | ||
|
|
7f5b5b614f | ||
|
|
5cd149b2b9 | ||
|
|
0bc2d0aaf6 | ||
|
|
1dc9a341d1 | ||
|
|
2ad1e71176 | ||
|
|
ca6973f529 | ||
|
|
323d624ec7 | ||
|
|
49f84db473 | ||
|
|
7399c402af | ||
|
|
cbfcb29691 | ||
|
|
ae616fbaf3 | ||
|
|
35275d4aa8 | ||
|
|
dda63830ec | ||
|
|
79b4f05809 | ||
|
|
b50c47b744 | ||
|
|
f7c6fdd861 | ||
|
|
47b583821e | ||
|
|
369ac113fa | ||
|
|
fc4d8b5ad0 | ||
|
|
72e1cf7d6a | ||
|
|
dd96556e2a | ||
|
|
a7ee51526a | ||
|
|
610b59f4c6 | ||
|
|
63ce327458 | ||
|
|
6ec7a50320 | ||
|
|
60a29ef2e7 | ||
|
|
52c3a0abe0 | ||
|
|
5bbe5c2720 | ||
|
|
c0c6a21e43 | ||
|
|
a7f93698a6 | ||
|
|
1a18058228 | ||
|
|
67024daa25 | ||
|
|
de6137d1a5 | ||
|
|
11e87bd519 | ||
|
|
3b4e089756 | ||
|
|
4a6f5845f9 | ||
|
|
e9684ce033 | ||
|
|
27abf1b0de | ||
|
|
f5f3f70e35 | ||
|
|
2d282a3261 | ||
|
|
a2d0d2d8c0 | ||
|
|
ea412086d4 | ||
|
|
455679a981 | ||
|
|
a21bc6174d | ||
|
|
fae1a89402 | ||
|
|
5a1a0c59f1 | ||
|
|
c98271f783 | ||
|
|
033660c2d9 | ||
|
|
1a639c51e1 | ||
|
|
1366579dd1 | ||
|
|
f5ed2c2c40 | ||
|
|
1598de9f5f | ||
|
|
6f47f5cc99 | ||
|
|
1117dcb935 | ||
|
|
01a58f9aa8 | ||
|
|
9096644d51 | ||
|
|
d42fc0e3f6 | ||
|
|
17d1526b6f | ||
|
|
db8ac195d4 | ||
|
|
c5f5f69fd6 | ||
|
|
44203223fd | ||
|
|
bdabadcd49 | ||
|
|
220e4388d4 | ||
|
|
51b2d1ce86 | ||
|
|
f3c1825c57 | ||
|
|
359dfcd102 | ||
|
|
649cdd893f | ||
|
|
0cb974acf5 | ||
|
|
9bca5dccc7 | ||
|
|
d707f1cc5d | ||
|
|
4ed4395535 | ||
|
|
0209d48475 | ||
|
|
437bee4a85 | ||
|
|
4b8e73fa57 | ||
|
|
b96f925d9a | ||
|
|
1551dc50fd | ||
|
|
daf4cef61c | ||
|
|
496e127f64 | ||
|
|
da1af66c77 | ||
|
|
01409985a2 | ||
|
|
a86ac0619a | ||
|
|
385d165512 | ||
|
|
fcfc97b964 | ||
|
|
53d05e73a6 | ||
|
|
40a1eb861d | ||
|
|
1d3cb95b89 | ||
|
|
010303a818 | ||
|
|
7281b9fed0 | ||
|
|
c5785c7ae6 | ||
|
|
698731cb9a | ||
|
|
99bae8f2c5 | ||
|
|
5034ec1aa0 | ||
|
|
be821c1f8b | ||
|
|
a364b79a9b | ||
|
|
0aa6e1e79a | ||
|
|
d2a6379131 | ||
|
|
07ce61d19f | ||
|
|
ad9f2d8609 | ||
|
|
57702d8a43 | ||
|
|
9a30af3818 | ||
|
|
23751fbdf3 | ||
|
|
db6d181f78 | ||
|
|
56ca4dcc61 | ||
|
|
d08b537721 | ||
|
|
c1a2edb489 | ||
|
|
164b7fa454 | ||
|
|
428483cf4c | ||
|
|
89f02eb399 | ||
|
|
4ce127516c | ||
|
|
6f4f487dfe | ||
|
|
57dd60e804 | ||
|
|
d24fd2250c | ||
|
|
e00bcdfc06 | ||
|
|
67dd204ee6 | ||
|
|
e130583fa4 | ||
|
|
6ad20a0fcf | ||
|
|
9fad644d7a | ||
|
|
8cb523dd06 | ||
|
|
b50ee23a26 | ||
|
|
a973cf699b | ||
|
|
102abf49c4 | ||
|
|
8929e503ea | ||
|
|
a2a794eb74 | ||
|
|
2e95f5dd95 | ||
|
|
23a42230cb | ||
|
|
e66daed7ae | ||
|
|
f2d0f68f07 | ||
|
|
be4af0bf84 | ||
|
|
15172e8b33 | ||
|
|
c6b7918525 | ||
|
|
4f1c4421e5 | ||
|
|
7b830f5a71 | ||
|
|
6ce1135835 | ||
|
|
66eaaef6de | ||
|
|
48fbf59036 | ||
|
|
0e0f4fbe9f | ||
|
|
6ba6e10108 | ||
|
|
cf8fa4ffb4 | ||
|
|
2b0180dce2 | ||
|
|
caee848a47 | ||
|
|
d01b7cf707 | ||
|
|
8921f84c38 | ||
|
|
6830df01fa | ||
|
|
67da59ef41 | ||
|
|
036cc9915d | ||
|
|
57b6ba19f0 | ||
|
|
32b5593d07 | ||
|
|
3b757562d2 | ||
|
|
4c8c2d0868 | ||
|
|
b2f266401f | ||
|
|
5541eca23d | ||
|
|
122d65840e | ||
|
|
ed4b72d85c | ||
|
|
4033e8618f | ||
|
|
42cada1811 | ||
|
|
ff7ed213c8 | ||
|
|
a0367af06b | ||
|
|
58c2965c53 | ||
|
|
edae41409a | ||
|
|
383d3a36ef | ||
|
|
6a958da390 | ||
|
|
ef154f99d5 | ||
|
|
4a20102de3 | ||
|
|
4e170f2917 | ||
|
|
a70d788f6b |
No files matched your search
@@ -1,82 +0,0 @@
|
||||
name: Assets
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: main
|
||||
|
||||
workflow_dispatch:
|
||||
inputs:
|
||||
asset_repo:
|
||||
type: choice
|
||||
required: false
|
||||
description: What asset repo to write to
|
||||
options:
|
||||
- blitzkit/assets
|
||||
- blitzkit/assets-preview
|
||||
- blitzkit/assets-dev
|
||||
default: blitzkit/assets
|
||||
|
||||
asset_source:
|
||||
type: string
|
||||
required: false
|
||||
description: "Archive URL or Steam to download (example: steam:APP_ID/DEPOT_ID or zip:URL_TO_ZIP)"
|
||||
default: "steam:444200/444202"
|
||||
|
||||
schedule:
|
||||
- cron: "0 2 * * *"
|
||||
|
||||
concurrency:
|
||||
group: ${{ github.workflow }}-${{ github.ref }}-${{ github.event.inputs.asset_repo }}
|
||||
cancel-in-progress: true
|
||||
|
||||
env:
|
||||
DISCORD_CLIENT_ID: ${{ secrets.DISCORD_CLIENT_ID }}
|
||||
DISCORD_TOKEN: ${{ secrets.DISCORD_TOKEN }}
|
||||
DATABASE_URL: ${{ secrets.DATABASE_URL }}
|
||||
VIDEOS_SHEET: ${{ secrets.VIDEOS_SHEET }}
|
||||
GOOGLE_APPLICATION_CREDENTIALS: ${{ secrets.GOOGLE_APPLICATION_CREDENTIALS }}
|
||||
WOTB_GLOSSARY: ${{ secrets.WOTB_GLOSSARY }}
|
||||
WOTB_DLC_CDN: ${{ secrets.WOTB_DLC_CDN }}
|
||||
PUBLIC_WARGAMING_APPLICATION_ID: ${{ secrets.PUBLIC_WARGAMING_APPLICATION_ID }}
|
||||
PUBLIC_ASSET_REPO: ${{ github.event.inputs.asset_repo != '' && github.event.inputs.asset_repo || secrets.PUBLIC_ASSET_REPO }}
|
||||
PUBLIC_ASSET_BRANCH: ${{ secrets.PUBLIC_ASSET_BRANCH }}
|
||||
WOTB_GLOSSARY_DOMAIN: ${{ secrets.WOTB_GLOSSARY_DOMAIN }}
|
||||
WOTB_GLOSSARY_PATH: ${{ secrets.WOTB_GLOSSARY_PATH }}
|
||||
PUBLIC_PROMOTE_OPENTEST: ${{ secrets.PUBLIC_PROMOTE_OPENTEST }}
|
||||
ALLOW_ROBOTS: true
|
||||
PUBLIC_GOOGLE_TAG_MANAGER_ID: ${{ secrets.PUBLIC_GOOGLE_TAG_MANAGER_ID }}
|
||||
PUBLIC_GOOGLE_ANALYTICS_PROPERTY_ID: ${{ secrets.PUBLIC_GOOGLE_ANALYTICS_PROPERTY_ID }}
|
||||
PUBLIC_PATREON_CLIENT_ID: ${{ secrets.PUBLIC_PATREON_CLIENT_ID }}
|
||||
PUBLIC_PATREON_REDIRECT_URI: ${{ secrets.PUBLIC_PATREON_REDIRECT_URI }}
|
||||
PATREON_CLIENT_SECRET: ${{ secrets.PATREON_CLIENT_SECRET }}
|
||||
PUBLIC_NITROPAY_ID: ${{ secrets.PUBLIC_NITROPAY_ID }}
|
||||
PUBLIC_DEBUG_MISSING_I18N: false
|
||||
PUBLIC_DISCORD_SERVER_ID: ${{ secrets.PUBLIC_DISCORD_SERVER_ID }}
|
||||
PUBLIC_ASSET_FAST_USER: blitzkit
|
||||
PUBLIC_ASSET_FAST_REPO: assets
|
||||
PUBLIC_ASSET_BASE: ${{ secrets.PUBLIC_ASSET_BASE }}
|
||||
GH_TOKEN: ${{ secrets.GH_TOKEN }}
|
||||
STEAM_USERNAME: ${{ secrets.STEAM_USERNAME }}
|
||||
STEAM_PASSWORD: ${{ secrets.STEAM_PASSWORD }}
|
||||
|
||||
jobs:
|
||||
build_assets:
|
||||
name: Build assets
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v6
|
||||
with:
|
||||
submodules: recursive
|
||||
token: ${{ secrets.GH_TOKEN }}
|
||||
- uses: arduino/setup-protoc@v3
|
||||
with:
|
||||
repo-token: ${{ secrets.GH_TOKEN }}
|
||||
- uses: oven-sh/setup-bun@v2
|
||||
- run: bun run setup
|
||||
|
||||
- name: AppArmor hack
|
||||
run: echo 0 | sudo tee /proc/sys/kernel/apparmor_restrict_unprivileged_userns
|
||||
|
||||
- name: Build assets
|
||||
run: bun run build:assets --all-targets --source=${{ github.event.inputs.asset_source || 'steam:444200/444202' }}
|
||||
@@ -1,54 +0,0 @@
|
||||
name: Averages
|
||||
|
||||
on:
|
||||
workflow_dispatch:
|
||||
schedule:
|
||||
- cron: "0 8 * * *"
|
||||
|
||||
concurrency:
|
||||
group: ${{ github.workflow }}-${{ github.ref }}
|
||||
cancel-in-progress: true
|
||||
|
||||
env:
|
||||
PUBLIC_ASSET_REPO: ${{ secrets.PUBLIC_ASSET_REPO }}
|
||||
PUBLIC_WARGAMING_APPLICATION_ID: ${{ secrets.PUBLIC_WARGAMING_APPLICATION_ID }}
|
||||
PUBLIC_ASSET_FAST_USER: ${{ secrets.PUBLIC_ASSET_FAST_USER }}
|
||||
PUBLIC_ASSET_FAST_REPO: ${{ secrets.PUBLIC_ASSET_FAST_REPO }}
|
||||
PUBLIC_PROMOTE_OPENTEST: ${{ secrets.PUBLIC_PROMOTE_OPENTEST }}
|
||||
ALLOW_ROBOTS: "true"
|
||||
WOTB_GLOSSARY: ${{ secrets.WOTB_GLOSSARY }}
|
||||
PUBLIC_GOOGLE_TAG_MANAGER_ID: ${{ secrets.PUBLIC_GOOGLE_TAG_MANAGER_ID }}
|
||||
PUBLIC_GOOGLE_ANALYTICS_PROPERTY_ID: ${{ secrets.PUBLIC_GOOGLE_ANALYTICS_PROPERTY_ID }}
|
||||
GOOGLE_APPLICATION_CREDENTIALS: ${{ secrets.GOOGLE_APPLICATION_CREDENTIALS }}
|
||||
WOTB_GLOSSARY_DOMAIN: ${{ secrets.WOTB_GLOSSARY_DOMAIN }}
|
||||
WOTB_GLOSSARY_PATH: ${{ secrets.WOTB_GLOSSARY_PATH }}
|
||||
PUBLIC_DISCORD_SERVER_ID: ${{ secrets.PUBLIC_DISCORD_SERVER_ID }}
|
||||
PUBLIC_ASSET_BASE: ${{ secrets.PUBLIC_ASSET_BASE }}
|
||||
PUBLIC_BRANCH: ${{ secrets.PUBLIC_BRANCH }}
|
||||
GH_TOKEN: ${{ secrets.GH_TOKEN }}
|
||||
|
||||
jobs:
|
||||
build:
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v6
|
||||
with:
|
||||
submodules: recursive
|
||||
token: ${{ secrets.GH_TOKEN }}
|
||||
- uses: oven-sh/setup-bun@v2
|
||||
- uses: arduino/setup-protoc@v3
|
||||
with:
|
||||
repo-token: ${{ secrets.GH_TOKEN }}
|
||||
- run: bun run setup
|
||||
|
||||
- name: Build averages
|
||||
env:
|
||||
PUBLIC_ASSET_BRANCH: main
|
||||
DISCORD_CLIENT_ID: ${{ secrets.DISCORD_CLIENT_ID }}
|
||||
|
||||
DISCORD_TOKEN: ${{ secrets.DISCORD_TOKEN }}
|
||||
DATABASE_URL: ${{ secrets.DATABASE_URL }}
|
||||
VIDEOS_SHEET: ${{ secrets.VIDEOS_SHEET }}
|
||||
GOOGLE_APPLICATION_CREDENTIALS: ${{ secrets.GOOGLE_APPLICATION_CREDENTIALS }}
|
||||
run: bun run build:averages --production
|
||||
@@ -1,34 +0,0 @@
|
||||
name: Bot
|
||||
|
||||
on:
|
||||
push:
|
||||
workflow_dispatch:
|
||||
|
||||
concurrency:
|
||||
group: ${{ github.workflow }}-${{ github.ref }}
|
||||
cancel-in-progress: true
|
||||
|
||||
jobs:
|
||||
build:
|
||||
name: Build bot
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v6
|
||||
with:
|
||||
submodules: recursive
|
||||
token: ${{ secrets.GH_TOKEN }}
|
||||
- uses: oven-sh/setup-bun@v2
|
||||
- uses: arduino/setup-protoc@v3
|
||||
with:
|
||||
repo-token: ${{ secrets.GH_TOKEN }}
|
||||
- run: bun run setup
|
||||
|
||||
- name: Build bot
|
||||
run: bun run build:bot
|
||||
|
||||
- name: Archive build
|
||||
uses: actions/upload-artifact@v5
|
||||
with:
|
||||
name: bot
|
||||
path: dist/bot
|
||||
@@ -1,36 +0,0 @@
|
||||
name: IDs
|
||||
|
||||
on:
|
||||
workflow_dispatch:
|
||||
schedule:
|
||||
- cron: "0 0 * * 1"
|
||||
|
||||
concurrency:
|
||||
group: ${{ github.workflow }}-${{ github.ref }}
|
||||
cancel-in-progress: true
|
||||
|
||||
env:
|
||||
DISCORD_TOKEN: ${{ secrets.DISCORD_TOKEN }}
|
||||
DATABASE_URL: ${{ secrets.DATABASE_URL }}
|
||||
PUBLIC_ASSET_BRANCH: ${{ secrets.PUBLIC_ASSET_BRANCH }}
|
||||
PUBLIC_ASSET_REPO: ${{ secrets.PUBLIC_ASSET_REPO }}
|
||||
PUBLIC_WARGAMING_APPLICATION_ID: ${{ secrets.PUBLIC_WARGAMING_APPLICATION_ID }}
|
||||
GH_TOKEN: ${{ secrets.GH_TOKEN }}
|
||||
|
||||
jobs:
|
||||
build:
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v6
|
||||
with:
|
||||
submodules: recursive
|
||||
token: ${{ secrets.GH_TOKEN }}
|
||||
- uses: oven-sh/setup-bun@v2
|
||||
- uses: arduino/setup-protoc@v3
|
||||
with:
|
||||
repo-token: ${{ secrets.GH_TOKEN }}
|
||||
- run: bun run setup
|
||||
|
||||
- name: Discover IDs
|
||||
run: bun build:ids --production
|
||||
@@ -1,61 +0,0 @@
|
||||
name: Host
|
||||
|
||||
on:
|
||||
workflow_dispatch:
|
||||
|
||||
concurrency:
|
||||
group: ${{ github.workflow }}-${{ github.ref }}
|
||||
cancel-in-progress: true
|
||||
|
||||
env:
|
||||
DISCORD_TOKEN: ${{ secrets.DISCORD_TOKEN }}
|
||||
DISCORD_CLIENT_ID: ${{ secrets.DISCORD_CLIENT_ID }}
|
||||
DATABASE_URL: ${{ secrets.DATABASE_URL }}
|
||||
PUBLIC_ASSET_REPO: ${{ secrets.PUBLIC_ASSET_REPO }}
|
||||
PUBLIC_ASSET_BRANCH: ${{ secrets.PUBLIC_ASSET_BRANCH }}
|
||||
PUBLIC_WARGAMING_APPLICATION_ID: ${{ secrets.PUBLIC_WARGAMING_APPLICATION_ID }}
|
||||
PUBLIC_ASSET_FAST_USER: ${{ secrets.PUBLIC_ASSET_FAST_USER }}
|
||||
PUBLIC_ASSET_FAST_REPO: ${{ secrets.PUBLIC_ASSET_FAST_REPO }}
|
||||
PUBLIC_PROMOTE_OPENTEST: ${{ secrets.PUBLIC_PROMOTE_OPENTEST }}
|
||||
ALLOW_ROBOTS: ${{ secrets.ALLOW_ROBOTS }}
|
||||
WOTB_GLOSSARY: ${{ secrets.WOTB_GLOSSARY }}
|
||||
PUBLIC_GOOGLE_TAG_MANAGER_ID: ${{ secrets.PUBLIC_GOOGLE_TAG_MANAGER_ID }}
|
||||
PUBLIC_GOOGLE_ANALYTICS_PROPERTY_ID: ${{ secrets.PUBLIC_GOOGLE_ANALYTICS_PROPERTY_ID }}
|
||||
GOOGLE_APPLICATION_CREDENTIALS: ${{ secrets.GOOGLE_APPLICATION_CREDENTIALS }}
|
||||
WOTB_GLOSSARY_DOMAIN: ${{ secrets.WOTB_GLOSSARY_DOMAIN }}
|
||||
WOTB_GLOSSARY_PATH: ${{ secrets.WOTB_GLOSSARY_PATH }}
|
||||
PUBLIC_DISCORD_SERVER_ID: ${{ secrets.PUBLIC_DISCORD_SERVER_ID }}
|
||||
PUBLIC_ASSET_BASE: ${{ secrets.PUBLIC_ASSET_BASE }}
|
||||
PUBLIC_BRANCH: ${{ secrets.PUBLIC_BRANCH }}
|
||||
PUBLIC_GUIDE_WEBSITE: ${{ secrets.PUBLIC_GUIDE_WEBSITE }}
|
||||
SERVICING: ${{ secrets.SERVICING }}
|
||||
GH_TOKEN: ${{ secrets.GH_TOKEN }}
|
||||
|
||||
jobs:
|
||||
host:
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- uses: oven-sh/setup-bun@v2
|
||||
- uses: arduino/setup-protoc@v3
|
||||
with:
|
||||
repo-token: ${{ secrets.GH_TOKEN }}
|
||||
|
||||
- name: Download release assets
|
||||
run: |
|
||||
DOWNLOAD_URL=$(curl -s https://api.github.com/repos/blitzkit/blitzkit/releases/latest \
|
||||
| grep "browser_download_url.*bot.zip" \
|
||||
| cut -d : -f 2,3 \
|
||||
| tr -d \")
|
||||
curl -L -o bot.zip $DOWNLOAD_URL
|
||||
mkdir -p dist/bot
|
||||
unzip bot.zip -d dist/bot
|
||||
|
||||
- name: Install sharp
|
||||
run: bun init -y && bun add sharp
|
||||
|
||||
- name: Move directories
|
||||
run: mv dist/bot/prisma .
|
||||
|
||||
- name: Run bot
|
||||
run: bun run dist/bot/main.js
|
||||
@@ -1,46 +0,0 @@
|
||||
name: Rating Asia
|
||||
|
||||
on:
|
||||
workflow_dispatch:
|
||||
schedule:
|
||||
- cron: "0 17 * * *"
|
||||
|
||||
env:
|
||||
PUBLIC_ASSET_BRANCH: main
|
||||
PUBLIC_ASSET_REPO: ${{ secrets.PUBLIC_ASSET_REPO }}
|
||||
DISCORD_CLIENT_ID: ${{ secrets.DISCORD_CLIENT_ID }}
|
||||
DISCORD_TOKEN: ${{ secrets.DISCORD_TOKEN }}
|
||||
DATABASE_URL: ${{ secrets.DATABASE_URL }}
|
||||
PUBLIC_WARGAMING_APPLICATION_ID: ${{ secrets.PUBLIC_WARGAMING_APPLICATION_ID }}
|
||||
PUBLIC_ASSET_FAST_USER: ${{ secrets.PUBLIC_ASSET_FAST_USER }}
|
||||
PUBLIC_ASSET_FAST_REPO: ${{ secrets.PUBLIC_ASSET_FAST_REPO }}
|
||||
PUBLIC_PROMOTE_OPENTEST: ${{ secrets.PUBLIC_PROMOTE_OPENTEST }}
|
||||
ALLOW_ROBOTS: "true"
|
||||
WOTB_GLOSSARY: ${{ secrets.WOTB_GLOSSARY }}
|
||||
PUBLIC_GOOGLE_TAG_MANAGER_ID: ${{ secrets.PUBLIC_GOOGLE_TAG_MANAGER_ID }}
|
||||
PUBLIC_GOOGLE_ANALYTICS_PROPERTY_ID: ${{ secrets.PUBLIC_GOOGLE_ANALYTICS_PROPERTY_ID }}
|
||||
GOOGLE_APPLICATION_CREDENTIALS: ${{ secrets.GOOGLE_APPLICATION_CREDENTIALS }}
|
||||
WOTB_GLOSSARY_DOMAIN: ${{ secrets.WOTB_GLOSSARY_DOMAIN }}
|
||||
WOTB_GLOSSARY_PATH: ${{ secrets.WOTB_GLOSSARY_PATH }}
|
||||
PUBLIC_DISCORD_SERVER_ID: ${{ secrets.PUBLIC_DISCORD_SERVER_ID }}
|
||||
PUBLIC_ASSET_BASE: ${{ secrets.PUBLIC_ASSET_BASE }}
|
||||
PUBLIC_BRANCH: ${{ secrets.PUBLIC_BRANCH }}
|
||||
GH_TOKEN: ${{ secrets.GH_TOKEN }}
|
||||
|
||||
jobs:
|
||||
host:
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v6
|
||||
with:
|
||||
submodules: recursive
|
||||
token: ${{ secrets.GH_TOKEN }}
|
||||
- uses: oven-sh/setup-bun@v2
|
||||
- uses: arduino/setup-protoc@v3
|
||||
with:
|
||||
repo-token: ${{ secrets.GH_TOKEN }}
|
||||
- run: bun run setup
|
||||
|
||||
- name: Generate leaderboard
|
||||
run: bun build:ratingleaderboard --region=asia
|
||||
@@ -1,46 +0,0 @@
|
||||
name: Rating Europe
|
||||
|
||||
on:
|
||||
workflow_dispatch:
|
||||
schedule:
|
||||
- cron: "0 23 * * *"
|
||||
|
||||
env:
|
||||
PUBLIC_ASSET_BRANCH: main
|
||||
PUBLIC_ASSET_REPO: ${{ secrets.PUBLIC_ASSET_REPO }}
|
||||
DISCORD_CLIENT_ID: ${{ secrets.DISCORD_CLIENT_ID }}
|
||||
DISCORD_TOKEN: ${{ secrets.DISCORD_TOKEN }}
|
||||
DATABASE_URL: ${{ secrets.DATABASE_URL }}
|
||||
PUBLIC_WARGAMING_APPLICATION_ID: ${{ secrets.PUBLIC_WARGAMING_APPLICATION_ID }}
|
||||
PUBLIC_ASSET_FAST_USER: ${{ secrets.PUBLIC_ASSET_FAST_USER }}
|
||||
PUBLIC_ASSET_FAST_REPO: ${{ secrets.PUBLIC_ASSET_FAST_REPO }}
|
||||
PUBLIC_PROMOTE_OPENTEST: ${{ secrets.PUBLIC_PROMOTE_OPENTEST }}
|
||||
ALLOW_ROBOTS: "true"
|
||||
WOTB_GLOSSARY: ${{ secrets.WOTB_GLOSSARY }}
|
||||
PUBLIC_GOOGLE_TAG_MANAGER_ID: ${{ secrets.PUBLIC_GOOGLE_TAG_MANAGER_ID }}
|
||||
PUBLIC_GOOGLE_ANALYTICS_PROPERTY_ID: ${{ secrets.PUBLIC_GOOGLE_ANALYTICS_PROPERTY_ID }}
|
||||
GOOGLE_APPLICATION_CREDENTIALS: ${{ secrets.GOOGLE_APPLICATION_CREDENTIALS }}
|
||||
WOTB_GLOSSARY_DOMAIN: ${{ secrets.WOTB_GLOSSARY_DOMAIN }}
|
||||
WOTB_GLOSSARY_PATH: ${{ secrets.WOTB_GLOSSARY_PATH }}
|
||||
PUBLIC_DISCORD_SERVER_ID: ${{ secrets.PUBLIC_DISCORD_SERVER_ID }}
|
||||
PUBLIC_ASSET_BASE: ${{ secrets.PUBLIC_ASSET_BASE }}
|
||||
PUBLIC_BRANCH: ${{ secrets.PUBLIC_BRANCH }}
|
||||
GH_TOKEN: ${{ secrets.GH_TOKEN }}
|
||||
|
||||
jobs:
|
||||
host:
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v6
|
||||
with:
|
||||
submodules: recursive
|
||||
token: ${{ secrets.GH_TOKEN }}
|
||||
- uses: oven-sh/setup-bun@v2
|
||||
- uses: arduino/setup-protoc@v3
|
||||
with:
|
||||
repo-token: ${{ secrets.GH_TOKEN }}
|
||||
- run: bun run setup
|
||||
|
||||
- name: Generate leaderboard
|
||||
run: bun build:ratingleaderboard --region=eu
|
||||
@@ -1,46 +0,0 @@
|
||||
name: Rating North America
|
||||
|
||||
on:
|
||||
workflow_dispatch:
|
||||
schedule:
|
||||
- cron: "0 5 * * *"
|
||||
|
||||
env:
|
||||
PUBLIC_ASSET_BRANCH: main
|
||||
PUBLIC_ASSET_REPO: ${{ secrets.PUBLIC_ASSET_REPO }}
|
||||
DISCORD_CLIENT_ID: ${{ secrets.DISCORD_CLIENT_ID }}
|
||||
DISCORD_TOKEN: ${{ secrets.DISCORD_TOKEN }}
|
||||
DATABASE_URL: ${{ secrets.DATABASE_URL }}
|
||||
PUBLIC_WARGAMING_APPLICATION_ID: ${{ secrets.PUBLIC_WARGAMING_APPLICATION_ID }}
|
||||
PUBLIC_ASSET_FAST_USER: ${{ secrets.PUBLIC_ASSET_FAST_USER }}
|
||||
PUBLIC_ASSET_FAST_REPO: ${{ secrets.PUBLIC_ASSET_FAST_REPO }}
|
||||
PUBLIC_PROMOTE_OPENTEST: ${{ secrets.PUBLIC_PROMOTE_OPENTEST }}
|
||||
ALLOW_ROBOTS: "true"
|
||||
WOTB_GLOSSARY: ${{ secrets.WOTB_GLOSSARY }}
|
||||
PUBLIC_GOOGLE_TAG_MANAGER_ID: ${{ secrets.PUBLIC_GOOGLE_TAG_MANAGER_ID }}
|
||||
PUBLIC_GOOGLE_ANALYTICS_PROPERTY_ID: ${{ secrets.PUBLIC_GOOGLE_ANALYTICS_PROPERTY_ID }}
|
||||
GOOGLE_APPLICATION_CREDENTIALS: ${{ secrets.GOOGLE_APPLICATION_CREDENTIALS }}
|
||||
WOTB_GLOSSARY_DOMAIN: ${{ secrets.WOTB_GLOSSARY_DOMAIN }}
|
||||
WOTB_GLOSSARY_PATH: ${{ secrets.WOTB_GLOSSARY_PATH }}
|
||||
PUBLIC_DISCORD_SERVER_ID: ${{ secrets.PUBLIC_DISCORD_SERVER_ID }}
|
||||
PUBLIC_ASSET_BASE: ${{ secrets.PUBLIC_ASSET_BASE }}
|
||||
PUBLIC_BRANCH: ${{ secrets.PUBLIC_BRANCH }}
|
||||
GH_TOKEN: ${{ secrets.GH_TOKEN }}
|
||||
|
||||
jobs:
|
||||
host:
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v6
|
||||
with:
|
||||
submodules: recursive
|
||||
token: ${{ secrets.GH_TOKEN }}
|
||||
- uses: oven-sh/setup-bun@v2
|
||||
- uses: arduino/setup-protoc@v3
|
||||
with:
|
||||
repo-token: ${{ secrets.GH_TOKEN }}
|
||||
- run: bun run setup
|
||||
|
||||
- name: Generate leaderboard
|
||||
run: bun build:ratingleaderboard --region=com
|
||||
@@ -1,38 +0,0 @@
|
||||
name: Reviews
|
||||
|
||||
on:
|
||||
workflow_dispatch:
|
||||
schedule:
|
||||
- cron: 0 0 * * 2
|
||||
|
||||
concurrency:
|
||||
group: ${{ github.workflow }}-${{ github.ref }}
|
||||
cancel-in-progress: true
|
||||
|
||||
env:
|
||||
DISCORD_TOKEN: ${{ secrets.DISCORD_TOKEN }}
|
||||
DATABASE_URL: ${{ secrets.DATABASE_URL }}
|
||||
PUBLIC_ASSET_BRANCH: ${{ secrets.PUBLIC_ASSET_BRANCH }}
|
||||
PUBLIC_ASSET_REPO: ${{ secrets.PUBLIC_ASSET_REPO }}
|
||||
GOOGLE_APPLICATION_CREDENTIALS: ${{ secrets.GOOGLE_APPLICATION_CREDENTIALS }}
|
||||
PUBLIC_WARGAMING_APPLICATION_ID: ${{ secrets.PUBLIC_WARGAMING_APPLICATION_ID }}
|
||||
GH_TOKEN: ${{ secrets.GH_TOKEN }}
|
||||
PUBLIC_ASSET_BASE: ${{ secrets.PUBLIC_ASSET_BASE }}
|
||||
|
||||
jobs:
|
||||
build:
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v6
|
||||
with:
|
||||
submodules: recursive
|
||||
token: ${{ secrets.GH_TOKEN }}
|
||||
- uses: oven-sh/setup-bun@v2
|
||||
- uses: arduino/setup-protoc@v3
|
||||
with:
|
||||
repo-token: ${{ secrets.GH_TOKEN }}
|
||||
- run: bun run setup
|
||||
|
||||
- name: Find reviews
|
||||
run: bun run build:reviews
|
||||
@@ -17,36 +17,30 @@ concurrency:
|
||||
cancel-in-progress: ${{ github.ref == 'refs/heads/main' }}
|
||||
|
||||
env:
|
||||
PUBLIC_WARGAMING_APPLICATION_ID: ${{ secrets.PUBLIC_WARGAMING_APPLICATION_ID }}
|
||||
PUBLIC_PROMOTE_OPENTEST: ${{ secrets.PUBLIC_PROMOTE_OPENTEST }}
|
||||
ALLOW_ROBOTS: ${{ secrets.ALLOW_ROBOTS }}
|
||||
WOTB_GLOSSARY: ${{ secrets.WOTB_GLOSSARY }}
|
||||
PUBLIC_GOOGLE_TAG_MANAGER_ID: ${{ secrets.PUBLIC_GOOGLE_TAG_MANAGER_ID }}
|
||||
PUBLIC_GOOGLE_ANALYTICS_PROPERTY_ID: ${{ secrets.PUBLIC_GOOGLE_ANALYTICS_PROPERTY_ID }}
|
||||
GOOGLE_APPLICATION_CREDENTIALS: ${{ secrets.GOOGLE_APPLICATION_CREDENTIALS }}
|
||||
WOTB_GLOSSARY_DOMAIN: ${{ secrets.WOTB_GLOSSARY_DOMAIN }}
|
||||
WOTB_GLOSSARY_PATH: ${{ secrets.WOTB_GLOSSARY_PATH }}
|
||||
PUBLIC_DISCORD_SERVER_ID: ${{ secrets.PUBLIC_DISCORD_SERVER_ID }}
|
||||
PUBLIC_ASSET_BASE: ${{ secrets.PUBLIC_ASSET_BASE }}
|
||||
PUBLIC_BRANCH: ${{ secrets.PUBLIC_BRANCH }}
|
||||
PUBLIC_GUIDE_WEBSITE: ${{ secrets.PUBLIC_GUIDE_WEBSITE }}
|
||||
SERVICING: ${{ secrets.SERVICING }}
|
||||
GH_TOKEN: ${{ secrets.GH_TOKEN }}
|
||||
WOTB_SERVER: ${{ secrets.WOTB_SERVER }}
|
||||
|
||||
jobs:
|
||||
build:
|
||||
name: Build website
|
||||
name: Build
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v6
|
||||
with:
|
||||
submodules: recursive
|
||||
token: ${{ secrets.GH_TOKEN }}
|
||||
|
||||
- uses: oven-sh/setup-bun@v2
|
||||
|
||||
- uses: actions/setup-node@v6
|
||||
with:
|
||||
node-version: latest
|
||||
|
||||
- uses: arduino/setup-protoc@v3
|
||||
with:
|
||||
repo-token: ${{ secrets.GH_TOKEN }}
|
||||
|
||||
- uses: actions/configure-pages@v5
|
||||
|
||||
- run: bun run setup
|
||||
|
||||
- name: Build website
|
||||
@@ -58,7 +52,7 @@ jobs:
|
||||
path: dist/website
|
||||
|
||||
deploy-github-pages:
|
||||
if: ${{ github.ref == 'refs/heads/main' }}
|
||||
if: ${{ github.ref == 'refs/heads/ue' && github.repository == 'blitzkit/host-beta' }}
|
||||
name: Deploy to GitHub Pages
|
||||
runs-on: ubuntu-latest
|
||||
needs: build
|
||||
@@ -22,7 +22,7 @@ depots
|
||||
public/sitemap*
|
||||
/firebase.json
|
||||
target
|
||||
# packages/core/src/protos/*.ts
|
||||
packages/website-ue/src/protos/*.ts
|
||||
/.vercel
|
||||
.astro
|
||||
.vercel
|
||||
|
||||
@@ -1,3 +1,6 @@
|
||||
[submodule "packages/closed"]
|
||||
path = packages/closed
|
||||
url = https://github.com/blitzkit/closed.git
|
||||
[submodule "packages/cue4parse"]
|
||||
path = packages/cue4parse
|
||||
url = https://github.com/FabianFG/CUE4Parse.git
|
||||
@@ -1,4 +1,6 @@
|
||||
{
|
||||
"js/ts.experimental.useTsgo": true,
|
||||
"protobuf.includes": ["${workspaceFolder}/path/to/protos"],
|
||||
"cSpell.words": [
|
||||
"AABBOX",
|
||||
"Abhi",
|
||||
@@ -62,8 +64,10 @@
|
||||
"Ddpf",
|
||||
"Ddsd",
|
||||
"deadrail",
|
||||
"DEBUFF",
|
||||
"debugflags",
|
||||
"deburr",
|
||||
"deburred",
|
||||
"decalmask",
|
||||
"decompressor",
|
||||
"décor",
|
||||
@@ -147,6 +151,7 @@
|
||||
"noout",
|
||||
"normalmap",
|
||||
"oneof",
|
||||
"Oodle",
|
||||
"oopsies",
|
||||
"Oopsy",
|
||||
"opentest",
|
||||
@@ -162,6 +167,7 @@
|
||||
"playerachievements",
|
||||
"playerinfo",
|
||||
"playform",
|
||||
"Playtest",
|
||||
"pngjs",
|
||||
"POSITIVEX",
|
||||
"POSITIVEY",
|
||||
@@ -178,6 +184,7 @@
|
||||
"ratingleaderboard",
|
||||
"raycaster",
|
||||
"Redirector",
|
||||
"REGEN",
|
||||
"Relogin",
|
||||
"researchable",
|
||||
"Resvg",
|
||||
@@ -191,11 +198,14 @@
|
||||
"searchplayers",
|
||||
"searchtanks",
|
||||
"SHAREDEXP",
|
||||
"Skia",
|
||||
"SKLLD",
|
||||
"sluggify",
|
||||
"smoothstep",
|
||||
"Smri",
|
||||
"Specularity",
|
||||
"SSAO",
|
||||
"stackable",
|
||||
"startcase",
|
||||
"statkit",
|
||||
"statsfull",
|
||||
@@ -219,6 +229,7 @@
|
||||
"tungstentip",
|
||||
"Turretless",
|
||||
"TYPELESS",
|
||||
"uasset",
|
||||
"ubjson",
|
||||
"Unicum",
|
||||
"UNLOCALIZED",
|
||||
@@ -228,6 +239,7 @@
|
||||
"unrotate",
|
||||
"unwrapper",
|
||||
"userns",
|
||||
"usmap",
|
||||
"vercel",
|
||||
"vickers",
|
||||
"vitepress",
|
||||
@@ -240,6 +252,7 @@
|
||||
"winrate",
|
||||
"wireframe",
|
||||
"Woah",
|
||||
"wooorm",
|
||||
"WOTB",
|
||||
"wotblitz",
|
||||
"wotbreplay",
|
||||
@@ -252,6 +265,5 @@
|
||||
"youtuber",
|
||||
"youtubers",
|
||||
"zoomable"
|
||||
],
|
||||
"typescript.tsdk": "node_modules\\typescript\\lib"
|
||||
]
|
||||
}
|
||||
@@ -1,10 +0,0 @@
|
||||
{
|
||||
"folders": [
|
||||
{
|
||||
"path": ".",
|
||||
},
|
||||
{
|
||||
"path": "C:/Program Files/WindowsApps/7458BE2C.WorldofTanksBlitz_11.1.256.0_x64__x4tje2y229k00/Data",
|
||||
},
|
||||
],
|
||||
}
|
||||
@@ -1,51 +1,25 @@
|
||||
{
|
||||
"name": "blitzkit",
|
||||
"version": "1.30.2",
|
||||
"version": "2.0.0-beta.3",
|
||||
"license": "BlitzKit License",
|
||||
"private": true,
|
||||
"scripts": {
|
||||
"build:assets": "cd packages/scripts && bun run build:assets",
|
||||
"build:averages": "bun --filter=@blitzkit/scripts run build:averages",
|
||||
"build:bot": "cd packages/scripts && bun run build:bot",
|
||||
"build:website": "cd packages/website && bun run build",
|
||||
"build:prisma": "prisma generate",
|
||||
"build:game": "cd packages/game && bun run build",
|
||||
"build:website": "cd packages/website-ue && bun run build",
|
||||
"build:proxyclient": "cd packages/scripts && bun run build:proxyclient",
|
||||
"build:catalogitemaccesssor": "cd packages/scripts && bun run build:catalogitemaccesssor",
|
||||
"build:ratingleaderboard": "cd packages/scripts && bun run build:ratingleaderboard",
|
||||
"build:app": "cd packages/app && bun run build",
|
||||
"dev:bot": "bun run build:bot --dev && bun start:bot --dev",
|
||||
"start:bot": "bun dist/bot/main.js",
|
||||
"dev:docs": "vitepress dev docs",
|
||||
"dev:website": "cd packages/website && bun run dev",
|
||||
"dev:app": "cd packages/app && bun run dev",
|
||||
"dev": "bun run dev:website",
|
||||
"dev:api": "bun --filter=@blitzkit/api run dev",
|
||||
"setup:depotdownloader": "bun --filter=@blitzkit/scripts run setup:depotdownloader",
|
||||
"setup:patches": "bun --filter=@blitzkit/scripts run setup:patches",
|
||||
"start:website": "bun --filter=@blitzkit/website run start",
|
||||
"host:docs": "vitepress preview docs",
|
||||
"lint": "tsc",
|
||||
"lint:website": "cd packages/website && bun run lint",
|
||||
"format": "prettier --write \"**/*.@(json|js|jsx|css|md|ts|tsx|html|xml|yml|gltf)\"",
|
||||
"update": "yarn upgrade --latest",
|
||||
"tunnel": "cloudflared tunnel --url http://localhost:3000",
|
||||
"discoverids": "scripts/discoverIds.ts",
|
||||
"build:protos": "cd packages/scripts && bun run build:protos",
|
||||
"preview:website": "cd packages/website && bun run preview",
|
||||
"build:reviews": "cd packages/scripts && bun build:reviews",
|
||||
"build:ids": "cd packages/scripts && bun build:ids",
|
||||
"prunestrings": "cd packages/scripts && bun prunestrings",
|
||||
"setup": "bun install && bun run build:prisma && bun run build:proxyclient",
|
||||
"patchnotes": "cd packages/scripts && bun run patchnotes"
|
||||
"dev": "bun run dev:website",
|
||||
"dev:website": "cd packages/website-ue && bun run dev",
|
||||
"lint": "tsc",
|
||||
"lint:website": "cd packages/website-ue && bun run lint",
|
||||
"setup": "bun install && bun run build:protos && bun run build:proxyclient && bun run build:catalogitemaccesssor"
|
||||
},
|
||||
"type": "module",
|
||||
"workspaces": [
|
||||
"packages/*"
|
||||
],
|
||||
"dependencies": {
|
||||
"@prisma/client": "^6.18.0",
|
||||
"prisma": "^6.18.0",
|
||||
"sharp": "^0.34.5",
|
||||
"typescript": "^5.9.3"
|
||||
}
|
||||
}
|
||||
@@ -1,49 +1,50 @@
|
||||
export * from './assertSecret';
|
||||
export * from './asset';
|
||||
export * from './availableProvisions';
|
||||
export * from './averageDefinitions';
|
||||
export * from "./assertSecret";
|
||||
export * from "./asset";
|
||||
export * from "./availableProvisions";
|
||||
export * from "./averageDefinitions";
|
||||
// export * from './camouflageDefinitions';
|
||||
// export * from './checkConsumableProvisionInclusivity';
|
||||
export * from './coefficient';
|
||||
export * from './consumableDefinitions';
|
||||
export * from "./coefficient";
|
||||
export * from "./consumableDefinitions";
|
||||
// export * from './context';
|
||||
export * from './createDefaultSkills';
|
||||
export * from './degressiveStat';
|
||||
export * from './discoveredIdDefinitions';
|
||||
export * from './emblemURL';
|
||||
export * from './equipmentDefinitions';
|
||||
export * from './eventManager';
|
||||
export * from './gameDefinitions';
|
||||
export * from './getArchivedLatestSeasonNumber';
|
||||
export * from "./createDefaultSkills";
|
||||
export * from "./degressiveStat";
|
||||
export * from "./discoveredIdDefinitions";
|
||||
export * from "./emblemURL";
|
||||
export * from "./equipmentDefinitions";
|
||||
export * from "./eventManager";
|
||||
export * from "./gameDefinitions";
|
||||
export * from "./getArchivedLatestSeasonNumber";
|
||||
// export * from './getArchivedRatingInfo';
|
||||
export * from './getArchivedRatingLeaderboard';
|
||||
export * from "./getArchivedRatingLeaderboard";
|
||||
// export * from './getArchivedRatingMidnightLeaderboard';
|
||||
export * from './getTimeDaysAgo';
|
||||
export * from './isExplosive';
|
||||
export * from './mapDefinitions';
|
||||
export * from './modelDefinitions';
|
||||
export * from './normalizeBoundingBox';
|
||||
export * from "./getTimeDaysAgo";
|
||||
export * from "./isExplosive";
|
||||
export * from "./mapDefinitions";
|
||||
export * from "./modelDefinitions";
|
||||
export * from "./normalizeBoundingBox";
|
||||
// export * from './parseBkni';
|
||||
// export * from './patientFetch';
|
||||
export * from './patientFetchJSON';
|
||||
export * from './progressiveStat';
|
||||
export * from './provisionDefinitions';
|
||||
export * from './resolveDpm';
|
||||
export * from './resolvePenetrationCoefficient';
|
||||
export * from './reviews';
|
||||
export * from './skillDefinitions';
|
||||
export * from './sum';
|
||||
export * from './tankDefinitions';
|
||||
export * from './tankIcon';
|
||||
export * from './tankNames';
|
||||
export * from './unionBoundingBox';
|
||||
export * from './uniqueGuns';
|
||||
export * from './unwrapBlitzkitResponse';
|
||||
export * from './votes';
|
||||
export * from "./patientFetchJSON";
|
||||
export * from "./progressiveStat";
|
||||
export * from "./provisionDefinitions";
|
||||
export * from "./resolveDpm";
|
||||
export * from "./resolvePenetrationCoefficient";
|
||||
export * from "./reviews";
|
||||
export * from "./skillDefinitions";
|
||||
export * from "./sum";
|
||||
export * from "./tankDefinitions";
|
||||
export * from "./tankIcon";
|
||||
export * from "./tankNames";
|
||||
export * from "./unionBoundingBox";
|
||||
export * from "./uniqueGuns";
|
||||
export * from "./unwrapBlitzkitResponse";
|
||||
export * from "./votes";
|
||||
// export * from './withCORSProxy';
|
||||
export * from './createDefaultProvisions';
|
||||
export * from './gallery';
|
||||
export * from './metaSortTank';
|
||||
export * from './popularTanks';
|
||||
export * from './romanize';
|
||||
export * from './youtubers';
|
||||
export * from "./createDefaultProvisions";
|
||||
export * from "./gallery";
|
||||
export * from "./metaSortTank";
|
||||
export * from "./popularTanks";
|
||||
export * from "./romanize";
|
||||
export * from "./sluggify.ts";
|
||||
export * from "./youtubers";
|
||||
@@ -0,0 +1,16 @@
|
||||
import { deburr } from "lodash-es";
|
||||
|
||||
const nonAlphanumericRegex = /[^a-z0-9]/g;
|
||||
const multipleDashesRegex = /--+/g;
|
||||
const trailingDashRegex = /-$/g;
|
||||
const leadingDashRegex = /^-/g;
|
||||
|
||||
export function sluggify(value: string) {
|
||||
let slug = deburr(value).toLowerCase();
|
||||
slug = slug.replaceAll(nonAlphanumericRegex, "-");
|
||||
slug = slug.replaceAll(multipleDashesRegex, "-");
|
||||
slug = slug.replaceAll(trailingDashRegex, "");
|
||||
slug = slug.replaceAll(leadingDashRegex, "");
|
||||
|
||||
return slug;
|
||||
}
|
||||
@@ -4,7 +4,6 @@ export * from "./imgur";
|
||||
export * from "./math";
|
||||
export * from "./patreon";
|
||||
export * from "./protobuf";
|
||||
export * from "./protos";
|
||||
export * from "./statistics";
|
||||
export * from "./streams";
|
||||
export * from "./types";
|
||||
@@ -3,6 +3,7 @@ export * from "./fisherYates";
|
||||
export * from "./formatCompact";
|
||||
export * from "./isNumber";
|
||||
export * from "./NaNFallback";
|
||||
export * from "./normalizeAngleDeg";
|
||||
export * from "./normalizeAngleRad";
|
||||
export * from "./normalToEuler";
|
||||
export * from "./numberToRomanNumeral";
|
||||
@@ -0,0 +1,6 @@
|
||||
export function normalizeAngleDeg(angle: number) {
|
||||
const newAngle = angle % 360;
|
||||
if (newAngle > 360) return newAngle - 360;
|
||||
if (newAngle < -360) return newAngle + 360;
|
||||
return newAngle;
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
[*.cs]
|
||||
indent_style = space
|
||||
indent_size = 2
|
||||
@@ -0,0 +1,57 @@
|
||||
## A streamlined .gitignore for modern .NET projects
|
||||
## including temporary files, build results, and
|
||||
## files generated by popular .NET tools. If you are
|
||||
## developing with Visual Studio, the VS .gitignore
|
||||
## https://github.com/github/gitignore/blob/main/VisualStudio.gitignore
|
||||
## has more thorough IDE-specific entries.
|
||||
##
|
||||
## Get latest from https://github.com/github/gitignore/blob/main/Dotnet.gitignore
|
||||
|
||||
# Build results
|
||||
[Dd]ebug/
|
||||
[Dd]ebugPublic/
|
||||
[Rr]elease/
|
||||
[Rr]eleases/
|
||||
x64/
|
||||
x86/
|
||||
[Ww][Ii][Nn]32/
|
||||
[Aa][Rr][Mm]/
|
||||
[Aa][Rr][Mm]64/
|
||||
bld/
|
||||
[Bb]in/
|
||||
[Oo]bj/
|
||||
[Ll]og/
|
||||
[Ll]ogs/
|
||||
|
||||
# .NET Core
|
||||
project.lock.json
|
||||
project.fragment.lock.json
|
||||
artifacts/
|
||||
|
||||
# ASP.NET Scaffolding
|
||||
ScaffoldingReadMe.txt
|
||||
|
||||
# NuGet Packages
|
||||
*.nupkg
|
||||
# NuGet Symbol Packages
|
||||
*.snupkg
|
||||
|
||||
# dotenv environment variables file
|
||||
.env
|
||||
|
||||
# Others
|
||||
~$*
|
||||
*~
|
||||
CodeCoverage/
|
||||
|
||||
# MSBuild Binary and Structured Log
|
||||
*.binlog
|
||||
|
||||
# MSTest test Results
|
||||
[Tt]est[Rr]esult*/
|
||||
[Bb]uild[Ll]og.*
|
||||
|
||||
# NUnit
|
||||
*.VisualState.xml
|
||||
TestResult.xml
|
||||
nunit-*.xml
|
||||
@@ -0,0 +1,114 @@
|
||||
using System.IO;
|
||||
using System.Text.RegularExpressions;
|
||||
using BlitzKit.Game.Models;
|
||||
using CUE4Parse_Conversion.Textures;
|
||||
using CUE4Parse.UE4.Assets.Exports.Texture;
|
||||
using CUE4Parse.UE4.Objects.Engine;
|
||||
using CUE4Parse.UE4.Objects.UObject;
|
||||
using Microsoft.JavaScript.NodeApi;
|
||||
using SkiaSharp;
|
||||
|
||||
namespace BlitzKit.Game.JSExport;
|
||||
|
||||
[JSExport]
|
||||
public partial class GameInterface
|
||||
{
|
||||
private readonly BlitzFileProvider provider;
|
||||
|
||||
public string[] files;
|
||||
public string[] tanksDirectoryNations;
|
||||
|
||||
public GameInterface(string directory)
|
||||
{
|
||||
provider = new(directory);
|
||||
|
||||
files = [.. provider.Files.Keys];
|
||||
|
||||
var tanksBase = "Blitz/Content/Tanks/";
|
||||
tanksDirectoryNations =
|
||||
[
|
||||
.. files
|
||||
.Where(path => path.StartsWith(tanksBase))
|
||||
.Select(path => path[tanksBase.Length..])
|
||||
.Select(path => path.Split('/')[0])
|
||||
.Where(nation => !nation.EndsWith(".uasset") && nation != "TankStub")
|
||||
.Distinct(),
|
||||
];
|
||||
}
|
||||
|
||||
public string[] Files => files;
|
||||
public string[] TanksDirectoryNations => tanksDirectoryNations;
|
||||
|
||||
public byte[] TankBigIcon(string tankId, string pdaName)
|
||||
{
|
||||
foreach (var nation in tanksDirectoryNations)
|
||||
{
|
||||
var path = $"Blitz/Content/Tanks/{nation}/{tankId}/{pdaName}.{pdaName}";
|
||||
|
||||
if (provider.TryLoadPackageObject<UPrimaryDataAsset>(path, out var pda))
|
||||
{
|
||||
FSoftObjectPath objectPath = pda.Get<FSoftObjectPath>("BigIcon");
|
||||
UTexture2D uTexture = objectPath.Load<UTexture2D>();
|
||||
CTexture? cTexture = uTexture.Decode(ETexturePlatform.DesktopMobile);
|
||||
|
||||
if (cTexture is null)
|
||||
{
|
||||
return [];
|
||||
}
|
||||
|
||||
SKBitmap bitmap = cTexture.ToSkBitmap();
|
||||
SKData data = bitmap.Encode(SKEncodedImageFormat.Webp, 80);
|
||||
byte[] bytes = data.ToArray();
|
||||
|
||||
return bytes;
|
||||
}
|
||||
}
|
||||
|
||||
return [];
|
||||
}
|
||||
|
||||
[GeneratedRegex(@"T_UI_Flag_(\w+)_S")]
|
||||
private static partial Regex FlagNameRegex();
|
||||
|
||||
public byte[] Flag(string nation)
|
||||
{
|
||||
var flagsBase = "Blitz/Content/UI/Textures/Flag/TankCard/";
|
||||
|
||||
foreach (var path in provider.Files.Keys)
|
||||
{
|
||||
if (!path.StartsWith(flagsBase))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
var fileName = Path.GetFileNameWithoutExtension(path);
|
||||
var match = FlagNameRegex().Match(fileName);
|
||||
|
||||
if (
|
||||
match.Success
|
||||
&& match.Groups[1].Value.Equals(nation, StringComparison.CurrentCultureIgnoreCase)
|
||||
)
|
||||
{
|
||||
if (provider.TryLoadPackageObject<UTexture2D>($"{path}.{fileName}", out var uTexture))
|
||||
{
|
||||
CTexture? cTexture = uTexture.Decode(ETexturePlatform.DesktopMobile);
|
||||
|
||||
if (cTexture is null)
|
||||
{
|
||||
return [];
|
||||
}
|
||||
|
||||
SKBitmap bitmap = cTexture.ToSkBitmap();
|
||||
SKData data = bitmap.Encode(SKEncodedImageFormat.Webp, 80);
|
||||
byte[] bytes = data.ToArray();
|
||||
|
||||
return bytes;
|
||||
}
|
||||
|
||||
return [];
|
||||
}
|
||||
}
|
||||
|
||||
return [];
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
using System.Runtime.InteropServices;
|
||||
using CUE4Parse.Compression;
|
||||
using CUE4Parse.FileProvider;
|
||||
using CUE4Parse.MappingsProvider;
|
||||
using CUE4Parse.UE4.Versions;
|
||||
|
||||
namespace BlitzKit.Game.Models;
|
||||
|
||||
public class BlitzFileProvider : DefaultFileProvider
|
||||
{
|
||||
public BlitzFileProvider(string directory)
|
||||
: base(
|
||||
directory: directory,
|
||||
searchOption: SearchOption.AllDirectories,
|
||||
versions: new(EGame.GAME_UE5_5),
|
||||
pathComparer: StringComparer.OrdinalIgnoreCase
|
||||
)
|
||||
{
|
||||
MappingsContainer = new FileUsmapTypeMappingsProvider("../../packages/closed/blitz.usmap");
|
||||
|
||||
Initialize();
|
||||
Mount();
|
||||
|
||||
// OodleHelper.DownloadOodleDll($"../../temp/oodle.so");
|
||||
OodleHelper.Initialize($"../../temp/oodle.so");
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
<PropertyGroup>
|
||||
<RootNamespace>BlitzKit.Game</RootNamespace>
|
||||
<TargetFramework>net9.0</TargetFramework>
|
||||
<!-- <RuntimeIdentifier>win-x64</RuntimeIdentifier> -->
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
<Nullable>enable</Nullable>
|
||||
<NodeApiAssemblyJSModuleType>esm</NodeApiAssemblyJSModuleType>
|
||||
<CopyLocalLockFileAssemblies>true</CopyLocalLockFileAssemblies>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="../cue4parse/CUE4Parse/CUE4Parse.csproj" />
|
||||
<ProjectReference Include="../cue4parse/CUE4Parse-Conversion/CUE4Parse-Conversion.csproj" />
|
||||
<PackageReference Include="Microsoft.JavaScript.NodeApi" Version="0.9.19" />
|
||||
<PackageReference Include="Microsoft.JavaScript.NodeApi.Generator" Version="0.9.19" />
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
@@ -0,0 +1,3 @@
|
||||
<Solution>
|
||||
<Project Path="game.csproj" />
|
||||
</Solution>
|
||||
@@ -0,0 +1,12 @@
|
||||
{
|
||||
"name": "@blitzkit/game",
|
||||
"private": true,
|
||||
"type": "module",
|
||||
"main": "src/index.ts",
|
||||
"scripts": {
|
||||
"build": "dotnet build"
|
||||
},
|
||||
"dependencies": {
|
||||
"node-api-dotnet": "^0.9.19"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
export * from "../bin/Debug/net9.0/game";
|
||||
@@ -1,4 +1,2 @@
|
||||
export * from "./literals";
|
||||
export * from "./strings";
|
||||
export * from "./unwrapper";
|
||||
export * from "./wrapper";
|
||||
@@ -1,16 +1,45 @@
|
||||
export function literals(
|
||||
string: string,
|
||||
literals?: Record<string, string | number | undefined>
|
||||
literals?: Record<string, string | number | undefined>,
|
||||
) {
|
||||
for (const key in literals) {
|
||||
const mutated = string.replaceAll(`{${key}}`, `${literals[key]}`);
|
||||
|
||||
if (import.meta.env.DEV && mutated === string) {
|
||||
console.warn(`Could not find literal {${key}} in string "${string}"`);
|
||||
}
|
||||
|
||||
string = mutated;
|
||||
string = string.replaceAll(`{${key}}`, `${literals[key]}`);
|
||||
}
|
||||
|
||||
return string;
|
||||
}
|
||||
|
||||
export function literalsArray<Type, Literal = Type | string>(
|
||||
string: string,
|
||||
literals?: Record<string, Literal>,
|
||||
) {
|
||||
if (!literals) return [string];
|
||||
|
||||
let array: (string | Literal)[] = [string];
|
||||
|
||||
for (const key in literals) {
|
||||
const value = literals[key];
|
||||
const next: (string | Literal)[] = [];
|
||||
|
||||
for (const chunk of array) {
|
||||
if (typeof chunk !== "string") {
|
||||
next.push(chunk);
|
||||
continue;
|
||||
}
|
||||
|
||||
const parts = chunk.split(`{${key}}`);
|
||||
|
||||
for (let index = 0; index < parts.length; index++) {
|
||||
if (parts[index]) next.push(parts[index]);
|
||||
|
||||
if (index < parts.length - 1) {
|
||||
next.push(value);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
array = next;
|
||||
}
|
||||
|
||||
return array;
|
||||
}
|
||||
@@ -1,68 +1,3 @@
|
||||
import { merge } from "ts-deepmerge";
|
||||
import locales from "../locales.json";
|
||||
import en from "../strings/en.json";
|
||||
import es from "../strings/es.json";
|
||||
import fr from "../strings/fr.json";
|
||||
import ja from "../strings/ja.json";
|
||||
import pl from "../strings/pl.json";
|
||||
import pt from "../strings/pt.json";
|
||||
import ru from "../strings/ru.json";
|
||||
import uk from "../strings/uk.json";
|
||||
import zh from "../strings/zh.json";
|
||||
import type en from "../strings/en.json";
|
||||
|
||||
export type BlitzKitStrings = typeof en;
|
||||
|
||||
const stringsRaw: Record<string, TranslationTree> = {
|
||||
en,
|
||||
es,
|
||||
fr,
|
||||
ja,
|
||||
pl,
|
||||
pt,
|
||||
ru,
|
||||
uk,
|
||||
zh,
|
||||
};
|
||||
|
||||
export const STRINGS: Record<string, BlitzKitStrings> = {};
|
||||
|
||||
for (const locale in stringsRaw) {
|
||||
if (locale === locales.default) {
|
||||
STRINGS[locales.default] = stringsRaw[locales.default] as BlitzKitStrings;
|
||||
continue;
|
||||
}
|
||||
|
||||
const localeStrings = stringsRaw[locale];
|
||||
STRINGS[locale] = merge(
|
||||
stringsRaw[locales.default],
|
||||
localeStrings,
|
||||
) as BlitzKitStrings;
|
||||
}
|
||||
|
||||
export const SUPPORTED_LOCALE_BLITZ_MAP: Record<string, string> = {
|
||||
en: "en",
|
||||
es: "es",
|
||||
fr: "fr",
|
||||
ja: "ja",
|
||||
pt: "pt",
|
||||
ru: "ru",
|
||||
uk: "uk",
|
||||
zh: "zh-Hans",
|
||||
pl: "pl",
|
||||
};
|
||||
|
||||
export const SUPPORTED_LOCALE_FLAGS: Record<string, string> = {
|
||||
en: "🇺🇸",
|
||||
es: "🇪🇸",
|
||||
fr: "🇫🇷",
|
||||
ja: "🇯🇵",
|
||||
pt: "🇵🇹",
|
||||
ru: "🇷🇺",
|
||||
uk: "🇺🇦",
|
||||
zh: "🇨🇳",
|
||||
pl: "🇵🇱",
|
||||
};
|
||||
|
||||
export type TranslationTree = { [key: string]: TranslationNode };
|
||||
|
||||
export type TranslationNode = string | TranslationTree;
|
||||
export type Strings = typeof en;
|
||||
@@ -1,12 +0,0 @@
|
||||
import { I18nString } from "../../core/src";
|
||||
import locales from "../locales.json";
|
||||
|
||||
export function unwrapper(locale = locales.default) {
|
||||
return function (i18nString: I18nString) {
|
||||
if (locale in i18nString.locales) {
|
||||
return i18nString.locales[locale];
|
||||
}
|
||||
|
||||
return i18nString.locales[locales.default];
|
||||
};
|
||||
}
|
||||
@@ -1,15 +0,0 @@
|
||||
import locales from "../locales.json";
|
||||
import { type BlitzKitStrings, STRINGS } from "./strings";
|
||||
|
||||
export function wrapper(slicer: (strings: BlitzKitStrings) => string) {
|
||||
const defaultString = slicer(STRINGS[locales.default] as BlitzKitStrings);
|
||||
|
||||
const object = { [locales.default]: defaultString };
|
||||
|
||||
for (const { locale } of locales.supported) {
|
||||
const string = slicer(STRINGS[locale] as BlitzKitStrings);
|
||||
if (string !== defaultString) object[locale] = string;
|
||||
}
|
||||
|
||||
return object;
|
||||
}
|
||||
@@ -1,6 +1,6 @@
|
||||
import { readdir, readFile, writeFile } from "fs/promises";
|
||||
|
||||
const SOURCES = "../../packages/closed/protos";
|
||||
const SOURCES = "../../packages/closed/protos/game/proto/legacy";
|
||||
const TARGET = "../../packages/closed/src/unreal/catalogItemAccessor.ts";
|
||||
|
||||
const componentPattern = /^message (\w+)Component {/gm;
|
||||
@@ -8,15 +8,15 @@ const componentPattern = /^message (\w+)Component {/gm;
|
||||
const files = await readdir(SOURCES).then((files) =>
|
||||
files.filter(
|
||||
(file) =>
|
||||
file.startsWith("blitz_static_") && file.endsWith("_component.proto")
|
||||
)
|
||||
file.startsWith("blitz_static_") && file.endsWith("_component.proto"),
|
||||
),
|
||||
);
|
||||
|
||||
const imports: { name: string; file: string }[] = [];
|
||||
|
||||
for (const file of files) {
|
||||
const content = await readFile(`${SOURCES}/${file}`).then((buffer) =>
|
||||
buffer.toString()
|
||||
buffer.toString(),
|
||||
);
|
||||
const components = content.matchAll(componentPattern);
|
||||
|
||||
@@ -26,7 +26,7 @@ for (const file of files) {
|
||||
|
||||
if (duplicate) {
|
||||
console.warn(
|
||||
`Duplicate component ${name} across ${duplicate.file}.proto and ${file}`
|
||||
`Duplicate component ${name} across ${duplicate.file}.proto and ${file}`,
|
||||
);
|
||||
continue;
|
||||
}
|
||||
@@ -40,7 +40,7 @@ for (const file of files) {
|
||||
let content = "";
|
||||
|
||||
for (const _import of imports) {
|
||||
content += `import { ${_import.name}Component } from "@protos/${_import.file}";\n`;
|
||||
content += `import { ${_import.name}Component } from "@protos/game/proto/legacy/${_import.file}";\n`;
|
||||
}
|
||||
|
||||
content +=
|
||||
|
||||
@@ -1,7 +1,8 @@
|
||||
import { readFile, writeFile } from "fs/promises";
|
||||
|
||||
const IMPORT = "@protos/auto_legacy_proxy_client";
|
||||
const SOURCE = "../../packages/closed/protos/auto_legacy_proxy_client.proto";
|
||||
const IMPORT = "@protos/game/proto/legacy/auto_legacy_proxy_client";
|
||||
const SOURCE =
|
||||
"../../packages/closed/protos/game/proto/legacy/auto_legacy_proxy_client.proto";
|
||||
const TARGET = "../../packages/closed/src/unreal/methodPopulatedProxyClient.ts";
|
||||
|
||||
const requestPattern = /^message (\w+)Request {/gm;
|
||||
|
||||
@@ -1,20 +1,12 @@
|
||||
import { exec as execSync } from "child_process";
|
||||
import { execFile } from "child_process";
|
||||
import { existsSync } from "fs";
|
||||
import { readdir, rm } from "fs/promises";
|
||||
import { promisify } from "util";
|
||||
import { mkdir, readdir, rm, writeFile } from "fs/promises";
|
||||
|
||||
const MAX_COMMAND_LENGTH = 2 ** 11;
|
||||
const TS_PROTO_EXECUTABLE_LOCATIONS = [
|
||||
"./node_modules/.bin/protoc-gen-ts_proto",
|
||||
"../../node_modules/.bin/protoc-gen-ts_proto",
|
||||
];
|
||||
|
||||
const roots = [
|
||||
"../../packages/core/src/protos",
|
||||
"../../packages/closed/protos",
|
||||
];
|
||||
|
||||
const exec = promisify(execSync);
|
||||
const ROOT = "../../packages/closed/protos";
|
||||
|
||||
let tsProtoExecutableLocation: string | undefined = undefined;
|
||||
|
||||
@@ -36,42 +28,36 @@ if (!tsProtoExecutableLocation) {
|
||||
);
|
||||
}
|
||||
|
||||
for (const root of roots) {
|
||||
const filesRaw = await readdir(`${root}`);
|
||||
const files: string[] = [];
|
||||
await mkdir("temp", { recursive: true });
|
||||
|
||||
for (const file of filesRaw) {
|
||||
if (file.endsWith(".proto")) files.push(file);
|
||||
if (file.endsWith(".ts")) await rm(`${root}/${file}`);
|
||||
let args = "";
|
||||
|
||||
args += `-I=${ROOT}\n`;
|
||||
args += `--plugin=${tsProtoExecutableLocation}\n`;
|
||||
args += "--ts_proto_opt=esModuleInterop=true\n";
|
||||
args += "--ts_proto_opt=oneof=unions-value\n";
|
||||
args += "--ts_proto_opt=unrecognizedEnum=false\n";
|
||||
args += "--ts_proto_opt=snakeToCamel=false\n";
|
||||
args += `--ts_proto_out=${ROOT}\n`;
|
||||
|
||||
const filesRaw = await readdir(`${ROOT}`, { recursive: true });
|
||||
const files: string[] = [];
|
||||
|
||||
for (const file of filesRaw) {
|
||||
if (file.endsWith(".proto")) {
|
||||
files.push(file);
|
||||
args += `${ROOT}/${file}\n`;
|
||||
}
|
||||
|
||||
while (files.length > 0) {
|
||||
let command = [
|
||||
"protoc",
|
||||
`--plugin=${tsProtoExecutableLocation}`,
|
||||
"--ts_proto_opt=esModuleInterop=true",
|
||||
"--ts_proto_opt=oneof=unions-value",
|
||||
// "--ts_proto_opt=removeEnumPrefix=true",
|
||||
"--ts_proto_opt=unrecognizedEnum=false",
|
||||
"--ts_proto_opt=snakeToCamel=false",
|
||||
`--ts_proto_out=${root}`,
|
||||
`-I=${root}`,
|
||||
].join(" ");
|
||||
|
||||
while (true) {
|
||||
if (files.length === 0) break;
|
||||
|
||||
const file = files.at(-1);
|
||||
const newLine = ` ${root}/${file}`;
|
||||
|
||||
if (command.length + newLine.length < MAX_COMMAND_LENGTH) {
|
||||
command += newLine;
|
||||
files.pop();
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
await exec(command);
|
||||
}
|
||||
if (file.endsWith(".ts")) await rm(`${ROOT}/${file}`);
|
||||
}
|
||||
|
||||
await writeFile("temp/protoc.txt", args);
|
||||
|
||||
// throw "";
|
||||
|
||||
execFile("protoc", ["@temp/protoc.txt"], (error, stdout, stderr) => {
|
||||
if (error) throw new Error(error.message);
|
||||
if (stderr) console.error(stderr);
|
||||
if (stdout) console.log(stdout);
|
||||
});
|
||||
@@ -4,8 +4,9 @@
|
||||
"main": "src/index.ts",
|
||||
"dependencies": {
|
||||
"@types/lodash-es": "^4.17.12",
|
||||
"@types/react": "^19.2.14",
|
||||
"immer": "^10.1.3",
|
||||
"lodash-es": "^4.17.21",
|
||||
"react": "^19.1.1"
|
||||
"react": "^19.2.5"
|
||||
}
|
||||
}
|
||||
@@ -11,7 +11,7 @@ export class Varuna<Type, Arguments = void> {
|
||||
|
||||
constructor(
|
||||
private creator: Type | ((...args: Arguments[]) => Type),
|
||||
private persistence?: string
|
||||
private persistence?: string,
|
||||
) {
|
||||
if (typeof creator !== "function") this.initialize(creator);
|
||||
}
|
||||
@@ -100,7 +100,7 @@ export class Varuna<Type, Arguments = void> {
|
||||
}
|
||||
|
||||
use<Slice = Type>(
|
||||
slicer: (state: Type) => Slice = (state) => state as unknown as Slice
|
||||
slicer: (state: Type) => Slice = (state) => state as unknown as Slice,
|
||||
) {
|
||||
return this.useDeferred(slicer, slicer(this.state));
|
||||
}
|
||||
|
||||
@@ -0,0 +1,104 @@
|
||||
import node from "@astrojs/node";
|
||||
import react from "@astrojs/react";
|
||||
import locales from "@blitzkit/i18n/locales.json";
|
||||
import strings from "@blitzkit/i18n/strings/en.json";
|
||||
import { mauve, mauveDark } from "@radix-ui/colors";
|
||||
import favicons from "astro-favicons";
|
||||
import { defineConfig } from "astro/config";
|
||||
import packageJSON from "../../package.json";
|
||||
|
||||
const POSSIBLE_TARGETS = ["app", "web"];
|
||||
|
||||
const target = process.env.PUBLIC_TARGET;
|
||||
|
||||
if (!target || !POSSIBLE_TARGETS.includes(target)) {
|
||||
throw new Error("Invalid target");
|
||||
}
|
||||
|
||||
export default defineConfig({
|
||||
devToolbar: { enabled: false },
|
||||
|
||||
vite: {
|
||||
server: { allowedHosts: [] },
|
||||
|
||||
esbuild: {
|
||||
minifyIdentifiers: true,
|
||||
minifySyntax: false,
|
||||
minifyWhitespace: true,
|
||||
},
|
||||
},
|
||||
output: target === "web" ? "static" : "server",
|
||||
site: "https://blitzkit.app",
|
||||
outDir: "../../dist/website",
|
||||
prefetch: { defaultStrategy: "hover", prefetchAll: true },
|
||||
|
||||
build: { concurrency: 4 },
|
||||
adapter: target === "app" ? node({ mode: "standalone" }) : undefined,
|
||||
|
||||
integrations: [
|
||||
favicons({
|
||||
name: strings.common.name,
|
||||
short_name: strings.common.name,
|
||||
|
||||
background: mauveDark.mauve1,
|
||||
themes: [mauve.mauve1, mauveDark.mauve1],
|
||||
appleStatusBarStyle: "black-translucent",
|
||||
|
||||
version: packageJSON.version,
|
||||
|
||||
// shortcuts: Object.values(tools)
|
||||
// .filter((tool) => !tool.disabled && !tool.href)
|
||||
// .map((tool) => {
|
||||
// const stringId = (tool.strings ??
|
||||
// tool.id) as keyof typeof strings.website.tools;
|
||||
|
||||
// return {
|
||||
// name: strings.website.tools[stringId].name,
|
||||
// name_localized: wrapper(
|
||||
// (strings) => strings.website.tools[stringId].name
|
||||
// ),
|
||||
// description: strings.website.tools[stringId].description,
|
||||
// description_localized: wrapper(
|
||||
// (strings) => strings.website.tools[stringId].description
|
||||
// ),
|
||||
// short_name: strings.website.tools[stringId].name,
|
||||
// short_name_localized: wrapper(
|
||||
// (strings) => strings.website.tools[stringId].name
|
||||
// ),
|
||||
// url: `/${tool.id}`,
|
||||
// icon: `public/assets/tools/${tool.id}.webp`,
|
||||
// };
|
||||
// }),
|
||||
|
||||
manifest: {
|
||||
// description: strings.website.home.seo_description,
|
||||
// description_localized: wrapper(
|
||||
// (strings) => strings.website.home.seo_description
|
||||
// ),
|
||||
|
||||
dir: "ltr",
|
||||
categories: ["utilities", "games", "developer", "developer tools"],
|
||||
|
||||
id: "com.tresabhi.blitzkit",
|
||||
start_url: "/",
|
||||
launch_handler: { client_mode: "navigate-new" },
|
||||
display: "fullscreen",
|
||||
display_override: ["fullscreen", "standalone", "minimal-ui"],
|
||||
|
||||
lang: locales.default,
|
||||
orientation: "any",
|
||||
},
|
||||
|
||||
icons: {
|
||||
windows: true,
|
||||
android: true,
|
||||
appleIcon: true,
|
||||
appleStartup: true,
|
||||
favicons: true,
|
||||
yandex: true,
|
||||
},
|
||||
}),
|
||||
|
||||
react(),
|
||||
],
|
||||
});
|
||||
@@ -0,0 +1,60 @@
|
||||
{
|
||||
"name": "@blitzkit/website-ue",
|
||||
"type": "module",
|
||||
"scripts": {
|
||||
"dev": "PUBLIC_TARGET=web astro dev",
|
||||
"build": "PUBLIC_TARGET=web astro build",
|
||||
"preview": "PUBLIC_TARGET=web astro preview",
|
||||
"lint": "PUBLIC_TARGET=web astro check",
|
||||
"astro": "astro"
|
||||
},
|
||||
"dependencies": {
|
||||
"@astrojs/check": "^0.9.4",
|
||||
"@astrojs/node": "^9.4.4",
|
||||
"@astrojs/react": "^4.4.0",
|
||||
"@astrolib/seo": "^1.0.0-beta.8",
|
||||
"@blitzkit/closed": "workspace:*",
|
||||
"@blitzkit/core": "workspace:*",
|
||||
"@blitzkit/game": "workspace:*",
|
||||
"@blitzkit/i18n": "workspace:*",
|
||||
"@bufbuild/protobuf": "^2.10.2",
|
||||
"@fontsource-variable/jetbrains-mono": "^5.2.8",
|
||||
"@fontsource-variable/roboto-flex": "^5.2.8",
|
||||
"@fontsource-variable/roboto-mono": "^5.2.8",
|
||||
"@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",
|
||||
"@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",
|
||||
"@wooorm/starry-night": "^3.9.0",
|
||||
"astro": "^5.14.4",
|
||||
"astro-favicons": "^3.1.5",
|
||||
"autoprefixer": "^10.4.23",
|
||||
"cssnano": "^7.1.2",
|
||||
"fuzzysort": "^3.1.0",
|
||||
"googleapis": "^171.1.0",
|
||||
"hast-util-to-jsx-runtime": "^2.3.6",
|
||||
"immer": "^10.1.3",
|
||||
"lodash-es": "^4.17.21",
|
||||
"postcss": "^8.5.6",
|
||||
"postcss-load-config": "^6.0.1",
|
||||
"postcss-nested": "^7.0.2",
|
||||
"postcss-preset-env": "^11.1.1",
|
||||
"quicklime": "^1.2.0",
|
||||
"react": "^19.2.0",
|
||||
"react-dom": "^19.2.0",
|
||||
"react-markdown": "^10.1.0",
|
||||
"react-promise-suspense": "^0.3.4",
|
||||
"sharp": "^0.34.5",
|
||||
"three": "^0.180.0",
|
||||
"three-stdlib": "^2.36.0",
|
||||
"typescript": "^5.9.3",
|
||||
"varuna": "workspace:*",
|
||||
"vite": "^7.1.9",
|
||||
"yaml": "^2.8.1"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
import cssnano from "cssnano";
|
||||
import type { Config } from "postcss-load-config";
|
||||
import postcssPresetEnv from "postcss-preset-env";
|
||||
|
||||
export default {
|
||||
plugins: [
|
||||
require("autoprefixer"),
|
||||
require("postcss-nested"),
|
||||
|
||||
cssnano({
|
||||
preset: "default",
|
||||
}),
|
||||
|
||||
postcssPresetEnv({
|
||||
features: {},
|
||||
}),
|
||||
],
|
||||
} satisfies Config;
|
||||
|
After Width: | Height: | Size: 5.0 KiB |
|
After Width: | Height: | Size: 5.1 KiB |
|
After Width: | Height: | Size: 4.0 KiB |
|
After Width: | Height: | Size: 4.5 KiB |
|
After Width: | Height: | Size: 5.7 KiB |
|
After Width: | Height: | Size: 48 KiB |
|
After Width: | Height: | Size: 13 KiB |
|
After Width: | Height: | Size: 481 KiB |
@@ -0,0 +1,3 @@
|
||||
<svg width="21" height="54" viewBox="0 0 21 54" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M21 38L10 49H0L11 38L0 27H10L21 38ZM21 1V21L20 22H10L21 11L10 0H20L21 1ZM10 11L0 21V1L10 11Z" fill="white"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 221 B |
@@ -0,0 +1,3 @@
|
||||
<svg width="30" height="52" viewBox="0 0 30 52" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M13.8564 44V52H0V36L13.8564 44ZM30 52H16.1436V44L30 36V52ZM28.8564 18V34L15 42L1.14355 34V18L15 10L28.8564 18ZM13.8564 8L0 16V0H13.8564V8ZM30 16L16.1436 8V0H30V16Z" fill="#EEEEF0"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 294 B |
@@ -0,0 +1,3 @@
|
||||
<svg width="70" height="35" viewBox="0 0 70 35" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M70 32L64 35H0L70 0V32ZM0 32V0H64L0 32Z" fill="#EEEEF0"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 170 B |
|
After Width: | Height: | Size: 453 KiB |
|
After Width: | Height: | Size: 676 KiB |
|
After Width: | Height: | Size: 405 KiB |
|
After Width: | Height: | Size: 187 KiB |
|
After Width: | Height: | Size: 443 KiB |
|
After Width: | Height: | Size: 330 KiB |
|
After Width: | Height: | Size: 715 KiB |
|
After Width: | Height: | Size: 144 KiB |
|
After Width: | Height: | Size: 188 KiB |
|
After Width: | Height: | Size: 367 KiB |
|
After Width: | Height: | Size: 1.0 MiB |
|
After Width: | Height: | Size: 274 KiB |
|
After Width: | Height: | Size: 346 KiB |
|
After Width: | Height: | Size: 208 KiB |
|
After Width: | Height: | Size: 406 KiB |
|
After Width: | Height: | Size: 360 KiB |
|
After Width: | Height: | Size: 193 KiB |
|
After Width: | Height: | Size: 200 KiB |
@@ -0,0 +1,46 @@
|
||||
<svg width="426" height="426" viewBox="0 0 426 426" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M416.628 244.997L235.625 372.974C223.13 381.809 202.87 381.809 190.375 372.974L9.37173 244.997C3.1239 240.58 -3.95076e-06 234.79 0 229V196.6H426V229C426 234.79 422.876 240.58 416.628 244.997Z" fill="#0D2847"/>
|
||||
<path d="M416.628 180.603L235.625 52.6262C223.13 43.7913 202.87 43.7913 190.375 52.6262L9.37172 180.603C-3.12391 189.438 -3.12391 203.762 9.37173 212.597L190.375 340.574C202.87 349.409 223.13 349.409 235.625 340.574L416.628 212.597C429.124 203.762 429.124 189.438 416.628 180.603Z" fill="#D9D9D9"/>
|
||||
<path d="M416.628 180.603L235.625 52.6262C223.13 43.7913 202.87 43.7913 190.375 52.6262L9.37172 180.603C-3.12391 189.438 -3.12391 203.762 9.37173 212.597L190.375 340.574C202.87 349.409 223.13 349.409 235.625 340.574L416.628 212.597C429.124 203.762 429.124 189.438 416.628 180.603Z" fill="url(#paint0_linear_764_240)"/>
|
||||
<path d="M416.628 180.603L235.625 52.6262C223.13 43.7913 202.87 43.7913 190.375 52.6262L9.37172 180.603C-3.12391 189.438 -3.12391 203.762 9.37173 212.597L190.375 340.574C202.87 349.409 223.13 349.409 235.625 340.574L416.628 212.597C429.124 203.762 429.124 189.438 416.628 180.603Z" fill="url(#paint1_linear_764_240)"/>
|
||||
<g filter="url(#filter0_d_764_240)">
|
||||
<path d="M197.056 150.108L201.368 153.051L290.596 213.945L306.6 202.599L310.832 199.599L289.153 184.23L288.86 177.31L335.236 182.298L351.706 170.622L359.102 165.378L288.049 158.111L286.355 118L263.968 133.871L265.867 167.722L217.292 135.762L197.056 150.108Z" fill="#111927" fill-opacity="0.5" shape-rendering="crispEdges"/>
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M192.905 289L74.2242 204.714L70 201.714L116.393 168.767C129.906 159.17 143.124 153.539 156.048 151.875C168.971 150.211 180.919 153.275 191.893 161.069C198.702 165.905 202.718 171.006 203.941 176.372C205.165 181.658 204.302 186.506 201.354 190.918L201.692 191.158C208.978 188.301 216.935 187.286 225.563 188.113C234.247 188.9 242.613 192.151 250.66 197.866C261.803 205.779 266.398 214.825 264.446 225.004C262.551 235.142 254.96 244.929 241.672 254.366L192.905 289ZM221.999 242.08L200.456 257.38L163.905 231.422L185.448 216.123C192.007 211.465 198.473 209.23 204.846 209.42C211.22 209.529 217.193 211.562 222.764 215.519C228.392 219.516 231.31 223.797 231.521 228.364C231.732 232.85 228.558 237.422 221.999 242.08ZM165.937 205.64L146.77 219.252L114.693 196.472L133.861 182.859C140.363 178.241 146.435 175.887 152.076 175.798C157.717 175.708 163.07 177.462 168.135 181.059C173.256 184.696 175.809 188.557 175.796 192.643C175.726 196.69 172.44 201.022 165.937 205.64Z" fill="#111927" fill-opacity="0.5" shape-rendering="crispEdges"/>
|
||||
<path d="M197.056 156.108L290.596 219.945L310.832 205.599L306.6 202.599L289.153 190.23L288.86 183.31L335.236 188.298L359.102 171.378L351.706 170.622L288.049 164.111L286.355 124L263.968 139.871L265.867 173.722L217.292 141.762L201.368 153.051L197.056 156.108Z" fill="#111927" fill-opacity="0.5" shape-rendering="crispEdges"/>
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M192.905 295L70 207.714L74.2242 204.714L116.393 174.767C129.906 165.17 143.124 159.539 156.048 157.875C168.971 156.211 180.919 159.275 191.893 167.069C198.702 171.905 202.718 177.006 203.941 182.372C205.165 187.658 204.302 192.506 201.354 196.918L201.692 197.158C208.978 194.301 216.935 193.286 225.563 194.113C234.247 194.9 242.613 198.151 250.66 203.866C261.803 211.779 266.398 220.825 264.446 231.004C262.551 241.142 254.96 250.929 241.672 260.366L192.905 295ZM221.999 248.08L200.456 263.38L163.905 237.422L185.448 222.123C192.007 217.465 198.473 215.23 204.846 215.42C211.22 215.529 217.193 217.562 222.764 221.519C228.392 225.516 231.31 229.797 231.521 234.364C231.732 238.85 228.558 243.422 221.999 248.08ZM165.937 211.64L146.77 225.252L114.693 202.472L133.861 188.859C140.363 184.241 146.435 181.887 152.076 181.798C157.717 181.708 163.07 183.462 168.135 187.059C173.256 190.696 175.809 194.557 175.796 198.643C175.726 202.69 172.44 207.022 165.937 211.64Z" fill="#111927" fill-opacity="0.5" shape-rendering="crispEdges"/>
|
||||
<path d="M310.832 199.599L306.6 202.599L310.832 205.599V199.599Z" fill="#111927" fill-opacity="0.5" shape-rendering="crispEdges"/>
|
||||
<path d="M359.102 165.378L351.706 170.622L359.102 171.378V165.378Z" fill="#111927" fill-opacity="0.5" shape-rendering="crispEdges"/>
|
||||
<path d="M201.368 153.051L197.056 150.108V156.108L201.368 153.051Z" fill="#111927" fill-opacity="0.5" shape-rendering="crispEdges"/>
|
||||
<path d="M74.2242 204.714L70 201.714V207.714L74.2242 204.714Z" fill="#111927" fill-opacity="0.5" shape-rendering="crispEdges"/>
|
||||
</g>
|
||||
<path d="M197.056 150.108L290.596 213.945L310.832 199.599L289.153 184.23L288.86 177.31L335.236 182.298L359.102 165.378L288.049 158.111L286.355 118L263.968 133.871L265.867 167.722L217.292 135.762L197.056 150.108Z" fill="url(#paint2_linear_764_240)"/>
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M192.905 289L70 201.714L116.393 168.767C129.906 159.17 143.124 153.539 156.048 151.875C168.971 150.211 180.919 153.275 191.893 161.069C198.702 165.905 202.718 171.006 203.941 176.372C205.165 181.658 204.302 186.506 201.354 190.918L201.692 191.158C208.978 188.301 216.935 187.286 225.563 188.113C234.247 188.9 242.613 192.151 250.66 197.866C261.803 205.779 266.398 214.825 264.446 225.004C262.551 235.142 254.96 244.929 241.672 254.366L192.905 289ZM221.999 242.08L200.456 257.38L163.905 231.422L185.448 216.123C192.007 211.465 198.473 209.23 204.846 209.42C211.22 209.529 217.193 211.562 222.764 215.519C228.392 219.516 231.31 223.797 231.521 228.364C231.732 232.85 228.558 237.422 221.999 242.08ZM165.937 205.64L146.77 219.252L114.693 196.472L133.861 182.859C140.363 178.241 146.435 175.887 152.076 175.798C157.717 175.708 163.07 177.462 168.135 181.059C173.256 184.696 175.809 188.557 175.796 192.643C175.726 196.69 172.44 201.022 165.937 205.64Z" fill="url(#paint3_linear_764_240)"/>
|
||||
<defs>
|
||||
<filter id="filter0_d_764_240" x="66" y="116" width="297.103" height="185" filterUnits="userSpaceOnUse" color-interpolation-filters="sRGB">
|
||||
<feFlood flood-opacity="0" result="BackgroundImageFix"/>
|
||||
<feColorMatrix in="SourceAlpha" type="matrix" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0" result="hardAlpha"/>
|
||||
<feOffset dy="2"/>
|
||||
<feGaussianBlur stdDeviation="2"/>
|
||||
<feComposite in2="hardAlpha" operator="out"/>
|
||||
<feColorMatrix type="matrix" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0.25 0"/>
|
||||
<feBlend mode="normal" in2="BackgroundImageFix" result="effect1_dropShadow_764_240"/>
|
||||
<feBlend mode="normal" in="SourceGraphic" in2="effect1_dropShadow_764_240" result="shape"/>
|
||||
</filter>
|
||||
<linearGradient id="paint0_linear_764_240" x1="213" y1="46" x2="213" y2="347.2" gradientUnits="userSpaceOnUse">
|
||||
<stop stop-color="#10243E"/>
|
||||
<stop offset="1" stop-color="#0F1B2D"/>
|
||||
</linearGradient>
|
||||
<linearGradient id="paint1_linear_764_240" x1="127.008" y1="96.51" x2="241.48" y2="334.974" gradientUnits="userSpaceOnUse">
|
||||
<stop stop-color="#262A65"/>
|
||||
<stop offset="1" stop-color="#104D87"/>
|
||||
</linearGradient>
|
||||
<linearGradient id="paint2_linear_764_240" x1="215" y1="98.5" x2="299.5" y2="210.5" gradientUnits="userSpaceOnUse">
|
||||
<stop offset="0.379808" stop-color="#C2E6FF"/>
|
||||
<stop offset="0.706731" stop-color="#70B8FF"/>
|
||||
</linearGradient>
|
||||
<linearGradient id="paint3_linear_764_240" x1="215" y1="98.5" x2="299.5" y2="210.5" gradientUnits="userSpaceOnUse">
|
||||
<stop offset="0.379808" stop-color="#C2E6FF"/>
|
||||
<stop offset="0.706731" stop-color="#70B8FF"/>
|
||||
</linearGradient>
|
||||
</defs>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 7.3 KiB |
@@ -0,0 +1,85 @@
|
||||
---
|
||||
import ApiMacroSee from "./ApiMacroSee.astro";
|
||||
import ApiMacroType from "./ApiMacroType.astro";
|
||||
import { MarkdownCustom } from "./MarkdownCustom";
|
||||
|
||||
interface Props {
|
||||
body: string;
|
||||
locale: string;
|
||||
}
|
||||
|
||||
const macroPattern = /@(\w+) (.+)/;
|
||||
const macros: Record<string, string[]> = {};
|
||||
|
||||
const macroComponents = {
|
||||
see: ApiMacroSee,
|
||||
type: ApiMacroType,
|
||||
};
|
||||
|
||||
const { body: bodyOriginal, locale } = Astro.props;
|
||||
let body = "";
|
||||
|
||||
for (const line of bodyOriginal.split("\n")) {
|
||||
const match = line.match(macroPattern);
|
||||
|
||||
if (match === null) {
|
||||
body += `${line}\n`;
|
||||
continue;
|
||||
}
|
||||
|
||||
const macro = match[1];
|
||||
const value = match[2];
|
||||
|
||||
if (macro in macros) {
|
||||
macros[macro].push(value);
|
||||
} else {
|
||||
macros[macro] = [value];
|
||||
}
|
||||
}
|
||||
---
|
||||
|
||||
<style>
|
||||
.api-description {
|
||||
display: flex;
|
||||
|
||||
.gutter {
|
||||
width: var(--space-2);
|
||||
background: linear-gradient(
|
||||
transparent,
|
||||
var(--gray-6) var(--space-4),
|
||||
var(--gray-6) calc(100% - var(--space-4)),
|
||||
transparent
|
||||
);
|
||||
|
||||
margin: 0 var(--space-4);
|
||||
}
|
||||
|
||||
.content {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: var(--space-4);
|
||||
|
||||
width: 100%;
|
||||
|
||||
padding-top: var(--space-4);
|
||||
padding-bottom: var(--space-3);
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
<div class="api-description">
|
||||
<div class="gutter"></div>
|
||||
<div class="content">
|
||||
<MarkdownCustom {body} />
|
||||
|
||||
{
|
||||
Object.entries(macroComponents).map(([macro, Component]) => {
|
||||
if (!(macro in macros)) return null;
|
||||
|
||||
return macros[macro].map((value) => {
|
||||
return <Component {locale} value={value} />;
|
||||
});
|
||||
})
|
||||
}
|
||||
</div>
|
||||
</div>
|
||||
@@ -0,0 +1,27 @@
|
||||
---
|
||||
import type { CollectionEntry } from "astro:content";
|
||||
import { api } from "../core/api/dynamic";
|
||||
import ApiDescription from "./ApiDescription.astro";
|
||||
import { ApiTester } from "./ApiTester";
|
||||
|
||||
interface Props {
|
||||
locale: string;
|
||||
api: CollectionEntry<"api">;
|
||||
}
|
||||
|
||||
const { locale, api: apiData } = Astro.props;
|
||||
const strings = await api.strings(locale);
|
||||
const body = apiData.data.docs ?? strings.api.no_docs;
|
||||
---
|
||||
|
||||
<style>
|
||||
.container {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
</style>
|
||||
|
||||
<div class="container">
|
||||
<ApiTester client:idle {locale} path={apiData.id} />
|
||||
<ApiDescription {locale} {body} />
|
||||
</div>
|
||||
@@ -0,0 +1,13 @@
|
||||
---
|
||||
import type { CollectionEntry } from "astro:content";
|
||||
import ApiEntry from "./ApiEntry.astro";
|
||||
|
||||
interface Props {
|
||||
locale: string;
|
||||
apis: CollectionEntry<"api">[];
|
||||
}
|
||||
|
||||
const { apis, locale } = Astro.props;
|
||||
---
|
||||
|
||||
{apis.map((api) => <ApiEntry {locale} {api} />)}
|
||||
@@ -0,0 +1,36 @@
|
||||
---
|
||||
import { sluggify } from "@blitzkit/core";
|
||||
import { Code } from "./Code";
|
||||
import { Link } from "./Link";
|
||||
import { Text } from "./Text";
|
||||
|
||||
interface Props {
|
||||
value: string;
|
||||
locale: string;
|
||||
}
|
||||
|
||||
const bodyPattern = /^([a-z0-9-\/\.\[\]]+) (.+)$/;
|
||||
|
||||
const { value, locale } = Astro.props;
|
||||
|
||||
const match = value.match(bodyPattern);
|
||||
|
||||
if (match === null) {
|
||||
throw new Error(`Invalid value for ApiMacroSee: ${value}`);
|
||||
}
|
||||
|
||||
const path = match[1];
|
||||
const message = match[2];
|
||||
---
|
||||
|
||||
<Text>
|
||||
<Text lowContrast weight="medium" color="tomato">
|
||||
<Code>@see</Code>
|
||||
</Text>
|
||||
|
||||
<Link underline="never" href={`#${sluggify(path)}`}>
|
||||
<Code>{path}</Code>
|
||||
</Link>
|
||||
|
||||
{message}
|
||||
</Text>
|
||||
@@ -0,0 +1,203 @@
|
||||
---
|
||||
import { ArrowBottomRightIcon } from "@radix-ui/react-icons";
|
||||
import { resolve } from "path";
|
||||
import {
|
||||
createProgram,
|
||||
forEachChild,
|
||||
isArrayTypeNode,
|
||||
isInterfaceDeclaration,
|
||||
isPropertySignature,
|
||||
isTypeNode,
|
||||
isTypeReferenceNode,
|
||||
type InterfaceDeclaration,
|
||||
type Node,
|
||||
type Symbol,
|
||||
type TypeNode,
|
||||
} from "typescript";
|
||||
import { api } from "../core/api/dynamic";
|
||||
import { Code } from "./Code";
|
||||
import HighlightedCodeBlock from "./HighlightedCodeBlock.astro";
|
||||
import { Link } from "./Link";
|
||||
import { Text } from "./Text";
|
||||
|
||||
interface Props {
|
||||
value: string;
|
||||
locale: string;
|
||||
}
|
||||
|
||||
const DEFAULT_EXPANDED = 8;
|
||||
|
||||
const { value, locale } = Astro.props;
|
||||
const strings = await api.strings(locale);
|
||||
|
||||
const lang = "ts";
|
||||
const root = "../../packages/closed/protos";
|
||||
|
||||
const [route, name] = value.split(".");
|
||||
const path = resolve(`${root}/${route}.ts`);
|
||||
|
||||
const program = createProgram([path], {});
|
||||
const source = program.getSourceFile(path);
|
||||
|
||||
if (source === undefined) {
|
||||
throw new Error(`Could not find ${path}`);
|
||||
}
|
||||
|
||||
const checker = program.getTypeChecker();
|
||||
const collected = new Map<string, string>();
|
||||
const visited = new Set<Symbol>();
|
||||
let declaration: InterfaceDeclaration | undefined;
|
||||
|
||||
forEachChild(source, (node) => {
|
||||
if (isInterfaceDeclaration(node) && node.name.text === name) {
|
||||
declaration = node;
|
||||
}
|
||||
});
|
||||
|
||||
if (declaration === undefined) {
|
||||
throw new Error(`Could not find ${name} in ${path}`);
|
||||
}
|
||||
|
||||
function collectNodes(node: Node) {
|
||||
if (isInterfaceDeclaration(node)) {
|
||||
const symbol = checker.getSymbolAtLocation(node.name);
|
||||
|
||||
if (symbol) {
|
||||
const text = node.getText();
|
||||
|
||||
collected.set(node.name.text, text);
|
||||
|
||||
node.members.forEach((member) => {
|
||||
if (isPropertySignature(member) && member.type) {
|
||||
collectTypes(member.type);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
forEachChild(node, collectNodes);
|
||||
}
|
||||
|
||||
function collectTypes(node: TypeNode) {
|
||||
if (isArrayTypeNode(node)) {
|
||||
collectTypes(node.elementType);
|
||||
return;
|
||||
}
|
||||
|
||||
if (isTypeReferenceNode(node)) {
|
||||
node.typeArguments?.forEach(collectTypes);
|
||||
}
|
||||
|
||||
const type = checker.getTypeAtLocation(node);
|
||||
const symbol = type.getSymbol();
|
||||
|
||||
if (!symbol || visited.has(symbol)) return;
|
||||
|
||||
visited.add(symbol);
|
||||
|
||||
const declarations = symbol.getDeclarations();
|
||||
|
||||
if (!declarations) return;
|
||||
|
||||
for (const declaration of declarations) {
|
||||
if (isInterfaceDeclaration(declaration)) {
|
||||
collected.set(declaration.name.text, declaration.getText());
|
||||
|
||||
declaration.members.forEach((member) => {
|
||||
if (isPropertySignature(member) && member.type) {
|
||||
collectTypes(member.type);
|
||||
}
|
||||
});
|
||||
} else {
|
||||
forEachChild(declaration, (child) => {
|
||||
if (isTypeNode(child)) collectTypes(child);
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
collectNodes(declaration);
|
||||
|
||||
let content = "";
|
||||
|
||||
for (const [, definition] of collected) {
|
||||
content += `${definition}\n\n`;
|
||||
}
|
||||
|
||||
content = content.replaceAll(/^export\s*/gm, "");
|
||||
content = content.trim();
|
||||
---
|
||||
|
||||
<style>
|
||||
.macro {
|
||||
color: var(--gray-11);
|
||||
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: var(--space-2);
|
||||
}
|
||||
|
||||
.types {
|
||||
overflow: hidden;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
|
||||
position: relative;
|
||||
|
||||
&:not([data-expanded="true"]) {
|
||||
max-height: 16rem;
|
||||
}
|
||||
|
||||
&[data-expanded="true"] {
|
||||
.overlay {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
|
||||
.overlay {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
|
||||
background: linear-gradient(transparent, var(--gray-1));
|
||||
|
||||
display: flex;
|
||||
align-items: end;
|
||||
justify-content: center;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
<script>
|
||||
const viewers = document.querySelectorAll(".view-full");
|
||||
|
||||
for (const viewer of viewers) {
|
||||
viewer.addEventListener("click", () => {
|
||||
viewer.parentElement!.parentElement!.dataset.expanded = "true";
|
||||
});
|
||||
}
|
||||
</script>
|
||||
|
||||
<div class="macro">
|
||||
<Text lowContrast weight="medium" color="tomato">
|
||||
<Code>@types</Code>
|
||||
</Text>
|
||||
|
||||
<ArrowBottomRightIcon />
|
||||
</div>
|
||||
|
||||
<div
|
||||
class="types"
|
||||
data-expanded={content.split("\n").length <= DEFAULT_EXPANDED}
|
||||
>
|
||||
<HighlightedCodeBlock {lang} content={content} />
|
||||
|
||||
<div class="overlay">
|
||||
<Link underline="always" href="#" className="view-full">
|
||||
{strings.api.view_full}
|
||||
</Link>
|
||||
</div>
|
||||
</div>
|
||||
@@ -0,0 +1,11 @@
|
||||
.tester {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: var(--space-4);
|
||||
|
||||
.title {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: var(--space-2);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,89 @@
|
||||
import { sluggify } from "@blitzkit/core";
|
||||
import { PlayIcon } from "@radix-ui/react-icons";
|
||||
import { Fragment, useState } from "react";
|
||||
import {
|
||||
LocaleProvider,
|
||||
type LocaleAcceptorProps,
|
||||
} from "../../hooks/useLocale";
|
||||
import { useStrings } from "../../hooks/useStrings";
|
||||
import { Button } from "../Button";
|
||||
import { Code } from "../Code";
|
||||
import { Link } from "../Link";
|
||||
import { Text } from "../Text";
|
||||
import { TextField } from "../TextField";
|
||||
import styles from "./index.module.css";
|
||||
|
||||
interface Props {
|
||||
path: string;
|
||||
}
|
||||
|
||||
const slugPattern = /\[\w+\]/g;
|
||||
|
||||
function Content({ path }: Props) {
|
||||
const strings = useStrings();
|
||||
|
||||
const slugs = (path.match(slugPattern) ?? []).map((slug) =>
|
||||
slug.slice(1, -1),
|
||||
);
|
||||
const [values, setValues] = useState(() => {
|
||||
const values: Record<string, string> = {};
|
||||
|
||||
for (const slug of slugs) {
|
||||
values[slug] = "";
|
||||
}
|
||||
|
||||
return values;
|
||||
});
|
||||
|
||||
const href = Object.entries(values).reduce(
|
||||
(href, [slug, value]) => href.replace(`[${slug}]`, value),
|
||||
`/api/${path}`,
|
||||
);
|
||||
|
||||
return (
|
||||
<div className={styles.tester} id={sluggify(path)}>
|
||||
<Text weight="medium">
|
||||
<Code className={styles.title}>
|
||||
{path.split(slugPattern).map((text, index) => {
|
||||
const slug = slugs[index - 1];
|
||||
|
||||
return (
|
||||
<Fragment key={index}>
|
||||
{index > 0 && (
|
||||
<TextField
|
||||
variant="form"
|
||||
className={styles.slug}
|
||||
placeholder={`[${slug}]`}
|
||||
align="center"
|
||||
autoWidth
|
||||
onChange={(event) => {
|
||||
setValues((state) => ({
|
||||
...state,
|
||||
[slug]: event.target.value,
|
||||
}));
|
||||
}}
|
||||
/>
|
||||
)}
|
||||
<span key={index}>{text}</span>
|
||||
</Fragment>
|
||||
);
|
||||
})}
|
||||
</Code>
|
||||
</Text>
|
||||
|
||||
<Link underline="never" href={href} target="_blank">
|
||||
<Button>
|
||||
{strings.api.test} <PlayIcon />
|
||||
</Button>
|
||||
</Link>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
export function ApiTester({ path, locale }: Props & LocaleAcceptorProps) {
|
||||
return (
|
||||
<LocaleProvider locale={locale}>
|
||||
<Content path={path} />
|
||||
</LocaleProvider>
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,102 @@
|
||||
.card {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
gap: var(--space-4);
|
||||
|
||||
.series {
|
||||
position: relative;
|
||||
width: 100%;
|
||||
aspect-ratio: 7 / 8;
|
||||
|
||||
.entry {
|
||||
position: absolute;
|
||||
|
||||
border-radius: var(--space-3);
|
||||
box-shadow: var(--shadow-interactive), var(--shadow-aggressive);
|
||||
|
||||
background-size: cover;
|
||||
background-position: center;
|
||||
|
||||
&.skeleton {
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
}
|
||||
|
||||
.count {
|
||||
position: absolute;
|
||||
bottom: var(--space-3);
|
||||
right: var(--space-3);
|
||||
|
||||
box-shadow: var(--shadow-aggressive);
|
||||
}
|
||||
}
|
||||
|
||||
.label {
|
||||
max-width: 100%;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
width: 100%;
|
||||
|
||||
.skeleton {
|
||||
width: 100%;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.details {
|
||||
display: flex;
|
||||
gap: var(--space-5);
|
||||
align-items: center;
|
||||
|
||||
.preview {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
|
||||
padding: var(--space-2);
|
||||
|
||||
&[data-grade="1"] .image {
|
||||
outline: var(--space-2) solid var(--gray-9);
|
||||
}
|
||||
|
||||
&[data-grade="2"] .image {
|
||||
outline: var(--space-2) solid var(--blue-9);
|
||||
box-shadow: 0 0 var(--space-3) var(--blue-9);
|
||||
}
|
||||
|
||||
&[data-grade="3"] .image {
|
||||
outline: var(--space-2) solid var(--purple-9);
|
||||
box-shadow: 0 0 var(--space-4) var(--purple-9);
|
||||
}
|
||||
|
||||
&[data-grade="4"] .image {
|
||||
outline: var(--space-2) solid var(--amber-9);
|
||||
box-shadow: 0 0 var(--space-5) var(--amber-9);
|
||||
}
|
||||
|
||||
.image {
|
||||
aspect-ratio: 7 / 8;
|
||||
width: 8rem;
|
||||
border-radius: var(--space-3);
|
||||
|
||||
background-size: cover;
|
||||
background-position: center;
|
||||
}
|
||||
|
||||
.grade {
|
||||
margin-top: calc(var(--space-3) * -1);
|
||||
}
|
||||
}
|
||||
|
||||
.description {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
|
||||
max-width: 20rem;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,153 @@
|
||||
import { literals } from "@blitzkit/i18n";
|
||||
import type { Avatar } from "@protos/blitzkit/avatar";
|
||||
import { Grade } from "@protos/game/proto/legacy/blitz_static_standard_grades_enum";
|
||||
import { DownloadIcon, StarFilledIcon } from "@radix-ui/react-icons";
|
||||
import type { Color } from "../../core/ui/color";
|
||||
import { useGameStrings } from "../../hooks/useGameStrings";
|
||||
import { useStrings } from "../../hooks/useStrings";
|
||||
import type { PropsWithSkeleton } from "../../types/propsWithSkeleton";
|
||||
import { Badge } from "../Badge";
|
||||
import { Button } from "../Button";
|
||||
import { Dialog } from "../Dialog";
|
||||
import { InlineSkeleton } from "../InlineSkeleton";
|
||||
import { Link } from "../Link";
|
||||
import { Skeleton } from "../Skeleton";
|
||||
import { Text } from "../Text";
|
||||
import styles from "./index.module.css";
|
||||
|
||||
interface Props {
|
||||
name: string;
|
||||
avatars: Avatar[];
|
||||
}
|
||||
|
||||
const MAX_CARDS = 3;
|
||||
const CARD_TRIM = "var(--space-3)";
|
||||
|
||||
export function AvatarCard(props: PropsWithSkeleton<Props>) {
|
||||
const card = (
|
||||
<div className={styles.card}>
|
||||
<Series skeleton={props.skeleton} {...props} />
|
||||
|
||||
<Text align="center" className={styles.label}>
|
||||
{props.skeleton ? <InlineSkeleton /> : props.name}
|
||||
</Text>
|
||||
</div>
|
||||
);
|
||||
|
||||
if (props.skeleton) return card;
|
||||
|
||||
return (
|
||||
<Dialog.Root>
|
||||
<Dialog.Trigger>{card}</Dialog.Trigger>
|
||||
<Dialog.Content>
|
||||
<Text size="major" weight="bold">
|
||||
{props.name}
|
||||
</Text>
|
||||
|
||||
<Details avatars={props.avatars} />
|
||||
</Dialog.Content>
|
||||
</Dialog.Root>
|
||||
);
|
||||
}
|
||||
|
||||
interface DetailsProps {
|
||||
avatars: Avatar[];
|
||||
}
|
||||
|
||||
const gradeColors: Record<Grade, Color> = {
|
||||
[Grade.GRADE_UNSPECIFIED]: "gray",
|
||||
[Grade.GRADE_COMMON]: "gray",
|
||||
[Grade.GRADE_RARE]: "blue",
|
||||
[Grade.GRADE_EPIC]: "purple",
|
||||
[Grade.GRADE_LEGENDARY]: "amber",
|
||||
};
|
||||
|
||||
function Details({ avatars }: DetailsProps) {
|
||||
const gameStrings = useGameStrings("ProfileAvatarEntity");
|
||||
const strings = useStrings();
|
||||
|
||||
return [...avatars].reverse().map((avatar) => {
|
||||
const description = gameStrings[avatar.stuff_ui!.description];
|
||||
const obtaining = gameStrings[avatar.stuff_ui!.obtaining_methods];
|
||||
const hasDescription = description || obtaining;
|
||||
|
||||
return (
|
||||
<div className={styles.details}>
|
||||
<div className={styles.preview} data-grade={avatar.stuff_ui!.grade}>
|
||||
<div
|
||||
className={styles.image}
|
||||
style={{
|
||||
backgroundImage: `url(/api/avatars/${avatar.name}.webp)`,
|
||||
}}
|
||||
/>
|
||||
<Badge
|
||||
color={gradeColors[avatar.stuff_ui!.grade]}
|
||||
className={styles.grade}
|
||||
>
|
||||
<StarFilledIcon />
|
||||
{strings.grades[avatar.stuff_ui!.grade]}
|
||||
</Badge>
|
||||
</div>
|
||||
|
||||
<div className={styles.description}>
|
||||
<Text>
|
||||
{hasDescription ? (
|
||||
<>
|
||||
{description} {obtaining}
|
||||
</>
|
||||
) : (
|
||||
strings.avatars.no_description
|
||||
)}
|
||||
</Text>
|
||||
|
||||
<Link
|
||||
underline="never"
|
||||
href={`/api/avatars/${avatar.name}.webp`}
|
||||
download
|
||||
>
|
||||
<Button>
|
||||
<DownloadIcon /> {strings.avatars.download}
|
||||
</Button>
|
||||
</Link>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
interface SeriesProps {
|
||||
avatars: Avatar[];
|
||||
}
|
||||
|
||||
function Series(props: PropsWithSkeleton<SeriesProps>) {
|
||||
const count = Math.min(props.skeleton ? 0 : props.avatars.length, MAX_CARDS);
|
||||
const strings = useStrings();
|
||||
|
||||
return (
|
||||
<div className={styles.series}>
|
||||
{!props.skeleton &&
|
||||
props.avatars.slice(-MAX_CARDS).map((avatar, index) => (
|
||||
<div
|
||||
key={avatar.name}
|
||||
className={styles.entry}
|
||||
style={{
|
||||
filter: `brightness(${(index + 1) / count})`,
|
||||
top: `calc(${index} * ${CARD_TRIM})`,
|
||||
left: `calc(${index} * ${CARD_TRIM})`,
|
||||
width: `calc(100% - ${CARD_TRIM} * ${count - 1})`,
|
||||
height: `calc(100% - ${CARD_TRIM} * ${count - 1})`,
|
||||
backgroundImage: `url(/api/avatars/${avatar.name}.webp)`,
|
||||
}}
|
||||
/>
|
||||
))}
|
||||
|
||||
{!props.skeleton && props.avatars.length > 1 && (
|
||||
<Badge color="gray" highContrast className={styles.count}>
|
||||
{literals(strings.units.x, { value: props.avatars.length })}
|
||||
</Badge>
|
||||
)}
|
||||
|
||||
{props.skeleton && <Skeleton className={styles.entry} />}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
.avatar-controls {
|
||||
display: flex;
|
||||
|
||||
.search {
|
||||
flex: 1;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,40 @@
|
||||
import { MagnifyingGlassIcon } from "@radix-ui/react-icons";
|
||||
import { useCallback, useEffect, useRef } from "react";
|
||||
import { useStrings } from "../../hooks/useStrings";
|
||||
import { Avatars } from "../../stores/avatars";
|
||||
import { TextField } from "../TextField";
|
||||
import "./index.css";
|
||||
|
||||
export function AvatarControls() {
|
||||
const strings = useStrings();
|
||||
const search = useRef<HTMLInputElement>(null);
|
||||
|
||||
const onChange = useCallback(() => {
|
||||
if (!search.current) return;
|
||||
|
||||
const trimmed = search.current.value.trim();
|
||||
|
||||
Avatars.mutate((draft) => {
|
||||
if (trimmed.length === 0) {
|
||||
draft.search = null;
|
||||
} else {
|
||||
draft.search = trimmed;
|
||||
}
|
||||
});
|
||||
}, []);
|
||||
|
||||
useEffect(onChange, []);
|
||||
|
||||
return (
|
||||
<div className="avatar-controls">
|
||||
<TextField
|
||||
ref={search}
|
||||
className="search"
|
||||
placeholder={strings.avatars.search}
|
||||
onChange={onChange}
|
||||
>
|
||||
<MagnifyingGlassIcon />
|
||||
</TextField>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
.avatars-list {
|
||||
display: grid;
|
||||
gap: var(--space-5) var(--space-4);
|
||||
grid-template-columns: repeat(auto-fill, minmax(6rem, 1fr));
|
||||
|
||||
@media (min-width: 32rem) {
|
||||
grid-template-columns: repeat(auto-fill, minmax(8rem, 1fr));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,85 @@
|
||||
import fuzzysort from "fuzzysort";
|
||||
import { useMemo } from "react";
|
||||
import { api } from "../../core/api/dynamic";
|
||||
import { useAwait } from "../../hooks/useAwait";
|
||||
import { useGameStrings } from "../../hooks/useGameStrings";
|
||||
import { useLocale } from "../../hooks/useLocale";
|
||||
import type { Avatar } from "../../protos/avatar";
|
||||
import { Avatars } from "../../stores/avatars";
|
||||
import { AvatarCard } from "../AvatarCard";
|
||||
import { IncrementalLoader } from "../IncrementalLoader";
|
||||
import "./index.css";
|
||||
|
||||
const { go } = fuzzysort;
|
||||
|
||||
const indexingPattern = /.+_(\d+)$/;
|
||||
|
||||
export function AvatarsList() {
|
||||
const locale = useLocale();
|
||||
const search = Avatars.use((state) => state.search);
|
||||
const { avatars } = useAwait(() => api.avatars(), "avatars");
|
||||
const gameStrings = useGameStrings("ProfileAvatarEntity");
|
||||
const groups = useMemo(() => {
|
||||
const groups = new Map<string, Avatar[]>();
|
||||
|
||||
for (const avatar of avatars) {
|
||||
const name =
|
||||
gameStrings[avatar.stuff_ui!.display_name] ??
|
||||
avatar.stuff_ui!.display_name;
|
||||
|
||||
if (groups.has(name)) {
|
||||
groups.get(name)!.push(avatar);
|
||||
} else {
|
||||
groups.set(name, [avatar]);
|
||||
}
|
||||
}
|
||||
|
||||
return groups;
|
||||
}, []);
|
||||
const ordered = useMemo(() => {
|
||||
const array = Array.from(groups.entries());
|
||||
return array
|
||||
.sort((a, b) => a[0].localeCompare(b[0], locale))
|
||||
.map(([name, avatars]) => ({
|
||||
key: name,
|
||||
name,
|
||||
avatars: avatars.sort((a, b) => {
|
||||
const gradeA = a.stuff_ui!.grade;
|
||||
const gradeB = b.stuff_ui!.grade;
|
||||
let diff = gradeA - gradeB;
|
||||
|
||||
if (diff === 0) {
|
||||
const matchesA = a.name.match(indexingPattern);
|
||||
const matchesB = b.name.match(indexingPattern);
|
||||
|
||||
if (matchesA && matchesB) {
|
||||
const indexA = Number(matchesA[1]);
|
||||
const indexB = Number(matchesB[1]);
|
||||
|
||||
diff = indexA - indexB;
|
||||
}
|
||||
}
|
||||
|
||||
return diff;
|
||||
}),
|
||||
}));
|
||||
}, []);
|
||||
const filtered = useMemo(() => {
|
||||
if (search === null) return ordered;
|
||||
|
||||
const searched = go(search, ordered, { keys: ["name"] });
|
||||
|
||||
return searched.map((result) => result.obj);
|
||||
}, [search]);
|
||||
|
||||
return (
|
||||
<div className="avatars-list">
|
||||
<IncrementalLoader
|
||||
initial={7 * 5}
|
||||
intermediate={7 * 3}
|
||||
data={filtered}
|
||||
Component={AvatarCard}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
.badge {
|
||||
border-radius: var(--max-size);
|
||||
|
||||
padding: var(--space-2) var(--space-3);
|
||||
|
||||
font-size: var(--font-size-minor);
|
||||
font-weight: var(--weight-medium);
|
||||
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: var(--space-2);
|
||||
|
||||
.svg {
|
||||
width: 1em;
|
||||
height: 1em;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
import type { ComponentProps } from "react";
|
||||
import { classNames } from "../../core/ui/classNames";
|
||||
import type { Color } from "../../core/ui/color";
|
||||
import { LIGHT_TEXT_COLORS } from "../Button";
|
||||
import styles from "./index.module.css";
|
||||
|
||||
export interface BadgeProps extends ComponentProps<"div"> {
|
||||
color?: Color | "accent";
|
||||
highContrast?: boolean;
|
||||
}
|
||||
|
||||
export function Badge({
|
||||
className,
|
||||
style,
|
||||
color = "accent",
|
||||
highContrast,
|
||||
...props
|
||||
}: BadgeProps) {
|
||||
const lightText = LIGHT_TEXT_COLORS.has(color as Color);
|
||||
|
||||
return (
|
||||
<div
|
||||
className={classNames(styles.badge, className)}
|
||||
style={{
|
||||
backgroundColor: `var(--${color}-${highContrast ? 12 : 9})`,
|
||||
color: `var(--gray-${highContrast || lightText ? 1 : 12})`,
|
||||
...style,
|
||||
}}
|
||||
{...props}
|
||||
/>
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
<meta charset="utf-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<link rel="sitemap" href="/sitemap-index.xml" />
|
||||
@@ -0,0 +1,112 @@
|
||||
---
|
||||
import "@fontsource-variable/jetbrains-mono";
|
||||
import "@fontsource-variable/roboto-flex";
|
||||
---
|
||||
|
||||
<style>
|
||||
:root {
|
||||
--space-0: 0.0625rem;
|
||||
--space-1: 0.125rem;
|
||||
--space-2: 0.25rem;
|
||||
--space-3: 0.5rem;
|
||||
--space-4: 1rem;
|
||||
--space-5: 2rem;
|
||||
--space-6: 4rem;
|
||||
--space-7: 8rem;
|
||||
--space-8: 16rem;
|
||||
--space-9: 32rem;
|
||||
|
||||
--page-width: 64rem;
|
||||
|
||||
--max-size: max(100vw, 100vh);
|
||||
|
||||
--font-size-regular: 1rem;
|
||||
--font-size-minor: 0.75rem;
|
||||
--font-size-major: 1.25rem;
|
||||
|
||||
--font-size-heading-1: 3rem;
|
||||
--font-size-heading-2: 2rem;
|
||||
--font-size-heading-3: 1.5rem;
|
||||
--font-size-heading-4: 1.25rem;
|
||||
--font-size-heading-5: 1rem;
|
||||
--font-size-heading-6: 0.75rem;
|
||||
|
||||
--font-family-regular: "Roboto Flex Variable", sans-serif;
|
||||
--font-family-mono: "JetBrains Mono Variable", monospace;
|
||||
|
||||
--color-regular: var(--gray-12);
|
||||
--color-low-contrast: var(--gray-11);
|
||||
|
||||
--weight-light: 300;
|
||||
--weight-regular: 400;
|
||||
--weight-medium: 500;
|
||||
--weight-bold: 700;
|
||||
--weight-black: 900;
|
||||
|
||||
--outline-interactive: var(--space-1) solid var(--gray-4);
|
||||
--outline-focus: var(--space-1) solid var(--accent-6);
|
||||
|
||||
/* --shadow-cavity:
|
||||
inset calc(var(--space-1) * sin(45deg)) calc(var(--space-1) * sin(45deg))
|
||||
var(--space-1) var(--black-a3),
|
||||
inset calc(var(--space-1) * sin(45deg) * -1)
|
||||
calc(var(--space-1) * sin(45deg) * -1) var(--space-1) var(--white-a1); */
|
||||
|
||||
--shadow-bump:
|
||||
inset calc(var(--space-1) * sin(45deg)) calc(var(--space-1) * sin(45deg))
|
||||
var(--space-1) var(--white-a3),
|
||||
inset calc(var(--space-1) * sin(45deg) * -1)
|
||||
calc(var(--space-1) * sin(45deg) * -1) var(--space-1) var(--black-a3);
|
||||
|
||||
--shadow-outline-width: 1.5px;
|
||||
--shadow-outline-width-negative: calc(var(--shadow-outline-width) * -1);
|
||||
|
||||
/* --shadow-interactive-background: 0 0 0 var(--shadow-outline-width)
|
||||
var(--gray-6);
|
||||
--shadow-interactive-shine: var(--shadow-outline-width-negative)
|
||||
var(--shadow-outline-width-negative) var(--shadow-outline-width)
|
||||
var(--white-a1);
|
||||
--shadow-interactive-shadow: var(--shadow-outline-width)
|
||||
var(--shadow-outline-width) var(--shadow-outline-width) var(--black-a4);
|
||||
--shadow-interactive:
|
||||
var(--shadow-interactive-shine), var(--shadow-interactive-shadow),
|
||||
var(--shadow-interactive-background); */
|
||||
|
||||
--shadow-aggressive: var(--space-1) var(--space-1) var(--space-4)
|
||||
var(--black-a11);
|
||||
--shadow-subtle: 0 var(--space-1) var(--space-3) var(--black-a5);
|
||||
--shadow-none: 0 0 0 transparent;
|
||||
|
||||
&.light {
|
||||
--shadow-subtle: 0 var(--space-1) var(--space-3) var(--black-a2);
|
||||
}
|
||||
|
||||
--blur-glass: blur(4rem);
|
||||
--blur-tint: blur(8rem);
|
||||
|
||||
--duration-brief: 200ms;
|
||||
--duration-subtle: 2s;
|
||||
|
||||
--tank-card-min-width: 8rem;
|
||||
}
|
||||
</style>
|
||||
|
||||
<style is:global>
|
||||
.composable-radius {
|
||||
&[data-radius="1"] {
|
||||
border-radius: var(--space-3);
|
||||
}
|
||||
|
||||
&[data-radius="2"] {
|
||||
border-radius: var(--space-4);
|
||||
}
|
||||
|
||||
&[data-radius="3"] {
|
||||
border-radius: var(--space-5);
|
||||
}
|
||||
|
||||
&[data-radius="max"] {
|
||||
border-radius: var(--max-size);
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@@ -0,0 +1,38 @@
|
||||
.button {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
gap: var(--space-2);
|
||||
|
||||
border-radius: var(--max-size);
|
||||
padding: var(--space-3) var(--space-4);
|
||||
|
||||
border: none;
|
||||
|
||||
font-family: var(--font-family-regular);
|
||||
font-size: var(--font-size-minor);
|
||||
color: var(--gray-1);
|
||||
font-weight: var(--weight-medium);
|
||||
|
||||
.svg {
|
||||
width: 1em;
|
||||
height: 1em;
|
||||
}
|
||||
|
||||
&[data-light-text="true"] {
|
||||
color: var(--white-a12);
|
||||
}
|
||||
|
||||
&[data-variant="solid"] {
|
||||
background-color: var(--accent-8);
|
||||
}
|
||||
|
||||
&[data-variant="surface"],
|
||||
&[data-variant="soft"] {
|
||||
background-color: var(--accent-3);
|
||||
}
|
||||
|
||||
&[data-variant="surface"] {
|
||||
outline: var(--space-1) solid var(--accent-6);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,45 @@
|
||||
import type { ComponentProps } from "react";
|
||||
import { classNames } from "../../core/ui/classNames";
|
||||
import type { Color } from "../../core/ui/color";
|
||||
import styles from "./index.module.css";
|
||||
|
||||
export interface ButtonProps extends ComponentProps<"button"> {
|
||||
color?: Color;
|
||||
radius?: `${1 | 2 | 3}` | "max";
|
||||
variant?: "solid" | "surface" | "soft";
|
||||
}
|
||||
|
||||
export const LIGHT_TEXT_COLORS = new Set<Color>([
|
||||
"gold",
|
||||
"bronze",
|
||||
"teal",
|
||||
"grass",
|
||||
"amber",
|
||||
"plum",
|
||||
"pink",
|
||||
"brown",
|
||||
"crimson",
|
||||
"jade",
|
||||
"blue",
|
||||
"tomato",
|
||||
]);
|
||||
|
||||
export function Button({
|
||||
className,
|
||||
color,
|
||||
variant = "solid",
|
||||
style,
|
||||
radius = "max",
|
||||
...props
|
||||
}: ButtonProps) {
|
||||
return (
|
||||
<button
|
||||
className={classNames("composable-radius", styles.button, className)}
|
||||
data-accent={color}
|
||||
data-variant={variant}
|
||||
data-light-text={variant === "solid"}
|
||||
data-radius={radius}
|
||||
{...props}
|
||||
/>
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,47 @@
|
||||
---
|
||||
import { ExclamationTriangleIcon } from "@radix-ui/react-icons";
|
||||
import { api } from "../core/api/dynamic";
|
||||
import { Heading } from "./Heading";
|
||||
import { Section } from "./Section";
|
||||
import { Text } from "./Text";
|
||||
|
||||
interface Props {
|
||||
locale: string;
|
||||
}
|
||||
|
||||
const { locale } = Astro.props;
|
||||
|
||||
const strings = await api.strings(locale);
|
||||
---
|
||||
|
||||
<style>
|
||||
.card {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: var(--space-3);
|
||||
max-width: 30rem;
|
||||
|
||||
padding: var(--space-4);
|
||||
margin: auto;
|
||||
|
||||
background-color: var(--red-3);
|
||||
|
||||
.title {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: var(--space-3);
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
<Section>
|
||||
<div class="card composable-radius" data-radius="1">
|
||||
<Heading size="4">
|
||||
<div class="title">
|
||||
<ExclamationTriangleIcon width="0.75em" height="0.75em" />
|
||||
{strings.client_unmounted.title}
|
||||
</div>
|
||||
</Heading>
|
||||
<Text>{strings.client_unmounted.body}</Text>
|
||||
</div>
|
||||
</Section>
|
||||
@@ -0,0 +1,16 @@
|
||||
.code {
|
||||
font: inherit;
|
||||
font-family: var(--font-family-mono);
|
||||
|
||||
white-space: pre;
|
||||
|
||||
display: inline-block;
|
||||
|
||||
&[data-variant="solid"] {
|
||||
background-color: var(--gray-3);
|
||||
|
||||
border-radius: var(--space-3);
|
||||
|
||||
padding: var(--space-4);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
import type { ComponentProps } from "react";
|
||||
import { classNames } from "../../core/ui/classNames";
|
||||
import styles from "./index.module.css";
|
||||
|
||||
export interface CodeProps extends ComponentProps<"code"> {
|
||||
variant?: "ghost" | "solid";
|
||||
}
|
||||
|
||||
export function Code({ className, variant = "ghost", ...props }: CodeProps) {
|
||||
return (
|
||||
<code
|
||||
data-variant={variant}
|
||||
className={classNames(styles.code, className)}
|
||||
{...props}
|
||||
/>
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,33 @@
|
||||
---
|
||||
import type { Color } from "../core/ui/color";
|
||||
|
||||
interface Props {
|
||||
color: Color;
|
||||
alias: string;
|
||||
alpha?: boolean;
|
||||
}
|
||||
|
||||
const { color, alias, alpha } = Astro.props;
|
||||
|
||||
let styles = "";
|
||||
|
||||
styles += ":root{";
|
||||
|
||||
for (let i = 0; i < 12; i++) {
|
||||
const n = i + 1;
|
||||
styles += `--${alias}-${alpha ? "a" : ""}${n}:var(--${color}-${alpha ? "a" : ""}${n});`;
|
||||
}
|
||||
|
||||
styles += "}";
|
||||
|
||||
styles += `*[data-accent='${alias}']{`;
|
||||
|
||||
for (let i = 0; i < 12; i++) {
|
||||
const n = i + 1;
|
||||
styles += `--accent-${alpha ? "a" : ""}${n}:var(--${alias}-${alpha ? "a" : ""}${n});`;
|
||||
}
|
||||
|
||||
styles += "}";
|
||||
---
|
||||
|
||||
<style set:html={styles}></style>
|
||||
@@ -0,0 +1,54 @@
|
||||
---
|
||||
import * as colors from "@radix-ui/colors";
|
||||
import type { Color } from "../core/ui/color";
|
||||
|
||||
interface Props {
|
||||
color: Color | AlphaOnlyColor;
|
||||
alpha?: boolean;
|
||||
}
|
||||
|
||||
const ALPHA_ONLY_COLORS = ["black", "white"] as const;
|
||||
type AlphaOnlyColor = (typeof ALPHA_ONLY_COLORS)[number];
|
||||
|
||||
const { color, alpha } = Astro.props;
|
||||
const nameLight = `${color}${alpha ? "A" : ""}`;
|
||||
const nameDark = `${color}${
|
||||
ALPHA_ONLY_COLORS.includes(color as AlphaOnlyColor) ? "" : "Dark"
|
||||
}${alpha ? "A" : ""}`;
|
||||
const scaleLight = colors[nameLight as keyof typeof colors];
|
||||
const scaleDark = colors[nameDark as keyof typeof colors];
|
||||
|
||||
let styles = "";
|
||||
|
||||
styles += ":root.dark{";
|
||||
|
||||
for (let i = 0; i < 12; i++) {
|
||||
const n = i + 1;
|
||||
const value =
|
||||
scaleDark[`${color}${alpha ? "A" : ""}${n}` as keyof typeof scaleDark];
|
||||
styles += `--${color}-${alpha ? "a" : ""}${n}:${value};`;
|
||||
}
|
||||
|
||||
styles += "}";
|
||||
styles += ":root.light{";
|
||||
|
||||
for (let i = 0; i < 12; i++) {
|
||||
const n = i + 1;
|
||||
const value =
|
||||
scaleLight[`${color}${alpha ? "A" : ""}${n}` as keyof typeof scaleLight];
|
||||
styles += `--${color}-${alpha ? "a" : ""}${n}:${value};`;
|
||||
}
|
||||
|
||||
styles += "}";
|
||||
|
||||
styles += `*[data-accent='${color}']{`;
|
||||
|
||||
for (let i = 0; i < 12; i++) {
|
||||
const n = i + 1;
|
||||
styles += `--accent-${alpha ? "a" : ""}${n}:var(--${color}-${alpha ? "a" : ""}${n});`;
|
||||
}
|
||||
|
||||
styles += "}";
|
||||
---
|
||||
|
||||
<style set:html={styles}></style>
|
||||
@@ -0,0 +1,36 @@
|
||||
.trigger {
|
||||
display: contents;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.overlay {
|
||||
position: fixed;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 100vw;
|
||||
height: 100dvh;
|
||||
overflow-y: scroll;
|
||||
|
||||
background-color: var(--black-a9);
|
||||
z-index: 1;
|
||||
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
box-sizing: border-box;
|
||||
|
||||
.content {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: var(--space-4);
|
||||
margin: var(--space-4);
|
||||
box-sizing: border-box;
|
||||
|
||||
min-width: 25rem;
|
||||
|
||||
background-color: var(--gray-3);
|
||||
padding: var(--space-4);
|
||||
box-shadow: var(--shadow-interactive), var(--shadow-aggressive);
|
||||
border-radius: var(--space-3);
|
||||
}
|
||||
}
|
||||