show local folders using core/disks

This commit is contained in:
FTCHD
2026-06-05 21:01:32 +03:00
parent 26809c5b1d
commit e936aa2861
4 changed files with 98 additions and 24 deletions
+2
View File
@@ -334,6 +334,7 @@ const FilePanel = forwardRef<
<RemoteSidebar
position="left"
selectedRemote={nav.selectedRemote}
cwd={nav.cwd}
onRemoteSelect={nav.selectRemote}
allowedKeys={allowedKeys}
remotes={nav.remotes}
@@ -410,6 +411,7 @@ const FilePanel = forwardRef<
<RemoteSidebar
position="right"
selectedRemote={nav.selectedRemote}
cwd={nav.cwd}
onRemoteSelect={nav.selectRemote}
allowedKeys={allowedKeys}
remotes={nav.remotes}
+48 -20
View File
@@ -1,9 +1,11 @@
import { Button, ScrollShadow, Tooltip, cn } from '@heroui/react'
import { useQuery } from '@tanstack/react-query'
import { platform } from '@tauri-apps/plugin-os'
import { LaptopIcon, StarIcon } from 'lucide-react'
import { StarIcon } from 'lucide-react'
import { useMemo } from 'react'
import rclone from '../../../lib/rclone/client.ts'
import type { AllowedKey, RemoteString } from './types'
import { getDiskIcon, getDiskLabel, shouldShowDisk } from './utils'
function RemoteButton({
remote,
@@ -51,13 +53,15 @@ function RemoteButton({
export default function RemoteSidebar({
position,
selectedRemote,
cwd,
onRemoteSelect,
allowedKeys,
remotes,
}: {
position: 'left' | 'right'
selectedRemote: RemoteString
onRemoteSelect: (remote: string | 'UI_LOCAL_FS' | 'UI_FAVORITES') => 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({
</Button>
</Tooltip>
)}
{canShowLocal && (
<Tooltip
content="Local Filesystem"
placement={position === 'left' ? 'right' : 'left'}
color="foreground"
size="lg"
>
<Button
isIconOnly={true}
className="shrink-0"
size="lg"
onPress={() => onRemoteSelect('UI_LOCAL_FS')}
variant={selectedRemote === 'UI_LOCAL_FS' ? 'faded' : 'light'}
>
<LaptopIcon className="size-6" />
</Button>
</Tooltip>
)}
{canShowLocal &&
disks.map((disk) => {
const { icon: DiskIcon, className: iconColor } = getDiskIcon(disk)
const label = getDiskLabel(disk)
return (
<Tooltip
key={disk}
content={label}
placement={position === 'left' ? 'right' : 'left'}
color="foreground"
size="lg"
>
<Button
isIconOnly={true}
className="shrink-0"
size="lg"
onPress={() => onRemoteSelect('UI_LOCAL_FS', disk)}
variant={activeDisk === disk ? 'faded' : 'light'}
>
<DiskIcon className={cn('size-6', iconColor)} />
</Button>
</Tooltip>
)
})}
{canShowRemotes &&
remotes.map((remote) => (
<RemoteButton
@@ -237,18 +237,18 @@ export default function useFileNavigation({
)
const selectRemote = useCallback(
async (remote: string | 'UI_LOCAL_FS' | 'UI_FAVORITES') => {
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 ?? '')
})
}
},
+44
View File
@@ -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 {