feat: nerd time

This commit is contained in:
tresabhi committed 2025-05-05 22:54:39 -05:00
1 parent b409e26ca5
commit ad8cbb96b7
5 files changed
+85 -172

No files matched your search

@@ -90,10 +90,11 @@ export function Options({ thicknessRange, canvas, skeleton }: OptionsProps) {
const mutateTankopediaPersistent = TankopediaPersistent.useMutation();
const mutateTankopediaEphemeral = TankopediaEphemeral.useMutation();
const { strings, unwrap } = useLocale();
const disturbed = TankopediaEphemeral.use((state) => state.disturbed);
return (
<>
<QuickInputs />
{disturbed && <QuickInputs />}
{display === TankopediaDisplay.ShootingRange && (
<Box
@@ -323,9 +324,9 @@ export function Options({ thicknessRange, canvas, skeleton }: OptionsProps) {
direction="column"
align="center"
position="absolute"
bottom="4"
bottom={disturbed ? '4' : '-100%'}
left="50%"
style={{ transform: 'translateX(-50%)' }}
style={{ transform: 'translateX(-50%)', transitionDuration: '200ms' }}
>
<Flex
direction="column"
@@ -0,0 +1,55 @@
import { TankType } from '@blitzkit/core';
import { Heading } from '@radix-ui/themes';
import { clamp } from 'three/src/math/MathUtils.js';
import { Var, type VarName } from '../../../../../core/radix/var';
import { useLocale } from '../../../../../hooks/useLocale';
import { Duel } from '../../../../../stores/duel';
import { TankopediaEphemeral } from '../../../../../stores/tankopediaEphemeral';
interface TitleProps {
outline?: boolean;
}
export function Title({ outline }: TitleProps) {
const { unwrap } = useLocale();
const protagonist = Duel.use((state) => state.protagonist.tank);
const disturbed = TankopediaEphemeral.use((state) => state.disturbed);
const revealed = TankopediaEphemeral.use((state) => state.revealed);
const treeColor =
protagonist.type === TankType.COLLECTOR
? 'blue'
: protagonist.type === TankType.PREMIUM
? 'amber'
: undefined;
const name = unwrap(protagonist.name);
return (
<Heading
weight="bold"
style={{
position: 'absolute',
top: '50%',
marginLeft: disturbed ? '2rem' : 0,
left: disturbed ? 0 : '50%',
transform: disturbed ? 'translate(0, -50%)' : 'translate(-50%, -50%)',
userSelect: 'none',
pointerEvents: 'none',
transitionDuration: '1s',
fontSize: disturbed
? '3rem'
: `${16 * clamp(12 / name.length, 0, 1)}rem`,
color: outline ? Var('gray-a7') : undefined,
WebkitTextStroke: outline
? `${disturbed ? '1px' : '2px'} ${Var(
`${treeColor ? (`${treeColor}-11` satisfies VarName) : 'gray-12'}`,
)}`
: undefined,
letterSpacing: disturbed ? 0 : '-0.06em',
}}
color={treeColor}
wrap="nowrap"
>
{name}
</Heading>
);
}
@@ -128,8 +128,8 @@ export function Controls({
camera.position
.copy(inspectModeInitialPosition)
.applyAxisAngle(I_HAT, (Math.PI / 16) * Math.sin(t / 9))
.applyAxisAngle(J_HAT, (-Math.PI / 4) * Math.sin(t / 7));
.applyAxisAngle(I_HAT, (Math.PI / 32) * Math.sin(t / 9))
.applyAxisAngle(J_HAT, (-Math.PI / 16) * Math.sin(t / 7));
invalidate();
}
@@ -30,7 +30,6 @@ import { AutoClear } from './components/AutoClear';
import { Controls } from './components/Control';
import { InitialFogReveal } from './components/InitialFogReveal';
import { Lighting } from './components/Lighting';
import { SceneProps } from './components/SceneProps';
import { TankModel } from './components/TankModel';
import { TransitionSkeleton } from './components/TransitionSkeleton';
@@ -234,7 +233,7 @@ export const TankSandbox = forwardRef<HTMLCanvasElement, TankSandboxProps>(
outline: naked ? '1rem red solid' : undefined,
}}
>
{!naked && <SceneProps />}
{/* {!naked && <SceneProps />} */}
{(display === TankopediaDisplay.Model ||
(display === TankopediaDisplay.DynamicArmor &&
!hideTankModelUnderArmor)) && <TankModel />}
@@ -1,14 +1,11 @@
import { assertSecret, TankType } from '@blitzkit/core';
import { CaretLeftIcon, MixIcon, UpdateIcon } from '@radix-ui/react-icons';
import { Box, Dialog, Flex, Heading, Link, Spinner } from '@radix-ui/themes';
import { TankType } from '@blitzkit/core';
import { Box, Flex } from '@radix-ui/themes';
import { times } from 'lodash-es';
import { Suspense, useEffect, useMemo, useRef, useState } from 'react';
import { NAVBAR_HEIGHT } from '../../../constants/navbar';
import { awaitableModelDefinitions } from '../../../core/awaitables/modelDefinitions';
import { awaitableProvisionDefinitions } from '../../../core/awaitables/provisionDefinitions';
import { awaitableTankDefinitions } from '../../../core/awaitables/tankDefinitions';
import { tankToDuelMember } from '../../../core/blitzkit/tankToDuelMember';
import { Var } from '../../../core/radix/var';
import { useFullScreen } from '../../../hooks/useFullScreen';
import { useLocale } from '../../../hooks/useLocale';
import { Duel } from '../../../stores/duel';
@@ -16,10 +13,9 @@ import { TankopediaEphemeral } from '../../../stores/tankopediaEphemeral';
import type { MaybeSkeletonComponentProps } from '../../../types/maybeSkeletonComponentProps';
import type { ThicknessRange } from '../../Armor/components/StaticArmor';
import { classIcons } from '../../ClassIcon';
import { ScienceIcon } from '../../ScienceIcon';
import { TankSearch } from '../../TankSearch';
import { Options } from './components/Options';
import { TankSandbox } from './components/TankSandbox';
import { Title } from './components/TankSandbox/Title';
const [provisionDefinitions, modelDefinitions, tankDefinitions] =
await Promise.all([
@@ -110,6 +106,8 @@ export function HeroSection({ skeleton }: MaybeSkeletonComponentProps) {
top={isFullScreen ? '0' : undefined}
left={isFullScreen ? '0' : undefined}
>
<Title />
<Box
className="tank-sandbox-container"
flexGrow="1"
@@ -122,10 +120,11 @@ export function HeroSection({ skeleton }: MaybeSkeletonComponentProps) {
width="100%"
height="100%"
position="relative"
left={disturbed ? '0' : { initial: '0', md: '12.5%' }}
style={{ transitionDuration: '200ms' }}
style={{
transitionDuration: '1s',
}}
>
{!revealed && (
{/* {!revealed && (
<Spinner
style={{
position: 'absolute',
@@ -136,13 +135,22 @@ export function HeroSection({ skeleton }: MaybeSkeletonComponentProps) {
height: Var('space-6'),
}}
/>
)}
)} */}
{/* {skeleton && <TankSandboxLoader id={protagonist.id} />} */}
<Suspense>
<TankSandbox ref={canvas} thicknessRange={thicknessRange} />
</Suspense>
<Box
style={{
width: '100%',
height: '100%',
transitionDuration: '2s',
opacity: revealed ? 1 : 0,
}}
>
<Suspense>
<TankSandbox ref={canvas} thicknessRange={thicknessRange} />
</Suspense>
</Box>
</Box>
<Options
@@ -153,157 +161,7 @@ export function HeroSection({ skeleton }: MaybeSkeletonComponentProps) {
</Box>
</Box>
<Flex
className="tankopedia-title-bar"
justify="center"
position={{ initial: 'static', md: 'absolute' }}
left={{
initial: '0',
md: disturbed ? '3' : '5',
lg: disturbed ? '7' : '9',
}}
pt="7"
pb="4"
top={{ initial: '8', md: '50%' }}
mt={{ initial: '0', md: '-9' }}
style={{
transitionDuration: '200ms',
userSelect: 'none',
// background: 'red',
}}
direction="column"
align="center"
gap="2"
>
<Flex
align="center"
gap="3"
width="100%"
justify={{ initial: 'center', md: 'start' }}
>
<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" />
</Heading>
<Heading
weight="medium"
size={
disturbed
? { initial: '7', lg: '8' }
: { initial: '8', lg: '9' }
}
style={{ transitionDuration: '200ms' }}
wrap="nowrap"
color={treeColor}
>
{unwrap(protagonist.name)}
</Heading>
</Flex>
<Flex
gap="4"
ml={disturbed ? '0' : '-2'}
style={{ transitionDuration: '200ms' }}
>
<Link color="gray" underline="always" href="/tools/tankopedia">
<Flex align="center" gap="1">
<CaretLeftIcon />
{strings.website.tools.tankopedia.meta.back}
</Flex>
</Link>
<Link
color="gray"
underline="always"
href={`/tools/compare?tanks=${compareTanks.join('%2C')}`}
>
<Flex align="center" gap="1">
<MixIcon />
{strings.website.tools.tankopedia.meta.compare}
</Flex>
</Link>
<Dialog.Root open={showSwapDialog} onOpenChange={setShowSwapDialog}>
<Dialog.Trigger>
<Link
color="gray"
underline="always"
href="#"
onClick={(event) => {
event.preventDefault();
setShowSwapDialog(true);
}}
>
<Flex align="center" gap="1">
<UpdateIcon />
{strings.website.tools.tankopedia.meta.swap.button}
</Flex>
</Link>
</Dialog.Trigger>
<Dialog.Content>
<Dialog.Title>
{strings.website.tools.tankopedia.meta.swap.title}
</Dialog.Title>
<TankSearch
compact
onSelect={(tank) => {
const model = modelDefinitions.models[tank.id];
setShowSwapDialog(false);
mutateTankopediaEphemeral((draft) => {
draft.model = modelDefinitions.models[tank.id];
});
mutateDuel((draft) => {
draft.protagonist = tankToDuelMember(
tank,
model,
provisionDefinitions,
);
});
window.history.replaceState(
null,
'',
`/tools/tankopedia/${tank.id}`,
);
}}
/>
</Dialog.Content>
</Dialog.Root>
{assertSecret(import.meta.env.PUBLIC_PROMOTE_OPENTEST) ===
'true' && (
<Link
color="jade"
href={`https://${
assertSecret(import.meta.env.PUBLIC_ASSET_BRANCH) ===
'opentest'
? ''
: 'opentest.'
}blitzkit.app/tools/tankopedia/${protagonist.id}`}
>
<Flex align="center" gap="1">
<ScienceIcon width="1.25em" height="1.25em" />
{assertSecret(import.meta.env.PUBLIC_ASSET_BRANCH) ===
'opentest'
? strings.website.tools.tankopedia.meta.vanilla
: strings.website.tools.tankopedia.meta.opentest}
</Flex>
</Link>
)}
</Flex>
</Flex>
<Title outline />
</Flex>
</Flex>
);