Compare commits

...
43 Commits
Author SHA1 Message Date
TrèsAbhi 382a23b661 Merge pull request #58 from tresabhi/1.15.8 2023-12-13 12:03:16 -06:00
TrèsAbhi 98107291f5 feat: changelogs 2023-12-13 12:03:02 -06:00
TrèsAbhi c6779a714b feat: custom titles 2023-12-13 11:59:37 -06:00
TrèsAbhi ef8f0fd72d feat: color previews 2023-12-13 11:46:36 -06:00
TrèsAbhi b42df81b48 feat: remove running bot instructions 2023-12-10 12:03:34 -06:00
TrèsAbhi 536fed5448 feat: newer website image 2023-12-10 12:03:02 -06:00
TrèsAbhi d4c0b01343 Merge pull request #56 from tresabhi/1.15.7 2023-12-03 10:51:33 -06:00
TrèsAbhi af67126156 feat: changelogs 2023-12-03 10:51:15 -06:00
TrèsAbhi 9930360405 feat: session tracker classnames 2023-12-03 10:44:49 -06:00
TrèsAbhi 4fb61d6dbd feat: session tracker themeing 2023-12-03 10:43:42 -06:00
TrèsAbhi bcb7ca5c4c fix: local string for ratings overflow count 2023-12-03 09:57:06 -06:00
TrèsAbhi 2be4dbea7a Merge pull request #54 from tresabhi/1.15.6 2023-11-28 10:18:06 -06:00
TrèsAbhi b951c81bf5 feat: changelog 2023-11-28 10:17:56 -06:00
TrèsAbhi 8c221a1295 feat: updated creators with a better format 2023-11-28 10:16:28 -06:00
TrèsAbhi c41f721a96 fix: regions at root 2023-11-28 10:14:45 -06:00
TrèsAbhi 1a92cbd951 Merge pull request #52 from tresabhi/1.15.5 2023-11-27 12:15:09 -06:00
TrèsAbhi 54c5faf929 fix: changelog version 2023-11-27 12:15:24 -06:00
TrèsAbhi d1d9e9e4d1 feat: changelogs 2023-11-27 12:14:35 -06:00
TrèsAbhi 5ca64f839e fix: exhaustive user and channel indexing 2023-11-27 12:12:57 -06:00
TrèsAbhi 4e7cd6f681 Merge pull request #51 from tresabhi/1.15.4 2023-11-27 12:06:01 -06:00
TrèsAbhi ba9f593716 feat: changelogs 2023-11-27 12:06:00 -06:00
TrèsAbhi 9d3d74c7c5 feat: change ratings root dir to "ratings" 2023-11-27 12:03:17 -06:00
TrèsAbhi aae26523ff feat: renamed blitzkrieg-db to blitzkrieg-assets 2023-11-27 12:01:32 -06:00
TrèsAbhi 338a2a14bf fix: continue after no player found 2023-11-27 12:00:19 -06:00
TrèsAbhi 1a66cab435 feat: change name to have "Ratings" in the front 2023-11-27 11:59:02 -06:00
TrèsAbhi 3363c9ab58 Merge pull request #50 from tresabhi/1.15.3 2023-11-25 21:12:30 -06:00
TrèsAbhi 10f64902aa fix: xml in md 2023-11-25 21:10:53 -06:00
TrèsAbhi 25e1f4caa4 fix: workflow triggers 2023-11-25 21:09:24 -06:00
TrèsAbhi 222fa89422 fix: remove pull request 2023-11-25 21:04:04 -06:00
TrèsAbhi 750e145f03 feat: version lint 2023-11-25 21:03:29 -06:00
TrèsAbhi 3bbbbfa402 feat: changelogs 2023-11-25 20:57:58 -06:00
TrèsAbhi f728751fa9 feat: better debug 2023-11-25 20:46:20 -06:00
TrèsAbhi f5425d0e54 fix: more accurate user count 2023-11-25 20:45:00 -06:00
TrèsAbhi debaaccf4c feat: presence 2023-11-25 20:40:11 -06:00
TrèsAbhi a3e20501af feat: new credits transfer 2023-11-25 20:08:01 -06:00
TrèsAbhi c87a75f3fd feat: combined ratings archive workflows 2023-11-25 20:01:12 -06:00
TrèsAbhi 55729c5eda feat: ratings leaderboard archive explicit target 2023-11-25 19:46:56 -06:00
TrèsAbhi 06cbcc2339 fix: "Midnight" in name 2023-11-23 14:39:04 -06:00
TrèsAbhi 1afe860e76 feat: change workflow file name to midnight 2023-11-23 14:38:04 -06:00
TrèsAbhi c0ac935652 feat: remove manual asia leaderboard trigger 2023-11-23 14:36:40 -06:00
TrèsAbhi 7c76b0f5a5 feat: Asia leaderboard manual trigger 2023-11-22 23:51:52 -06:00
TrèsAbhi 42091c54b7 fix: illegal json invocation 2023-11-22 23:49:24 -06:00
TrèsAbhi 396b48d017 feat: smaller fetching size 2023-11-20 13:32:53 -06:00
42 changed files with 445 additions and 242 deletions

No files matched your search

