feat: start of perforamnce

This commit is contained in:
tresabhi committed 2025-01-06 20:31:21 -06:00
1 parent db4132f666
commit 7dfdf4c11b
13 files changed
+79 -39

No files matched your search

+6 -1
View File
@@ -733,7 +733,12 @@
"name": "Performance", "name": "Performance",
"button": "View tanks", "button": "View tanks",
"description": "Tank performance statistics", "description": "Tank performance statistics",
"seo_description": "Best tanks and their performances in World of Tanks Blitz" "seo_description": "Best tanks and their performances in World of Tanks Blitz",
"estimation": {
"body": "Estimated stats based on %s1 players. Updated %s2 ago.",
"hours": "%s1 hours",
"minutes": "%s1 minutes"
}
}, },
"gallery": { "gallery": {
"name": "Gallery", "name": "Gallery",
+5 -3
View File
@@ -1,9 +1,11 @@
import { merge } from 'lodash-es'; import { merge } from 'lodash-es';
import type en from '../../lang/en.json'; import type en from '../../lang/en.json';
import { DEFAULT_LOCALE, SUPPORTED_LOCALES } from '../blitzkit'; import { assertSecret, DEFAULT_LOCALE, SUPPORTED_LOCALES } from '../blitzkit';
import { TranslationTree } from './translator'; import { TranslationTree } from './translator';
const DEBUG_MISSING_I18N = import.meta.env.DEBUG_MISSING_I18N; const PUBLIC_DEBUG_MISSING_I18N = assertSecret(
import.meta.env.PUBLIC_DEBUG_MISSING_I18N,
);
const files = import.meta.glob('../../lang/*.json', { eager: true }); const files = import.meta.glob('../../lang/*.json', { eager: true });
export const localizedStrings: Record<string, typeof en> = {}; export const localizedStrings: Record<string, typeof en> = {};
@@ -23,7 +25,7 @@ SUPPORTED_LOCALES.forEach((locale) => {
const strings = files[`../../lang/${locale}.json`]; const strings = files[`../../lang/${locale}.json`];
const mergedStrings = merge({}, defaultStrings, strings); const mergedStrings = merge({}, defaultStrings, strings);
if (DEBUG_MISSING_I18N === 'true') nuke(mergedStrings); if (PUBLIC_DEBUG_MISSING_I18N === 'true') nuke(mergedStrings);
localizedStrings[locale] = mergedStrings as typeof en; localizedStrings[locale] = mergedStrings as typeof en;
}); });
+2 -3
View File
@@ -1,5 +1,4 @@
const numberFormat = Intl.NumberFormat('en', { notation: 'compact' }); export function formatCompact(locale: string, number: number) {
const numberFormat = Intl.NumberFormat(locale, { notation: 'compact' });
export function formatCompact(number: number) {
return numberFormat.format(number); return numberFormat.format(number);
} }
@@ -1,7 +1,11 @@
import { assertSecret, idToRegion } from '@blitzkit/core'; import { assertSecret, idToRegion } from '@blitzkit/core';
import { Button, Flex, Heading, Text } from '@radix-ui/themes'; import { Button, Flex, Heading, Text } from '@radix-ui/themes';
import { useEffect, useState } from 'react'; import { useEffect, useState } from 'react';
import { useLocale } from '../../hooks/useLocale'; import {
LocaleProvider,
useLocale,
type LocaleAcceptorProps,
} from '../../hooks/useLocale';
import { App } from '../../stores/app'; import { App } from '../../stores/app';
import { CURRENT_POLICIES_AGREEMENT_INDEX } from '../../stores/app/constants'; import { CURRENT_POLICIES_AGREEMENT_INDEX } from '../../stores/app/constants';
import { LinkI18n } from '../LinkI18n'; import { LinkI18n } from '../LinkI18n';
@@ -20,11 +24,13 @@ type Extension =
status: 'error'; status: 'error';
}; };
export function Checks() { export function Checks({ locale }: LocaleAcceptorProps) {
return ( return (
<LocaleProvider locale={locale}>
<App.Provider> <App.Provider>
<Content /> <Content />
</App.Provider> </App.Provider>
</LocaleProvider>
); );
} }
@@ -4,7 +4,11 @@ import { Box, Flex, Heading, Text } from '@radix-ui/themes';
import { google } from 'googleapis'; import { google } from 'googleapis';
import { awaitableTankDefinitions } from '../core/awaitables/tankDefinitions'; import { awaitableTankDefinitions } from '../core/awaitables/tankDefinitions';
import { literals } from '../core/i18n/literals'; import { literals } from '../core/i18n/literals';
import { LocaleProvider, useLocale } from '../hooks/useLocale'; import {
LocaleProvider,
useLocale,
type LocaleAcceptorProps,
} from '../hooks/useLocale';
import { TankopediaPersistent } from '../stores/tankopediaPersistent'; import { TankopediaPersistent } from '../stores/tankopediaPersistent';
import { TankCard } from './TankCard'; import { TankCard } from './TankCard';
@@ -65,11 +69,7 @@ const hotTanks = report.data.rows
views, views,
})); }));
interface HomePageHotTanksProps { export function HomePageHotTanks({ locale }: LocaleAcceptorProps) {
locale: string | undefined;
}
export function HomePageHotTanks({ locale }: HomePageHotTanksProps) {
return ( return (
<LocaleProvider locale={locale}> <LocaleProvider locale={locale}>
<TankopediaPersistent.Provider> <TankopediaPersistent.Provider>
+2 -3
View File
@@ -1,9 +1,8 @@
import { Link, type LinkProps } from '@radix-ui/themes'; import { Link, type LinkProps } from '@radix-ui/themes';
import { getBestLocale } from '../core/i18n/getBestLocale'; import { getBestLocale } from '../core/i18n/getBestLocale';
import type { LocaleAcceptorProps } from '../hooks/useLocale';
type LinkI18nProps = LinkProps & { type LinkI18nProps = LinkProps & LocaleAcceptorProps;
locale: string | undefined;
};
export function LinkI18n({ locale, href, ...props }: LinkI18nProps) { export function LinkI18n({ locale, href, ...props }: LinkI18nProps) {
const bestLocale = getBestLocale(); const bestLocale = getBestLocale();
@@ -3,8 +3,9 @@ import { InfoCircledIcon } from '@radix-ui/react-icons';
import { Callout, Flex } from '@radix-ui/themes'; import { Callout, Flex } from '@radix-ui/themes';
import { awaitableAverageDefinitions } from '../../core/awaitables/averageDefinitions'; import { awaitableAverageDefinitions } from '../../core/awaitables/averageDefinitions';
import { awaitableDiscoveredIdsDefinitions } from '../../core/awaitables/discoveredIdsDefinitions'; import { awaitableDiscoveredIdsDefinitions } from '../../core/awaitables/discoveredIdsDefinitions';
import { literals } from '../../core/i18n/literals';
import { useLocale } from '../../hooks/useLocale';
import type { MaybeSkeletonComponentProps } from '../../types/maybeSkeletonComponentProps'; import type { MaybeSkeletonComponentProps } from '../../types/maybeSkeletonComponentProps';
import { InlineSkeleton } from '../InlineSkeleton';
const [discoveredIdsDefinitions, averageDefinitions] = await Promise.all([ const [discoveredIdsDefinitions, averageDefinitions] = await Promise.all([
awaitableDiscoveredIdsDefinitions, awaitableDiscoveredIdsDefinitions,
@@ -12,14 +13,21 @@ const [discoveredIdsDefinitions, averageDefinitions] = await Promise.all([
]); ]);
export function PerformanceInfo({ skeleton }: MaybeSkeletonComponentProps) { export function PerformanceInfo({ skeleton }: MaybeSkeletonComponentProps) {
const samples = formatCompact(Math.round(discoveredIdsDefinitions.count)); const { strings, locale } = useLocale();
const samples = formatCompact(
locale,
Math.round(discoveredIdsDefinitions.count),
);
const minutesAgo = Math.floor( const minutesAgo = Math.floor(
(Date.now() - averageDefinitions.time) / (1000 * 60), (Date.now() - averageDefinitions.time) / (1000 * 60),
); );
const hoursAgo = Math.floor(minutesAgo / 60); const hoursAgo = Math.floor(minutesAgo / 60);
const timeAgo = `${hoursAgo === 0 ? minutesAgo : hoursAgo} ${ const timeAgo = literals(
strings.website.tools.performance.estimation[
hoursAgo === 0 ? 'minutes' : 'hours' hoursAgo === 0 ? 'minutes' : 'hours'
}`; ],
[`${hoursAgo === 0 ? minutesAgo : hoursAgo}`],
);
return ( return (
<Flex justify="center"> <Flex justify="center">
@@ -28,9 +36,14 @@ export function PerformanceInfo({ skeleton }: MaybeSkeletonComponentProps) {
<InfoCircledIcon /> <InfoCircledIcon />
</Callout.Icon> </Callout.Icon>
<Callout.Text> <Callout.Text>
Estimated stats based on{' '} {/* Estimated stats based on{' '}
{skeleton ? <InlineSkeleton width="2rem" /> : samples} players. {skeleton ? <InlineSkeleton width="2rem" /> : samples} players.
Updated {skeleton ? <InlineSkeleton width="3rem" /> : timeAgo} ago. Updated {skeleton ? <InlineSkeleton width="3rem" /> : timeAgo} ago. */}
{literals(strings.website.tools.performance.estimation.body, [
samples,
timeAgo,
])}
</Callout.Text> </Callout.Text>
</Callout.Root> </Callout.Root>
</Flex> </Flex>
+5 -2
View File
@@ -7,8 +7,7 @@ const LocaleContext = createContext<{
localeRaw: string | undefined; localeRaw: string | undefined;
} | null>(null); } | null>(null);
interface LocaleProviderProps { interface LocaleProviderProps extends LocaleAcceptorProps {
locale: string | undefined;
children: ReactNode; children: ReactNode;
} }
@@ -33,3 +32,7 @@ export function useLocale() {
return { locale: context.locale, strings }; return { locale: context.locale, strings };
} }
export interface LocaleAcceptorProps {
locale: string | undefined;
}
@@ -12,6 +12,7 @@ export interface Props {
} }
const { noFooter } = Astro.props; const { noFooter } = Astro.props;
const { locale } = Astro.params;
const { pathname } = Astro.url; const { pathname } = Astro.url;
const isRoot = pathname === '/'; const isRoot = pathname === '/';
--- ---
@@ -57,7 +58,7 @@ const isRoot = pathname === '/';
<Flex direction="column" minHeight="100vh"> <Flex direction="column" minHeight="100vh">
<Navbar /> <Navbar />
<Checks client:only="react" /> <Checks {locale} client:only="react" />
<slot /> <slot />
@@ -3,17 +3,25 @@ import { PerformanceInfo } from '../../../../components/Performance/PerformanceI
import { PlayerCountControl } from '../../../../components/Performance/PlayerCountControl'; import { PlayerCountControl } from '../../../../components/Performance/PlayerCountControl';
import { TankTable } from '../../../../components/Performance/Table'; import { TankTable } from '../../../../components/Performance/Table';
import { FilterControl } from '../../../../components/TankSearch/components/FilterControl'; import { FilterControl } from '../../../../components/TankSearch/components/FilterControl';
import {
LocaleProvider,
type LocaleAcceptorProps,
} from '../../../../hooks/useLocale';
import { TankPerformanceEphemeral } from '../../../../stores/tankPerformanceEphemeral'; import { TankPerformanceEphemeral } from '../../../../stores/tankPerformanceEphemeral';
import { TankPerformanceSort } from '../../../../stores/tankPerformanceSort'; import { TankPerformanceSort } from '../../../../stores/tankPerformanceSort';
import type { MaybeSkeletonComponentProps } from '../../../../types/maybeSkeletonComponentProps'; import type { MaybeSkeletonComponentProps } from '../../../../types/maybeSkeletonComponentProps';
export function Page({ skeleton }: MaybeSkeletonComponentProps) { type PageProps = MaybeSkeletonComponentProps & LocaleAcceptorProps;
export function Page({ skeleton, locale }: PageProps) {
return ( return (
<LocaleProvider locale={locale}>
<TankPerformanceSort.Provider> <TankPerformanceSort.Provider>
<TankPerformanceEphemeral.Provider> <TankPerformanceEphemeral.Provider>
<Content skeleton={skeleton} /> <Content skeleton={skeleton} />
</TankPerformanceEphemeral.Provider> </TankPerformanceEphemeral.Provider>
</TankPerformanceSort.Provider> </TankPerformanceSort.Provider>
</LocaleProvider>
); );
} }
@@ -5,12 +5,14 @@ import BaseLayout from '../../../../layouts/BaseLayout.astro';
import { Page } from './_index'; import { Page } from './_index';
export { getStaticPaths } from '../../index.astro'; export { getStaticPaths } from '../../index.astro';
const { locale } = Astro.params;
--- ---
<ToolOpenGraph tool={performanceTool} /> <ToolOpenGraph tool={performanceTool} />
<BaseLayout noFooter> <BaseLayout noFooter>
<Page client:only="react"> <Page client:only="react" {locale}>
<Page skeleton slot="fallback" /> <Page skeleton slot="fallback" {locale} />
</Page> </Page>
</BaseLayout> </BaseLayout>
@@ -12,16 +12,19 @@ import { VideoSection } from '../../../../../components/Tankopedia/VideoSection'
import { awaitableModelDefinitions } from '../../../../../core/awaitables/modelDefinitions'; import { awaitableModelDefinitions } from '../../../../../core/awaitables/modelDefinitions';
import { awaitableProvisionDefinitions } from '../../../../../core/awaitables/provisionDefinitions'; import { awaitableProvisionDefinitions } from '../../../../../core/awaitables/provisionDefinitions';
import { awaitableTankDefinitions } from '../../../../../core/awaitables/tankDefinitions'; import { awaitableTankDefinitions } from '../../../../../core/awaitables/tankDefinitions';
import { LocaleProvider } from '../../../../../hooks/useLocale'; import {
LocaleProvider,
type LocaleAcceptorProps,
} from '../../../../../hooks/useLocale';
import { App } from '../../../../../stores/app'; import { App } from '../../../../../stores/app';
import { Duel } from '../../../../../stores/duel'; import { Duel } from '../../../../../stores/duel';
import { TankopediaEphemeral } from '../../../../../stores/tankopediaEphemeral'; import { TankopediaEphemeral } from '../../../../../stores/tankopediaEphemeral';
import { TankopediaPersistent } from '../../../../../stores/tankopediaPersistent'; import { TankopediaPersistent } from '../../../../../stores/tankopediaPersistent';
import type { MaybeSkeletonComponentProps } from '../../../../../types/maybeSkeletonComponentProps'; import type { MaybeSkeletonComponentProps } from '../../../../../types/maybeSkeletonComponentProps';
type PageProps = MaybeSkeletonComponentProps & { type PageProps = MaybeSkeletonComponentProps &
LocaleAcceptorProps & {
id: number; id: number;
locale: string | undefined;
}; };
const [tankDefinitions, provisionDefinitions, modelDefinitions] = const [tankDefinitions, provisionDefinitions, modelDefinitions] =
@@ -1,14 +1,13 @@
import { PageWrapper } from '../../../../components/PageWrapper'; import { PageWrapper } from '../../../../components/PageWrapper';
import { TankSearch } from '../../../../components/TankSearch'; import { TankSearch } from '../../../../components/TankSearch';
import { LocaleProvider } from '../../../../hooks/useLocale'; import {
LocaleProvider,
type LocaleAcceptorProps,
} from '../../../../hooks/useLocale';
import { App } from '../../../../stores/app'; import { App } from '../../../../stores/app';
import { TankopediaPersistent } from '../../../../stores/tankopediaPersistent'; import { TankopediaPersistent } from '../../../../stores/tankopediaPersistent';
interface PageProps { export function Page({ locale }: LocaleAcceptorProps) {
locale: string | undefined;
}
export function Page({ locale }: PageProps) {
return ( return (
<LocaleProvider locale={locale}> <LocaleProvider locale={locale}>
<PageWrapper color="purple" maxWidth="80rem"> <PageWrapper color="purple" maxWidth="80rem">