Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
36 changes: 36 additions & 0 deletions apps/sim/app/workspace/[workspaceId]/utils/commands-utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ export type CommandId =
| 'accept-diff-changes'
| 'add-agent'
| 'add-workflow'
| 'collapse-sidebar'
| 'goto-logs'
| 'open-search'
| 'open-workflow-search-replace'
Expand Down Expand Up @@ -57,6 +58,11 @@ export const COMMAND_DEFINITIONS: Record<CommandId, CommandDefinition> = {
shortcut: 'Mod+Shift+P',
allowInEditable: false,
},
'collapse-sidebar': {
id: 'collapse-sidebar',
shortcut: 'Mod+B',
allowInEditable: false,
},
Comment thread
waleedlatif1 marked this conversation as resolved.
Comment thread
waleedlatif1 marked this conversation as resolved.
'goto-logs': {
id: 'goto-logs',
shortcut: 'Mod+L',
Expand Down Expand Up @@ -144,3 +150,33 @@ export function createCommand(input: CreateCommandInput): GlobalCommand {
export function createCommands(inputs: CreateCommandInput[]): GlobalCommand[] {
return inputs.map((input) => createCommand(input))
}

/** Display symbols for shortcut modifiers on macOS. */
const MAC_MODIFIER_SYMBOLS: Record<string, string> = {
Mod: '⌘',
Shift: '⇧',
Alt: '⌥',
}

/** Display labels for shortcut modifiers on Windows/Linux. */
const NON_MAC_MODIFIER_LABELS: Record<string, string> = {
Mod: 'Ctrl',
Shift: 'Shift',
Alt: 'Alt',
}

/**
* Formats a command's shortcut for display, deriving the keys from
* {@link COMMAND_DEFINITIONS} so tooltips never drift from the registered
* binding. macOS renders compact symbols (`⌘⇧P`); other platforms render
* `+`-joined labels (`Ctrl+Shift+P`).
*
* @param id - Command whose shortcut to format.
* @param isMac - Whether to render macOS symbols instead of Windows/Linux labels.
*/
export function formatCommandShortcut(id: CommandId, isMac: boolean): string {
const tokens = COMMAND_DEFINITIONS[id].shortcut.split('+')
return isMac
? tokens.map((token) => MAC_MODIFIER_SYMBOLS[token] ?? token).join('')
: tokens.map((token) => NON_MAC_MODIFIER_LABELS[token] ?? token).join('+')
}
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ import {
Plus,
Send,
Skeleton,
Tooltip,
} from '@/components/emcn'
import { ManageWorkspace, PanelLeft } from '@/components/emcn/icons'
import { cn } from '@/lib/core/utils/cn'
Expand Down Expand Up @@ -68,6 +69,8 @@ interface WorkspaceHeaderProps {
isCollapsed?: boolean
/** Callback to expand the sidebar from collapsed state */
onExpandSidebar?: () => void
/** Formatted keyboard shortcut shown in the expand affordance tooltip */
expandShortcut?: string
}

/**
Expand All @@ -93,6 +96,7 @@ function WorkspaceHeaderImpl({
sessionUserId,
isCollapsed = false,
onExpandSidebar,
expandShortcut,
}: WorkspaceHeaderProps) {
const [isCreateModalOpen, setIsCreateModalOpen] = useState(false)
const [isInviteModalOpen, setIsInviteModalOpen] = useState(false)
Expand Down Expand Up @@ -270,41 +274,52 @@ function WorkspaceHeaderImpl({
return (
<div className='min-w-0 flex-1'>
{isMounted && isCollapsed ? (
<button
type='button'
aria-label='Expand sidebar'
onClick={onExpandSidebar}
className={chipVariants({ fullWidth: true })}
>
<div className='relative flex size-[16px] flex-shrink-0 items-center justify-center'>
{!activeWorkspaceFull ? (
<Skeleton className='size-[16px] rounded-sm' />
) : (
<>
{activeWorkspaceFull.logoUrl ? (
<img
src={activeWorkspaceFull.logoUrl}
alt={activeWorkspaceFull.name || 'Workspace logo'}
className='size-[16px] rounded-sm object-cover group-hover:invisible'
/>
<Tooltip.Root>
<Tooltip.Trigger asChild>
<button
type='button'
aria-label='Expand sidebar'
onClick={onExpandSidebar}
className={chipVariants({ fullWidth: true })}
>
<div className='relative flex size-[16px] flex-shrink-0 items-center justify-center'>
{!activeWorkspaceFull ? (
<Skeleton className='size-[16px] rounded-sm' />
) : (
<div
className='flex size-[16px] items-center justify-center rounded-sm font-medium text-[9px] text-white leading-none group-hover:invisible'
style={{
backgroundColor: activeWorkspaceFull.color ?? 'var(--brand-accent)',
}}
>
{workspaceInitial}
</div>
<>
{activeWorkspaceFull.logoUrl ? (
<img
src={activeWorkspaceFull.logoUrl}
alt={activeWorkspaceFull.name || 'Workspace logo'}
className='size-[16px] rounded-sm object-cover group-hover:invisible'
/>
) : (
<div
className='flex size-[16px] items-center justify-center rounded-sm font-medium text-[9px] text-white leading-none group-hover:invisible'
style={{
backgroundColor: activeWorkspaceFull.color ?? 'var(--brand-accent)',
}}
>
{workspaceInitial}
</div>
)}
<PanelLeft
aria-hidden
className='pointer-events-none invisible absolute inset-0 m-auto size-[16px] rotate-180 text-[var(--text-icon)] group-hover:visible'
/>
</>
Comment thread
waleedlatif1 marked this conversation as resolved.
)}
<PanelLeft
aria-hidden
className='pointer-events-none invisible absolute inset-0 m-auto size-[16px] rotate-180 text-[var(--text-icon)] group-hover:visible'
/>
</>
</div>
</button>
</Tooltip.Trigger>
<Tooltip.Content side='right'>
{expandShortcut ? (
<Tooltip.Shortcut keys={expandShortcut}>Expand sidebar</Tooltip.Shortcut>
) : (
<p>Expand sidebar</p>
)}
</div>
</button>
</Tooltip.Content>
</Tooltip.Root>
) : isMounted && isWorkspaceReady ? (
<DropdownMenu
open={isWorkspaceMenuOpen}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,10 @@ import { buildFolderTree, getFolderPath } from '@/lib/folders/tree'
import { captureEvent } from '@/lib/posthog/client'
import { useRegisterGlobalCommands } from '@/app/workspace/[workspaceId]/providers/global-commands-provider'
import { useUserPermissionsContext } from '@/app/workspace/[workspaceId]/providers/workspace-permissions-provider'
import { createCommands } from '@/app/workspace/[workspaceId]/utils/commands-utils'
import {
createCommands,
formatCommandShortcut,
} from '@/app/workspace/[workspaceId]/utils/commands-utils'
import {
CollapsedChatFlyoutItem,
CollapsedFolderItems,
Expand Down Expand Up @@ -118,18 +121,20 @@ export function SidebarTooltip({
label,
enabled,
side = 'right',
shortcut,
}: {
children: React.ReactElement
label: string
enabled: boolean
side?: 'right' | 'bottom'
shortcut?: string
}) {
if (!enabled) return children
return (
<Tooltip.Root>
<Tooltip.Trigger asChild>{children}</Tooltip.Trigger>
<Tooltip.Content side={side}>
<p>{label}</p>
{shortcut ? <Tooltip.Shortcut keys={shortcut}>{label}</Tooltip.Shortcut> : <p>{label}</p>}
</Tooltip.Content>
</Tooltip.Root>
)
Expand Down Expand Up @@ -388,6 +393,7 @@ export const Sidebar = memo(function Sidebar() {
}, [isCollapsed])

const isMac = isMacPlatform()
const collapseShortcut = formatCommandShortcut('collapse-sidebar', isMac)

const [showCollapsedTooltips, setShowCollapsedTooltips] = useState(isCollapsed)

Expand Down Expand Up @@ -1218,6 +1224,12 @@ export const Sidebar = memo(function Sidebar() {
handleCreateWorkflow()
},
},
{
id: 'collapse-sidebar',
handler: () => {
toggleCollapsed()
},
},
])
)

Expand Down Expand Up @@ -1267,8 +1279,14 @@ export const Sidebar = memo(function Sidebar() {
sessionUserId={sessionData?.user?.id}
isCollapsed={isCollapsed}
onExpandSidebar={toggleCollapsed}
expandShortcut={collapseShortcut}
/>
<SidebarTooltip label='Collapse sidebar' enabled={!isCollapsed} side='bottom'>
<SidebarTooltip
label='Collapse sidebar'
enabled={!isCollapsed}
side='bottom'
shortcut={collapseShortcut}
>
Comment thread
waleedlatif1 marked this conversation as resolved.
<button
type='button'
onClick={toggleCollapsed}
Expand Down
Loading