diff --git a/app/playground/page.tsx b/app/playground/page.tsx index f6a7bde..9357f72 100644 --- a/app/playground/page.tsx +++ b/app/playground/page.tsx @@ -1,5 +1,5 @@ import { TerminalApp } from '@/components/terminal-app' -import { Terminal, TerminalCommand, TerminalDiff, TerminalOutput, TerminalSpinner, TerminalBadge, ThemeSwitcher } from '@/components/terminal' +import { Terminal, TerminalCommand, TerminalDiff, TerminalOutput, TerminalSpinner, TerminalBadge, ThemeSwitcher, TerminalKeybinding } from '@/components/terminal' import { TerminalProgress } from '@/components/terminal-progress' import { LogDemo } from './log-demo' import { PromptDemo } from './prompt-demo' @@ -175,6 +175,30 @@ export default function PlaygroundPage() { + +
+

+ TerminalKeybinding +

+

+ Display keyboard shortcuts in terminal-style format. +

+ + show-shortcuts + +
+ + + + + + + + +
+
+
+
) } diff --git a/components/terminal-keybinding.tsx b/components/terminal-keybinding.tsx new file mode 100644 index 0000000..1def0bc --- /dev/null +++ b/components/terminal-keybinding.tsx @@ -0,0 +1,114 @@ +'use client' + +import { ReactNode } from 'react' + +export interface TerminalKeybindingProps { + /** Keyboard shortcut (e.g., 'Ctrl+C', 'Alt+Tab', '↑') */ + keys: string + /** Optional description of the action */ + description?: string + /** Variant color (default: 'neutral') */ + variant?: 'neutral' | 'success' | 'error' | 'warning' | 'info' + /** Additional CSS classes */ + className?: string +} + +const variantClasses: Record, string> = { + neutral: 'border-[var(--glass-border)] text-[var(--term-fg)]', + success: 'border-[var(--term-green)]/40 text-[var(--term-green)]', + error: 'border-[var(--term-red)]/40 text-[var(--term-red)]', + warning: 'border-[var(--term-yellow)]/40 text-[var(--term-yellow)]', + info: 'border-[var(--term-blue)]/40 text-[var(--term-blue)]', +} + +// Special key mappings for consistent display +const KEY_DISPLAY_MAP: Record = { + // Modifiers + ctrl: 'Ctrl', + control: 'Ctrl', + cmd: 'Cmd', + command: 'Cmd', + meta: 'Meta', + alt: 'Alt', + option: 'Alt', + shift: 'Shift', + // Special keys + enter: 'Enter', + return: 'Enter', + esc: 'Esc', + escape: 'Esc', + tab: 'Tab', + space: 'Space', + backspace: 'Backspace', + delete: 'Del', + // Arrow keys (support both symbols and names) + up: '↑', + down: '↓', + left: '←', + right: '→', + arrowup: '↑', + arrowdown: '↓', + arrowleft: '←', + arrowright: '→', +} + +/** + * Displays keyboard shortcuts in terminal-style format. + * Parses key combinations and renders them as styled badges. + * + * @param keys - Keyboard shortcut string (e.g., 'Ctrl+C', 'Alt+Tab', '↑') + * @param description - Optional description of what the shortcut does + * @param variant - Visual variant for semantic color + * @param className - Additional classes applied to the root element + * + * @example + * ```tsx + * + * + * + * + * ``` + */ +export function TerminalKeybinding({ + keys, + description, + variant = 'neutral', + className = '', +}: TerminalKeybindingProps) { + // Parse the keys string (split by + or -) + const keyParts = keys + .split(/[\+\-]/) + .map((k) => k.trim()) + .filter(Boolean) + .map((k) => { + const lower = k.toLowerCase() + return KEY_DISPLAY_MAP[lower] || k + }) + + const variantClass = variantClasses[variant] + + return ( +
+ {/* Key badges */} + + {keyParts.map((key, i) => ( + + {i > 0 && ( + + + )} + + {key} + + + ))} + + + {/* Optional description */} + {description && ( + {description} + )} +
+ ) +} diff --git a/components/terminal.tsx b/components/terminal.tsx index 56c9e1f..5c690f7 100644 --- a/components/terminal.tsx +++ b/components/terminal.tsx @@ -264,3 +264,4 @@ export { TerminalAutocomplete, useAutocomplete, COMMON_COMMANDS, COMMON_FLAGS, f export { TerminalGhosttyTheme, GhosttyThemePicker } from './terminal-ghostty' export { ThemeSwitcher } from './theme-switcher' export { TerminalBadge } from './terminal-badge' +export { TerminalKeybinding } from './terminal-keybinding'