mirror of
https://github.com/blitzkit/blitzkit.git
synced 2026-10-21 18:57:03 +02:00
currency icons
This commit is contained in:
1 parent
f0e0d849d5
commit
d9ce16b41a
6 files changed
+83
-35
No files matched your search
@@ -36,13 +36,12 @@ function PriceEntry({ entry }: PriceEntryProps) {
|
||||
throw new Error("Unsupported price type");
|
||||
}
|
||||
|
||||
const [, iconName] = entry.currency_price.currency_catalog_id.split(".");
|
||||
|
||||
return (
|
||||
<Text size="minor" lowContrast className={styles.entry}>
|
||||
<div className={styles.wrapper}>
|
||||
<img
|
||||
className={styles.icon}
|
||||
src="https://static.vecteezy.com/system/resources/thumbnails/047/493/988/small/hairy-fluffy-cat-playing-png.png"
|
||||
/>
|
||||
<img className={styles.icon} src={`/api/currencies/${iconName}.webp`} />
|
||||
{formatCompact(locale, entry.currency_price.amount)}
|
||||
</div>
|
||||
</Text>
|
||||
|
||||
@@ -11,13 +11,17 @@
|
||||
gap: var(--space-3);
|
||||
|
||||
.stage {
|
||||
padding: var(--space-3);
|
||||
position: relative;
|
||||
aspect-ratio: 3 / 4;
|
||||
|
||||
font-size: 2em;
|
||||
|
||||
.icon {
|
||||
width: 1em;
|
||||
height: 1em;
|
||||
|
||||
transform: translateX(var(--space-1));
|
||||
transform: translate(var(--space-1), calc(-1 * var(--space-1)));
|
||||
}
|
||||
|
||||
.tier {
|
||||
|
||||
@@ -8,8 +8,8 @@ import { useProtagonist } from "../../hooks/useProtagonist";
|
||||
import { useStrings } from "../../hooks/useStrings";
|
||||
import { useUpgradePreset } from "../../hooks/useUpgradePreset";
|
||||
import { Tankopedia } from "../../stores/tankopedia";
|
||||
import { Button } from "../Button";
|
||||
import { Heading } from "../Heading";
|
||||
import { IconButton } from "../IconButton";
|
||||
import { Price } from "../Price";
|
||||
import { Section } from "../Section";
|
||||
import { Text } from "../Text";
|
||||
@@ -117,7 +117,7 @@ function LineElement({ index, lineName, stage }: LineElementProps) {
|
||||
const isSelected = upgrades[lineName] === index;
|
||||
|
||||
return (
|
||||
<IconButton
|
||||
<Button
|
||||
color={isSelected ? undefined : "gray"}
|
||||
variant={isSelected ? "surface" : "soft"}
|
||||
radius="1"
|
||||
@@ -183,6 +183,6 @@ function LineElement({ index, lineName, stage }: LineElementProps) {
|
||||
</Text>
|
||||
|
||||
{price && <Price className={styles.price} price={price} />}
|
||||
</IconButton>
|
||||
</Button>
|
||||
);
|
||||
}
|
||||
@@ -41,6 +41,8 @@ export abstract class AbstractAPI {
|
||||
abstract background(id: string): Promise<Background>;
|
||||
abstract backgrounds(): Promise<Backgrounds>;
|
||||
|
||||
abstract currencyIcon(id: string): Promise<string>;
|
||||
|
||||
private assertLocale(locale: string) {
|
||||
const supported = locales.supported.find(
|
||||
(supported) => supported.locale === locale,
|
||||
|
||||
@@ -35,6 +35,40 @@ export class ServerAPI extends AbstractAPI {
|
||||
super();
|
||||
}
|
||||
|
||||
resolveRemoteUrl(remoteUrls: string[]) {
|
||||
let remoteStorage: RemoteStorageComponent | undefined = undefined;
|
||||
|
||||
for (const remoteUrl of remoteUrls) {
|
||||
const item = this.metadata.item(remoteUrl);
|
||||
const candidate = item.RemoteStorage();
|
||||
|
||||
if (
|
||||
remoteStorage === undefined ||
|
||||
candidate.download_speed_weight > remoteStorage.download_speed_weight
|
||||
) {
|
||||
remoteStorage = candidate;
|
||||
}
|
||||
}
|
||||
|
||||
if (remoteStorage === undefined) {
|
||||
throw new Error("No suitable production remote storage found");
|
||||
}
|
||||
|
||||
return remoteStorage;
|
||||
}
|
||||
|
||||
resolveClientConfig() {
|
||||
const group = this.metadata.group("ClientConfigsEntity");
|
||||
|
||||
if (group.length !== 1) {
|
||||
throw new RangeError(
|
||||
`Don't know how to handle ${group.length} ClientConfigsEntities`,
|
||||
);
|
||||
}
|
||||
|
||||
return this.metadata.item(group[0].id);
|
||||
}
|
||||
|
||||
@Cache()
|
||||
async tankList() {
|
||||
const group = this.metadata.group("TankEntity");
|
||||
@@ -207,37 +241,14 @@ export class ServerAPI extends AbstractAPI {
|
||||
|
||||
@Cache()
|
||||
async gameStrings(locale: string) {
|
||||
const group = this.metadata.group("ClientConfigsEntity");
|
||||
|
||||
if (group.length !== 1) {
|
||||
throw new RangeError(
|
||||
`Don't know how to handle ${group.length} ClientConfigsEntities`,
|
||||
);
|
||||
}
|
||||
|
||||
const clientConfig = this.metadata.item(group[0].id);
|
||||
const clientConfig = this.resolveClientConfig();
|
||||
const localizationResources = clientConfig.LocalizationResources();
|
||||
const strings: Record<string, string> = {};
|
||||
|
||||
for (const remoteStorageSettings of localizationResources.remote_storages) {
|
||||
let remoteStorage: RemoteStorageComponent | undefined = undefined;
|
||||
|
||||
for (const remoteUrl of remoteStorageSettings.remote_urls) {
|
||||
const item = this.metadata.item(remoteUrl);
|
||||
const candidate = item.RemoteStorage();
|
||||
|
||||
if (
|
||||
remoteStorage === undefined ||
|
||||
candidate.download_speed_weight > remoteStorage.download_speed_weight
|
||||
) {
|
||||
remoteStorage = candidate;
|
||||
}
|
||||
}
|
||||
|
||||
if (remoteStorage === undefined) {
|
||||
throw new Error("No suitable production remote storage found");
|
||||
}
|
||||
|
||||
const remoteStorage = this.resolveRemoteUrl(
|
||||
remoteStorageSettings.remote_urls,
|
||||
);
|
||||
const configPath = `${remoteStorage.url}${remoteStorage.relative_path}/config.yaml`;
|
||||
const config = await fetch(configPath)
|
||||
.then((response) => response.text())
|
||||
@@ -344,4 +355,23 @@ export class ServerAPI extends AbstractAPI {
|
||||
|
||||
return { backgrounds };
|
||||
}
|
||||
|
||||
@Cache()
|
||||
async currencyIcon(id: string) {
|
||||
const item = this.metadata.item(`CurrencyEntity.${id}`);
|
||||
const stuffUI = item.StuffUI("UIComponent");
|
||||
const config = this.resolveClientConfig();
|
||||
const metroResources = config.MetroResources();
|
||||
const remoteStorage = this.resolveRemoteUrl(
|
||||
metroResources.remote_storage!.remote_urls,
|
||||
);
|
||||
|
||||
const iconPathHack = stuffUI.icon.replace("\n", "");
|
||||
|
||||
if (!stuffUI.icon.includes("\n")) {
|
||||
throw new Error("Icon path doesn't include newline, can't apply hack");
|
||||
}
|
||||
|
||||
return `${remoteStorage.url}${remoteStorage.relative_path}${iconPathHack}`;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
import type { GetStaticPaths } from "astro";
|
||||
import { api } from "../../../core/api/dynamic";
|
||||
import { imageProxy } from "../../../core/api/imageProxy";
|
||||
|
||||
export const getStaticPaths = (async () => {
|
||||
const group = api.metadata.group("CurrencyEntity");
|
||||
return group.map(({ name }) => ({ params: { id: name } }));
|
||||
}) satisfies GetStaticPaths;
|
||||
|
||||
export async function GET({ params }: { params: { id: string } }) {
|
||||
const icon = await api.currencyIcon(params.id);
|
||||
return await imageProxy(icon);
|
||||
}
|
||||
Reference in new issue
Block a user