Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
17 commits
Select commit Hold shift + click to select a range
b360cfc
add arc-style keyboard shortcuts system with workspace and tab naviga…
caffeinum Nov 6, 2025
4aca4ab
implement remaining shortcuts: split views and close tab
caffeinum Nov 6, 2025
562e8a7
fix keyboard shortcuts: auto-focus terminals and cmd+w reliability
caffeinum Nov 6, 2025
497cc38
cmd+t new tab
caffeinum Nov 6, 2025
295f0fd
fix tab navigation to work within tab groups
caffeinum Nov 6, 2025
0848154
improve keyboard shortcuts: cmd+t, cmd+w, and cmd+1-9
caffeinum Nov 6, 2025
28c0e85
fix terminal focus when selecting tabs inside tab groups
caffeinum Nov 6, 2025
8e53d26
fix cmd+t to show new terminal immediately without refresh
caffeinum Nov 6, 2025
8b30a34
fix cmd+t sidebar not updating by refreshing workspaces list
caffeinum Nov 6, 2025
343cdc3
fix cmd+w sidebar not updating by refreshing workspaces list
caffeinum Nov 6, 2025
f266c3f
improve split view shortcuts: auto-focus, sidebar updates, and proper…
caffeinum Nov 6, 2025
ed46120
implement auto-close terminal tab on exit
caffeinum Nov 6, 2025
7c1f57d
fix terminal display glitches: scroll position and padding-aware sizing
caffeinum Nov 6, 2025
2e2149b
Revert "fix terminal display glitches: scroll position and padding-aw…
caffeinum Nov 6, 2025
fdd3d3c
improve sidebar controls and fix split view refresh issues
caffeinum Nov 6, 2025
2b640d1
Revert "fix keyboard shortcuts: auto-focus terminals and cmd+w reliab…
caffeinum Nov 6, 2025
eba2f85
fix: handle undefined mosaicTree and correct worktree ID in tab selec…
caffeinum Nov 6, 2025
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
44 changes: 44 additions & 0 deletions CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -178,3 +178,47 @@ Each instance needs:
- **Separate user data directory** - Pass via `--user-data-dir` flag

The desktop app loads environment variables from the monorepo root `.env` file.

### Keyboard Shortcuts System

The desktop app uses a centralized keyboard shortcuts system inspired by Arc Browser.

**File Structure:**
- `src/renderer/lib/keyboard-shortcuts.ts` - Core shortcuts infrastructure (types, matchers, handlers)
- `src/renderer/lib/shortcuts.ts` - Arc-style shortcut definitions (workspace, tab, terminal)

**Implemented Shortcuts:**

**Workspace Management:**
- `Cmd+Option+Left/Right` - Switch between workspaces
- `Cmd+S` - Toggle sidebar visibility
- `Cmd+D` - Create split view (horizontal)
- `Cmd+Shift+D` - Create split view (vertical)

**Tab Management:**
- `Cmd+Option+Up/Down` - Switch between tabs
- `Cmd+T` - Create new tab
- `Cmd+W` - Close tab
- `Cmd+Shift+T` - Reopen closed tab [TODO - requires history tracking]
- `Cmd+1-9` - Jump to tab by position

**Terminal:**
- `Cmd+K` - Clear terminal (scrollback + screen)

**Adding New Shortcuts:**

1. Define handlers in the component (e.g., `MainScreen.tsx`)
2. Create shortcut group using helper functions from `shortcuts.ts`
3. Use `createShortcutHandler` to convert to event handler
4. Attach to event listener or terminal custom key handler

**Example:**
```typescript
const shortcuts = createWorkspaceShortcuts({
switchToPrevWorkspace: () => { /* handler logic */ },
// ... other handlers
});

const handleKeyDown = createShortcutHandler(shortcuts.shortcuts);
window.addEventListener("keydown", handleKeyDown);
```
13 changes: 13 additions & 0 deletions apps/desktop/src/main/lib/terminal.ts
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,19 @@ class TerminalManager {
this.addTerminalMessage(id, data);
});

// Handle terminal exit
ptyProcess.onExit(({ exitCode }) => {
console.log(`Terminal ${id} exited with code ${exitCode}`);
// Notify renderer that terminal has exited
this.mainWindow?.webContents.send("terminal-exited", {
id,
exitCode,
});
// Clean up
this.processes.delete(id);
this.outputHistory.delete(id);
});

