feat: homepage

This commit is contained in:
tresabhi committed 2025-01-06 20:09:11 -06:00
1 parent 1d44ecab18
commit d9688f6051
18 files changed
+303 -153

No files matched your search

+138 -1
View File
@@ -1,5 +1,18 @@
{
"test": {
"$": "test",
"long": "This is a long test string. You MUST NEVER see this in the UI. My favorite fruit is %s1 because it has the color of %s2. I like it so much that I will say its name 3 times! %s1! %s1! %s1! Once again, it's %s2, not %s3.",
"fox": "The quick brown fox jumps over the lazy dog."
},
"common": {
"branches": {
"local": "dev",
"dev": "beta",
"opentest": "opentest",
"preview": "preview"
},
"locales": {
"en": "English",
"es": "Spanish",
@@ -689,5 +702,129 @@
}
},
"website": {}
"website": {
"home": {
"hero": {
"credit": "By %s1 ❤️"
},
"hot_tanks": {
"title": "Popular tanks",
"subtitle": "Last %s1 days"
},
"other_projects": {
"title": "Other cool projects"
}
},
"tools": {
"tankopedia": {
"name": "Tankopedia",
"button": "Find tanks",
"description": "Blitz tank encyclopedia",
"seo_description": "Statistics, armor, and more for all tanks in World of Tanks Blitz"
},
"compare": {
"name": "Compare",
"button": "Compare tanks",
"description": "Compare tank statistics",
"seo_description": "Compare tanks statistics and loadouts in World of Tanks Blitz"
},
"performance": {
"name": "Performance",
"button": "View tanks",
"description": "Tank performance statistics",
"seo_description": "Best tanks and their performances in World of Tanks Blitz"
},
"gallery": {
"name": "Gallery",
"button": "Browse all",
"description": "Blitz player avatars",
"seo_description": "All World of Tanks Blitz player avatars"
},
"session": {
"name": "Session",
"button": "Start tracking",
"description": "Live session stats",
"seo_description": "Track your stats in real time as you play World of Tanks Blitz"
},
"tier_list": {
"name": "Tier list",
"button": "Rank tanks",
"description": "Rank Blitz tanks",
"seo_description": "Explore tier lists ranking tanks from best to worst, based on player ratings and statistical performance in World of Tanks Blitz"
},
"embed": {
"name": "Embed",
"button": "Create now",
"description": "Embeds for streaming",
"seo_description": "Create embeds for streaming World of Tanks Blitz with extreme customization"
},
"charts": {
"name": "Charts",
"button": "Nerd out",
"description": "Lots of graphs",
"seo_description": "Charts and graphs on anything and everything about tanks, players, and events in World of Tanks Blitz"
},
"rating": {
"name": "Rating",
"button": "View leaderboard",
"description": "Full rating leaderboard",
"seo_description": "Live and archived full rating leaderboard for World of Tanks Blitz"
},
"discord": {
"name": "Discord bot",
"button": "Install now",
"description": "Stats right in Discord",
"seo_description": "Get stats right in Discord with BlitzKit's Discord bot"
},
"more": {
"name": "More coming soon",
"button": "Join Discord",
"description": "What we're making",
"seo_description": "What we're making with BlitzKit"
},
"players": {
"name": "Players",
"button": "Lookup player",
"description": "Periodical player statistics",
"seo_description": "Periodical player statistics in World of Tanks Blitz"
},
"home": {
"name": "Home",
"button": "Get started",
"description": "Get started with BlitzKit",
"seo_description": "Get started with BlitzKit"
},
"blitz_analysis": {
"name": "BlitzAnalysis[]",
"button": "Analyze now",
"description": "Rich historic average stats",
"seo_description": "Rich historic average stats in World of Tanks Blitz"
},
"blitz_insider": {
"name": "Blitz Insider",
"button": "Discover today",
"description": "In-game session stats",
"seo_description": "In-game session stats in World of Tanks Blitz"
}
},
"footer": {
"motto": "Everything World of Tanks Blitz",
"copyright": "Unaffiliated with Wargaming or any service",
"about": {
"title": "About",
"credits": "Credits",
"discord": "Discord",
"github": "GitHub",
"patches": "Patches"
},
"legal": {
"title": "Legal",
"privacy": "Privacy policy",
"terms": "Terms of service"
}
}
}
}
+1 -12
View File
@@ -1,13 +1,2 @@
export const SUPPORTED_LOCALES = [
'en',
'es',
'hr',
'pt',
'ru',
'uk',
'zh',
] as const;
export const SUPPORTED_LOCALES = ['en', 'es', 'hr', 'pt', 'ru', 'uk', 'zh'];
export const DEFAULT_LOCALE = SUPPORTED_LOCALES[0];
export type SupportedLocale = (typeof SUPPORTED_LOCALES)[number];
+2
View File
@@ -0,0 +1,2 @@
export * from './strings';
export * from './translator';
+46
View File
@@ -0,0 +1,46 @@
import { merge } from 'lodash-es';
import type en from '../../lang/en.json';
import { DEFAULT_LOCALE, SUPPORTED_LOCALES } from '../blitzkit';
import { TranslationTree } from './translator';
const DEBUG_MISSING_I18N = import.meta.env.DEBUG_MISSING_I18N;
const files = import.meta.glob('../../lang/*.json', { eager: true });
export const localizedStrings: Record<string, typeof en> = {};
function nuke(object: TranslationTree) {
for (const key in object) {
const typedKey = key as keyof typeof object;
if (typeof object[typedKey] === 'string') {
const value = object[typedKey];
object[typedKey] = redact(value as string);
} else nuke(object[typedKey] as TranslationTree);
}
}
SUPPORTED_LOCALES.forEach((locale) => {
const defaultStrings = files[`../../lang/${DEFAULT_LOCALE}.json`];
const strings = files[`../../lang/${locale}.json`];
const mergedStrings = merge({}, defaultStrings, strings);
if (DEBUG_MISSING_I18N === 'true') nuke(mergedStrings);
localizedStrings[locale] = mergedStrings as typeof en;
});
function redact(string: string) {
const matches = [...string.matchAll(/%s\d+/g)];
const characters = string
.split('')
.map((char) => (char === ' ' ? ' ' : '█')) as string[];
matches.forEach((match) => {
const start = match.index;
const matchText = match[0];
for (let i = 0; i < matchText.length; i++) {
characters[start + i] = matchText[i];
}
});
return characters.join('');
}
@@ -1,9 +1,6 @@
import en from '@blitzkit/core/lang/en.json';
import ru from '@blitzkit/core/lang/ru.json';
export type TranslationTree = { [key: string]: TranslationNode };
type TranslationTree = { [key: string]: Translation };
type Translation = string | TranslationTree;
export type TranslationNode = string | TranslationTree;
type NestedKeys<Type> = Type extends object
? {
@@ -17,7 +14,7 @@ type NestedKeys<Type> = Type extends object
}[keyof Type]
: never;
class Prate<
export class Translator<
Locale extends string,
DefaultLocale extends Locale,
Strings extends TranslationTree,
@@ -26,8 +23,8 @@ class Prate<
private readonly defaultStrings: Map<string, string>;
constructor(
public strings: Record<Locale, Strings>,
public defaultLocale: DefaultLocale,
private strings: Record<Locale, Strings>,
private defaultLocale: DefaultLocale,
) {
this.defaultStrings = this.flatten(strings[defaultLocale]);
}
@@ -35,7 +32,7 @@ class Prate<
private flatten(strings: TranslationTree) {
const translations = new Map<string, string>();
function traverse(parent: string, tree: Record<string, Translation>) {
function traverse(parent: string, tree: Record<string, TranslationNode>) {
for (const key in tree) {
const path = `${parent}${key}`;
@@ -91,5 +88,3 @@ class Prate<
return { translate, t: translate };
}
}
const prate = new Prate({ en, ru }, 'en');
+1
View File
@@ -1,6 +1,7 @@
export * from './blitz';
export * from './blitzkit';
export * from './databases';
export * from './i18n';
export * from './imgur';
export * from './math';
export * from './patreon';
+1
View File
@@ -0,0 +1 @@
/// <reference types="vite/client" />
+16 -14
View File
@@ -2,10 +2,12 @@
import { assertSecret, fetchGameDefinitions } from '@blitzkit/core';
import { Code, Flex, Heading, Link, Text } from '@radix-ui/themes';
import packageJson from '../../../../package.json';
import { getStrings } from '../core/i18n/getStrings';
import { LinkI18n } from './LinkI18n';
const gameDefinitions = await fetchGameDefinitions();
const { locale } = Astro.params;
const strings = getStrings(locale);
---
<style>
@@ -15,7 +17,6 @@ const { locale } = Astro.params;
</style>
<Flex className="footer" gap="6" p="6" direction="column" align="center">
{locale}
<Flex
align="center"
justify="between"
@@ -34,9 +35,9 @@ const { locale } = Astro.params;
}}
>
<Heading>BlitzKit</Heading>
<Text color="gray">Everything World of Tanks Blitz</Text>
<Text color="gray">{strings.website.footer.motto}</Text>
<Text size="1" color="gray">
Unaffiliated with Wargaming or any service
{strings.website.footer.copyright}
</Text>
</Flex>
@@ -63,7 +64,7 @@ const { locale } = Astro.params;
sm: 'auto',
}}
>
<Heading size="3">About</Heading>
<Heading size="3">{strings.website.footer.about.title}</Heading>
<Flex
direction="column"
align={{
@@ -71,25 +72,26 @@ const { locale } = Astro.params;
sm: 'start',
}}
>
<LinkI18n {locale} href="/docs/about/credits" color="gray"
>Credits</LinkI18n
>
<LinkI18n {locale} href="/docs/about/credits" color="gray">
{strings.website.footer.about.credits}
</LinkI18n>
<Link
href="https://discord.gg/nDt7AjGJQH"
target="_blank"
color="gray"
>
Discord
{strings.website.footer.about.discord}
</Link>
<Link
href="https://github.com/tresabhi/blitzkit"
target="_blank"
color="gray"
>
GitHub
{strings.website.footer.about.github}
</Link>
<LinkI18n {locale} href="/docs/patches" color="gray">Patches</LinkI18n
>
<LinkI18n {locale} href="/docs/patches" color="gray">
{strings.website.footer.about.patches}
</LinkI18n>
</Flex>
</Flex>
@@ -105,13 +107,13 @@ const { locale } = Astro.params;
sm: 'auto',
}}
>
<Heading size="3">Legal</Heading>
<Heading size="3">{strings.website.footer.legal.title}</Heading>
<Flex direction="column">
<LinkI18n {locale} href="/docs/legal/privacy-policy" color="gray">
Privacy policy
{strings.website.footer.legal.privacy}
</LinkI18n>
<LinkI18n {locale} href="/docs/legal/terms-of-service" color="gray">
Terms of service
{strings.website.footer.legal.terms}
</LinkI18n>
</Flex>
</Flex>
@@ -1,9 +1,14 @@
---
import { Code, Flex, Heading, Text } from '@radix-ui/themes';
import { resolveBranchName } from '../core/blitzkit/branches';
import { DEFAULT_LOCALE } from '@blitzkit/core';
import { getStrings } from '../core/i18n/getStrings';
import { literals } from '../core/i18n/literals';
const branchName = resolveBranchName();
const { locale } = Astro.params;
const branchName = resolveBranchName(locale);
const isBranchNamed = branchName !== undefined;
const strings = getStrings(locale);
---
<style>
@@ -141,7 +146,9 @@ const isBranchNamed = branchName !== undefined;
</Flex>
</Heading>
<Text color="gray" align="center" size="4">By TrèsAbhi ❤️</Text>
<Text color="gray" align="center" size="4"
>{literals(strings.website.home.hero.credit, ['TrèsAbhi'])}</Text
>
</Flex>
</Flex>
</Flex>
@@ -3,7 +3,8 @@ import { EyeOpenIcon } from '@radix-ui/react-icons';
import { Box, Flex, Heading, Text } from '@radix-ui/themes';
import { google } from 'googleapis';
import { awaitableTankDefinitions } from '../core/awaitables/tankDefinitions';
import { LocaleProvider } from '../hooks/useLocale';
import { literals } from '../core/i18n/literals';
import { LocaleProvider, useLocale } from '../hooks/useLocale';
import { TankopediaPersistent } from '../stores/tankopediaPersistent';
import { TankCard } from './TankCard';
@@ -79,13 +80,15 @@ export function HomePageHotTanks({ locale }: HomePageHotTanksProps) {
}
function Content() {
const { locale, strings } = useLocale();
return (
<Flex direction="column" pt="4" pb="8">
<Heading align="center" size="5">
Popular tanks
{strings.website.home.hot_tanks.title}
</Heading>
<Text color="gray" align="center" mb="5" size="2">
Last 7 days
{literals(strings.website.home.hot_tanks.subtitle, ['7'])}
</Text>
<Flex justify="center" gap="4" wrap="wrap">
@@ -96,7 +99,7 @@ function Content() {
discriminator={
<Flex align="center" gap="1" justify="center">
<EyeOpenIcon />
{Math.round(row.views * (30 / 7)).toLocaleString('en-US')}
{Math.round(row.views * (30 / 7)).toLocaleString(locale)}
</Flex>
}
/>
+18 -9
View File
@@ -19,14 +19,15 @@ import {
} from '@radix-ui/themes';
import { resolveBranchName } from '../core/blitzkit/branches';
import { homeTool, TOOLS } from '../constants/tools';
import { NavbarAccount } from './NavbarAccount';
import { LinkI18n } from './LinkI18n';
import { getStrings } from '../core/i18n/getStrings';
const toolsFiltered = TOOLS.filter((tool) => !('href' in tool));
const tools = [homeTool, ...toolsFiltered];
const branchName = resolveBranchName();
const isBranchNamed = branchName !== undefined;
const { locale } = Astro.params;
const branchName = resolveBranchName(locale);
const isBranchNamed = branchName !== undefined;
const strings = getStrings(locale);
---
<style>
@@ -139,14 +140,17 @@ const { locale } = Astro.params;
(branch) =>
branch !== assertSecret(import.meta.env.PUBLIC_ASSET_BRANCH),
);
const selected = Astro.url.pathname.startsWith(
`/tools/${tool.id}`,
);
const selected = Astro.url.pathname.includes(`/tools/${tool.id}`);
const toolStrings =
strings.website.tools[
(tool.stringsId ??
tool.id) as keyof typeof strings.website.tools
];
if (unavailableOnBranch) return null;
return (
<Fragment key={tool.title}>
<Fragment key={tool.id}>
{index > 0 && <Separator orientation="vertical" size="1" />}
<LinkI18n
{locale}
@@ -156,7 +160,7 @@ const { locale } = Astro.params;
href={`/tools/${tool.id}`}
underline={selected ? 'always' : 'hover'}
>
{tool.title}
{toolStrings.name}
</LinkI18n>
</Fragment>
);
@@ -212,6 +216,11 @@ const { locale } = Astro.params;
(branch) =>
branch !== assertSecret(import.meta.env.PUBLIC_ASSET_BRANCH),
);
const toolStrings =
strings.website.tools[
(tool.stringsId ??
tool.id) as keyof typeof strings.website.tools
];
if (unavailableOnBranch) return null;
@@ -265,7 +274,7 @@ const { locale } = Astro.params;
WebkitBackdropFilter: 'blur(4rem)',
}}
>
<Text>{tool.title}</Text>
<Text>{toolStrings.name}</Text>
</Flex>
</LinkI18n>
</Flex>
@@ -3,6 +3,7 @@ import { assertSecret, imgur, ImgurSize } from '@blitzkit/core';
import { CaretRightIcon } from '@radix-ui/react-icons';
import { Box, Button, Code, Flex, Heading, Text } from '@radix-ui/themes';
import type { Tool } from '../constants/tools';
import { getStrings } from '../core/i18n/getStrings';
import { LinkI18n } from './LinkI18n';
interface Props {
@@ -14,6 +15,11 @@ const disabled = tool.branches?.every(
(branch) => branch !== assertSecret(import.meta.env.PUBLIC_ASSET_BRANCH),
);
const { locale } = Astro.params;
const strings = getStrings(locale);
const toolStrings =
strings.website.tools[
(tool.stringsId??tool.id ) as keyof typeof strings.website.tools
];
---
<style>
@@ -101,7 +107,7 @@ const { locale } = Astro.params;
size={{ initial: '6', sm: tool.significant ? '7' : '5' }}
weight="medium"
>
{tool.title}
{toolStrings.name}
</Heading>
<Text
align={{ initial: 'center', sm: 'left' }}
@@ -115,7 +121,7 @@ const { locale } = Astro.params;
<Code>{assertSecret(import.meta.env.PUBLIC_ASSET_BRANCH)}</Code>
</>
) : (
tool.description
toolStrings.description
)
}
</Text>
@@ -132,7 +138,7 @@ const { locale } = Astro.params;
color={tool.button.color}
style={{ cursor: 'inherit' }}
>
{tool.button.text}
{toolStrings.button}
<CaretRightIcon />
</Button>
)
+6 -63
View File
@@ -3,15 +3,12 @@ import type { ComponentProps } from 'react';
export interface Tool {
id: string;
stringsId?: string;
image: string;
title: string;
description: string;
disabled?: boolean;
href?: string;
pageDescription?: string;
button: {
highContrast?: boolean;
text: string;
color: ComponentProps<typeof Button>['color'];
};
significant?: boolean;
@@ -20,13 +17,8 @@ export interface Tool {
export const tankopediaTool: Tool = {
id: 'tankopedia',
title: 'Tankopedia',
description: 'Blitz tank encyclopedia',
pageDescription:
'Statistics, armor, and more for all tanks in World of Tanks Blitz',
image: 'D8j6GZx',
button: {
text: 'Find tanks',
color: 'purple',
},
significant: true,
@@ -35,13 +27,8 @@ export const tankopediaTool: Tool = {
// export const ratingTool: Tool = {
// id: 'rating',
// title: 'Rating',
// description: 'Full rating leaderboard',
// pageDescription:
// 'Live and archived full rating leaderboard for World of Tanks Blitz',
// image: 'WEyMZH3',
// button: {
// text: 'View leaderboard',
// color: 'orange',
// },
// branches: ['main', 'dev'],
@@ -49,13 +36,8 @@ export const tankopediaTool: Tool = {
export const compareTool: Tool = {
id: 'compare',
title: 'Compare',
description: 'Compare tank statistics',
pageDescription:
'Compare tanks statistics and loadouts in World of Tanks Blitz',
image: 'O6VNl6e',
button: {
text: 'Compare tanks',
color: 'crimson',
},
branches: ['main', 'dev', 'opentest', 'preview'],
@@ -64,13 +46,8 @@ export const compareTool: Tool = {
export const sessionTool: Tool = {
// TODO: rename to tracker
id: 'session',
title: 'Session',
description: 'Live session stats',
pageDescription:
'Track your stats in real time as you play World of Tanks Blitz',
image: 'HdG9sTf',
button: {
text: 'Start tracking',
color: 'blue',
},
branches: ['main', 'dev'],
@@ -78,35 +55,25 @@ export const sessionTool: Tool = {
export const discordTool: Tool = {
id: 'discord',
title: 'Discord bot',
description: 'Stats right in Discord',
href: 'https://discord.com/application-directory/1097673957865443370',
image: '0bWE5hC',
button: {
text: 'Install now',
color: 'indigo',
},
};
export const moreTool: Tool = {
id: 'more',
title: 'More coming soon',
description: "What we're making",
href: 'https://discord.gg/nDt7AjGJQH',
image: '1nPm6VI',
button: {
text: 'Join Discord',
color: 'plum',
},
};
export const playerStatsTool: Tool = {
id: 'player-stats',
title: 'Player stats',
description: 'Periodical player statistics',
pageDescription: 'Periodical player statistics in World of Tanks Blitz',
export const playersTool: Tool = {
id: 'players',
button: {
text: 'Lookup player',
color: 'blue',
},
image: 'YelSOfT',
@@ -116,11 +83,7 @@ export const playerStatsTool: Tool = {
export const performanceTool: Tool = {
id: 'performance',
title: 'Performance',
description: 'Tank performance statistics',
pageDescription: 'Best tanks and their performances in World of Tanks Blitz',
button: {
text: 'View tanks',
color: 'jade',
},
image: 'vOKFB03',
@@ -129,12 +92,7 @@ export const performanceTool: Tool = {
export const embedTool: Tool = {
id: 'embed',
title: 'Embed',
description: 'Embeds for streaming',
pageDescription:
'Create embeds for streaming World of Tanks Blitz with extreme customization',
button: {
text: 'Create now',
color: 'red',
},
image: 'Q0faRYg',
@@ -142,20 +100,14 @@ export const embedTool: Tool = {
};
export const homeTool: Tool = {
id: '',
title: 'Home',
button: { color: 'blue', text: '' },
description: '',
id: 'home',
button: { color: 'blue' },
image: 'rUPie9G',
};
export const galleryTool: Tool = {
id: 'gallery',
title: 'Gallery',
description: 'Blitz player avatars',
pageDescription: 'All World of Tanks Blitz player avatars',
button: {
text: 'Browse all',
color: 'gold',
},
image: 'VhKlknk',
@@ -164,12 +116,8 @@ export const galleryTool: Tool = {
export const tierListTool: Tool = {
id: 'tier-list',
title: 'Tier list',
description: 'Rank Blitz tanks',
pageDescription:
'Explore tier lists ranking tanks from best to worst, based on player ratings and statistical performance in World of Tanks Blitz',
stringsId: 'tier_list',
button: {
text: 'Rank tanks',
color: 'orange',
},
image: 'oKKc8Xv',
@@ -178,12 +126,7 @@ export const tierListTool: Tool = {
export const chartsTool: Tool = {
id: 'charts',
title: 'Charts',
description: 'Lots of graphs',
pageDescription:
'Charts and graphs on anything and everything about tanks, players, and events in World of Tanks Blitz',
button: {
text: 'Nerd out',
color: 'bronze',
},
image: '6fhkljA',
+8 -10
View File
@@ -1,19 +1,17 @@
import { assertSecret } from '@blitzkit/core';
import { assertSecret, DEFAULT_LOCALE, localizedStrings } from '@blitzkit/core';
const BRANCH_NAMES: Record<string, string> = {
dev: 'beta',
opentest: 'opentest',
preview: 'preview',
};
export function resolveBranchName() {
export function resolveBranchName(locale = DEFAULT_LOCALE) {
const strings = localizedStrings[locale];
const secret = assertSecret(import.meta.env.PUBLIC_ASSET_BRANCH);
if (
assertSecret(import.meta.env.MODE) === 'development' &&
secret === 'dev'
) {
return 'dev';
return strings.common.branches.local;
} else {
return BRANCH_NAMES[secret] as string | undefined;
return (strings.common.branches as Record<string, string>)[secret] as
| string
| undefined;
}
}
@@ -0,0 +1,5 @@
import { DEFAULT_LOCALE, localizedStrings } from '@blitzkit/core';
export function getStrings(locale: string = DEFAULT_LOCALE) {
return localizedStrings[locale];
}
@@ -0,0 +1,5 @@
export function literals(string: string, literals: string[]) {
return literals.reduce((accumulator, literal, index) => {
return accumulator.replace(`%s${index + 1}`, literal);
}, string);
}
+12 -5
View File
@@ -1,8 +1,11 @@
import { DEFAULT_LOCALE } from '@blitzkit/core';
import { createContext, useContext, type ReactNode } from 'react';
import { getStrings } from '../core/i18n/getStrings';
const LocaleContext = createContext<{ locale: string | undefined } | null>(
null,
);
const LocaleContext = createContext<{
locale: string;
localeRaw: string | undefined;
} | null>(null);
interface LocaleProviderProps {
locale: string | undefined;
@@ -11,7 +14,9 @@ interface LocaleProviderProps {
export function LocaleProvider({ locale, children }: LocaleProviderProps) {
return (
<LocaleContext.Provider value={{ locale }}>
<LocaleContext.Provider
value={{ locale: locale ?? DEFAULT_LOCALE, localeRaw: locale }}
>
{children}
</LocaleContext.Provider>
);
@@ -24,5 +29,7 @@ export function useLocale() {
throw new Error('useLocale must be used within a LocaleProvider');
}
return { locale: context.locale };
const strings = getStrings(context.locale);
return { locale: context.locale, strings };
}
@@ -2,9 +2,9 @@
import {
assertSecret,
DEFAULT_LOCALE,
localizedStrings,
SUPPORTED_LOCALES,
} from '@blitzkit/core';
import strings from '@blitzkit/core/lang/en.json';
import { Box, Flex, Heading, Link, Text } from '@radix-ui/themes';
import type { GetStaticPaths } from 'astro';
import { AesonPlug } from '../../components/AesonPlug';
@@ -23,10 +23,12 @@ import {
tankopediaTool,
tierListTool,
} from '../../constants/tools';
import { getStrings } from '../../core/i18n/getStrings';
import BaseLayout from '../../layouts/BaseLayout.astro';
const branch = assertSecret(import.meta.env.PUBLIC_ASSET_BRANCH);
const { locale } = Astro.params;
const locale = Astro.params.locale ?? DEFAULT_LOCALE;
const strings = getStrings(Astro.params.locale);
export const getStaticPaths = (() => {
return [
@@ -45,6 +47,7 @@ export const getStaticPaths = (() => {
const selected =
thisLocale === locale ||
(locale === undefined && thisLocale === DEFAULT_LOCALE);
const localeNames = localizedStrings[thisLocale].common.locales;
return (
<>
@@ -55,7 +58,7 @@ export const getStaticPaths = (() => {
highContrast={selected}
href={`/${thisLocale === DEFAULT_LOCALE ? '' : thisLocale}`}
>
{strings.common.locales[thisLocale]}
{localeNames[thisLocale as keyof typeof localeNames]}
</Link>
</>
);
@@ -105,33 +108,24 @@ export const getStaticPaths = (() => {
<Box flexGrow="1" />
</Flex>
<Heading align="center" mt="6">Other cool projects</Heading>
<Heading align="center" mt="6"
>{strings.website.home.other_projects.title}</Heading
>
<Flex gap="4" mb="6" direction={{ initial: 'column', sm: 'row' }}>
<ToolCard
tool={{
button: {
text: 'Analyze',
color: 'blue',
},
description: 'Rich historic average stats',
id: 'blitz-analysis',
button: { color: 'blue' },
id: 'blitz_analysis',
image: 'j76YXGl',
title: 'BlitzAnalysis[]',
href: 'https://blitzanalysiz.com/',
}}
/>
<ToolCard
tool={{
button: {
color: 'purple',
text: 'Install',
highContrast: true,
},
button: { color: 'purple', highContrast: true },
image: 'zYrrYbR',
description: 'In-game session stats',
id: 'blitz-insider',
title: 'Blitz Insider',
id: 'blitz_insider',
href: 'https://discord.gg/UjWf9eGgtR',
}}
/>