mirror of
https://github.com/blitzkit/blitzkit.git
synced 2026-10-21 10:47:04 +02:00
Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
cb9d283f62 | ||
|
|
8aba19e05b | ||
|
|
b7b4035492 | ||
|
|
3667fd82b7 | ||
|
|
691d5cde27 | ||
|
|
7f431b07e1 | ||
|
|
8264f19ad4 | ||
|
|
e947cfba45 | ||
|
|
e69590c035 | ||
|
|
8b19393d7c | ||
|
|
9480603572 | ||
|
|
90c6535a4c | ||
|
|
258588921a | ||
|
|
525b309037 | ||
|
|
2f941b9224 | ||
|
|
259c4240b5 | ||
|
|
9eb7157fce |
No files matched your search
@@ -29,4 +29,4 @@ jobs:
|
||||
unzip bot.zip
|
||||
|
||||
- name: Run bot
|
||||
run: NODE_ENV=production GH_TOKEN=${{ secrets.GH_TOKEN }} DISCORD_TOKEN=${{ secrets.DISCORD_TOKEN }} WARGAMING_APPLICATION_ID=${{ WARGAMING_APPLICATION_ID }} node --enable-source-maps --trace-warnings bot/index.cjs
|
||||
run: NODE_ENV=production GH_TOKEN=${{ secrets.GH_TOKEN }} DISCORD_TOKEN=${{ secrets.DISCORD_TOKEN }} node --enable-source-maps --trace-warnings index.cjs
|
||||
@@ -1,4 +1,4 @@
|
||||
name: CI Build
|
||||
name: CI Build Bot
|
||||
|
||||
on: [push, pull_request]
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
name: CI Build
|
||||
name: CI Build Docs
|
||||
|
||||
on: [push, pull_request]
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
name: CI Build
|
||||
name: CI Build Website
|
||||
|
||||
on: [push, pull_request]
|
||||
|
||||
|
||||
@@ -1,21 +1,42 @@
|
||||
# blitzkrieg
|
||||
|
||||
A Discord bot for anything and everything related to World of Tanks Blitz.
|
||||
Tools for everything World of Tanks Blitz
|
||||
|
||||
## Invite the Bot
|
||||
## Invite the bot
|
||||
|
||||
Join the [Discord server](https://discord.gg/nDt7AjGJQH), click on the bot's profile, and click "Add to Server".
|
||||
Go to [application directory for Blitzkrieg](https://discord.com/application-directory/1097673957865443370) and click "Add to Server." Voila! You're ready to go.
|
||||
|
||||
## Using
|
||||

|
||||
|
||||
### Installing dependencies
|
||||
## Visit the website
|
||||
|
||||
### https://blitz-krieg.vercel.app/
|
||||
|
||||

|
||||
|
||||
## Visit the documentation website
|
||||
|
||||
### https://tresabhi.github.io/blitzkrieg/
|
||||
|
||||

|
||||
|
||||
## Run the bot
|
||||
|
||||
### Install dependencies
|
||||
|
||||
```bash
|
||||
yarn
|
||||
```
|
||||
|
||||
### Running
|
||||
### Create `.env`
|
||||
|
||||
```env
|
||||
GH_TOKEN={YOUR_GITHUB_TOKEN_HERE}
|
||||
DISCORD_TOKEN={YOUR_DISCORD_TOKE_HERE}
|
||||
```
|
||||
|
||||
### Run the command
|
||||
|
||||
```bash
|
||||
yarn start discord-token=<token> wargaming-application-id=<id>
|
||||
yarn dev:bot
|
||||
```
|
||||
@@ -0,0 +1,17 @@
|
||||
# Blitzkrieg 1.13.1
|
||||
|
||||
The quickest minor update in town 🤠
|
||||
|
||||
## Changes
|
||||
|
||||
- Added a title, description, and icon to the website
|
||||
- Added display options to the session tracker
|
||||
|
||||
## Fixes
|
||||
|
||||
- Center aligned stats in breakdown to work better on low width devices
|
||||
- Center aligned the Blitzkrieg logo in the navbar
|
||||
|
||||
## Technical Changes
|
||||
|
||||
- Added up-to-date information to `README.md` and embed docs
|
||||
+12
-12
@@ -1,23 +1,23 @@
|
||||
# Embeds
|
||||
|
||||
Embeds are generated by a few commands as a URL that can be loaded in a browser/streaming software.
|
||||
Embeds are URLs generated by commands or tools that represent the "naked" version of the respective command or tool
|
||||
|
||||
## Creating Embeds
|
||||
|
||||
1. Use a command of your liking (for example, `/stats`).
|
||||
2. Customize the command however you like and the URL generated for the embed will match your needs.
|
||||
3. Send the command and when the bot is "done thinking," an "Embed" button will appear below the bot's reply.
|
||||
1. Use a command or tool and click on "Embed" if it's available
|
||||
2. Make sure to tweak the settings of the command or tool because embeds replicate everything
|
||||
|
||||
## Using Embeds in Streaming Softwares
|
||||
|
||||
1. Click on the "Embed" button.
|
||||
2. Copy the URL from your browser.
|
||||
3. Paste the URL into a Browser Source.
|
||||
4. Set the refresh rate/FPS to something very low like `0.0167` (that's 1 frame every 60 seconds).
|
||||
1. Click on the "Embed" button
|
||||
- If this was generated by a command, copy the URL from the browser
|
||||
- If this was generated by a tool, the URL has been copied to your clipboard already
|
||||
2. Paste this URL into your streaming service as a "Browser Source"
|
||||
- Tool embeds use local storage so data won't be transferred from you browser to your streaming software
|
||||
- Make sure to visit the tool's page in your streaming software (using the "Interact" feature) and then open the embed
|
||||
- Set your browser source refresh rate to `1Hz` because that's how fast embeds refresh
|
||||
|
||||
## How Embeds Behave
|
||||
|
||||
- They load like any normal website albeit with a significant delay.
|
||||
- They auto refresh every `60s`.
|
||||
- All embeds and images generated by Blitzkrieg have a width of `640px` but the height varies and must be found manually through trial and error.
|
||||
- It's okay to have a Browser Source that has a height larger than needed as Blitzkrieg embeds are transparent.
|
||||
- They load like any normal website
|
||||
- They auto refresh every `1s`
|
||||
+3
-2
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "blitzkrieg",
|
||||
"version": "1.13.0",
|
||||
"description": "🎉 All-in-one Discord bot for everything World of Tanks Blitz",
|
||||
"version": "1.13.1",
|
||||
"description": "🎉 Tools for everything World of Tanks Blitz",
|
||||
"main": "src/server.ts",
|
||||
"type": "module",
|
||||
"scripts": {
|
||||
@@ -37,6 +37,7 @@
|
||||
"esbuild": "^0.19.3",
|
||||
"express": "^4.18.2",
|
||||
"fuzzysort": "^2.0.4",
|
||||
"immer": "^10.0.2",
|
||||
"lodash": "^4.17.21",
|
||||
"markdown-escape": "^2.0.0",
|
||||
"next": "^13.5.2",
|
||||
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 177 KiB |
+158
-122
@@ -12,6 +12,7 @@ import { TankopediaEntry, tankopedia } from '../../../core/blitz/tankopedia';
|
||||
import { tankAverages } from '../../../core/blitzstars/tankAverages';
|
||||
import { useSession } from '../../../stores/session';
|
||||
import { IndividualTankStats, TanksStats } from '../../../types/tanksStats';
|
||||
import { CustomColumnDisplay } from '../../tools/session/components/CustomColumn';
|
||||
|
||||
const REFRESH_RATE = 1 / 5;
|
||||
|
||||
@@ -139,136 +140,171 @@ export default function SessionPage() {
|
||||
return () => clearInterval(interval);
|
||||
}, [session]);
|
||||
|
||||
const totalRowStats: Record<
|
||||
CustomColumnDisplay,
|
||||
Breakdown.RowStatItem | undefined
|
||||
> = {
|
||||
battles: {
|
||||
title: 'Battles',
|
||||
current: sessionBattles?.toLocaleString(),
|
||||
career: tankStatsArray
|
||||
.reduce((accumulator, stats) => accumulator + stats.all.battles, 0)
|
||||
.toLocaleString(),
|
||||
},
|
||||
winrate: {
|
||||
title: 'Winrate',
|
||||
current: sessionBattles ? `${(100 * sessionWinrate).toFixed(2)}%` : '--',
|
||||
career: `${(100 * careerWinrate).toFixed(2)}%`,
|
||||
delta: sessionBattles === 0 ? 0 : sessionWinrate - careerWinrate,
|
||||
},
|
||||
wn8: (() => {
|
||||
if (!diff) return undefined;
|
||||
|
||||
const battlesWithWN8 = diff.list.reduce(
|
||||
(accumulator, { currentWN8, stats }) =>
|
||||
(currentWN8 === undefined ? 0 : stats.all.battles) + accumulator,
|
||||
0,
|
||||
);
|
||||
const currentWN8 =
|
||||
diff.list.reduce(
|
||||
(accumulator, { currentWN8, stats }) =>
|
||||
stats.all.battles * (currentWN8 ?? 0) + accumulator,
|
||||
0,
|
||||
) / battlesWithWN8!;
|
||||
|
||||
return {
|
||||
title: 'WN8',
|
||||
current: battlesWithWN8
|
||||
? Math.round(currentWN8!).toLocaleString()
|
||||
: '--',
|
||||
percentile: battlesWithWN8 ? getWN8Percentile(currentWN8!) : undefined,
|
||||
career: Math.round(diff.careerWN8).toLocaleString(),
|
||||
};
|
||||
})(),
|
||||
damage: {
|
||||
title: 'Damage',
|
||||
delta: sessionBattles === 0 ? 0 : currentDamage - careerDamage,
|
||||
current: sessionBattles
|
||||
? Math.round(currentDamage).toLocaleString()
|
||||
: '--',
|
||||
career: Math.round(careerDamage).toLocaleString(),
|
||||
},
|
||||
none: undefined,
|
||||
};
|
||||
|
||||
return (
|
||||
<Breakdown.Root>
|
||||
{session.isTracking && since !== undefined && diff !== undefined && (
|
||||
<Breakdown.Row
|
||||
title={`Since ${since.toLocaleString(undefined, {
|
||||
hour: 'numeric',
|
||||
minute: 'numeric',
|
||||
hour12: true,
|
||||
month: 'short',
|
||||
year: 'numeric',
|
||||
day: 'numeric',
|
||||
})}`}
|
||||
stats={[
|
||||
{
|
||||
title: 'Battles',
|
||||
current: sessionBattles!.toLocaleString(),
|
||||
career: tankStatsArray
|
||||
.reduce(
|
||||
(accumulator, stats) => accumulator + stats.all.battles,
|
||||
0,
|
||||
)
|
||||
.toLocaleString(),
|
||||
},
|
||||
{
|
||||
title: 'Winrate',
|
||||
current: sessionBattles
|
||||
? `${(100 * sessionWinrate).toFixed(2)}%`
|
||||
: '--',
|
||||
career: `${(100 * careerWinrate).toFixed(2)}%`,
|
||||
delta: sessionBattles === 0 ? 0 : sessionWinrate - careerWinrate,
|
||||
},
|
||||
(() => {
|
||||
const battlesWithWN8 = diff.list.reduce(
|
||||
(accumulator, { currentWN8, stats }) =>
|
||||
(currentWN8 === undefined ? 0 : stats.all.battles) +
|
||||
accumulator,
|
||||
0,
|
||||
);
|
||||
const currentWN8 =
|
||||
diff.list.reduce(
|
||||
(accumulator, { currentWN8, stats }) =>
|
||||
stats.all.battles * (currentWN8 ?? 0) + accumulator,
|
||||
0,
|
||||
) / battlesWithWN8;
|
||||
{session.showTotal &&
|
||||
session.isTracking &&
|
||||
since !== undefined &&
|
||||
diff !== undefined && (
|
||||
<Breakdown.Row
|
||||
minimized={!session.showCareer}
|
||||
title={`Since ${since.toLocaleString(undefined, {
|
||||
hour: 'numeric',
|
||||
minute: 'numeric',
|
||||
hour12: true,
|
||||
month: 'short',
|
||||
year: 'numeric',
|
||||
day: 'numeric',
|
||||
})}`}
|
||||
stats={session.customColumns.map((customColumn) => {
|
||||
const rowStat = totalRowStats[customColumn.display];
|
||||
|
||||
if (!rowStat) return undefined;
|
||||
|
||||
return {
|
||||
title: 'WN8',
|
||||
current: battlesWithWN8
|
||||
? Math.round(currentWN8).toLocaleString()
|
||||
: '--',
|
||||
percentile: battlesWithWN8
|
||||
? getWN8Percentile(currentWN8)
|
||||
: undefined,
|
||||
career: Math.round(diff.careerWN8).toLocaleString(),
|
||||
...rowStat,
|
||||
delta:
|
||||
customColumn.showDelta && rowStat.percentile === undefined
|
||||
? rowStat.delta
|
||||
: undefined,
|
||||
};
|
||||
})(),
|
||||
{
|
||||
title: 'Damage',
|
||||
delta: sessionBattles === 0 ? 0 : currentDamage - careerDamage,
|
||||
current: sessionBattles
|
||||
? Math.round(currentDamage).toLocaleString()
|
||||
: '--',
|
||||
career: Math.round(careerDamage).toLocaleString(),
|
||||
},
|
||||
]}
|
||||
/>
|
||||
)}
|
||||
})}
|
||||
/>
|
||||
)}
|
||||
|
||||
{diff?.list
|
||||
.sort((a, b) => b.stats.last_battle_time - a.stats.last_battle_time)
|
||||
.map(({ stats, tankopedia, career, careerWN8, currentWN8 }) => (
|
||||
<Breakdown.Row
|
||||
key={stats.tank_id}
|
||||
title={tankopedia?.name ?? `Unknown tank ${stats.tank_id}`}
|
||||
type="tank"
|
||||
tankType={tankopedia?.type}
|
||||
treeType={(() => {
|
||||
if (tankopedia?.is_collectible) return TreeTypeEnum.Collector;
|
||||
if (tankopedia?.is_premium) return TreeTypeEnum.Premium;
|
||||
})()}
|
||||
stats={[
|
||||
{
|
||||
title: 'Battles',
|
||||
current: stats.all.battles.toLocaleString(),
|
||||
career: career.all.battles.toLocaleString(),
|
||||
},
|
||||
{
|
||||
title: 'Winrate',
|
||||
current: `${(
|
||||
100 *
|
||||
(stats.all.wins / stats.all.battles)
|
||||
).toFixed(2)}%`,
|
||||
career: `${(
|
||||
100 *
|
||||
(career.all.wins / career.all.battles)
|
||||
).toFixed(2)}%`,
|
||||
delta:
|
||||
stats.all.wins / stats.all.battles -
|
||||
career.all.wins / career.all.battles,
|
||||
},
|
||||
{
|
||||
title: 'WN8',
|
||||
current:
|
||||
currentWN8 === undefined
|
||||
? undefined
|
||||
: Math.round(currentWN8).toLocaleString(),
|
||||
career:
|
||||
careerWN8 === undefined
|
||||
? undefined
|
||||
: Math.round(careerWN8).toLocaleString(),
|
||||
percentile:
|
||||
currentWN8 === undefined
|
||||
? undefined
|
||||
: getWN8Percentile(currentWN8),
|
||||
},
|
||||
{
|
||||
title: 'Damage',
|
||||
current: Math.round(
|
||||
stats.all.damage_dealt / stats.all.battles,
|
||||
).toLocaleString(),
|
||||
career: Math.round(
|
||||
career.all.damage_dealt / career.all.battles,
|
||||
).toLocaleString(),
|
||||
delta:
|
||||
stats.all.damage_dealt / stats.all.battles -
|
||||
career.all.damage_dealt / career.all.battles,
|
||||
},
|
||||
]}
|
||||
/>
|
||||
))}
|
||||
.map(({ stats, tankopedia, career, careerWN8, currentWN8 }) => {
|
||||
const rowStats: Record<
|
||||
CustomColumnDisplay,
|
||||
Breakdown.RowStatItem | undefined
|
||||
> = {
|
||||
battles: {
|
||||
title: 'Battles',
|
||||
current: stats.all.battles.toLocaleString(),
|
||||
career: career.all.battles.toLocaleString(),
|
||||
},
|
||||
winrate: {
|
||||
title: 'Winrate',
|
||||
current: `${(100 * (stats.all.wins / stats.all.battles)).toFixed(
|
||||
2,
|
||||
)}%`,
|
||||
career: `${(100 * (career.all.wins / career.all.battles)).toFixed(
|
||||
2,
|
||||
)}%`,
|
||||
delta:
|
||||
stats.all.wins / stats.all.battles -
|
||||
career.all.wins / career.all.battles,
|
||||
},
|
||||
wn8: {
|
||||
title: 'WN8',
|
||||
current:
|
||||
currentWN8 === undefined
|
||||
? undefined
|
||||
: Math.round(currentWN8).toLocaleString(),
|
||||
career:
|
||||
careerWN8 === undefined
|
||||
? undefined
|
||||
: Math.round(careerWN8).toLocaleString(),
|
||||
percentile:
|
||||
currentWN8 === undefined
|
||||
? undefined
|
||||
: getWN8Percentile(currentWN8),
|
||||
},
|
||||
damage: {
|
||||
title: 'Damage',
|
||||
current: Math.round(
|
||||
stats.all.damage_dealt / stats.all.battles,
|
||||
).toLocaleString(),
|
||||
career: Math.round(
|
||||
career.all.damage_dealt / career.all.battles,
|
||||
).toLocaleString(),
|
||||
delta:
|
||||
stats.all.damage_dealt / stats.all.battles -
|
||||
career.all.damage_dealt / career.all.battles,
|
||||
},
|
||||
none: undefined,
|
||||
};
|
||||
|
||||
return (
|
||||
<Breakdown.Row
|
||||
key={stats.tank_id}
|
||||
minimized={!session.showCareer}
|
||||
title={tankopedia?.name ?? `Unknown tank ${stats.tank_id}`}
|
||||
type="tank"
|
||||
tankType={tankopedia?.type}
|
||||
treeType={(() => {
|
||||
if (tankopedia?.is_collectible) return TreeTypeEnum.Collector;
|
||||
if (tankopedia?.is_premium) return TreeTypeEnum.Premium;
|
||||
})()}
|
||||
stats={session.customColumns.map((customColumn) => {
|
||||
const rowStat = rowStats[customColumn.display];
|
||||
|
||||
if (!rowStat) return undefined;
|
||||
|
||||
return {
|
||||
...rowStat,
|
||||
delta:
|
||||
customColumn.showDelta && rowStat.percentile === undefined
|
||||
? rowStat.delta
|
||||
: undefined,
|
||||
};
|
||||
})}
|
||||
/>
|
||||
);
|
||||
})}
|
||||
</Breakdown.Root>
|
||||
);
|
||||
}
|
||||
@@ -25,6 +25,14 @@ export default function RootLayout({ children }: RootLayoutProps) {
|
||||
|
||||
return (
|
||||
<html lang="en" className={robotoFlex.className}>
|
||||
<head>
|
||||
<title>Blitzkrieg</title>
|
||||
<meta
|
||||
name="description"
|
||||
content="🎉 Tools for everything World of Tanks Blitz"
|
||||
/>
|
||||
</head>
|
||||
|
||||
<body
|
||||
style={{
|
||||
margin: 0,
|
||||
|
||||
@@ -0,0 +1,66 @@
|
||||
import { DropdownMenu } from '@radix-ui/themes';
|
||||
import mutateSession, { useSession } from '../../../../stores/session';
|
||||
|
||||
export type CustomColumnDisplay =
|
||||
| 'battles'
|
||||
| 'winrate'
|
||||
| 'wn8'
|
||||
| 'damage'
|
||||
| 'none';
|
||||
|
||||
const NO_DELTA: CustomColumnDisplay[] = ['battles', 'wn8', 'none'];
|
||||
|
||||
interface CustomColumn {
|
||||
column: number;
|
||||
}
|
||||
|
||||
export function CustomColumn({ column }: CustomColumn) {
|
||||
const customColumn = useSession((state) => state.customColumns[column]);
|
||||
|
||||
return (
|
||||
<DropdownMenu.Sub>
|
||||
<DropdownMenu.SubTrigger>Column {column + 1}</DropdownMenu.SubTrigger>
|
||||
|
||||
<DropdownMenu.SubContent>
|
||||
<DropdownMenu.Label>Display</DropdownMenu.Label>
|
||||
|
||||
<DropdownMenu.RadioGroup
|
||||
value={customColumn.display}
|
||||
onValueChange={(event) =>
|
||||
mutateSession((draft) => {
|
||||
draft.customColumns[column].display =
|
||||
event as CustomColumnDisplay;
|
||||
})
|
||||
}
|
||||
>
|
||||
<DropdownMenu.RadioItem value="battles">
|
||||
Battles
|
||||
</DropdownMenu.RadioItem>
|
||||
<DropdownMenu.RadioItem value="winrate">
|
||||
Winrate
|
||||
</DropdownMenu.RadioItem>
|
||||
<DropdownMenu.RadioItem value="wn8">WN8</DropdownMenu.RadioItem>
|
||||
<DropdownMenu.RadioItem value="damage">Damage</DropdownMenu.RadioItem>
|
||||
<DropdownMenu.RadioItem value="none">None</DropdownMenu.RadioItem>
|
||||
</DropdownMenu.RadioGroup>
|
||||
|
||||
{!NO_DELTA.includes(customColumn.display) && (
|
||||
<>
|
||||
<DropdownMenu.Separator />
|
||||
|
||||
<DropdownMenu.CheckboxItem
|
||||
checked={customColumn.showDelta}
|
||||
onCheckedChange={(checked) =>
|
||||
mutateSession((draft) => {
|
||||
draft.customColumns[column].showDelta = checked;
|
||||
})
|
||||
}
|
||||
>
|
||||
Show delta
|
||||
</DropdownMenu.CheckboxItem>
|
||||
</>
|
||||
)}
|
||||
</DropdownMenu.SubContent>
|
||||
</DropdownMenu.Sub>
|
||||
);
|
||||
}
|
||||
@@ -1,6 +1,11 @@
|
||||
'use client';
|
||||
|
||||
import { CopyIcon, PersonIcon, ReloadIcon } from '@radix-ui/react-icons';
|
||||
import {
|
||||
CaretDownIcon,
|
||||
CopyIcon,
|
||||
PersonIcon,
|
||||
ReloadIcon,
|
||||
} from '@radix-ui/react-icons';
|
||||
import {
|
||||
AlertDialog,
|
||||
Button,
|
||||
@@ -23,10 +28,9 @@ import listPlayers, {
|
||||
import { useSession } from '../../../stores/session';
|
||||
import { NormalizedTankStats, TanksStats } from '../../../types/tanksStats';
|
||||
import SessionPage from '../../embeds/session/page';
|
||||
import { CustomColumn } from './components/CustomColumn';
|
||||
import * as styles from './page.css';
|
||||
|
||||
// 1 once per 5 seconds
|
||||
|
||||
export default function Page() {
|
||||
const input = useRef<HTMLInputElement>(null);
|
||||
const [searchResults, setSearchResults] = useState<
|
||||
@@ -150,6 +154,7 @@ export default function Page() {
|
||||
<AlertDialog.Root>
|
||||
<AlertDialog.Trigger>
|
||||
<Button
|
||||
variant="soft"
|
||||
onClick={(event) => {
|
||||
if (!session.promptBeforeReset) {
|
||||
event.preventDefault();
|
||||
@@ -206,6 +211,7 @@ export default function Page() {
|
||||
|
||||
<Tooltip content="Copy to clipboard">
|
||||
<Button
|
||||
variant="soft"
|
||||
className={styles.toolbarButton}
|
||||
onClick={() =>
|
||||
navigator.clipboard.writeText(
|
||||
@@ -216,6 +222,41 @@ export default function Page() {
|
||||
<CopyIcon width="16" height="16" /> Embed
|
||||
</Button>
|
||||
</Tooltip>
|
||||
|
||||
<DropdownMenu.Root>
|
||||
<DropdownMenu.Trigger>
|
||||
<Button variant="soft" className={styles.toolbarButton}>
|
||||
Options
|
||||
<CaretDownIcon />
|
||||
</Button>
|
||||
</DropdownMenu.Trigger>
|
||||
|
||||
<DropdownMenu.Content>
|
||||
<CustomColumn column={0} />
|
||||
<CustomColumn column={1} />
|
||||
<CustomColumn column={2} />
|
||||
<CustomColumn column={3} />
|
||||
|
||||
<DropdownMenu.Separator />
|
||||
|
||||
<DropdownMenu.CheckboxItem
|
||||
checked={session.showTotal}
|
||||
onCheckedChange={(checked) =>
|
||||
useSession.setState({ showTotal: checked })
|
||||
}
|
||||
>
|
||||
Show total
|
||||
</DropdownMenu.CheckboxItem>
|
||||
<DropdownMenu.CheckboxItem
|
||||
checked={session.showCareer}
|
||||
onCheckedChange={(checked) =>
|
||||
useSession.setState({ showCareer: checked })
|
||||
}
|
||||
>
|
||||
Show career
|
||||
</DropdownMenu.CheckboxItem>
|
||||
</DropdownMenu.Content>
|
||||
</DropdownMenu.Root>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
@@ -4,6 +4,14 @@ import { theme } from '../../../stitches.config';
|
||||
import { TREE_TYPE_ICONS, TreeTypeEnum } from '../../Tanks';
|
||||
import { RowStat } from './RowStat';
|
||||
|
||||
export interface RowStatItem {
|
||||
title: string;
|
||||
current?: number | string;
|
||||
career?: number | string;
|
||||
delta?: number;
|
||||
percentile?: Percentile;
|
||||
}
|
||||
|
||||
interface RowProps {
|
||||
type?: 'tank' | 'summary';
|
||||
title: string;
|
||||
@@ -11,13 +19,7 @@ interface RowProps {
|
||||
treeType?: TreeTypeEnum;
|
||||
tankType?: TankType;
|
||||
|
||||
stats: {
|
||||
title: string;
|
||||
current?: number | string;
|
||||
career?: number | string;
|
||||
delta?: number;
|
||||
percentile?: Percentile;
|
||||
}[];
|
||||
stats: (RowStatItem | undefined)[];
|
||||
}
|
||||
|
||||
export function Row(props: RowProps) {
|
||||
@@ -77,16 +79,19 @@ export function Row(props: RowProps) {
|
||||
paddingBottom: 8,
|
||||
}}
|
||||
>
|
||||
{props.stats.map((row, index) => (
|
||||
<RowStat
|
||||
minimized={props.minimized}
|
||||
key={index}
|
||||
name={`${row.title} • ${row.career ?? '--'}`}
|
||||
value={row.current ?? '--'}
|
||||
delta={row.delta}
|
||||
percentile={row.percentile}
|
||||
/>
|
||||
))}
|
||||
{props.stats.map(
|
||||
(row, index) =>
|
||||
row && (
|
||||
<RowStat
|
||||
minimized={props.minimized}
|
||||
key={index}
|
||||
name={`${row.title} • ${row.career ?? '--'}`}
|
||||
value={row.current ?? '--'}
|
||||
delta={row.delta}
|
||||
percentile={row.percentile}
|
||||
/>
|
||||
),
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
|
||||
@@ -55,6 +55,7 @@ export function RowStat({
|
||||
color: theme.colors.textHighContrast,
|
||||
fontWeight: 'bold',
|
||||
fontSize: 16,
|
||||
textAlign: 'center',
|
||||
}}
|
||||
>
|
||||
{value}
|
||||
@@ -62,7 +63,13 @@ export function RowStat({
|
||||
</div>
|
||||
|
||||
{!minimized && (
|
||||
<span style={{ color: theme.colors.textLowContrast, fontSize: 12 }}>
|
||||
<span
|
||||
style={{
|
||||
color: theme.colors.textLowContrast,
|
||||
textAlign: 'center',
|
||||
fontSize: 12,
|
||||
}}
|
||||
>
|
||||
{name}
|
||||
</span>
|
||||
)}
|
||||
|
||||
@@ -19,7 +19,15 @@ export default function Navbar() {
|
||||
{/* <Button>
|
||||
<HamburgerMenuIcon />
|
||||
</Button> */}
|
||||
<Link href="/" style={{ color: 'inherit' }}>
|
||||
<Link
|
||||
href="/"
|
||||
style={{
|
||||
color: 'inherit',
|
||||
display: 'flex',
|
||||
alignItems: 'center',
|
||||
justifyContent: 'center',
|
||||
}}
|
||||
>
|
||||
<BlitzkriegWormWide />
|
||||
</Link>
|
||||
{/* <Button>
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
import { produce } from 'immer';
|
||||
import { create } from 'zustand';
|
||||
import { devtools, persist } from 'zustand/middleware';
|
||||
import { CustomColumnDisplay } from '../app/tools/session/components/CustomColumn';
|
||||
import { Region } from '../constants/regions';
|
||||
import { NormalizedTankStats } from '../types/tanksStats';
|
||||
|
||||
@@ -18,6 +20,12 @@ type Session = (
|
||||
}
|
||||
) & {
|
||||
promptBeforeReset: boolean;
|
||||
customColumns: {
|
||||
display: CustomColumnDisplay;
|
||||
showDelta: boolean;
|
||||
}[] & { length: 4 };
|
||||
showTotal: boolean;
|
||||
showCareer: boolean;
|
||||
};
|
||||
|
||||
export const useSession = create<Session>()(
|
||||
@@ -26,6 +34,15 @@ export const useSession = create<Session>()(
|
||||
(set) => ({
|
||||
isTracking: false,
|
||||
promptBeforeReset: true,
|
||||
showTotal: true,
|
||||
showCareer: true,
|
||||
|
||||
customColumns: [
|
||||
{ display: 'battles', showDelta: false },
|
||||
{ display: 'winrate', showDelta: true },
|
||||
{ display: 'wn8', showDelta: false },
|
||||
{ display: 'damage', showDelta: true },
|
||||
],
|
||||
}),
|
||||
{
|
||||
name: 'session',
|
||||
@@ -33,3 +50,7 @@ export const useSession = create<Session>()(
|
||||
),
|
||||
),
|
||||
);
|
||||
|
||||
export default function mutateSession(recipe: (draft: Session) => void) {
|
||||
useSession.setState(produce(recipe));
|
||||
}
|
||||
@@ -3078,6 +3078,11 @@ ignore@^5.1.8, ignore@^5.2.4:
|
||||
resolved "https://registry.yarnpkg.com/ignore/-/ignore-5.2.4.tgz#a291c0c6178ff1b960befe47fcdec301674a6324"
|
||||
integrity sha512-MAb38BcSbH0eHNBxn7ql2NH/kX33OkB3lZ1BNdh7ENeRChHTYsTvWrMubiIAMNS2llXEEgZ1MUOBtXChP3kaFQ==
|
||||
|
||||
immer@^10.0.2:
|
||||
version "10.0.2"
|
||||
resolved "https://registry.yarnpkg.com/immer/-/immer-10.0.2.tgz#11636c5b77acf529e059582d76faf338beb56141"
|
||||
integrity sha512-Rx3CqeqQ19sxUtYV9CU911Vhy8/721wRFnJv3REVGWUmoAcIwzifTsdmJte/MV+0/XpM35LZdQMBGkRIoLPwQA==
|
||||
|
||||
indent-string@^4.0.0:
|
||||
version "4.0.0"
|
||||
resolved "https://registry.yarnpkg.com/indent-string/-/indent-string-4.0.0.tgz#624f8f4497d619b2d9768531d58f4122854d7251"
|
||||
|
||||
Reference in new issue
Block a user