From ff5bb433824b3cea5e79a1a7cc858d0fe9827a6a Mon Sep 17 00:00:00 2001 From: syntaxbullet Date: Fri, 3 Jul 2026 16:08:45 +0200 Subject: [PATCH] feat(view): show transform measurements --- view/App.tsx | 6 ++++- view/BottomControlsIsland.tsx | 9 +++++-- view/bottom-controls/TransformControls.tsx | 28 ++++++++++++++++++++++ 3 files changed, 40 insertions(+), 3 deletions(-) create mode 100644 view/bottom-controls/TransformControls.tsx diff --git a/view/App.tsx b/view/App.tsx index 1c20104..a7fc08b 100644 --- a/view/App.tsx +++ b/view/App.tsx @@ -20,6 +20,9 @@ export function App({ app }: AppProps) { const viewportActivityIsland = useViewportActivityIsland(state.editor.viewport); const [layersOpen, setLayersOpen] = useState(false); const selectionSummary = getSelectionSummary(state.document, state.editor.selection); + const transformBounds = state.editor.transformSession?.target.type === "artboard" + ? state.document.artboards.find((artboard) => artboard.id === state.editor.transformSession?.target.id)?.bounds + : undefined; return (
@@ -41,9 +44,10 @@ export function App({ app }: AppProps) {
setLayersOpen(true)} /> diff --git a/view/BottomControlsIsland.tsx b/view/BottomControlsIsland.tsx index baf42d5..7a2f56f 100644 --- a/view/BottomControlsIsland.tsx +++ b/view/BottomControlsIsland.tsx @@ -2,7 +2,9 @@ import type { AppStore } from "@editor/store"; import type { ViewportState } from "@editor/state"; import { PanControls } from "./bottom-controls/PanControls"; import { SelectionControls } from "./bottom-controls/SelectionControls"; +import { TransformControls } from "./bottom-controls/TransformControls"; import { ZoomControls } from "./bottom-controls/ZoomControls"; +import type { Rect } from "@core/geometry"; import type { SelectionSummary } from "./selectionSummary"; export type BottomControlsAction = "pan" | "zoom"; @@ -12,11 +14,12 @@ export type BottomControlsIslandProps = { visible: boolean; action: BottomControlsAction; selection: SelectionSummary; + transformBounds?: Rect; dispatch: AppStore["dispatch"]; onOpenLayers: () => void; }; -export function BottomControlsIsland({ viewport, visible, action, selection, dispatch, onOpenLayers }: BottomControlsIslandProps) { +export function BottomControlsIsland({ viewport, visible, action, selection, transformBounds, dispatch, onOpenLayers }: BottomControlsIslandProps) { const zoomPercent = Math.round(viewport.zoom * 100); const x = Math.round(viewport.center.x); const y = Math.round(viewport.center.y); @@ -28,7 +31,9 @@ export function BottomControlsIsland({ viewport, visible, action, selection, dis visible ? "pointer-events-auto translate-y-0 opacity-100" : "pointer-events-none translate-y-3 opacity-0" }`} > - {selection.type !== "none" ? ( + {transformBounds ? ( + + ) : selection.type !== "none" ? ( ) : action === "pan" ? ( diff --git a/view/bottom-controls/TransformControls.tsx b/view/bottom-controls/TransformControls.tsx new file mode 100644 index 0000000..9d45f09 --- /dev/null +++ b/view/bottom-controls/TransformControls.tsx @@ -0,0 +1,28 @@ +import { BoundingBox } from "@phosphor-icons/react"; +import type { Rect } from "@core/geometry"; +import { BottomControlDivider } from "./Divider"; +import { bottomControlIconSlotClass, bottomControlLabelClass, bottomControlValueClass } from "./styles"; + +export type TransformControlsProps = { + bounds: Rect; +}; + +export function TransformControls({ bounds }: TransformControlsProps) { + return ( +
+ + + + + X + {Math.round(bounds.x)} + Y + {Math.round(bounds.y)} + + W + {Math.round(bounds.w)} + H + {Math.round(bounds.h)} +
+ ); +}