diff --git a/packages/ui/src/components/layout/SidebarFilesTree.tsx b/packages/ui/src/components/layout/SidebarFilesTree.tsx index 47121de3..24086af5 100644 --- a/packages/ui/src/components/layout/SidebarFilesTree.tsx +++ b/packages/ui/src/components/layout/SidebarFilesTree.tsx @@ -13,6 +13,7 @@ import { RiMore2Fill, RiRefreshLine, RiSearchLine, + RiDownloadLine, } from '@remixicon/react'; import { toast } from '@/components/ui'; @@ -44,7 +45,7 @@ import { useGitStatus } from '@/stores/useGitStore'; import { useDirectoryShowHidden } from '@/lib/directoryShowHidden'; import { useFilesViewShowGitignored } from '@/lib/filesViewShowGitignored'; import { copyTextToClipboard } from '@/lib/clipboard'; -import { cn } from '@/lib/utils'; +import { cn, getRevealLabel } from '@/lib/utils'; import { opencodeClient } from '@/lib/opencode/client'; import { FileTypeIcon } from '@/components/icons/FileTypeIcon'; import { getContextFileOpenFailureMessage, validateContextFileOpen } from '@/lib/contextFileOpenGuard'; @@ -132,6 +133,7 @@ interface FileRowProps { canDelete: boolean; canReveal: boolean; }; + downloadFile?: (path: string) => Promise; contextMenuPath: string | null; setContextMenuPath: (path: string | null) => void; onSelect: (node: FileNode) => void; @@ -147,6 +149,7 @@ const FileRow: React.FC = ({ status, badge, permissions, + downloadFile, contextMenuPath, setContextMenuPath, onSelect, @@ -244,9 +247,17 @@ const FileRow: React.FC = ({ }}> Copy Path + {!isDir && downloadFile && ( + { + e.stopPropagation(); + void downloadFile(node.path); + }}> + Save + + )} {canReveal && ( { e.stopPropagation(); onRevealPath(node.path); }}> - Reveal in Finder + {getRevealLabel()} )} {isDir && (canCreateFile || canCreateFolder) && ( @@ -749,6 +760,7 @@ export const SidebarFilesTree: React.FC = () => { status={!isDir ? getFileStatus(node.path) : undefined} badge={isDir ? getFolderBadge(node.path) : undefined} permissions={{ canRename, canCreateFile, canCreateFolder, canDelete, canReveal }} + downloadFile={files.downloadFile} contextMenuPath={contextMenuPath} setContextMenuPath={setContextMenuPath} onSelect={handleOpenFile} diff --git a/packages/ui/src/components/views/FilesView.tsx b/packages/ui/src/components/views/FilesView.tsx index 894d3d00..6aeadce9 100644 --- a/packages/ui/src/components/views/FilesView.tsx +++ b/packages/ui/src/components/views/FilesView.tsx @@ -26,6 +26,7 @@ import { RiFileTransferLine, RiCodeSSlashLine, RiNodeTree, + RiDownloadLine, } from '@remixicon/react'; import { toast } from '@/components/ui'; import { copyTextToClipboard } from '@/lib/clipboard'; @@ -58,7 +59,7 @@ import { import { useDebouncedValue } from '@/hooks/useDebouncedValue'; import { useFileSearchStore } from '@/stores/useFileSearchStore'; import { useDeviceInfo } from '@/lib/device'; -import { cn, getModifierLabel, hasModifier } from '@/lib/utils'; +import { cn, getModifierLabel, getRevealLabel, hasModifier } from '@/lib/utils'; import { getLanguageFromExtension, getImageMimeType, isImageFile } from '@/lib/toolHelpers'; import { useRuntimeAPIs } from '@/hooks/useRuntimeAPIs'; import { EditorView } from '@codemirror/view'; @@ -292,6 +293,7 @@ interface FileRowProps { canDelete: boolean; canReveal: boolean; }; + downloadFile?: (path: string) => Promise; contextMenuPath: string | null; setContextMenuPath: (path: string | null) => void; onSelect: (node: FileNode) => void; @@ -308,6 +310,7 @@ const FileRow: React.FC = ({ status, badge, permissions, + downloadFile, contextMenuPath, setContextMenuPath, onSelect, @@ -414,9 +417,17 @@ const FileRow: React.FC = ({ }}> Copy Path + {!isDir && downloadFile && ( + { + e.stopPropagation(); + void downloadFile(node.path); + }}> + Save + + )} {canReveal && ( { e.stopPropagation(); onRevealPath(node.path); }}> - Reveal in Finder + {getRevealLabel()} )} {isDir && (canCreateFile || canCreateFolder) && ( @@ -1638,6 +1649,7 @@ export const FilesView: React.FC = ({ mode = 'full' }) => { status={!isDir ? getFileStatus(node.path) : undefined} badge={isDir ? getFolderBadge(node.path) : undefined} permissions={{ canRename, canCreateFile, canCreateFolder, canDelete, canReveal }} + downloadFile={files.downloadFile} contextMenuPath={contextMenuPath} setContextMenuPath={setContextMenuPath} onSelect={handleSelectFile} @@ -2426,6 +2438,22 @@ export const FilesView: React.FC = ({ mode = 'full' }) => { )} + {files.downloadFile && ( + + )} + {exitFullscreenOnly ? (