- Fix LogStreamPanel event listener cleanup with synchronous unlisten - Fix eventBus async-unsafe unsubscribe with proper error handling - Fix KubernetesPage infinite loading by resetting state on section change - Add ErrorBoundary component with reset capability - Add Badge component with multiple variants - Add ResourceDetailsDrawer for slide-out details panel - Add useFavorites hook with localStorage persistence - Add useKeyboardShortcuts hook for declarative shortcuts - Add comprehensive test coverage for all new components/hooks - Add keyboard shortcuts documentation to README - Wrap KubernetesPage with ErrorBoundary for crash recovery - Install react-window for virtual scrolling support Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
56 lines
1.9 KiB
TypeScript
56 lines
1.9 KiB
TypeScript
import { useEffect, useCallback, useRef } from "react";
|
|
|
|
export interface KeyboardShortcut {
|
|
key: string;
|
|
ctrl?: boolean;
|
|
alt?: boolean;
|
|
shift?: boolean;
|
|
meta?: boolean;
|
|
callback: () => void;
|
|
description: string;
|
|
enabled?: boolean;
|
|
}
|
|
|
|
export function useKeyboardShortcuts(shortcuts: KeyboardShortcut[]): void {
|
|
const shortcutsRef = useRef(shortcuts);
|
|
shortcutsRef.current = shortcuts;
|
|
|
|
const handleKeyDown = useCallback((event: KeyboardEvent) => {
|
|
for (const shortcut of shortcutsRef.current) {
|
|
if (shortcut.enabled === false) continue;
|
|
|
|
const ctrlMatch = shortcut.ctrl ? event.ctrlKey || event.metaKey : !event.ctrlKey && !event.metaKey;
|
|
const altMatch = shortcut.alt ? event.altKey : !event.altKey;
|
|
const shiftMatch = shortcut.shift ? event.shiftKey : !event.shiftKey;
|
|
const metaMatch = shortcut.meta ? event.metaKey : !event.metaKey;
|
|
|
|
if (
|
|
event.key.toLowerCase() === shortcut.key.toLowerCase() &&
|
|
ctrlMatch &&
|
|
altMatch &&
|
|
shiftMatch &&
|
|
metaMatch
|
|
) {
|
|
event.preventDefault();
|
|
shortcut.callback();
|
|
break;
|
|
}
|
|
}
|
|
}, []);
|
|
|
|
useEffect(() => {
|
|
document.addEventListener("keydown", handleKeyDown);
|
|
return () => document.removeEventListener("keydown", handleKeyDown);
|
|
}, [handleKeyDown]);
|
|
}
|
|
|
|
export const GLOBAL_SHORTCUTS = {
|
|
COMMAND_PALETTE: { key: "k", ctrl: true, description: "Open command palette" },
|
|
REFRESH: { key: "r", ctrl: true, description: "Refresh current view" },
|
|
SEARCH: { key: "f", ctrl: true, description: "Focus search" },
|
|
HELP: { key: "?", shift: true, description: "Show keyboard shortcuts" },
|
|
ESCAPE: { key: "Escape", description: "Close modal/dialog" },
|
|
NAVIGATE_UP: { key: "ArrowUp", ctrl: true, description: "Navigate up" },
|
|
NAVIGATE_DOWN: { key: "ArrowDown", ctrl: true, description: "Navigate down" },
|
|
} as const;
|