mirror of
https://github.com/blitzkit/blitzkit.git
synced 2026-10-23 19:49:50 +02:00
feat: start of characteristics
This commit is contained in:
1 parent
381a4fefd9
commit
c855bd1653
5 files changed
+84
-27
No files matched your search
@@ -11,9 +11,9 @@ import {
|
|||||||
import { debounce } from 'lodash';
|
import { debounce } from 'lodash';
|
||||||
import { Fragment, use, useEffect, useRef, useState } from 'react';
|
import { Fragment, use, useEffect, useRef, useState } from 'react';
|
||||||
import { lerp } from 'three/src/math/MathUtils';
|
import { lerp } from 'three/src/math/MathUtils';
|
||||||
import { ShellButton } from '../../../../../../components/ModuleButtons/ShellButton';
|
|
||||||
import { applyPitchYawLimits } from '../../../../../../core/blitz/applyPitchYawLimits';
|
import { applyPitchYawLimits } from '../../../../../../core/blitz/applyPitchYawLimits';
|
||||||
import { isExplosive } from '../../../../../../core/blitz/isExplosive';
|
import { isExplosive } from '../../../../../../core/blitz/isExplosive';
|
||||||
|
import { asset } from '../../../../../../core/blitzkit/asset';
|
||||||
import { coefficient } from '../../../../../../core/blitzkit/coefficient';
|
import { coefficient } from '../../../../../../core/blitzkit/coefficient';
|
||||||
import { equipmentDefinitions } from '../../../../../../core/blitzkit/equipmentDefinitions';
|
import { equipmentDefinitions } from '../../../../../../core/blitzkit/equipmentDefinitions';
|
||||||
import { modelDefinitions } from '../../../../../../core/blitzkit/modelDefinitions';
|
import { modelDefinitions } from '../../../../../../core/blitzkit/modelDefinitions';
|
||||||
@@ -22,7 +22,6 @@ import { tankCharacteristics } from '../../../../../../core/blitzkit/tankCharact
|
|||||||
import {
|
import {
|
||||||
CREW_MEMBER_NAMES,
|
CREW_MEMBER_NAMES,
|
||||||
GUN_TYPE_NAMES,
|
GUN_TYPE_NAMES,
|
||||||
SHELL_NAMES,
|
|
||||||
} from '../../../../../../core/blitzkit/tankDefinitions/constants';
|
} from '../../../../../../core/blitzkit/tankDefinitions/constants';
|
||||||
import { useEquipment } from '../../../../../../hooks/useEquipment';
|
import { useEquipment } from '../../../../../../hooks/useEquipment';
|
||||||
import { useFullScreen } from '../../../../../../hooks/useFullScreen';
|
import { useFullScreen } from '../../../../../../hooks/useFullScreen';
|
||||||
@@ -129,12 +128,12 @@ export function Characteristics() {
|
|||||||
if (isFullScreen) return null;
|
if (isFullScreen) return null;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Flex direction="column" gap="8" style={{ width: '100%' }}>
|
<Flex direction="column" gap="8">
|
||||||
<Flex direction="column" gap="2">
|
<Flex direction="column" gap="2">
|
||||||
<Flex align="center" gap="4">
|
<Flex align="center" gap="4">
|
||||||
<Heading size="5">Fire</Heading>
|
<Heading size="5">Fire</Heading>
|
||||||
|
|
||||||
<Flex>
|
{/* <Flex>
|
||||||
{gun.shells.map((thisShell, index) => {
|
{gun.shells.map((thisShell, index) => {
|
||||||
return (
|
return (
|
||||||
<ShellButton
|
<ShellButton
|
||||||
@@ -153,6 +152,36 @@ export function Characteristics() {
|
|||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
})}
|
})}
|
||||||
|
</Flex> */}
|
||||||
|
|
||||||
|
<Flex>
|
||||||
|
{gun.shells.map((thisShell, shellIndex) => (
|
||||||
|
<IconButton
|
||||||
|
color={thisShell.id === shell.id ? undefined : 'gray'}
|
||||||
|
variant="soft"
|
||||||
|
key={thisShell.id}
|
||||||
|
style={{
|
||||||
|
borderTopLeftRadius: shellIndex === 0 ? undefined : 0,
|
||||||
|
borderBottomLeftRadius: shellIndex === 0 ? undefined : 0,
|
||||||
|
borderTopRightRadius:
|
||||||
|
shellIndex === gun.shells.length - 1 ? undefined : 0,
|
||||||
|
borderBottomRightRadius:
|
||||||
|
shellIndex === gun.shells.length - 1 ? undefined : 0,
|
||||||
|
marginLeft: shellIndex === 0 ? 0 : -1,
|
||||||
|
}}
|
||||||
|
onClick={() => {
|
||||||
|
mutateDuel((draft) => {
|
||||||
|
draft.protagonist!.shell = thisShell;
|
||||||
|
});
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<img
|
||||||
|
width={16}
|
||||||
|
height={16}
|
||||||
|
src={asset(`icons/shells/${thisShell.icon}.webp`)}
|
||||||
|
/>
|
||||||
|
</IconButton>
|
||||||
|
))}
|
||||||
</Flex>
|
</Flex>
|
||||||
</Flex>
|
</Flex>
|
||||||
<Info name="Gun type">{GUN_TYPE_NAMES[gun.type]}</Info>
|
<Info name="Gun type">{GUN_TYPE_NAMES[gun.type]}</Info>
|
||||||
|
|||||||
@@ -0,0 +1,21 @@
|
|||||||
|
import { Flex, Heading } from '@radix-ui/themes';
|
||||||
|
import { Characteristics } from '../Characteristics';
|
||||||
|
import { Consumables } from '../Characteristics/components/Consumables';
|
||||||
|
import { Modules } from '../Characteristics/components/Modules';
|
||||||
|
|
||||||
|
export function CharacteristicsSection() {
|
||||||
|
return (
|
||||||
|
<Flex justify="center">
|
||||||
|
<Flex style={{ maxWidth: 640 }}>
|
||||||
|
<Flex style={{ flex: 1 }} direction="column" gap="4">
|
||||||
|
<Heading>Configure</Heading>
|
||||||
|
|
||||||
|
<Modules />
|
||||||
|
<Consumables />
|
||||||
|
</Flex>
|
||||||
|
|
||||||
|
<Characteristics />
|
||||||
|
</Flex>
|
||||||
|
</Flex>
|
||||||
|
);
|
||||||
|
}
|
||||||
@@ -1,7 +1,7 @@
|
|||||||
import { EnterFullScreenIcon, ExitFullScreenIcon } from '@radix-ui/react-icons';
|
import { Checkbox, Flex, Heading, Text } from '@radix-ui/themes';
|
||||||
import { Checkbox, Flex, Heading, IconButton, Text } from '@radix-ui/themes';
|
|
||||||
import { TIER_ROMAN_NUMERALS } from '../../../../../../core/blitzkit/tankDefinitions/constants';
|
import { TIER_ROMAN_NUMERALS } from '../../../../../../core/blitzkit/tankDefinitions/constants';
|
||||||
import { useFullScreen } from '../../../../../../hooks/useFullScreen';
|
import { useFullScreen } from '../../../../../../hooks/useFullScreen';
|
||||||
|
import { useWideFormat } from '../../../../../../hooks/useWideFormat';
|
||||||
import strings from '../../../../../../lang/en-US.json';
|
import strings from '../../../../../../lang/en-US.json';
|
||||||
import { theme } from '../../../../../../stitches.config';
|
import { theme } from '../../../../../../stitches.config';
|
||||||
import { useDuel } from '../../../../../../stores/duel';
|
import { useDuel } from '../../../../../../stores/duel';
|
||||||
@@ -9,22 +9,27 @@ import mutateTankopediaPersistent, {
|
|||||||
useTankopediaPersistent,
|
useTankopediaPersistent,
|
||||||
} from '../../../../../../stores/tankopedia';
|
} from '../../../../../../stores/tankopedia';
|
||||||
import { TankSandbox } from './TankSandbox';
|
import { TankSandbox } from './TankSandbox';
|
||||||
|
import { Options } from './components/Options';
|
||||||
|
|
||||||
export function HeroSection() {
|
export function HeroSection() {
|
||||||
const tank = useDuel((state) => state.protagonist!.tank);
|
const tank = useDuel((state) => state.protagonist!.tank);
|
||||||
const mode = useTankopediaPersistent((state) => state.mode);
|
const mode = useTankopediaPersistent((state) => state.mode);
|
||||||
const isFullScreen = useFullScreen();
|
const isFullScreen = useFullScreen();
|
||||||
|
const wideFormat = useWideFormat(880);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Flex
|
<Flex
|
||||||
justify="center"
|
justify="center"
|
||||||
pl="9"
|
pl={wideFormat ? '9' : undefined}
|
||||||
|
p={wideFormat ? '0' : '6'}
|
||||||
|
pb={wideFormat ? '0' : '6'}
|
||||||
style={{
|
style={{
|
||||||
background: `linear-gradient(90deg, ${theme.colors.appBackground1}, ${theme.colors.appBackground2})`,
|
background: `linear-gradient(90deg, ${theme.colors.appBackground1}, ${theme.colors.appBackground2})`,
|
||||||
position: 'relative',
|
position: 'relative',
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<Flex
|
<Flex
|
||||||
|
direction={wideFormat ? 'row' : 'column'}
|
||||||
style={{
|
style={{
|
||||||
maxWidth: 1600,
|
maxWidth: 1600,
|
||||||
flex: 1,
|
flex: 1,
|
||||||
@@ -33,12 +38,12 @@ export function HeroSection() {
|
|||||||
<Flex
|
<Flex
|
||||||
direction="column"
|
direction="column"
|
||||||
justify="center"
|
justify="center"
|
||||||
gap="4"
|
gap={wideFormat ? '4' : '2'}
|
||||||
style={{
|
style={{
|
||||||
flex: 1,
|
flex: 1,
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<Heading size="9">{tank.name}</Heading>
|
<Heading size={wideFormat ? '9' : '8'}>{tank.name}</Heading>
|
||||||
<Text color="gray">
|
<Text color="gray">
|
||||||
Tier {TIER_ROMAN_NUMERALS[tank.tier]}{' '}
|
Tier {TIER_ROMAN_NUMERALS[tank.tier]}{' '}
|
||||||
{(strings.common.nations as Record<string, string>)[tank.nation]}{' '}
|
{(strings.common.nations as Record<string, string>)[tank.nation]}{' '}
|
||||||
@@ -49,7 +54,7 @@ export function HeroSection() {
|
|||||||
<div
|
<div
|
||||||
style={{
|
style={{
|
||||||
height: 512,
|
height: 512,
|
||||||
flex: 3,
|
flex: wideFormat ? 3 : undefined,
|
||||||
position: 'relative',
|
position: 'relative',
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
@@ -57,7 +62,6 @@ export function HeroSection() {
|
|||||||
style={{
|
style={{
|
||||||
width: '100%',
|
width: '100%',
|
||||||
height: '100%',
|
height: '100%',
|
||||||
position: 'relative',
|
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<TankSandbox />
|
<TankSandbox />
|
||||||
@@ -86,8 +90,9 @@ export function HeroSection() {
|
|||||||
</div>
|
</div>
|
||||||
</Flex>
|
</Flex>
|
||||||
|
|
||||||
<IconButton
|
{/* <IconButton
|
||||||
variant="ghost"
|
variant="ghost"
|
||||||
|
color="gray"
|
||||||
style={{
|
style={{
|
||||||
position: 'absolute',
|
position: 'absolute',
|
||||||
top: 16,
|
top: 16,
|
||||||
@@ -102,7 +107,9 @@ export function HeroSection() {
|
|||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
{isFullScreen ? <ExitFullScreenIcon /> : <EnterFullScreenIcon />}
|
{isFullScreen ? <ExitFullScreenIcon /> : <EnterFullScreenIcon />}
|
||||||
</IconButton>
|
</IconButton> */}
|
||||||
|
|
||||||
|
<Options />
|
||||||
</Flex>
|
</Flex>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@@ -4,9 +4,9 @@ import {
|
|||||||
EyeOpenIcon,
|
EyeOpenIcon,
|
||||||
GearIcon,
|
GearIcon,
|
||||||
} from '@radix-ui/react-icons';
|
} from '@radix-ui/react-icons';
|
||||||
import { Button, DropdownMenu, Flex } from '@radix-ui/themes';
|
import { DropdownMenu, Flex, IconButton } from '@radix-ui/themes';
|
||||||
import { RefObject } from 'react';
|
|
||||||
import { Pose, poseEvent } from '../../../../../../../core/blitzkit/pose';
|
import { Pose, poseEvent } from '../../../../../../../core/blitzkit/pose';
|
||||||
|
import { useFullScreen } from '../../../../../../../hooks/useFullScreen';
|
||||||
import { useApp } from '../../../../../../../stores/app';
|
import { useApp } from '../../../../../../../stores/app';
|
||||||
import mutateTankopediaPersistent, {
|
import mutateTankopediaPersistent, {
|
||||||
mutateTankopediaTemporary,
|
mutateTankopediaTemporary,
|
||||||
@@ -14,12 +14,8 @@ import mutateTankopediaPersistent, {
|
|||||||
} from '../../../../../../../stores/tankopedia';
|
} from '../../../../../../../stores/tankopedia';
|
||||||
import { ENVIRONMENTS } from '../../Lighting';
|
import { ENVIRONMENTS } from '../../Lighting';
|
||||||
|
|
||||||
interface OptionsProps {
|
export function Options() {
|
||||||
isFullScreen: boolean;
|
const isFullScreen = useFullScreen();
|
||||||
canvasWrapper: RefObject<HTMLElement>;
|
|
||||||
}
|
|
||||||
|
|
||||||
export function Options({ isFullScreen }: OptionsProps) {
|
|
||||||
const showGrid = useTankopediaPersistent(
|
const showGrid = useTankopediaPersistent(
|
||||||
(state) => state.model.visual.showGrid,
|
(state) => state.model.visual.showGrid,
|
||||||
);
|
);
|
||||||
@@ -54,9 +50,9 @@ export function Options({ isFullScreen }: OptionsProps) {
|
|||||||
>
|
>
|
||||||
<DropdownMenu.Root>
|
<DropdownMenu.Root>
|
||||||
<DropdownMenu.Trigger>
|
<DropdownMenu.Trigger>
|
||||||
<Button variant="ghost">
|
<IconButton variant="ghost" color="gray">
|
||||||
<EyeOpenIcon />
|
<EyeOpenIcon />
|
||||||
</Button>
|
</IconButton>
|
||||||
</DropdownMenu.Trigger>
|
</DropdownMenu.Trigger>
|
||||||
|
|
||||||
<DropdownMenu.Content>
|
<DropdownMenu.Content>
|
||||||
@@ -76,9 +72,9 @@ export function Options({ isFullScreen }: OptionsProps) {
|
|||||||
|
|
||||||
<DropdownMenu.Root>
|
<DropdownMenu.Root>
|
||||||
<DropdownMenu.Trigger>
|
<DropdownMenu.Trigger>
|
||||||
<Button variant="ghost">
|
<IconButton variant="ghost" color="gray">
|
||||||
<GearIcon />
|
<GearIcon />
|
||||||
</Button>
|
</IconButton>
|
||||||
</DropdownMenu.Trigger>
|
</DropdownMenu.Trigger>
|
||||||
|
|
||||||
<DropdownMenu.Content>
|
<DropdownMenu.Content>
|
||||||
@@ -154,6 +150,7 @@ export function Options({ isFullScreen }: OptionsProps) {
|
|||||||
});
|
});
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
|
{/* TODO: consider removing this? */}
|
||||||
View environment
|
View environment
|
||||||
</DropdownMenu.CheckboxItem>
|
</DropdownMenu.CheckboxItem>
|
||||||
|
|
||||||
@@ -182,7 +179,8 @@ export function Options({ isFullScreen }: OptionsProps) {
|
|||||||
</DropdownMenu.Root>
|
</DropdownMenu.Root>
|
||||||
|
|
||||||
{fullScreenAvailable && (
|
{fullScreenAvailable && (
|
||||||
<Button
|
<IconButton
|
||||||
|
color="gray"
|
||||||
variant="ghost"
|
variant="ghost"
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
if (isFullScreen) {
|
if (isFullScreen) {
|
||||||
@@ -191,7 +189,7 @@ export function Options({ isFullScreen }: OptionsProps) {
|
|||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
{isFullScreen ? <ExitFullScreenIcon /> : <EnterFullScreenIcon />}
|
{isFullScreen ? <ExitFullScreenIcon /> : <EnterFullScreenIcon />}
|
||||||
</Button>
|
</IconButton>
|
||||||
)}
|
)}
|
||||||
</Flex>
|
</Flex>
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -6,6 +6,7 @@ import { assignDuelMember } from '../../../../core/blitzkit/assignDuelMember';
|
|||||||
import { useWideFormat } from '../../../../hooks/useWideFormat';
|
import { useWideFormat } from '../../../../hooks/useWideFormat';
|
||||||
import { mutateDuel, useDuel } from '../../../../stores/duel';
|
import { mutateDuel, useDuel } from '../../../../stores/duel';
|
||||||
import { mutateTankopediaTemporary } from '../../../../stores/tankopedia';
|
import { mutateTankopediaTemporary } from '../../../../stores/tankopedia';
|
||||||
|
import { CharacteristicsSection } from './components/Model/CharacteristicsSection';
|
||||||
import { HeroSection } from './components/Model/HeroSection';
|
import { HeroSection } from './components/Model/HeroSection';
|
||||||
|
|
||||||
export default function Page({ params }: { params: { id: string } }) {
|
export default function Page({ params }: { params: { id: string } }) {
|
||||||
@@ -59,6 +60,7 @@ export default function Page({ params }: { params: { id: string } }) {
|
|||||||
{assigned && (
|
{assigned && (
|
||||||
<>
|
<>
|
||||||
<HeroSection />
|
<HeroSection />
|
||||||
|
<CharacteristicsSection />
|
||||||
</>
|
</>
|
||||||
)}
|
)}
|
||||||
</PageWrapper>
|
</PageWrapper>
|
||||||
|
|||||||
Reference in new issue
Block a user