Files
drive/apps/drive-web/src/directories/directory-path-breadcrumb.tsx

123 lines
2.9 KiB
TypeScript
Raw Normal View History

2025-10-03 23:23:05 +00:00
import { Link } from "@tanstack/react-router"
2025-10-18 19:55:14 +00:00
import type { PrimitiveAtom } from "jotai"
import { atom } from "jotai"
2025-10-18 19:55:14 +00:00
import { Fragment } from "react"
2025-10-03 23:23:05 +00:00
import {
Breadcrumb,
BreadcrumbItem,
BreadcrumbLink,
BreadcrumbList,
BreadcrumbPage,
BreadcrumbSeparator,
2025-10-18 19:55:14 +00:00
} from "@/components/ui/breadcrumb"
2025-10-03 23:23:05 +00:00
import {
Tooltip,
TooltipContent,
TooltipTrigger,
2025-10-18 19:55:14 +00:00
} from "@/components/ui/tooltip"
import type { FileDragInfo } from "@/files/use-file-drop"
import { useFileDrop } from "@/files/use-file-drop"
import { cn } from "@/lib/utils"
import type { DirectoryInfoWithPath } from "@/vfs/vfs"
import type { PathSegment } from "../lib/path"
2025-10-03 23:23:05 +00:00
/**
* This is a placeholder file drag info atom that always stores null and is never mutated.
*/
const nullFileDragInfoAtom = atom<FileDragInfo | null>(null)
2025-10-18 19:55:14 +00:00
export function DirectoryPathBreadcrumb({
directory,
2025-10-05 15:01:55 +00:00
rootLabel,
directoryUrlFn,
fileDragInfoAtom = nullFileDragInfoAtom,
2025-10-05 15:01:55 +00:00
}: {
directory: DirectoryInfoWithPath
2025-10-05 15:01:55 +00:00
rootLabel: string
directoryUrlFn: (directoryId: string) => string
fileDragInfoAtom?: PrimitiveAtom<FileDragInfo | null>
2025-10-05 15:01:55 +00:00
}) {
if (directory.path.length === 1) {
return (
<Breadcrumb>
<BreadcrumbList>
<BreadcrumbItem>
<BreadcrumbPage>{rootLabel}</BreadcrumbPage>
</BreadcrumbItem>
<BreadcrumbSeparator />
</BreadcrumbList>
</Breadcrumb>
)
}
2025-10-18 19:55:14 +00:00
const breadcrumbItems: React.ReactNode[] = [
<FilePathBreadcrumbItem
key={directory.path[0]!.id}
segment={directory.path[0]!}
label={rootLabel}
2025-10-18 19:55:14 +00:00
directoryUrlFn={directoryUrlFn}
fileDragInfoAtom={fileDragInfoAtom}
/>,
]
2025-10-03 23:23:05 +00:00
for (let i = 1; i < directory.path.length - 1; i++) {
breadcrumbItems.push(
<Fragment key={directory.path[i]!.id}>
2025-10-03 23:23:05 +00:00
<BreadcrumbSeparator />
<FilePathBreadcrumbItem
segment={directory.path[i]!}
2025-10-05 15:01:55 +00:00
directoryUrlFn={directoryUrlFn}
2025-10-18 19:55:14 +00:00
fileDragInfoAtom={fileDragInfoAtom}
/>
2025-10-03 23:23:05 +00:00
</Fragment>,
)
}
return (
<Breadcrumb>
<BreadcrumbList>
{breadcrumbItems}
<BreadcrumbSeparator />
<BreadcrumbItem>
<BreadcrumbPage>{directory.name}</BreadcrumbPage>{" "}
</BreadcrumbItem>
</BreadcrumbList>
</Breadcrumb>
)
}
function FilePathBreadcrumbItem({
segment,
label,
2025-10-05 15:01:55 +00:00
directoryUrlFn,
2025-10-18 19:55:14 +00:00
fileDragInfoAtom,
}: {
segment: PathSegment
label?: string
directoryUrlFn: (directoryId: string) => string
2025-10-18 19:55:14 +00:00
fileDragInfoAtom: PrimitiveAtom<FileDragInfo | null>
}) {
2025-10-03 23:23:05 +00:00
const { isDraggedOver, dropHandlers } = useFileDrop({
destDir: segment.id,
2025-10-18 19:55:14 +00:00
dragInfoAtom: fileDragInfoAtom,
enabled: true,
2025-10-03 23:23:05 +00:00
})
const dirName = label || segment.name
2025-10-03 23:23:05 +00:00
return (
<Tooltip open={isDraggedOver}>
<TooltipTrigger asChild>
<BreadcrumbItem
className={cn({ "bg-muted": isDraggedOver })}
{...dropHandlers}
>
<BreadcrumbLink asChild>
<Link to={directoryUrlFn(segment.id)}>{dirName}</Link>
2025-10-03 23:23:05 +00:00
</BreadcrumbLink>
</BreadcrumbItem>
</TooltipTrigger>
<TooltipContent>Move to {dirName}</TooltipContent>
</Tooltip>
)
}