2024-11-29 13:20:27 -06:00
|
|
|
import { TankType } from '@blitzkit/core';
|
2025-04-15 00:35:12 -05:00
|
|
|
import { Box, Flex, Heading, Spinner, 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';
|
2024-11-29 13:20:27 -06:00
|
|
|
import { awaitableTankDefinitions } from '../../../core/awaitables/tankDefinitions';
|
2024-09-21 20:26:58 -05:00
|
|
|
import { useFullScreen } from '../../../hooks/useFullScreen';
|
2025-01-14 19:22:41 -06:00
|
|
|
import { useLocale } from '../../../hooks/useLocale';
|
2024-09-22 21:12:18 -05:00
|
|
|
import { Duel } from '../../../stores/duel';
|
2024-11-10 20:59:01 -06:00
|
|
|
import { TankopediaEphemeral } from '../../../stores/tankopediaEphemeral';
|
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';
|
2024-05-03 12:57:04 -05:00
|
|
|
|
2024-11-29 13:20:27 -06: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-04-15 00:35:12 -05:00
|
|
|
const revealed = TankopediaEphemeral.use((state) => state.revealed);
|
2025-04-14 19:26:41 -05:00
|
|
|
const disturbed = TankopediaEphemeral.use((state) => state.disturbed);
|
2025-01-14 19:22:41 -06:00
|
|
|
const { unwrap } = useLocale();
|
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();
|
2024-11-10 20:59:01 -06:00
|
|
|
const mutateTankopediaEphemeral = TankopediaEphemeral.useMutation();
|
2024-10-18 11:36:50 -05:00
|
|
|
|
|
|
|
|
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];
|
|
|
|
|
});
|
2024-11-10 20:59:01 -06:00
|
|
|
mutateTankopediaEphemeral((draft) => {
|
|
|
|
|
draft.customShell = undefined;
|
|
|
|
|
});
|
2024-10-18 11:36:50 -05:00
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
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 (
|
2025-04-14 19:26:41 -05:00
|
|
|
<Flex justify="center">
|
2024-09-01 23:00:37 -05:00
|
|
|
<Flex
|
|
|
|
|
direction={{ initial: 'column', md: 'row' }}
|
2025-04-14 19:26:41 -05:00
|
|
|
style={{
|
|
|
|
|
zIndex: isFullScreen ? 2 : undefined,
|
|
|
|
|
backgroundColor: 'black',
|
|
|
|
|
}}
|
2024-09-01 17:00:02 -05:00
|
|
|
height={
|
|
|
|
|
isFullScreen ? '100vh' : `calc(100vh - ${NAVBAR_HEIGHT}px - 8rem)`
|
|
|
|
|
}
|
2024-12-17 21:46:44 -06:00
|
|
|
maxHeight={isFullScreen ? undefined : '60rem'}
|
2024-09-01 17:05:40 -05:00
|
|
|
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
|
|
|
<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
|
|
|
>
|
2025-04-14 19:26:41 -05:00
|
|
|
<Box position="absolute" width="100%" height="100%" overflow="hidden">
|
|
|
|
|
<Box
|
|
|
|
|
width="100%"
|
|
|
|
|
height="100%"
|
|
|
|
|
position="relative"
|
2025-04-14 23:56:29 -05:00
|
|
|
left={disturbed ? '0' : { initial: '0', md: '12.5%' }}
|
2025-04-14 19:26:41 -05:00
|
|
|
style={{ transitionDuration: '200ms' }}
|
|
|
|
|
>
|
2025-04-15 00:35:12 -05:00
|
|
|
{/* {skeleton && <TankSandboxLoader id={protagonist.id} />} */}
|
2024-11-09 18:38:04 -06:00
|
|
|
|
2025-04-15 00:35:12 -05:00
|
|
|
<Suspense>
|
2024-09-01 17:00:02 -05:00
|
|
|
<TankSandbox ref={canvas} thicknessRange={thicknessRange} />
|
|
|
|
|
</Suspense>
|
|
|
|
|
</Box>
|
|
|
|
|
|
2025-04-14 23:56:29 -05:00
|
|
|
<Options
|
|
|
|
|
skeleton={skeleton}
|
|
|
|
|
canvas={canvas}
|
|
|
|
|
thicknessRange={thicknessRange}
|
|
|
|
|
/>
|
2024-09-01 17:00:02 -05:00
|
|
|
</Box>
|
2024-08-28 22:22:53 -05:00
|
|
|
</Box>
|
2025-04-15 00:35:12 -05:00
|
|
|
|
|
|
|
|
<Flex
|
|
|
|
|
justify="center"
|
|
|
|
|
position={{ initial: 'relative', md: 'absolute' }}
|
|
|
|
|
left={{ initial: '0', md: '5', lg: '9' }}
|
|
|
|
|
py="4"
|
|
|
|
|
top={{ initial: '8', md: '50%' }}
|
|
|
|
|
style={{
|
|
|
|
|
transform: 'translate(0, -50%)',
|
|
|
|
|
transitionDuration: '200ms',
|
|
|
|
|
}}
|
|
|
|
|
direction="column"
|
|
|
|
|
align={{ initial: 'center', md: 'start' }}
|
|
|
|
|
gap={disturbed ? '0' : { initial: '0', md: '2' }}
|
|
|
|
|
>
|
|
|
|
|
<Flex align="center" gap="3">
|
|
|
|
|
<Heading
|
|
|
|
|
color={treeColor}
|
|
|
|
|
trim="end"
|
|
|
|
|
size={
|
|
|
|
|
disturbed
|
|
|
|
|
? { initial: '6', lg: '7' }
|
|
|
|
|
: { initial: '7', lg: '8' }
|
|
|
|
|
}
|
|
|
|
|
style={{ transitionDuration: '200ms', position: 'relative' }}
|
|
|
|
|
>
|
|
|
|
|
<Icon
|
|
|
|
|
width="1em"
|
|
|
|
|
height="1em"
|
|
|
|
|
style={{ opacity: revealed ? 1 : 0 }}
|
|
|
|
|
/>
|
|
|
|
|
<Spinner
|
|
|
|
|
style={{
|
|
|
|
|
position: 'absolute',
|
|
|
|
|
top: '0',
|
|
|
|
|
left: '0',
|
|
|
|
|
width: '1em',
|
|
|
|
|
height: '1em',
|
|
|
|
|
opacity: revealed ? 0 : 1,
|
|
|
|
|
}}
|
|
|
|
|
/>
|
|
|
|
|
</Heading>
|
|
|
|
|
|
|
|
|
|
<Heading
|
|
|
|
|
weight="regular"
|
|
|
|
|
size={
|
|
|
|
|
disturbed
|
|
|
|
|
? { initial: '7', lg: '8' }
|
|
|
|
|
: { initial: '8', lg: '9' }
|
|
|
|
|
}
|
|
|
|
|
style={{ transitionDuration: '200ms' }}
|
|
|
|
|
wrap="nowrap"
|
|
|
|
|
color={treeColor}
|
|
|
|
|
>
|
|
|
|
|
{unwrap(protagonist.name)}
|
|
|
|
|
</Heading>
|
|
|
|
|
</Flex>
|
|
|
|
|
|
|
|
|
|
<Box
|
|
|
|
|
ml="3"
|
|
|
|
|
style={{
|
|
|
|
|
transitionDuration: '200ms',
|
|
|
|
|
opacity: revealed ? 1 : 0,
|
|
|
|
|
transform: revealed ? 'translateY(0)' : 'translateY(-100%)',
|
|
|
|
|
}}
|
|
|
|
|
>
|
|
|
|
|
<Text
|
|
|
|
|
color="gray"
|
|
|
|
|
size={{ initial: '3', lg: disturbed ? '4' : '5' }}
|
|
|
|
|
weight="light"
|
|
|
|
|
ml={{
|
|
|
|
|
initial: '0',
|
|
|
|
|
md: disturbed ? 'var(--font-size-6)' : 'var(--font-size-7)',
|
|
|
|
|
lg: disturbed ? 'var(--font-size-7)' : 'var(--font-size-8)',
|
|
|
|
|
}}
|
|
|
|
|
>
|
|
|
|
|
BlitzKit Tankopedia
|
|
|
|
|
</Text>
|
|
|
|
|
</Box>
|
|
|
|
|
</Flex>
|
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
|
|
|
);
|
|
|
|
|
}
|