/** * SessionContextMenu - Right-click context menu for sidebar session items. * Supports opening in current pane, new tab, and split right. * Shows keyboard shortcut hints for actions that have them. */ import { useEffect, useRef, useState } from 'react'; import { MAX_PANES } from '@renderer/types/panes'; import { formatShortcut } from '@renderer/utils/stringUtils'; import { Check, ClipboardCopy, Eye, EyeOff, Pin, PinOff, Terminal } from 'lucide-react'; interface SessionContextMenuProps { x: number; y: number; sessionId: string; projectId: string; sessionLabel: string; paneCount: number; isPinned: boolean; isHidden: boolean; onClose: () => void; onOpenInCurrentPane: () => void; onOpenInNewTab: () => void; onSplitRightAndOpen: () => void; onTogglePin: () => void; onToggleHide: () => void; } export const SessionContextMenu = ({ x, y, sessionId, paneCount, isPinned, isHidden, onClose, onOpenInCurrentPane, onOpenInNewTab, onSplitRightAndOpen, onTogglePin, onToggleHide, }: SessionContextMenuProps): React.JSX.Element => { const menuRef = useRef(null); const [copiedField, setCopiedField] = useState<'id' | 'command' | null>(null); useEffect(() => { const handleMouseDown = (e: MouseEvent): void => { if (menuRef.current && !menuRef.current.contains(e.target as Node)) { onClose(); } }; const handleKeyDown = (e: KeyboardEvent): void => { if (e.key === 'Escape') onClose(); }; document.addEventListener('mousedown', handleMouseDown); document.addEventListener('keydown', handleKeyDown); return () => { document.removeEventListener('mousedown', handleMouseDown); document.removeEventListener('keydown', handleKeyDown); }; }, [onClose]); const menuWidth = 240; const menuHeight = 290; const clampedX = Math.min(x, window.innerWidth - menuWidth - 8); const clampedY = Math.min(y, window.innerHeight - menuHeight - 8); const handleClick = (action: () => void) => () => { action(); onClose(); }; const handleCopy = (text: string, field: 'id' | 'command') => async () => { try { await navigator.clipboard.writeText(text); setCopiedField(field); setTimeout(() => { setCopiedField(null); onClose(); }, 600); } catch { // Silently fail } }; const atMaxPanes = paneCount >= MAX_PANES; return (
: } onClick={handleClick(onTogglePin)} /> : } onClick={handleClick(onToggleHide)} />
) : ( ) } onClick={handleCopy(sessionId, 'id')} /> ) : ( ) } onClick={handleCopy(`claude --resume ${sessionId}`, 'command')} />
); }; const MenuItem = ({ label, shortcut, icon, onClick, disabled, }: { label: string; shortcut?: string; icon?: React.ReactNode; onClick: () => void; disabled?: boolean; }): React.JSX.Element => { return ( ); };