feat: implement Phase 9 - Keyboard Shortcuts
All checks were successful
Build and Push Docker Image to Gitea / build-and-push (push) Successful in 1m11s

Features added:
- Created useKeyboardShortcuts hook for managing keyboard shortcuts
  - Supports modifier keys (Ctrl, Shift, Alt)
  - Automatically ignores shortcuts when input fields are focused
  - ESC key blurs input fields to enable shortcuts
- Added global keyboard shortcuts:
  - / : Focus search field
  - r : Refresh process list
  - a : Select all processes (flat view only)
  - ESC : Clear selection / unfocus
  - ? (Shift+/) : Show keyboard shortcuts help
- Added process navigation shortcuts:
  - j : Select next process
  - k : Select previous process
  - Space : Toggle selection of focused process
  - Auto-scroll to focused process
- Created KeyboardShortcutsHelp modal component:
  - Organized shortcuts by category
  - Visual kbd elements for keys
  - Info about input field behavior
- Added keyboard shortcuts button to processes page header
- Added isFocused prop to ProcessCard with accent ring styling
- Added data-process-id attributes for keyboard navigation

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
2025-11-23 19:50:17 +01:00
parent 4aa0c49372
commit 961020d8ac
4 changed files with 338 additions and 13 deletions

View File

@@ -14,10 +14,11 @@ import { cn } from '@/lib/utils/cn';
interface ProcessCardProps {
process: ProcessInfo;
isSelected?: boolean;
isFocused?: boolean;
onSelectionChange?: (processId: string, selected: boolean) => void;
}
export function ProcessCard({ process, isSelected = false, onSelectionChange }: ProcessCardProps) {
export function ProcessCard({ process, isSelected = false, isFocused = false, onSelectionChange }: ProcessCardProps) {
const [showSignalModal, setShowSignalModal] = useState(false);
const [showStdinModal, setShowStdinModal] = useState(false);
const startMutation = useStartProcess();
@@ -43,7 +44,8 @@ export function ProcessCard({ process, isSelected = false, onSelectionChange }:
className={cn(
'transition-all hover:shadow-lg animate-fade-in',
onSelectionChange && 'cursor-pointer',
isSelected && 'ring-2 ring-primary ring-offset-2'
isSelected && 'ring-2 ring-primary ring-offset-2',
isFocused && 'ring-2 ring-accent ring-offset-2 shadow-xl'
)}
onClick={onSelectionChange ? handleCardClick : undefined}
>