@@ -1,34 +0,0 @@
name: CD Asia Ratings Latest
on:
schedule:
- cron: "0 0 * * *"
jobs:
host:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v3
- name: Use node
uses: actions/setup-node@v3
with:
node-version: 18
cache: "npm"
- name: Install Yarn
run: npm install --location=global yarn
- name: Use node_modules cache
uses: actions/cache@v3
with:
path: "**/node_modules"
key: ${{ runner.os }}-modules-${{ hashFiles('**/yarn.lock') }}
- name: Install dependencies
run: yarn
- name: Generate leaderboard
run: GH_TOKEN=${{ secrets.GH_TOKEN }} yarn publish:ratingsleaderboard --region=asia --latest
@@ -1,34 +0,0 @@
name: CD Asia Ratings Leaderboards
on:
schedule:
- cron: "0 17 * * *"
jobs:
host:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v3
- name: Use node
uses: actions/setup-node@v3
with:
node-version: 18
cache: "npm"
- name: Install Yarn
run: npm install --location=global yarn
- name: Use node_modules cache
uses: actions/cache@v3
with:
path: "**/node_modules"
key: ${{ runner.os }}-modules-${{ hashFiles('**/yarn.lock') }}
- name: Install dependencies
run: yarn
- name: Generate leaderboard
run: GH_TOKEN=${{ secrets.GH_TOKEN }} yarn publish:ratingsleaderboard --region=asia
+1 -1
View File
@@ -2,7 +2,7 @@ name: CD Docs
on: on:
push: push:
branches: [main] branches: main
jobs: jobs:
build: build:
@@ -1,8 +1,12 @@
name: CD Europe Ratings Latest name: CD Ratings Asia
# latest: '0 0 * * *'
# asia midnight: '0 17 * * *'
on: on:
schedule: schedule:
- cron: "0 0 * * *" - cron: '0 0 * * *'
- cron: '0 17 * * *'
jobs: jobs:
host: host:
@@ -16,7 +20,7 @@ jobs:
uses: actions/setup-node@v3 uses: actions/setup-node@v3
with: with:
node-version: 18 node-version: 18
cache: "npm" cache: 'npm'
- name: Install Yarn - name: Install Yarn
run: npm install --location=global yarn run: npm install --location=global yarn
@@ -24,11 +28,11 @@ jobs:
- name: Use node_modules cache - name: Use node_modules cache
uses: actions/cache@v3 uses: actions/cache@v3
with: with:
path: "**/node_modules" path: '**/node_modules'
key: ${{ runner.os }}-modules-${{ hashFiles('**/yarn.lock') }} key: ${{ runner.os }}-modules-${{ hashFiles('**/yarn.lock') }}
- name: Install dependencies - name: Install dependencies
run: yarn run: yarn
- name: Generate leaderboard - name: Generate leaderboard
run: GH_TOKEN=${{ secrets.GH_TOKEN }} yarn publish:ratingsleaderboard --region=eu --latest run: GH_TOKEN=${{ secrets.GH_TOKEN }} yarn publish:ratingsleaderboard --region=asia --target=${{ github.event.schedule == '0 0 * * *' && 'latest' || 'midnight' }}
@@ -1,8 +1,12 @@
name: CD North America Ratings Latest name: CD Ratings Europe
# latest: '0 0 * * *'
# eu midnight: '0 23 * * *'
on: on:
schedule: schedule:
- cron: '0 0 * * *' - cron: '0 0 * * *'
- cron: '0 23 * * *'
jobs: jobs:
host: host:
@@ -31,4 +35,4 @@ jobs:
run: yarn run: yarn
- name: Generate leaderboard - name: Generate leaderboard
run: GH_TOKEN=${{ secrets.GH_TOKEN }} yarn publish:ratingsleaderboard --region=na --latest run: GH_TOKEN=${{ secrets.GH_TOKEN }} yarn publish:ratingsleaderboard --region=eu --target=${{ github.event.schedule == '0 0 * * *' && 'latest' || 'midnight' }}
@@ -1,8 +1,12 @@
name: CD Europe Ratings Leaderboards name: CD Ratings North America
# latest: '0 0 * * *'
# na midnight: '0 5 * * *'
on: on:
schedule: schedule:
- cron: "0 23 * * *" - cron: '0 0 * * *'
- cron: '0 5 * * *'
jobs: jobs:
host: host:
@@ -16,7 +20,7 @@ jobs:
uses: actions/setup-node@v3 uses: actions/setup-node@v3
with: with:
node-version: 18 node-version: 18
cache: "npm" cache: 'npm'
- name: Install Yarn - name: Install Yarn
run: npm install --location=global yarn run: npm install --location=global yarn
@@ -24,11 +28,11 @@ jobs:
- name: Use node_modules cache - name: Use node_modules cache
uses: actions/cache@v3 uses: actions/cache@v3
with: with:
path: "**/node_modules" path: '**/node_modules'
key: ${{ runner.os }}-modules-${{ hashFiles('**/yarn.lock') }} key: ${{ runner.os }}-modules-${{ hashFiles('**/yarn.lock') }}
- name: Install dependencies - name: Install dependencies
run: yarn run: yarn
- name: Generate leaderboard - name: Generate leaderboard
run: GH_TOKEN=${{ secrets.GH_TOKEN }} yarn publish:ratingsleaderboard --region=eu run: GH_TOKEN=${{ secrets.GH_TOKEN }} yarn publish:ratingsleaderboard --region=na --target=${{ github.event.schedule == '0 0 * * *' && 'latest' || 'midnight' }}
+1 -1
View File
@@ -1,6 +1,6 @@
name: CI Build Bot name: CI Build Bot
on: [push, pull_request] on: push
concurrency: concurrency:
group: ${{ github.workflow }}-${{ github.ref }} group: ${{ github.workflow }}-${{ github.ref }}
+1 -1
View File
@@ -1,6 +1,6 @@
name: CI Build Docs name: CI Build Docs
on: [push, pull_request] on: push
concurrency: concurrency:
group: ${{ github.workflow }}-${{ github.ref }} group: ${{ github.workflow }}-${{ github.ref }}
+1 -1
View File
@@ -1,6 +1,6 @@
name: CI Build Website name: CI Build Website
on: [push, pull_request] on: push
concurrency: concurrency:
group: ${{ github.workflow }}-${{ github.ref }} group: ${{ github.workflow }}-${{ github.ref }}
@@ -1,8 +1,6 @@
name: CD North America Ratings Leaderboards name: CI Version
on: on: push
schedule:
- cron: '0 5 * * *'
jobs: jobs:
host: host:
@@ -31,4 +29,4 @@ jobs:
run: yarn run: yarn
- name: Generate leaderboard - name: Generate leaderboard
run: GH_TOKEN=${{ secrets.GH_TOKEN }} yarn publish:ratingsleaderboard --region=na run: yarn lint:version
+2
View File
@@ -15,6 +15,7 @@
"fuzzysort", "fuzzysort",
"immer", "immer",
"kranvagn", "kranvagn",
"krieg",
"Leaderboard", "Leaderboard",
"leaderboards", "leaderboards",
"MURICA", "MURICA",
@@ -46,6 +47,7 @@
"Unregistering", "Unregistering",
"vickers", "vickers",
"vitepress", "vitepress",
"Vovko",
"wargaming", "wargaming",
"webp", "webp",
"winrate", "winrate",
+1 -22
View File
@@ -14,31 +14,10 @@ Go to [application directory for Blitzkrieg](https://discord.com/application-dir
### https://blitz-krieg.vercel.app/ ### https://blitz-krieg.vercel.app/
![Blitzkrieg website](https://i.imgur.com/QOXUP63.png) ![Blitzkrieg website](https://i.imgur.com/eRIZe5P.png)
## Visit the documentation website ## Visit the documentation website
### https://tresabhi.github.io/blitzkrieg/ ### https://tresabhi.github.io/blitzkrieg/
![Blitzkrieg documentation website](https://i.imgur.com/mCZCZEI.png) ![Blitzkrieg documentation website](https://i.imgur.com/mCZCZEI.png)
## Run the bot
### Install dependencies
```bash
yarn
```
### Create `.env`
```env
GH_TOKEN={YOUR_GITHUB_TOKEN_HERE}
DISCORD_TOKEN={YOUR_DISCORD_TOKE_HERE}
```
### Run the command
```bash
yarn dev:bot
```
+30
View File
@@ -0,0 +1,30 @@
# Blitzkrieg 1.15.3
The bot now gets more expressive!
## Features
- The bot can now have presence messages; examples:
- "Living in {number} servers"
- "Server {number} users"
- "Observing {number} channels"
- More will be added in the future! Give me some ideas
## Changes
- Moved `/credits` to `/about creators`
- `/debug` command now ditches embeds and has better information to serve
## Technical Features
- Added a workflow and lint for package and changelog version miss match
## Technical Changes
- Removed manual trigger for Asian latest ratings leaderboard archiver
- Leaderboard archiver now accepts an explicit target like `midnight` or `latest`
- Combined midnight and latest leaderboard archival workflow into one file
## Technical Fixed
- Reviewed all workflow triggers and updated them
+13
View File
@@ -0,0 +1,13 @@
# Blitzkrieg 1.15.4
Unlocking future potential
## Technical Changes
- Moved the word "Ratings" to the front of the workflow name
- Renamed `blitzkrieg-db` to `blitzkrieg-assets`
- Moved the region folders from the root to `regions`
## Technical Fixes
- The ratings leaderboard archiver now correctly skips undefined players
+7
View File
@@ -0,0 +1,7 @@
# Blitzkrieg 1.15.5
Oops, this should've been in the last patch.
## Fixes
- User and channel cache is now guild cache exhaustive
+11
View File
@@ -0,0 +1,11 @@
# Blitzkrieg 1.15.6
This should have also been in the last update lol.
## Changes
- Changed the format of `/about creators` and added one more person
## Fixes
- Archived ratings leaderboards are now fetched from the correct URL path
+20
View File
@@ -0,0 +1,20 @@
# Blitzkrieg 1.15.7
Simple yet powerful theming options for the session tracker
## Features
- The accent color of the session tracker (hence the embed too) can now be tweaked
- Access this setting via the dropdown from Options > Accent color
## Fixes
- Reimplemented the commas for last numbers in the overflow count of the ratings leaderboard
- For example, "+1234567 more" will now read "+1,234,567 more"
## Technical Features
- Added class names for more in-depth customization for those who are comfortable with CSS
- `session-tracker-root`
- `session-tracker-row`
- `session-tracker-row-stat`
+9
View File
@@ -0,0 +1,9 @@
# Blitzkrieg 1.15.8
A request fulfilled \:\)
## Features
- Added custom titles in session tracker
- Change the title through Options > Edit title...
- Colors are shown when selecting a theme color for the session tracker
+5
View File
@@ -0,0 +1,5 @@
# Creators
- **TrèsAbhi** `@tresabhi`: Creator and main programmer
- **Prince_NA** `@prince_na`: Game advisor & tester
- **Vovko**: Technical advisor
+2 -1
View File
@@ -1,6 +1,6 @@
{ {
"name": "blitzkrieg", "name": "blitzkrieg",
"version": "1.15.2", "version": "1.15.8",
"description": "🎉 Tools for everything World of Tanks Blitz", "description": "🎉 Tools for everything World of Tanks Blitz",
"main": "src/server.ts", "main": "src/server.ts",
"type": "module", "type": "module",
@@ -21,6 +21,7 @@
"lint": "npx tsc", "lint": "npx tsc",
"lint:website": "next lint", "lint:website": "next lint",
"format": "prettier --write \"**/*.@(json|js|jsx|css|md|ts|tsx|html|xml|yml|gltf)\"", "format": "prettier --write \"**/*.@(json|js|jsx|css|md|ts|tsx|html|xml|yml|gltf)\"",
"lint:version": "vite-node --script scripts/checkVersionMissMatch",
"knip": "knip", "knip": "knip",
"update": "yarn upgrade --latest" "update": "yarn upgrade --latest"
}, },
+12 -10
View File
@@ -23,12 +23,15 @@ export type BlitzkriegRatingsLeaderboardEntry = { id: number; score: number };
export type BlitzkriegRatingsLeaderboard = BlitzkriegRatingsLeaderboardEntry[]; export type BlitzkriegRatingsLeaderboard = BlitzkriegRatingsLeaderboardEntry[];
const publish = argv.includes('--publish'); const publish = argv.includes('--publish');
const latest = argv.includes('--latest'); const target = argv
.find((arg) => arg.startsWith('--target='))
?.split('=')[1] as 'midnight' | 'latest' | undefined;
const server = argv.find((arg) => arg.startsWith('--region='))?.split('=')[1]; const server = argv.find((arg) => arg.startsWith('--region='))?.split('=')[1];
if (!target) throw new Error('Target parameter not specified');
if (!server) throw new Error('Region parameter not specified'); if (!server) throw new Error('Region parameter not specified');
const NEIGHBORS = 1024; const NEIGHBORS = 2 ** 8;
const PLAYERS = await patientFetchJSON<RatingsInfo>( const PLAYERS = await patientFetchJSON<RatingsInfo>(
`https://${server}.wotblitz.com/en/api/rating-leaderboards/season/`, `https://${server}.wotblitz.com/en/api/rating-leaderboards/season/`,
).then((data) => (data.detail === undefined ? data.count : undefined)); ).then((data) => (data.detail === undefined ? data.count : undefined));
@@ -98,7 +101,10 @@ await Promise.all([
console.log('Converting to an array...'); console.log('Converting to an array...');
for (let index = 0; index < PLAYERS; index++) { for (let index = 0; index < PLAYERS; index++) {
const listing = players[index + 1]; const listing = players[index + 1];
if (!listing) console.warn(`Position ${index + 1} had no player`); if (!listing) {
console.warn(`Position ${index + 1} had no player`);
continue;
}
leaderboard[index] = { leaderboard[index] = {
id: listing.spa_id, id: listing.spa_id,
@@ -110,23 +116,19 @@ const leaderboardJSON = JSON.stringify(leaderboard);
if (publish) { if (publish) {
const octokit = new Octokit({ auth: env.GH_TOKEN }); const octokit = new Octokit({ auth: env.GH_TOKEN });
const info = await patientFetchJSON<RatingsInfo & { detail: undefined }>( const info = await patientFetchJSON<RatingsInfo & { detail: undefined }>(
`https://${server}.wotblitz.com/en/api/rating-leaderboards/season/`, `https://${server}.wotblitz.com/en/api/rating-leaderboards/season/`,
); );
const normalizedServer = server === 'na' ? 'com' : server; const normalizedServer = server === 'na' ? 'com' : server;
const infoPath = `regions/${normalizedServer}/ratings/${info.current_season}/info.json`;
const infoPath = `${normalizedServer}/ratings/${info.current_season}/info.json`; const leaderboardPath = `regions/${normalizedServer}/ratings/${info.current_season}/${target}.json`;
const leaderboardPath = `${normalizedServer}/ratings/${info.current_season}/${
latest ? 'latest' : 'midnight'
}.json`;
const infoJSON = JSON.stringify(info); const infoJSON = JSON.stringify(info);
console.log(`Publishing to season ${info.current_season}...`); console.log(`Publishing to season ${info.current_season}...`);
commitMultipleFiles( commitMultipleFiles(
octokit, octokit,
'tresabhi', 'tresabhi',
'blitzkrieg-db', 'blitzkrieg-assets',
'main', 'main',
new Date().toString(), new Date().toString(),
[ [
+12
View File
@@ -0,0 +1,12 @@
import { readdir } from 'fs/promises';
import packageJSON from '../package.json';
const { version } = packageJSON;
const changelogs = await readdir('docs/changelogs');
const hasVersion = changelogs.includes(`${version}.md`);
if (hasVersion) {
console.log(`Version ${version} found in changelogs`);
} else {
throw new Error(`Version ${version} not found in changelogs`);
}
+3 -8
View File
@@ -207,15 +207,9 @@ export default function SessionPage() {
since !== undefined && since !== undefined &&
diff !== undefined && ( diff !== undefined && (
<Breakdown.Row <Breakdown.Row
color={session.color}
minimized={!session.showCareer} minimized={!session.showCareer}
title={`Since ${since.toLocaleString(undefined, { title={session.title}
hour: 'numeric',
minute: 'numeric',
hour12: true,
month: 'short',
year: 'numeric',
day: 'numeric',
})}`}
stats={session.customColumns.map((customColumn) => { stats={session.customColumns.map((customColumn) => {
const rowStat = totalRowStats[customColumn.display]; const rowStat = totalRowStats[customColumn.display];
@@ -293,6 +287,7 @@ export default function SessionPage() {
return ( return (
<Breakdown.Row <Breakdown.Row
color={session.color}
key={stats.tank_id} key={stats.tank_id}
minimized={!session.showCareer} minimized={!session.showCareer}
title={tankopedia?.name ?? `Unknown tank ${stats.tank_id}`} title={tankopedia?.name ?? `Unknown tank ${stats.tank_id}`}
@@ -23,8 +23,6 @@ export function CustomColumn({ column, Builder }: CustomColumn) {
<Builder.SubTrigger>Column {column + 1}</Builder.SubTrigger> <Builder.SubTrigger>Column {column + 1}</Builder.SubTrigger>
<Builder.SubContent> <Builder.SubContent>
<Builder.Label>Display</Builder.Label>
<Builder.RadioGroup <Builder.RadioGroup
value={customColumn.display} value={customColumn.display}
onValueChange={(event) => onValueChange={(event) =>
+118 -28
View File
@@ -1,4 +1,21 @@
import { ContextMenu, DropdownMenu } from '@radix-ui/themes'; import {
Button,
ContextMenu,
Dialog,
DropdownMenu,
Flex,
Heading,
TextField,
} from '@radix-ui/themes';
import { createColors } from 'bepaint';
import { useRef, useState } from 'react';
import {
ACCENT_COLORS,
AccentColor,
GRAY_COLORS,
GrayColor,
PALETTES,
} from '../../../../constants/radixColors';
import { useSession } from '../../../../stores/session'; import { useSession } from '../../../../stores/session';
import { CustomColumn } from './CustomColumn'; import { CustomColumn } from './CustomColumn';
@@ -9,38 +26,111 @@ interface ContextMenuProps {
export function Menu({ Builder, reset }: ContextMenuProps) { export function Menu({ Builder, reset }: ContextMenuProps) {
const session = useSession(); const session = useSession();
const [showTitleEditor, setShowTitleEditor] = useState(false);
const titleInput = useRef<HTMLInputElement>(null);
return ( return (
<Builder.Content> <>
<CustomColumn Builder={Builder} column={0} /> <Dialog.Root open={showTitleEditor} onOpenChange={setShowTitleEditor}>
<CustomColumn Builder={Builder} column={1} /> <Dialog.Content>
<CustomColumn Builder={Builder} column={2} /> <Flex direction="column" gap="4">
<CustomColumn Builder={Builder} column={3} /> <Heading size="4">Edit title</Heading>
<Builder.Separator /> <Flex gap="2" style={{ width: '100%' }}>
<TextField.Root style={{ flex: 1 }}>
<TextField.Input
ref={titleInput}
defaultValue={session.title}
placeholder="Enter title..."
onKeyDown={(event) => {
if (event.key === 'Enter' && titleInput.current) {
setShowTitleEditor(false);
useSession.setState({ title: titleInput.current!.value });
}
}}
/>
</TextField.Root>
<Builder.CheckboxItem <Dialog.Close>
checked={session.showTotal} <Button
onCheckedChange={(checked) => onClick={() =>
useSession.setState({ showTotal: checked }) useSession.setState({ title: titleInput.current!.value })
} }
> >
Show total Set
</Builder.CheckboxItem> </Button>
<Builder.CheckboxItem </Dialog.Close>
checked={session.showCareer} </Flex>
onCheckedChange={(checked) => </Flex>
useSession.setState({ showCareer: checked }) </Dialog.Content>
} </Dialog.Root>
>
Show career
</Builder.CheckboxItem>
<Builder.Separator /> <Builder.Content>
<Builder.Sub>
<Builder.SubTrigger>Accent color</Builder.SubTrigger>
<Builder.Item color="red" onClick={reset}> <Builder.SubContent>
Reset <Builder.RadioGroup
</Builder.Item> value={session.color}
</Builder.Content> onValueChange={(value) =>
useSession.setState({ color: value as AccentColor | GrayColor })
}
>
{[...ACCENT_COLORS, ...GRAY_COLORS].map((color) => (
<Builder.RadioItem value={color} key={color}>
<Flex gap="2" align="center">
<div
style={{
backgroundColor: createColors(PALETTES[color])
.solidBackground,
width: 16,
height: 16,
borderRadius: '100%',
}}
/>
{`${color.charAt(0).toUpperCase()}${color.slice(1)}`}
</Flex>
</Builder.RadioItem>
))}
</Builder.RadioGroup>
</Builder.SubContent>
</Builder.Sub>
<Builder.Separator />
<Builder.Item onClick={() => setShowTitleEditor(true)}>
Edit title...
</Builder.Item>
<CustomColumn Builder={Builder} column={0} />
<CustomColumn Builder={Builder} column={1} />
<CustomColumn Builder={Builder} column={2} />
<CustomColumn Builder={Builder} column={3} />
<Builder.Separator />
<Builder.CheckboxItem
checked={session.showTotal}
onCheckedChange={(checked) =>
useSession.setState({ showTotal: checked })
}
>
Show total
</Builder.CheckboxItem>
<Builder.CheckboxItem
checked={session.showCareer}
onCheckedChange={(checked) =>
useSession.setState({ showCareer: checked })
}
>
Show career
</Builder.CheckboxItem>
<Builder.Separator />
<Builder.Item color="red" onClick={reset}>
Reset
</Builder.Item>
</Builder.Content>
</>
); );
} }
+2
View File
@@ -11,6 +11,7 @@ const DOCS = {
introduction: 'guide/introduction', introduction: 'guide/introduction',
invite: 'guide/invite', invite: 'guide/invite',
timezones: 'guide/timezones', timezones: 'guide/timezones',
creators: 'guide/creators',
}; };
const DOC_DESCRIPTIONS: Record<keyof typeof DOCS, string> = { const DOC_DESCRIPTIONS: Record<keyof typeof DOCS, string> = {
permissions: 'The permissions needed for the bot to function', permissions: 'The permissions needed for the bot to function',
@@ -18,6 +19,7 @@ const DOC_DESCRIPTIONS: Record<keyof typeof DOCS, string> = {
introduction: 'About the bot', introduction: 'About the bot',
invite: 'How to invite the bot', invite: 'How to invite the bot',
timezones: 'How Blitzkrieg infers and uses your timezone', timezones: 'How Blitzkrieg infers and uses your timezone',
creators: 'Who created the bot',
}; };
function addDocsSubcommands(option: SlashCommandSubcommandsOnlyBuilder) { function addDocsSubcommands(option: SlashCommandSubcommandsOnlyBuilder) {
-15
View File
@@ -1,15 +0,0 @@
import { AttachmentBuilder, SlashCommandBuilder } from 'discord.js';
import { CommandRegistry } from '../events/interactionCreate';
export const creditsCommand: CommandRegistry = {
inProduction: true,
inPublic: true,
command: new SlashCommandBuilder()
.setName('credits')
.setDescription('Me and the people who made this bot'),
async handler() {
return new AttachmentBuilder('https://i.imgur.com/ZF5ch33.png');
},
};
+15 -23
View File
@@ -1,11 +1,6 @@
import { SlashCommandBuilder } from 'discord.js'; import { SlashCommandBuilder } from 'discord.js';
import packageJSON from '../../package.json' assert { type: 'json' }; import packageJSON from '../../package.json' assert { type: 'json' };
import getClientId from '../core/blitzkrieg/getClientId';
import { tankAverages } from '../core/blitzstars/tankAverages';
import { tankopedia } from '../core/blitzstars/tankopedia';
import { client } from '../core/discord/client'; import { client } from '../core/discord/client';
import embedInfo from '../core/discord/embedInfo';
import markdownTable from '../core/discord/markdownTable';
import { CommandRegistry } from '../events/interactionCreate'; import { CommandRegistry } from '../events/interactionCreate';
const executionStart = new Date().getTime(); const executionStart = new Date().getTime();
@@ -21,24 +16,21 @@ export const debugCommand: CommandRegistry = {
async handler(interaction) { async handler(interaction) {
const currentTime = new Date().getTime(); const currentTime = new Date().getTime();
const uptime = currentTime - executionStart; const uptime = currentTime - executionStart;
const list = [
['Version', packageJSON.version],
['Shard', client.shard?.ids[0] ?? 'default'],
[
'Uptime',
`${Math.floor((uptime / 1000 / 60 / 60) % 24)}h ${Math.floor(
(uptime / 1000 / 60) % 60,
)}m ${Math.floor((uptime / 1000) % 60)}s ${Math.floor(
uptime % 1000,
)}ms`,
],
]
.map(([key, value]) => `- ${key}: ${value}`)
.join('\n');
return embedInfo( return `# Debug\n\n${list}`;
`${client.user?.username} debug information`,
markdownTable([
['Version', packageJSON.version],
['Client ID', getClientId()],
['Tag', interaction.client.user.tag],
[
'Uptime',
`${Math.floor(uptime / 1000 / 60 / 60 / 24)}d ${Math.floor(
(uptime / 1000 / 60 / 60) % 24,
)}h ${Math.floor((uptime / 1000 / 60) % 60)}m ${Math.floor(
(uptime / 1000) % 60,
)}s ${Math.floor(uptime % 1000)}ms`,
],
['Tankopedia cached', `${(await tankopedia) !== undefined}`],
['Tank averages cached', `${(await tankAverages) !== undefined}`],
]),
);
}, },
}; };
+6 -4
View File
@@ -17,7 +17,6 @@ import { getClanAccountInfo } from '../core/blitz/getClanAccountInfo';
import getRatingsInfo from '../core/blitz/getRatingsInfo'; import getRatingsInfo from '../core/blitz/getRatingsInfo';
import { getRatingsLeague } from '../core/blitz/getRatingsLeague'; import { getRatingsLeague } from '../core/blitz/getRatingsLeague';
import { getRatingsNeighbors } from '../core/blitz/getRatingsNeighbors'; import { getRatingsNeighbors } from '../core/blitz/getRatingsNeighbors';
import regionToRegionSubdomain from '../core/blitz/regionToRegionSubdomain';
import { getArchivedLatestSeasonNumber } from '../core/blitzkrieg/getArchivedLatestSeasonNumber'; import { getArchivedLatestSeasonNumber } from '../core/blitzkrieg/getArchivedLatestSeasonNumber';
import getArchivedRatingsInfo from '../core/blitzkrieg/getArchivedRatingsInfo'; import getArchivedRatingsInfo from '../core/blitzkrieg/getArchivedRatingsInfo';
import { getArchivedRatingsLeaderboard } from '../core/blitzkrieg/getArchivedRatingsLeaderboard'; import { getArchivedRatingsLeaderboard } from '../core/blitzkrieg/getArchivedRatingsLeaderboard';
@@ -256,7 +255,6 @@ export const ratingsCommand = new Promise<CommandRegistryRaw>(
if (regionRatingsInfo.detail !== undefined) return noOngoingSeason; if (regionRatingsInfo.detail !== undefined) return noOngoingSeason;
const regionSubdomain = regionToRegionSubdomain(region);
const result = const result =
subcommandGroup === 'current' subcommandGroup === 'current'
? await getRatingsLeague(region, leagueIndex).then( ? await getRatingsLeague(region, leagueIndex).then(
@@ -461,11 +459,15 @@ export const ratingsCommand = new Promise<CommandRegistryRaw>(
{items && ( {items && (
<Leaderboard.Root> <Leaderboard.Root>
{playersBefore > 0 && ( {playersBefore > 0 && (
<Leaderboard.Gap message={`+ ${playersBefore} more`} /> <Leaderboard.Gap
message={`+ ${playersBefore.toLocaleString()} more`}
/>
)} )}
{items} {items}
{playersAfter > 0 && ( {playersAfter > 0 && (
<Leaderboard.Gap message={`+ ${playersAfter} more`} /> <Leaderboard.Gap
message={`+ ${playersAfter.toLocaleString()} more`}
/>
)} )}
</Leaderboard.Root> </Leaderboard.Root>
)} )}
+4 -1
View File
@@ -6,7 +6,10 @@ export interface RootProps {
export function Root({ children }: RootProps) { export function Root({ children }: RootProps) {
return ( return (
<div style={{ display: 'flex', flexDirection: 'column', gap: 8 }}> <div
className="session-tracker-root"
style={{ display: 'flex', flexDirection: 'column', gap: 8 }}
>
{children} {children}
</div> </div>
); );
+33 -21
View File
@@ -1,5 +1,10 @@
import { createColors } from 'bepaint';
import { Percentile } from '../../../constants/percentiles'; import { Percentile } from '../../../constants/percentiles';
import { theme } from '../../../stitches.config'; import {
AccentColor,
GrayColor,
PALETTES,
} from '../../../constants/radixColors';
import { TREE_TYPE_ICONS, TreeTypeEnum } from '../../Tanks'; import { TREE_TYPE_ICONS, TreeTypeEnum } from '../../Tanks';
import { RowStat } from './RowStat'; import { RowStat } from './RowStat';
@@ -17,18 +22,29 @@ interface RowProps {
minimized?: boolean; minimized?: boolean;
treeType?: TreeTypeEnum; treeType?: TreeTypeEnum;
tankType?: string; tankType?: string;
color?: AccentColor | GrayColor;
stats: (RowStatItem | undefined)[]; stats: (RowStatItem | undefined)[];
} }
export function Row(props: RowProps) { export function Row({
color = 'slate',
stats,
title,
minimized,
tankType,
treeType,
type,
}: RowProps) {
const theme = createColors(PALETTES[`${color}Dark`]);
return ( return (
<div <div
className="session-tracker-row"
style={{ style={{
display: 'flex', display: 'flex',
flexDirection: 'column', flexDirection: 'column',
borderRadius: 4, borderRadius: 4,
backgroundColor: theme.colors.appBackground2, backgroundColor: theme.appBackground2,
overflow: 'hidden', overflow: 'hidden',
}} }}
> >
@@ -39,16 +55,12 @@ export function Row(props: RowProps) {
justifyContent: 'center', justifyContent: 'center',
padding: 8, padding: 8,
gap: 4, gap: 4,
backgroundColor: theme.colors.componentInteractive, backgroundColor: theme.componentInteractive,
}} }}
> >
{props.type === 'tank' && props.tankType !== undefined && ( {type === 'tank' && tankType !== undefined && (
<img <img
src={ src={TREE_TYPE_ICONS[treeType ?? TreeTypeEnum.TechTree][tankType]}
TREE_TYPE_ICONS[props.treeType ?? TreeTypeEnum.TechTree][
props.tankType
]
}
style={{ width: 16, height: 16 }} style={{ width: 16, height: 16 }}
/> />
)} )}
@@ -56,18 +68,18 @@ export function Row(props: RowProps) {
<span <span
style={{ style={{
color: color:
props.type === 'tank' type === 'tank'
? props.treeType === TreeTypeEnum.Collector ? treeType === TreeTypeEnum.Collector
? theme.colors.textLowContrast_blue ? theme.textLowContrast_blue
: props.treeType === TreeTypeEnum.Premium : treeType === TreeTypeEnum.Premium
? theme.colors.textLowContrast_amber ? theme.textLowContrast_amber
: theme.colors.textHighContrast : theme.textHighContrast
: theme.colors.textLowContrast, : theme.textLowContrast,
fontWeight: 900, fontWeight: 900,
fontSize: 16, fontSize: 16,
}} }}
> >
{props.title} {title}
</span> </span>
</div> </div>
@@ -78,11 +90,11 @@ export function Row(props: RowProps) {
paddingBottom: 8, paddingBottom: 8,
}} }}
> >
{props.stats.map( {stats.map(
(row, index) => (row, index) =>
row && ( row && (
<RowStat <RowStat
minimized={props.minimized} minimized={minimized}
key={index} key={index}
name={`${row.title} • ${row.career ?? '--'}`} name={`${row.title} • ${row.career ?? '--'}`}
value={row.current ?? '--'} value={row.current ?? '--'}
@@ -1,5 +1,10 @@
import { createColors } from 'bepaint';
import { Percentile } from '../../../constants/percentiles'; import { Percentile } from '../../../constants/percentiles';
import { theme } from '../../../stitches.config'; import {
AccentColor,
GrayColor,
PALETTES,
} from '../../../constants/radixColors';
import PercentileIndicator from '../../PercentileIndicator'; import PercentileIndicator from '../../PercentileIndicator';
export interface RowStatProps { export interface RowStatProps {
@@ -8,6 +13,7 @@ export interface RowStatProps {
delta?: number; delta?: number;
percentile?: Percentile; percentile?: Percentile;
minimized?: boolean; minimized?: boolean;
color?: AccentColor | GrayColor;
} }
export function RowStat({ export function RowStat({
@@ -16,9 +22,13 @@ export function RowStat({
delta, delta,
percentile, percentile,
minimized = false, minimized = false,
color = 'slate',
}: RowStatProps) { }: RowStatProps) {
const theme = createColors(PALETTES[`${color}Dark`]);
return ( return (
<div <div
className="session-tracker-row-stat"
style={{ style={{
display: 'flex', display: 'flex',
flexDirection: 'column', flexDirection: 'column',
@@ -52,7 +62,7 @@ export function RowStat({
<span <span
style={{ style={{
color: theme.colors.textHighContrast, color: theme.textHighContrast,
fontWeight: 'bold', fontWeight: 'bold',
fontSize: 16, fontSize: 16,
textAlign: 'center', textAlign: 'center',
@@ -65,7 +75,7 @@ export function RowStat({
{!minimized && ( {!minimized && (
<span <span
style={{ style={{
color: theme.colors.textLowContrast, color: theme.textLowContrast,
textAlign: 'center', textAlign: 'center',
fontSize: 12, fontSize: 12,
}} }}
+55
View File
@@ -0,0 +1,55 @@
import * as colors from '@radix-ui/colors';
import { Theme } from '@radix-ui/themes';
import { ComponentProps } from 'react';
export type AccentColor = Exclude<
ComponentProps<typeof Theme>['accentColor'],
'gray' | undefined
>;
export type AccentColorDark = `${AccentColor}Dark`;
export type GrayColor = Exclude<
ComponentProps<typeof Theme>['grayColor'],
'auto' | undefined
>;
export type GrayColorDark = `${GrayColor}Dark`;
export const ACCENT_COLORS: AccentColor[] = [
'tomato',
'red',
'ruby',
'crimson',
'pink',
'plum',
'purple',
'violet',
'iris',
'indigo',
'blue',
'cyan',
'teal',
'jade',
'green',
'grass',
'brown',
'orange',
'sky',
'mint',
'lime',
'yellow',
'amber',
'gold',
'bronze',
];
export const GRAY_COLORS: GrayColor[] = [
'gray',
'mauve',
'slate',
'sage',
'olive',
'sand',
];
export const PALETTES: Record<
AccentColor | AccentColorDark | GrayColor | GrayColorDark,
{ [key: `${string}${number}`]: string }
> = colors;
@@ -8,7 +8,7 @@ export async function getArchivedLatestSeasonNumber() {
if (ratingsInfo.detail) { if (ratingsInfo.detail) {
const comURL = ( const comURL = (
(await fetch( (await fetch(
'https://api.github.com/repos/tresabhi/blitzkrieg-db/git/trees/main', 'https://api.github.com/repos/tresabhi/blitzkrieg-assets/git/trees/main/regions',
).then((response) => response.json())) as { ).then((response) => response.json())) as {
tree: { path: string; url: string }[]; tree: { path: string; url: string }[];
} }
@@ -24,7 +24,7 @@ export default async function getArchivedRatingsInfo(
} }
const response = await fetch( const response = await fetch(
`https://raw.githubusercontent.com/tresabhi/blitzkrieg-db/main/${region}/ratings/${season}/info.json`, `https://raw.githubusercontent.com/tresabhi/blitzkrieg-assets/main/regions/${region}/ratings/${season}/info.json`,
); );
const jsonContent = (await response.json()) as RatingsInfo & { const jsonContent = (await response.json()) as RatingsInfo & {
detail: undefined; detail: undefined;
@@ -19,7 +19,7 @@ export async function getArchivedRatingsLeaderboard(
} }
const response = await fetch( const response = await fetch(
`https://raw.githubusercontent.com/tresabhi/blitzkrieg-db/main/${region}/ratings/${season}/latest.json`, `https://raw.githubusercontent.com/tresabhi/blitzkrieg-assets/main/regions/${region}/ratings/${season}/latest.json`,
); );
const json = (await response.json()) as BlitzkriegRatingsLeaderboard; const json = (await response.json()) as BlitzkriegRatingsLeaderboard;
LEADERBOARD_CACHE[region][season] = json; LEADERBOARD_CACHE[region][season] = json;
@@ -1,7 +1,7 @@
import { BlitzkriegRatingsLeaderboard } from '../../../scripts/buildRatingsLeaderboard'; import { BlitzkriegRatingsLeaderboard } from '../../../scripts/buildRatingsLeaderboard';
import { Region } from '../../constants/regions'; import { Region } from '../../constants/regions';
export const DATABASE_REPO = { owner: 'tresabhi', repo: 'blitzkrieg-db' }; export const DATABASE_REPO = { owner: 'tresabhi', repo: 'blitzkrieg-assets' };
const MIDNIGHT_LEADERBOARD_CACHE: Record< const MIDNIGHT_LEADERBOARD_CACHE: Record<
Region, Region,
@@ -22,7 +22,7 @@ export default async function getArchivedRatingsMidnightLeaderboard(
try { try {
const response = await fetch( const response = await fetch(
`https://raw.githubusercontent.com/tresabhi/blitzkrieg-db/main/${region}/ratings/${season}/midnight.json`, `https://raw.githubusercontent.com/tresabhi/blitzkrieg-assets/main/regions/${region}/ratings/${season}/midnight.json`,
); );
const json = (await response.json()) as BlitzkriegRatingsLeaderboard; const json = (await response.json()) as BlitzkriegRatingsLeaderboard;
MIDNIGHT_LEADERBOARD_CACHE[region][season] = json; MIDNIGHT_LEADERBOARD_CACHE[region][season] = json;
+2 -2
View File
@@ -7,8 +7,8 @@ export async function patientFetchJSON<Type extends object>(
while (patientJSON! === undefined) { while (patientJSON! === undefined) {
try { try {
patientJSON = (await fetch(url, options).then(({ json }) => patientJSON = (await fetch(url, options).then((response) =>
json(), response.json(),
)) as Type; )) as Type;
} catch (error) { } catch (error) {
console.warn( console.warn(
+2 -1
View File
@@ -1,10 +1,11 @@
import { Client, GatewayIntentBits } from 'discord.js'; import { Client, GatewayIntentBits } from 'discord.js';
import guildMemberAdd from '../../events/guildMemberAdd'; import guildMemberAdd from '../../events/guildMemberAdd';
import interactionCreate from '../../events/interactionCreate'; import interactionCreate from '../../events/interactionCreate';
import ready from '../../events/ready';
export const client = new Client({ export const client = new Client({
intents: [GatewayIntentBits.Guilds, GatewayIntentBits.GuildMembers], intents: [GatewayIntentBits.Guilds, GatewayIntentBits.GuildMembers],
}) })
// .on('ready', ready) .on('ready', ready)
.on('guildMemberAdd', guildMemberAdd) .on('guildMemberAdd', guildMemberAdd)
.on('interactionCreate', interactionCreate); .on('interactionCreate', interactionCreate);
-2
View File
@@ -16,7 +16,6 @@ import {
import discord from '../../../discord.json' assert { type: 'json' }; import discord from '../../../discord.json' assert { type: 'json' };
import { aboutCommand } from '../../commands/about'; import { aboutCommand } from '../../commands/about';
import { breakdownCommand } from '../../commands/breakdown'; import { breakdownCommand } from '../../commands/breakdown';
import { creditsCommand } from '../../commands/credits';
import { debugCommand } from '../../commands/debug'; import { debugCommand } from '../../commands/debug';
import { eligibleCommand } from '../../commands/eligible'; import { eligibleCommand } from '../../commands/eligible';
import { evolutionCommand } from '../../commands/evolution'; import { evolutionCommand } from '../../commands/evolution';
@@ -102,7 +101,6 @@ export const COMMANDS_RAW: CommandRegistry[] = [
evolutionCommand, evolutionCommand,
statsCommand, statsCommand,
ratingsCommand, ratingsCommand,
creditsCommand,
]; ];
export const commands = Promise.all(COMMANDS_RAW).then((rawCommands) => export const commands = Promise.all(COMMANDS_RAW).then((rawCommands) =>
+26 -2
View File
@@ -1,5 +1,29 @@
import { Client } from 'discord.js'; import { ActivityType, Client } from 'discord.js';
export default function ready(client: Client<true>) { export default function ready(client: Client<true>) {
console.log(`🟢 Launched bot ${client.shard?.ids[0]}`); console.log(`🟢 Launched bot ${client.shard?.ids[0] ?? 'default'}`);
const activities: (() => string)[] = [
() => `Living in ${client.guilds.cache.size.toLocaleString()} servers`,
() =>
`Serving ${client.guilds.cache
.reduce((accumulator, guild) => accumulator + guild.memberCount, 0)
.toLocaleString()} users`,
() =>
`Observing ${client.guilds.cache
.reduce(
(accumulator, guild) => accumulator + guild.channels.cache.size,
0,
)
.toLocaleString()} channels`,
];
client.user.setPresence({
activities: [
{
type: ActivityType.Custom,
name: activities[Math.floor(Math.random() * activities.length)](),
},
],
});
} }
+6 -3
View File
@@ -2,6 +2,7 @@ import { produce } from 'immer';
import { create } from 'zustand'; import { create } from 'zustand';
import { devtools, persist } from 'zustand/middleware'; import { devtools, persist } from 'zustand/middleware';
import { CustomColumnDisplay } from '../app/tools/session/components/CustomColumn'; import { CustomColumnDisplay } from '../app/tools/session/components/CustomColumn';
import { AccentColor, GrayColor } from '../constants/radixColors';
import { Region } from '../constants/regions'; import { Region } from '../constants/regions';
import { WARGAMING_APPLICATION_ID } from '../constants/wargamingApplicationID'; import { WARGAMING_APPLICATION_ID } from '../constants/wargamingApplicationID';
import fetchBlitz from '../core/blitz/fetchBlitz'; import fetchBlitz from '../core/blitz/fetchBlitz';
@@ -21,6 +22,7 @@ type Session = (
time: number; time: number;
} }
) & { ) & {
title: string;
resetPrompt: boolean; resetPrompt: boolean;
embedPrompt: boolean; embedPrompt: boolean;
customColumns: { customColumns: {
@@ -29,6 +31,7 @@ type Session = (
}[] & { length: 4 }; }[] & { length: 4 };
showTotal: boolean; showTotal: boolean;
showCareer: boolean; showCareer: boolean;
color: AccentColor | GrayColor;
}; };
export async function setSession(region: Region, id: number, nickname: string) { export async function setSession(region: Region, id: number, nickname: string) {
@@ -66,6 +69,7 @@ export const useSession = create<Session>()(
devtools( devtools(
persist( persist(
(set) => ({ (set) => ({
title: 'Untitled session',
isTracking: false, isTracking: false,
resetPrompt: true, resetPrompt: true,
showTotal: true, showTotal: true,
@@ -78,10 +82,9 @@ export const useSession = create<Session>()(
{ display: 'wn8', showDelta: false }, { display: 'wn8', showDelta: false },
{ display: 'damage', showDelta: true }, { display: 'damage', showDelta: true },
], ],
color: 'slate',
}), }),
{ { name: 'session' },
name: 'session',
},
), ),
), ),
); );