feat: add zoom controls and reset functionality to workflow editor toolbar

This commit is contained in:
mlogclub
2026-06-28 10:55:28 +08:00
parent af9c28033a
commit 6a0e65bc07
2 changed files with 86 additions and 0 deletions
@@ -3,6 +3,9 @@
import type { ReactNode } from "react"
import {
CheckCircle2Icon,
Maximize2Icon,
MinusIcon,
PlusIcon,
RotateCcwIcon,
SaveIcon,
SendIcon,
@@ -11,6 +14,7 @@ import {
} from "lucide-react"
import { Button } from "@/components/ui/button"
import { Tooltip, TooltipContent, TooltipTrigger } from "@/components/ui/tooltip"
import { cn } from "@/lib/utils"
import type { WorkflowDraftValidation } from "./workflow-utils"
@@ -26,6 +30,11 @@ export function WorkflowEditorToolbar({
redoDisabled = false,
onAutoLayout,
autoLayoutDisabled = false,
zoomPercent,
onZoomIn,
onZoomOut,
onResetZoom,
onFitView,
onRestoreDefault,
restoreDefaultDisabled = false,
onValidate,
@@ -45,6 +54,11 @@ export function WorkflowEditorToolbar({
redoDisabled?: boolean
onAutoLayout?: () => void
autoLayoutDisabled?: boolean
zoomPercent?: string
onZoomIn?: () => void
onZoomOut?: () => void
onResetZoom?: () => void
onFitView?: () => void
onRestoreDefault?: () => void
restoreDefaultDisabled?: boolean
onValidate?: () => void
@@ -72,6 +86,35 @@ export function WorkflowEditorToolbar({
</div>
<div className="flex items-center gap-1">
{toolbarExtra}
<div className="flex h-7 items-center rounded-lg border bg-muted/30 p-0.5">
<WorkflowToolbarIconButton label="缩小" onClick={onZoomOut}>
<MinusIcon className="size-3.5" />
</WorkflowToolbarIconButton>
<Tooltip>
<TooltipTrigger
render={
<Button
type="button"
variant="ghost"
size="sm"
className="h-6 w-12 px-1 text-xs tabular-nums"
aria-label="重置为 100%"
disabled={!onResetZoom}
onClick={onResetZoom}
/>
}
>
{zoomPercent ?? "100%"}
</TooltipTrigger>
<TooltipContent> 100%</TooltipContent>
</Tooltip>
<WorkflowToolbarIconButton label="放大" onClick={onZoomIn}>
<PlusIcon className="size-3.5" />
</WorkflowToolbarIconButton>
<WorkflowToolbarIconButton label="适配画布" onClick={onFitView}>
<Maximize2Icon className="size-3.5" />
</WorkflowToolbarIconButton>
</div>
<Button type="button" variant="ghost" size="sm" className="h-7 px-2 text-xs" disabled={undoDisabled} onClick={onUndo}>
<Undo2Icon className="size-3.5" />
@@ -102,3 +145,34 @@ export function WorkflowEditorToolbar({
</div>
)
}
function WorkflowToolbarIconButton({
label,
onClick,
children,
}: {
label: string
onClick?: () => void
children: ReactNode
}) {
return (
<Tooltip>
<TooltipTrigger
render={
<Button
type="button"
variant="ghost"
size="icon-xs"
className="size-6"
aria-label={label}
disabled={!onClick}
onClick={onClick}
/>
}
>
{children}
</TooltipTrigger>
<TooltipContent>{label}</TooltipContent>
</Tooltip>
)
}
@@ -191,6 +191,7 @@ function WorkflowEditorInner({
const workflowDocument = useService(WorkflowDocument)
const selectService = useService(WorkflowSelectService)
const [autoLayouting, setAutoLayouting] = useState(false)
const zoomPercent = `${Math.round(playgroundTools.zoom * 100)}%`
useEffect(() => {
const disposable = selectService.onSelectionChanged(() => {
@@ -248,6 +249,12 @@ function WorkflowEditorInner({
}
}
const resetZoom = () => {
context.playground.config.updateConfig({
zoom: 1,
})
}
const closeConfigPanel = () => {
selectService.clear()
onSelectNode("")
@@ -273,6 +280,11 @@ function WorkflowEditorInner({
redoDisabled={redoDisabled}
onAutoLayout={() => void autoLayout()}
autoLayoutDisabled={autoLayouting || definition.nodes.length < 2}
zoomPercent={zoomPercent}
onZoomIn={() => playgroundTools.zoomin(true)}
onZoomOut={() => playgroundTools.zoomout(true)}
onResetZoom={resetZoom}
onFitView={() => playgroundTools.fitView(true)}
onRestoreDefault={onRestoreDefault}
restoreDefaultDisabled={restoreDefaultDisabled}
onValidate={onValidate}