diff --git a/src/renderer/src/components/editor/EditorPanel.tsx b/src/renderer/src/components/editor/EditorPanel.tsx index 77616d92c..519dc6247 100644 --- a/src/renderer/src/components/editor/EditorPanel.tsx +++ b/src/renderer/src/components/editor/EditorPanel.tsx @@ -5,11 +5,19 @@ across multiple components. Autosave now lives in a smaller headless controller so hidden editor UI no longer participates in shutdown. */ import React, { useCallback, useEffect, useRef, useState, Suspense } from 'react' import * as monaco from 'monaco-editor' -import { Columns2, FileText, Rows2 } from 'lucide-react' +import { Columns2, Copy, ExternalLink, FileText, Rows2 } from 'lucide-react' import { useAppStore } from '@/store' import { detectLanguage } from '@/lib/language-detect' import { getEditorHeaderCopyState, getEditorHeaderOpenFileState } from './editor-header' import { Tooltip, TooltipContent, TooltipProvider, TooltipTrigger } from '@/components/ui/tooltip' +import { + DropdownMenu, + DropdownMenuContent, + DropdownMenuItem, + DropdownMenuSeparator, + DropdownMenuTrigger +} from '@/components/ui/dropdown-menu' +import { CLOSE_ALL_CONTEXT_MENUS_EVENT } from '../tab-bar/SortableTab' import type { MarkdownViewMode, OpenFile } from '@/store/slices/editor' import MarkdownViewToggle from './MarkdownViewToggle' import { EditorContent } from './EditorContent' @@ -24,6 +32,16 @@ import { type EditorPathMutationTarget } from './editor-autosave' +const isMac = navigator.userAgent.includes('Mac') +const isLinux = navigator.userAgent.includes('Linux') + +/** Platform-appropriate label: macOS → Finder, Windows → File Explorer, Linux → Files */ +const revealLabel = isMac + ? 'Reveal in Finder' + : isLinux + ? 'Open Containing Folder' + : 'Reveal in File Explorer' + type FileContent = { content: string isBinary: boolean @@ -61,6 +79,8 @@ export default function EditorPanel({ ) const [sideBySide, setSideBySide] = useState(settings?.diffDefaultView === 'side-by-side') const [prevDiffView, setPrevDiffView] = useState(settings?.diffDefaultView) + const [pathMenuOpen, setPathMenuOpen] = useState(false) + const [pathMenuPoint, setPathMenuPoint] = useState({ x: 0, y: 0 }) // Why: When the user changes their global diff-view preference in Settings, // sync the local toggle to match during render (avoids flash of stale diff mode). @@ -74,6 +94,12 @@ export default function EditorPanel({ const openFilesRef = useRef(openFiles) openFilesRef.current = openFiles + useEffect(() => { + const closeMenu = (): void => setPathMenuOpen(false) + window.addEventListener(CLOSE_ALL_CONTEXT_MENUS_EVENT, closeMenu) + return () => window.removeEventListener(CLOSE_ALL_CONTEXT_MENUS_EVENT, closeMenu) + }, []) + // Why: keepCurrentModel / keepCurrent*Model retain Monaco models after unmount // so undo history survives tab switches. When a tab is *closed*, the user has // signalled they're done with the file — dispose the models to reclaim memory @@ -454,7 +480,15 @@ export default function EditorPanel({ {!isCombinedDiff && (