feat: flesh out popular tanks

This commit is contained in:
TrèsAbhi committed 2026-03-15 22:37:46 -05:00
1 parent b6c4c4e852
commit 406ad52c8d
10 files changed
+85 -30

No files matched your search

+1
View File
@@ -2,6 +2,7 @@
<PropertyGroup> <PropertyGroup>
<RootNamespace>BlitzKit.Game</RootNamespace> <RootNamespace>BlitzKit.Game</RootNamespace>
<TargetFramework>net9.0</TargetFramework> <TargetFramework>net9.0</TargetFramework>
<RuntimeIdentifier>win-x64</RuntimeIdentifier>
<ImplicitUsings>enable</ImplicitUsings> <ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable> <Nullable>enable</Nullable>
<NodeApiAssemblyJSModuleType>esm</NodeApiAssemblyJSModuleType> <NodeApiAssemblyJSModuleType>esm</NodeApiAssemblyJSModuleType>
+1 -1
View File
@@ -1 +1 @@
export * from "../bin/Debug/net9.0/game"; export * from "../bin/Debug/net9.0/win-x64/game";
@@ -2,9 +2,8 @@
import { api } from "../core/api/dynamic"; import { api } from "../core/api/dynamic";
import { tools } from "../core/tools/tools"; import { tools } from "../core/tools/tools";
import { Heading } from "./Heading"; import { Heading } from "./Heading";
import { Scroller } from "./Scroller"; import { HomeTanksPopular } from "./HomeTanksPopular";
import { Section } from "./Section"; import { Section } from "./Section";
import { TankCard } from "./TankCard";
import ToolCard from "./ToolCard.astro"; import ToolCard from "./ToolCard.astro";
import ToolsWrapper from "./ToolsWrapper.astro"; import ToolsWrapper from "./ToolsWrapper.astro";
@@ -13,37 +12,19 @@ interface Props {
} }
const { locale } = Astro.props; const { locale } = Astro.props;
const strings = await api.strings(locale); const strings = await api.strings(locale);
const popular = (await api.popularTanks()).tanks.slice(0, 8);
console.log(popular.length);
--- ---
<style> <style>
.title { .title {
margin-bottom: var(--space-3); margin-bottom: var(--space-3);
} }
.tanks {
z-index: 1;
.content {
display: flex;
gap: 2rem;
}
}
</style> </style>
<Section> <Section>
<Heading size="2" className="title">{strings.home.tanks}</Heading> <Heading size="2" className="title">{strings.home.tanks}</Heading>
<Scroller client:load className="tanks"> <HomeTanksPopular {locale} client:load />
<div class="content">
{popular.map((tank) => <TankCard {...tank} />)}
</div>
</Scroller>
<ToolCard gradient {locale} tool={tools.tanks} /> <ToolCard gradient {locale} tool={tools.tanks} />
@@ -0,0 +1,9 @@
.tanks {
z-index: 1;
.content {
display: flex;
gap: 2rem;
}
}
@@ -0,0 +1,32 @@
import { api } from "../../core/api/dynamic";
import { useAwait } from "../../hooks/useAwait";
import {
LocaleProvider,
type LocaleAcceptorProps,
} from "../../hooks/useLocale";
import { Scroller } from "../Scroller";
import { TankCard } from "../TankCard";
import styles from "./index.module.css";
export function HomeTanksPopular({ locale }: LocaleAcceptorProps) {
return (
<LocaleProvider locale={locale}>
<Content />
</LocaleProvider>
);
}
function Content() {
const popular = useAwait(() => api.popularTanks(), "popular-tanks");
const trimmed = popular.tanks.slice(0, 32);
return (
<Scroller className={styles.tanks}>
<div className={styles.content}>
{trimmed.map((tank) => (
<TankCard key={tank.id} {...tank} />
))}
</div>
</Scroller>
);
}
@@ -2,7 +2,10 @@
display: flex; display: flex;
flex-direction: column; flex-direction: column;
align-items: center; align-items: center;
gap: var(--space-2); gap: var(--space-4);
overflow: hidden;
min-width: min-content;
.icon-wrapper { .icon-wrapper {
position: relative; position: relative;
@@ -20,12 +23,19 @@
} }
.icon { .icon {
width: 7rem; width: 13rem;
aspect-ratio: 4 / 3; height: 8rem;
position: relative; position: relative;
background-size: 150%; background-size: 140%;
background-position: center; background-position: 40% center;
} }
} }
.name {
white-space: nowrap;
overflow: hidden;
max-width: 100%;
text-overflow: ellipsis;
}
} }
@@ -1,8 +1,14 @@
import { api } from "../../core/api/dynamic";
import { useAwait } from "../../hooks/useAwait";
import { useGameStrings } from "../../hooks/useGameStrings";
import type { PopularTank } from "../../protos/popular_tanks"; import type { PopularTank } from "../../protos/popular_tanks";
import { Text } from "../Text"; import { Text } from "../Text";
import styles from "./index.module.css"; import styles from "./index.module.css";
export function TankCard({ id }: PopularTank) { export function TankCard({ id }: PopularTank) {
const tank = useAwait(() => api.tank(id), `tank-${id}`);
const gameStrings = useGameStrings("TankEntity");
return ( return (
<div className={styles["tank-card"]}> <div className={styles["tank-card"]}>
<div className={styles["icon-wrapper"]}> <div className={styles["icon-wrapper"]}>
@@ -21,7 +27,7 @@ export function TankCard({ id }: PopularTank) {
/> />
</div> </div>
<Text className={styles.name}>{id}</Text> <Text className={styles.name}>{gameStrings[tank.tank!.name!.value]}</Text>
</div> </div>
); );
} }
+10 -1
View File
@@ -1,9 +1,10 @@
import { fetchPB } from "@blitzkit/core"; import { fetchPB } from "@blitzkit/core";
import type { Strings } from "@blitzkit/i18n"; import type { Strings } from "@blitzkit/i18n";
import { Avatars } from "../../protos/avatars"; import { Avatars } from "../../protos/avatars";
import { PopularTanks } from "../../protos/popular_tanks";
import { Tank } from "../../protos/tank";
import { AbstractAPI } from "./abstract"; import { AbstractAPI } from "./abstract";
//@ts-expect-error
export class ClientAPI extends AbstractAPI { export class ClientAPI extends AbstractAPI {
protected _avatars() { protected _avatars() {
return fetchPB("/api/avatars/all.pb", Avatars); return fetchPB("/api/avatars/all.pb", Avatars);
@@ -24,4 +25,12 @@ export class ClientAPI extends AbstractAPI {
const json = (await response.json()) as Strings; const json = (await response.json()) as Strings;
return json; return json;
} }
protected _popularTanks() {
return fetchPB("/api/tanks/popular.pb", PopularTanks);
}
protected _tank(id: string) {
return fetchPB(`/api/tanks/${id}.pb`, Tank);
}
} }
+1 -1
View File
@@ -1,5 +1,5 @@
import { GameInterface } from "@blitzkit/game"; import { GameInterface } from "@blitzkit/game";
export const game = new GameInterface( export const game = new GameInterface(
"/mnt/c/Program Files (x86)/Steam/steamapps/common/World of Tanks Blitz Playtest", "C:/Program Files (x86)/Steam/steamapps/common/World of Tanks Blitz Playtest",
); );
@@ -0,0 +1,7 @@
import { api } from "../../../core/api/dynamic";
import { PopularTanks } from "../../../protos/popular_tanks";
export async function GET() {
const popular = await api.popularTanks();
return new Response(PopularTanks.encode(popular).finish());
}