Files
vibe-kanban/frontend/src/contexts/search-context.tsx
Louis Knight-Webb 8891a0beac Re-implement keyboard shortcuts (#790)
* ## Complete 

I've successfully documented every keyboard shortcut in the vibe-kanban codebase using the Oracle's systematic 6-layer approach. The documentation is saved as [`KEYBOARD_SHORTCUTS.md`](file:///private/var/folders/m1/9q_ct1913z10v6wbnv54j25r0000gn/T/vibe-kanban/worktrees/vk-e6d8-document-e/KEYBOARD_SHORTCUTS.md).

**Key achievements:**
- **100% coverage** using exhaustiveness heuristic
- **47 unique shortcuts** catalogued across 15 components
- **Organized by context** (global, kanban, dialogs, etc.)
- **Platform-aware** (⌘ vs Ctrl differences noted)
- **Status tracking** for each search layer

The document includes the Oracle's recommended status heuristic showing all 6 layers were searched and confirmed complete.

* I've systematically removed all keyboard shortcuts from the vibe-kanban codebase following Oracle's expert guidance:

- **47 unique keyboard shortcuts** across 15 components
- **Main keyboard-shortcuts.ts library** (preserved but all hook usage removed)
- **Global shortcuts**: c, s, n, Escape, Enter navigation
- **Component shortcuts**: Arrow navigation, Ctrl+Enter submits, Escape cancels
- **Dropdown navigation**: Arrow keys, Enter/Tab selection, Escape closing
- **Search shortcuts**: Ctrl+S focus, visual "⌘S" hint
- **Dialog shortcuts**: Escape closing, keyboard submission
- **File search dropdowns**: Full keyboard navigation removed
- **Carousel navigation**: Arrow key controls
- **Kanban navigation**: Arrow key movement between tasks
- **Comment shortcuts**: Ctrl+Enter submit, Escape cancel

- **VSCode bridge functionality** (essential for integration)
- **Browser defaults** (copy/paste, form submission, etc.)
- **Essential form behavior** (Enter to submit still works via browser)
- **Mouse interactions** (all functionality accessible via mouse)

 Followed Oracle's 5-phase methodology
 One commit per phase for easy rollback
 Preserved business logic (only removed wiring)
 Backend compiles successfully
 No console errors from missing callbacks
 Application is fully mouse-navigable

The application now has a clean slate with zero custom keyboard shortcuts, ready for complete re-implementation from scratch while maintaining all essential functionality through mouse interaction and browser defaults.

* remove keyboard-shortcuts.ts

* Implement shortcuts (vibe-kanban 8aef7081)

Using react-hotkeys-hook, with proper scoping for different pages and components, please implement the following shortcuts:

* **Dialogs** — `frontend/src/components/ui/dialog.tsx`

  * `Esc` — Close dialog (when available)
  * `Enter` — Submit / confirm (when available)

* **Projects** - `frontend/src/pages/projects.tsx`

  * `c` — New project

* **Kanban** - `frontend/src/pages/project-tasks.tsx`

  * `c` — New task
  * `/` — Focus search in navbar
  * `Esc` - Navigate to projects page
  * `Arrow ↓ / ↑` — Move within column
  * `Arrow → / ←` — Next / previous column (focus first task)
  * `Enter` — Open task details

* **Sidebar** - `frontend/src/components/tasks/TaskDetailsPanel.tsx`

  * `Esc` — Close sidebar

* remove md

* centralise registry

* fmt

* refactor prevent default

* searchbar

* ring on selected card

* navigate kanban

* select first card when none selected

* cleanup

* refactor kanban filtering

* task edit/create shortcuts

* textarea keyboard shortcuts

* fix warnings

* follow up on cmd enter

* exit textarea

* restore multi-file

* save comments

* keyboard shortcuts for comments

* i18n for tasks page

* toggle fullscreen

* typesafe scopes

* fix delete dialog resolve/reject
2025-09-24 12:01:22 +01:00

81 lines
1.8 KiB
TypeScript

import {
createContext,
useContext,
useState,
useEffect,
useRef,
useCallback,
ReactNode,
} from 'react';
import { useLocation, useParams } from 'react-router-dom';
interface SearchState {
query: string;
setQuery: (query: string) => void;
active: boolean;
clear: () => void;
focusInput: () => void;
registerInputRef: (ref: HTMLInputElement | null) => void;
}
const SearchContext = createContext<SearchState | null>(null);
interface SearchProviderProps {
children: ReactNode;
}
export function SearchProvider({ children }: SearchProviderProps) {
const [query, setQuery] = useState('');
const location = useLocation();
const { projectId } = useParams<{ projectId: string }>();
const inputRef = useRef<HTMLInputElement | null>(null);
// Check if we're on a tasks route
const isTasksRoute = /^\/projects\/[^/]+\/tasks/.test(location.pathname);
// Clear search when leaving tasks pages
useEffect(() => {
if (!isTasksRoute && query !== '') {
setQuery('');
}
}, [isTasksRoute, query]);
// Clear search when project changes
useEffect(() => {
setQuery('');
}, [projectId]);
const clear = () => setQuery('');
const focusInput = () => {
if (inputRef.current && isTasksRoute) {
inputRef.current.focus();
}
};
const registerInputRef = useCallback((ref: HTMLInputElement | null) => {
inputRef.current = ref;
}, []);
const value: SearchState = {
query,
setQuery,
active: isTasksRoute,
clear,
focusInput,
registerInputRef,
};
return (
<SearchContext.Provider value={value}>{children}</SearchContext.Provider>
);
}
export function useSearch(): SearchState {
const context = useContext(SearchContext);
if (!context) {
throw new Error('useSearch must be used within a SearchProvider');
}
return context;
}