mirror of
https://github.com/blitzkit/blitzkit.git
synced 2026-10-21 02:37:05 +02:00
feat: localize performance
This commit is contained in:
1 parent
7dfdf4c11b
commit
9de41529d1
15 files changed
+134
-76
No files matched your search
@@ -6,6 +6,16 @@
|
||||
},
|
||||
|
||||
"common": {
|
||||
"player_count_period": {
|
||||
"total": "Total",
|
||||
"d_120": "Past 120 days",
|
||||
"d_90": "Past 90 days",
|
||||
"d_60": "Past 60 days",
|
||||
"d_30": "Past month",
|
||||
"d_7": "Past week",
|
||||
"d_1": "Yesterday"
|
||||
},
|
||||
|
||||
"branches": {
|
||||
"local": "dev",
|
||||
"dev": "beta",
|
||||
@@ -738,6 +748,30 @@
|
||||
"body": "Estimated stats based on %s1 players. Updated %s2 ago.",
|
||||
"hours": "%s1 hours",
|
||||
"minutes": "%s1 minutes"
|
||||
},
|
||||
"player_count": {
|
||||
"label": "Player count"
|
||||
},
|
||||
"table": {
|
||||
"tanks": {
|
||||
"header": "Tank",
|
||||
"total": "Total"
|
||||
},
|
||||
"stats": {
|
||||
"winrate": "Winrate",
|
||||
"players": "Players",
|
||||
"damage": "Damage",
|
||||
"survival": "Survival",
|
||||
"xp": "XP",
|
||||
"kills": "Kills",
|
||||
"spots": "Spots",
|
||||
"accuracy": "Accuracy",
|
||||
"shots": "Shots",
|
||||
"hits": "Hits",
|
||||
"damage_ratio": "Dmg. ratio",
|
||||
"damage_taken": "Dmg. taken",
|
||||
"capture_points": "Cap points"
|
||||
}
|
||||
}
|
||||
},
|
||||
"gallery": {
|
||||
|
||||
@@ -1,11 +1,8 @@
|
||||
import { merge } from 'lodash-es';
|
||||
import type en from '../../lang/en.json';
|
||||
import { assertSecret, DEFAULT_LOCALE, SUPPORTED_LOCALES } from '../blitzkit';
|
||||
import { DEFAULT_LOCALE, SUPPORTED_LOCALES } from '../blitzkit';
|
||||
import { TranslationTree } from './translator';
|
||||
|
||||
const PUBLIC_DEBUG_MISSING_I18N = assertSecret(
|
||||
import.meta.env.PUBLIC_DEBUG_MISSING_I18N,
|
||||
);
|
||||
const files = import.meta.glob('../../lang/*.json', { eager: true });
|
||||
export const localizedStrings: Record<string, typeof en> = {};
|
||||
|
||||
@@ -25,7 +22,11 @@ SUPPORTED_LOCALES.forEach((locale) => {
|
||||
const strings = files[`../../lang/${locale}.json`];
|
||||
const mergedStrings = merge({}, defaultStrings, strings);
|
||||
|
||||
if (PUBLIC_DEBUG_MISSING_I18N === 'true') nuke(mergedStrings);
|
||||
/**
|
||||
* For some reason, this won't load on the server on the first render so I am
|
||||
* not asserting this one lol
|
||||
*/
|
||||
if (import.meta.env.PUBLIC_DEBUG_MISSING_I18N === 'true') nuke(mergedStrings);
|
||||
|
||||
localizedStrings[locale] = mergedStrings as typeof en;
|
||||
});
|
||||
|
||||
@@ -8,6 +8,7 @@ import {
|
||||
} from '@radix-ui/themes';
|
||||
import type { ComponentProps } from 'react';
|
||||
import { radToDeg } from 'three/src/math/MathUtils.js';
|
||||
import { useLocale } from '../../../hooks/useLocale';
|
||||
import type {
|
||||
Shot,
|
||||
ShotLayer,
|
||||
@@ -49,6 +50,8 @@ function LayerEntry({
|
||||
layer: ShotLayer;
|
||||
angle?: number;
|
||||
}) {
|
||||
const { locale } = useLocale();
|
||||
|
||||
return (
|
||||
<Flex align="center" gap="2">
|
||||
<Text size="1" color="gray" style={{ width: 12 }}>
|
||||
@@ -61,7 +64,7 @@ function LayerEntry({
|
||||
{layer.type === null && (
|
||||
<>
|
||||
<Text size="2" color={shotStatusColor} style={{ width: 64 }}>
|
||||
{Math.round(layer.distance * 1000).toLocaleString()}
|
||||
{Math.round(layer.distance * 1000).toLocaleString(locale)}
|
||||
<Text size="1">mm</Text>
|
||||
</Text>
|
||||
|
||||
@@ -73,7 +76,7 @@ function LayerEntry({
|
||||
|
||||
{layer.type === ArmorType.External && (
|
||||
<Text size="2" color={shotStatusColor} style={{ width: 64 }}>
|
||||
{Math.round(layer.thickness).toLocaleString()}
|
||||
{Math.round(layer.thickness).toLocaleString(locale)}
|
||||
<Text size="1">mm</Text>
|
||||
</Text>
|
||||
)}
|
||||
@@ -82,14 +85,14 @@ function LayerEntry({
|
||||
layer.type === ArmorType.Spaced) && (
|
||||
<>
|
||||
<Text size="2" color={shotStatusColor} style={{ width: 80 }}>
|
||||
{Math.round(layer.thicknessAngled).toLocaleString()}
|
||||
{Math.round(layer.thicknessAngled).toLocaleString(locale)}
|
||||
<Text size="1">{`mm${
|
||||
angle === undefined ? '' : ` ${Math.round(radToDeg(angle))}°`
|
||||
}`}</Text>
|
||||
</Text>
|
||||
|
||||
<Text size="2" color="gray">
|
||||
{Math.round(layer.thickness).toLocaleString()}
|
||||
{Math.round(layer.thickness).toLocaleString(locale)}
|
||||
<Text size="1">mm</Text> nominal
|
||||
</Text>
|
||||
</>
|
||||
@@ -103,6 +106,8 @@ interface ShotDisplayCardProps extends CardProps {
|
||||
}
|
||||
|
||||
export function ShotDisplayCard({ shot, ...props }: ShotDisplayCardProps) {
|
||||
const { locale } = useLocale();
|
||||
|
||||
if (!shot) return null;
|
||||
|
||||
const outTitleColor = shot.out
|
||||
@@ -117,7 +122,7 @@ export function ShotDisplayCard({ shot, ...props }: ShotDisplayCardProps) {
|
||||
<Text color={inTitleColor} weight="bold">
|
||||
{shot.in.status !== 'blocked' && shot.in.status !== 'ricochet' && (
|
||||
<>
|
||||
{Math.round(shot.damage).toLocaleString()}
|
||||
{Math.round(shot.damage).toLocaleString(locale)}
|
||||
<Text size="1">hp</Text>
|
||||
</>
|
||||
)}
|
||||
@@ -182,7 +187,7 @@ export function ShotDisplayCard({ shot, ...props }: ShotDisplayCardProps) {
|
||||
{shot.out.status !== 'blocked' &&
|
||||
shot.out.status !== 'ricochet' && (
|
||||
<>
|
||||
{Math.round(shot.damage).toLocaleString()}
|
||||
{Math.round(shot.damage).toLocaleString(locale)}
|
||||
<Text size="1">hp</Text>
|
||||
</>
|
||||
)}
|
||||
|
||||
@@ -16,6 +16,7 @@ import {
|
||||
} from '@radix-ui/themes';
|
||||
import { times } from 'lodash-es';
|
||||
import { useState } from 'react';
|
||||
import { useLocale } from '../../hooks/useLocale';
|
||||
import './index.css';
|
||||
|
||||
const DAY_TITLES = ['Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat'];
|
||||
@@ -37,6 +38,7 @@ export function DatePicker({
|
||||
const [yearOffset, setYearOffset] = useState(0);
|
||||
const [monthOffset, setMonthOffset] = useState(0);
|
||||
const date = new Date(year + yearOffset, month + monthOffset, day);
|
||||
const { locale } = useLocale();
|
||||
|
||||
const daysInLastMonth = new Date(
|
||||
year + yearOffset,
|
||||
@@ -94,11 +96,7 @@ export function DatePicker({
|
||||
</IconButton>
|
||||
|
||||
<Flex gap="1">
|
||||
<Text>
|
||||
{date.toLocaleString(undefined, {
|
||||
month: 'long',
|
||||
})}
|
||||
</Text>
|
||||
<Text>{date.toLocaleString(locale, { month: 'long' })}</Text>
|
||||
|
||||
<Popover.Root onOpenChange={() => setYearScroll(0)}>
|
||||
<Popover.Trigger>
|
||||
|
||||
@@ -2,6 +2,7 @@ import { Flex, Text } from '@radix-ui/themes';
|
||||
import fuzzysort from 'fuzzysort';
|
||||
import { times } from 'lodash-es';
|
||||
import { useMemo, useState } from 'react';
|
||||
import { useLocale } from '../../hooks/useLocale';
|
||||
import { GalleryEphemeral } from '../../stores/galleryEphemeral';
|
||||
import { GalleryCard } from './Card';
|
||||
|
||||
@@ -20,6 +21,7 @@ const PREVIEW_COUNT = 28;
|
||||
export function GalleryList({ avatars }: GalleryListProps) {
|
||||
const search = GalleryEphemeral.use((state) => state.search);
|
||||
const [loadedCards, setLoadedCards] = useState(DEFAULT_LOADED);
|
||||
const { locale } = useLocale();
|
||||
const filtered = useMemo(() => {
|
||||
setLoadedCards(DEFAULT_LOADED);
|
||||
|
||||
@@ -35,7 +37,7 @@ export function GalleryList({ avatars }: GalleryListProps) {
|
||||
return (
|
||||
<>
|
||||
<Text align="center" color="gray">
|
||||
{filtered.length.toLocaleString()} avatars
|
||||
{filtered.length.toLocaleString(locale)} avatars
|
||||
</Text>
|
||||
|
||||
<Flex wrap="wrap" gap="4" justify="center">
|
||||
|
||||
@@ -4,21 +4,23 @@ import {
|
||||
CaretUpIcon,
|
||||
} from '@radix-ui/react-icons';
|
||||
import { Button, Flex, Table } from '@radix-ui/themes';
|
||||
import { useLocale } from '../../hooks/useLocale';
|
||||
import { TankPerformanceSort } from '../../stores/tankPerformanceSort';
|
||||
import {
|
||||
TankPerformanceSortTypeNames,
|
||||
TankPerformanceSortTypeNamesArray,
|
||||
} from '../../stores/tankPerformanceSort/constants';
|
||||
import { TankPerformanceSortTypeNamesArray } from '../../stores/tankPerformanceSort/constants';
|
||||
import { StickyColumnHeaderCell } from '../StickyColumnHeaderCell';
|
||||
|
||||
export function Header() {
|
||||
const sort = TankPerformanceSort.use();
|
||||
const store = TankPerformanceSort.useStore();
|
||||
const { strings } = useLocale();
|
||||
|
||||
return (
|
||||
<Table.Header>
|
||||
<Table.Row align="center">
|
||||
<StickyColumnHeaderCell>Tank</StickyColumnHeaderCell>
|
||||
<StickyColumnHeaderCell>
|
||||
{strings.website.tools.performance.table.tanks.header}
|
||||
</StickyColumnHeaderCell>
|
||||
|
||||
{TankPerformanceSortTypeNamesArray.map((type) => {
|
||||
const isSelected = sort.type === type;
|
||||
|
||||
@@ -42,7 +44,7 @@ export function Header() {
|
||||
}
|
||||
}}
|
||||
>
|
||||
{TankPerformanceSortTypeNames[type]}
|
||||
{strings.website.tools.performance.table.stats[type]}
|
||||
|
||||
{!isSelected && <CaretSortIcon />}
|
||||
{isSelected && (
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import { Flex, Select, Text } from '@radix-ui/themes';
|
||||
import { useLocale } from '../../hooks/useLocale';
|
||||
import {
|
||||
TankPerformanceEphemeral,
|
||||
type PlayerCountPeriod,
|
||||
@@ -9,10 +10,11 @@ export function PlayerCountControl() {
|
||||
(state) => state.playerCountPeriod,
|
||||
);
|
||||
const mutateTankPerformanceSort = TankPerformanceEphemeral.useMutation();
|
||||
const { strings } = useLocale();
|
||||
|
||||
return (
|
||||
<Flex justify="center" align="center" gap="2">
|
||||
<Text>Player count</Text>
|
||||
<Text>{strings.website.tools.performance.player_count.label}</Text>
|
||||
<Select.Root
|
||||
value={playerCountPeriod}
|
||||
onValueChange={(period) => {
|
||||
@@ -23,13 +25,27 @@ export function PlayerCountControl() {
|
||||
>
|
||||
<Select.Trigger />
|
||||
<Select.Content>
|
||||
<Select.Item value="total">Total</Select.Item>
|
||||
<Select.Item value="d_120">Past 120 days</Select.Item>
|
||||
<Select.Item value="d_90">Past 90 days</Select.Item>
|
||||
<Select.Item value="d_60">Past 60 days</Select.Item>
|
||||
<Select.Item value="d_30">This month</Select.Item>
|
||||
<Select.Item value="d_7">This week</Select.Item>
|
||||
<Select.Item value="d_1">Yesterday</Select.Item>
|
||||
<Select.Item value="total">
|
||||
{strings.common.player_count_period.total}
|
||||
</Select.Item>
|
||||
<Select.Item value="d_120">
|
||||
{strings.common.player_count_period.d_120}
|
||||
</Select.Item>
|
||||
<Select.Item value="d_90">
|
||||
{strings.common.player_count_period.d_90}
|
||||
</Select.Item>
|
||||
<Select.Item value="d_60">
|
||||
{strings.common.player_count_period.d_60}
|
||||
</Select.Item>
|
||||
<Select.Item value="d_30">
|
||||
{strings.common.player_count_period.d_30}
|
||||
</Select.Item>
|
||||
<Select.Item value="d_7">
|
||||
{strings.common.player_count_period.d_7}
|
||||
</Select.Item>
|
||||
<Select.Item value="d_1">
|
||||
{strings.common.player_count_period.d_1}
|
||||
</Select.Item>
|
||||
</Select.Content>
|
||||
</Select.Root>
|
||||
</Flex>
|
||||
|
||||
@@ -3,6 +3,7 @@ import { Table } from '@radix-ui/themes';
|
||||
import { memo } from 'react';
|
||||
import { awaitableAverageDefinitions } from '../../core/awaitables/averageDefinitions';
|
||||
import { useAveragesExclusionRatio } from '../../hooks/useAveragesExclusionRatio';
|
||||
import { useLocale } from '../../hooks/useLocale';
|
||||
import { TankPerformanceEphemeral } from '../../stores/tankPerformanceEphemeral';
|
||||
import { TankRowHeaderCell } from '../TankRowHeaderCell';
|
||||
|
||||
@@ -19,6 +20,7 @@ export const TankRow = memo<TankRowProps>(
|
||||
const playerCountPeriod = TankPerformanceEphemeral.use(
|
||||
(state) => state.playerCountPeriod,
|
||||
);
|
||||
const { locale } = useLocale();
|
||||
|
||||
return (
|
||||
<Table.Row>
|
||||
@@ -29,13 +31,14 @@ export const TankRow = memo<TankRowProps>(
|
||||
</Table.Cell>
|
||||
<Table.Cell align="center">
|
||||
{formatCompact(
|
||||
locale,
|
||||
Math.round(ratio * averages.samples[playerCountPeriod]),
|
||||
)}
|
||||
</Table.Cell>
|
||||
<Table.Cell align="center">
|
||||
{Math.round(
|
||||
averages.mu.damage_dealt / averages.mu.battles,
|
||||
).toLocaleString()}
|
||||
).toLocaleString(locale)}
|
||||
</Table.Cell>
|
||||
<Table.Cell align="center">
|
||||
{Math.round(
|
||||
@@ -44,7 +47,9 @@ export const TankRow = memo<TankRowProps>(
|
||||
%
|
||||
</Table.Cell>
|
||||
<Table.Cell align="center">
|
||||
{Math.round(averages.mu.xp / averages.mu.battles).toLocaleString()}
|
||||
{Math.round(averages.mu.xp / averages.mu.battles).toLocaleString(
|
||||
locale,
|
||||
)}
|
||||
</Table.Cell>
|
||||
<Table.Cell align="center">
|
||||
{(averages.mu.frags / averages.mu.battles).toFixed(2)}
|
||||
@@ -67,7 +72,7 @@ export const TankRow = memo<TankRowProps>(
|
||||
<Table.Cell align="center">
|
||||
{Math.round(
|
||||
averages.mu.damage_received / averages.mu.battles,
|
||||
).toLocaleString()}
|
||||
).toLocaleString(locale)}
|
||||
</Table.Cell>
|
||||
<Table.Cell align="center">
|
||||
{(averages.mu.capture_points / averages.mu.battles).toFixed(2)}
|
||||
|
||||
@@ -7,6 +7,7 @@ import { Table } from '@radix-ui/themes';
|
||||
import { memo, useCallback } from 'react';
|
||||
import { awaitableAverageDefinitions } from '../../core/awaitables/averageDefinitions';
|
||||
import { useAveragesExclusionRatio } from '../../hooks/useAveragesExclusionRatio';
|
||||
import { useLocale } from '../../hooks/useLocale';
|
||||
import { TankPerformanceEphemeral } from '../../stores/tankPerformanceEphemeral';
|
||||
import { StickyRowHeaderCell } from '../StickyRowHeaderCell';
|
||||
|
||||
@@ -25,6 +26,7 @@ export const Total = memo<TotalProps>(
|
||||
const playerCountPeriod = TankPerformanceEphemeral.use(
|
||||
(state) => state.playerCountPeriod,
|
||||
);
|
||||
const { strings, locale } = useLocale();
|
||||
const ratio = useAveragesExclusionRatio();
|
||||
const sum = useCallback(
|
||||
(slice: (tank: BlitzkitStats) => number) => {
|
||||
@@ -54,20 +56,23 @@ export const Total = memo<TotalProps>(
|
||||
return (
|
||||
<Table.Row>
|
||||
<StickyRowHeaderCell style={{ overflow: 'hidden', display: 'flex' }}>
|
||||
Total
|
||||
{strings.website.tools.performance.table.tanks.total}
|
||||
</StickyRowHeaderCell>
|
||||
<Table.Cell align="center">{(winrate * 100).toFixed(1)}%</Table.Cell>
|
||||
<Table.Cell align="center">
|
||||
{formatCompact(ratio * averageDefinitions.samples[playerCountPeriod])}
|
||||
{formatCompact(
|
||||
locale,
|
||||
ratio * averageDefinitions.samples[playerCountPeriod],
|
||||
)}
|
||||
</Table.Cell>
|
||||
<Table.Cell align="center">
|
||||
{Math.round(damage).toLocaleString()}
|
||||
{Math.round(damage).toLocaleString(locale)}
|
||||
</Table.Cell>
|
||||
<Table.Cell align="center">
|
||||
{Math.round(survival * 100).toFixed(1)}%
|
||||
</Table.Cell>
|
||||
<Table.Cell align="center">
|
||||
{Math.round(xp).toLocaleString()}
|
||||
{Math.round(xp).toLocaleString(locale)}
|
||||
</Table.Cell>
|
||||
<Table.Cell align="center">{kills.toFixed(2)}</Table.Cell>
|
||||
<Table.Cell align="center">{spots.toFixed(2)}</Table.Cell>
|
||||
@@ -76,7 +81,7 @@ export const Total = memo<TotalProps>(
|
||||
<Table.Cell align="center">{hits.toFixed(1)}</Table.Cell>
|
||||
<Table.Cell align="center">{damageRatio.toFixed(2)}</Table.Cell>
|
||||
<Table.Cell align="center">
|
||||
{Math.round(damageReceived).toLocaleString()}
|
||||
{Math.round(damageReceived).toLocaleString(locale)}
|
||||
</Table.Cell>
|
||||
<Table.Cell align="center">{capturePoints.toFixed(2)}</Table.Cell>
|
||||
</Table.Row>
|
||||
|
||||
@@ -187,7 +187,7 @@ export function MetaSection() {
|
||||
} price`}
|
||||
>
|
||||
<Flex align="center" gap="1">
|
||||
{protagonist.price.value.toLocaleString()}
|
||||
{protagonist.price.value.toLocaleString(locale)}
|
||||
<img
|
||||
style={{ width: '1em', height: '1em' }}
|
||||
alt={TankPriceType[protagonist.price.type]}
|
||||
@@ -203,7 +203,7 @@ export function MetaSection() {
|
||||
</Listing>
|
||||
<Listing label="Sale price">
|
||||
<Flex align="center" gap="1">
|
||||
{(protagonist.price.value / 2).toLocaleString()}
|
||||
{(protagonist.price.value / 2).toLocaleString(locale)}
|
||||
<img
|
||||
style={{ width: '1em', height: '1em' }}
|
||||
alt={TankPriceType[protagonist.price.type]}
|
||||
@@ -223,7 +223,7 @@ export function MetaSection() {
|
||||
{(
|
||||
protagonist.research_cost.research_cost_type!
|
||||
.value as number
|
||||
).toLocaleString()}
|
||||
).toLocaleString(locale)}
|
||||
<img
|
||||
style={{ width: '1em', height: '1em' }}
|
||||
alt="xp"
|
||||
|
||||
@@ -3,6 +3,7 @@ import { CaretLeftIcon, CaretRightIcon, PlusIcon } from '@radix-ui/react-icons';
|
||||
import { Flex, Heading, IconButton, ScrollArea, Text } from '@radix-ui/themes';
|
||||
import { Fragment, useEffect, useMemo, useRef, useState } from 'react';
|
||||
import { awaitableTankDefinitions } from '../../../core/awaitables/tankDefinitions';
|
||||
import { useLocale } from '../../../hooks/useLocale';
|
||||
import { Duel } from '../../../stores/duel';
|
||||
import { TankopediaEphemeral } from '../../../stores/tankopediaEphemeral';
|
||||
import type { MaybeSkeletonComponentProps } from '../../../types/maybeSkeletonComponentProps';
|
||||
@@ -16,6 +17,7 @@ const tankDefinitions = await awaitableTankDefinitions;
|
||||
export const XP_MULTIPLIERS = [1, 2, 3, 4, 5, 10];
|
||||
|
||||
export function TechTreeSection({ skeleton }: MaybeSkeletonComponentProps) {
|
||||
const { locale } = useLocale();
|
||||
const master = Duel.use((state) => state.protagonist.tank);
|
||||
const xpMultiplier = TankopediaEphemeral.use((state) => state.xpMultiplier);
|
||||
const mutateTankopediaEphemeral = TankopediaEphemeral.useMutation();
|
||||
@@ -105,7 +107,7 @@ export function TechTreeSection({ skeleton }: MaybeSkeletonComponentProps) {
|
||||
objectPosition: 'center',
|
||||
}}
|
||||
/>
|
||||
{Math.round(totalXp / xpMultiplier).toLocaleString()}
|
||||
{Math.round(totalXp / xpMultiplier).toLocaleString(locale)}
|
||||
</Flex>
|
||||
</Text>
|
||||
|
||||
@@ -121,7 +123,7 @@ export function TechTreeSection({ skeleton }: MaybeSkeletonComponentProps) {
|
||||
objectPosition: 'center',
|
||||
}}
|
||||
/>
|
||||
{totalCredits.toLocaleString()}
|
||||
{totalCredits.toLocaleString(locale)}
|
||||
</Flex>
|
||||
</Text>
|
||||
</Flex>
|
||||
|
||||
@@ -39,6 +39,7 @@ import { StickyTableRoot } from '../../../../components/StickyTableRoot';
|
||||
import { TankRowHeaderCell } from '../../../../components/TankRowHeaderCell';
|
||||
import { awaitableAverageDefinitions } from '../../../../core/awaitables/averageDefinitions';
|
||||
import { awaitableTankDefinitions } from '../../../../core/awaitables/tankDefinitions';
|
||||
import { useLocale } from '../../../../hooks/useLocale';
|
||||
import { Session, type SessionTracking } from '../../../../stores/session';
|
||||
|
||||
const [tankDefinitions, averageDefinitions] = await Promise.all([
|
||||
@@ -55,6 +56,7 @@ export function Page() {
|
||||
}
|
||||
|
||||
function Content() {
|
||||
const { locale } = useLocale();
|
||||
const [showSearch, setShowSearch] = useState(false);
|
||||
const [searching, setSearching] = useState(false);
|
||||
const [searchResults, setSearchResults] = useState<AccountListWithServer>([]);
|
||||
@@ -265,7 +267,7 @@ function Content() {
|
||||
<Flex mt="2" mb="2" direction="column" gap="2">
|
||||
<Heading size="5">Tracking {accountInfo?.nickname}</Heading>
|
||||
<Text color="gray">
|
||||
Since {new Date(session.player.since).toLocaleString()}
|
||||
Since {new Date(session.player.since).toLocaleString(locale)}
|
||||
</Text>
|
||||
</Flex>
|
||||
|
||||
|
||||
@@ -1,14 +1,14 @@
|
||||
---
|
||||
import {
|
||||
asset,
|
||||
createDefaultProvisions,
|
||||
createDefaultSkills,
|
||||
fetchEquipmentDefinitions,
|
||||
fetchModelDefinitions,
|
||||
fetchProvisionDefinitions,
|
||||
fetchSkillDefinitions,
|
||||
fetchTankDefinitions,
|
||||
TIER_ROMAN_NUMERALS,
|
||||
asset,
|
||||
createDefaultProvisions,
|
||||
createDefaultSkills,
|
||||
fetchEquipmentDefinitions,
|
||||
fetchModelDefinitions,
|
||||
fetchProvisionDefinitions,
|
||||
fetchSkillDefinitions,
|
||||
fetchTankDefinitions,
|
||||
TIER_ROMAN_NUMERALS,
|
||||
} from '@blitzkit/core';
|
||||
import strings from '@blitzkit/core/lang/en-US.json';
|
||||
import type { GetStaticPaths } from 'astro';
|
||||
@@ -31,8 +31,8 @@ export const getStaticPaths = (async () => {
|
||||
.flat();
|
||||
}) satisfies GetStaticPaths;
|
||||
|
||||
const { id, locale } = Astro.params;
|
||||
|
||||
const {id} = Astro.params;
|
||||
const locale = Astro.params.locale ?? DEFAULT_LOCALE;
|
||||
const tankDefinitions = await fetchTankDefinitions();
|
||||
const skillDefinitions = await fetchSkillDefinitions();
|
||||
const provisionDefinitions = await fetchProvisionDefinitions();
|
||||
@@ -77,7 +77,7 @@ const description = `${
|
||||
name
|
||||
} armor, statistics, equipment, provisions, and more. ${Math.round(
|
||||
characteristics.dpm,
|
||||
).toLocaleString()} DPM, ${characteristics.damage.toFixed(0)}hp alpha, ${characteristics.penetration.toFixed(
|
||||
).toLocaleString(locale)} DPM, ${characteristics.damage.toFixed(0)}hp alpha, ${characteristics.penetration.toFixed(
|
||||
0,
|
||||
)}mm penetration, ${characteristics.speedForwards.toFixed(
|
||||
0,
|
||||
|
||||
@@ -1,21 +1,6 @@
|
||||
import en from '@blitzkit/core/lang/en.json';
|
||||
import type { TankPerformanceSortType } from '.';
|
||||
|
||||
export const TankPerformanceSortTypeNames = {
|
||||
winrate: 'Winrate',
|
||||
players: 'Players',
|
||||
damage: 'Damage',
|
||||
survival: 'Survival',
|
||||
xp: 'XP',
|
||||
kills: 'Kills',
|
||||
spots: 'Spots',
|
||||
accuracy: 'Accuracy',
|
||||
shots: 'Shots',
|
||||
hits: 'Hits',
|
||||
damageRatio: 'Dmg. ratio',
|
||||
damageTaken: 'Dmg. taken',
|
||||
capturePoints: 'Cap points',
|
||||
} as const;
|
||||
|
||||
export const TankPerformanceSortTypeNamesArray = Object.keys(
|
||||
TankPerformanceSortTypeNames,
|
||||
en.website.tools.performance.table.stats,
|
||||
) as TankPerformanceSortType[];
|
||||
@@ -1,8 +1,9 @@
|
||||
import type en from '@blitzkit/core/lang/en.json';
|
||||
import { create } from 'zustand';
|
||||
import { createContextualStore } from '../../core/zustand/createContextualStore';
|
||||
import { TankPerformanceSortTypeNames } from './constants';
|
||||
|
||||
export type TankPerformanceSortType = keyof typeof TankPerformanceSortTypeNames;
|
||||
export type TankPerformanceSortType =
|
||||
keyof typeof en.website.tools.performance.table.stats;
|
||||
|
||||
export interface TankPerformanceSort {
|
||||
type: TankPerformanceSortType;
|
||||
|
||||
Reference in new issue
Block a user