Skip to content

Commit 343cd3c

Browse files
committed
feat: add hotkeys for zooming the canvas
1 parent a742a11 commit 343cd3c

File tree

4 files changed

+69
-10
lines changed

4 files changed

+69
-10
lines changed

apps/builder/app/builder/features/workspace/canvas-tools/canvas-tools.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ import { Label } from "./outline/label";
1717
import { Outline } from "./outline/outline";
1818
import { useSubscribeDragAndDropState } from "./use-subscribe-drag-drop-state";
1919
import { applyScale } from "./outline";
20-
import { $clampingRect, $scale } from "~/builder/shared/nano-states";
20+
import { $clampingRect, $scale, $zoom } from "~/builder/shared/nano-states";
2121
import { BlockChildHoveredInstanceOutline } from "./outline/block-instance-outline";
2222
import { TextEditorContextMenu } from "./block-editor-context-menu";
2323

apps/builder/app/builder/features/workspace/workspace.tsx

Lines changed: 12 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import {
55
$canvasWidth,
66
$scale,
77
$workspaceRect,
8+
$zoom,
89
} from "~/builder/shared/nano-states";
910
import { $textEditingInstanceSelector } from "~/shared/nano-states";
1011
import { CanvasTools } from "./canvas-tools";
@@ -50,6 +51,7 @@ const useMeasureWorkspace = () => {
5051
};
5152

5253
const getCanvasStyle = (
54+
zoom: number,
5355
scale: number,
5456
workspaceRect?: DOMRect,
5557
canvasWidth?: number
@@ -62,31 +64,36 @@ const getCanvasStyle = (
6264
}
6365

6466
return {
65-
width: canvasWidth ?? "100%",
66-
height: canvasHeight ?? "100%",
67+
width: canvasWidth != null ? canvasWidth / zoom : 100 + "%",
68+
height: canvasHeight != null ? canvasHeight : 100 + "%",
6769
left: "50%",
6870
transform: `scale(${scale}%) translateX(-50%)`,
71+
// transformOrigin: "top center",
6972
};
7073
};
7174

7275
const useCanvasStyle = () => {
76+
const zoom = useStore($zoom);
7377
const scale = useStore($scale);
7478
const workspaceRect = useStore($workspaceRect);
7579
const canvasWidth = useStore($canvasWidth);
7680

77-
return getCanvasStyle(scale, workspaceRect, canvasWidth);
81+
return getCanvasStyle(zoom, scale, workspaceRect, canvasWidth);
7882
};
7983

8084
const useOutlineStyle = () => {
85+
const zoom = useStore($zoom);
8186
const scale = useStore($scale);
8287
const workspaceRect = useStore($workspaceRect);
8388
const canvasWidth = useStore($canvasWidth);
84-
const style = getCanvasStyle(100, workspaceRect, canvasWidth);
89+
const style = getCanvasStyle(zoom, 100, workspaceRect, canvasWidth);
8590

8691
return {
8792
...style,
8893
width:
89-
canvasWidth === undefined ? "100%" : (canvasWidth ?? 0) * (scale / 100),
94+
canvasWidth === undefined
95+
? "100%"
96+
: (canvasWidth ?? 0) * (scale / zoom / 100),
9097
} as const;
9198
};
9299

apps/builder/app/builder/shared/commands.ts

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,8 @@ import { $publisher } from "~/shared/pubsub";
3030
import {
3131
$activeInspectorPanel,
3232
$publishDialog,
33+
$scale,
34+
$zoom,
3335
setActiveSidebarPanel,
3436
toggleActiveSidebarPanel,
3537
} from "./nano-states";
@@ -331,6 +333,54 @@ export const { emitCommand, subscribeCommands } = createCommandsEmitter({
331333
},
332334
disableOnInputLikeControls: true,
333335
},
336+
{
337+
name: "zoomIn",
338+
defaultHotkeys: ["="],
339+
handler: () => {
340+
$zoom.set($zoom.get() + 0.15);
341+
},
342+
disableOnInputLikeControls: true,
343+
},
344+
{
345+
name: "zoomOut",
346+
defaultHotkeys: ["-"],
347+
handler: () => {
348+
$zoom.set($zoom.get() - 0.15);
349+
},
350+
disableOnInputLikeControls: true,
351+
},
352+
{
353+
name: "resetZoom",
354+
defaultHotkeys: ["0"],
355+
handler: () => {
356+
$zoom.set(1);
357+
},
358+
disableOnInputLikeControls: true,
359+
},
360+
{
361+
name: "zoomInSlightly",
362+
defaultHotkeys: ["ctrl+="],
363+
handler: () => {
364+
$zoom.set($zoom.get() + 0.05);
365+
},
366+
disableOnInputLikeControls: true,
367+
},
368+
{
369+
name: "zoomOutSlightly",
370+
defaultHotkeys: ["ctrl+-"],
371+
handler: () => {
372+
$zoom.set($zoom.get() - 0.05);
373+
},
374+
disableOnInputLikeControls: true,
375+
},
376+
{
377+
name: "zoomToActualSize",
378+
defaultHotkeys: ["ctrl+0"],
379+
handler: () => {
380+
$zoom.set($zoom.get() * (100 / $scale.get()));
381+
},
382+
disableOnInputLikeControls: true,
383+
},
334384
{
335385
name: "toggleNavigatorPanel",
336386
defaultHotkeys: ["z"],

apps/builder/app/builder/shared/nano-states/index.ts

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -22,18 +22,20 @@ export const $canvasScrollbarSize = atom<
2222
{ width: number; height: number } | undefined
2323
>();
2424

25+
export const $zoom = atom<number>(1);
26+
2527
export const $scale = computed(
26-
[$canvasWidth, $workspaceRect],
27-
(canvasWidth, workspaceRect) => {
28+
[$canvasWidth, $workspaceRect, $zoom],
29+
(canvasWidth, workspaceRect, zoom) => {
2830
if (
2931
canvasWidth === undefined ||
3032
workspaceRect === undefined ||
3133
canvasWidth <= workspaceRect.width
3234
) {
33-
return 100;
35+
return 100 * zoom;
3436
}
3537
return Number.parseFloat(
36-
((workspaceRect.width / canvasWidth) * 100).toFixed(2)
38+
((workspaceRect.width / canvasWidth) * 100 * zoom).toFixed(2)
3739
);
3840
}
3941
);

0 commit comments

Comments
 (0)