diff --git a/src/components/navigator/FilePanel.tsx b/src/components/navigator/FilePanel.tsx index 985f5c6..ab5e3c6 100644 --- a/src/components/navigator/FilePanel.tsx +++ b/src/components/navigator/FilePanel.tsx @@ -334,6 +334,7 @@ const FilePanel = forwardRef< void + cwd?: string + onRemoteSelect: (remote: string | 'UI_LOCAL_FS' | 'UI_FAVORITES', initialPath?: string) => void allowedKeys: AllowedKey[] remotes: string[] }) { @@ -65,6 +69,24 @@ export default function RemoteSidebar({ const canShowLocal = allowedKeys.includes('LOCAL_FS') const canShowRemotes = allowedKeys.includes('REMOTES') + const disksQuery = useQuery({ + queryKey: ['core', 'disks'], + queryFn: () => rclone('/core/disks'), + staleTime: 1000 * 60 * 5, + enabled: canShowLocal, + }) + + const disks = useMemo( + () => (disksQuery.data?.disks ?? []).filter(shouldShowDisk), + [disksQuery.data] + ) + + const activeDisk = useMemo(() => { + if (selectedRemote !== 'UI_LOCAL_FS' || !cwd) return null + const sorted = [...disks].sort((a, b) => b.length - a.length) + return sorted.find((disk) => cwd.startsWith(disk)) ?? null + }, [selectedRemote, cwd, disks]) + const orderClass = position === 'right' ? 'order-last' : 'order-first' return ( @@ -94,24 +116,30 @@ export default function RemoteSidebar({ )} - {canShowLocal && ( - - - - )} + {canShowLocal && + disks.map((disk) => { + const { icon: DiskIcon, className: iconColor } = getDiskIcon(disk) + const label = getDiskLabel(disk) + return ( + + + + ) + })} {canShowRemotes && remotes.map((remote) => ( { + async (remote: string | 'UI_LOCAL_FS' | 'UI_FAVORITES', initialPath?: string) => { cleanupSelectionForRemote(remote) if (remote === 'UI_LOCAL_FS') { - const home = await homeDir() + const startPath = initialPath ?? (await homeDir()) startTransition(() => { setSelectedRemote(remote) - setCwd(home) + setCwd(startPath) }) } else { startTransition(() => { setSelectedRemote(remote) - setCwd('') + setCwd(initialPath ?? '') }) } }, diff --git a/src/components/navigator/utils.ts b/src/components/navigator/utils.ts index dc80e72..c78565e 100644 --- a/src/components/navigator/utils.ts +++ b/src/components/navigator/utils.ts @@ -1,5 +1,14 @@ import { dirname, join, sep } from '@tauri-apps/api/path' import { readDir } from '@tauri-apps/plugin-fs' +import type { LucideIcon } from 'lucide-react' +import { + DownloadIcon, + FileTextIcon, + HardDriveIcon, + HouseIcon, + MonitorIcon, + UsbIcon, +} from 'lucide-react' import { createRef } from 'react' import rclone from '../../../lib/rclone/client.ts' import type { SelectItem } from './types' @@ -177,6 +186,41 @@ export function getFileExtension(filename: string): string { return filename.slice(lastDot + 1).toLowerCase() } +export function getDiskLabel(disk: string): string { + const last = disk.split(/[/\\]/).filter(Boolean).pop() + return last ?? disk +} + +const SHOWN_DISKS = new Set(['desktop', 'documents', 'downloads']) + +export function shouldShowDisk(disk: string): boolean { + if (disk === '/' || /^[A-Z]:[\\/]?$/i.test(disk)) return true + const last = disk.split(/[/\\]/).filter(Boolean).pop()?.toLowerCase() + if (last && SHOWN_DISKS.has(last)) return true + // Home folder: parent is a known users directory + if (/[\\/](?:Users|home)[\\/][^/\\]+\/?$/i.test(disk)) return true + // USB / external volumes + if (/[\\/](?:media|Volumes|mnt)[\\/]/i.test(disk)) return true + return false +} + +export function getDiskIcon(disk: string): { icon: LucideIcon; className: string } { + const last = disk.split(/[/\\]/).filter(Boolean).pop()?.toLowerCase() + switch (last) { + case 'desktop': + return { icon: MonitorIcon, className: 'text-sky-400' } + case 'documents': + return { icon: FileTextIcon, className: 'text-blue-400' } + case 'downloads': + return { icon: DownloadIcon, className: 'text-green-400' } + } + if (disk === '/' || /^[A-Z]:[\\/]?$/i.test(disk)) + return { icon: HardDriveIcon, className: 'text-zinc-400' } + if (/[\\/](?:media|Volumes|mnt)[\\/]/i.test(disk)) + return { icon: UsbIcon, className: 'text-orange-400' } + return { icon: HouseIcon, className: 'text-amber-400' } +} + export function formatModTime(modTime: string | undefined): string { if (!modTime) return '—' try {