mirror of
https://github.com/blitzkit/blitzkit.git
synced 2026-10-21 10:47:04 +02:00
feat: quick controls
This commit is contained in:
1 parent
45938c875f
commit
2bef96475c
6 files changed
+288
-273
No files matched your search
+4
-4
@@ -46,9 +46,9 @@
|
|||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@types/bun": "latest",
|
"@types/bun": "latest",
|
||||||
"@types/lodash-es": "^4.17.12",
|
"@types/lodash-es": "^4.17.12",
|
||||||
"@types/node": "^22.5.4",
|
"@types/node": "^22.14.1",
|
||||||
"prettier": "^3.3.3",
|
"prettier": "^3.5.3",
|
||||||
"prisma": "^6.0.0",
|
"prisma": "^6.6.0",
|
||||||
"typescript": "^5.5.4"
|
"typescript": "^5.8.3"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -13,8 +13,8 @@ export function MissingShellIcon(props: ComponentProps<'svg'>) {
|
|||||||
<path
|
<path
|
||||||
d="M39.5461 16.5714L47.4286 24.4539M16.1429 37.5714L26.4286 47.8571M56 10.3802L53.6198 8C32.2378 20.0846 22.0873 28.6952 8 48.0661C8.13223 48.595 8.63471 50.2876 11.1736 52.8264C13.7124 55.3653 15.405 55.8678 15.9339 56C35.3048 41.9127 43.9154 31.7622 56 10.3802Z"
|
d="M39.5461 16.5714L47.4286 24.4539M16.1429 37.5714L26.4286 47.8571M56 10.3802L53.6198 8C32.2378 20.0846 22.0873 28.6952 8 48.0661C8.13223 48.595 8.63471 50.2876 11.1736 52.8264C13.7124 55.3653 15.405 55.8678 15.9339 56C35.3048 41.9127 43.9154 31.7622 56 10.3802Z"
|
||||||
stroke="currentColor"
|
stroke="currentColor"
|
||||||
stroke-width="4"
|
strokeWidth="4"
|
||||||
stroke-linecap="round"
|
strokeLinecap="round"
|
||||||
stroke-linejoin="round"
|
stroke-linejoin="round"
|
||||||
/>
|
/>
|
||||||
</svg>
|
</svg>
|
||||||
|
|||||||
+17
-8
@@ -5,14 +5,17 @@ import { Suspense } from 'react';
|
|||||||
import { useLocale } from '../../../../../../hooks/useLocale';
|
import { useLocale } from '../../../../../../hooks/useLocale';
|
||||||
import { TankopediaEphemeral } from '../../../../../../stores/tankopediaEphemeral';
|
import { TankopediaEphemeral } from '../../../../../../stores/tankopediaEphemeral';
|
||||||
import { TankopediaPersistent } from '../../../../../../stores/tankopediaPersistent';
|
import { TankopediaPersistent } from '../../../../../../stores/tankopediaPersistent';
|
||||||
|
import { TankopediaDisplay } from '../../../../../../stores/tankopediaPersistent/constants';
|
||||||
|
import type { MaybeSkeletonComponentProps } from '../../../../../../types/maybeSkeletonComponentProps';
|
||||||
import type { ThicknessRange } from '../../../../../Armor/components/StaticArmor';
|
import type { ThicknessRange } from '../../../../../Armor/components/StaticArmor';
|
||||||
import { DynamicArmorSwitcher } from './DynamicArmorSwitcher';
|
import { DynamicArmorSwitcher } from './DynamicArmorSwitcher';
|
||||||
|
|
||||||
interface ThicknessesProps {
|
type ThicknessesProps = MaybeSkeletonComponentProps & {
|
||||||
thicknessRange: ThicknessRange;
|
thicknessRange: ThicknessRange;
|
||||||
}
|
};
|
||||||
|
|
||||||
export function Thicknesses({ thicknessRange }: ThicknessesProps) {
|
export function Thicknesses({ thicknessRange, skeleton }: ThicknessesProps) {
|
||||||
|
const display = TankopediaEphemeral.use((state) => state.display);
|
||||||
const showExternalModules = TankopediaPersistent.use(
|
const showExternalModules = TankopediaPersistent.use(
|
||||||
(state) => state.showExternalModules,
|
(state) => state.showExternalModules,
|
||||||
);
|
);
|
||||||
@@ -31,10 +34,14 @@ export function Thicknesses({ thicknessRange }: ThicknessesProps) {
|
|||||||
return (
|
return (
|
||||||
<Flex
|
<Flex
|
||||||
position="absolute"
|
position="absolute"
|
||||||
right="0"
|
right={display === TankopediaDisplay.StaticArmor ? '0' : '-6rem'}
|
||||||
top="50%"
|
top="50%"
|
||||||
mr="4"
|
mr="4"
|
||||||
style={{ transform: 'translateY(-50%)', userSelect: 'none' }}
|
style={{
|
||||||
|
transform: 'translateY(-50%)',
|
||||||
|
userSelect: 'none',
|
||||||
|
transitionDuration: '200ms',
|
||||||
|
}}
|
||||||
direction="column"
|
direction="column"
|
||||||
gap="5"
|
gap="5"
|
||||||
align="end"
|
align="end"
|
||||||
@@ -190,9 +197,11 @@ export function Thicknesses({ thicknessRange }: ThicknessesProps) {
|
|||||||
</Button>
|
</Button>
|
||||||
</Flex>
|
</Flex>
|
||||||
|
|
||||||
<Suspense>
|
{!skeleton && (
|
||||||
<DynamicArmorSwitcher />
|
<Suspense>
|
||||||
</Suspense>
|
<DynamicArmorSwitcher />
|
||||||
|
</Suspense>
|
||||||
|
)}
|
||||||
</Flex>
|
</Flex>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
+257
-255
@@ -42,6 +42,7 @@ import {
|
|||||||
} from '../../../../../stores/tankopediaEphemeral';
|
} from '../../../../../stores/tankopediaEphemeral';
|
||||||
import { TankopediaPersistent } from '../../../../../stores/tankopediaPersistent';
|
import { TankopediaPersistent } from '../../../../../stores/tankopediaPersistent';
|
||||||
import { TankopediaDisplay } from '../../../../../stores/tankopediaPersistent/constants';
|
import { TankopediaDisplay } from '../../../../../stores/tankopediaPersistent/constants';
|
||||||
|
import type { MaybeSkeletonComponentProps } from '../../../../../types/maybeSkeletonComponentProps';
|
||||||
import type { ThicknessRange } from '../../../../Armor/components/StaticArmor';
|
import type { ThicknessRange } from '../../../../Armor/components/StaticArmor';
|
||||||
import { ModuleButton } from '../../../../ModuleButtons/ModuleButton';
|
import { ModuleButton } from '../../../../ModuleButtons/ModuleButton';
|
||||||
import { SmallTankIcon } from '../../../../SmallTankIcon';
|
import { SmallTankIcon } from '../../../../SmallTankIcon';
|
||||||
@@ -51,12 +52,12 @@ import { DynamicArmorSwitcher } from './components/DynamicArmorSwitcher';
|
|||||||
import { QuickInputs } from './components/QuickInputs';
|
import { QuickInputs } from './components/QuickInputs';
|
||||||
import { Thicknesses } from './components/Thicknesses';
|
import { Thicknesses } from './components/Thicknesses';
|
||||||
|
|
||||||
interface OptionsProps {
|
type OptionsProps = MaybeSkeletonComponentProps & {
|
||||||
thicknessRange: ThicknessRange;
|
thicknessRange: ThicknessRange;
|
||||||
canvas: RefObject<HTMLCanvasElement>;
|
canvas: RefObject<HTMLCanvasElement>;
|
||||||
}
|
};
|
||||||
|
|
||||||
export function Options({ thicknessRange, canvas }: OptionsProps) {
|
export function Options({ thicknessRange, canvas, skeleton }: OptionsProps) {
|
||||||
const hasCustomShell = TankopediaEphemeral.use(
|
const hasCustomShell = TankopediaEphemeral.use(
|
||||||
(state) => state.customShell !== undefined,
|
(state) => state.customShell !== undefined,
|
||||||
);
|
);
|
||||||
@@ -111,216 +112,212 @@ export function Options({ thicknessRange, canvas }: OptionsProps) {
|
|||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
{display === TankopediaDisplay.StaticArmor && (
|
<Thicknesses skeleton={skeleton} thicknessRange={thicknessRange} />
|
||||||
<Thicknesses thicknessRange={thicknessRange} />
|
|
||||||
)}
|
|
||||||
|
|
||||||
{display === TankopediaDisplay.DynamicArmor && (
|
<Flex
|
||||||
<Flex
|
gap="2"
|
||||||
gap="2"
|
direction="column"
|
||||||
direction="column"
|
top="50%"
|
||||||
top="50%"
|
right={display === TankopediaDisplay.DynamicArmor ? '3' : '-3rem'}
|
||||||
right="3"
|
style={{
|
||||||
style={{ position: 'absolute', transform: 'translateY(-50%)' }}
|
position: 'absolute',
|
||||||
align="end"
|
transform: 'translateY(-50%)',
|
||||||
>
|
transitionDuration: '200ms',
|
||||||
{!hasCustomShell && (
|
}}
|
||||||
<Text color="gray" size={{ initial: '1', sm: '2' }}>
|
align="end"
|
||||||
{literals(strings.common.units.mm, [
|
>
|
||||||
(
|
{!hasCustomShell && (
|
||||||
resolvePenetrationCoefficient(
|
<Text color="gray" size={{ initial: '1', sm: '2' }}>
|
||||||
hasCalibratedShells,
|
{literals(strings.common.units.mm, [
|
||||||
antagonistShell.type,
|
(
|
||||||
) * antagonistShell.penetration.near
|
resolvePenetrationCoefficient(
|
||||||
).toFixed(0),
|
hasCalibratedShells,
|
||||||
])}
|
antagonistShell.type,
|
||||||
</Text>
|
) * antagonistShell.penetration.near
|
||||||
)}
|
).toFixed(0),
|
||||||
{antagonistUniqueGuns.length > 1 && (
|
])}
|
||||||
<Popover.Root>
|
</Text>
|
||||||
<Popover.Trigger>
|
)}
|
||||||
<IconButton
|
|
||||||
radius="full"
|
|
||||||
variant="soft"
|
|
||||||
color="gray"
|
|
||||||
size={{ initial: '2', sm: '3' }}
|
|
||||||
style={{ position: 'relative' }}
|
|
||||||
>
|
|
||||||
<Text
|
|
||||||
size="1"
|
|
||||||
color="gray"
|
|
||||||
style={{
|
|
||||||
position: 'absolute',
|
|
||||||
right: 0,
|
|
||||||
bottom: 0,
|
|
||||||
}}
|
|
||||||
mr="2"
|
|
||||||
mb="1"
|
|
||||||
>
|
|
||||||
{
|
|
||||||
TIER_ROMAN_NUMERALS[
|
|
||||||
antagonistGun.gun_type!.value.base.tier
|
|
||||||
]
|
|
||||||
}
|
|
||||||
</Text>
|
|
||||||
|
|
||||||
<img
|
{antagonistUniqueGuns.length > 1 && (
|
||||||
alt="Antagonist Gun"
|
<Popover.Root>
|
||||||
src={asset('icons/modules/gun.webp')}
|
<Popover.Trigger>
|
||||||
style={{
|
|
||||||
width: '65%',
|
|
||||||
height: '65%',
|
|
||||||
objectFit: 'contain',
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
</IconButton>
|
|
||||||
</Popover.Trigger>
|
|
||||||
|
|
||||||
<Popover.Content side="left" align="center">
|
|
||||||
<Flex gap="2">
|
|
||||||
{[...antagonistUniqueGuns]
|
|
||||||
.reverse()
|
|
||||||
.map(({ gun, turret }) => (
|
|
||||||
<ModuleButton
|
|
||||||
module="gun"
|
|
||||||
key={gun.gun_type!.value.base.id}
|
|
||||||
onClick={() =>
|
|
||||||
mutateDuel((draft) => {
|
|
||||||
draft.antagonist.turret = turret;
|
|
||||||
draft.antagonist.gun = gun;
|
|
||||||
draft.antagonist.shell =
|
|
||||||
gun.gun_type!.value.base.shells[0];
|
|
||||||
})
|
|
||||||
}
|
|
||||||
selected={
|
|
||||||
gun.gun_type!.value.base.id ===
|
|
||||||
antagonistGun.gun_type!.value.base.id
|
|
||||||
}
|
|
||||||
discriminator={
|
|
||||||
TIER_ROMAN_NUMERALS[gun.gun_type!.value.base.tier]
|
|
||||||
}
|
|
||||||
secondaryDiscriminator={
|
|
||||||
<Text style={{ fontSize: '0.75em' }}>
|
|
||||||
{literals(strings.common.units.mm, [
|
|
||||||
gun.gun_type!.value.base.shells[0].caliber.toFixed(
|
|
||||||
0,
|
|
||||||
),
|
|
||||||
])}
|
|
||||||
</Text>
|
|
||||||
}
|
|
||||||
/>
|
|
||||||
))}
|
|
||||||
</Flex>
|
|
||||||
</Popover.Content>
|
|
||||||
</Popover.Root>
|
|
||||||
)}
|
|
||||||
<Flex
|
|
||||||
direction="column"
|
|
||||||
style={{
|
|
||||||
borderRadius: 'var(--radius-full)',
|
|
||||||
}}
|
|
||||||
overflow="hidden"
|
|
||||||
>
|
|
||||||
{antagonistGun.gun_type!.value.base.shells.map((thisShell) => (
|
|
||||||
<IconButton
|
<IconButton
|
||||||
color={
|
radius="full"
|
||||||
thisShell.id === antagonistShell.id && !hasCustomShell
|
|
||||||
? undefined
|
|
||||||
: 'gray'
|
|
||||||
}
|
|
||||||
variant="soft"
|
variant="soft"
|
||||||
key={thisShell.id}
|
color="gray"
|
||||||
size={{ initial: '2', sm: '3' }}
|
size={{ initial: '2', sm: '3' }}
|
||||||
radius="none"
|
style={{ position: 'relative' }}
|
||||||
onClick={() => {
|
|
||||||
mutateDuel((draft) => {
|
|
||||||
draft.antagonist.shell = thisShell;
|
|
||||||
});
|
|
||||||
mutateTankopediaEphemeral((draft) => {
|
|
||||||
draft.shot = undefined;
|
|
||||||
draft.customShell = undefined;
|
|
||||||
});
|
|
||||||
}}
|
|
||||||
>
|
>
|
||||||
<img
|
<Text
|
||||||
alt={unwrap(thisShell.name)}
|
size="1"
|
||||||
src={asset(`icons/shells/${thisShell.icon}.webp`)}
|
color="gray"
|
||||||
style={{
|
style={{
|
||||||
width: '50%',
|
position: 'absolute',
|
||||||
height: '50%',
|
right: 0,
|
||||||
|
bottom: 0,
|
||||||
|
}}
|
||||||
|
mr="2"
|
||||||
|
mb="1"
|
||||||
|
>
|
||||||
|
{TIER_ROMAN_NUMERALS[antagonistGun.gun_type!.value.base.tier]}
|
||||||
|
</Text>
|
||||||
|
|
||||||
|
<img
|
||||||
|
alt="Antagonist Gun"
|
||||||
|
src={asset('icons/modules/gun.webp')}
|
||||||
|
style={{
|
||||||
|
width: '65%',
|
||||||
|
height: '65%',
|
||||||
|
objectFit: 'contain',
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
</IconButton>
|
</IconButton>
|
||||||
))}
|
</Popover.Trigger>
|
||||||
|
|
||||||
<CustomShellButton />
|
<Popover.Content side="left" align="center">
|
||||||
</Flex>
|
<Flex gap="2">
|
||||||
|
{[...antagonistUniqueGuns].reverse().map(({ gun, turret }) => (
|
||||||
|
<ModuleButton
|
||||||
|
module="gun"
|
||||||
|
key={gun.gun_type!.value.base.id}
|
||||||
|
onClick={() =>
|
||||||
|
mutateDuel((draft) => {
|
||||||
|
draft.antagonist.turret = turret;
|
||||||
|
draft.antagonist.gun = gun;
|
||||||
|
draft.antagonist.shell =
|
||||||
|
gun.gun_type!.value.base.shells[0];
|
||||||
|
})
|
||||||
|
}
|
||||||
|
selected={
|
||||||
|
gun.gun_type!.value.base.id ===
|
||||||
|
antagonistGun.gun_type!.value.base.id
|
||||||
|
}
|
||||||
|
discriminator={
|
||||||
|
TIER_ROMAN_NUMERALS[gun.gun_type!.value.base.tier]
|
||||||
|
}
|
||||||
|
secondaryDiscriminator={
|
||||||
|
<Text style={{ fontSize: '0.75em' }}>
|
||||||
|
{literals(strings.common.units.mm, [
|
||||||
|
gun.gun_type!.value.base.shells[0].caliber.toFixed(0),
|
||||||
|
])}
|
||||||
|
</Text>
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
))}
|
||||||
|
</Flex>
|
||||||
|
</Popover.Content>
|
||||||
|
</Popover.Root>
|
||||||
|
)}
|
||||||
|
|
||||||
<Flex
|
<Flex
|
||||||
direction="column"
|
direction="column"
|
||||||
style={{
|
style={{
|
||||||
pointerEvents: 'auto',
|
borderRadius: 'var(--radius-full)',
|
||||||
borderRadius: 'var(--radius-full)',
|
}}
|
||||||
|
overflow="hidden"
|
||||||
|
>
|
||||||
|
{antagonistGun.gun_type!.value.base.shells.map((thisShell) => (
|
||||||
|
<IconButton
|
||||||
|
color={
|
||||||
|
thisShell.id === antagonistShell.id && !hasCustomShell
|
||||||
|
? undefined
|
||||||
|
: 'gray'
|
||||||
|
}
|
||||||
|
variant="soft"
|
||||||
|
key={thisShell.id}
|
||||||
|
size={{ initial: '2', sm: '3' }}
|
||||||
|
radius="none"
|
||||||
|
onClick={() => {
|
||||||
|
mutateDuel((draft) => {
|
||||||
|
draft.antagonist.shell = thisShell;
|
||||||
|
});
|
||||||
|
mutateTankopediaEphemeral((draft) => {
|
||||||
|
draft.shot = undefined;
|
||||||
|
draft.customShell = undefined;
|
||||||
|
});
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<img
|
||||||
|
alt={unwrap(thisShell.name)}
|
||||||
|
src={asset(`icons/shells/${thisShell.icon}.webp`)}
|
||||||
|
style={{
|
||||||
|
width: '50%',
|
||||||
|
height: '50%',
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
</IconButton>
|
||||||
|
))}
|
||||||
|
|
||||||
|
<CustomShellButton />
|
||||||
|
</Flex>
|
||||||
|
|
||||||
|
<Flex
|
||||||
|
direction="column"
|
||||||
|
style={{
|
||||||
|
pointerEvents: 'auto',
|
||||||
|
borderRadius: 'var(--radius-full)',
|
||||||
|
}}
|
||||||
|
overflow="hidden"
|
||||||
|
>
|
||||||
|
<IconButton
|
||||||
|
color={hasCalibratedShells ? undefined : 'gray'}
|
||||||
|
variant="soft"
|
||||||
|
size={{ initial: '2', sm: '3' }}
|
||||||
|
radius="none"
|
||||||
|
onClick={() => {
|
||||||
|
mutateDuel((draft) => {
|
||||||
|
draft.antagonist.equipmentMatrix[0][0] = hasCalibratedShells
|
||||||
|
? 0
|
||||||
|
: 1;
|
||||||
|
});
|
||||||
|
mutateTankopediaEphemeral((draft) => {
|
||||||
|
draft.shot = undefined;
|
||||||
|
});
|
||||||
}}
|
}}
|
||||||
overflow="hidden"
|
|
||||||
>
|
>
|
||||||
<IconButton
|
<img
|
||||||
color={hasCalibratedShells ? undefined : 'gray'}
|
alt="Calibrated Shells"
|
||||||
variant="soft"
|
src={asset('icons/equipment/103.webp')}
|
||||||
size={{ initial: '2', sm: '3' }}
|
style={{
|
||||||
radius="none"
|
width: '50%',
|
||||||
onClick={() => {
|
height: '50%',
|
||||||
mutateDuel((draft) => {
|
|
||||||
draft.antagonist.equipmentMatrix[0][0] = hasCalibratedShells
|
|
||||||
? 0
|
|
||||||
: 1;
|
|
||||||
});
|
|
||||||
mutateTankopediaEphemeral((draft) => {
|
|
||||||
draft.shot = undefined;
|
|
||||||
});
|
|
||||||
}}
|
}}
|
||||||
>
|
/>
|
||||||
<img
|
</IconButton>
|
||||||
alt="Calibrated Shells"
|
<IconButton
|
||||||
src={asset('icons/equipment/103.webp')}
|
color={hasEnhancedArmor ? undefined : 'gray'}
|
||||||
style={{
|
variant="soft"
|
||||||
width: '50%',
|
size={{ initial: '2', sm: '3' }}
|
||||||
height: '50%',
|
radius="none"
|
||||||
}}
|
onClick={() => {
|
||||||
/>
|
mutateDuel((draft) => {
|
||||||
</IconButton>
|
draft.protagonist.equipmentMatrix[1][1] = hasEnhancedArmor
|
||||||
<IconButton
|
? 0
|
||||||
color={hasEnhancedArmor ? undefined : 'gray'}
|
: -1;
|
||||||
variant="soft"
|
});
|
||||||
size={{ initial: '2', sm: '3' }}
|
mutateTankopediaEphemeral((draft) => {
|
||||||
radius="none"
|
draft.shot = undefined;
|
||||||
onClick={() => {
|
});
|
||||||
mutateDuel((draft) => {
|
}}
|
||||||
draft.protagonist.equipmentMatrix[1][1] = hasEnhancedArmor
|
>
|
||||||
? 0
|
<img
|
||||||
: -1;
|
alt="Enhanced Armor"
|
||||||
});
|
src={asset('icons/equipment/110.webp')}
|
||||||
mutateTankopediaEphemeral((draft) => {
|
style={{
|
||||||
draft.shot = undefined;
|
width: '50%',
|
||||||
});
|
height: '50%',
|
||||||
}}
|
}}
|
||||||
>
|
/>
|
||||||
<img
|
</IconButton>
|
||||||
alt="Enhanced Armor"
|
</Flex>
|
||||||
src={asset('icons/equipment/110.webp')}
|
|
||||||
style={{
|
|
||||||
width: '50%',
|
|
||||||
height: '50%',
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
</IconButton>
|
|
||||||
</Flex>
|
|
||||||
|
|
||||||
|
{!skeleton && (
|
||||||
<Suspense>
|
<Suspense>
|
||||||
<DynamicArmorSwitcher />
|
<DynamicArmorSwitcher />
|
||||||
</Suspense>
|
</Suspense>
|
||||||
</Flex>
|
)}
|
||||||
)}
|
</Flex>
|
||||||
|
|
||||||
<Flex
|
<Flex
|
||||||
direction="column"
|
direction="column"
|
||||||
@@ -330,72 +327,77 @@ export function Options({ thicknessRange, canvas }: OptionsProps) {
|
|||||||
left="50%"
|
left="50%"
|
||||||
style={{ transform: 'translateX(-50%)' }}
|
style={{ transform: 'translateX(-50%)' }}
|
||||||
>
|
>
|
||||||
{display === TankopediaDisplay.DynamicArmor && (
|
<Flex
|
||||||
<>
|
direction="column"
|
||||||
<Flex
|
align="center"
|
||||||
align="center"
|
style={{ transitionDuration: '200ms' }}
|
||||||
gap="2"
|
position="relative"
|
||||||
mb="1"
|
bottom={display === TankopediaDisplay.DynamicArmor ? '0' : '-7rem'}
|
||||||
style={{ cursor: 'pointer' }}
|
>
|
||||||
onClick={() => {
|
<Flex
|
||||||
mutateTankopediaPersistent((draft) => {
|
align="center"
|
||||||
draft.advancedHighlighting = !draft.advancedHighlighting;
|
gap="2"
|
||||||
});
|
mb="1"
|
||||||
}}
|
style={{ cursor: 'pointer' }}
|
||||||
|
onClick={() => {
|
||||||
|
mutateTankopediaPersistent((draft) => {
|
||||||
|
draft.advancedHighlighting = !draft.advancedHighlighting;
|
||||||
|
});
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<Checkbox checked={advancedHighlighting} />
|
||||||
|
<Text color="gray" size="2">
|
||||||
|
{strings.website.tools.tankopedia.sandbox.dynamic.advanced}
|
||||||
|
</Text>
|
||||||
|
</Flex>
|
||||||
|
|
||||||
|
<Flex align="center" gap="2">
|
||||||
|
<Text color="gray" size="2">
|
||||||
|
{strings.website.tools.tankopedia.sandbox.dynamic.shooter}
|
||||||
|
</Text>
|
||||||
|
<Dialog.Root
|
||||||
|
open={antagonistSelectorOpen}
|
||||||
|
onOpenChange={setAntagonistSelectorOpen}
|
||||||
>
|
>
|
||||||
<Checkbox checked={advancedHighlighting} />
|
<Dialog.Trigger>
|
||||||
<Text color="gray" size="2">
|
<Button variant="ghost">
|
||||||
{strings.website.tools.tankopedia.sandbox.dynamic.advanced}
|
<Flex gap="2" align="center">
|
||||||
</Text>
|
<SmallTankIcon id={antagonistTank.id} size={16} />
|
||||||
</Flex>
|
{unwrap(antagonistTank.name)}
|
||||||
|
</Flex>
|
||||||
|
</Button>
|
||||||
|
</Dialog.Trigger>
|
||||||
|
|
||||||
<Flex align="center" gap="2">
|
<Dialog.Content>
|
||||||
<Text color="gray" size="2">
|
<Dialog.Title align="center">Select tank</Dialog.Title>
|
||||||
{strings.website.tools.tankopedia.sandbox.dynamic.shooter}
|
|
||||||
</Text>
|
|
||||||
<Dialog.Root
|
|
||||||
open={antagonistSelectorOpen}
|
|
||||||
onOpenChange={setAntagonistSelectorOpen}
|
|
||||||
>
|
|
||||||
<Dialog.Trigger>
|
|
||||||
<Button variant="ghost">
|
|
||||||
<Flex gap="2" align="center">
|
|
||||||
<SmallTankIcon id={antagonistTank.id} size={16} />
|
|
||||||
{unwrap(antagonistTank.name)}
|
|
||||||
</Flex>
|
|
||||||
</Button>
|
|
||||||
</Dialog.Trigger>
|
|
||||||
|
|
||||||
<Dialog.Content>
|
<Tabs.Root
|
||||||
<Dialog.Title align="center">Select tank</Dialog.Title>
|
value={tab}
|
||||||
|
onValueChange={setTab}
|
||||||
|
style={{ position: 'relative' }}
|
||||||
|
>
|
||||||
|
<TankSearch
|
||||||
|
compact
|
||||||
|
onSelect={(tank) => {
|
||||||
|
mutateDuel((draft) => {
|
||||||
|
draft.antagonist.tank = tank;
|
||||||
|
draft.antagonist.engine = tank.engines.at(-1)!;
|
||||||
|
draft.antagonist.track = tank.tracks.at(-1)!;
|
||||||
|
draft.antagonist.turret = tank.turrets.at(-1)!;
|
||||||
|
draft.antagonist.gun =
|
||||||
|
draft.antagonist.turret.guns.at(-1)!;
|
||||||
|
draft.antagonist.shell =
|
||||||
|
draft.antagonist.gun.gun_type!.value.base.shells[0];
|
||||||
|
});
|
||||||
|
setAntagonistSelectorOpen(false);
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
</Tabs.Root>
|
||||||
|
</Dialog.Content>
|
||||||
|
</Dialog.Root>
|
||||||
|
</Flex>
|
||||||
|
</Flex>
|
||||||
|
|
||||||
<Tabs.Root
|
|
||||||
value={tab}
|
|
||||||
onValueChange={setTab}
|
|
||||||
style={{ position: 'relative' }}
|
|
||||||
>
|
|
||||||
<TankSearch
|
|
||||||
compact
|
|
||||||
onSelect={(tank) => {
|
|
||||||
mutateDuel((draft) => {
|
|
||||||
draft.antagonist.tank = tank;
|
|
||||||
draft.antagonist.engine = tank.engines.at(-1)!;
|
|
||||||
draft.antagonist.track = tank.tracks.at(-1)!;
|
|
||||||
draft.antagonist.turret = tank.turrets.at(-1)!;
|
|
||||||
draft.antagonist.gun =
|
|
||||||
draft.antagonist.turret.guns.at(-1)!;
|
|
||||||
draft.antagonist.shell =
|
|
||||||
draft.antagonist.gun.gun_type!.value.base.shells[0];
|
|
||||||
});
|
|
||||||
setAntagonistSelectorOpen(false);
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
</Tabs.Root>
|
|
||||||
</Dialog.Content>
|
|
||||||
</Dialog.Root>
|
|
||||||
</Flex>
|
|
||||||
</>
|
|
||||||
)}
|
|
||||||
<Flex gap="3" align="center" mt="2">
|
<Flex gap="3" align="center" mt="2">
|
||||||
<SegmentedControl.Root
|
<SegmentedControl.Root
|
||||||
value={`${display}`}
|
value={`${display}`}
|
||||||
|
|||||||
@@ -101,7 +101,7 @@ export function HeroSection({ skeleton }: MaybeSkeletonComponentProps) {
|
|||||||
style={{ transform: 'translateY(-50%)', transitionDuration: '200ms' }}
|
style={{ transform: 'translateY(-50%)', transitionDuration: '200ms' }}
|
||||||
direction="column"
|
direction="column"
|
||||||
align={{ initial: 'center', md: 'start' }}
|
align={{ initial: 'center', md: 'start' }}
|
||||||
gap={disturbed ? '0' : '2'}
|
gap={disturbed ? '0' : { initial: '0', md: '2' }}
|
||||||
>
|
>
|
||||||
<Flex align="center" gap="3">
|
<Flex align="center" gap="3">
|
||||||
<Heading
|
<Heading
|
||||||
@@ -139,7 +139,7 @@ export function HeroSection({ skeleton }: MaybeSkeletonComponentProps) {
|
|||||||
weight="light"
|
weight="light"
|
||||||
ml={{
|
ml={{
|
||||||
initial: '0',
|
initial: '0',
|
||||||
md: '8',
|
md: disturbed ? 'var(--font-size-7)' : 'var(--font-size-8)',
|
||||||
lg: disturbed ? 'var(--font-size-8)' : 'var(--font-size-9)',
|
lg: disturbed ? 'var(--font-size-8)' : 'var(--font-size-9)',
|
||||||
}}
|
}}
|
||||||
style={{ transitionDuration: '200ms' }}
|
style={{ transitionDuration: '200ms' }}
|
||||||
@@ -161,7 +161,7 @@ export function HeroSection({ skeleton }: MaybeSkeletonComponentProps) {
|
|||||||
width="100%"
|
width="100%"
|
||||||
height="100%"
|
height="100%"
|
||||||
position="relative"
|
position="relative"
|
||||||
left={disturbed ? '0' : '12.5%'}
|
left={disturbed ? '0' : { initial: '0', md: '12.5%' }}
|
||||||
style={{ transitionDuration: '200ms' }}
|
style={{ transitionDuration: '200ms' }}
|
||||||
>
|
>
|
||||||
{skeleton && <TankSandboxLoader id={protagonist.id} />}
|
{skeleton && <TankSandboxLoader id={protagonist.id} />}
|
||||||
@@ -171,7 +171,11 @@ export function HeroSection({ skeleton }: MaybeSkeletonComponentProps) {
|
|||||||
</Suspense>
|
</Suspense>
|
||||||
</Box>
|
</Box>
|
||||||
|
|
||||||
<Options canvas={canvas} thicknessRange={thicknessRange} />
|
<Options
|
||||||
|
skeleton={skeleton}
|
||||||
|
canvas={canvas}
|
||||||
|
thicknessRange={thicknessRange}
|
||||||
|
/>
|
||||||
</Box>
|
</Box>
|
||||||
</Box>
|
</Box>
|
||||||
</Flex>
|
</Flex>
|
||||||
|
|||||||
Reference in new issue
Block a user