Compare commits

...
15 Commits
20 changed files with 288 additions and 101 deletions

No files matched your search

+1
View File
@@ -47,6 +47,7 @@
"Unregistering",
"vickers",
"vitepress",
"Vovko",
"wargaming",
"webp",
"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/
![Blitzkrieg website](https://i.imgur.com/QOXUP63.png)
![Blitzkrieg website](https://i.imgur.com/eRIZe5P.png)
## Visit the documentation website
### https://tresabhi.github.io/blitzkrieg/
![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
```
+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
+3 -4
View File
@@ -1,6 +1,5 @@
# Creators
- TrèsAbhi `@tresabhi`
- Creator & main programmer; _I do it all!_
- Prince_NA `@prince_na`
- Advisor & tester
- **TrèsAbhi** `@tresabhi`: Creator and main programmer
- **Prince_NA** `@prince_na`: Game advisor & tester
- **Vovko**: Technical advisor
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "blitzkrieg",
"version": "1.15.5",
"version": "1.15.8",
"description": "🎉 Tools for everything World of Tanks Blitz",
"main": "src/server.ts",
"type": "module",
+3 -8
View File
@@ -207,15 +207,9 @@ export default function SessionPage() {
since !== undefined &&
diff !== undefined && (
<Breakdown.Row
color={session.color}
minimized={!session.showCareer}
title={`Since ${since.toLocaleString(undefined, {
hour: 'numeric',
minute: 'numeric',
hour12: true,
month: 'short',
year: 'numeric',
day: 'numeric',
})}`}
title={session.title}
stats={session.customColumns.map((customColumn) => {
const rowStat = totalRowStats[customColumn.display];
@@ -293,6 +287,7 @@ export default function SessionPage() {
return (
<Breakdown.Row
color={session.color}
key={stats.tank_id}
minimized={!session.showCareer}
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.SubContent>
<Builder.Label>Display</Builder.Label>
<Builder.RadioGroup
value={customColumn.display}
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 { CustomColumn } from './CustomColumn';
@@ -9,38 +26,111 @@ interface ContextMenuProps {
export function Menu({ Builder, reset }: ContextMenuProps) {
const session = useSession();
const [showTitleEditor, setShowTitleEditor] = useState(false);
const titleInput = useRef<HTMLInputElement>(null);
return (
<Builder.Content>
<CustomColumn Builder={Builder} column={0} />
<CustomColumn Builder={Builder} column={1} />
<CustomColumn Builder={Builder} column={2} />
<CustomColumn Builder={Builder} column={3} />
<>
<Dialog.Root open={showTitleEditor} onOpenChange={setShowTitleEditor}>
<Dialog.Content>
<Flex direction="column" gap="4">
<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
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>
<Dialog.Close>
<Button
onClick={() =>
useSession.setState({ title: titleInput.current!.value })
}
>
Set
</Button>
</Dialog.Close>
</Flex>
</Flex>
</Dialog.Content>
</Dialog.Root>
<Builder.Separator />
<Builder.Content>
<Builder.Sub>
<Builder.SubTrigger>Accent color</Builder.SubTrigger>
<Builder.Item color="red" onClick={reset}>
Reset
</Builder.Item>
</Builder.Content>
<Builder.SubContent>
<Builder.RadioGroup
value={session.color}
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>
</>
);
}
+6 -4
View File
@@ -17,7 +17,6 @@ import { getClanAccountInfo } from '../core/blitz/getClanAccountInfo';
import getRatingsInfo from '../core/blitz/getRatingsInfo';
import { getRatingsLeague } from '../core/blitz/getRatingsLeague';
import { getRatingsNeighbors } from '../core/blitz/getRatingsNeighbors';
import regionToRegionSubdomain from '../core/blitz/regionToRegionSubdomain';
import { getArchivedLatestSeasonNumber } from '../core/blitzkrieg/getArchivedLatestSeasonNumber';
import getArchivedRatingsInfo from '../core/blitzkrieg/getArchivedRatingsInfo';
import { getArchivedRatingsLeaderboard } from '../core/blitzkrieg/getArchivedRatingsLeaderboard';
@@ -256,7 +255,6 @@ export const ratingsCommand = new Promise<CommandRegistryRaw>(
if (regionRatingsInfo.detail !== undefined) return noOngoingSeason;
const regionSubdomain = regionToRegionSubdomain(region);
const result =
subcommandGroup === 'current'
? await getRatingsLeague(region, leagueIndex).then(
@@ -461,11 +459,15 @@ export const ratingsCommand = new Promise<CommandRegistryRaw>(
{items && (
<Leaderboard.Root>
{playersBefore > 0 && (
<Leaderboard.Gap message={`+ ${playersBefore} more`} />
<Leaderboard.Gap
message={`+ ${playersBefore.toLocaleString()} more`}
/>
)}
{items}
{playersAfter > 0 && (
<Leaderboard.Gap message={`+ ${playersAfter} more`} />
<Leaderboard.Gap
message={`+ ${playersAfter.toLocaleString()} more`}
/>
)}
</Leaderboard.Root>
)}
+4 -1
View File
@@ -6,7 +6,10 @@ export interface RootProps {
export function Root({ children }: RootProps) {
return (
<div style={{ display: 'flex', flexDirection: 'column', gap: 8 }}>
<div
className="session-tracker-root"
style={{ display: 'flex', flexDirection: 'column', gap: 8 }}
>
{children}
</div>
);
+33 -21
View File
@@ -1,5 +1,10 @@
import { createColors } from 'bepaint';
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 { RowStat } from './RowStat';
@@ -17,18 +22,29 @@ interface RowProps {
minimized?: boolean;
treeType?: TreeTypeEnum;
tankType?: string;
color?: AccentColor | GrayColor;
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 (
<div
className="session-tracker-row"
style={{
display: 'flex',
flexDirection: 'column',
borderRadius: 4,
backgroundColor: theme.colors.appBackground2,
backgroundColor: theme.appBackground2,
overflow: 'hidden',
}}
>
@@ -39,16 +55,12 @@ export function Row(props: RowProps) {
justifyContent: 'center',
padding: 8,
gap: 4,
backgroundColor: theme.colors.componentInteractive,
backgroundColor: theme.componentInteractive,
}}
>
{props.type === 'tank' && props.tankType !== undefined && (
{type === 'tank' && tankType !== undefined && (
<img
src={
TREE_TYPE_ICONS[props.treeType ?? TreeTypeEnum.TechTree][
props.tankType
]
}
src={TREE_TYPE_ICONS[treeType ?? TreeTypeEnum.TechTree][tankType]}
style={{ width: 16, height: 16 }}
/>
)}
@@ -56,18 +68,18 @@ export function Row(props: RowProps) {
<span
style={{
color:
props.type === 'tank'
? props.treeType === TreeTypeEnum.Collector
? theme.colors.textLowContrast_blue
: props.treeType === TreeTypeEnum.Premium
? theme.colors.textLowContrast_amber
: theme.colors.textHighContrast
: theme.colors.textLowContrast,
type === 'tank'
? treeType === TreeTypeEnum.Collector
? theme.textLowContrast_blue
: treeType === TreeTypeEnum.Premium
? theme.textLowContrast_amber
: theme.textHighContrast
: theme.textLowContrast,
fontWeight: 900,
fontSize: 16,
}}
>
{props.title}
{title}
</span>
</div>
@@ -78,11 +90,11 @@ export function Row(props: RowProps) {
paddingBottom: 8,
}}
>
{props.stats.map(
{stats.map(
(row, index) =>
row && (
<RowStat
minimized={props.minimized}
minimized={minimized}
key={index}
name={`${row.title} • ${row.career ?? '--'}`}
value={row.current ?? '--'}
@@ -1,5 +1,10 @@
import { createColors } from 'bepaint';
import { Percentile } from '../../../constants/percentiles';
import { theme } from '../../../stitches.config';
import {
AccentColor,
GrayColor,
PALETTES,
} from '../../../constants/radixColors';
import PercentileIndicator from '../../PercentileIndicator';
export interface RowStatProps {
@@ -8,6 +13,7 @@ export interface RowStatProps {
delta?: number;
percentile?: Percentile;
minimized?: boolean;
color?: AccentColor | GrayColor;
}
export function RowStat({
@@ -16,9 +22,13 @@ export function RowStat({
delta,
percentile,
minimized = false,
color = 'slate',
}: RowStatProps) {
const theme = createColors(PALETTES[`${color}Dark`]);
return (
<div
className="session-tracker-row-stat"
style={{
display: 'flex',
flexDirection: 'column',
@@ -52,7 +62,7 @@ export function RowStat({
<span
style={{
color: theme.colors.textHighContrast,
color: theme.textHighContrast,
fontWeight: 'bold',
fontSize: 16,
textAlign: 'center',
@@ -65,7 +75,7 @@ export function RowStat({
{!minimized && (
<span
style={{
color: theme.colors.textLowContrast,
color: theme.textLowContrast,
textAlign: 'center',
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) {
const comURL = (
(await fetch(
'https://api.github.com/repos/tresabhi/blitzkrieg-assets/git/trees/main',
'https://api.github.com/repos/tresabhi/blitzkrieg-assets/git/trees/main/regions',
).then((response) => response.json())) as {
tree: { path: string; url: string }[];
}
@@ -24,7 +24,7 @@ export default async function getArchivedRatingsInfo(
}
const response = await fetch(
`https://raw.githubusercontent.com/tresabhi/blitzkrieg-assets/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 & {
detail: undefined;
@@ -19,7 +19,7 @@ export async function getArchivedRatingsLeaderboard(
}
const response = await fetch(
`https://raw.githubusercontent.com/tresabhi/blitzkrieg-assets/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;
LEADERBOARD_CACHE[region][season] = json;
@@ -22,7 +22,7 @@ export default async function getArchivedRatingsMidnightLeaderboard(
try {
const response = await fetch(
`https://raw.githubusercontent.com/tresabhi/blitzkrieg-assets/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;
MIDNIGHT_LEADERBOARD_CACHE[region][season] = json;
+6 -3
View File
@@ -2,6 +2,7 @@ import { produce } from 'immer';
import { create } from 'zustand';
import { devtools, persist } from 'zustand/middleware';
import { CustomColumnDisplay } from '../app/tools/session/components/CustomColumn';
import { AccentColor, GrayColor } from '../constants/radixColors';
import { Region } from '../constants/regions';
import { WARGAMING_APPLICATION_ID } from '../constants/wargamingApplicationID';
import fetchBlitz from '../core/blitz/fetchBlitz';
@@ -21,6 +22,7 @@ type Session = (
time: number;
}
) & {
title: string;
resetPrompt: boolean;
embedPrompt: boolean;
customColumns: {
@@ -29,6 +31,7 @@ type Session = (
}[] & { length: 4 };
showTotal: boolean;
showCareer: boolean;
color: AccentColor | GrayColor;
};
export async function setSession(region: Region, id: number, nickname: string) {
@@ -66,6 +69,7 @@ export const useSession = create<Session>()(
devtools(
persist(
(set) => ({
title: 'Untitled session',
isTracking: false,
resetPrompt: true,
showTotal: true,
@@ -78,10 +82,9 @@ export const useSession = create<Session>()(
{ display: 'wn8', showDelta: false },
{ display: 'damage', showDelta: true },
],
color: 'slate',
}),
{
name: 'session',
},
{ name: 'session' },
),
),
);