diff --git a/src/renderer/components/AppKeyboardShortcuts.tsx b/src/renderer/components/AppKeyboardShortcuts.tsx index c30153f7d..30f45d540 100644 --- a/src/renderer/components/AppKeyboardShortcuts.tsx +++ b/src/renderer/components/AppKeyboardShortcuts.tsx @@ -9,10 +9,18 @@ import { useTaskManagementContext } from '../contexts/TaskManagementContext'; export interface AppKeyboardShortcutsProps { showCommandPalette: boolean; showSettings: boolean; + showBrowser: boolean; + showDiffViewer: boolean; + showEditor: boolean; + showKanban: boolean; handleToggleCommandPalette: () => void; handleOpenSettings: () => void; handleCloseCommandPalette: () => void; handleCloseSettings: () => void; + handleCloseBrowser: () => void; + handleCloseDiffViewer: () => void; + handleCloseEditor: () => void; + handleCloseKanban: () => void; handleToggleKanban: () => void; handleToggleEditor: () => void; handleOpenInEditor: () => void; @@ -21,10 +29,18 @@ export interface AppKeyboardShortcutsProps { const AppKeyboardShortcuts: React.FC = ({ showCommandPalette, showSettings, + showBrowser, + showDiffViewer, + showEditor, + showKanban, handleToggleCommandPalette, handleOpenSettings, handleCloseCommandPalette, handleCloseSettings, + handleCloseBrowser, + handleCloseDiffViewer, + handleCloseEditor, + handleCloseKanban, handleToggleKanban, handleToggleEditor, handleOpenInEditor, @@ -55,13 +71,22 @@ const AppKeyboardShortcuts: React.FC = ({ new CustomEvent('emdash:switch-agent', { detail: { direction: 'prev' } }) ), onOpenInEditor: handleOpenInEditor, - onCloseModal: showCommandPalette - ? handleCloseCommandPalette - : showSettings - ? handleCloseSettings - : undefined, + onCloseModal: ( + [ + [showCommandPalette, handleCloseCommandPalette], + [showSettings, handleCloseSettings], + [showBrowser, handleCloseBrowser], + [showDiffViewer, handleCloseDiffViewer], + [showEditor, handleCloseEditor], + [showKanban, handleCloseKanban], + ] as const + ).find(([open]) => open)?.[1], isCommandPaletteOpen: showCommandPalette, isSettingsOpen: showSettings, + isBrowserOpen: showBrowser, + isDiffViewerOpen: showDiffViewer, + isEditorOpen: showEditor, + isKanbanOpen: showKanban, customKeyboardSettings: keyboardSettings ?? undefined, }); diff --git a/src/renderer/hooks/useKeyboardShortcuts.ts b/src/renderer/hooks/useKeyboardShortcuts.ts index 5da57e689..f0e7fc54d 100644 --- a/src/renderer/hooks/useKeyboardShortcuts.ts +++ b/src/renderer/hooks/useKeyboardShortcuts.ts @@ -487,12 +487,17 @@ export function useKeyboardShortcuts(handlers: GlobalShortcutHandlers) { // Command palette is blocking; settings behaves like a page and should // not force-close for global shortcuts. const isCommandPaletteOpen = Boolean(handlers.isCommandPaletteOpen); - const hasClosableOverlay = Boolean( - handlers.isCommandPaletteOpen || handlers.isSettingsOpen + const hasClosableView = Boolean( + handlers.isCommandPaletteOpen || + handlers.isSettingsOpen || + handlers.isBrowserOpen || + handlers.isDiffViewerOpen || + handlers.isEditorOpen || + handlers.isKanbanOpen ); - // Modal-priority shortcuts (like Escape) only work when an overlay is open - if (shortcut.priority === 'modal' && !hasClosableOverlay) continue; + // Modal-priority shortcuts (like Escape) only work when a closable view is open + if (shortcut.priority === 'modal' && !hasClosableView) continue; // Global shortcuts if (shortcut.priority === 'global') { diff --git a/src/renderer/types/shortcuts.ts b/src/renderer/types/shortcuts.ts index e41dabbe5..46ab71169 100644 --- a/src/renderer/types/shortcuts.ts +++ b/src/renderer/types/shortcuts.ts @@ -96,6 +96,10 @@ export interface GlobalShortcutHandlers { // State checks isCommandPaletteOpen?: boolean; isSettingsOpen?: boolean; + isBrowserOpen?: boolean; + isDiffViewerOpen?: boolean; + isEditorOpen?: boolean; + isKanbanOpen?: boolean; // Custom keyboard settings customKeyboardSettings?: KeyboardSettings; diff --git a/src/renderer/views/Workspace.tsx b/src/renderer/views/Workspace.tsx index 97095a747..4b25c1fda 100644 --- a/src/renderer/views/Workspace.tsx +++ b/src/renderer/views/Workspace.tsx @@ -34,7 +34,7 @@ import { activityStore } from '@/lib/activityStore'; import { handleMenuUndo, handleMenuRedo } from '@/lib/menuUndoRedo'; import { rpc } from '@/lib/rpc'; import { soundPlayer } from '@/lib/soundPlayer'; -import BrowserProvider from '@/providers/BrowserProvider'; +import BrowserProvider, { useBrowser } from '@/providers/BrowserProvider'; import { useState, useCallback, useEffect, useRef, useMemo } from 'react'; import { SettingsPageTab } from '@/components/SettingsPage'; const PANEL_RESIZE_DRAGGING_EVENT = 'emdash:panel-resize-dragging'; @@ -60,6 +60,20 @@ const RightSidebarBridge: React.FC<{ return null; }; +/** Bridge that reads BrowserProvider context and forwards it to AppKeyboardShortcuts */ +const BrowserAwareShortcuts: React.FC< + Omit, 'showBrowser' | 'handleCloseBrowser'> +> = (props) => { + const browser = useBrowser(); + return ( + + ); +}; + export function Workspace() { useTheme(); // Initialize theme on app startup const { showModal } = useModalContext(); @@ -100,6 +114,11 @@ export function Workspace() { const [showDiffViewer, setShowDiffViewer] = useState(false); const [diffViewerInitialFile, setDiffViewerInitialFile] = useState(null); const [diffViewerTaskPath, setDiffViewerTaskPath] = useState(null); + const handleCloseDiffViewer = useCallback(() => { + setShowDiffViewer(false); + setDiffViewerInitialFile(null); + setDiffViewerTaskPath(null); + }, []); const panelHandleDraggingRef = useRef>({ left: false, right: false, @@ -176,6 +195,8 @@ export function Workspace() { setShowKanban(false); setShowEditorMode((v) => !v); }, [setShowKanban, setShowEditorMode]); + const handleCloseEditor = useCallback(() => setShowEditorMode(false), [setShowEditorMode]); + const handleCloseKanban = useCallback(() => setShowKanban(false), [setShowKanban]); // --- Task management --- const taskMgmt = useTaskManagementContext(); @@ -313,13 +334,19 @@ export function Workspace() { - {showDiffViewer ? ( { - setShowDiffViewer(false); - setDiffViewerInitialFile(null); - setDiffViewerTaskPath(null); - }} + onClose={handleCloseDiffViewer} taskId={activeTask?.id} taskPath={diffViewerTaskPath || activeTask?.path} initialFile={diffViewerInitialFile} @@ -436,7 +459,7 @@ export function Workspace() { taskPath={activeTask.path} taskName={activeTask.name} projectName={selectedProject.name} - onClose={() => setShowEditorMode(false)} + onClose={handleCloseEditor} connectionId={derivedRemoteConnectionId} remotePath={derivedRemotePath} />