Files
blitzkit/packages/website/src/components/Tankopedia/HeroSection/index.tsx
T

160 lines
4.7 KiB
TypeScript
Raw Normal View History

2025-09-01 22:56:39 -05:00
import { Box, Flex } from "@radix-ui/themes";
import { times } from "lodash-es";
import { Suspense, useEffect, useMemo, useRef } from "react";
import { awaitableTankDefinitions } from "../../../core/awaitables/tankDefinitions";
import { useFullScreen } from "../../../hooks/useFullScreen";
import { Duel } from "../../../stores/duel";
import { Tankopedia } from "../../../stores/tankopedia";
import type { MaybeSkeletonComponentProps } from "../../../types/maybeSkeletonComponentProps";
import type { ThicknessRange } from "../../Armor/components/StaticArmor";
import { Options } from "./components/Options";
import { TankSandbox } from "./components/TankSandbox";
import { Title } from "./components/TankSandbox/Title";
2024-05-03 12:57:04 -05:00
2025-05-16 23:03:56 -05:00
const tankDefinitions = await awaitableTankDefinitions;
2024-09-21 20:26:58 -05:00
2024-11-09 18:38:04 -06:00
export function HeroSection({ skeleton }: MaybeSkeletonComponentProps) {
2025-09-01 22:56:39 -05:00
const revealed = Tankopedia.use((state) => state.revealed);
const disturbed = Tankopedia.use((state) => state.disturbed);
2024-08-25 19:11:30 -05:00
const canvas = useRef<HTMLCanvasElement>(null);
2024-05-04 17:02:03 -05:00
const isFullScreen = useFullScreen();
2024-09-22 21:12:18 -05:00
const protagonist = Duel.use((state) => state.protagonist.tank);
2024-07-29 14:08:52 -05:00
const thicknessRange = useMemo(() => {
2024-10-05 23:20:04 -05:00
const entries = Object.values(tankDefinitions.tanks);
2024-09-01 18:00:15 -05:00
const filtered = entries.filter(
2025-09-01 22:56:39 -05:00
(thisTank) => thisTank.tier === protagonist.tier
2024-09-01 18:00:15 -05:00
);
2024-07-30 13:45:52 -05:00
const value =
2024-07-31 13:25:58 -05:00
(filtered.reduce((accumulator, thisTank) => {
2024-07-30 13:45:52 -05:00
return (
accumulator +
2025-08-18 12:06:14 -05:00
thisTank.turrets.at(-1)!.guns.at(-1)!.shells[0].penetration.near
2024-07-30 13:45:52 -05:00
);
}, 0) /
2024-07-31 13:25:58 -05:00
filtered.length) *
(3 / 4);
2024-07-29 14:08:52 -05:00
2024-07-30 13:45:52 -05:00
return { value } satisfies ThicknessRange;
2024-09-01 18:00:15 -05:00
}, [protagonist]);
2025-05-06 13:29:40 -05:00
useEffect(() => {
if (disturbed) {
2025-09-01 22:56:39 -05:00
document.body.classList.remove("no-navbar");
2025-05-06 13:29:40 -05:00
}
}, [disturbed]);
2024-10-18 11:36:50 -05:00
useEffect(() => {
function handleKeyDown(event: KeyboardEvent) {
times(3, (index) => {
2025-09-02 16:24:13 -05:00
if (
event.key === `${index + 1}` &&
Duel.state.antagonist.gun.shells.length > index
) {
Duel.mutate((draft) => {
draft.antagonist.shell = Duel.state.antagonist.gun.shells[index];
2024-10-18 11:36:50 -05:00
});
2025-09-01 22:56:39 -05:00
Tankopedia.mutate((draft) => {
2024-11-10 20:59:01 -06:00
draft.customShell = undefined;
});
2024-10-18 11:36:50 -05:00
}
});
}
2025-09-01 22:56:39 -05:00
window.addEventListener("keydown", handleKeyDown);
return () => window.removeEventListener("keydown", handleKeyDown);
2024-10-18 11:36:50 -05:00
}, []);
2024-07-10 20:47:02 -05:00
2024-05-03 12:57:04 -05:00
return (
2025-05-06 13:29:40 -05:00
<Flex
2025-05-06 13:39:07 -05:00
overflow="hidden"
2025-05-06 13:29:40 -05:00
justify="center"
style={{
2025-09-01 22:56:39 -05:00
backgroundColor: "black",
2025-05-06 13:29:40 -05:00
}}
position="relative"
>
<Box
position="absolute"
width="100%"
height="100%"
top="0"
left="0"
style={{
opacity: disturbed ? 0 : 1,
2025-09-01 22:56:39 -05:00
background: "black",
transitionDuration: "1s",
2025-05-06 13:29:40 -05:00
}}
/>
2025-05-07 19:16:10 -05:00
{/* <ScrollHint /> */}
2025-05-06 13:29:40 -05:00
2024-09-01 23:00:37 -05:00
<Flex
2025-09-01 22:56:39 -05:00
direction={{ initial: "column-reverse", md: "row" }}
2025-04-14 19:26:41 -05:00
style={{
zIndex: isFullScreen ? 2 : undefined,
2025-09-01 22:56:39 -05:00
transitionDuration: "1s",
background: isFullScreen ? "black" : undefined,
2025-04-14 19:26:41 -05:00
}}
2025-08-29 22:51:24 -05:00
height={
isFullScreen
2025-09-01 22:56:39 -05:00
? "100vh"
2025-08-29 22:51:24 -05:00
: disturbed
2025-09-01 22:56:39 -05:00
? "calc(100svh - 6rem)"
2025-08-29 22:51:24 -05:00
: {
2025-09-01 22:56:39 -05:00
initial: "28rem",
md: "calc(100svh - 12rem)",
2025-08-29 22:51:24 -05:00
}
}
2025-09-01 22:56:39 -05:00
maxWidth={isFullScreen ? undefined : "120rem"}
2024-09-01 17:00:02 -05:00
flexGrow="1"
2025-09-01 22:56:39 -05:00
width={isFullScreen ? "100vw" : undefined}
position={isFullScreen ? "fixed" : "relative"}
top={isFullScreen ? "0" : undefined}
left={isFullScreen ? "0" : undefined}
2024-08-28 22:22:53 -05:00
>
2025-04-20 21:16:50 -05:00
<Box
className="tank-sandbox-container"
flexGrow="1"
flexBasis="0"
flexShrink="0"
position="relative"
>
<Box position="absolute" width="100%" height="100%" overflow="hidden">
<Box
width="100%"
height="100%"
position="relative"
2025-05-05 22:54:39 -05:00
style={{
2025-09-01 22:56:39 -05:00
transitionDuration: "1s",
2025-05-05 22:54:39 -05:00
}}
2025-04-20 21:16:50 -05:00
>
2025-05-05 22:54:39 -05:00
<Box
style={{
2025-09-01 22:56:39 -05:00
width: "100%",
height: "100%",
transitionDuration: "2s",
2025-05-05 22:54:39 -05:00
opacity: revealed ? 1 : 0,
2025-08-09 11:52:10 -05:00
filter: disturbed
? undefined
: `drop-shadow(0 1rem 1rem black)`,
2025-05-05 22:54:39 -05:00
}}
>
<Suspense>
<TankSandbox ref={canvas} thicknessRange={thicknessRange} />
</Suspense>
</Box>
2025-04-20 21:16:50 -05:00
</Box>
2025-08-28 17:59:31 -05:00
<Title />
2025-08-09 12:07:26 -05:00
2025-04-20 21:16:50 -05:00
<Options
skeleton={skeleton}
canvas={canvas}
thicknessRange={thicknessRange}
/>
</Box>
</Box>
2024-09-01 23:00:37 -05:00
</Flex>
2024-09-01 17:00:02 -05:00
</Flex>
2024-05-03 12:57:04 -05:00
);
}