From a41d2c713e87d56f23d5884585b4bb43c43a250a Mon Sep 17 00:00:00 2001 From: simosmik Date: Sat, 21 Mar 2026 16:40:44 +0000 Subject: [PATCH] fix: claude auth changes and adding copy on mobile --- .../provider-auth/view/ProviderLoginModal.tsx | 7 +- src/components/shell/view/Shell.tsx | 26 +- .../subcomponents/TerminalShortcutsPanel.tsx | 283 ++++++++++-------- 3 files changed, 171 insertions(+), 145 deletions(-) diff --git a/src/components/provider-auth/view/ProviderLoginModal.tsx b/src/components/provider-auth/view/ProviderLoginModal.tsx index b1fa1f1..9e80302 100644 --- a/src/components/provider-auth/view/ProviderLoginModal.tsx +++ b/src/components/provider-auth/view/ProviderLoginModal.tsx @@ -24,7 +24,7 @@ type ProviderLoginModalProps = { const getProviderCommand = ({ provider, customCommand, - isAuthenticated, + isAuthenticated: _isAuthenticated, }: { provider: CliProvider; customCommand?: string; @@ -35,10 +35,7 @@ const getProviderCommand = ({ } if (provider === 'claude') { - if (isAuthenticated) { - return 'claude setup-token --dangerously-skip-permissions'; - } - return 'claude /login --dangerously-skip-permissions'; + return 'claude --dangerously-skip-permissions /login'; } if (provider === 'cursor') { diff --git a/src/components/shell/view/Shell.tsx b/src/components/shell/view/Shell.tsx index 3d51980..a31a331 100644 --- a/src/components/shell/view/Shell.tsx +++ b/src/components/shell/view/Shell.tsx @@ -207,15 +207,23 @@ export default function Shell({ if (minimal) { return ( - + <> + + + ); } diff --git a/src/components/shell/view/subcomponents/TerminalShortcutsPanel.tsx b/src/components/shell/view/subcomponents/TerminalShortcutsPanel.tsx index fc238e1..0378f0d 100644 --- a/src/components/shell/view/subcomponents/TerminalShortcutsPanel.tsx +++ b/src/components/shell/view/subcomponents/TerminalShortcutsPanel.tsx @@ -1,61 +1,65 @@ -import { type MutableRefObject, useState, useCallback, useEffect, useRef } from 'react'; +import { type MutableRefObject, useCallback, useState } from 'react'; import { - ChevronLeft, - ChevronRight, - Keyboard, + Clipboard, ArrowDownToLine, + ArrowUp, + ArrowDown, + ArrowLeft, + ArrowRight, } from 'lucide-react'; import { useTranslation } from 'react-i18next'; import type { Terminal } from '@xterm/xterm'; import { sendSocketMessage } from '../../utils/socket'; -const SHORTCUTS = [ - { id: 'escape', labelKey: 'escape', sequence: '\x1b', hint: 'Esc' }, - { id: 'tab', labelKey: 'tab', sequence: '\t', hint: 'Tab' }, - { id: 'shift-tab', labelKey: 'shiftTab', sequence: '\x1b[Z', hint: '\u21e7Tab' }, - { id: 'arrow-up', labelKey: 'arrowUp', sequence: '\x1b[A', hint: '\u2191' }, - { id: 'arrow-down', labelKey: 'arrowDown', sequence: '\x1b[B', hint: '\u2193' }, -] as const; +type Shortcut = + | { type: 'key'; id: string; label: string; sequence: string } + | { type: 'modifier'; id: string; label: string; modifier: 'ctrl' | 'alt' } + | { type: 'arrow'; id: string; sequence: string; icon: 'up' | 'down' | 'left' | 'right' }; + +const MOBILE_KEYS: Shortcut[] = [ + { type: 'key', id: 'esc', label: 'Esc', sequence: '\x1b' }, + { type: 'key', id: 'tab', label: 'Tab', sequence: '\t' }, + { type: 'key', id: 'shift-tab', label: '\u21e7Tab', sequence: '\x1b[Z' }, + { type: 'modifier', id: 'ctrl', label: 'CTRL', modifier: 'ctrl' }, + { type: 'modifier', id: 'alt', label: 'ALT', modifier: 'alt' }, + { type: 'arrow', id: 'arrow-up', sequence: '\x1b[A', icon: 'up' }, + { type: 'arrow', id: 'arrow-down', sequence: '\x1b[B', icon: 'down' }, + { type: 'arrow', id: 'arrow-left', sequence: '\x1b[D', icon: 'left' }, + { type: 'arrow', id: 'arrow-right', sequence: '\x1b[C', icon: 'right' }, +]; + +const ARROW_ICONS = { + up: ArrowUp, + down: ArrowDown, + left: ArrowLeft, + right: ArrowRight, +} as const; type TerminalShortcutsPanelProps = { wsRef: MutableRefObject; terminalRef: MutableRefObject; isConnected: boolean; + bottomOffset?: string; }; const preventFocusSteal = (e: React.PointerEvent) => e.preventDefault(); +const KEY_BTN = + 'shrink-0 rounded-md border border-gray-600 bg-gray-700 px-2.5 py-1.5 text-xs font-medium text-gray-100 transition-colors select-none active:bg-blue-600 active:text-white active:border-blue-600 disabled:cursor-not-allowed disabled:opacity-40'; +const KEY_BTN_ACTIVE = + 'shrink-0 rounded-md border border-blue-500 bg-blue-600 px-2.5 py-1.5 text-xs font-medium text-white transition-colors select-none disabled:cursor-not-allowed disabled:opacity-40'; +const ICON_BTN = + 'shrink-0 rounded-md border border-gray-600 bg-gray-700 p-1.5 text-gray-100 transition-colors select-none active:bg-blue-600 active:text-white active:border-blue-600 disabled:cursor-not-allowed disabled:opacity-40'; + export default function TerminalShortcutsPanel({ wsRef, terminalRef, isConnected, + bottomOffset = 'bottom-14', }: TerminalShortcutsPanelProps) { const { t } = useTranslation('settings'); - const [isOpen, setIsOpen] = useState(false); - const closeTimeoutRef = useRef | null>(null); - - useEffect(() => { - return () => { - if (closeTimeoutRef.current) { - clearTimeout(closeTimeoutRef.current); - } - }; - }, []); - - const handleToggle = useCallback(() => { - setIsOpen((prev) => !prev); - }, []); - - const handleShortcutAction = useCallback((action: () => void) => { - action(); - if (document.activeElement instanceof HTMLElement) { - document.activeElement.blur(); - } - if (closeTimeoutRef.current) { - clearTimeout(closeTimeoutRef.current); - } - closeTimeoutRef.current = setTimeout(() => setIsOpen(false), 50); - }, []); + const [ctrlActive, setCtrlActive] = useState(false); + const [altActive, setAltActive] = useState(false); const sendInput = useCallback( (data: string) => { @@ -68,103 +72,120 @@ export default function TerminalShortcutsPanel({ terminalRef.current?.scrollToBottom(); }, [terminalRef]); - return ( - <> - {/* Pull Tab */} - + setCtrlActive(false); + } + if (altActive && seq.length === 1) { + finalSeq = '\x1b' + finalSeq; + setAltActive(false); + } + sendInput(finalSeq); + }, + [ctrlActive, altActive, sendInput], + ); - {/* Panel */} -
-
- {/* Header */} -
-

- - {t('terminalShortcuts.title')} -

-
- - {/* Content — conditionally rendered so buttons remount with clean CSS states */} - {isOpen && ( -
- {/* Shortcut Keys */} -
-

- {t('terminalShortcuts.sectionKeys')} -

- {SHORTCUTS.map((shortcut) => ( - - ))} -
- - {/* Navigation */} -
-

- {t('terminalShortcuts.sectionNavigation')} -

- -
-
- )} -
-
- - {/* Backdrop */} - {isOpen && ( -
+
+ + + {MOBILE_KEYS.map((key) => { + if (key.type === 'modifier') { + const isActive = key.modifier === 'ctrl' ? ctrlActive : altActive; + const toggle = + key.modifier === 'ctrl' + ? () => setCtrlActive((v) => !v) + : () => setAltActive((v) => !v); + return ( + + ); + } + + if (key.type === 'arrow') { + const Icon = ARROW_ICONS[key.icon]; + return ( + + ); + } + + return ( + + ); + })} + + +
+
); }