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 && (
-
+
{ + event.preventDefault() + window.dispatchEvent(new Event(CLOSE_ALL_CONTEXT_MENUS_EVENT)) + setPathMenuPoint({ x: event.clientX, y: event.clientY }) + setPathMenuOpen(true) + }} + >
+ + +
{isSingleDiff && ( diff --git a/src/renderer/src/components/tab-bar/EditorFileTab.tsx b/src/renderer/src/components/tab-bar/EditorFileTab.tsx index f56d6410c..b4b517bc5 100644 --- a/src/renderer/src/components/tab-bar/EditorFileTab.tsx +++ b/src/renderer/src/components/tab-bar/EditorFileTab.tsx @@ -1,7 +1,7 @@ import { useEffect, useState } from 'react' import { useSortable } from '@dnd-kit/sortable' import { CSS } from '@dnd-kit/utilities' -import { X, FileCode, GitCompareArrows, Copy, ShieldAlert } from 'lucide-react' +import { X, FileCode, GitCompareArrows, Copy, ShieldAlert, ExternalLink } from 'lucide-react' import { DropdownMenu, DropdownMenuContent, @@ -16,6 +16,16 @@ import type { GitFileStatus } from '../../../../shared/types' import type { OpenFile } from '../../store/slices/editor' import { CLOSE_ALL_CONTEXT_MENUS_EVENT } from './SortableTab' +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' + export default function EditorFileTab({ file, isActive, @@ -177,10 +187,10 @@ export default function EditorFileTab({ Close + Close All Editor Tabs Close Tabs To The Right - Close All Editor Tabs { @@ -198,6 +208,15 @@ export default function EditorFileTab({ Copy Relative Path + + { + window.api.shell.openPath(file.filePath) + }} + > + + {revealLabel} +