- Introduced a new FileIcon component to render file-type icons with support for Devicon CDN and fallback to lucide-react icons. - Added a glow effect for file icons in dark mode to improve visibility. - Updated various components to utilize the new FileIcon component for consistent icon rendering. - Refined keyboard shortcut handling to use event.code for layout-independent key detection, improving cross-platform compatibility. - Enhanced the EditorTabBar with a context menu for tab management, including options to close tabs and manage open files more efficiently.
92 lines
2.5 KiB
TypeScript
92 lines
2.5 KiB
TypeScript
/**
|
|
* Keyboard utility functions for platform-aware shortcuts
|
|
*/
|
|
|
|
/**
|
|
* Detect if running on macOS
|
|
*/
|
|
export function isMacOS(): boolean {
|
|
return navigator.userAgent.toLowerCase().includes('mac');
|
|
}
|
|
|
|
/**
|
|
* Resolve the physical key from a keyboard event, independent of keyboard layout.
|
|
*
|
|
* Uses `event.code` (physical key position on a QWERTY keyboard) to determine
|
|
* the key, so shortcuts work correctly regardless of active layout (Russian,
|
|
* Hebrew, Arabic, etc.).
|
|
*
|
|
* Returns a lowercase single character for letter keys, digit for number keys,
|
|
* the symbol for punctuation keys, or falls back to `event.key` for special
|
|
* keys (Tab, Enter, Escape, Arrow*, etc.) which are layout-independent.
|
|
*/
|
|
export function physicalKey(e: KeyboardEvent): string {
|
|
const { code, key } = e;
|
|
|
|
// Letter keys: KeyA → 'a', KeyF → 'f', KeyZ → 'z'
|
|
if (code.startsWith('Key') && code.length === 4) {
|
|
return code[3].toLowerCase();
|
|
}
|
|
|
|
// Digit keys: Digit0 → '0', Digit9 → '9'
|
|
if (code.startsWith('Digit') && code.length === 6) {
|
|
return code[5];
|
|
}
|
|
|
|
// Punctuation / symbol keys
|
|
switch (code) {
|
|
case 'BracketLeft':
|
|
return '[';
|
|
case 'BracketRight':
|
|
return ']';
|
|
case 'Backslash':
|
|
return '\\';
|
|
case 'Comma':
|
|
return ',';
|
|
case 'Period':
|
|
return '.';
|
|
case 'Slash':
|
|
return '/';
|
|
case 'Semicolon':
|
|
return ';';
|
|
case 'Quote':
|
|
return "'";
|
|
case 'Minus':
|
|
return '-';
|
|
case 'Equal':
|
|
return '=';
|
|
case 'Backquote':
|
|
return '`';
|
|
default:
|
|
// Special keys: Tab, Enter, Escape, ArrowUp, ArrowDown, Space, etc.
|
|
return key;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Get the primary modifier key name for the current platform
|
|
* @returns 'Cmd' on macOS, 'Ctrl' on other platforms
|
|
*/
|
|
export function getModifierKeyName(): string {
|
|
return isMacOS() ? 'Cmd' : 'Ctrl';
|
|
}
|
|
|
|
/**
|
|
* Get the primary modifier key symbol for the current platform
|
|
* @returns '⌘' on macOS, 'Ctrl' on other platforms
|
|
*/
|
|
export function getModifierKeySymbol(): string {
|
|
return isMacOS() ? '⌘' : 'Ctrl';
|
|
}
|
|
|
|
/**
|
|
* Format a keyboard shortcut for display
|
|
* @param key - The key to press (e.g., 'K', 'G', 'Enter')
|
|
* @param useSymbol - Whether to use symbols (⌘) or text (Cmd)
|
|
* @returns Formatted shortcut string (e.g., '⌘K' or 'Ctrl+K')
|
|
*/
|
|
export function formatModifierShortcut(key: string, useSymbol = true): string {
|
|
const modifier = useSymbol ? getModifierKeySymbol() : getModifierKeyName();
|
|
const separator = useSymbol && isMacOS() ? '' : '+';
|
|
return `${modifier}${separator}${key}`;
|
|
}
|