mirror of
https://github.com/blitzkit/blitzkit.git
synced 2026-11-11 11:46:10 +01:00
thicknesses
This commit is contained in:
4 files changed
+200
-204
No files matched your search
@@ -0,0 +1,67 @@
|
||||
.thicknesses {
|
||||
pointer-events: auto;
|
||||
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: flex-end;
|
||||
gap: var(--space-4);
|
||||
|
||||
position: absolute;
|
||||
right: var(--space-4);
|
||||
top: 50%;
|
||||
|
||||
user-select: none;
|
||||
transition: var(--duration-brief);
|
||||
|
||||
/* slides off the right edge when the static armor view isn't active */
|
||||
transform: translate(calc(100% + var(--space-4)), -50%);
|
||||
|
||||
&[data-visible="true"] {
|
||||
transform: translate(0, -50%);
|
||||
}
|
||||
}
|
||||
|
||||
.toggle {
|
||||
display: flex;
|
||||
gap: var(--space-3);
|
||||
|
||||
padding: 0;
|
||||
border: none;
|
||||
background: none;
|
||||
font: inherit;
|
||||
|
||||
cursor: pointer;
|
||||
opacity: 0.5;
|
||||
|
||||
&[data-visible="true"] {
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
&[data-scaled="true"] {
|
||||
height: 4rem;
|
||||
}
|
||||
}
|
||||
|
||||
.labels {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: flex-end;
|
||||
justify-content: space-between;
|
||||
}
|
||||
|
||||
.swatch {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
|
||||
width: 1rem;
|
||||
border-radius: var(--radius-max);
|
||||
overflow: hidden;
|
||||
|
||||
color: black;
|
||||
|
||||
/* the unscaled swatch is just an icon-sized dot */
|
||||
.toggle:not([data-scaled="true"]) & {
|
||||
height: 1rem;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,131 @@
|
||||
import { literals } from "@blitzkit/i18n/src/literals";
|
||||
import { EyeClosedIcon, EyeOpenIcon } from "@radix-ui/react-icons";
|
||||
import { useCallback, type ReactNode } from "react";
|
||||
import { useStrings } from "../../hooks/useStrings";
|
||||
import { Tankopedia } from "../../stores/tankopedia";
|
||||
import { TankopediaPersistent } from "../../stores/tankopediaPersistent";
|
||||
import { TankopediaDisplay } from "../../stores/tankopediaPersistent/constants";
|
||||
import type { ThicknessRange } from "../TankStaticArmor";
|
||||
import { Text } from "../Text";
|
||||
import styles from "./index.module.css";
|
||||
|
||||
interface LayerToggleProps {
|
||||
visible: boolean;
|
||||
label: ReactNode;
|
||||
/** Thickness labels for the top and bottom of the scale */
|
||||
range?: [ReactNode, ReactNode];
|
||||
swatch: string;
|
||||
onToggle(): void;
|
||||
}
|
||||
|
||||
function LayerToggle({
|
||||
visible,
|
||||
label,
|
||||
range,
|
||||
swatch,
|
||||
onToggle,
|
||||
}: LayerToggleProps) {
|
||||
return (
|
||||
<button
|
||||
className={styles.toggle}
|
||||
data-visible={visible}
|
||||
data-scaled={range !== undefined}
|
||||
onClick={onToggle}
|
||||
>
|
||||
<div className={styles.labels}>
|
||||
{range && (
|
||||
<Text size="minor" lowContrast>
|
||||
{range[0]}
|
||||
</Text>
|
||||
)}
|
||||
|
||||
<Text size="minor">{label}</Text>
|
||||
|
||||
{range && (
|
||||
<Text size="minor" lowContrast>
|
||||
{range[1]}
|
||||
</Text>
|
||||
)}
|
||||
</div>
|
||||
|
||||
<div className={styles.swatch} style={{ background: swatch }}>
|
||||
{visible ? <EyeOpenIcon /> : <EyeClosedIcon />}
|
||||
</div>
|
||||
</button>
|
||||
);
|
||||
}
|
||||
|
||||
export interface ThicknessesProps {
|
||||
thicknessRange: ThicknessRange;
|
||||
}
|
||||
|
||||
export function Thicknesses({ thicknessRange }: ThicknessesProps) {
|
||||
const strings = useStrings();
|
||||
const display = Tankopedia.use((state) => state.loaders.display.loaded);
|
||||
const showControls = Tankopedia.use((state) => state.showControls);
|
||||
const showPrimaryArmor = TankopediaPersistent.use(
|
||||
(state) => state.showPrimaryArmor,
|
||||
);
|
||||
const showSpacedArmor = TankopediaPersistent.use(
|
||||
(state) => state.showSpacedArmor,
|
||||
);
|
||||
const showExternalModules = TankopediaPersistent.use(
|
||||
(state) => state.showExternalModules,
|
||||
);
|
||||
const { element } = strings.tanks.shot_card;
|
||||
const mm = useCallback(
|
||||
(value: number) =>
|
||||
literals(strings.common.units.mm, { value: value.toFixed(0) }),
|
||||
[strings],
|
||||
);
|
||||
const clearHighlight = useCallback(() => {
|
||||
Tankopedia.mutate((draft) => {
|
||||
draft.highlightArmor = undefined;
|
||||
});
|
||||
}, []);
|
||||
|
||||
return (
|
||||
<div
|
||||
className={styles.thicknesses}
|
||||
data-visible={showControls && display === TankopediaDisplay.StaticArmor}
|
||||
>
|
||||
<LayerToggle
|
||||
visible={showPrimaryArmor}
|
||||
label={element.primary}
|
||||
range={[mm(thicknessRange.value * 1.5), mm(0)]}
|
||||
swatch="linear-gradient(rgb(64, 0, 0), rgb(255, 0, 0) 33%, rgb(255, 255, 0) 66%, rgb(0, 255, 0))"
|
||||
onToggle={() => {
|
||||
TankopediaPersistent.mutate((draft) => {
|
||||
draft.showPrimaryArmor = !draft.showPrimaryArmor;
|
||||
});
|
||||
clearHighlight();
|
||||
}}
|
||||
/>
|
||||
|
||||
<LayerToggle
|
||||
visible={showSpacedArmor}
|
||||
label={element.spaced}
|
||||
range={[mm(thicknessRange.value), mm(0)]}
|
||||
swatch="linear-gradient(rgb(32, 0, 225), rgb(255, 0, 255))"
|
||||
onToggle={() => {
|
||||
TankopediaPersistent.mutate((draft) => {
|
||||
draft.showSpacedArmor = !draft.showSpacedArmor;
|
||||
});
|
||||
clearHighlight();
|
||||
}}
|
||||
/>
|
||||
|
||||
<LayerToggle
|
||||
visible={showExternalModules}
|
||||
label={element.external}
|
||||
swatch="#c0c0c0"
|
||||
onToggle={() => {
|
||||
TankopediaPersistent.mutate((draft) => {
|
||||
draft.showExternalModules = !draft.showExternalModules;
|
||||
});
|
||||
clearHighlight();
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
Reference in new issue
Block a user