mirror of
https://github.com/blitzkit/blitzkit.git
synced 2026-10-23 11:39:50 +02:00
rename methods
This commit is contained in:
1 parent
ec161addab
commit
5f737d940d
111 files changed
+563
-413
No files matched your search
+11
-17
@@ -1,23 +1,18 @@
|
||||
import { alias, Avatar } from "@blitzkit/core";
|
||||
import { Cross1Icon, DownloadIcon } from "@radix-ui/react-icons";
|
||||
import {
|
||||
Dialog,
|
||||
Flex,
|
||||
IconButton,
|
||||
Link,
|
||||
Skeleton,
|
||||
Text,
|
||||
} from "@radix-ui/themes";
|
||||
import { useRef } from "react";
|
||||
import { useIntersection } from "../../hooks/useIntersection";
|
||||
import { useLocale } from "../../hooks/useLocale";
|
||||
import type { MaybeSkeletonComponentProps } from "../../types/maybeSkeletonComponentProps";
|
||||
import { useIntersection } from "../hooks/useIntersection";
|
||||
import { useLocale } from "../hooks/useLocale";
|
||||
import type { MaybeSkeletonComponentProps } from "../types/maybeSkeletonComponentProps";
|
||||
import { Flex } from "./Flex";
|
||||
import { Skeleton } from "./Skeleton";
|
||||
import { Text } from "./Text";
|
||||
|
||||
type GalleryCardProps = MaybeSkeletonComponentProps<{
|
||||
avatar: Avatar;
|
||||
}>;
|
||||
|
||||
export function GalleryCard(props: GalleryCardProps) {
|
||||
export function AvatarCard(props: GalleryCardProps) {
|
||||
const src = alias(
|
||||
"api",
|
||||
`/gallery/avatars/${!props.skeleton && `${props.avatar.id}${props.avatar.extension}`}`,
|
||||
@@ -31,17 +26,16 @@ export function GalleryCard(props: GalleryCardProps) {
|
||||
|
||||
const content = (
|
||||
<Flex
|
||||
direction="column"
|
||||
column
|
||||
align="center"
|
||||
width="6rem"
|
||||
gap="1"
|
||||
ref={card}
|
||||
style={{ cursor: "pointer" }}
|
||||
>
|
||||
{props.skeleton && (
|
||||
<>
|
||||
<Skeleton width="100%" height="4.57rem" />
|
||||
<Skeleton width="100%" height="1em" />
|
||||
<Skeleton />
|
||||
<Skeleton />
|
||||
</>
|
||||
)}
|
||||
|
||||
@@ -58,7 +52,7 @@ export function GalleryCard(props: GalleryCardProps) {
|
||||
alt={unwrap(props.avatar.name!)}
|
||||
/>
|
||||
|
||||
<Text size="1" align="center" style={{ maxWidth: "100%" }}>
|
||||
<Text size="minor" align="center" style={{ maxWidth: "100%" }}>
|
||||
{unwrap(props.avatar.name!)}
|
||||
</Text>
|
||||
</>
|
||||
+6
-9
@@ -1,19 +1,18 @@
|
||||
import { MagnifyingGlassIcon } from "@radix-ui/react-icons";
|
||||
import { TextField } from "@radix-ui/themes";
|
||||
import { useRef } from "react";
|
||||
import { useLocale } from "../../hooks/useLocale";
|
||||
import { Gallery } from "../../stores/gallery";
|
||||
import type { MaybeSkeletonComponentProps } from "../../types/maybeSkeletonComponentProps";
|
||||
import { TextField } from "../TextField";
|
||||
|
||||
export function GallerySearch({ skeleton }: MaybeSkeletonComponentProps) {
|
||||
export function AvatarsSearch({ skeleton }: MaybeSkeletonComponentProps) {
|
||||
const input = useRef<HTMLInputElement>(null);
|
||||
const { strings } = useLocale();
|
||||
|
||||
return (
|
||||
<TextField.Root
|
||||
variant="classic"
|
||||
<TextField
|
||||
disabled={skeleton}
|
||||
placeholder={strings.website.tools.gallery.search.hint}
|
||||
placeholder={strings.website.tools.avatars.search.hint}
|
||||
ref={input}
|
||||
onChange={(event) => {
|
||||
Gallery.mutate((draft) => {
|
||||
@@ -22,9 +21,7 @@ export function GallerySearch({ skeleton }: MaybeSkeletonComponentProps) {
|
||||
});
|
||||
}}
|
||||
>
|
||||
<TextField.Slot>
|
||||
<MagnifyingGlassIcon />
|
||||
</TextField.Slot>
|
||||
</TextField.Root>
|
||||
<MagnifyingGlassIcon />
|
||||
</TextField>
|
||||
);
|
||||
}
|
||||
Whitespace-only changes.
+9
-8
@@ -1,6 +1,5 @@
|
||||
import locales from "@blitzkit/i18n/locales.json";
|
||||
import { literals } from "@blitzkit/i18n/src/literals";
|
||||
import { Flex, Text } from "@radix-ui/themes";
|
||||
import fuzzysort from "fuzzysort";
|
||||
import { times } from "lodash-es";
|
||||
import { useMemo, useState } from "react";
|
||||
@@ -8,20 +7,22 @@ import { api } from "../../core/blitzkit/api";
|
||||
import { useLocale } from "../../hooks/useLocale";
|
||||
import { Gallery } from "../../stores/gallery";
|
||||
import type { MaybeSkeletonComponentProps } from "../../types/maybeSkeletonComponentProps";
|
||||
import { AvatarCard } from "../AvatarCard";
|
||||
import { Flex } from "../Flex";
|
||||
import { InlineSkeleton } from "../InlineSkeleton";
|
||||
import { GalleryCard } from "./Card";
|
||||
import { Text } from "../Text";
|
||||
|
||||
export interface Avatar {
|
||||
name: string;
|
||||
id: string;
|
||||
}
|
||||
|
||||
const gallery = await api.galleryDefinitions();
|
||||
const gallery = await api.gallery();
|
||||
|
||||
const DEFAULT_LOADED = 42;
|
||||
const PREVIEW_COUNT = 28;
|
||||
|
||||
export function GalleryList({ skeleton }: MaybeSkeletonComponentProps) {
|
||||
export function AvatarsList({ skeleton }: MaybeSkeletonComponentProps) {
|
||||
const search = Gallery.use((state) => state.search);
|
||||
const [loadedCards, setLoadedCards] = useState(DEFAULT_LOADED);
|
||||
const { locale, strings } = useLocale();
|
||||
@@ -48,9 +49,9 @@ export function GalleryList({ skeleton }: MaybeSkeletonComponentProps) {
|
||||
<>
|
||||
<Text align="center" color="gray">
|
||||
{skeleton ? (
|
||||
<InlineSkeleton width="7rem" />
|
||||
<InlineSkeleton />
|
||||
) : (
|
||||
literals(strings.website.tools.gallery.search.results, {
|
||||
literals(strings.website.tools.avatars.search.results, {
|
||||
count: filtered.length.toLocaleString(locale),
|
||||
})
|
||||
)}
|
||||
@@ -60,14 +61,14 @@ export function GalleryList({ skeleton }: MaybeSkeletonComponentProps) {
|
||||
{!skeleton &&
|
||||
filtered
|
||||
.slice(0, loadedCards)
|
||||
.map((avatar) => <GalleryCard key={avatar.id} avatar={avatar} />)}
|
||||
.map((avatar) => <AvatarCard key={avatar.id} avatar={avatar} />)}
|
||||
|
||||
{times(
|
||||
skeleton
|
||||
? DEFAULT_LOADED + PREVIEW_COUNT
|
||||
: Math.min(PREVIEW_COUNT, filtered.length - loadedCards),
|
||||
(index) => (
|
||||
<GalleryCard
|
||||
<AvatarCard
|
||||
key={index}
|
||||
skeleton
|
||||
onIntersection={() => setLoadedCards((state) => state + 2)}
|
||||
@@ -0,0 +1,16 @@
|
||||
.code {
|
||||
font: inherit;
|
||||
font-family: var(--font-family-mono);
|
||||
|
||||
white-space: pre;
|
||||
|
||||
display: inline-block;
|
||||
|
||||
&[data-variant="solid"] {
|
||||
background-color: var(--gray-3);
|
||||
|
||||
border-radius: var(--space-3);
|
||||
|
||||
padding: var(--space-4);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
import { classNames } from "../../ui/classNames";
|
||||
import { Text, type TextProps } from "../Text";
|
||||
import styles from "./index.module.css";
|
||||
|
||||
export interface CodeProps extends TextProps {
|
||||
lowContrast?: boolean;
|
||||
variant?: "ghost" | "solid";
|
||||
}
|
||||
|
||||
export function Code({ className, variant = "ghost", ...props }: CodeProps) {
|
||||
return (
|
||||
<Text
|
||||
data-variant={variant}
|
||||
className={classNames(styles.code, className)}
|
||||
{...props}
|
||||
/>
|
||||
);
|
||||
}
|
||||
@@ -39,10 +39,10 @@ const [
|
||||
consumableDefinitions,
|
||||
provisionDefinitions,
|
||||
] = await Promise.all([
|
||||
api.skillDefinitions(),
|
||||
api.equipmentDefinitions(),
|
||||
api.consumableDefinitions(),
|
||||
api.provisionDefinitions(),
|
||||
api.skill(),
|
||||
api.equipment(),
|
||||
api.consumables(),
|
||||
api.provisions(),
|
||||
]);
|
||||
|
||||
export function CompareTable({ stats }: CompareTableProps) {
|
||||
|
||||
@@ -15,7 +15,7 @@ interface ControlsProps {
|
||||
onAddTankDialogOpenChange: (open: boolean) => void;
|
||||
}
|
||||
|
||||
const provisionDefinitions = await api.provisionDefinitions();
|
||||
const provisionDefinitions = await api.provisions();
|
||||
|
||||
export function Controls({
|
||||
addTankDialogOpen,
|
||||
|
||||
@@ -13,7 +13,7 @@ interface TankControlProps {
|
||||
slug: string;
|
||||
}
|
||||
|
||||
const provisionDefinitions = await api.provisionDefinitions();
|
||||
const provisionDefinitions = await api.provisions();
|
||||
|
||||
export function TankControl({ index, slug }: TankControlProps) {
|
||||
const { locale, strings } = useLocale();
|
||||
|
||||
@@ -8,7 +8,7 @@ interface CrewSkillManagerProps {
|
||||
onChange?: (skillLevels: Record<string, number>) => void;
|
||||
}
|
||||
|
||||
const skillDefinitions = await api.skillDefinitions();
|
||||
const skillDefinitions = await api.skill();
|
||||
|
||||
export function CrewSkillManager({
|
||||
skillLevels,
|
||||
|
||||
@@ -30,7 +30,7 @@ export const compositeStatsKeysOptions = compositeStatsKeys.map((value) => ({
|
||||
}));
|
||||
|
||||
const [tankDefinitions, averageDefinitions] = await Promise.all([
|
||||
api.tankDefinitions(),
|
||||
api.tanks(),
|
||||
|
||||
awaitableAverageDefinitions,
|
||||
]);
|
||||
|
||||
@@ -0,0 +1,55 @@
|
||||
.error-display {
|
||||
z-index: 1;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
|
||||
gap: var(--space-4);
|
||||
padding: var(--space-4);
|
||||
box-sizing: border-box;
|
||||
|
||||
position: fixed;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 100dvw;
|
||||
height: 100dvh;
|
||||
|
||||
text-align: center;
|
||||
background-color: var(--gray-1);
|
||||
|
||||
.info {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
flex-direction: column;
|
||||
|
||||
gap: var(--space-3);
|
||||
}
|
||||
|
||||
.error {
|
||||
text-align: left;
|
||||
overflow: hidden;
|
||||
position: relative;
|
||||
box-sizing: border-box;
|
||||
|
||||
max-width: min(100%, var(--page-width));
|
||||
|
||||
.cover {
|
||||
position: absolute;
|
||||
right: 0;
|
||||
top: 0;
|
||||
|
||||
width: 25%;
|
||||
height: 100%;
|
||||
|
||||
background: linear-gradient(90deg, transparent, var(--gray-1));
|
||||
}
|
||||
}
|
||||
|
||||
.options {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
justify-content: center;
|
||||
gap: var(--space-3);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,84 @@
|
||||
import { useState, type ReactNode } from "react";
|
||||
import {
|
||||
ErrorBoundary,
|
||||
getErrorMessage,
|
||||
type FallbackProps,
|
||||
} from "react-error-boundary";
|
||||
import { discordLink } from "../../config/socials";
|
||||
import { Button } from "../Button";
|
||||
import { Code } from "../Code";
|
||||
import { Heading } from "../Heading";
|
||||
import { Link } from "../Link";
|
||||
import { Text } from "../Text";
|
||||
import styles from "./index.module.css";
|
||||
|
||||
interface Props {
|
||||
children: ReactNode;
|
||||
}
|
||||
|
||||
export function ErrorWrapper({ children }: Props) {
|
||||
return (
|
||||
<ErrorBoundary fallbackRender={(props) => <Fallback {...props} />}>
|
||||
{children}
|
||||
</ErrorBoundary>
|
||||
);
|
||||
}
|
||||
|
||||
function Fallback({ error, resetErrorBoundary }: FallbackProps) {
|
||||
const [showError, setShowError] = useState(false);
|
||||
|
||||
let body: string | undefined;
|
||||
|
||||
if (error instanceof Error) {
|
||||
body = error.stack || getErrorMessage(error);
|
||||
} else {
|
||||
body = getErrorMessage(error);
|
||||
}
|
||||
|
||||
body ??= "No error message";
|
||||
|
||||
return (
|
||||
<div className={styles["error-display"]}>
|
||||
<div className={styles.info}>
|
||||
<Heading size="3">BlitzKit crashed</Heading>
|
||||
<Text lowContrast>Sorry about that! You have a couple of options.</Text>
|
||||
</div>
|
||||
|
||||
{showError && (
|
||||
<Code variant="solid" className={styles.error}>
|
||||
{body}
|
||||
<div className={styles.cover} />
|
||||
</Code>
|
||||
)}
|
||||
|
||||
<div className={styles.options}>
|
||||
{!showError && (
|
||||
<Button variant="outline" onClick={() => setShowError(true)}>
|
||||
View error
|
||||
</Button>
|
||||
)}
|
||||
|
||||
{showError && (
|
||||
<Button
|
||||
variant="outline"
|
||||
onClick={() => navigator.clipboard.writeText(body)}
|
||||
>
|
||||
Copy error
|
||||
</Button>
|
||||
)}
|
||||
|
||||
<Link href="" underline="never">
|
||||
<Button variant="outline">Hard reload</Button>
|
||||
</Link>
|
||||
|
||||
<Button variant="outline" onClick={resetErrorBoundary}>
|
||||
Soft reset
|
||||
</Button>
|
||||
|
||||
<Link href={discordLink} target="_blank" underline="never">
|
||||
<Button>Discord server</Button>
|
||||
</Link>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@@ -11,7 +11,7 @@ export interface Props {
|
||||
locale: string;
|
||||
}
|
||||
|
||||
const gameDefinitions = await api.gameDefinitions();
|
||||
const gameDefinitions = await api.game();
|
||||
const environment = assertSecret(import.meta.env.PUBLIC_ENVIRONMENT);
|
||||
const { locale } = Astro.props;
|
||||
const strings = getStrings(locale);
|
||||
|
||||
@@ -9,8 +9,8 @@ import { Tankopedia } from "../../stores/tankopedia";
|
||||
import "./index.css";
|
||||
|
||||
const [modelDefinitions, provisionDefinitions] = await Promise.all([
|
||||
api.modelDefinitions(),
|
||||
api.provisionDefinitions(),
|
||||
api.models(),
|
||||
api.provisions(),
|
||||
]);
|
||||
|
||||
export function GuessBackground() {
|
||||
|
||||
@@ -40,7 +40,7 @@ const { go } = fuzzysort;
|
||||
|
||||
const [tankNames, tankDefinitions] = await Promise.all([
|
||||
awaitableTankNames,
|
||||
api.tankDefinitions(),
|
||||
api.tanks(),
|
||||
]);
|
||||
|
||||
const ids = Object.keys(tankDefinitions.tanks);
|
||||
|
||||
@@ -11,7 +11,7 @@ import {
|
||||
import { TankCard } from "./TankCard";
|
||||
|
||||
const [tankDefinitions, popularTanks] = await Promise.all([
|
||||
api.tankDefinitions(),
|
||||
api.tanks(),
|
||||
awaitablePopularTanks,
|
||||
]);
|
||||
|
||||
|
||||
@@ -12,7 +12,7 @@ import { controlsEnabledEvent } from "../../../core/controlsEnabled";
|
||||
import { useModel } from "../../../hooks/useModel";
|
||||
import { Mixer } from "../../../stores/mixer";
|
||||
|
||||
const modelDefinitions = await api.modelDefinitions();
|
||||
const modelDefinitions = await api.models();
|
||||
|
||||
export function Model() {
|
||||
const canvas = useThree((state) => state.gl.domElement);
|
||||
|
||||
@@ -13,7 +13,7 @@ interface ConsumableButtonProps extends TankComponentButtonProps {
|
||||
cooldown?: number;
|
||||
}
|
||||
|
||||
const consumableDefinitions = await api.consumableDefinitions();
|
||||
const consumableDefinitions = await api.consumables();
|
||||
|
||||
export function ConsumableButton({
|
||||
consumable,
|
||||
|
||||
@@ -8,7 +8,7 @@ interface EquipmentButtonProps extends TankComponentButtonProps {
|
||||
equipment: number;
|
||||
}
|
||||
|
||||
const equipmentDefinitions = await api.equipmentDefinitions();
|
||||
const equipmentDefinitions = await api.equipment();
|
||||
|
||||
export function EquipmentButton({ equipment, ...props }: EquipmentButtonProps) {
|
||||
const { unwrap } = useLocale();
|
||||
|
||||
@@ -8,7 +8,7 @@ interface ProvisionButtonProps extends TankComponentButtonProps {
|
||||
provision: number;
|
||||
}
|
||||
|
||||
const provisionDefinitions = await api.provisionDefinitions();
|
||||
const provisionDefinitions = await api.provisions();
|
||||
|
||||
export function ProvisionButton({ provision, ...props }: ProvisionButtonProps) {
|
||||
const { unwrap } = useLocale();
|
||||
|
||||
@@ -27,7 +27,7 @@ const PREVIEW_COUNT = 10;
|
||||
const DEFAULT_LOADED_ROWS = 25;
|
||||
|
||||
const [tankDefinitions, averageDefinitions] = await Promise.all([
|
||||
api.tankDefinitions(),
|
||||
api.tanks(),
|
||||
awaitableAverageDefinitions,
|
||||
]);
|
||||
|
||||
|
||||
@@ -22,7 +22,7 @@ import type { MaybeSkeletonComponentProps } from "../types/maybeSkeletonComponen
|
||||
import { LinkI18n } from "./LinkI18n";
|
||||
import { TankSearchFilters } from "./TankSearchFilters";
|
||||
|
||||
const tankDefinitions = await api.tankDefinitions();
|
||||
const tankDefinitions = await api.tanks();
|
||||
|
||||
const POOL_HEIGHT = "16rem";
|
||||
|
||||
|
||||
@@ -14,7 +14,7 @@ interface Props extends PlaylistEntry {
|
||||
index: number;
|
||||
}
|
||||
|
||||
const tankDefinitions = await api.tankDefinitions();
|
||||
const tankDefinitions = await api.tanks();
|
||||
|
||||
export const PlaylistTankEntry = memo<Props>(
|
||||
({ id, checked, then, now, index }) => {
|
||||
|
||||
@@ -9,7 +9,7 @@ interface ProvisionsManagerProps {
|
||||
onChange?: (provisions: number[]) => void;
|
||||
}
|
||||
|
||||
const provisionDefinitions = await api.provisionDefinitions();
|
||||
const provisionDefinitions = await api.provisions();
|
||||
|
||||
export function ProvisionsManager({
|
||||
provisions,
|
||||
|
||||
@@ -11,7 +11,7 @@ import { TankCardWrapper } from "../TankCardWrapper";
|
||||
import { Text } from "../Text";
|
||||
import styles from "./index.module.css";
|
||||
|
||||
const tankDefinitions = await api.tankDefinitions();
|
||||
const tankDefinitions = await api.tanks();
|
||||
|
||||
export function RecentlyViewedTanks() {
|
||||
const filters = TankFilters.use();
|
||||
|
||||
@@ -21,7 +21,7 @@ type TankCardProps = {
|
||||
compact?: boolean;
|
||||
};
|
||||
|
||||
const tankDefinitions = await api.tankDefinitions();
|
||||
const tankDefinitions = await api.tanks();
|
||||
|
||||
export const TankCard = (props: MaybeSkeletonComponentProps<TankCardProps>) => {
|
||||
if (props.skeleton) {
|
||||
|
||||
@@ -15,7 +15,7 @@ interface TankSearchCardProps {
|
||||
onSelect?: (tank: TankDefinition) => void;
|
||||
}
|
||||
|
||||
const modelDefinitions = await api.modelDefinitions();
|
||||
const modelDefinitions = await api.models();
|
||||
|
||||
export function TankSearchCard({ tank, onSelect }: TankSearchCardProps) {
|
||||
const by = TankSort.use((state) => state.by);
|
||||
|
||||
@@ -45,9 +45,9 @@ export type TankSearchProps = MaybeSkeletonComponentProps & {
|
||||
|
||||
const [gameDefinitions, modelDefinitions, tankDefinitions, tankNames] =
|
||||
await Promise.all([
|
||||
api.gameDefinitions(),
|
||||
api.modelDefinitions(),
|
||||
api.tankDefinitions(),
|
||||
api.game(),
|
||||
api.models(),
|
||||
api.tanks(),
|
||||
awaitableTankNames,
|
||||
]);
|
||||
|
||||
|
||||
@@ -1,19 +1,19 @@
|
||||
import {
|
||||
alias,
|
||||
GunDefinition,
|
||||
ShellType,
|
||||
TANK_CLASSES,
|
||||
TANK_TYPES,
|
||||
TankType,
|
||||
TIER_ROMAN_NUMERALS,
|
||||
alias,
|
||||
GunDefinition,
|
||||
ShellType,
|
||||
TANK_CLASSES,
|
||||
TANK_TYPES,
|
||||
TankType,
|
||||
TIER_ROMAN_NUMERALS,
|
||||
} from "@blitzkit/core";
|
||||
import { literals } from "@blitzkit/i18n";
|
||||
import locales from "@blitzkit/i18n/locales.json";
|
||||
import {
|
||||
LockClosedIcon,
|
||||
LockOpen2Icon,
|
||||
ResetIcon,
|
||||
TrashIcon,
|
||||
LockClosedIcon,
|
||||
LockOpen2Icon,
|
||||
ResetIcon,
|
||||
TrashIcon,
|
||||
} from "@radix-ui/react-icons";
|
||||
import { times } from "lodash-es";
|
||||
import { Fragment, type ComponentProps, type ReactNode } from "react";
|
||||
@@ -37,10 +37,10 @@ import { Text } from "../Text";
|
||||
import { Tooltip } from "../Tooltip";
|
||||
import styles from "./index.module.css";
|
||||
|
||||
const gameDefinitions = await api.gameDefinitions();
|
||||
const consumableDefinitions = await api.consumableDefinitions();
|
||||
const provisionDefinitions = await api.provisionDefinitions();
|
||||
const tankDefinitions = await api.tankDefinitions();
|
||||
const gameDefinitions = await api.game();
|
||||
const consumableDefinitions = await api.consumables();
|
||||
const provisionDefinitions = await api.provisions();
|
||||
const tankDefinitions = await api.tanks();
|
||||
|
||||
const gameModeRoleSets: Record<number, Set<number>> = {};
|
||||
|
||||
|
||||
@@ -10,7 +10,7 @@ import { AesonPlug } from "../AesonPlug";
|
||||
import { ExperimentIcon } from "../ExperimentIcon";
|
||||
import { MAX_RECENTLY_VIEWED } from "../TankSearch/constants";
|
||||
|
||||
const tankDefinitions = await api.tankDefinitions();
|
||||
const tankDefinitions = await api.tanks();
|
||||
|
||||
export function CalloutsSection() {
|
||||
const tank = Duel.use((state) => state.protagonist.tank);
|
||||
|
||||
+1
-1
@@ -11,7 +11,7 @@ import { InfoWithDelta } from "./InfoWithDelta";
|
||||
import { StatsTableWrapper } from "./StatsTableWrapper";
|
||||
import type { StatsAcceptorProps } from "./TraverseVisualizer";
|
||||
|
||||
const provisionDefinitions = await api.provisionDefinitions();
|
||||
const provisionDefinitions = await api.provisions();
|
||||
|
||||
export function Crew({ stats }: StatsAcceptorProps) {
|
||||
const tank = Duel.use((state) => state.protagonist.tank);
|
||||
|
||||
+1
-1
@@ -9,7 +9,7 @@ import {
|
||||
import { Duel } from "../../../../../../../../stores/duel";
|
||||
import { ModelChunk } from "./ModelChunk";
|
||||
|
||||
const modelDefinitions = await api.modelDefinitions();
|
||||
const modelDefinitions = await api.models();
|
||||
|
||||
export function CanvasContent() {
|
||||
const hullWrapper = useRef<Group>(null);
|
||||
|
||||
+1
-1
@@ -5,7 +5,7 @@ import { jsxTree } from "../../../../../../../../core/blitzkit/jsxTree";
|
||||
import { useModel } from "../../../../../../../../hooks/useModel";
|
||||
import { Duel } from "../../../../../../../../stores/duel";
|
||||
|
||||
const modelDefinitions = await api.modelDefinitions();
|
||||
const modelDefinitions = await api.models();
|
||||
|
||||
const surfaceMaterial: Record<Props["only"], MeshBasicMaterial> = {
|
||||
gun: new MeshBasicMaterial({
|
||||
|
||||
+1
-1
@@ -20,7 +20,7 @@ import { FlexibilityCanvas } from "./components/FlexibilityCanvas";
|
||||
|
||||
const ANGLE_COEFFICIENT = 1 / 10;
|
||||
|
||||
const modelDefinition = await api.modelDefinitions();
|
||||
const modelDefinition = await api.models();
|
||||
|
||||
function mag(x: number) {
|
||||
return (1 / Math.PI) * Math.atan(ANGLE_COEFFICIENT * x) + 1 / 2;
|
||||
|
||||
+5
-5
@@ -37,11 +37,11 @@ const [
|
||||
modelDefinitions,
|
||||
skillDefinitions,
|
||||
] = await Promise.all([
|
||||
api.tankDefinitions(),
|
||||
api.provisionDefinitions(),
|
||||
api.equipmentDefinitions(),
|
||||
api.modelDefinitions(),
|
||||
api.skillDefinitions(),
|
||||
api.tanks(),
|
||||
api.provisions(),
|
||||
api.equipment(),
|
||||
api.models(),
|
||||
api.skill(),
|
||||
]);
|
||||
|
||||
export const InfoWithDelta = memo<InfoWithDeltaProps>(
|
||||
|
||||
+2
-2
@@ -15,8 +15,8 @@ import { Maneuverability } from "./components/Maneuverability";
|
||||
import { Survivability } from "./components/Survivability";
|
||||
|
||||
const [equipmentDefinitions, provisionDefinitions] = await Promise.all([
|
||||
api.equipmentDefinitions(),
|
||||
api.provisionDefinitions(),
|
||||
api.equipment(),
|
||||
api.provisions(),
|
||||
]);
|
||||
|
||||
export function Characteristics({ skeleton }: MaybeSkeletonComponentProps) {
|
||||
|
||||
+1
-1
@@ -15,7 +15,7 @@ import { Duel } from "../../../../stores/duel";
|
||||
import { ConsumablesManager } from "../../../ConsumablesManager";
|
||||
import { ConfigurationChildWrapper } from "./ConfigurationChildWrapper";
|
||||
|
||||
const consumableDefinitions = await api.consumableDefinitions();
|
||||
const consumableDefinitions = await api.consumables();
|
||||
|
||||
export function Consumables() {
|
||||
const protagonist = Duel.use((state) => state.protagonist);
|
||||
|
||||
+1
-1
@@ -5,7 +5,7 @@ import { Duel } from "../../../../stores/duel";
|
||||
import { EquipmentManager } from "../../../EquipmentManager";
|
||||
import { ConfigurationChildWrapper } from "./ConfigurationChildWrapper";
|
||||
|
||||
const equipmentDefinitions = await api.equipmentDefinitions();
|
||||
const equipmentDefinitions = await api.equipment();
|
||||
|
||||
export function Equipment() {
|
||||
const protagonist = Duel.use((state) => state.protagonist);
|
||||
|
||||
+1
-1
@@ -156,7 +156,7 @@ function ModuleButton({
|
||||
return <Tooltip content={tooltip}>{node}</Tooltip>;
|
||||
}
|
||||
|
||||
const tankDefinitions = await api.tankDefinitions();
|
||||
const tankDefinitions = await api.tanks();
|
||||
|
||||
export function Modules() {
|
||||
const tank = Duel.use((state) => state.protagonist.tank);
|
||||
|
||||
+1
-1
@@ -6,7 +6,7 @@ import { Duel } from "../../../../stores/duel";
|
||||
import { ProvisionsManager } from "../../../ProvisionsManager";
|
||||
import { ConfigurationChildWrapper } from "./ConfigurationChildWrapper";
|
||||
|
||||
const provisionDefinitions = await api.provisionDefinitions();
|
||||
const provisionDefinitions = await api.provisions();
|
||||
|
||||
export function Provisions() {
|
||||
const { tank, gun } = Duel.use((state) => state.protagonist);
|
||||
|
||||
@@ -5,11 +5,7 @@ import { useLocale } from "../../hooks/useLocale";
|
||||
import { Duel } from "../../stores/duel";
|
||||
|
||||
const [gameDefinitions, consumableDefinitions, provisionDefinitions] =
|
||||
await Promise.all([
|
||||
api.gameDefinitions(),
|
||||
api.consumableDefinitions(),
|
||||
api.provisionDefinitions(),
|
||||
]);
|
||||
await Promise.all([api.game(), api.consumables(), api.provisions()]);
|
||||
|
||||
export function GameModeSection() {
|
||||
const { unwrap, strings } = useLocale();
|
||||
|
||||
+1
-1
@@ -21,7 +21,7 @@ const poseDistances: Record<Pose, number> = {
|
||||
|
||||
const inspectModeInitialPosition = new Vector3(-8, 2, -13);
|
||||
|
||||
const modelDefinitions = await api.modelDefinitions();
|
||||
const modelDefinitions = await api.models();
|
||||
|
||||
interface ControlsProps {
|
||||
autoRotate?: boolean;
|
||||
|
||||
+1
-1
@@ -5,7 +5,7 @@ import { api } from "../../../../../../core/blitzkit/api";
|
||||
import { modelTransformEvent } from "../../../../../../core/blitzkit/modelTransform";
|
||||
import { Duel } from "../../../../../../stores/duel";
|
||||
|
||||
const modelDefinitions = await api.modelDefinitions();
|
||||
const modelDefinitions = await api.models();
|
||||
|
||||
export function InitialAligner() {
|
||||
const tank = Duel.use((state) => state.protagonist.tank);
|
||||
|
||||
@@ -12,7 +12,7 @@ import { Options } from "./components/Options";
|
||||
import { TankSandbox } from "./components/TankSandbox";
|
||||
import { Title } from "./components/TankSandbox/Title";
|
||||
|
||||
const tankDefinitions = await api.tankDefinitions();
|
||||
const tankDefinitions = await api.tanks();
|
||||
|
||||
export function HeroSection({ skeleton }: MaybeSkeletonComponentProps) {
|
||||
const equalize = Duel.use((state) => state.equalize);
|
||||
|
||||
@@ -15,7 +15,7 @@ type NodeProps = MaybeSkeletonComponentProps & {
|
||||
};
|
||||
|
||||
const [tankDefinitions, averageDefinitions] = await Promise.all([
|
||||
api.tankDefinitions(),
|
||||
api.tanks(),
|
||||
awaitableAverageDefinitions,
|
||||
]);
|
||||
|
||||
|
||||
@@ -13,7 +13,7 @@ import { Node } from "./components/Node";
|
||||
|
||||
type Line = number[];
|
||||
|
||||
const tankDefinitions = await api.tankDefinitions();
|
||||
const tankDefinitions = await api.tanks();
|
||||
|
||||
export const XP_MULTIPLIERS = [1, 2, 3, 4, 5, 10];
|
||||
|
||||
|
||||
@@ -10,7 +10,7 @@ interface TierListRowProps {
|
||||
index: number;
|
||||
}
|
||||
|
||||
const tankDefinitions = await api.tankDefinitions();
|
||||
const tankDefinitions = await api.tanks();
|
||||
|
||||
export function TierListRow({ index }: TierListRowProps) {
|
||||
const tanks = TierList.use((state) => state.rows[index].tanks);
|
||||
|
||||
@@ -6,13 +6,13 @@ import { api } from "../../core/blitzkit/api";
|
||||
import { filterTanks } from "../../core/blitzkit/filterTanks";
|
||||
import { TankFilters } from "../../stores/tankFilters";
|
||||
import { TierList } from "../../stores/tierList";
|
||||
import { TankCardWrapper } from "../TankCardWrapper";
|
||||
import { TankCardSkeleton } from "../TankCardSkeleton";
|
||||
import { TankCardWrapper } from "../TankCardWrapper";
|
||||
import { TierListTile } from "./Tile";
|
||||
|
||||
const [tankDefinitions, gameDefinitions] = await Promise.all([
|
||||
api.tankDefinitions(),
|
||||
api.gameDefinitions(),
|
||||
api.tanks(),
|
||||
api.game(),
|
||||
]);
|
||||
|
||||
const tanks = Object.values(tankDefinitions.tanks);
|
||||
|
||||
@@ -3,7 +3,7 @@ import { api } from "../../core/blitzkit/api";
|
||||
import { generateTierListParams } from "../../core/blitzkit/generateTierListParams";
|
||||
import { TierList } from "../../stores/tierList";
|
||||
|
||||
const tankDefinitions = await api.tankDefinitions();
|
||||
const tankDefinitions = await api.tanks();
|
||||
|
||||
export function URLManager() {
|
||||
const rows = TierList.use((state) => state.rows);
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
export const discordLink = "https://discord.gg/nDt7AjGJQH";
|
||||
@@ -1,3 +1 @@
|
||||
import { fetchAverageDefinitions } from '@blitzkit/core';
|
||||
|
||||
export const awaitableAverageDefinitions = fetchAverageDefinitions();
|
||||
export const awaitableAverageDefinitions = fetchAverage();
|
||||
@@ -1,4 +1 @@
|
||||
import { fetchDiscoveredIdsDefinitions } from '@blitzkit/core';
|
||||
|
||||
export const awaitableDiscoveredIdsDefinitions =
|
||||
fetchDiscoveredIdsDefinitions();
|
||||
export const awaitableDiscoveredIdsDefinitions = fetchDiscoveredIds();
|
||||
@@ -1,20 +1,4 @@
|
||||
import type { BlitzKitAPI } from "@blitzkit/core/src/blitzkit/api/base";
|
||||
import { createDynamicAPI } from "@blitzkit/core";
|
||||
import { vfs } from "./vfs";
|
||||
|
||||
let _api: BlitzKitAPI;
|
||||
|
||||
if (import.meta.env.SSR) {
|
||||
const { ServerBlitzKitAPI } = await import(
|
||||
"@blitzkit/core/src/blitzkit/api/server/index"
|
||||
);
|
||||
const { vfs } = await import("./vfs");
|
||||
|
||||
_api = await new ServerBlitzKitAPI(vfs).init();
|
||||
} else {
|
||||
const { ClientBlitzKitAPI } = await import(
|
||||
"@blitzkit/core/src/blitzkit/api/client"
|
||||
);
|
||||
|
||||
_api = new ClientBlitzKitAPI();
|
||||
}
|
||||
|
||||
export const api = _api;
|
||||
export const api = await createDynamicAPI(vfs);
|
||||
@@ -1,7 +1,7 @@
|
||||
import { api } from "./api";
|
||||
|
||||
const tankDefinitions = await api.tankDefinitions();
|
||||
const modelDefinitions = await api.modelDefinitions();
|
||||
const tankDefinitions = await api.tanks();
|
||||
const modelDefinitions = await api.models();
|
||||
|
||||
const tanks = Object.values(tankDefinitions.tanks).filter((tank) => {
|
||||
const tankModel = modelDefinitions.models[tank.id];
|
||||
|
||||
@@ -6,9 +6,9 @@ import { api } from "./api";
|
||||
|
||||
const SHELLS = times(3, (index) => index);
|
||||
|
||||
const consumableDefinitions = await api.consumableDefinitions();
|
||||
const provisionDefinitions = await api.provisionDefinitions();
|
||||
const gameDefinitions = await api.gameDefinitions();
|
||||
const consumableDefinitions = await api.consumables();
|
||||
const provisionDefinitions = await api.provisions();
|
||||
const gameDefinitions = await api.game();
|
||||
|
||||
export async function filterTank(
|
||||
filters: TankFilters,
|
||||
|
||||
@@ -10,7 +10,7 @@ import { TankFilters } from "../../stores/tankFilters";
|
||||
import { api } from "./api";
|
||||
import { filterTanks } from "./filterTanks";
|
||||
|
||||
const tankDefinitions = await api.tankDefinitions();
|
||||
const tankDefinitions = await api.tanks();
|
||||
const tanks = Object.values(tankDefinitions.tanks);
|
||||
|
||||
export async function generatePlaylist() {
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import type { EquipmentMatrix } from "../../stores/duel";
|
||||
import { api } from "./api";
|
||||
|
||||
const equipmentDefinitions = await api.equipmentDefinitions();
|
||||
const equipmentDefinitions = await api.equipment();
|
||||
|
||||
export function hasEquipment(
|
||||
id: number,
|
||||
|
||||
@@ -0,0 +1,14 @@
|
||||
import type { ReactNode } from "react";
|
||||
import { ErrorWrapper } from "../components/ErrorWrapper";
|
||||
|
||||
export function withErrorWrapper<Props extends object>(
|
||||
Component: (props: Props) => ReactNode,
|
||||
) {
|
||||
return function (props: Props) {
|
||||
return (
|
||||
<ErrorWrapper>
|
||||
<Component {...props} />
|
||||
</ErrorWrapper>
|
||||
);
|
||||
};
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
import type { ReactNode } from "react";
|
||||
import { LocaleProvider } from "../hooks/useLocale";
|
||||
|
||||
interface WithLocaleProps {
|
||||
locale: string;
|
||||
}
|
||||
|
||||
export function withLocale<Props extends object>(
|
||||
Component: (props: Props) => ReactNode,
|
||||
) {
|
||||
return function ({ locale, ...props }: Props & WithLocaleProps) {
|
||||
return (
|
||||
<LocaleProvider locale={locale}>
|
||||
<Component {...(props as Props)} />
|
||||
</LocaleProvider>
|
||||
);
|
||||
};
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
import { use } from "react";
|
||||
|
||||
const cache = new Map<string, Promise<unknown>>();
|
||||
|
||||
export function useAwait<Type>(
|
||||
creator: () => Promise<Type>,
|
||||
discriminator: string,
|
||||
) {
|
||||
let promise;
|
||||
|
||||
if (cache.has(discriminator)) {
|
||||
promise = cache.get(discriminator) as Promise<Type>;
|
||||
} else {
|
||||
promise = creator();
|
||||
cache.set(discriminator, promise);
|
||||
}
|
||||
|
||||
return use(promise);
|
||||
}
|
||||
@@ -9,7 +9,7 @@ export enum UseEccentricityMode {
|
||||
Class,
|
||||
}
|
||||
|
||||
const tankDefinitions = await api.tankDefinitions();
|
||||
const tankDefinitions = await api.tanks();
|
||||
|
||||
export function useEccentricity(mode: UseEccentricityMode) {
|
||||
const tank = Duel.use((state) => state.protagonist.tank);
|
||||
|
||||
@@ -2,7 +2,7 @@ import { useMemo } from "react";
|
||||
import { api } from "../core/blitzkit/api";
|
||||
import { Duel } from "../stores/duel";
|
||||
|
||||
const equipmentDefinitions = await api.equipmentDefinitions();
|
||||
const equipmentDefinitions = await api.equipment();
|
||||
|
||||
export function useEquipment(id: number, antagonist = false) {
|
||||
const member = Duel.use(
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { api } from "../core/blitzkit/api";
|
||||
|
||||
const equipmentDefinitions = await api.equipmentDefinitions();
|
||||
const equipmentDefinitions = await api.equipment();
|
||||
|
||||
export function useEquipmentPreset(preset: string) {
|
||||
return equipmentDefinitions.presets[preset];
|
||||
|
||||
@@ -4,7 +4,7 @@ import { api } from "../../../core/blitzkit/api";
|
||||
export { getStaticPaths } from "../_index";
|
||||
|
||||
export async function GET() {
|
||||
const definitions = await api.camouflageDefinitions();
|
||||
const definitions = await api.camouflage();
|
||||
const bytes = CamouflageDefinitions.encode(definitions).finish();
|
||||
|
||||
return new Response(bytes);
|
||||
|
||||
@@ -4,7 +4,7 @@ import { api } from "../../../core/blitzkit/api";
|
||||
export { getStaticPaths } from "../_index";
|
||||
|
||||
export async function GET() {
|
||||
const definitions = await api.consumableDefinitions();
|
||||
const definitions = await api.consumables();
|
||||
const bytes = ConsumableDefinitions.encode(definitions).finish();
|
||||
|
||||
return new Response(bytes);
|
||||
|
||||
@@ -4,7 +4,7 @@ import { api } from "../../../core/blitzkit/api";
|
||||
export { getStaticPaths } from "../_index";
|
||||
|
||||
export async function GET() {
|
||||
const definitions = await api.equipmentDefinitions();
|
||||
const definitions = await api.equipment();
|
||||
const bytes = EquipmentDefinitions.encode(definitions).finish();
|
||||
|
||||
return new Response(bytes);
|
||||
|
||||
@@ -4,7 +4,7 @@ import { api } from "../../../core/blitzkit/api";
|
||||
export { getStaticPaths } from "../_index";
|
||||
|
||||
export async function GET() {
|
||||
const definitions = await api.galleryDefinitions();
|
||||
const definitions = await api.gallery();
|
||||
const bytes = Gallery.encode(definitions).finish();
|
||||
|
||||
return new Response(bytes);
|
||||
|
||||
@@ -4,7 +4,7 @@ import { api } from "../../../core/blitzkit/api";
|
||||
export { getStaticPaths } from "../_index";
|
||||
|
||||
export async function GET() {
|
||||
const definitions = await api.gameDefinitions();
|
||||
const definitions = await api.game();
|
||||
const bytes = GameDefinitions.encode(definitions).finish();
|
||||
|
||||
return new Response(bytes);
|
||||
|
||||
@@ -4,7 +4,7 @@ import { api } from "../../../core/blitzkit/api";
|
||||
export { getStaticPaths } from "../_index";
|
||||
|
||||
export async function GET() {
|
||||
const definitions = await api.mapDefinitions();
|
||||
const definitions = await api.map();
|
||||
const bytes = MapDefinitions.encode(definitions).finish();
|
||||
|
||||
return new Response(bytes);
|
||||
|
||||
@@ -4,7 +4,7 @@ import { api } from "../../../core/blitzkit/api";
|
||||
export { getStaticPaths } from "../_index";
|
||||
|
||||
export async function GET() {
|
||||
const definitions = await api.modelDefinitions();
|
||||
const definitions = await api.models();
|
||||
const bytes = ModelDefinitions.encode(definitions).finish();
|
||||
|
||||
return new Response(bytes);
|
||||
|
||||
@@ -4,7 +4,7 @@ import { api } from "../../../core/blitzkit/api";
|
||||
export { getStaticPaths } from "../_index";
|
||||
|
||||
export async function GET() {
|
||||
const definitions = await api.provisionDefinitions();
|
||||
const definitions = await api.provisions();
|
||||
const bytes = ProvisionDefinitions.encode(definitions).finish();
|
||||
|
||||
return new Response(bytes);
|
||||
|
||||
@@ -4,7 +4,7 @@ import { api } from "../../../core/blitzkit/api";
|
||||
export { getStaticPaths } from "../_index";
|
||||
|
||||
export async function GET() {
|
||||
const definitions = await api.skillDefinitions();
|
||||
const definitions = await api.skill();
|
||||
const bytes = SkillDefinitions.encode(definitions).finish();
|
||||
|
||||
return new Response(bytes);
|
||||
|
||||
@@ -4,7 +4,7 @@ import { api } from "../../../core/blitzkit/api";
|
||||
export { getStaticPaths } from "../_index";
|
||||
|
||||
export async function GET() {
|
||||
const definitions = await api.tankDefinitions();
|
||||
const definitions = await api.tanks();
|
||||
const bytes = TankDefinitions.encode(definitions).finish();
|
||||
|
||||
return new Response(bytes);
|
||||
|
||||
@@ -3,7 +3,7 @@ import { mixStaticPaths } from "../../../../core/blitzkit/mixStaticPaths";
|
||||
import { getStaticPaths as _getStaticPaths } from "../../_index";
|
||||
|
||||
export const getStaticPaths = mixStaticPaths(_getStaticPaths, async () => {
|
||||
const tanks = await api.tankDefinitions();
|
||||
const tanks = await api.tanks();
|
||||
|
||||
return Object.values(tanks.tanks).map((tank) => ({
|
||||
params: { id: tank.id },
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
import { GalleryList } from "../../../../components/Gallery/List";
|
||||
import { GallerySearch } from "../../../../components/Gallery/Search";
|
||||
import { PageWrapper } from "../../../../components/PageWrapper";
|
||||
import { AvatarsSearch } from "../../../../components/Avatars/Search";
|
||||
import { AvatarsList } from "../../../../components/AvatarsList";
|
||||
import {
|
||||
LocaleProvider,
|
||||
type LocaleAcceptorProps,
|
||||
@@ -20,9 +19,9 @@ export function Page({
|
||||
|
||||
function Content({ skeleton }: MaybeSkeletonComponentProps) {
|
||||
return (
|
||||
<PageWrapper maxWidth="80rem" color="gold">
|
||||
<GallerySearch skeleton={skeleton} />
|
||||
<GalleryList skeleton={skeleton} />
|
||||
</PageWrapper>
|
||||
<>
|
||||
<AvatarsSearch skeleton={skeleton} />
|
||||
<AvatarsList skeleton={skeleton} />
|
||||
</>
|
||||
);
|
||||
}
|
||||
@@ -1,7 +1,8 @@
|
||||
---
|
||||
import { Section } from "../../../../components/Section";
|
||||
import ToolBanner from "../../../../components/ToolBanner.astro";
|
||||
import { tools } from "../../../../constants/tools";
|
||||
import ToolLayout from "../../../../layouts/ToolLayout.astro";
|
||||
import type { getStaticPaths } from "../index.astro";
|
||||
import BaseLayout from "../../../../layouts/BaseLayout.astro";
|
||||
import { Page } from "./_index";
|
||||
|
||||
export { getStaticPaths } from "../index.astro";
|
||||
@@ -9,8 +10,12 @@ export { getStaticPaths } from "../index.astro";
|
||||
const { locale } = Astro.props;
|
||||
---
|
||||
|
||||
<ToolLayout {locale} tool={tools.gallery}>
|
||||
<Page {locale} client:only="react">
|
||||
<Page {locale} skeleton slot="fallback" />
|
||||
</Page>
|
||||
</ToolLayout>
|
||||
<BaseLayout {locale} accent="purple">
|
||||
<ToolBanner {locale} tool={tools.avatars} slot="pre-app" />
|
||||
|
||||
<Section>
|
||||
<Page {locale} client:only="react">
|
||||
<Page {locale} skeleton slot="fallback" />
|
||||
</Page>
|
||||
</Section>
|
||||
</BaseLayout>
|
||||
@@ -20,11 +20,11 @@ const [
|
||||
skillDefinitions,
|
||||
tankDefinitions,
|
||||
] = await Promise.all([
|
||||
api.modelDefinitions(),
|
||||
api.equipmentDefinitions(),
|
||||
api.provisionDefinitions(),
|
||||
api.skillDefinitions(),
|
||||
api.tankDefinitions(),
|
||||
api.models(),
|
||||
api.equipment(),
|
||||
api.provisions(),
|
||||
api.skill(),
|
||||
api.tanks(),
|
||||
]);
|
||||
|
||||
export function Page({ locale }: LocaleAcceptorProps) {
|
||||
|
||||
@@ -17,8 +17,8 @@ import { Tankopedia } from "../../../../stores/tankopedia";
|
||||
import type { MaybeSkeletonComponentProps } from "../../../../types/maybeSkeletonComponentProps";
|
||||
|
||||
const [tankDefinitions, modelDefinitions] = await Promise.all([
|
||||
api.tankDefinitions(),
|
||||
api.modelDefinitions(),
|
||||
api.tanks(),
|
||||
api.models(),
|
||||
]);
|
||||
|
||||
const ids = Object.keys(tankDefinitions.tanks);
|
||||
|
||||
@@ -35,10 +35,8 @@ import { Mixer } from "../../../../stores/mixer";
|
||||
import { Tankopedia } from "../../../../stores/tankopedia";
|
||||
import type { MaybeSkeletonComponentProps } from "../../../../types/maybeSkeletonComponentProps";
|
||||
|
||||
const modelDefinition = await api
|
||||
.modelDefinitions()
|
||||
.then(({ models }) => models[1]);
|
||||
const tankDefinitions = await api.tankDefinitions();
|
||||
const modelDefinition = await api.models().then(({ models }) => models[1]);
|
||||
const tankDefinitions = await api.tanks();
|
||||
|
||||
export function Page({
|
||||
locale,
|
||||
|
||||
@@ -47,7 +47,7 @@ import {
|
||||
import { Session, type SessionTracking } from "../../../../stores/session";
|
||||
|
||||
const [tankDefinitions, averageDefinitions] = await Promise.all([
|
||||
api.tankDefinitions(),
|
||||
api.tanks(),
|
||||
awaitableAverageDefinitions,
|
||||
]);
|
||||
|
||||
|
||||
+23
@@ -0,0 +1,23 @@
|
||||
.page {
|
||||
max-height: 100dvh;
|
||||
flex-grow: 1;
|
||||
display: flex;
|
||||
|
||||
.sandbox {
|
||||
flex-grow: 1;
|
||||
|
||||
overflow-y: auto;
|
||||
}
|
||||
|
||||
.loadout {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
|
||||
gap: var(--space-5);
|
||||
padding: var(--space-5);
|
||||
|
||||
overflow-y: auto;
|
||||
|
||||
background-color: var(--gray-2);
|
||||
}
|
||||
}
|
||||
@@ -1,55 +1,45 @@
|
||||
import { TankType } from "@blitzkit/core";
|
||||
import { PageWrapper } from "../../../../../components/PageWrapper";
|
||||
import { CalloutsSection } from "../../../../../components/Tankopedia/CalloutsSection";
|
||||
import { CharacteristicsSection } from "../../../../../components/Tankopedia/CharacteristicsSection";
|
||||
import { GameModeSection } from "../../../../../components/Tankopedia/GameModeSection";
|
||||
import { GuideSection } from "../../../../../components/Tankopedia/GuideSection";
|
||||
import { HeroSection } from "../../../../../components/Tankopedia/HeroSection";
|
||||
import { MetaSection } from "../../../../../components/Tankopedia/MetaSection";
|
||||
import { TechTreeSection } from "../../../../../components/Tankopedia/TechTreeSection";
|
||||
import { VideoSection } from "../../../../../components/Tankopedia/VideoSection";
|
||||
import { useMemo } from "react";
|
||||
import { api } from "../../../../../core/blitzkit/api";
|
||||
import {
|
||||
LocaleProvider,
|
||||
type LocaleAcceptorProps,
|
||||
} from "../../../../../hooks/useLocale";
|
||||
import { Duel } from "../../../../../stores/duel";
|
||||
import { withErrorWrapper } from "../../../../../hocs/withErrorWrapper";
|
||||
import { withLocale } from "../../../../../hocs/withLocale";
|
||||
import { useAwait } from "../../../../../hooks/useAwait";
|
||||
import { Tankopedia } from "../../../../../stores/tankopedia";
|
||||
import type { MaybeSkeletonComponentProps } from "../../../../../types/maybeSkeletonComponentProps";
|
||||
import type { TankGuide } from "../../../../../types/tankGuide";
|
||||
import styles from "./_index.module.css";
|
||||
|
||||
type PageProps = MaybeSkeletonComponentProps &
|
||||
LocaleAcceptorProps & {
|
||||
id: number;
|
||||
guide?: TankGuide;
|
||||
};
|
||||
|
||||
const [tankDefinitions, modelDefinitions] = await Promise.all([
|
||||
api.tankDefinitions(),
|
||||
api.modelDefinitions(),
|
||||
]);
|
||||
|
||||
export function Page({ id, skeleton, locale, guide }: PageProps) {
|
||||
const tank = tankDefinitions.tanks[id];
|
||||
const model = modelDefinitions.models[id];
|
||||
|
||||
Tankopedia.useInitialization(model);
|
||||
Duel.useInitialization({ tank, model });
|
||||
|
||||
return (
|
||||
<LocaleProvider locale={locale}>
|
||||
<PageWrapper p="0" maxWidth="unset" color="purple" gap="9" pb="9">
|
||||
<HeroSection skeleton={skeleton} />
|
||||
<MetaSection />
|
||||
<CalloutsSection />
|
||||
{tank.type === TankType.TANK_TYPE_RESEARCHABLE && !tank.deprecated && (
|
||||
<TechTreeSection skeleton={skeleton} />
|
||||
)}
|
||||
<CharacteristicsSection skeleton={skeleton} />
|
||||
<GameModeSection />
|
||||
{guide && <GuideSection guide={guide} />}
|
||||
<VideoSection skeleton={skeleton} />
|
||||
</PageWrapper>
|
||||
</LocaleProvider>
|
||||
);
|
||||
interface PageProps {
|
||||
id: number;
|
||||
}
|
||||
|
||||
export const Page = withErrorWrapper(
|
||||
withLocale<PageProps>(({ id }) => {
|
||||
const protagonistTank = useAwait(() => api.tank(id), `tank-${id}`);
|
||||
|
||||
Tankopedia.useInitialization(protagonistTank);
|
||||
|
||||
const protagonist = Tankopedia.use((state) => state.protagonist);
|
||||
const protagonistEquipment = useEquipment(protagonistTank.tank!);
|
||||
|
||||
const { characteristics, parameters } = useMemo(
|
||||
() =>
|
||||
computeCharacteristics(
|
||||
protagonistTank,
|
||||
protagonistEquipment,
|
||||
protagonist,
|
||||
),
|
||||
[protagonist],
|
||||
);
|
||||
|
||||
return (
|
||||
<div className={styles.page}>
|
||||
<div className={styles.loadout}>
|
||||
<TankopediaLoadout characteristics={characteristics} />
|
||||
</div>
|
||||
|
||||
<div className={styles.sandbox}>
|
||||
<TankopediaSandbox parameters={parameters} />
|
||||
<TankopediaCharacteristics characteristics={characteristics} />
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}),
|
||||
);
|
||||
+14
-113
@@ -1,130 +1,31 @@
|
||||
---
|
||||
import { AstroSeo } from "@astrolib/seo";
|
||||
import {
|
||||
alias,
|
||||
assertSecret,
|
||||
createDefaultProvisions,
|
||||
createDefaultSkills,
|
||||
TIER_ROMAN_NUMERALS,
|
||||
} from "@blitzkit/core";
|
||||
import { unwrapper } from "@blitzkit/i18n";
|
||||
import { literals } from "@blitzkit/i18n/src/literals";
|
||||
import { load } from "cheerio";
|
||||
import { api } from "../../../../../core/blitzkit/api";
|
||||
import { mixStaticPaths } from "../../../../../core/blitzkit/mixStaticPaths";
|
||||
import { tankCharacteristics } from "../../../../../core/blitzkit/tankCharacteristics";
|
||||
import { getStrings } from "../../../../../core/i18n/getStrings";
|
||||
import BaseLayout from "../../../../../layouts/BaseLayout.astro";
|
||||
import { genericDefaultEquipmentMatrix } from "../../../../../stores/duel/constants";
|
||||
import type { TankGuide } from "../../../../../types/tankGuide";
|
||||
import "@radix-ui/colors/violet-dark.css";
|
||||
import { api } from "../../../../api/dynamic";
|
||||
import { mixStaticPaths } from "../../../../astro/mixStaticPaths";
|
||||
import ColorScale from "../../../../components/ColorScale.astro";
|
||||
import BaseLayout from "../../../../layouts/BaseLayout.astro";
|
||||
import { getStaticPaths as _getStaticPaths } from "../index.astro";
|
||||
import { Page } from "./_index";
|
||||
|
||||
export const getStaticPaths = mixStaticPaths(_getStaticPaths, async () => {
|
||||
const tankDefinitions = await api.tankDefinitions();
|
||||
const { list } = await api.tankList();
|
||||
|
||||
return Object.values(tankDefinitions.tanks).map((tank) => ({
|
||||
return list.map((tank) => ({
|
||||
params: { slug: tank.slug },
|
||||
props: { id: tank.id },
|
||||
}));
|
||||
});
|
||||
|
||||
const { id, locale } = Astro.props;
|
||||
const strings = getStrings(locale);
|
||||
const tankDefinitions = await api.tankDefinitions();
|
||||
const skillDefinitions = await api.skillDefinitions();
|
||||
const provisionDefinitions = await api.provisionDefinitions();
|
||||
const equipmentDefinitions = await api.equipmentDefinitions();
|
||||
const tankModelDefinitions = await api.modelDefinitions();
|
||||
|
||||
const tank = tankDefinitions.tanks[id];
|
||||
const tankModelDefinition = tankModelDefinitions.models[tank.id];
|
||||
const unwrap = unwrapper(locale);
|
||||
const title = literals(strings.website.tools.tankopedia.tank_seo_title, {
|
||||
name: unwrap(tank.name!),
|
||||
tier: TIER_ROMAN_NUMERALS[tank.tier],
|
||||
nationality:
|
||||
strings.common.nations_adjectives[
|
||||
tank.nation as keyof typeof strings.common.nations_adjectives
|
||||
],
|
||||
class: strings.common.tank_class_short[tank.class],
|
||||
website: "BlitzKit",
|
||||
});
|
||||
const url = import.meta.env.SITE + Astro.url.pathname;
|
||||
|
||||
const icon = alias("api", `/tanks/${id}/icons/big.webp`);
|
||||
const turret = tank.turrets.at(-1)!;
|
||||
const gun = turret.guns.at(-1)!;
|
||||
const shell = gun.shells[0];
|
||||
const characteristics = tankCharacteristics(
|
||||
{
|
||||
tank,
|
||||
applyDynamicArmor: false,
|
||||
applyReactiveArmor: false,
|
||||
applySpallLiner: false,
|
||||
camouflage: true,
|
||||
consumables: [],
|
||||
crewSkills: createDefaultSkills(skillDefinitions),
|
||||
engine: tank.engines.at(-1)!,
|
||||
equipmentMatrix: genericDefaultEquipmentMatrix,
|
||||
turret,
|
||||
gun,
|
||||
provisions: createDefaultProvisions(tank, gun, provisionDefinitions),
|
||||
shell,
|
||||
stockEngine: tank.engines[0],
|
||||
stockGun: tank.turrets[0].guns[0],
|
||||
stockTurret: tank.turrets[0],
|
||||
stockTrack: tank.tracks[0],
|
||||
track: tank.tracks.at(-1)!,
|
||||
assaultDistance: 0,
|
||||
equalize: false,
|
||||
},
|
||||
{ equipmentDefinitions, provisionDefinitions, tankModelDefinition },
|
||||
);
|
||||
const description = literals(
|
||||
strings.website.tools.tankopedia.tank_seo_description,
|
||||
{
|
||||
name: unwrap(tank.name!),
|
||||
dpm: Math.round(characteristics.dpm).toLocaleString(locale),
|
||||
alpha: Math.round(characteristics.damage).toLocaleString(locale),
|
||||
penetration: Math.round(characteristics.penetration).toLocaleString(locale),
|
||||
speed: Math.round(characteristics.speedForwards).toLocaleString(locale),
|
||||
health: Math.round(characteristics.health).toLocaleString(locale),
|
||||
},
|
||||
);
|
||||
|
||||
const guideUrl = `${assertSecret(import.meta.env.PUBLIC_GUIDE_WEBSITE)}/${tank.slug}`;
|
||||
let guide: TankGuide | undefined = undefined;
|
||||
const guideResponse = await fetch(guideUrl);
|
||||
|
||||
if (guideResponse.ok) {
|
||||
const $ = await guideResponse.text().then(load);
|
||||
const description = $(".entry-content p").first().text();
|
||||
const image = $(".entry-content img").first().attr("src")?.toString();
|
||||
|
||||
if (description !== undefined || image !== undefined) {
|
||||
guide = {
|
||||
url: guideUrl,
|
||||
description,
|
||||
image,
|
||||
};
|
||||
}
|
||||
}
|
||||
---
|
||||
|
||||
<AstroSeo
|
||||
{title}
|
||||
{description}
|
||||
openGraph={{ title, description, images: [{ url: icon }], url }}
|
||||
/>
|
||||
<BaseLayout {locale} accent="violet">
|
||||
<ColorScale color="amber" alpha />
|
||||
|
||||
<meta name="twitter:title" content={title} />
|
||||
<meta name="twitter:description" content={description} />
|
||||
<meta name="twitter:card" content="summary" />
|
||||
<meta name="twitter:image:src" content={icon} />
|
||||
<ColorScale color="red" />
|
||||
<ColorScale color="orange" />
|
||||
<ColorScale color="amber" />
|
||||
<ColorScale color="jade" />
|
||||
|
||||
<BaseLayout {locale} integrated>
|
||||
<Page {locale} id={id} {guide} client:only="react">
|
||||
<Page {locale} id={id} {guide} skeleton slot="fallback" />
|
||||
</Page>
|
||||
<Page {locale} {id} client:load />
|
||||
</BaseLayout>
|
||||
+2
-2
@@ -5,7 +5,7 @@ import LegacyRedirect from "../../../../../../layouts/LegacyRedirect.astro";
|
||||
import { getStaticPaths as _getStaticPaths } from "../index.astro";
|
||||
|
||||
export const getStaticPaths = mixStaticPaths(_getStaticPaths, async () => {
|
||||
const tankDefinitions = await api.tankDefinitions();
|
||||
const tankDefinitions = await api.tanks();
|
||||
|
||||
return Object.values(tankDefinitions.tanks).map(({ id }) => ({
|
||||
params: { id },
|
||||
@@ -14,7 +14,7 @@ export const getStaticPaths = mixStaticPaths(_getStaticPaths, async () => {
|
||||
|
||||
const { id } = Astro.params;
|
||||
const { locale } = Astro.props;
|
||||
const tankDefinitions = await api.tankDefinitions();
|
||||
const tankDefinitions = await api.tanks();
|
||||
const tank = tankDefinitions.tanks[id];
|
||||
---
|
||||
|
||||
|
||||
@@ -44,7 +44,7 @@ export interface DuelStore {
|
||||
equalize: boolean;
|
||||
}
|
||||
|
||||
const provisionDefinitions = await api.provisionDefinitions();
|
||||
const provisionDefinitions = await api.provisions();
|
||||
|
||||
export const Duel = new Varuna<
|
||||
DuelStore,
|
||||
|
||||
@@ -105,7 +105,7 @@ interface Tankopedia {
|
||||
statSearch?: string;
|
||||
}
|
||||
|
||||
const skillDefinitions = await api.skillDefinitions();
|
||||
const skillDefinitions = await api.skill();
|
||||
|
||||
export const Tankopedia = new Varuna<Tankopedia, ModelDefinition>((model) => ({
|
||||
disturbed: false,
|
||||
|
||||
Reference in new issue
Block a user