diff --git a/.vscode/settings.json b/.vscode/settings.json index 17e5e3eb5..61f4ce672 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -102,6 +102,7 @@ "NEGATIVEX", "NEGATIVEY", "NEGATIVEZ", + "nivo", "nmatname", "noout", "normalmap", diff --git a/bun.lockb b/bun.lockb index 509c67288..374b1c460 100644 Binary files a/bun.lockb and b/bun.lockb differ diff --git a/package.json b/package.json index bebbeda26..9197143a4 100644 --- a/package.json +++ b/package.json @@ -30,6 +30,7 @@ "license": "MIT", "dependencies": { "@gltf-transform/core": "^3.9.0", + "@nivo/bar": "^0.87.0", "@octokit/plugin-throttling": "^8.1.3", "@octokit/rest": "^20.0.1", "@prisma/client": "^5.4.1", diff --git a/src/app/tools/tank-performance/components/Header.tsx b/src/app/tools/tank-performance/components/Header.tsx index 96d8efe33..44a77b328 100644 --- a/src/app/tools/tank-performance/components/Header.tsx +++ b/src/app/tools/tank-performance/components/Header.tsx @@ -16,7 +16,7 @@ export function Header() { const sort = useTankPerformanceSort(); return ( - + Tank {tankPerformanceSortTypeNamesArray.map((type) => { @@ -24,6 +24,7 @@ export function Header() { return ( + + + Players (30d) per tier + + + + { + const tier = (index + 1) as Tier; + const tierTanks = awaitedAverageDefinitionsArray.filter( + ({ id }) => awaitedTankDefinitions[id].tier === tier, + ); + const populations: Record = { + 'AT-SPG': 0, + heavyTank: 0, + lightTank: 0, + mediumTank: 0, + }; + + tierTanks.forEach((stats) => { + const tank = awaitedTankDefinitions[stats.id]; + populations[tank.class] += stats.mu.battles * stats.samples; + }); + + TANK_CLASSES.forEach((tankClass) => { + populations[tankClass] = Math.round(populations[tankClass]); + }); + + return { tier: TIER_ROMAN_NUMERALS[tier], ...populations }; + })} + keys={[...TANK_CLASSES].reverse()} + indexBy="tier" + colors={{ scheme: 'dark2' }} + label={(d) => numberFormat.format(d.value as number)} + margin={{ right: 96, bottom: 20, left: 40 }} + legendLabel={(d) => + strings.common.tank_class_short[d.id as TankClass] + } + axisLeft={{ + tickSize: 0, + format: (value) => numberFormat.format(value as number), + }} + axisBottom={{ tickSize: 0 }} + legends={[ + { + dataFrom: 'keys', + anchor: 'bottom-right', + direction: 'column', + translateX: 120, + itemsSpacing: 4, + itemWidth: 100, + itemHeight: 20, + }, + ]} + /> + + + + ); +} diff --git a/src/app/tools/tank-performance/page.tsx b/src/app/tools/tank-performance/page.tsx index 108dbb10c..fc21cd5f5 100644 --- a/src/app/tools/tank-performance/page.tsx +++ b/src/app/tools/tank-performance/page.tsx @@ -3,12 +3,14 @@ import { TankFiltersProvider } from '../../../stores/tankFilters'; import { FilterControl } from '../tankopedia/components/FilterControl'; import { Info } from './components/Info'; import { TankTable } from './components/Table'; +import { TierBreakdown } from './components/TierBreakdown'; export default function Page() { return ( + diff --git a/src/constants/tools.tsx b/src/constants/tools.tsx index 7f365657e..bbfb3cbe5 100644 --- a/src/constants/tools.tsx +++ b/src/constants/tools.tsx @@ -111,7 +111,7 @@ export const tankPerformanceTool: Tool = { id: 'tank-performance', title: 'Tank performance', description: 'Tank performance statistics', - pageDescription: 'Tank performance statistics in World of Tanks Blitz', + pageDescription: 'Best tanks and their performances in World of Tanks Blitz', button: { text: 'View tanks', color: 'jade', diff --git a/src/core/nivo/theme.ts b/src/core/nivo/theme.ts new file mode 100644 index 000000000..93a0ffe2a --- /dev/null +++ b/src/core/nivo/theme.ts @@ -0,0 +1,10 @@ +import { Theme } from '@nivo/core'; + +export const nivoTheme = { + theme: { + text: { fill: 'var(--gray-11)' }, + grid: { line: { stroke: 'var(--gray-3)' } }, + } satisfies Theme, + borderRadius: 2, + innerPadding: 1, +};