feat: data-driven tools

This commit is contained in:
TrèsAbhi committed 2025-09-13 22:53:29 -05:00
1 parent 58b5ee7f83
commit 84dc5e4960
14 files changed
+118 -135

No files matched your search

+8 -10
View File
@@ -1,5 +1,4 @@
--- ---
import { assertSecret } from "@blitzkit/core";
import { import {
Cross1Icon, Cross1Icon,
DiscordLogoIcon, DiscordLogoIcon,
@@ -7,18 +6,20 @@ import {
HamburgerMenuIcon, HamburgerMenuIcon,
} from "@radix-ui/react-icons"; } from "@radix-ui/react-icons";
import { Box, Code, Flex, IconButton, Link } from "@radix-ui/themes"; import { Box, Code, Flex, IconButton, Link } from "@radix-ui/themes";
import { TOOLS } from "../constants/tools";
import { resolveBranchName } from "../core/blitzkit/branches"; import { resolveBranchName } from "../core/blitzkit/branches";
import { getStrings } from "../core/i18n/getStrings"; import { getStrings } from "../core/i18n/getStrings";
import { Var } from "../core/radix/var"; import { Var } from "../core/radix/var";
import { LinkI18n } from "./LinkI18n"; import { LinkI18n } from "./LinkI18n";
import { tools } from "../constants/tools";
export interface Props { export interface Props {
integrated?: boolean; integrated?: boolean;
} }
const { integrated = false } = Astro.props; const { integrated = false } = Astro.props;
const toolsFiltered = TOOLS.filter((tool) => !tool.href && !tool.disabled); const toolsFiltered = Object.entries(tools).filter(
([, tool]) => !tool.href && !tool.disabled
);
const { locale } = Astro.params; const { locale } = Astro.params;
const branchName = resolveBranchName(locale); const branchName = resolveBranchName(locale);
const isBranchNamed = branchName !== undefined; const isBranchNamed = branchName !== undefined;
@@ -137,16 +138,13 @@ const strings = getStrings(locale);
className="tools" className="tools"
> >
{ {
toolsFiltered.map((tool) => { toolsFiltered.map(([id, tool]) => {
const selected = Astro.url.pathname.includes(`/${tool.id}`); const selected = Astro.url.pathname.includes(`/${tool.id}`);
const toolStrings = const toolStrings =
strings.website.tools[ strings.website.tools[
(tool.strings ?? (tool.strings ?? id) as keyof typeof strings.website.tools
tool.id) as keyof typeof strings.website.tools
]; ];
if (toolStrings === undefined) console.log(tool.id);
return ( return (
<LinkI18n <LinkI18n
{locale} {locale}
@@ -205,10 +203,10 @@ const strings = getStrings(locale);
display={{ initial: "flex", sm: "none" }} display={{ initial: "flex", sm: "none" }}
> >
{ {
toolsFiltered.map((tool) => { toolsFiltered.map(([id, tool]) => {
const toolStrings = const toolStrings =
strings.website.tools[ strings.website.tools[
(tool.strings ?? tool.id) as keyof typeof strings.website.tools (tool.strings ?? id) as keyof typeof strings.website.tools
]; ];
return ( return (
+12 -4
View File
@@ -1,6 +1,13 @@
--- ---
import { CaretRightIcon } from "@radix-ui/react-icons"; import { CaretRightIcon } from "@radix-ui/react-icons";
import { Box, Button, Flex, Heading, Text } from "@radix-ui/themes"; import {
Box,
Button,
Flex,
Heading,
Text,
type ButtonProps,
} from "@radix-ui/themes";
import type { Tool } from "../constants/tools"; import type { Tool } from "../constants/tools";
import { getStrings } from "../core/i18n/getStrings"; import { getStrings } from "../core/i18n/getStrings";
import { LinkI18n } from "./LinkI18n"; import { LinkI18n } from "./LinkI18n";
@@ -45,7 +52,9 @@ const toolStrings =
</style> </style>
<Flex <Flex
style={{ backgroundImage: `url(/assets/images/tools/${tool.id}.webp)` }} style={{
backgroundImage: `url(/assets/images/tools/${tool.id}.webp)`,
}}
data-significant={tool.significant} data-significant={tool.significant}
className="container" className="container"
position="relative" position="relative"
@@ -105,12 +114,11 @@ const toolStrings =
</Flex> </Flex>
<Button <Button
highContrast={tool.button.highContrast}
size={{ size={{
initial: undefined, initial: undefined,
sm: tool.significant ? "3" : undefined, sm: tool.significant ? "3" : undefined,
}} }}
color={tool.button.color} color={tool.button as ButtonProps["color"]}
style={{ cursor: "inherit" }} style={{ cursor: "inherit" }}
> >
{toolStrings.button} {toolStrings.button}
@@ -1,7 +1,7 @@
--- ---
import { AstroSeo } from '@astrolib/seo'; import { AstroSeo } from "@astrolib/seo";
import { type Tool } from '../constants/tools'; import type { Tool } from "../constants/tools";
import { getStrings } from '../core/i18n/getStrings'; import { getStrings } from "../core/i18n/getStrings";
interface Props { interface Props {
tool: Tool; tool: Tool;
@@ -12,7 +12,7 @@ const { locale } = Astro.params;
const strings = getStrings(locale); const strings = getStrings(locale);
const toolStrings = const toolStrings =
strings.website.tools[ strings.website.tools[
(tool.stringsId ?? tool.id) as keyof typeof strings.website.tools (tool.strings ?? tool.id) as keyof typeof strings.website.tools
]; ];
--- ---
@@ -23,11 +23,13 @@ const toolStrings =
openGraph={{ openGraph={{
url: Astro.url.href, url: Astro.url.href,
images: [ images: [
{ url: `${Astro.url.origin}/assets/images/tools/${tool.id}.webp` }, {
url: `${Astro.url.origin}/assets/images/tools/${tool.id}.webp`,
},
], ],
title: toolStrings.name, title: toolStrings.name,
description: toolStrings.seo_description, description: toolStrings.seo_description,
site_name: 'BlitzKit', site_name: "BlitzKit",
}} }}
twitter={{ cardType: 'summary_large_image' }} twitter={{ cardType: "summary_large_image" }}
/> />
-24
View File
@@ -1,24 +0,0 @@
[
{
"id": "tanks",
"strings": "tankopedia",
"button": { "color": "purple" },
"significant": true
},
{
"id": "compare",
"button": { "color": "crimson" }
},
{
"id": "session",
"button": { "color": "blue" }
},
{
"id": "discord",
"href": "https://discord.com/application-directory/1097673957865443370",
"button": { "color": "indigo" }
}
]
+32 -40
View File
@@ -1,82 +1,74 @@
import { Button } from "@radix-ui/themes"; import type { ButtonProps } from "@radix-ui/themes";
import type { ComponentProps } from "react";
export interface Tool { export interface Tool {
id: string; id: string;
strings?: string; strings?: string;
button: ButtonProps["color"];
significant?: boolean;
disabled?: boolean; disabled?: boolean;
href?: string; href?: string;
button: {
highContrast?: boolean;
color: ComponentProps<typeof Button>["color"];
};
significant?: boolean;
} }
export const TOOLS: Tool[] = [ export const tools: Record<string, Tool> = {
{ tanks: {
id: "tanks", id: "tanks",
strings: "tankopedia", strings: "tankopedia",
button: { color: "purple" }, button: "purple",
significant: true, significant: true,
}, },
{ players: {
id: "players", id: "players",
disabled: true, disabled: true,
button: { color: "blue" }, button: "blue",
}, },
{ compare: {
id: "compare", id: "compare",
button: { color: "crimson" }, button: "crimson",
}, },
{ performance: {
id: "performance", id: "performance",
button: { color: "jade" }, button: "jade",
}, },
{ charts: {
id: "charts", id: "charts",
disabled: true, disabled: true,
button: { color: "bronze" }, button: "bronze",
}, },
{ guess: {
id: "guess", id: "guess",
button: { color: "cyan" }, button: "cyan",
}, },
{ mixer: {
id: "mixer", id: "mixer",
disabled: true, disabled: true,
button: { color: "red" }, button: "red",
}, },
{ gallery: {
id: "charts",
disabled: true,
button: { color: "red" },
},
{
id: "gallery", id: "gallery",
button: { color: "gold" }, button: "gold",
}, },
{ session: {
id: "session", id: "session",
button: { color: "blue" }, button: "blue",
}, },
{ discord: {
id: "discord", id: "discord",
href: "https://discord.com/application-directory/1097673957865443370", href: "https://discord.com/application-directory/1097673957865443370",
button: { color: "indigo" }, button: "indigo",
}, },
{ tier_list: {
id: "tier-list", id: "tier-list",
strings: "tier_list", strings: "tier_list",
button: { color: "orange" }, button: "orange",
}, },
{ embed: {
id: "embed", id: "embed",
button: { color: "red" }, button: "red",
}, },
{ more: {
id: "more", id: "more",
href: "https://discord.gg/nDt7AjGJQH", href: "https://discord.gg/nDt7AjGJQH",
button: { color: "plum" }, button: "plum",
}, },
]; };
@@ -1,7 +1,7 @@
--- ---
import { Box, Flex, Heading, Text } from "@radix-ui/themes"; import { Box, Flex, Heading, Text } from "@radix-ui/themes";
import ToolOpenGraph from "../components/ToolOpenGraph.astro"; import ToolOpenGraph from "../components/ToolOpenGraph.astro";
import { type Tool } from "../constants/tools"; import type { Tool } from "../constants/tools";
import { getStrings } from "../core/i18n/getStrings"; import { getStrings } from "../core/i18n/getStrings";
import BaseLayout from "./BaseLayout.astro"; import BaseLayout from "./BaseLayout.astro";
@@ -18,7 +18,7 @@ const toolStrings =
]; ];
--- ---
<ToolOpenGraph tool={tool} /> <ToolOpenGraph {tool} />
<BaseLayout> <BaseLayout>
<Box <Box
@@ -1,15 +1,15 @@
--- ---
import ToolOpenGraph from '../../../components/ToolOpenGraph.astro'; import ToolOpenGraph from "../../../components/ToolOpenGraph.astro";
import { compareTool } from '../../../constants/tools'; import { tools } from "../../../constants/tools";
import BaseLayout from '../../../layouts/BaseLayout.astro'; 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; const { locale } = Astro.params;
--- ---
<ToolOpenGraph tool={compareTool} /> <ToolOpenGraph tool={tools.compare} />
<BaseLayout noFooter> <BaseLayout noFooter>
<Page {locale} client:load /> <Page {locale} client:load />
@@ -1,13 +1,13 @@
--- ---
import { embedTool } from '../../../constants/tools'; import { tools } from "../../../constants/tools";
import ToolLayout from '../../../layouts/ToolLayout.astro'; import ToolLayout from "../../../layouts/ToolLayout.astro";
import { Page } from './_index'; import { Page } from "./_index";
export { getStaticPaths } from '../index.astro'; export { getStaticPaths } from "../index.astro";
const { locale } = Astro.params; const { locale } = Astro.params;
--- ---
<ToolLayout tool={embedTool}> <ToolLayout tool={tools.embed}>
<Page {locale} /> <Page {locale} />
</ToolLayout> </ToolLayout>
@@ -1,15 +1,15 @@
--- ---
import { galleryTool } from '../../../constants/tools'; import { tools } from "../../../constants/tools";
import ToolLayout from '../../../layouts/ToolLayout.astro'; import ToolLayout from "../../../layouts/ToolLayout.astro";
import type { getStaticPaths } from '../index.astro'; import type { getStaticPaths } from "../index.astro";
import { Page } from './_index'; import { Page } from "./_index";
export { getStaticPaths } from '../index.astro'; export { getStaticPaths } from "../index.astro";
const { locale } = Astro.params; const { locale } = Astro.params;
--- ---
<ToolLayout tool={galleryTool}> <ToolLayout tool={tools.gallery}>
<Page {locale} client:only="react"> <Page {locale} client:only="react">
<Page {locale} skeleton slot="fallback" /> <Page {locale} skeleton slot="fallback" />
</Page> </Page>
@@ -9,7 +9,7 @@ import { AesonPlug } from "../../components/AesonPlug";
import HomeHero from "../../components/HomeHero.astro"; import HomeHero from "../../components/HomeHero.astro";
import { Plugs } from "../../components/Plugs"; import { Plugs } from "../../components/Plugs";
import ToolCard from "../../components/ToolCard.astro"; import ToolCard from "../../components/ToolCard.astro";
import { TOOLS, type Tool } from "../../constants/tools"; import { tools, type Tool } from "../../constants/tools";
import { getStrings } from "../../core/i18n/getStrings"; import { getStrings } from "../../core/i18n/getStrings";
import BaseLayout from "../../layouts/BaseLayout.astro"; import BaseLayout from "../../layouts/BaseLayout.astro";
@@ -20,11 +20,15 @@ const locale = Astro.params.locale ?? DEFAULT_LOCALE;
const strings = getStrings(Astro.params.locale); const strings = getStrings(Astro.params.locale);
const rows: Tool[][] = []; const rows: Tool[][] = [];
for (const tool of TOOLS) { for (const id in tools) {
if (tool.disabled) continue; const tool = tools[id];
if ("disabled" in tool && tool.disabled) continue;
const compatibleRow = rows.find( const compatibleRow = rows.find(
(row) => row.length < MAX_TOOLS_PER_ROW && !row[0].significant (row) =>
row.length < MAX_TOOLS_PER_ROW &&
!("significant" in row[0] && row[0].significant)
); );
if (compatibleRow) { if (compatibleRow) {
@@ -109,11 +113,12 @@ export const getStaticPaths = (() => {
rows.map((row) => ( rows.map((row) => (
<Flex gap="4" direction={{ initial: "column", sm: "row" }}> <Flex gap="4" direction={{ initial: "column", sm: "row" }}>
{row.map((tool) => ( {row.map((tool) => (
<ToolCard tool={tool} /> <ToolCard {tool} />
))} ))}
{row.length < MAX_TOOLS_PER_ROW && !row[0].significant && ( {row.length < MAX_TOOLS_PER_ROW &&
<Box flexGrow="1" /> !("significant" in row[0] && row[0].significant) && (
)} <Box flexGrow="1" />
)}
</Flex> </Flex>
)) ))
} }
@@ -1,16 +1,16 @@
--- ---
import ToolOpenGraph from '../../../components/ToolOpenGraph.astro'; import ToolOpenGraph from "../../../components/ToolOpenGraph.astro";
import { performanceTool } from '../../../constants/tools'; import { tools } from "../../../constants/tools";
import BaseLayout from '../../../layouts/BaseLayout.astro'; import BaseLayout from "../../../layouts/BaseLayout.astro";
import type { getStaticPaths } from '../index.astro'; import type { getStaticPaths } from "../index.astro";
import { Page } from './_index'; import { Page } from "./_index";
export { getStaticPaths } from '../index.astro'; export { getStaticPaths } from "../index.astro";
const { locale } = Astro.params; const { locale } = Astro.params;
--- ---
<ToolOpenGraph tool={performanceTool} /> <ToolOpenGraph tool={tools.performance} />
<BaseLayout noFooter> <BaseLayout noFooter>
<Page client:only="react" {locale}> <Page client:only="react" {locale}>
@@ -1,14 +1,14 @@
--- ---
import { sessionTool } from '../../../constants/tools'; import { tools } from "../../../constants/tools";
import ToolLayout from '../../../layouts/ToolLayout.astro'; import ToolLayout from "../../../layouts/ToolLayout.astro";
import type { getStaticPaths } from '../index.astro'; import type { getStaticPaths } from "../index.astro";
import { Page } from './_index'; import { Page } from "./_index";
export { getStaticPaths } from '../index.astro'; export { getStaticPaths } from "../index.astro";
const { locale } = Astro.params; const { locale } = Astro.params;
--- ---
<ToolLayout tool={sessionTool}> <ToolLayout tool={tools.session}>
<Page client:load {locale} /> <Page client:load {locale} />
</ToolLayout> </ToolLayout>
@@ -1,14 +1,14 @@
--- ---
import { tankopediaTool } from '../../../constants/tools'; import { tools } from "../../../constants/tools";
import ToolLayout from '../../../layouts/ToolLayout.astro'; import ToolLayout from "../../../layouts/ToolLayout.astro";
import { Page } from './_index'; import { Page } from "./_index";
export { getStaticPaths } from '../index.astro'; export { getStaticPaths } from "../index.astro";
const { locale } = Astro.params; const { locale } = Astro.params;
--- ---
<ToolLayout tool={tankopediaTool}> <ToolLayout tool={tools.tanks}>
<Page {locale} client:only="react"> <Page {locale} client:only="react">
<Page {locale} skeleton slot="fallback" /> <Page {locale} skeleton slot="fallback" />
</Page> </Page>
@@ -1,13 +1,15 @@
--- ---
import { tierListTool } from '../../../constants/tools'; import { tools } from "../../../constants/tools";
import ToolLayout from '../../../layouts/ToolLayout.astro'; import ToolLayout from "../../../layouts/ToolLayout.astro";
import { Page } from './_index'; import { Page } from "./_index";
export { getStaticPaths } from '../index.astro'; export { getStaticPaths } from "../index.astro";
const { locale } = Astro.params; const { locale } = Astro.params;
--- ---
<ToolLayout tool={tierListTool}> <ToolLayout tool={tools.tier_list}>
<Page {locale} client:load /> <Page {locale} client:load />
</ToolLayout> </ToolLayout>