feat(ui): show platform-specific shortcut labels
This commit is contained in:
@@ -5,7 +5,12 @@ import React from 'react';
|
||||
import { Icon } from '@/components/icon/Icon';
|
||||
import { Tooltip, TooltipContent, TooltipTrigger } from '@/components/ui/tooltip';
|
||||
import { useI18n } from '@/lib/i18n';
|
||||
import { cn, isMacOS } from '@/lib/utils';
|
||||
import {
|
||||
formatShortcutForDisplay,
|
||||
getEffectiveShortcutCombo,
|
||||
} from '@/lib/shortcuts';
|
||||
import { cn } from '@/lib/utils';
|
||||
import { useUIStore } from '@/stores/useUIStore';
|
||||
|
||||
type FocusModeButtonProps = {
|
||||
footerIconButtonClass: string;
|
||||
@@ -17,6 +22,12 @@ type FocusModeButtonProps = {
|
||||
export const FocusModeButton = React.memo(function FocusModeButton(props: FocusModeButtonProps) {
|
||||
const { footerIconButtonClass, iconSizeClass, isExpandedInput, onToggle } = props;
|
||||
const { t } = useI18n();
|
||||
const expandInputShortcutOverride = useUIStore((state) => state.shortcutOverrides.expand_input);
|
||||
const expandInputCombo = getEffectiveShortcutCombo(
|
||||
'expand_input',
|
||||
expandInputShortcutOverride === undefined ? undefined : { expand_input: expandInputShortcutOverride },
|
||||
);
|
||||
const shortcut = expandInputCombo ? formatShortcutForDisplay(expandInputCombo) : null;
|
||||
|
||||
return (
|
||||
<Tooltip>
|
||||
@@ -43,9 +54,7 @@ export const FocusModeButton = React.memo(function FocusModeButton(props: FocusM
|
||||
<TooltipContent side="top" sideOffset={8}>
|
||||
<div className="flex flex-col gap-0.5 text-center">
|
||||
<span>{t('chat.chatInput.focusMode.label')}</span>
|
||||
<span className="font-mono opacity-60">
|
||||
{isMacOS() ? '⌘⇧E' : 'Ctrl+Shift+E'}
|
||||
</span>
|
||||
{shortcut ? <span className="font-mono opacity-60">{shortcut}</span> : null}
|
||||
</div>
|
||||
</TooltipContent>
|
||||
</Tooltip>
|
||||
|
||||
@@ -5,6 +5,7 @@ import { Textarea } from '@/components/ui/textarea';
|
||||
import { cn } from '@/lib/utils';
|
||||
import { useDeviceInfo } from '@/lib/device';
|
||||
import { useI18n } from '@/lib/i18n';
|
||||
import { formatShortcutForDisplay } from '@/lib/shortcuts';
|
||||
|
||||
export interface InlineCommentInputProps {
|
||||
initialText?: string;
|
||||
@@ -35,6 +36,7 @@ export function InlineCommentInput({
|
||||
const { isMobile } = useDeviceInfo();
|
||||
const [text, setText] = React.useState(initialText);
|
||||
const textareaRef = useRef<HTMLTextAreaElement>(null);
|
||||
const saveShortcut = formatShortcutForDisplay('mod+enter');
|
||||
|
||||
const handleTextChange = (value: string) => {
|
||||
setText(value);
|
||||
@@ -154,7 +156,9 @@ export function InlineCommentInput({
|
||||
value={text}
|
||||
onChange={(e) => handleTextChange(e.target.value)}
|
||||
onKeyDown={handleKeyDown}
|
||||
placeholder={isMobile ? t('inlineComment.input.placeholderShort') : t('inlineComment.input.placeholder')}
|
||||
placeholder={isMobile
|
||||
? t('inlineComment.input.placeholderShort')
|
||||
: t('inlineComment.input.placeholder', { shortcut: saveShortcut })}
|
||||
outerClassName="rounded-[var(--radius-xl)] bg-[var(--surface-subtle)] ring-1 ring-inset ring-border/60 focus-within:ring-2 focus-within:ring-[var(--interactive-focus-ring)]"
|
||||
className="min-h-[80px] px-3 py-2.5 text-sm resize-y"
|
||||
/>
|
||||
|
||||
@@ -64,6 +64,7 @@ import { useRuntimeAPIs } from '@/hooks/useRuntimeAPIs';
|
||||
import type { TerminalShellOption } from '@/lib/api/types';
|
||||
import { isTerminalShell } from '@/lib/terminalShell';
|
||||
import { subscribeRuntimeEndpointChanged } from '@/lib/runtime-switch';
|
||||
import { formatShortcutForDisplay } from '@/lib/shortcuts';
|
||||
|
||||
interface Option<T extends string> {
|
||||
id: T;
|
||||
@@ -1543,7 +1544,10 @@ export const OpenChamberVisualSettings: React.FC<OpenChamberVisualSettingsProps>
|
||||
label={t('settings.openchamber.visual.field.terminalQuickKeys')}
|
||||
ariaLabel={t('settings.openchamber.visual.field.terminalQuickKeysAria')}
|
||||
settingsItem="appearance.terminal-quick-keys"
|
||||
info={t('settings.openchamber.visual.field.terminalQuickKeysTooltip')}
|
||||
info={t('settings.openchamber.visual.field.terminalQuickKeysTooltip', {
|
||||
control: formatShortcutForDisplay('ctrl'),
|
||||
alt: formatShortcutForDisplay('alt'),
|
||||
})}
|
||||
/>
|
||||
)}
|
||||
{showTerminalShellSetting && (
|
||||
|
||||
@@ -22,6 +22,7 @@ import { MobileOverlayPanel } from '@/components/ui/MobileOverlayPanel';
|
||||
import { Icon } from "@/components/icon/Icon";
|
||||
import { opencodeClient } from '@/lib/opencode/client';
|
||||
import { useI18n } from '@/lib/i18n';
|
||||
import { formatShortcutForDisplay } from '@/lib/shortcuts';
|
||||
|
||||
interface DirectoryExplorerDialogProps {
|
||||
open: boolean;
|
||||
@@ -338,9 +339,7 @@ export const DirectoryExplorerDialog: React.FC<DirectoryExplorerDialogProps> = (
|
||||
const hasHighlightedBrowseItem = Boolean(
|
||||
highlightedRow && (highlightedRow.type === 'up' || (highlightedRow.type === 'directory' && !highlightedRow.disabled))
|
||||
);
|
||||
const submitModifierLabel = typeof navigator !== 'undefined' && /Mac|iPhone|iPad/.test(navigator.platform)
|
||||
? '⌘'
|
||||
: 'Ctrl';
|
||||
const submitModifierLabel = formatShortcutForDisplay('mod');
|
||||
const submitActionLabel = isAlreadyAdded
|
||||
? t('directoryExplorerDialog.actions.alreadyAdded')
|
||||
: isCloneMode
|
||||
|
||||
@@ -11,7 +11,6 @@ import { useUIStore } from "@/stores/useUIStore";
|
||||
import {
|
||||
getEffectiveShortcutCombo,
|
||||
getShortcutAction,
|
||||
getModifierLabel,
|
||||
formatShortcutForDisplay,
|
||||
type ShortcutActionId,
|
||||
} from "@/lib/shortcuts";
|
||||
@@ -44,7 +43,6 @@ export const HelpDialog: React.FC = () => {
|
||||
const isHelpDialogOpen = useUIStore((state) => state.isHelpDialogOpen);
|
||||
const setHelpDialogOpen = useUIStore((state) => state.setHelpDialogOpen);
|
||||
const shortcutOverrides = useUIStore((state) => state.shortcutOverrides);
|
||||
const mod = getModifierLabel();
|
||||
const isVSCode = isVSCodeRuntime();
|
||||
|
||||
const shortcuts: ShortcutSection[] = [
|
||||
@@ -104,7 +102,7 @@ export const HelpDialog: React.FC = () => {
|
||||
keys: '',
|
||||
},
|
||||
{
|
||||
keys: [`Shift + Alt + ${mod} + N`],
|
||||
keys: [formatShortcutForDisplay('mod+shift+alt+n')],
|
||||
descriptionKey: "helpDialog.item.newWindow",
|
||||
icon: "window",
|
||||
},
|
||||
@@ -195,7 +193,7 @@ export const HelpDialog: React.FC = () => {
|
||||
keys: '',
|
||||
},
|
||||
{
|
||||
keys: [`${mod} + 1...0`],
|
||||
keys: [`${formatShortcutForDisplay('mod')} + 1...0`],
|
||||
descriptionKey: "helpDialog.item.switchContextSurface",
|
||||
icon: "layout-right",
|
||||
},
|
||||
|
||||
@@ -53,7 +53,7 @@ import { getOutsideFileGrant } from '@/lib/outsideFileGrants';
|
||||
import { DiagramEditor } from '@/components/diagram';
|
||||
import { useRuntimeAPIs } from '@/hooks/useRuntimeAPIs';
|
||||
import { useKeybind, useKeybinds } from '@/hooks/useKeybind';
|
||||
import { getModifierLabel } from '@/lib/shortcuts';
|
||||
import { formatShortcutForDisplay, getEffectiveShortcutCombo } from '@/lib/shortcuts';
|
||||
import { EditorView } from '@codemirror/view';
|
||||
import type { Extension } from '@codemirror/state';
|
||||
import { useThemeSystem } from '@/contexts/useThemeSystem';
|
||||
@@ -3167,6 +3167,7 @@ export const FilesView: React.FC<FilesViewProps> = ({ mode = 'full' }) => {
|
||||
}
|
||||
|
||||
const docked = layout === 'docked';
|
||||
const saveShortcut = formatShortcutForDisplay(getEffectiveShortcutCombo('save_file'));
|
||||
const wrapperCls = docked
|
||||
? 'pointer-events-auto flex flex-wrap items-center gap-1'
|
||||
: 'pointer-events-auto flex items-center gap-1 rounded-lg border border-[var(--interactive-border)] bg-[var(--surface-elevated)] p-1 shadow-sm';
|
||||
@@ -3196,14 +3197,14 @@ export const FilesView: React.FC<FilesViewProps> = ({ mode = 'full' }) => {
|
||||
<Icon name="check" className="size-3.5" />
|
||||
{t('filesView.editor.saved')}
|
||||
</span>
|
||||
) : isDirty ? withTooltip(t(autoSaveEnabled ? 'filesView.editor.saveNowTitle' : 'filesView.editor.saveNowManualTitle', { shortcut: `${getModifierLabel()}+S` }),
|
||||
) : isDirty ? withTooltip(t(autoSaveEnabled ? 'filesView.editor.saveNowTitle' : 'filesView.editor.saveNowManualTitle', { shortcut: saveShortcut }),
|
||||
<Button
|
||||
variant="ghost"
|
||||
size="sm"
|
||||
onClick={() => void saveDraft()}
|
||||
className="h-6 gap-1 px-1 text-muted-foreground opacity-80 hover:bg-transparent hover:opacity-100 focus-visible:bg-transparent active:bg-transparent"
|
||||
title={t(autoSaveEnabled ? 'filesView.editor.saveNowTitle' : 'filesView.editor.saveNowManualTitle', { shortcut: `${getModifierLabel()}+S` })}
|
||||
aria-label={t('filesView.editor.saveAria', { shortcut: `${getModifierLabel()}+S` })}
|
||||
title={t(autoSaveEnabled ? 'filesView.editor.saveNowTitle' : 'filesView.editor.saveNowManualTitle', { shortcut: saveShortcut })}
|
||||
aria-label={t('filesView.editor.saveAria', { shortcut: saveShortcut })}
|
||||
>
|
||||
<Icon name="save-3" className="size-4" />
|
||||
</Button>
|
||||
|
||||
@@ -1,6 +1,9 @@
|
||||
import React from 'react';
|
||||
import { cn } from '@/lib/utils';
|
||||
import { getModifierLabel } from '@/lib/shortcuts';
|
||||
import {
|
||||
formatShortcutForDisplay,
|
||||
getEffectiveShortcutCombo,
|
||||
} from '@/lib/shortcuts';
|
||||
import { useUIStore } from '@/stores/useUIStore';
|
||||
import { useProjectsStore } from '@/stores/useProjectsStore';
|
||||
import { useAgentsStore } from '@/stores/useAgentsStore';
|
||||
@@ -240,6 +243,7 @@ export const SettingsView: React.FC<SettingsViewProps> = ({ onClose, forceMobile
|
||||
const settingsPageRaw = useUIStore((state) => state.settingsPage);
|
||||
const isSettingsDialogOpen = useUIStore((state) => state.isSettingsDialogOpen);
|
||||
const setSettingsPage = useUIStore((state) => state.setSettingsPage);
|
||||
const openSettingsShortcutOverride = useUIStore((state) => state.shortcutOverrides.open_settings);
|
||||
const settingsSlug = resolveSettingsSlug(settingsPageRaw);
|
||||
|
||||
const [mobileStage, setMobileStage] = React.useState<MobileStage>(initialMobileStage);
|
||||
@@ -751,7 +755,15 @@ export const SettingsView: React.FC<SettingsViewProps> = ({ onClose, forceMobile
|
||||
: showBackButton
|
||||
? t('settings.view.actions.backToSettings')
|
||||
: t('settings.view.actions.closeSettings');
|
||||
const shortcutKey = getModifierLabel();
|
||||
const openSettingsCombo = getEffectiveShortcutCombo(
|
||||
'open_settings',
|
||||
openSettingsShortcutOverride === undefined ? undefined : { open_settings: openSettingsShortcutOverride },
|
||||
);
|
||||
const closeSettingsTitle = openSettingsCombo
|
||||
? t('settings.view.actions.closeSettingsWithShortcut', {
|
||||
shortcut: formatShortcutForDisplay(openSettingsCombo),
|
||||
})
|
||||
: t('settings.view.actions.closeSettings');
|
||||
|
||||
const pushMobileSplitDetailHistory = React.useCallback((slug: SettingsPageSlug) => {
|
||||
if (typeof window === 'undefined' || runtimeCtx.isVSCode) {
|
||||
@@ -1119,7 +1131,7 @@ export const SettingsView: React.FC<SettingsViewProps> = ({ onClose, forceMobile
|
||||
type="button"
|
||||
onClick={onClose}
|
||||
aria-label={t('settings.view.actions.closeSettings')}
|
||||
title={t('settings.view.actions.closeSettingsWithShortcut', { shortcut: shortcutKey })}
|
||||
title={closeSettingsTitle}
|
||||
className="inline-flex h-9 w-9 flex-shrink-0 items-center justify-center rounded-lg p-2 text-muted-foreground hover:text-foreground hover:bg-interactive-hover/50 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-primary"
|
||||
>
|
||||
<Icon name="close" className="h-5 w-5" />
|
||||
@@ -1147,7 +1159,7 @@ export const SettingsView: React.FC<SettingsViewProps> = ({ onClose, forceMobile
|
||||
type="button"
|
||||
onClick={onClose}
|
||||
aria-label={t('settings.view.actions.closeSettings')}
|
||||
title={t('settings.view.actions.closeSettingsWithShortcut', { shortcut: shortcutKey })}
|
||||
title={closeSettingsTitle}
|
||||
className="inline-flex h-7 w-7 items-center justify-center rounded-md p-0.5 text-muted-foreground hover:text-foreground hover:bg-interactive-hover/50 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-primary"
|
||||
>
|
||||
<Icon name="close" className="h-5 w-5" />
|
||||
|
||||
@@ -21,6 +21,7 @@ import { useI18n } from '@/lib/i18n';
|
||||
import { PROJECT_ACTION_ICON_MAP, type ProjectActionIconKey } from '@/lib/projectActions';
|
||||
import { useInlineCommentDraftStore } from '@/stores/useInlineCommentDraftStore';
|
||||
import { applyTerminalModifier, terminalControlCharacter, terminalSequenceForKey, type TerminalModifier as Modifier, type TerminalQuickKey as MobileKey } from '@/lib/terminalInput';
|
||||
import { formatShortcutForDisplay } from '@/lib/shortcuts';
|
||||
|
||||
type TerminalViewProps = {
|
||||
visible?: boolean;
|
||||
@@ -924,7 +925,7 @@ export const TerminalView: React.FC<TerminalViewProps> = ({ visible }) => {
|
||||
onClick={() => handleModifierToggle('ctrl')}
|
||||
disabled={quickKeysDisabled}
|
||||
>
|
||||
<span className="text-xs font-medium">{t('terminalView.quickKeys.controlLabel')}</span>
|
||||
<span className="text-xs font-medium">{formatShortcutForDisplay('ctrl')}</span>
|
||||
<span className="sr-only">{t('terminalView.quickKeys.controlModifierAria')}</span>
|
||||
</Button>
|
||||
<Button
|
||||
@@ -937,7 +938,7 @@ export const TerminalView: React.FC<TerminalViewProps> = ({ visible }) => {
|
||||
onClick={() => handleModifierToggle('alt')}
|
||||
disabled={quickKeysDisabled}
|
||||
>
|
||||
<span className="text-xs font-medium">{t('terminalView.quickKeys.altLabel')}</span>
|
||||
<span className="text-xs font-medium">{formatShortcutForDisplay('alt')}</span>
|
||||
<span className="sr-only">{t('terminalView.quickKeys.altModifierAria')}</span>
|
||||
</Button>
|
||||
<Button
|
||||
|
||||
@@ -40,7 +40,7 @@ export const settingsDict = {
|
||||
'settings.view.actions.backToSettings': 'Zurück zu Einstellungen',
|
||||
'settings.view.actions.closeSettings': 'Einstellungen schließen',
|
||||
'settings.view.actions.openSectionList': 'Abschnittsliste öffnen',
|
||||
'settings.view.actions.closeSettingsWithShortcut': 'Einstellungen schließen ({shortcut}+,)',
|
||||
'settings.view.actions.closeSettingsWithShortcut': 'Einstellungen schließen ({shortcut})',
|
||||
'settings.view.actions.back': 'Zurück',
|
||||
'settings.view.actions.resizeNavigation': 'Einstellungsnavigation skalieren',
|
||||
'settings.view.search.placeholder': 'Einstellungen durchsuchen',
|
||||
@@ -1857,7 +1857,7 @@ export const settingsDict = {
|
||||
'settings.openchamber.visual.actions.resetInputBarOffsetAria': 'Versatz der Eingabeleiste zurücksetzen',
|
||||
'settings.openchamber.visual.field.terminalQuickKeysAria': 'Schnelltasten des Terminals',
|
||||
'settings.openchamber.visual.field.terminalQuickKeys': 'Schnelltasten des Terminals',
|
||||
'settings.openchamber.visual.field.terminalQuickKeysTooltip': 'Esc, Strg, Pfeiltasten in der Terminalansicht anzeigen',
|
||||
'settings.openchamber.visual.field.terminalQuickKeysTooltip': 'Esc, {control}, {alt} und Pfeiltasten in der Terminalansicht anzeigen',
|
||||
'settings.openchamber.visual.field.fileEditorKeymap': 'Tastaturlayout für Datei-Editor',
|
||||
'settings.openchamber.visual.option.fileEditorKeymap.default': 'Standard',
|
||||
'settings.openchamber.visual.option.fileEditorKeymap.vim': 'Vim',
|
||||
|
||||
@@ -1368,7 +1368,7 @@ export const dict = {
|
||||
'rightSidebar.contextNotesTodo.toast.planImported': 'Plan importiert',
|
||||
'rightSidebar.contextNotesTodo.toast.readPlanFileFailed': 'Fehler beim Lesen der Plan-Datei',
|
||||
'inlineComment.range.lines': 'Zeilen {start}-{end}',
|
||||
'inlineComment.input.placeholder': 'Kommentar hinzufügen... (Cmd+Enter zum Speichern)',
|
||||
'inlineComment.input.placeholder': 'Kommentar hinzufügen... ({shortcut} zum Speichern)',
|
||||
'inlineComment.input.placeholderShort': 'Kommentar hinzufügen...',
|
||||
'inlineComment.actions.cancel': 'Abbrechen',
|
||||
'inlineComment.actions.save': 'Speichern',
|
||||
|
||||
@@ -43,7 +43,7 @@ export const settingsDict = {
|
||||
'settings.view.actions.backToSettings': 'Back to Settings',
|
||||
'settings.view.actions.closeSettings': 'Close settings',
|
||||
'settings.view.actions.openSectionList': 'Open section list',
|
||||
'settings.view.actions.closeSettingsWithShortcut': 'Close Settings ({shortcut}+,)',
|
||||
'settings.view.actions.closeSettingsWithShortcut': 'Close Settings ({shortcut})',
|
||||
'settings.view.actions.back': 'Back',
|
||||
'settings.view.actions.resizeNavigation': 'Resize settings navigation',
|
||||
'settings.view.search.placeholder': 'Search settings',
|
||||
@@ -1938,7 +1938,7 @@ export const settingsDict = {
|
||||
'settings.openchamber.visual.actions.resetInputBarOffsetAria': 'Reset input bar offset',
|
||||
'settings.openchamber.visual.field.terminalQuickKeysAria': 'Terminal quick keys',
|
||||
'settings.openchamber.visual.field.terminalQuickKeys': 'Terminal Quick Keys',
|
||||
'settings.openchamber.visual.field.terminalQuickKeysTooltip': 'Show Esc, Ctrl, Arrows in terminal view',
|
||||
'settings.openchamber.visual.field.terminalQuickKeysTooltip': 'Show Esc, {control}, {alt}, and arrow keys in the terminal view',
|
||||
'settings.openchamber.visual.field.fileEditorKeymap': 'File editor keymap',
|
||||
'settings.openchamber.visual.option.fileEditorKeymap.default': 'Default',
|
||||
'settings.openchamber.visual.option.fileEditorKeymap.vim': 'Vim',
|
||||
|
||||
@@ -1521,7 +1521,7 @@ export const dict = {
|
||||
'rightSidebar.contextNotesTodo.toast.planImported': 'Plan imported',
|
||||
'rightSidebar.contextNotesTodo.toast.readPlanFileFailed': 'Failed to read plan file',
|
||||
'inlineComment.range.lines': 'Lines {start}-{end}',
|
||||
'inlineComment.input.placeholder': 'Add a comment... (Cmd+Enter to save)',
|
||||
'inlineComment.input.placeholder': 'Add a comment... ({shortcut} to save)',
|
||||
'inlineComment.input.placeholderShort': 'Add a comment...',
|
||||
'inlineComment.actions.cancel': 'Cancel',
|
||||
'inlineComment.actions.save': 'Save',
|
||||
|
||||
@@ -43,7 +43,7 @@ export const settingsDict = {
|
||||
"settings.view.actions.backToSettings": "Volver a Configuración",
|
||||
"settings.view.actions.closeSettings": "Cerrar configuración",
|
||||
"settings.view.actions.openSectionList": "Abrir lista de secciones",
|
||||
"settings.view.actions.closeSettingsWithShortcut": "Cerrar configuración ({shortcut}+,)",
|
||||
"settings.view.actions.closeSettingsWithShortcut": "Cerrar configuración ({shortcut})",
|
||||
"settings.view.actions.back": "Atrás",
|
||||
"settings.view.actions.resizeNavigation": "Ajustar tamaño de la navegación",
|
||||
"settings.view.search.placeholder": "Buscar configuración",
|
||||
@@ -1914,7 +1914,7 @@ export const settingsDict = {
|
||||
"settings.openchamber.visual.actions.resetInputBarOffsetAria": "Restablecer desplazamiento de la barra de entrada",
|
||||
"settings.openchamber.visual.field.terminalQuickKeysAria": "Teclas rápidas del terminal",
|
||||
"settings.openchamber.visual.field.terminalQuickKeys": "Teclas rápidas del terminal",
|
||||
"settings.openchamber.visual.field.terminalQuickKeysTooltip": "Mostrar Esc, Ctrl y flechas en la vista del terminal",
|
||||
"settings.openchamber.visual.field.terminalQuickKeysTooltip": "Mostrar Esc, {control}, {alt} y las flechas en la vista del terminal",
|
||||
"settings.openchamber.visual.field.fileEditorKeymap": "Mapa de teclas del editor de archivos",
|
||||
"settings.openchamber.visual.option.fileEditorKeymap.default": "Predeterminado",
|
||||
"settings.openchamber.visual.option.fileEditorKeymap.vim": "Vim",
|
||||
|
||||
@@ -1499,7 +1499,7 @@ export const dict: Record<I18nKey, string> = {
|
||||
"rightSidebar.contextNotesTodo.toast.planImported": "Plan importado",
|
||||
"rightSidebar.contextNotesTodo.toast.readPlanFileFailed": "No se pudo leer el archivo del plan",
|
||||
"inlineComment.range.lines": "Líneas {start}-{end}",
|
||||
"inlineComment.input.placeholder": "Añadir un comentario... (Cmd+Enter para guardar)",
|
||||
"inlineComment.input.placeholder": "Añadir un comentario... ({shortcut} para guardar)",
|
||||
"inlineComment.input.placeholderShort": "Añadir un comentario...",
|
||||
"inlineComment.actions.cancel": "Cancelar",
|
||||
"inlineComment.actions.save": "Guardar",
|
||||
|
||||
@@ -43,7 +43,7 @@ export const settingsDict = {
|
||||
'settings.view.actions.backToSettings': 'Retour aux paramètres',
|
||||
'settings.view.actions.closeSettings': 'Fermer les paramètres',
|
||||
'settings.view.actions.openSectionList': 'Ouvrir la liste des sections',
|
||||
'settings.view.actions.closeSettingsWithShortcut': 'Fermer les paramètres ({shortcut}+,)',
|
||||
'settings.view.actions.closeSettingsWithShortcut': 'Fermer les paramètres ({shortcut})',
|
||||
'settings.view.actions.back': 'Retour',
|
||||
'settings.view.actions.resizeNavigation': 'Redimensionner la navigation dans les paramètres',
|
||||
'settings.page.projects.title': 'Projets',
|
||||
@@ -1822,7 +1822,7 @@ export const settingsDict = {
|
||||
'settings.openchamber.visual.actions.resetInputBarOffsetAria': 'Réinitialiser le décalage de la barre d\'entrée',
|
||||
'settings.openchamber.visual.field.terminalQuickKeysAria': 'Touches rapides du terminal',
|
||||
'settings.openchamber.visual.field.terminalQuickKeys': 'Touches rapides du terminal',
|
||||
'settings.openchamber.visual.field.terminalQuickKeysTooltip': 'Afficher Esc, Ctrl, Flèches dans la vue du terminal',
|
||||
'settings.openchamber.visual.field.terminalQuickKeysTooltip': 'Afficher Échap, {control}, {alt} et les flèches dans la vue du terminal',
|
||||
'settings.openchamber.visual.field.activityDefaultModeAria': 'Mode d\'activité par défaut : {option}',
|
||||
'settings.openchamber.visual.field.showExpandedBashToolsAria': 'Afficher les outils bash étendus',
|
||||
'settings.openchamber.visual.field.showExpandedEditToolsAria': 'Afficher les outils d\'édition étendus',
|
||||
|
||||
@@ -1341,7 +1341,7 @@ export const dict = {
|
||||
'rightSidebar.contextNotesTodo.toast.planImported': 'Forfait importé',
|
||||
'rightSidebar.contextNotesTodo.toast.readPlanFileFailed': 'Échec de la lecture du fichier de plan',
|
||||
'inlineComment.range.lines': 'Lignes {start}-{end}',
|
||||
'inlineComment.input.placeholder': 'Ajouter un commentaire... (Cmd+Entrée pour enregistrer)',
|
||||
'inlineComment.input.placeholder': 'Ajouter un commentaire... ({shortcut} pour enregistrer)',
|
||||
'inlineComment.actions.cancel': 'Annuler',
|
||||
'inlineComment.actions.save': 'Sauvegarder',
|
||||
'inlineComment.actions.comment': 'Commentaire',
|
||||
|
||||
@@ -43,7 +43,7 @@ export const settingsDict = {
|
||||
'settings.view.actions.backToSettings': '設定に戻る',
|
||||
'settings.view.actions.closeSettings': '設定を閉じる',
|
||||
'settings.view.actions.openSectionList': 'セクション一覧を開く',
|
||||
'settings.view.actions.closeSettingsWithShortcut': '設定を閉じる ({shortcut}+,)',
|
||||
'settings.view.actions.closeSettingsWithShortcut': '設定を閉じる ({shortcut})',
|
||||
'settings.view.actions.back': '戻る',
|
||||
'settings.view.actions.resizeNavigation': '設定ナビゲーションのサイズ変更',
|
||||
'settings.view.search.placeholder': '設定を検索',
|
||||
@@ -1947,7 +1947,7 @@ export const settingsDict = {
|
||||
'settings.openchamber.visual.actions.resetInputBarOffsetAria': '入力バーオフセットをリセット',
|
||||
'settings.openchamber.visual.field.terminalQuickKeysAria': 'ターミナルクイックキー',
|
||||
'settings.openchamber.visual.field.terminalQuickKeys': 'ターミナルクイックキー',
|
||||
'settings.openchamber.visual.field.terminalQuickKeysTooltip': 'ターミナルビューに Esc、Ctrl、矢印を表示',
|
||||
'settings.openchamber.visual.field.terminalQuickKeysTooltip': 'ターミナルビューに Esc、{control}、{alt}、矢印キーを表示',
|
||||
'settings.openchamber.visual.field.fileEditorKeymap': 'ファイルエディターキーマップ',
|
||||
'settings.openchamber.visual.option.fileEditorKeymap.default': 'デフォルト',
|
||||
'settings.openchamber.visual.option.fileEditorKeymap.vim': 'Vim',
|
||||
|
||||
@@ -1517,7 +1517,7 @@ export const dict: Record<I18nKey, string> = {
|
||||
'rightSidebar.contextNotesTodo.toast.planImported': '計画をインポートしました',
|
||||
'rightSidebar.contextNotesTodo.toast.readPlanFileFailed': '計画ファイルの読み込みに失敗しました',
|
||||
'inlineComment.range.lines': '{start}行目~{end}行目',
|
||||
'inlineComment.input.placeholder': 'コメントを追加...(Cmd+Enterで保存)',
|
||||
'inlineComment.input.placeholder': 'コメントを追加...({shortcut}で保存)',
|
||||
'inlineComment.input.placeholderShort': 'コメントを追加...',
|
||||
'inlineComment.actions.cancel': 'キャンセル',
|
||||
'inlineComment.actions.save': '保存',
|
||||
|
||||
@@ -43,7 +43,7 @@ export const settingsDict = {
|
||||
'settings.view.actions.backToSettings': '설정으로 돌아가기',
|
||||
'settings.view.actions.closeSettings': '설정 닫기',
|
||||
'settings.view.actions.openSectionList': '섹션 목록 열기',
|
||||
'settings.view.actions.closeSettingsWithShortcut': '설정 닫기 ({shortcut}+,)',
|
||||
'settings.view.actions.closeSettingsWithShortcut': '설정 닫기 ({shortcut})',
|
||||
'settings.view.actions.back': '뒤로',
|
||||
'settings.view.actions.resizeNavigation': '설정 내비게이션 크기 조정',
|
||||
'settings.view.search.placeholder': '설정 검색',
|
||||
@@ -1914,7 +1914,7 @@ export const settingsDict = {
|
||||
'settings.openchamber.visual.actions.resetInputBarOffsetAria': '입력 바 오프셋 초기화',
|
||||
'settings.openchamber.visual.field.terminalQuickKeysAria': '터미널 빠른 키',
|
||||
'settings.openchamber.visual.field.terminalQuickKeys': '터미널 빠른 키',
|
||||
'settings.openchamber.visual.field.terminalQuickKeysTooltip': '터미널 보기에서 Esc, Ctrl, 화살표를 표시합니다',
|
||||
'settings.openchamber.visual.field.terminalQuickKeysTooltip': '터미널 보기에서 Esc, {control}, {alt}, 화살표 키를 표시합니다',
|
||||
'settings.openchamber.visual.field.fileEditorKeymap': '파일 편집기 키맵',
|
||||
'settings.openchamber.visual.option.fileEditorKeymap.default': '기본값',
|
||||
'settings.openchamber.visual.option.fileEditorKeymap.vim': 'Vim',
|
||||
|
||||
@@ -1524,7 +1524,7 @@ export const dict: Record<I18nKey, string> = {
|
||||
'rightSidebar.contextNotesTodo.toast.planImported': '플랜 가져옴',
|
||||
'rightSidebar.contextNotesTodo.toast.readPlanFileFailed': '플랜 파일 읽기 실패',
|
||||
'inlineComment.range.lines': '줄 {start}-{end}',
|
||||
'inlineComment.input.placeholder': '댓글 추가… (Cmd+Enter로 저장)',
|
||||
'inlineComment.input.placeholder': '댓글 추가… ({shortcut}로 저장)',
|
||||
'inlineComment.input.placeholderShort': '댓글 추가…',
|
||||
'inlineComment.actions.cancel': '취소',
|
||||
'inlineComment.actions.save': '저장',
|
||||
|
||||
@@ -1109,7 +1109,7 @@ export const settingsDict = {
|
||||
'settings.openchamber.visual.field.editorFontSize': 'Rozmiar czcionki edytora',
|
||||
'settings.openchamber.visual.field.terminalQuickKeys': 'Szybkie klawisze terminala',
|
||||
'settings.openchamber.visual.field.terminalQuickKeysAria': 'Szybkie klawisze terminala',
|
||||
'settings.openchamber.visual.field.terminalQuickKeysTooltip': 'Pokaż Esc, Ctrl i strzałki w widoku terminala',
|
||||
'settings.openchamber.visual.field.terminalQuickKeysTooltip': 'Pokaż Esc, {control}, {alt} i klawisze strzałek w widoku terminala',
|
||||
'settings.openchamber.visual.field.fileEditorKeymap': 'Mapa klawiszy edytora plików',
|
||||
'settings.openchamber.visual.option.fileEditorKeymap.default': 'Domyślna',
|
||||
'settings.openchamber.visual.option.fileEditorKeymap.vim': 'Vim',
|
||||
@@ -2004,7 +2004,7 @@ export const settingsDict = {
|
||||
'settings.view.actions.back': 'Wstecz',
|
||||
'settings.view.actions.backToSettings': 'Powrót do ustawień',
|
||||
'settings.view.actions.closeSettings': 'Zamknij ustawienia',
|
||||
'settings.view.actions.closeSettingsWithShortcut': 'Zamknij ustawienia ({shortcut}+,)',
|
||||
'settings.view.actions.closeSettingsWithShortcut': 'Zamknij ustawienia ({shortcut})',
|
||||
'settings.view.actions.openSectionList': 'Otwórz listę sekcji',
|
||||
'settings.view.actions.reloadOpenCode': 'Przeładuj OpenCode',
|
||||
'settings.view.actions.reloadOpenCodeTooltip': 'Uruchom ponownie OpenCode i przeładuj jego konfigurację.',
|
||||
|
||||
@@ -2364,7 +2364,7 @@ export const dict: Record<I18nKey, string> = {
|
||||
'inlineComment.actions.save': 'Zapisz',
|
||||
'inlineComment.actions.showLess': 'Show less',
|
||||
'inlineComment.actions.showMore': 'Show more',
|
||||
'inlineComment.input.placeholder': 'Add a comment... (Cmd+Enter to save)',
|
||||
'inlineComment.input.placeholder': 'Dodaj komentarz... ({shortcut}, aby zapisać)',
|
||||
'inlineComment.input.placeholderShort': 'Dodaj komentarz...',
|
||||
'inlineComment.range.lines': 'Lines {start}-{end}',
|
||||
'inlineComment.toast.selectSessionToSave': 'Select a session to save comment',
|
||||
|
||||
@@ -43,7 +43,7 @@ export const settingsDict = {
|
||||
"settings.view.actions.backToSettings": "Voltar às configurações",
|
||||
"settings.view.actions.closeSettings": "Fechar configurações",
|
||||
"settings.view.actions.openSectionList": "Abrir lista de seções",
|
||||
"settings.view.actions.closeSettingsWithShortcut": "Fechar configurações ({shortcut}+,)",
|
||||
"settings.view.actions.closeSettingsWithShortcut": "Fechar configurações ({shortcut})",
|
||||
"settings.view.actions.back": "Voltar",
|
||||
"settings.view.actions.resizeNavigation": "Ajustar tamanho da navegação",
|
||||
"settings.view.search.placeholder": "Buscar configurações",
|
||||
@@ -1914,7 +1914,7 @@ export const settingsDict = {
|
||||
"settings.openchamber.visual.actions.resetInputBarOffsetAria": "Redefinir deslocamento da barra de entrada",
|
||||
"settings.openchamber.visual.field.terminalQuickKeysAria": "Teclas rápidas do terminal",
|
||||
"settings.openchamber.visual.field.terminalQuickKeys": "Teclas rápidas do terminal",
|
||||
"settings.openchamber.visual.field.terminalQuickKeysTooltip": "Mostrar Esc, Ctrl e flechas na vista do terminal",
|
||||
"settings.openchamber.visual.field.terminalQuickKeysTooltip": "Mostrar Esc, {control}, {alt} e as setas na vista do terminal",
|
||||
"settings.openchamber.visual.field.fileEditorKeymap": "Mapa de teclas do editor de arquivos",
|
||||
"settings.openchamber.visual.option.fileEditorKeymap.default": "Padrão",
|
||||
"settings.openchamber.visual.option.fileEditorKeymap.vim": "Vim",
|
||||
|
||||
@@ -1499,7 +1499,7 @@ export const dict: Record<I18nKey, string> = {
|
||||
"rightSidebar.contextNotesTodo.toast.planImported": "Plano importado",
|
||||
"rightSidebar.contextNotesTodo.toast.readPlanFileFailed": "Não foi possível ler o arquivo do plano",
|
||||
"inlineComment.range.lines": "Linhas {start}-{end}",
|
||||
"inlineComment.input.placeholder": "Adicionar um comentário... (Cmd+Enter para salvar)",
|
||||
"inlineComment.input.placeholder": "Adicionar um comentário... ({shortcut} para salvar)",
|
||||
"inlineComment.input.placeholderShort": "Adicionar um comentário...",
|
||||
"inlineComment.actions.cancel": "Cancelar",
|
||||
"inlineComment.actions.save": "Salvar",
|
||||
|
||||
@@ -43,7 +43,7 @@ export const settingsDict = {
|
||||
"settings.view.actions.backToSettings": "Назад до налаштувань",
|
||||
"settings.view.actions.closeSettings": "Закрити налаштування",
|
||||
"settings.view.actions.openSectionList": "Відкрити список розділів",
|
||||
"settings.view.actions.closeSettingsWithShortcut": "Закрити налаштування ({shortcut}+,)",
|
||||
"settings.view.actions.closeSettingsWithShortcut": "Закрити налаштування ({shortcut})",
|
||||
"settings.view.actions.back": "Назад",
|
||||
"settings.view.actions.resizeNavigation": "Змінити розмір навігації налаштувань",
|
||||
"settings.view.search.placeholder": "Пошук налаштувань",
|
||||
@@ -1914,7 +1914,7 @@ export const settingsDict = {
|
||||
"settings.openchamber.visual.actions.resetInputBarOffsetAria": "Скинути зміщення панелі вводу",
|
||||
"settings.openchamber.visual.field.terminalQuickKeysAria": "Швидкі клавіші терміналу",
|
||||
"settings.openchamber.visual.field.terminalQuickKeys": "Швидкі клавіші терміналу",
|
||||
"settings.openchamber.visual.field.terminalQuickKeysTooltip": "Показати Esc, Ctrl, стрілки в поданні терміналу",
|
||||
"settings.openchamber.visual.field.terminalQuickKeysTooltip": "Показувати Esc, {control}, {alt} і клавіші зі стрілками в поданні термінала",
|
||||
"settings.openchamber.visual.field.fileEditorKeymap": "Розкладка клавіш редактора файлів",
|
||||
"settings.openchamber.visual.option.fileEditorKeymap.default": "Типова",
|
||||
"settings.openchamber.visual.option.fileEditorKeymap.vim": "Vim",
|
||||
|
||||
@@ -1499,7 +1499,7 @@ export const dict: Record<I18nKey, string> = {
|
||||
"rightSidebar.contextNotesTodo.toast.planImported": "План імпортовано",
|
||||
"rightSidebar.contextNotesTodo.toast.readPlanFileFailed": "Не вдалося прочитати файл плану",
|
||||
"inlineComment.range.lines": "Рядки {start}-{end}",
|
||||
"inlineComment.input.placeholder": "Додайте коментар... (Cmd+Enter, щоб зберегти)",
|
||||
"inlineComment.input.placeholder": "Додайте коментар... ({shortcut}, щоб зберегти)",
|
||||
"inlineComment.input.placeholderShort": "Додайте коментар...",
|
||||
"inlineComment.actions.cancel": "Скасувати",
|
||||
"inlineComment.actions.save": "Зберегти",
|
||||
|
||||
@@ -43,7 +43,7 @@ export const settingsDict = {
|
||||
'settings.view.actions.backToSettings': '返回设置',
|
||||
'settings.view.actions.closeSettings': '关闭设置',
|
||||
'settings.view.actions.openSectionList': '打开分组列表',
|
||||
'settings.view.actions.closeSettingsWithShortcut': '关闭设置({shortcut}+,)',
|
||||
'settings.view.actions.closeSettingsWithShortcut': '关闭设置({shortcut})',
|
||||
'settings.view.actions.back': '返回',
|
||||
'settings.view.actions.resizeNavigation': '调整设置导航宽度',
|
||||
'settings.view.search.placeholder': '搜索设置',
|
||||
@@ -1914,7 +1914,7 @@ export const settingsDict = {
|
||||
'settings.openchamber.visual.actions.resetInputBarOffsetAria': '重置输入栏偏移',
|
||||
'settings.openchamber.visual.field.terminalQuickKeysAria': '终端快捷键',
|
||||
'settings.openchamber.visual.field.terminalQuickKeys': '终端快捷键',
|
||||
'settings.openchamber.visual.field.terminalQuickKeysTooltip': '在终端视图显示 Esc、Ctrl、方向键',
|
||||
'settings.openchamber.visual.field.terminalQuickKeysTooltip': '在终端视图显示 Esc、{control}、{alt} 和方向键',
|
||||
'settings.openchamber.visual.field.fileEditorKeymap': '文件编辑器键位映射',
|
||||
'settings.openchamber.visual.option.fileEditorKeymap.default': '默认',
|
||||
'settings.openchamber.visual.option.fileEditorKeymap.vim': 'Vim',
|
||||
|
||||
@@ -1487,7 +1487,7 @@ export const dict: Record<I18nKey, string> = {
|
||||
'rightSidebar.contextNotesTodo.toast.planImported': '计划已导入',
|
||||
'rightSidebar.contextNotesTodo.toast.readPlanFileFailed': '读取计划文件失败',
|
||||
'inlineComment.range.lines': '行 {start}-{end}',
|
||||
'inlineComment.input.placeholder': '添加评论...(Cmd+Enter 保存)',
|
||||
'inlineComment.input.placeholder': '添加评论...({shortcut} 保存)',
|
||||
'inlineComment.input.placeholderShort': '添加评论…',
|
||||
'inlineComment.actions.cancel': '取消',
|
||||
'inlineComment.actions.save': '保存',
|
||||
|
||||
@@ -41,7 +41,7 @@
|
||||
'settings.view.actions.backToSettings': '返回設定頁',
|
||||
'settings.view.actions.closeSettings': '關閉設定',
|
||||
'settings.view.actions.openSectionList': '開啟群組清單',
|
||||
'settings.view.actions.closeSettingsWithShortcut': '關閉設定({shortcut}+,)',
|
||||
'settings.view.actions.closeSettingsWithShortcut': '關閉設定({shortcut})',
|
||||
'settings.view.actions.back': '返回',
|
||||
'settings.view.actions.resizeNavigation': '調整設定導覽寬度',
|
||||
'settings.view.search.placeholder': '搜尋設定',
|
||||
@@ -1820,7 +1820,7 @@
|
||||
'settings.openchamber.visual.actions.resetInputBarOffsetAria': '重設輸入列偏移',
|
||||
'settings.openchamber.visual.field.terminalQuickKeysAria': '終端機快速鍵',
|
||||
'settings.openchamber.visual.field.terminalQuickKeys': '終端機快速鍵',
|
||||
'settings.openchamber.visual.field.terminalQuickKeysTooltip': '在終端機檢視顯示 Esc、Ctrl、方向鍵',
|
||||
'settings.openchamber.visual.field.terminalQuickKeysTooltip': '在終端機檢視顯示 Esc、{control}、{alt} 和方向鍵',
|
||||
'settings.openchamber.visual.field.fileEditorKeymap': '檔案編輯器鍵位映射',
|
||||
'settings.openchamber.visual.option.fileEditorKeymap.default': '預設',
|
||||
'settings.openchamber.visual.option.fileEditorKeymap.vim': 'Vim',
|
||||
|
||||
@@ -1497,7 +1497,7 @@ export const dict: Record<I18nKey, string> = {
|
||||
'rightSidebar.contextNotesTodo.toast.planImported': '計畫已匯入',
|
||||
'rightSidebar.contextNotesTodo.toast.readPlanFileFailed': '讀取計畫檔案失敗',
|
||||
'inlineComment.range.lines': '行 {start}-{end}',
|
||||
'inlineComment.input.placeholder': '新增留言...(Cmd+Enter 儲存)',
|
||||
'inlineComment.input.placeholder': '新增留言...({shortcut} 儲存)',
|
||||
'inlineComment.input.placeholderShort': '新增留言…',
|
||||
'inlineComment.actions.cancel': '取消',
|
||||
'inlineComment.actions.save': '儲存',
|
||||
|
||||
@@ -25,7 +25,7 @@ Component interaction keys that are not application commands, such as list navig
|
||||
|
||||
# Binding rules
|
||||
|
||||
Bindings remain persisted as `Record<string, string>`. Each binding has one chord or at most two space-separated chords, such as `mod+s p`. `normalizeCombo`, `parseShortcut`, `formatShortcutForDisplay`, and `getShortcutConflict` provide the shared parsing and validation behavior. A single chord conflicts with a sequence sharing its first chord; sibling sequences are valid.
|
||||
Bindings remain persisted as `Record<string, string>`. Each binding has one chord or at most two space-separated chords, such as `mod+s p`. `mod` is the platform-neutral primary modifier (Command on macOS, Control elsewhere), while `alt` is the platform-neutral alternate modifier (Option on macOS, Alt elsewhere); `command`, `cmd`, `meta`, and `option` are accepted input aliases but normalize to those canonical tokens. `normalizeCombo`, `parseShortcut`, `formatShortcutForDisplay`, and `getShortcutConflict` provide the shared parsing and validation behavior. Display formatting uses macOS keyboard symbols (`⌘`, `⌥`, `⌃`, `⇧`) on macOS and named modifiers (`Ctrl`, `Alt`, `Shift`) elsewhere, including tooltip and accessible text consumers. A single chord conflicts with a sequence sharing its first chord; sibling sequences are valid.
|
||||
|
||||
Contextual internal commands may deliberately share a sequence leader. The single-chord handler gets the first chance to handle the event; returning `false` lets the dispatcher start the sequence. The active file editor therefore owns `mod+s` for saving, while a mounted but unfocused editor yields `mod+s p`, `mod+s g`, and `mod+s l` to the draft target pickers and session list.
|
||||
|
||||
|
||||
@@ -106,3 +106,23 @@ describe('shortcut sequences', () => {
|
||||
expect(isRiskyBrowserShortcut('mod+s p')).toBe(true);
|
||||
});
|
||||
});
|
||||
|
||||
describe('platform shortcut labels', () => {
|
||||
test('normalizes Command and Option to platform-neutral modifiers', () => {
|
||||
expect(normalizeCombo('command+option+n')).toBe('mod+alt+n');
|
||||
});
|
||||
|
||||
test('uses macOS modifier symbols', () => {
|
||||
expect(formatShortcutForDisplay('mod+ctrl+shift+alt+n', 'Unassigned', 'macos')).toBe(
|
||||
'⌘ + ⌃ + ⇧ + ⌥ + N',
|
||||
);
|
||||
expect(formatShortcutForDisplay('alt', 'Unassigned', 'macos')).toBe('⌥');
|
||||
});
|
||||
|
||||
test('uses named modifiers on other platforms', () => {
|
||||
expect(formatShortcutForDisplay('mod+shift+alt+n', 'Unassigned', 'other')).toBe(
|
||||
'Ctrl + Shift + Alt + N',
|
||||
);
|
||||
expect(formatShortcutForDisplay('alt', 'Unassigned', 'other')).toBe('Alt');
|
||||
});
|
||||
});
|
||||
|
||||
@@ -3,6 +3,7 @@ import { isDesktopShell } from '@/lib/desktop';
|
||||
import { isMacOS } from '@/lib/utils';
|
||||
|
||||
type ShortcutModifier = 'mod' | 'shift' | 'alt' | 'ctrl';
|
||||
type ShortcutDisplayPlatform = 'macos' | 'other';
|
||||
type ShortcutKey = string;
|
||||
|
||||
export type ShortcutCombo = string;
|
||||
@@ -30,11 +31,19 @@ const MODIFIER_KEY_MAP: Record<string, ShortcutModifier> = {
|
||||
command: 'mod',
|
||||
};
|
||||
|
||||
const DISPLAY_LABEL_MAP: Record<ShortcutModifier, string> = {
|
||||
mod: isMacOS() && isDesktopShell() ? '⌘' : 'Ctrl',
|
||||
shift: '⇧',
|
||||
alt: '⌥',
|
||||
ctrl: '⌃',
|
||||
const MODIFIER_LABELS: Record<ShortcutDisplayPlatform, Record<ShortcutModifier, string>> = {
|
||||
macos: {
|
||||
mod: '⌘',
|
||||
shift: '⇧',
|
||||
alt: '⌥',
|
||||
ctrl: '⌃',
|
||||
},
|
||||
other: {
|
||||
mod: 'Ctrl',
|
||||
shift: 'Shift',
|
||||
alt: 'Alt',
|
||||
ctrl: 'Ctrl',
|
||||
},
|
||||
};
|
||||
|
||||
const KEY_LABEL_MAP: Record<string, string> = {
|
||||
@@ -176,19 +185,31 @@ export function parseShortcut(combo: ShortcutCombo): ParsedShortcut | undefined
|
||||
};
|
||||
}
|
||||
|
||||
export function formatShortcutForDisplay(combo: ShortcutCombo, unassignedLabel = 'Unassigned'): string {
|
||||
function getShortcutDisplayPlatform(): ShortcutDisplayPlatform {
|
||||
return isMacOS() ? 'macos' : 'other';
|
||||
}
|
||||
|
||||
export function formatShortcutForDisplay(
|
||||
combo: ShortcutCombo,
|
||||
unassignedLabel = 'Unassigned',
|
||||
platform = getShortcutDisplayPlatform(),
|
||||
): string {
|
||||
if (isUnassignedShortcut(combo)) return unassignedLabel;
|
||||
const parsed = parseShortcut(combo);
|
||||
if (!parsed || parsed.chords.some((chord) => !chord.key && chord.modifiers.size === 0)) {
|
||||
return unassignedLabel;
|
||||
}
|
||||
return parsed.chords.map(formatChordForDisplay).join(', ');
|
||||
return parsed.chords.map((chord) => formatChordForDisplay(chord, platform)).join(', ');
|
||||
}
|
||||
|
||||
function formatChordForDisplay(parsed: ParsedShortcutChord): string {
|
||||
function formatChordForDisplay(
|
||||
parsed: ParsedShortcutChord,
|
||||
platform: ShortcutDisplayPlatform,
|
||||
): string {
|
||||
const modifierLabels = MODIFIER_LABELS[platform];
|
||||
const parts = MODIFIER_PRIORITY
|
||||
.filter((modifier) => parsed.modifiers.has(modifier))
|
||||
.map((modifier) => DISPLAY_LABEL_MAP[modifier]);
|
||||
.map((modifier) => modifierLabels[modifier]);
|
||||
if (parsed.key) {
|
||||
parts.push(KEY_LABEL_MAP[parsed.key.toLowerCase()] || parsed.key.toUpperCase());
|
||||
}
|
||||
@@ -308,7 +329,3 @@ export function eventMatchesShortcutPrefix(
|
||||
|
||||
return !chord.key || Boolean(heldKeys?.has(chord.key.toLowerCase()));
|
||||
}
|
||||
|
||||
export function getModifierLabel(): string {
|
||||
return isMacOS() && isDesktopShell() ? '⌘' : 'Ctrl';
|
||||
}
|
||||
|
||||
@@ -2,7 +2,6 @@ export {
|
||||
eventMatchesShortcut,
|
||||
eventMatchesShortcutPrefix,
|
||||
formatShortcutForDisplay,
|
||||
getModifierLabel,
|
||||
getShortcutConflict,
|
||||
isRiskyBrowserShortcut,
|
||||
isShortcutPrefixHeld,
|
||||
|
||||
Reference in New Issue
Block a user