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

141 lines
4.6 KiB
TypeScript
Raw Normal View History

2024-10-05 23:20:04 -05:00
import { fetchTankDefinitions, TankType } from '@blitzkit/core';
2024-08-28 22:22:53 -05:00
import { Box, Flex, Heading, Text } from '@radix-ui/themes';
2024-10-18 11:36:50 -05:00
import { times } from 'lodash-es';
import { Suspense, useEffect, useMemo, useRef } from 'react';
2024-09-21 20:26:58 -05:00
import { NAVBAR_HEIGHT } from '../../../constants/navbar';
import { Var } from '../../../core/radix/var';
import { useFullScreen } from '../../../hooks/useFullScreen';
2024-09-22 21:12:18 -05:00
import { Duel } from '../../../stores/duel';
2024-11-09 18:38:04 -06:00
import type { MaybeSkeletonComponentProps } from '../../../types/maybeSkeletonComponentProps';
2024-09-21 20:26:58 -05:00
import type { ThicknessRange } from '../../Armor/components/StaticArmor';
import { classIcons } from '../../ClassIcon';
2024-08-28 22:22:53 -05:00
import { Options } from './components/Options';
2024-09-21 20:26:58 -05:00
import { TankSandbox } from './components/TankSandbox';
import { TankSandboxLoader } from './components/TankSandboxLoader';
2024-05-03 12:57:04 -05:00
2024-10-05 23:20:04 -05:00
const tankDefinitions = await fetchTankDefinitions();
2024-09-21 20:26:58 -05:00
2024-11-09 18:38:04 -06:00
export function HeroSection({ skeleton }: MaybeSkeletonComponentProps) {
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-06-29 12:12:10 -05:00
const Icon = classIcons[protagonist.class];
2024-07-13 14:25:26 -05:00
const treeColor =
2024-10-05 23:20:04 -05:00
protagonist.type === TankType.COLLECTOR
2024-07-13 14:25:26 -05:00
? 'blue'
2024-10-05 23:20:04 -05:00
: protagonist.type === TankType.PREMIUM
2024-09-08 10:46:12 -05:00
? 'amber'
: undefined;
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(
(thisTank) => thisTank.tier === protagonist.tier,
);
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 +
2024-10-07 18:45:11 -05:00
thisTank.turrets.at(-1)!.guns.at(-1)!.gun_type!.value.base.shells[0]
2024-10-05 23:20:04 -05:00
.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]);
2024-10-18 11:36:50 -05:00
const duelStore = Duel.useStore();
const mutateDuel = Duel.useMutation();
useEffect(() => {
function handleKeyDown(event: KeyboardEvent) {
const { shells } =
duelStore.getState().antagonist.gun.gun_type!.value.base;
times(3, (index) => {
if (event.key === `${index + 1}` && shells.length > index) {
mutateDuel((draft) => {
draft.antagonist.shell = shells[index];
});
}
});
}
window.addEventListener('keydown', handleKeyDown);
return () => window.removeEventListener('keydown', handleKeyDown);
}, []);
2024-07-10 20:47:02 -05:00
2024-05-03 12:57:04 -05:00
return (
2024-09-01 17:00:02 -05:00
<Flex justify="center" style={{ backgroundColor: Var('color-surface') }}>
2024-09-01 23:00:37 -05:00
<Flex
direction={{ initial: 'column', md: 'row' }}
2024-09-01 17:00:02 -05:00
style={{
backgroundColor: isFullScreen
? Var('color-background')
: Var('color-surface'),
zIndex: isFullScreen ? 2 : undefined,
}}
height={
isFullScreen ? '100vh' : `calc(100vh - ${NAVBAR_HEIGHT}px - 8rem)`
}
2024-09-01 17:05:40 -05:00
maxHeight={isFullScreen ? undefined : '40rem'}
maxWidth={isFullScreen ? undefined : '120rem'}
2024-09-01 17:00:02 -05:00
flexGrow="1"
width={isFullScreen ? '100vw' : undefined}
position={isFullScreen ? 'fixed' : 'relative'}
top={isFullScreen ? '0' : undefined}
left={isFullScreen ? '0' : undefined}
2024-08-28 22:22:53 -05:00
>
2024-09-01 17:00:02 -05:00
<Flex
2024-09-01 23:00:37 -05:00
style={{ userSelect: 'none' }}
direction="column"
align={{ initial: 'center', md: 'start' }}
justify="center"
pl={{ initial: '0', md: '9' }}
pt={{ initial: '5', md: '0' }}
2024-09-01 17:00:02 -05:00
>
2024-09-01 23:00:37 -05:00
<Heading
weight="bold"
size={{ initial: '8', lg: '9' }}
wrap="nowrap"
color={treeColor}
>
<Flex align="center" gap="3">
<Icon width="0.8em" height="0.8em" />
{protagonist.name}
</Flex>
</Heading>
2024-08-28 22:22:53 -05:00
2024-09-01 23:00:37 -05:00
<Text
color="gray"
size="3"
weight="light"
ml={{ initial: '0', md: '7', lg: '9' }}
2024-09-01 23:00:37 -05:00
>
BlitzKit Tankopedia
</Text>
2024-09-01 17:00:02 -05:00
</Flex>
<Box
className="tank-sandbox-container"
2024-09-01 23:00:37 -05:00
flexGrow="1"
flexBasis="0"
flexShrink="0"
position="relative"
2024-09-01 17:00:02 -05:00
>
2024-09-01 23:00:37 -05:00
<Box position="absolute" width="100%" height="100%">
2024-09-01 17:00:02 -05:00
<Box width="100%" height="100%">
2024-11-09 18:38:04 -06:00
{skeleton && <TankSandboxLoader id={protagonist.id} />}
2024-09-22 21:27:46 -05:00
<Suspense fallback={<TankSandboxLoader id={protagonist.id} />}>
2024-09-01 17:00:02 -05:00
<TankSandbox ref={canvas} thicknessRange={thicknessRange} />
</Suspense>
</Box>
<Options canvas={canvas} thicknessRange={thicknessRange} />
</Box>
2024-08-28 22:22:53 -05:00
</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
);
}