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