Skip to content

Commit 6f22ffa

Browse files
authored
fix(hotkeys): Properly map all hotkeys in UI based on the platform (#784)
* map keyboard shortcuts correctly based on platform * changelog
1 parent 7e278d3 commit 6f22ffa

File tree

11 files changed

+95
-25
lines changed

11 files changed

+95
-25
lines changed

CHANGELOG.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,9 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
77

88
## [Unreleased]
99

10+
### Fixed
11+
- Properly map all hotkeys in UI based on the platform [#784](https://github.com/sourcebot-dev/sourcebot/pull/784)
12+
1013
## [4.10.16] - 2026-01-22
1114

1215
### Changed

packages/web/src/app/[domain]/browse/components/bottomPanel.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -67,7 +67,7 @@ export const BottomPanel = ({ order }: BottomPanelProps) => {
6767
>
6868
<VscReferences className="w-4 h-4" />
6969
Explore
70-
<KeyboardShortcutHint shortcut="⇧ ⌘ E" />
70+
<KeyboardShortcutHint shortcut="shift+mod+e" />
7171
</Button>
7272
</div>
7373

packages/web/src/app/[domain]/chat/components/chatSidePanel.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -232,7 +232,7 @@ export const ChatSidePanel = ({
232232
</Button>
233233
</TooltipTrigger>
234234
<TooltipContent side="bottom" className="flex flex-row items-center gap-2">
235-
<KeyboardShortcutHint shortcut="⌘ B" />
235+
<KeyboardShortcutHint shortcut="mod+b" />
236236
<Separator orientation="vertical" className="h-4" />
237237
<span>Open side panel</span>
238238
</TooltipContent>

packages/web/src/app/[domain]/components/searchBar/searchSuggestionsBox.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -411,13 +411,13 @@ const SearchSuggestionsBox = forwardRef(({
411411
Syntax help:
412412
</p>
413413
<div className="flex flex-row gap-0.5 items-center">
414-
<KeyboardShortcutHint shortcut="" />
414+
<KeyboardShortcutHint shortcut="mod" />
415415
<KeyboardShortcutHint shortcut="/" />
416416
</div>
417417
</div>
418418
{isFocused && (
419419
<span className="flex flex-row gap-1.5 items-center">
420-
<KeyboardShortcutHint shortcut="" />
420+
<KeyboardShortcutHint shortcut="enter" />
421421
<span className="text-muted-foreground text-sm font-medium">
422422
to select
423423
</span>

packages/web/src/app/[domain]/components/searchModeSelector.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -95,7 +95,7 @@ export const SearchModeSelector = ({
9595
<span>Search</span>
9696
<div className="flex flex-row items-center gap-2">
9797
<Separator orientation="vertical" className="h-4" />
98-
<KeyboardShortcutHint shortcut="⌘ P" />
98+
<KeyboardShortcutHint shortcut="mod+p" />
9999
</div>
100100
</div>
101101

@@ -135,7 +135,7 @@ export const SearchModeSelector = ({
135135

136136
<div className="flex flex-row items-center gap-2">
137137
<Separator orientation="vertical" className="h-4" />
138-
<KeyboardShortcutHint shortcut="⌘ I" />
138+
<KeyboardShortcutHint shortcut="mod+i" />
139139
</div>
140140
</div>
141141
</SelectItemNoItemText>

packages/web/src/app/[domain]/components/syntaxReferenceGuideHint.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ export const SyntaxReferenceGuideHint = () => {
1111
className="text-sm cursor-pointer"
1212
onClick={() => onOpenChanged(!isOpen)}
1313
>
14-
<span className="dark:text-gray-300">Reference guide: </span><KeyboardShortcutHint shortcut="" /> <KeyboardShortcutHint shortcut="/" />
14+
<span className="dark:text-gray-300">Reference guide: </span><KeyboardShortcutHint shortcut="mod" /> <KeyboardShortcutHint shortcut="/" />
1515
</div>
1616
)
1717
}

packages/web/src/app/[domain]/search/components/searchResultsPage.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -298,7 +298,7 @@ const PanelGroup = ({
298298
</Button>
299299
</TooltipTrigger>
300300
<TooltipContent side="right" className="flex flex-row items-center gap-2">
301-
<KeyboardShortcutHint shortcut="⌘ B" />
301+
<KeyboardShortcutHint shortcut="mod+b" />
302302
<Separator orientation="vertical" className="h-4" />
303303
<span>Open filter panel</span>
304304
</TooltipContent>

packages/web/src/app/components/keyboardShortcutHint.tsx

Lines changed: 78 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -4,22 +4,89 @@ import { cn, IS_MAC } from '@/lib/utils'
44
import React, { useMemo } from 'react'
55

66
interface KeyboardShortcutHintProps {
7-
shortcut: string
8-
label?: string
9-
className?: string
7+
shortcut: string
8+
label?: string
9+
className?: string
1010
}
1111

1212
/**
13-
* Converts Mac-specific keyboard shortcuts to platform-appropriate shortcuts.
14-
* On Mac: displays the shortcut as-is (e.g., "⌘")
15-
* On Windows/Linux: replaces "⌘" with "Ctrl"
13+
* Maps for converting react-hotkeys syntax to platform-specific symbols.
14+
* Accepts shortcuts like "mod+b", "alt+shift+f12", etc.
1615
*/
17-
function getPlatformShortcut(shortcut: string): string {
18-
if (IS_MAC) {
19-
return shortcut;
16+
const MAC_KEY_MAP: Record<string, string> = {
17+
mod: '⌘',
18+
meta: '⌘',
19+
ctrl: '⌃',
20+
control: '⌃',
21+
alt: '⌥',
22+
option: '⌥',
23+
shift: '⇧',
24+
enter: '↵',
25+
return: '↵',
26+
backspace: '⌫',
27+
delete: '⌦',
28+
escape: '⎋',
29+
esc: '⎋',
30+
tab: '⇥',
31+
space: '␣',
32+
up: '↑',
33+
down: '↓',
34+
left: '←',
35+
right: '→',
36+
};
37+
38+
const WINDOWS_KEY_MAP: Record<string, string> = {
39+
mod: 'Ctrl',
40+
meta: 'Win',
41+
ctrl: 'Ctrl',
42+
control: 'Ctrl',
43+
alt: 'Alt',
44+
option: 'Alt',
45+
shift: 'Shift',
46+
enter: 'Enter',
47+
return: 'Enter',
48+
backspace: 'Backspace',
49+
delete: 'Delete',
50+
escape: 'Esc',
51+
esc: 'Esc',
52+
tab: 'Tab',
53+
space: 'Space',
54+
up: '↑',
55+
down: '↓',
56+
left: '←',
57+
right: '→',
58+
};
59+
60+
/**
61+
* Converts a single key from react-hotkeys syntax to platform-appropriate display.
62+
*/
63+
function mapKey(key: string, keyMap: Record<string, string>): string {
64+
const lowerKey = key.toLowerCase();
65+
if (keyMap[lowerKey]) {
66+
return keyMap[lowerKey];
67+
}
68+
// For single letters, keep uppercase
69+
if (key.length === 1) {
70+
return key.toUpperCase();
2071
}
21-
// Replace Mac Command key symbol with Ctrl for non-Mac platforms
22-
return shortcut.replace(//g, 'Ctrl');
72+
// For function keys (F1-F12), keep as-is but uppercase
73+
if (/^f\d{1,2}$/i.test(key)) {
74+
return key.toUpperCase();
75+
}
76+
// Default: return the key with first letter capitalized
77+
return key.charAt(0).toUpperCase() + key.slice(1).toLowerCase();
78+
}
79+
80+
/**
81+
* Converts react-hotkeys syntax to platform-appropriate keyboard shortcut display.
82+
* Accepts formats like: "mod+b", "alt+shift+f12", "ctrl enter"
83+
*/
84+
function getPlatformShortcut(shortcut: string): string {
85+
// Split by + or space to handle both "mod+b" and "⌘ B" formats
86+
const keys = shortcut.split(/[+\s]+/).filter(Boolean);
87+
const keyMap = IS_MAC ? MAC_KEY_MAP : WINDOWS_KEY_MAP;
88+
89+
return keys.map(key => mapKey(key, keyMap)).join(' ');
2390
}
2491

2592
export function KeyboardShortcutHint({ shortcut, label, className }: KeyboardShortcutHintProps) {

packages/web/src/ee/features/codeNav/components/exploreMenu/index.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -172,7 +172,7 @@ export const ExploreMenu = ({
172172
<TooltipContent side="top" align="center">
173173
Search all repositories
174174
<KeyboardShortcutHint
175-
shortcut="⇧ A"
175+
shortcut="shift+a"
176176
className="ml-2"
177177
/>
178178
</TooltipContent>

packages/web/src/ee/features/codeNav/components/symbolHoverPopup/index.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -287,7 +287,7 @@ export const SymbolHoverPopup: React.FC<SymbolHoverPopupProps> = ({
287287
side="bottom"
288288
className="flex flex-row items-center gap-2"
289289
>
290-
<KeyboardShortcutHint shortcut="⌥ F12" />
290+
<KeyboardShortcutHint shortcut="alt+f12" />
291291
<Separator orientation="vertical" className="h-4" />
292292
<span>{`Go to ${symbolInfo.symbolDefinitions && symbolInfo.symbolDefinitions.length > 1 ? "definitions" : "definition"}`}</span>
293293
</TooltipContent>
@@ -306,7 +306,7 @@ export const SymbolHoverPopup: React.FC<SymbolHoverPopupProps> = ({
306306
side="bottom"
307307
className="flex flex-row items-center gap-2"
308308
>
309-
<KeyboardShortcutHint shortcut="⌥ ⇧ F12" />
309+
<KeyboardShortcutHint shortcut="alt+shift+f12" />
310310
<Separator orientation="vertical" className="h-4" />
311311
<span>Find references</span>
312312
</TooltipContent>

0 commit comments

Comments
 (0)