mirror of
https://github.com/blitzkit/blitzkit.git
synced 2026-10-24 03:59:50 +02:00
feat: start of perforamnce
This commit is contained in:
1 parent
db4132f666
commit
7dfdf4c11b
13 files changed
+79
-39
No files matched your search
@@ -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",
|
||||||
|
|||||||
@@ -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;
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -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>
|
||||||
|
|||||||
@@ -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>
|
||||||
|
|||||||
@@ -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">
|
||||||
|
|||||||
Reference in new issue
Block a user