feat(chat): desktop prompt navigator rail (#2054)

* feat(chat): add desktop prompt navigator rail

Add a ChatGPT-style right-center prompt marker rail for web/desktop chat
with hover/keyboard preview panel, load-more for partial history (panel only),
Chat setting, and mod+alt+p shortcut. Disabled in VS Code across rail,
shortcut, settings, help, and search surfaces.

Co-authored-by: Serhii Dziupin <makeittech@users.noreply.github.com>

* fix(ui): read promptNavigatorEnabled from getState in shortcut handler

Match the file convention used by other shortcut handlers so the toggle
does not rely on a hook-level selector closure.

Co-authored-by: Serhii Dziupin <makeittech@users.noreply.github.com>

* fix(ui): drop use-no-memo and default prompt navigator off

Remove the project-unprecedented React Compiler opt-out, and ship the
prompt navigator as opt-in to match other recent chat UI toggles.

Co-authored-by: Serhii Dziupin <makeittech@users.noreply.github.com>

---------

Co-authored-by: Cursor Agent <cursoragent@cursor.com>
Co-authored-by: Serhii Dziupin <makeittech@users.noreply.github.com>
This commit is contained in:
Serhii Dziupin
2026-07-13 09:02:14 +03:00
committed by GitHub
co-authored by Serhii Dziupin Cursor Agent
parent 502c96630e
commit 1fb448d827
36 changed files with 754 additions and 21 deletions
@@ -35,6 +35,8 @@ export const useKeyboardShortcuts = () => {
const setSettingsDialogOpen = useUIStore((s) => s.setSettingsDialogOpen);
const setModelSelectorOpen = useUIStore((s) => s.setModelSelectorOpen);
const setTimelineDialogOpen = useUIStore((s) => s.setTimelineDialogOpen);
const togglePromptNavigatorPanel = useUIStore((s) => s.togglePromptNavigatorPanel);
const setPromptNavigatorPanelOpen = useUIStore((s) => s.setPromptNavigatorPanelOpen);
const toggleExpandedInput = useUIStore((s) => s.toggleExpandedInput);
const shortcutOverrides = useUIStore((s) => s.shortcutOverrides);
const currentDirectory = useDirectoryStore((s) => s.currentDirectory);
@@ -142,6 +144,42 @@ export const useKeyboardShortcuts = () => {
return;
}
if (eventMatchesShortcut(e, combo('toggle_prompt_navigator'))) {
const {
activeMainTab,
promptNavigatorEnabled,
isSettingsDialogOpen,
isCommandPaletteOpen,
isHelpDialogOpen,
isSessionSwitcherOpen,
isAboutDialogOpen,
isTimelineDialogOpen,
isMultiRunLauncherOpen,
isImagePreviewOpen,
} = useUIStore.getState();
if (!promptNavigatorEnabled || isMobile || isVSCodeRuntime() || activeMainTab !== 'chat') {
return;
}
const hasOverlay = isSettingsDialogOpen
|| isCommandPaletteOpen
|| isHelpDialogOpen
|| isSessionSwitcherOpen
|| isAboutDialogOpen
|| isTimelineDialogOpen
|| isMultiRunLauncherOpen
|| isImagePreviewOpen;
if (hasOverlay) {
return;
}
e.preventDefault();
togglePromptNavigatorPanel();
return;
}
if (eventMatchesShortcut(e, combo('open_status'))) {
e.preventDefault();
void showOpenCodeStatus();
@@ -505,6 +543,7 @@ export const useKeyboardShortcuts = () => {
isMultiRunLauncherOpen,
isImagePreviewOpen,
activeMainTab,
isPromptNavigatorPanelOpen,
} = useUIStore.getState();
if (isInsideDialog || isInsideTerminal || hasDropdownInteraction) {
@@ -512,6 +551,13 @@ export const useKeyboardShortcuts = () => {
return;
}
if (isPromptNavigatorPanelOpen) {
e.preventDefault();
setPromptNavigatorPanelOpen(false);
resetAbortPriming();
return;
}
// If settings is open, close it
if (isSettingsDialogOpen) {
e.preventDefault();
@@ -594,6 +640,8 @@ export const useKeyboardShortcuts = () => {
setSettingsDialogOpen,
setModelSelectorOpen,
setTimelineDialogOpen,
togglePromptNavigatorPanel,
setPromptNavigatorPanelOpen,
toggleExpandedInput,
setThemeMode,
working,