feat: add hotkey to toggle chat modes (#1274) (#995) (#1284)

Adds Ctrl+Shift+A (Cmd+Shift+A on Mac) keyboard shortcut to toggle
between Ask and Build chat modes.

**Changes:**
- Created `useChatModeToggle` hook for shared logic
- Added shortcut to ChatInput and HomeChatInput components

**Usage:**
Press Ctrl+Shift+A (or Cmd+Shift+A on Mac) to quickly switch between
chat modes without using the UI.

<img width="434" height="123" alt="image"
src="https://github.com/user-attachments/assets/a8c167b6-2b54-46f5-8191-5019991fc8e5"
/>

Closes (#995)
    
<!-- This is an auto-generated description by cubic. -->
---

## Summary by cubic
Add a global hotkey to toggle between Ask and Build modes: Ctrl+Shift+A
(Cmd+Shift+A on Mac). Makes switching faster without touching the UI and
fulfills Linear #995.

- **New Features**
- Added useChatModeToggle hook to flip selectedChatMode, detect
platform, and track PostHog event chat:mode_toggle.
- Wired the hotkey into ChatInput and HomeChatInput via
useChatModeToggle.
  - Updated ChatModeSelector tooltip to show the shortcut.

<!-- End of auto-generated description by cubic. -->

<!-- CURSOR_SUMMARY -->
---

> [!NOTE]
> Adds Cmd/Ctrl + . shortcut to cycle chat modes via a new hook, and
updates the mode selector tooltip to show the shortcut.
> 
> - **UX/Hotkey**:
> - Introduces `useChatModeToggle` to cycle `settings.selectedChatMode`
(captures `chat:mode_toggle`), with platform detection
(`detectIsMac`/`useIsMac`) and `useShortcut` binding for `Cmd/Ctrl + .`.
> - **Integrations**:
> - Wires `useChatModeToggle()` into `components/chat/ChatInput.tsx` and
`components/chat/HomeChatInput.tsx` to enable the shortcut in chat
inputs.
> - **UI**:
> - Enhances `components/ChatModeSelector.tsx` tooltip to display the
platform-specific shortcut hint (`⌘ + .` or `Ctrl + .`).
> 
> <sup>Written by [Cursor
Bugbot](https://cursor.com/dashboard?tab=bugbot) for commit
d8cc3fff43b6eb3227623f1c084410f42392c0b3. This will update automatically
on new commits. Configure
[here](https://cursor.com/dashboard?tab=bugbot).</sup>
<!-- /CURSOR_SUMMARY -->

---------

Co-authored-by: Will Chen <willchen90@gmail.com>
This commit is contained in:
Adeniji Adekunle James
2025-09-30 21:43:24 +01:00
committed by GitHub
parent 8f31821442
commit 3b68fb4e48
4 changed files with 85 additions and 1 deletions

View File

@@ -0,0 +1,71 @@
import { useCallback, useMemo } from "react";
import { useSettings } from "./useSettings";
import { useShortcut } from "./useShortcut";
import { usePostHog } from "posthog-js/react";
import { ChatModeSchema } from "../lib/schemas";
export function useChatModeToggle() {
const { settings, updateSettings } = useSettings();
const posthog = usePostHog();
// Detect if user is on mac
const isMac = useIsMac();
// Memoize the modifiers object to prevent re-registration
const modifiers = useMemo(
() => ({
ctrl: !isMac,
meta: isMac,
}),
[isMac],
);
// Function to toggle between ask and build chat modes
const toggleChatMode = useCallback(() => {
if (!settings || !settings.selectedChatMode) return;
const currentMode = settings.selectedChatMode;
const modes = ChatModeSchema.options;
const currentIndex = modes.indexOf(settings.selectedChatMode);
const newMode = modes[(currentIndex + 1) % modes.length];
updateSettings({ selectedChatMode: newMode });
posthog.capture("chat:mode_toggle", {
from: currentMode,
to: newMode,
trigger: "keyboard_shortcut",
});
}, [settings, updateSettings, posthog]);
// Add keyboard shortcut with memoized modifiers
useShortcut(
".",
modifiers,
toggleChatMode,
true, // Always enabled since we're not dependent on component selector
);
return { toggleChatMode, isMac };
}
// Add this function at the top
type NavigatorWithUserAgentData = Navigator & {
userAgentData?: {
platform?: string;
};
};
export function detectIsMac(): boolean {
const nav = navigator as NavigatorWithUserAgentData;
// Try modern API first
if ("userAgentData" in nav && nav.userAgentData?.platform) {
return nav.userAgentData.platform.toLowerCase().includes("mac");
}
// Fallback to user agent check
return /Mac|iPhone|iPad|iPod/.test(navigator.userAgent);
}
// Export the utility function and hook for use elsewhere
export function useIsMac(): boolean {
return useMemo(() => detectIsMac(), []);
}