feat: better card positioning

This commit is contained in:
TrèsAbhi committed 2024-07-29 20:18:31 -05:00
1 parent c4b5baf6cc
commit 969c9a903e
5 files changed
+45 -50

No files matched your search

@@ -109,6 +109,7 @@ export function HeroSection({ id }: HeroSectionProps) {
justify="center" justify="center"
style={{ style={{
height: '100%', height: '100%',
userSelect: 'none',
}} }}
> >
<Flex gap="4"> <Flex gap="4">
@@ -14,10 +14,14 @@ export function ArmorPlateDisplay() {
return ( return (
<group position={highlightArmor.point}> <group position={highlightArmor.point}>
<Html> <Html center>
<Card <Card
ml="9" mb="4"
style={{ whiteSpace: 'nowrap', color: highlightArmor.color }} style={{
whiteSpace: 'nowrap',
color: highlightArmor.color,
transform: 'translateY(-50%)',
}}
> >
<Flex direction="column"> <Flex direction="column">
<Text weight="bold"> <Text weight="bold">
+13 -11
View File
@@ -16,6 +16,7 @@ import {
Quaternion, Quaternion,
} from 'three'; } from 'three';
import { J_HAT, K_HAT } from '../../../constants/axis'; import { J_HAT, K_HAT } from '../../../constants/axis';
import { useFullScreen } from '../../../hooks/useFullScreen';
import * as TankopediaEphemeral from '../../../stores/tankopediaEphemeral'; import * as TankopediaEphemeral from '../../../stores/tankopediaEphemeral';
import { ShotDisplayCard } from './ShotDisplayCard'; import { ShotDisplayCard } from './ShotDisplayCard';
@@ -35,6 +36,7 @@ const TRACER_THICK = 1 / 32;
const TRACER_THIN = TRACER_THICK / 2; const TRACER_THIN = TRACER_THICK / 2;
export function ShotDisplay() { export function ShotDisplay() {
const isFullscreen = useFullScreen();
const shot = TankopediaEphemeral.use((state) => state.shot); const shot = TankopediaEphemeral.use((state) => state.shot);
const inTracer = useRef<Mesh>(null); const inTracer = useRef<Mesh>(null);
const outTracer = useRef<Mesh>(null); const outTracer = useRef<Mesh>(null);
@@ -139,6 +141,8 @@ export function ShotDisplay() {
? shotStatusColors[shot.out.status] ? shotStatusColors[shot.out.status]
: undefined; : undefined;
const inTitleColor = shotStatusColors[shot.in.status]; const inTitleColor = shotStatusColors[shot.in.status];
const tracerGoingUp =
shot.in.surfaceNormal.y + (shot.out?.surfaceNormal.y ?? 0) > 0;
return ( return (
<group> <group>
@@ -162,19 +166,17 @@ export function ShotDisplay() {
</group> </group>
)} )}
<Html <Html position={inLast.point} center>
position={inLast.point}
style={{
pointerEvents: 'none',
transform: 'translateY(-50%)',
}}
>
<Box <Box
pl="9" display={isFullscreen ? undefined : { initial: 'none', sm: 'block' }}
display={{ style={{
initial: 'none', pointerEvents: 'none',
sm: 'block', transform: `translateY(${tracerGoingUp ? 50 : -50}%)`,
}} }}
mb={tracerGoingUp ? '0' : '9'}
pb={tracerGoingUp ? '0' : '4'}
mt={tracerGoingUp ? '9' : '0'}
pt={tracerGoingUp ? '4' : '0'}
> >
<ShotDisplayCard shot={shot} /> <ShotDisplayCard shot={shot} />
</Box> </Box>
@@ -1,4 +1,11 @@
import { Card, Flex, Inset, Separator, Text } from '@radix-ui/themes'; import {
Card,
CardProps,
Flex,
Inset,
Separator,
Text,
} from '@radix-ui/themes';
import { ComponentProps } from 'react'; import { ComponentProps } from 'react';
import { radToDeg } from 'three/src/math/MathUtils'; import { radToDeg } from 'three/src/math/MathUtils';
import * as TankopediaEphemeral from '../../../stores/tankopediaEphemeral'; import * as TankopediaEphemeral from '../../../stores/tankopediaEphemeral';
@@ -40,13 +47,7 @@ function LayerEntry({
}) { }) {
return ( return (
<Flex align="center" gap="2"> <Flex align="center" gap="2">
<Text <Text size="1" color="gray" style={{ width: 12 }}>
size="1"
color="gray"
style={{
width: 12,
}}
>
{layerIndex} {layerIndex}
</Text> </Text>
<Text size="2" color={shotStatusColor} style={{ width: 47 }}> <Text size="2" color={shotStatusColor} style={{ width: 47 }}>
@@ -55,13 +56,7 @@ function LayerEntry({
{layer.type === null && ( {layer.type === null && (
<> <>
<Text <Text size="2" color={shotStatusColor} style={{ width: 64 }}>
size="2"
color={shotStatusColor}
style={{
width: 64,
}}
>
{Math.round(layer.distance * 1000).toLocaleString()} {Math.round(layer.distance * 1000).toLocaleString()}
<Text size="1">mm</Text> <Text size="1">mm</Text>
</Text> </Text>
@@ -73,13 +68,7 @@ function LayerEntry({
)} )}
{layer.type === ArmorType.External && ( {layer.type === ArmorType.External && (
<Text <Text size="2" color={shotStatusColor} style={{ width: 64 }}>
size="2"
color={shotStatusColor}
style={{
width: 64,
}}
>
{Math.round(layer.thickness).toLocaleString()} {Math.round(layer.thickness).toLocaleString()}
<Text size="1">mm</Text> <Text size="1">mm</Text>
</Text> </Text>
@@ -87,13 +76,7 @@ function LayerEntry({
{(layer.type === ArmorType.Core || layer.type === ArmorType.Spaced) && ( {(layer.type === ArmorType.Core || layer.type === ArmorType.Spaced) && (
<> <>
<Text <Text size="2" color={shotStatusColor} style={{ width: 80 }}>
size="2"
color={shotStatusColor}
style={{
width: 80,
}}
>
{Math.round(layer.thicknessAngled).toLocaleString()} {Math.round(layer.thicknessAngled).toLocaleString()}
<Text size="1">{`mm${angle === undefined ? '' : ` ${Math.round(radToDeg(angle))}°`}`}</Text> <Text size="1">{`mm${angle === undefined ? '' : ` ${Math.round(radToDeg(angle))}°`}`}</Text>
</Text> </Text>
@@ -108,11 +91,11 @@ function LayerEntry({
); );
} }
interface ShotDisplayCardProps { interface ShotDisplayCardProps extends CardProps {
shot: TankopediaEphemeral.Shot; shot: TankopediaEphemeral.Shot;
} }
export function ShotDisplayCard({ shot }: ShotDisplayCardProps) { export function ShotDisplayCard({ shot, ...props }: ShotDisplayCardProps) {
if (!shot) return null; if (!shot) return null;
const outTitleColor = shot.out const outTitleColor = shot.out
@@ -121,7 +104,7 @@ export function ShotDisplayCard({ shot }: ShotDisplayCardProps) {
const inTitleColor = shotStatusColors[shot.in.status]; const inTitleColor = shotStatusColors[shot.in.status];
return ( return (
<Card style={{ width: 300 }}> <Card style={{ width: 300 }} {...props}>
<Flex direction="column" gap="2"> <Flex direction="column" gap="2">
<Flex direction="column" gap="1"> <Flex direction="column" gap="1">
<Text color={inTitleColor} weight="bold"> <Text color={inTitleColor} weight="bold">
@@ -2,6 +2,7 @@ import { useThree } from '@react-three/fiber';
import { clamp } from 'lodash'; import { clamp } from 'lodash';
import { useCallback, useEffect, useMemo } from 'react'; import { useCallback, useEffect, useMemo } from 'react';
import { import {
Box3,
Color, Color,
DoubleSide, DoubleSide,
FrontSide, FrontSide,
@@ -149,7 +150,6 @@ export function SpacedArmorSceneComponent({
if (selectedName === undefined) { if (selectedName === undefined) {
// nothing selected, go back to defaults // nothing selected, go back to defaults
material.opacity = opacity; material.opacity = opacity;
// material.transparent = opacity < 1;
material.color = color; material.color = color;
material.depthWrite = props.type !== ArmorType.External; material.depthWrite = props.type !== ArmorType.External;
material.side = FrontSide; material.side = FrontSide;
@@ -164,18 +164,18 @@ export function SpacedArmorSceneComponent({
) { ) {
// this selected, stand out! // this selected, stand out!
material.opacity = 1; material.opacity = 1;
// material.transparent = false;
material.color = color; material.color = color;
material.depthWrite = true; material.depthWrite = true;
material.side = DoubleSide; material.side = DoubleSide;
} else { } else {
// something else selected, become background // something else selected, become background
material.opacity = 1 / 4; material.opacity = 1 / 4;
// material.transparent = true;
material.color = unselectedColor; material.color = unselectedColor;
material.depthWrite = props.type !== ArmorType.External; material.depthWrite = props.type !== ArmorType.External;
material.side = FrontSide; material.side = FrontSide;
} }
material.transparent = material.opacity < 1;
} }
const unsubscribe = tankopediaEphemeralStore.subscribe( const unsubscribe = tankopediaEphemeralStore.subscribe(
@@ -198,7 +198,12 @@ export function SpacedArmorSceneComponent({
onClick(event) { onClick(event) {
event.stopPropagation(); event.stopPropagation();
const { point } = event; const bounds = new Box3().setFromObject(event.object);
const point = bounds.min
.clone()
.add(bounds.max)
.divideScalar(2)
.setY(bounds.max.y);
const cameraNormal = camera.position.clone().sub(point).normalize(); const cameraNormal = camera.position.clone().sub(point).normalize();
const surfaceNormal = event const surfaceNormal = event
.normal!.clone() .normal!.clone()