this.processes.set(id, ptyProcess);
return id;
} catch (error) {
Expand Down
97 changes: 97 additions & 0 deletions apps/desktop/src/renderer/lib/keyboard-shortcuts.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@
/**
* Keyboard shortcuts module
* Central place for all keyboard shortcut definitions and handling
*/

export type ModifierKey = "meta" | "ctrl" | "alt" | "shift";

export interface KeyboardShortcut {
key: string;
modifiers?: ModifierKey[];
description: string;
handler: (event: KeyboardEvent) => boolean | void;
}

export interface KeyboardShortcutGroup {
name: string;
shortcuts: KeyboardShortcut[];
}

/**
* Check if event matches the shortcut definition
*/
export function matchesShortcut(
event: KeyboardEvent,
shortcut: KeyboardShortcut,
): boolean {
// Check key match (case insensitive)
if (event.key.toLowerCase() !== shortcut.key.toLowerCase()) {
return false;
}

// Check modifiers
const modifiers = shortcut.modifiers || [];
const hasCtrl = modifiers.includes("ctrl");
const hasMeta = modifiers.includes("meta");
const hasAlt = modifiers.includes("alt");
const hasShift = modifiers.includes("shift");

return (
event.ctrlKey === hasCtrl &&
event.metaKey === hasMeta &&
event.altKey === hasAlt &&
event.shiftKey === hasShift
);
}

/**
* Create a keyboard event handler that processes multiple shortcuts
*/
export function createShortcutHandler(shortcuts: KeyboardShortcut[]) {
return (event: KeyboardEvent): boolean => {
for (const shortcut of shortcuts) {
if (matchesShortcut(event, shortcut)) {
const result = shortcut.handler(event);
// If handler returns false, prevent default and stop propagation
if (result === false) {
event.preventDefault();
return false;
}
}
}
// Allow event to propagate normally
return true;
};
}

/**
* Format shortcut for display (e.g., "Cmd+K" or "Ctrl+Shift+P")
*/
export function formatShortcut(shortcut: KeyboardShortcut): string {
const modifiers = shortcut.modifiers || [];
const parts: string[] = [];

// Use platform-specific display names
const isMac = navigator.platform.toLowerCase().includes("mac");

for (const mod of modifiers) {
switch (mod) {
case "meta":
parts.push(isMac ? "Cmd" : "Win");
break;
case "ctrl":
parts.push("Ctrl");
break;
case "alt":
parts.push(isMac ? "Opt" : "Alt");
break;
case "shift":
parts.push("Shift");
break;
}
}

parts.push(shortcut.key.toUpperCase());

return parts.join("+");
}
199 changes: 199 additions & 0 deletions apps/desktop/src/renderer/lib/shortcuts.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,199 @@
/**
* Arc-style keyboard shortcuts for Superset
*/

import type {
KeyboardShortcut,
KeyboardShortcutGroup,
} from "./keyboard-shortcuts";

export interface ShortcutHandlers {
// Workspace management
switchToPrevWorkspace: () => void;
switchToNextWorkspace: () => void;
toggleSidebar: () => void;
createSplitView: () => void;
createVerticalSplit: () => void;

// Tab management
switchToPrevTab: () => void;
switchToNextTab: () => void;
newTab: () => void;
closeTab: () => void;
reopenClosedTab: () => void;
jumpToTab: (index: number) => void;

// Terminal specific
clearTerminal: () => void;
}

export function createWorkspaceShortcuts(
handlers: Pick<
ShortcutHandlers,
| "switchToPrevWorkspace"
| "switchToNextWorkspace"
| "toggleSidebar"
| "createSplitView"
| "createVerticalSplit"
>,
): KeyboardShortcutGroup {
return {
name: "Workspace Management",
shortcuts: [
{
key: "ArrowLeft",
modifiers: ["meta", "alt"],
description: "Switch to previous workspace",
handler: (event) => {
event.preventDefault();
handlers.switchToPrevWorkspace();
return false;
},
},
{
key: "ArrowRight",
modifiers: ["meta", "alt"],
description: "Switch to next workspace",
handler: (event) => {
event.preventDefault();
handlers.switchToNextWorkspace();
return false;
},
},
{
key: "s",
modifiers: ["meta"],
description: "Toggle sidebar visibility",
handler: (event) => {
event.preventDefault();
handlers.toggleSidebar();
return false;
},
},
{
key: "d",
modifiers: ["meta"],
description: "Create split view (horizontal)",
handler: (event) => {
event.preventDefault();
handlers.createSplitView();
return false;
},
},
{
key: "d",
modifiers: ["meta", "shift"],
description: "Create split view (vertical)",
handler: (event) => {
event.preventDefault();
handlers.createVerticalSplit();
return false;
},
},
],
};
}

export function createTabShortcuts(
handlers: Pick<
ShortcutHandlers,
| "switchToPrevTab"
| "switchToNextTab"
| "newTab"
| "closeTab"
| "reopenClosedTab"
| "jumpToTab"
>,
): KeyboardShortcutGroup {
const shortcuts: KeyboardShortcut[] = [
{
key: "ArrowUp",
modifiers: ["meta", "alt"],
description: "Switch to previous tab",
handler: (event) => {
event.preventDefault();
handlers.switchToPrevTab();
return false;
},
},
{
key: "ArrowDown",
modifiers: ["meta", "alt"],
description: "Switch to next tab",
handler: (event) => {
event.preventDefault();
handlers.switchToNextTab();
return false;
},
},
{
key: "t",
modifiers: ["meta"],
description: "Create new tab",
handler: (event) => {
event.preventDefault();
handlers.newTab();
return false;
},
},
{
key: "w",
modifiers: ["meta"],
description: "Close current tab",
handler: (event) => {
event.preventDefault();
handlers.closeTab();
return false;
},
},
{
key: "t",
modifiers: ["meta", "shift"],
description: "Reopen closed tab",
handler: (event) => {
event.preventDefault();
handlers.reopenClosedTab();
return false;
},
},
];

// Add Cmd+1-9 shortcuts for jumping to tabs
for (let i = 1; i <= 9; i++) {
shortcuts.push({
key: i.toString(),
modifiers: ["meta"],
description: `Jump to tab ${i}`,
handler: (event) => {
event.preventDefault();
handlers.jumpToTab(i);
return false;
},
});
}

return {
name: "Tab Management",
shortcuts,
};
}

export function createTerminalShortcuts(
handlers: Pick<ShortcutHandlers, "clearTerminal">,
): KeyboardShortcutGroup {
return {
name: "Terminal",
shortcuts: [
{
key: "k",
modifiers: ["meta"],
description: "Clear terminal (scrollback + screen)",
handler: (event) => {
event.preventDefault();
handlers.clearTerminal();
return false;
},
},
],
};
}
Loading
Loading