11'use client'
22
3- import { useRef , useState } from 'react'
3+ import { useCallback , useRef , useState } from 'react'
44import { createLogger } from '@sim/logger'
5+ import clsx from 'clsx'
6+ import { Scan } from 'lucide-react'
57import { useReactFlow } from 'reactflow'
68import {
79 Button ,
810 ChevronDown ,
911 Cursor ,
10- Expand ,
1112 Hand ,
1213 Popover ,
1314 PopoverAnchor ,
@@ -19,11 +20,14 @@ import {
1920 Undo ,
2021} from '@/components/emcn'
2122import { useSession } from '@/lib/auth/auth-client'
23+ import { useRegisterGlobalCommands } from '@/app/workspace/[workspaceId]/providers/global-commands-provider'
24+ import { createCommand } from '@/app/workspace/[workspaceId]/utils/commands-utils'
2225import { useUpdateGeneralSetting } from '@/hooks/queries/general-settings'
2326import { useCanvasViewport } from '@/hooks/use-canvas-viewport'
2427import { useCollaborativeWorkflow } from '@/hooks/use-collaborative-workflow'
2528import { useCanvasModeStore } from '@/stores/canvas-mode'
2629import { useGeneralStore } from '@/stores/settings/general'
30+ import { useTerminalStore } from '@/stores/terminal'
2731import { useUndoRedoStore } from '@/stores/undo-redo'
2832import { useWorkflowRegistry } from '@/stores/workflows/registry/store'
2933
@@ -36,6 +40,7 @@ export function ActionBar() {
3640 const { undo, redo } = useCollaborativeWorkflow ( )
3741 const showActionBar = useGeneralStore ( ( s ) => s . showActionBar )
3842 const updateSetting = useUpdateGeneralSetting ( )
43+ const isTerminalResizing = useTerminalStore ( ( state ) => state . isResizing )
3944
4045 const { activeWorkflowId } = useWorkflowRegistry ( )
4146 const { data : session } = useSession ( )
@@ -46,6 +51,17 @@ export function ActionBar() {
4651 const canUndo = stack . undo . length > 0
4752 const canRedo = stack . redo . length > 0
4853
54+ const handleFitToView = useCallback ( ( ) => {
55+ fitViewToBounds ( { padding : 0.1 , duration : 300 } )
56+ } , [ fitViewToBounds ] )
57+
58+ useRegisterGlobalCommands ( [
59+ createCommand ( {
60+ id : 'fit-to-view' ,
61+ handler : handleFitToView ,
62+ } ) ,
63+ ] )
64+
4965 const [ contextMenu , setContextMenu ] = useState < { x : number ; y : number } | null > ( null )
5066 const [ isCanvasModeOpen , setIsCanvasModeOpen ] = useState ( false )
5167 const menuRef = useRef < HTMLDivElement > ( null )
@@ -72,7 +88,14 @@ export function ActionBar() {
7288 return (
7389 < >
7490 < div
75- className = '-translate-x-1/2 fixed bottom-[calc(var(--terminal-height)+16px)] left-[calc((100vw+var(--sidebar-width)-var(--panel-width))/2)] z-10 flex h-[36px] items-center gap-[2px] rounded-[8px] border border-[var(--border)] bg-[var(--surface-1)] p-[4px] shadow-sm transition-[left,bottom] duration-100 ease-out'
91+ className = { clsx (
92+ 'fixed z-10 flex h-[36px] items-center gap-[2px] rounded-[8px] border border-[var(--border)] bg-[var(--surface-1)] p-[4px]' ,
93+ ! isTerminalResizing && 'transition-[bottom] duration-100 ease-out'
94+ ) }
95+ style = { {
96+ bottom : 'calc(var(--terminal-height) + 16px)' ,
97+ left : 'calc(var(--sidebar-width) + 16px)' ,
98+ } }
7699 onContextMenu = { handleContextMenu }
77100 >
78101 { /* Canvas Mode Selector */ }
@@ -82,20 +105,27 @@ export function ActionBar() {
82105 variant = 'secondary'
83106 size = 'sm'
84107 >
85- < PopoverTrigger asChild >
86- < div className = 'flex cursor-pointer items-center gap-[4px]' >
87- < Button className = 'h-[28px] w-[28px] rounded-[6px] p-0' variant = 'active' >
88- { mode === 'hand' ? (
89- < Hand className = 'h-[14px] w-[14px]' />
90- ) : (
91- < Cursor className = 'h-[14px] w-[14px]' />
92- ) }
93- </ Button >
94- < Button className = '!p-[2px] group' variant = 'ghost' >
95- < ChevronDown className = 'h-[8px] w-[10px] text-[var(--text-muted)] group-hover:text-[var(--text-secondary)]' />
96- </ Button >
97- </ div >
98- </ PopoverTrigger >
108+ < Tooltip . Root >
109+ < PopoverTrigger asChild >
110+ < div className = 'flex cursor-pointer items-center gap-[4px]' >
111+ < Tooltip . Trigger asChild >
112+ < Button className = 'h-[28px] w-[28px] rounded-[6px] p-0' variant = 'active' >
113+ { mode === 'hand' ? (
114+ < Hand className = 'h-[14px] w-[14px]' />
115+ ) : (
116+ < Cursor className = 'h-[14px] w-[14px]' />
117+ ) }
118+ </ Button >
119+ </ Tooltip . Trigger >
120+ < Button className = '-m-[4px] !p-[6px] group' variant = 'ghost' >
121+ < ChevronDown
122+ className = { `h-[8px] w-[10px] text-[var(--text-muted)] transition-transform duration-100 group-hover:text-[var(--text-secondary)] ${ isCanvasModeOpen ? 'rotate-180' : '' } ` }
123+ />
124+ </ Button >
125+ </ div >
126+ </ PopoverTrigger >
127+ < Tooltip . Content side = 'top' > { mode === 'hand' ? 'Mover' : 'Pointer' } </ Tooltip . Content >
128+ </ Tooltip . Root >
99129 < PopoverContent align = 'center' side = 'top' sideOffset = { 8 } maxWidth = { 100 } minWidth = { 100 } >
100130 < PopoverItem
101131 onClick = { ( ) => {
@@ -159,12 +189,14 @@ export function ActionBar() {
159189 < Button
160190 variant = 'ghost'
161191 className = 'h-[28px] w-[28px] rounded-[6px] p-0 hover:bg-[var(--surface-5)]'
162- onClick = { ( ) => fitViewToBounds ( { padding : 0.1 , duration : 300 } ) }
192+ onClick = { handleFitToView }
163193 >
164- < Expand className = 'h-[16px] w-[16px]' />
194+ < Scan className = 'h-[16px] w-[16px]' />
165195 </ Button >
166196 </ Tooltip . Trigger >
167- < Tooltip . Content side = 'top' > Zoom to fit</ Tooltip . Content >
197+ < Tooltip . Content side = 'top' >
198+ < Tooltip . Shortcut keys = '⌘⇧F' > Fit to View</ Tooltip . Shortcut >
199+ </ Tooltip . Content >
168200 </ Tooltip . Root >
169201 </ div >
170202
0 commit comments