# Ticket 11.5 — Keyboard Shortcuts

**Phase**: 11 — UI/UX Polish
**Priority**: Medium
**Depends on**: None

## Description

conduit has no keyboard shortcuts for common actions. claude-relay doesn't have a formal shortcut system either, but the lack of any shortcuts in conduit makes power-user workflows slower than necessary.

Implement a lightweight keyboard shortcut system with these bindings:

- `Cmd/Ctrl + K`: Focus the slash command menu (or open a command palette)
- `Cmd/Ctrl + B`: Toggle sidebar
- `` Cmd/Ctrl + ` ``: Toggle terminal panel
- `Cmd/Ctrl + N`: Create new session
- `Cmd/Ctrl + Shift + F`: Toggle file browser
- `Escape`: Close any open modal/overlay/panel, or blur input
- `/` (when input not focused): Focus input with `/` prefix for slash commands

The shortcut system should:

- Use a centralized handler (not scattered event listeners)
- Prevent default browser actions for claimed shortcuts
- Be discoverable (shown in tooltips or a help modal)
- Respect input focus (don't trigger shortcuts while typing in textarea)

## Acceptance Criteria

### AC1: Toggle sidebar
```gherkin
Given the user is not focused on a text input or textarea
When they press Cmd+B (Mac) or Ctrl+B (Windows/Linux)
Then the sidebar toggles between open and closed states
And the default browser action (e.g., bold text) is prevented
```

### AC2: Toggle terminal panel
```gherkin
Given the user is not focused on a text input or textarea
When they press Cmd+` (Mac) or Ctrl+` (Windows/Linux)
Then the terminal panel toggles between open and closed states
```

### AC3: Create new session
```gherkin
Given the user is not focused on a text input or textarea
When they press Cmd+N (Mac) or Ctrl+N (Windows/Linux)
Then a new session is created
And the default browser action (e.g., new window) is prevented
```

### AC4: Toggle file browser
```gherkin
Given the user is not focused on a text input or textarea
When they press Cmd+Shift+F (Mac) or Ctrl+Shift+F (Windows/Linux)
Then the file browser panel toggles between open and closed states
And the default browser action (e.g., find in page) is prevented
```

### AC5: Escape closes topmost overlay
```gherkin
Given a modal, overlay, or panel is currently open
When the user presses the Escape key
Then the topmost open modal, overlay, or panel is closed
And if no modal/overlay/panel is open, the currently focused input is blurred
```

### AC6: Shortcuts suppressed during text input
```gherkin
Given the user is focused on the chat textarea or any text input
When they press a keyboard shortcut (e.g., Cmd+B)
Then the shortcut action does not fire
And the keypress is handled normally by the input field
```

### AC7: Shortcut hints in tooltips
```gherkin
Given a button has an associated keyboard shortcut
When the user hovers over that button
Then the tooltip displays the shortcut key combination
And the modifier key matches the user's platform (⌘ for Mac, Ctrl for others)
```

## Testable Components

| Component | Test Type | What to Assert |
|-----------|-----------|----------------|
| Centralized keydown handler dispatches correct actions | Unit | Handler maps key combos to action functions; each binding triggers the right action |
| Modifier key detection (Cmd on Mac, Ctrl on Windows) | Unit | `metaKey` used on Mac, `ctrlKey` used on non-Mac platforms |
| Input focus guard prevents shortcut firing during typing | Unit | Handler returns early when `event.target` is an input or textarea element |
| Sidebar toggle via Cmd/Ctrl+B | E2E | Pressing shortcut toggles sidebar visibility state |
| Terminal toggle via Cmd/Ctrl+` | E2E | Pressing shortcut toggles terminal panel visibility state |
| New session via Cmd/Ctrl+N | E2E | Pressing shortcut creates a new session and navigates to it |
| Escape closes modal | E2E | Pressing Escape with an open modal closes it |
| Tooltip shows shortcut hint | E2E | Button tooltip text includes keyboard shortcut string |
| preventDefault called for claimed shortcuts | Unit | `event.preventDefault()` is called when a shortcut matches |

## Reference

- Current lack of shortcuts: no keydown listeners outside InputArea/CommandMenu
- InputArea: `conduit/src/lib/public/components/layout/InputArea.svelte`
- UI store: `conduit/src/lib/public/stores/ui.svelte.ts` (sidebar, terminal, file browser state)
