mirror of
https://github.com/blitzkit/blitzkit.git
synced 2026-10-23 19:49:50 +02:00
feat: left sided name
This commit is contained in:
1 parent
8b183269d1
commit
4f80169f9b
5 files changed
+128
-114
No files matched your search
@@ -11,7 +11,7 @@ import { useAwait } from '../../../../../hooks/useAwait';
|
|||||||
import * as Duel from '../../../../../stores/duel';
|
import * as Duel from '../../../../../stores/duel';
|
||||||
import * as TankopediaEphemeral from '../../../../../stores/tankopediaEphemeral';
|
import * as TankopediaEphemeral from '../../../../../stores/tankopediaEphemeral';
|
||||||
|
|
||||||
const initialPosition = [0, 5, -16] as const;
|
const initialPosition = [0, 6, -32] as const;
|
||||||
const poseDistances: Record<Pose, number> = {
|
const poseDistances: Record<Pose, number> = {
|
||||||
[Pose.HullDown]: 15,
|
[Pose.HullDown]: 15,
|
||||||
[Pose.FaceHug]: 5,
|
[Pose.FaceHug]: 5,
|
||||||
|
|||||||
@@ -53,72 +53,87 @@ export function HeroSection({ id }: HeroSectionProps) {
|
|||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Box
|
<Flex justify="center" style={{ backgroundColor: Var('color-surface') }}>
|
||||||
style={{
|
|
||||||
background: isFullScreen
|
|
||||||
? Var('color-background')
|
|
||||||
: Var('color-surface'),
|
|
||||||
zIndex: isFullScreen ? 2 : undefined,
|
|
||||||
}}
|
|
||||||
height={
|
|
||||||
isFullScreen ? '100vh' : `calc(100vh - ${NAVBAR_HEIGHT}px - 8rem)`
|
|
||||||
}
|
|
||||||
width={isFullScreen ? '100vw' : undefined}
|
|
||||||
position={isFullScreen ? 'fixed' : 'relative'}
|
|
||||||
top={isFullScreen ? '0' : undefined}
|
|
||||||
left={isFullScreen ? '0' : undefined}
|
|
||||||
>
|
|
||||||
<Flex
|
|
||||||
position="absolute"
|
|
||||||
width="100%"
|
|
||||||
height="100%"
|
|
||||||
align="center"
|
|
||||||
direction="column"
|
|
||||||
mt="7"
|
|
||||||
>
|
|
||||||
<Heading
|
|
||||||
weight="bold"
|
|
||||||
size={{ initial: '8', xs: '9' }}
|
|
||||||
color={treeColor}
|
|
||||||
>
|
|
||||||
<Flex align="center" gap="3">
|
|
||||||
<Icon width="0.75em" height="0.75em" />
|
|
||||||
{tank.name}
|
|
||||||
</Flex>
|
|
||||||
</Heading>
|
|
||||||
<Text color="gray" weight="light" mt="1">
|
|
||||||
BlitzKit Tankopedia
|
|
||||||
</Text>
|
|
||||||
</Flex>
|
|
||||||
|
|
||||||
<Box
|
<Box
|
||||||
position="absolute"
|
style={{
|
||||||
width="100%"
|
backgroundColor: isFullScreen
|
||||||
height="100%"
|
? Var('color-background')
|
||||||
className="tank-sandbox-container"
|
: Var('color-surface'),
|
||||||
|
zIndex: isFullScreen ? 2 : undefined,
|
||||||
|
}}
|
||||||
|
height={
|
||||||
|
isFullScreen ? '100vh' : `calc(100vh - ${NAVBAR_HEIGHT}px - 8rem)`
|
||||||
|
}
|
||||||
|
maxHeight="40rem"
|
||||||
|
maxWidth="120rem"
|
||||||
|
flexGrow="1"
|
||||||
|
width={isFullScreen ? '100vw' : undefined}
|
||||||
|
position={isFullScreen ? 'fixed' : 'relative'}
|
||||||
|
top={isFullScreen ? '0' : undefined}
|
||||||
|
left={isFullScreen ? '0' : undefined}
|
||||||
>
|
>
|
||||||
<Box width="100%" height="100%" position="absolute">
|
<Flex
|
||||||
<Box width="100%" height="100%">
|
position="absolute"
|
||||||
<TankSandboxLoader
|
justify={{ initial: 'center', md: 'start' }}
|
||||||
id={id}
|
width="100%"
|
||||||
display={dummyLoader ? 'flex' : 'none'}
|
mt={{ initial: '6', md: '-8' }}
|
||||||
/>
|
top={{ initial: '0', md: '50%' }}
|
||||||
|
left={{ initial: '-4', md: '0' }}
|
||||||
<Suspense
|
pl={{ initial: '0', md: '8' }}
|
||||||
fallback={
|
>
|
||||||
<TankSandboxLoader
|
<Flex direction="column" align={{ initial: 'center', md: 'start' }}>
|
||||||
id={id}
|
<Heading
|
||||||
display={dummyLoader ? 'none' : 'flex'}
|
weight="bold"
|
||||||
/>
|
size={{ initial: '8', xl: '9' }}
|
||||||
}
|
wrap="nowrap"
|
||||||
|
color={treeColor}
|
||||||
>
|
>
|
||||||
<TankSandbox ref={canvas} thicknessRange={thicknessRange} />
|
<Flex align="center" gap="3">
|
||||||
</Suspense>
|
<Icon width="0.8em" height="0.8em" />
|
||||||
</Box>
|
{tank.name}
|
||||||
|
</Flex>
|
||||||
|
</Heading>
|
||||||
|
|
||||||
<Options canvas={canvas} thicknessRange={thicknessRange} />
|
<Text
|
||||||
|
color="gray"
|
||||||
|
size="3"
|
||||||
|
weight="light"
|
||||||
|
ml={{ initial: '0', md: '7', xl: '9' }}
|
||||||
|
>
|
||||||
|
BlitzKit Tankopedia
|
||||||
|
</Text>
|
||||||
|
</Flex>
|
||||||
|
</Flex>
|
||||||
|
|
||||||
|
<Box
|
||||||
|
position="absolute"
|
||||||
|
width="100%"
|
||||||
|
height="100%"
|
||||||
|
className="tank-sandbox-container"
|
||||||
|
>
|
||||||
|
<Box width="100%" height="100%" position="absolute">
|
||||||
|
<Box width="100%" height="100%">
|
||||||
|
<TankSandboxLoader
|
||||||
|
id={id}
|
||||||
|
display={dummyLoader ? 'flex' : 'none'}
|
||||||
|
/>
|
||||||
|
|
||||||
|
<Suspense
|
||||||
|
fallback={
|
||||||
|
<TankSandboxLoader
|
||||||
|
id={id}
|
||||||
|
display={dummyLoader ? 'none' : 'flex'}
|
||||||
|
/>
|
||||||
|
}
|
||||||
|
>
|
||||||
|
<TankSandbox ref={canvas} thicknessRange={thicknessRange} />
|
||||||
|
</Suspense>
|
||||||
|
</Box>
|
||||||
|
|
||||||
|
<Options canvas={canvas} thicknessRange={thicknessRange} />
|
||||||
|
</Box>
|
||||||
</Box>
|
</Box>
|
||||||
</Box>
|
</Box>
|
||||||
</Box>
|
</Flex>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@@ -1,6 +1,8 @@
|
|||||||
import { Code, Flex } from '@radix-ui/themes';
|
import { ChevronLeftIcon, MixIcon } from '@radix-ui/react-icons';
|
||||||
|
import { Button, Code, Flex } from '@radix-ui/themes';
|
||||||
import { Suspense } from 'react';
|
import { Suspense } from 'react';
|
||||||
import { classIcons } from '../../../../../../../components/ClassIcon';
|
import { classIcons } from '../../../../../../../components/ClassIcon';
|
||||||
|
import { Link } from '../../../../../../../components/Link';
|
||||||
import { asset } from '../../../../../../../core/blitzkit/asset';
|
import { asset } from '../../../../../../../core/blitzkit/asset';
|
||||||
import strings from '../../../../../../../lang/en-US.json';
|
import strings from '../../../../../../../lang/en-US.json';
|
||||||
import * as App from '../../../../../../../stores/app';
|
import * as App from '../../../../../../../stores/app';
|
||||||
@@ -11,27 +13,48 @@ import { VotesSkeleton } from './components/VotesSkeleton';
|
|||||||
|
|
||||||
export function MetaSection() {
|
export function MetaSection() {
|
||||||
const developerMode = App.useDeferred(false, (state) => state.developerMode);
|
const developerMode = App.useDeferred(false, (state) => state.developerMode);
|
||||||
const tank = Duel.use((state) => state.protagonist.tank);
|
const protagonist = Duel.use((state) => state.protagonist.tank);
|
||||||
const ClassIcon = classIcons[tank.class];
|
const ClassIcon = classIcons[protagonist.class];
|
||||||
|
const antagonist = Duel.use((state) => state.antagonist.tank);
|
||||||
|
const compareTanks =
|
||||||
|
protagonist.id === antagonist.id
|
||||||
|
? [protagonist.id]
|
||||||
|
: [protagonist.id, antagonist.id];
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Flex justify="center" align="center">
|
<Flex justify="center" align="center">
|
||||||
<Flex direction="column" align="center" gap="6">
|
<Flex direction="column" align="center" gap="6">
|
||||||
|
<Flex gap="2">
|
||||||
|
<Link href="/tools/tankopedia">
|
||||||
|
<Button variant="outline">
|
||||||
|
<ChevronLeftIcon />
|
||||||
|
Back
|
||||||
|
</Button>
|
||||||
|
</Link>
|
||||||
|
|
||||||
|
<Link href={`/tools/compare?tanks=${compareTanks.join('%2C')}`}>
|
||||||
|
<Button>
|
||||||
|
<MixIcon />
|
||||||
|
Compare
|
||||||
|
</Button>
|
||||||
|
</Link>
|
||||||
|
</Flex>
|
||||||
|
|
||||||
<Flex gap="6">
|
<Flex gap="6">
|
||||||
<Flex direction="column" width="100%">
|
<Flex direction="column" width="100%">
|
||||||
{tank.nameFull && (
|
{protagonist.nameFull && (
|
||||||
<Listing label="Full-name">{tank.nameFull}</Listing>
|
<Listing label="Full-name">{protagonist.nameFull}</Listing>
|
||||||
)}
|
)}
|
||||||
<Listing label="Nation">
|
<Listing label="Nation">
|
||||||
<Flex align="center" gap="1">
|
<Flex align="center" gap="1">
|
||||||
<img
|
<img
|
||||||
style={{ width: '1em', height: '1em' }}
|
style={{ width: '1em', height: '1em' }}
|
||||||
alt={tank.nation}
|
alt={protagonist.nation}
|
||||||
src={asset(`flags/circle/${tank.nation}.webp`)}
|
src={asset(`flags/circle/${protagonist.nation}.webp`)}
|
||||||
/>
|
/>
|
||||||
{
|
{
|
||||||
strings.common.nations[
|
strings.common.nations[
|
||||||
tank.nation as keyof typeof strings.common.nations
|
protagonist.nation as keyof typeof strings.common.nations
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
</Flex>
|
</Flex>
|
||||||
@@ -39,34 +62,34 @@ export function MetaSection() {
|
|||||||
<Listing label="Class">
|
<Listing label="Class">
|
||||||
<Flex align="center" gap="1">
|
<Flex align="center" gap="1">
|
||||||
<ClassIcon width="1em" height="1em" />
|
<ClassIcon width="1em" height="1em" />
|
||||||
{strings.common.tank_class_short[tank.class]}
|
{strings.common.tank_class_short[protagonist.class]}
|
||||||
</Flex>
|
</Flex>
|
||||||
</Listing>
|
</Listing>
|
||||||
<Listing label="Tier">{tank.tier}</Listing>
|
<Listing label="Tier">{protagonist.tier}</Listing>
|
||||||
<Listing
|
<Listing
|
||||||
label="Type"
|
label="Type"
|
||||||
color={
|
color={
|
||||||
tank.treeType === 'collector'
|
protagonist.treeType === 'collector'
|
||||||
? 'blue'
|
? 'blue'
|
||||||
: tank.treeType === 'premium'
|
: protagonist.treeType === 'premium'
|
||||||
? 'amber'
|
? 'amber'
|
||||||
: undefined
|
: undefined
|
||||||
}
|
}
|
||||||
>
|
>
|
||||||
{strings.common.tree_type[tank.treeType]}
|
{strings.common.tree_type[protagonist.treeType]}
|
||||||
</Listing>
|
</Listing>
|
||||||
</Flex>
|
</Flex>
|
||||||
|
|
||||||
<Flex direction="column" width="100%">
|
<Flex direction="column" width="100%">
|
||||||
{developerMode && (
|
{developerMode && (
|
||||||
<Listing label="DEV: ID">
|
<Listing label="DEV: ID">
|
||||||
<Code>{tank.id}</Code>
|
<Code>{protagonist.id}</Code>
|
||||||
</Listing>
|
</Listing>
|
||||||
)}
|
)}
|
||||||
{tank.treeType === 'premium' && (
|
{protagonist.treeType === 'premium' && (
|
||||||
<Listing label="Purchase price">
|
<Listing label="Purchase price">
|
||||||
<Flex align="center" gap="1">
|
<Flex align="center" gap="1">
|
||||||
{tank.price.value / 400}
|
{protagonist.price.value / 400}
|
||||||
<img
|
<img
|
||||||
style={{ width: '1em', height: '1em' }}
|
style={{ width: '1em', height: '1em' }}
|
||||||
alt="gold"
|
alt="gold"
|
||||||
@@ -76,35 +99,35 @@ export function MetaSection() {
|
|||||||
</Listing>
|
</Listing>
|
||||||
)}
|
)}
|
||||||
<Listing
|
<Listing
|
||||||
label={`${tank.treeType === 'researchable' ? 'Purchase' : 'Restoration'} price`}
|
label={`${protagonist.treeType === 'researchable' ? 'Purchase' : 'Restoration'} price`}
|
||||||
>
|
>
|
||||||
<Flex align="center" gap="1">
|
<Flex align="center" gap="1">
|
||||||
{tank.price.value.toLocaleString()}
|
{protagonist.price.value.toLocaleString()}
|
||||||
<img
|
<img
|
||||||
style={{ width: '1em', height: '1em' }}
|
style={{ width: '1em', height: '1em' }}
|
||||||
alt={tank.price.type}
|
alt={protagonist.price.type}
|
||||||
src={asset(
|
src={asset(
|
||||||
`icons/currencies/${tank.price.type === 'gold' ? 'gold' : 'silver'}.webp`,
|
`icons/currencies/${protagonist.price.type === 'gold' ? 'gold' : 'silver'}.webp`,
|
||||||
)}
|
)}
|
||||||
/>
|
/>
|
||||||
</Flex>
|
</Flex>
|
||||||
</Listing>
|
</Listing>
|
||||||
<Listing label="Sale price">
|
<Listing label="Sale price">
|
||||||
<Flex align="center" gap="1">
|
<Flex align="center" gap="1">
|
||||||
{(tank.price.value / 2).toLocaleString()}
|
{(protagonist.price.value / 2).toLocaleString()}
|
||||||
<img
|
<img
|
||||||
style={{ width: '1em', height: '1em' }}
|
style={{ width: '1em', height: '1em' }}
|
||||||
alt={tank.price.type}
|
alt={protagonist.price.type}
|
||||||
src={asset(
|
src={asset(
|
||||||
`icons/currencies/${tank.price.type === 'gold' ? 'gold' : 'silver'}.webp`,
|
`icons/currencies/${protagonist.price.type === 'gold' ? 'gold' : 'silver'}.webp`,
|
||||||
)}
|
)}
|
||||||
/>
|
/>
|
||||||
</Flex>
|
</Flex>
|
||||||
</Listing>
|
</Listing>
|
||||||
{tank.xp && (
|
{protagonist.xp && (
|
||||||
<Listing label="Research XP">
|
<Listing label="Research XP">
|
||||||
<Flex align="center" gap="1">
|
<Flex align="center" gap="1">
|
||||||
{tank.xp.toLocaleString()}
|
{protagonist.xp.toLocaleString()}
|
||||||
<img
|
<img
|
||||||
style={{ width: '1em', height: '1em' }}
|
style={{ width: '1em', height: '1em' }}
|
||||||
alt="xp"
|
alt="xp"
|
||||||
|
|||||||
@@ -1,13 +1,11 @@
|
|||||||
import {
|
import {
|
||||||
CameraIcon,
|
CameraIcon,
|
||||||
ChevronLeftIcon,
|
|
||||||
CopyIcon,
|
CopyIcon,
|
||||||
DownloadIcon,
|
DownloadIcon,
|
||||||
EnterFullScreenIcon,
|
EnterFullScreenIcon,
|
||||||
ExitFullScreenIcon,
|
ExitFullScreenIcon,
|
||||||
EyeOpenIcon,
|
EyeOpenIcon,
|
||||||
GearIcon,
|
GearIcon,
|
||||||
MixIcon,
|
|
||||||
} from '@radix-ui/react-icons';
|
} from '@radix-ui/react-icons';
|
||||||
import {
|
import {
|
||||||
Button,
|
Button,
|
||||||
@@ -24,7 +22,6 @@ import {
|
|||||||
import { invalidate } from '@react-three/fiber';
|
import { invalidate } from '@react-three/fiber';
|
||||||
import { RefObject, use, useEffect, useState } from 'react';
|
import { RefObject, use, useEffect, useState } from 'react';
|
||||||
import { ThicknessRange } from '../../../../../../../components/Armor/components/StaticArmor';
|
import { ThicknessRange } from '../../../../../../../components/Armor/components/StaticArmor';
|
||||||
import { Link } from '../../../../../../../components/Link';
|
|
||||||
import { ModuleButton } from '../../../../../../../components/ModuleButtons/ModuleButton';
|
import { ModuleButton } from '../../../../../../../components/ModuleButtons/ModuleButton';
|
||||||
import { SmallTankIcon } from '../../../../../../../components/SmallTankIcon';
|
import { SmallTankIcon } from '../../../../../../../components/SmallTankIcon';
|
||||||
import { resolveNearPenetration } from '../../../../../../../core/blitz/resolveNearPenetration';
|
import { resolveNearPenetration } from '../../../../../../../core/blitz/resolveNearPenetration';
|
||||||
@@ -61,12 +58,6 @@ export function Options({ thicknessRange, canvas }: OptionsProps) {
|
|||||||
const [display, setDisplay] = useState<TankopediaDisplay>(
|
const [display, setDisplay] = useState<TankopediaDisplay>(
|
||||||
TankopediaDisplay.Model,
|
TankopediaDisplay.Model,
|
||||||
);
|
);
|
||||||
const antagonist = Duel.use((state) => state.antagonist.tank);
|
|
||||||
const protagonist = Duel.use((state) => state.protagonist.tank);
|
|
||||||
const compareTanks =
|
|
||||||
protagonist.id === antagonist.id
|
|
||||||
? [protagonist.id]
|
|
||||||
: [protagonist.id, antagonist.id];
|
|
||||||
const isFullScreen = useFullScreen();
|
const isFullScreen = useFullScreen();
|
||||||
const showGrid = TankopediaPersistent.use(
|
const showGrid = TankopediaPersistent.use(
|
||||||
(state) => state.model.visual.showGrid,
|
(state) => state.model.visual.showGrid,
|
||||||
@@ -346,26 +337,10 @@ export function Options({ thicknessRange, canvas }: OptionsProps) {
|
|||||||
direction="column"
|
direction="column"
|
||||||
align="center"
|
align="center"
|
||||||
position="absolute"
|
position="absolute"
|
||||||
bottom="2"
|
bottom="4"
|
||||||
left="50%"
|
left="50%"
|
||||||
style={{ transform: 'translateX(-50%)' }}
|
style={{ transform: 'translateX(-50%)' }}
|
||||||
>
|
>
|
||||||
<Flex gap="4">
|
|
||||||
<Link href="/tools/tankopedia">
|
|
||||||
<Button variant="ghost" size="1">
|
|
||||||
<ChevronLeftIcon />
|
|
||||||
Back
|
|
||||||
</Button>
|
|
||||||
</Link>
|
|
||||||
|
|
||||||
<Link href={`/tools/compare?tanks=${compareTanks.join('%2C')}`}>
|
|
||||||
<Button variant="ghost" size="1">
|
|
||||||
<MixIcon />
|
|
||||||
Compare
|
|
||||||
</Button>
|
|
||||||
</Link>
|
|
||||||
</Flex>
|
|
||||||
|
|
||||||
{display === TankopediaDisplay.DynamicArmor && (
|
{display === TankopediaDisplay.DynamicArmor && (
|
||||||
<Flex align="center" gap="2">
|
<Flex align="center" gap="2">
|
||||||
<Text color="gray" size="2">
|
<Text color="gray" size="2">
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
type Name =
|
type Name =
|
||||||
| `color-${'background' | `panel-${'solid' | 'translucent'}` | 'surface' | 'overlay'}`
|
| `color-${'background' | `panel-${'solid' | 'translucent'}` | 'surface' | 'overlay'}`
|
||||||
| `radius-${1 | 2 | 3 | 4 | 5 | 6 | 'full'}`;
|
| `radius-${1 | 2 | 3 | 4 | 5 | 6 | 'full'}`
|
||||||
|
| `space-${1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9}`;
|
||||||
|
|
||||||
export function Var(name: Name) {
|
export function Var(name: Name) {
|
||||||
return `var(--${name})`;
|
return `var(--${name})`;
|
||||||
|
|||||||
Reference in new issue
Block a user