mirror of
https://github.com/blitzkit/blitzkit.git
synced 2026-10-23 19:49:50 +02:00
feat: better card positioning
This commit is contained in:
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">
|
||||||
|
|||||||
@@ -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()
|
||||||
|
|||||||
Reference in new issue
Block a user