feat: revamp

This commit is contained in:
TrèsAbhi committed 2024-05-03 12:57:04 -05:00
1 parent 468308ad22
commit e3d69ab83c
4 files changed
+137 -198

No files matched your search

@@ -0,0 +1,103 @@
import { EnterFullScreenIcon, ExitFullScreenIcon } from '@radix-ui/react-icons';
import { Checkbox, Flex, Heading, IconButton, Text } from '@radix-ui/themes';
import { TIER_ROMAN_NUMERALS } from '../../../../../../core/blitzkit/tankDefinitions/constants';
import { useFullScreen } from '../../../../../../hooks/useFullScreen';
import strings from '../../../../../../lang/en-US.json';
import { theme } from '../../../../../../stitches.config';
import { useDuel } from '../../../../../../stores/duel';
import mutateTankopediaPersistent, {
useTankopediaPersistent,
} from '../../../../../../stores/tankopedia';
import { TankSandbox } from './TankSandbox';
export function HeroSection() {
const tank = useDuel((state) => state.protagonist!.tank);
const mode = useTankopediaPersistent((state) => state.mode);
const isFullScreen = useFullScreen();
return (
<Flex
justify="center"
pl="9"
style={{
background: `linear-gradient(90deg, ${theme.colors.appBackground1}, ${theme.colors.appBackground2})`,
position: 'relative',
}}
>
<Flex
style={{
maxWidth: 1600,
flex: 1,
}}
>
<Flex
direction="column"
justify="center"
style={{
flex: 1,
}}
>
<Heading size="7">{tank.name}</Heading>
<Text color="gray">
Tier {TIER_ROMAN_NUMERALS[tank.tier]}{' '}
{(strings.common.nations as Record<string, string>)[tank.nation]}{' '}
{strings.common.tank_class_short[tank.class]}
</Text>
</Flex>
<div
style={{
height: 512,
flex: 3,
position: 'relative',
}}
>
<div
style={{
width: '100%',
height: '100%',
position: 'relative',
}}
>
<TankSandbox />
</div>
<Flex
style={{
position: 'absolute',
bottom: 16,
left: '50%',
transform: 'translateX(-50%)',
cursor: 'default',
userSelect: 'none',
}}
align="center"
gap="2"
onClick={() => {
mutateTankopediaPersistent((draft) => {
draft.mode = draft.mode === 'armor' ? 'model' : 'armor';
});
}}
>
<Checkbox checked={mode === 'armor'} />
Armor
</Flex>
</div>
</Flex>
<IconButton
variant="ghost"
style={{
position: 'absolute',
top: 16,
right: 16,
}}
onClick={() => {
document.body.requestFullscreen();
}}
>
{isFullScreen ? <ExitFullScreenIcon /> : <EnterFullScreenIcon />}
</IconButton>
</Flex>
);
}
@@ -1,5 +1,3 @@
import { LightningBoltIcon } from '@radix-ui/react-icons';
import { Button, Card, Flex, Tabs, Text, Theme } from '@radix-ui/themes';
import { PerspectiveCamera } from '@react-three/drei';
import { Canvas } from '@react-three/fiber';
import { Suspense, use, useEffect, useRef, useState } from 'react';
@@ -10,24 +8,18 @@ import { applyPitchYawLimits } from '../../../../../../core/blitz/applyPitchYawL
import { modelDefinitions } from '../../../../../../core/blitzkit/modelDefinitions';
import { modelTransformEvent } from '../../../../../../core/blitzkit/modelTransform';
import { Pose, poseEvent } from '../../../../../../core/blitzkit/pose';
import { tankIcon } from '../../../../../../core/blitzkit/tankIcon';
import { useEquipment } from '../../../../../../hooks/useEquipment';
import { useFullScreen } from '../../../../../../hooks/useFullScreen';
import { useWideFormat } from '../../../../../../hooks/useWideFormat';
import { BlitzkitWide } from '../../../../../../icons/BlitzkitWide';
import { mutateDuel, useDuel } from '../../../../../../stores/duel';
import mutateTankopediaPersistent, {
TankopediaMode,
import {
mutateTankopediaTemporary,
useTankopediaPersistent,
} from '../../../../../../stores/tankopedia';
import { AntagonistBar } from '../AntagonistBar';
import { Controls } from '../Control';
import { Lighting } from '../Lighting';
import { RotationInputs } from '../QuickInputs';
import { SceneProps } from '../SceneProps';
import { ModelLoader } from './components/ModelLoader';
import { Options } from './components/Options';
import { TankModel } from './components/TankModel';
export function TankSandbox() {
@@ -138,137 +130,30 @@ export function TankSandbox() {
}, [protagonist.gun, protagonist.turret]);
return (
<Theme radius={isFullScreen ? 'none' : undefined}>
<Card
style={{
position: isFullScreen ? 'fixed' : 'relative',
border: isFullScreen ? 'none' : 'unset',
width: isFullScreen ? '100vw' : 'unset',
height: isFullScreen ? 'calc(100vh)' : 'unset',
top: isFullScreen ? 0 : 'unset',
left: isFullScreen ? 0 : 'unset',
zIndex: isFullScreen ? 2 : 'unset',
}}
ref={canvasWrapper}
>
<Flex
style={{
height: isFullScreen ? '100%' : '75vh',
maxHeight: isFullScreen ? 'unset' : 576,
}}
direction="column"
gap="2"
>
<Tabs.Root
value={mode}
onValueChange={(mode) => {
mutateTankopediaPersistent((draft) => {
draft.mode = mode as TankopediaMode;
});
}}
>
<Tabs.List>
<Tabs.Trigger value="model">
<Flex gap="2" align="center">
Model
</Flex>
</Tabs.Trigger>
<Tabs.Trigger value="armor">Armor</Tabs.Trigger>
</Tabs.List>
</Tabs.Root>
<Canvas
gl={{
clippingPlanes: Object.freeze([]),
localClippingEnabled: true,
}}
shadows
ref={canvas}
onPointerDown={handlePointerDown}
onPointerMissed={() => {
mutateTankopediaTemporary((draft) => {
draft.shot = undefined;
});
}}
>
<PerspectiveCamera makeDefault fov={25} far={32} />
<Controls />
<SceneProps />
{wideFormat && (
<Text
color="gray"
style={{
position: 'absolute',
left: '50%',
top: 10,
}}
>
<BlitzkitWide height={32} />
</Text>
)}
<div
style={{
height: 'calc(100% - 64px)',
position: 'absolute',
width: '100%',
bottom: 0,
}}
>
{loadModel ? (
<div style={{ width: '100%', height: '100%' }}>
<Canvas
gl={{
clippingPlanes: Object.freeze([]),
localClippingEnabled: true,
}}
shadows
ref={canvas}
onPointerDown={handlePointerDown}
onPointerMissed={() => {
mutateTankopediaTemporary((draft) => {
draft.shot = undefined;
});
}}
>
<PerspectiveCamera makeDefault fov={25} far={32} />
<Controls />
<SceneProps />
<Suspense fallback={<ModelLoader />}>
<Lighting />
<TankModel />
<Armor />
<ShotDisplay />
</Suspense>
</Canvas>
</div>
) : (
<Flex
align="center"
justify="center"
style={{ height: '100%', position: 'relative' }}
>
<Button
style={{
zIndex: 1,
}}
onClick={() => {
setLoadModel(true);
}}
>
<LightningBoltIcon /> Load model
</Button>
<Flex
style={{
filter: 'blur(16px)',
width: 256,
height: 128,
display: 'flex',
position: 'absolute',
top: '50%',
left: '50%',
transformOrigin: 'center center',
transform: 'translate(25%, -25%) scale(300%)',
}}
>
<img src={tankIcon(duel.antagonist!.tank.id, 'big')} />
</Flex>
</Flex>
)}
</div>
<Options canvasWrapper={canvasWrapper} isFullScreen={isFullScreen} />
{isFullScreen && <AntagonistBar floating />}
{loadModel && <RotationInputs isFullScreen={isFullScreen} />}
</Flex>
</Card>
</Theme>
<Suspense fallback={<ModelLoader />}>
<Lighting />
<TankModel />
<Armor />
<ShotDisplay />
</Suspense>
</Canvas>
);
}
+3 -56
View File
@@ -1,23 +1,12 @@
'use client';
import { Flex } from '@radix-ui/themes';
import { useEffect } from 'react';
import PageWrapper from '../../../../components/PageWrapper';
import { assignDuelMember } from '../../../../core/blitzkit/assignDuelMember';
import { useWideFormat } from '../../../../hooks/useWideFormat';
import { mutateDuel, useDuel } from '../../../../stores/duel';
import { mutateTankopediaTemporary } from '../../../../stores/tankopedia';
import { AntagonistBar } from './components/AntagonistBar';
import { Characteristics } from './components/Characteristics';
import { Consumables } from './components/Characteristics/components/Consumables';
import { Equipment } from './components/Characteristics/components/Equipment';
import { Miscellaneous } from './components/Characteristics/components/Miscellaneous';
import { Modules } from './components/Characteristics/components/Modules';
import { Provisions } from './components/Characteristics/components/Provisions';
import { Skills } from './components/Characteristics/components/Skills';
import { TankSandbox } from './components/Model/TankSandbox';
import { Title } from './components/Title';
import { Videos } from './components/Videos';
import { HeroSection } from './components/Model/HeroSection';
export default function Page({ params }: { params: { id: string } }) {
const initialId = parseInt(params.id);
@@ -66,52 +55,10 @@ export default function Page({ params }: { params: { id: string } }) {
}, [initialId, assigned]);
return (
<PageWrapper color="purple" size={1600}>
<PageWrapper noPadding noMaxWidth color="purple" size={1600}>
{assigned && (
<>
<Title />
<Flex
style={{ width: '100%' }}
gap="8"
direction={wideFormat ? 'row' : 'column'}
align="start"
justify="center"
>
<Flex
gap="8"
direction="column"
style={{
flex: 1,
width: '100%',
top: 64 + 16,
position: wideFormat ? 'sticky' : undefined,
}}
>
<Flex gap="4" direction="column">
<TankSandbox />
<AntagonistBar />
</Flex>
<Flex gap="5" wrap="wrap">
<Modules />
<Provisions />
<Consumables />
<Flex gap="5" wrap="wrap">
<Skills />
<Equipment />
</Flex>
<Miscellaneous />
</Flex>
</Flex>
<Flex style={{ width: wideFormat ? 320 : '100%' }}>
<Characteristics />
</Flex>
</Flex>
<Videos />
<HeroSection />
</>
)}
</PageWrapper>
+6 -2
View File
@@ -4,6 +4,8 @@ import { ComponentProps } from 'react';
type PageWrapperProps = FlexProps & {
color?: ComponentProps<typeof Theme>['accentColor'];
size?: number | string;
noPadding?: boolean;
noMaxWidth?: boolean;
};
export default function PageWrapper({
@@ -11,6 +13,8 @@ export default function PageWrapper({
color,
size = 800,
children,
noPadding = false,
noMaxWidth = false,
...props
}: PageWrapperProps) {
return (
@@ -27,9 +31,9 @@ export default function PageWrapper({
gap="4"
style={{
width: '100%',
maxWidth: size,
maxWidth: noMaxWidth ? undefined : size,
margin: 'auto',
padding: 16,
padding: noPadding ? 0 : 16,
boxSizing: 'border-box',
flex: 1,
...style,