Some checks are pending
E2E / Playwright e2e (push) Waiting to run
- Introduced turbopack alias for canvas in next.config.mjs. - Updated package.json scripts for development and branding tasks. - Added new dependencies for Tiptap extensions. - Implemented new demo layouts for agenda, contacts, drive, and mail applications. - Enhanced globals.css for improved theming and splash screen animations. - Added OAuth callback handling for drive mounts. - Updated layout components to integrate new demo shells and improve structure.
173 lines
5.7 KiB
TypeScript
173 lines
5.7 KiB
TypeScript
"use client"
|
|
|
|
import { useRouter } from "next/navigation"
|
|
import { FileThumbnail } from "@/components/drive/file-thumbnail"
|
|
import { DriveGridView } from "@/components/drive/drive-grid-view"
|
|
import { DriveListModified } from "@/components/drive/drive-list-modified"
|
|
import { DriveFileContextMenu } from "@/components/drive/drive-file-context-menu"
|
|
import type { DriveFileInfo } from "@/lib/api/types"
|
|
import { useDriveSettingsStore } from "@/lib/stores/drive-settings-store"
|
|
import { openDriveItem } from "@/lib/drive/drive-open-item"
|
|
import { useDriveMutations } from "@/lib/api/hooks/use-drive-queries"
|
|
import { pathRefFromRoute, type DrivePathRef } from "@/lib/api/drive-roots"
|
|
import type { DriveView } from "@/lib/drive/drive-url"
|
|
import type { PublicShareThumbContext } from "@/lib/api/hooks/use-public-share-preview-thumb"
|
|
import { useDriveUIStore } from "@/lib/stores/drive-ui-store"
|
|
import {
|
|
displayFileBaseName,
|
|
displayFileFormatLabel,
|
|
} from "@/lib/drive/display-file-name"
|
|
import { useDriveGridSelection } from "@/lib/hooks/use-drive-grid-selection"
|
|
import { DRIVE_CARD_PAD_X } from "@/lib/drive/drive-chrome-classes"
|
|
import { useDriveRouteRoot } from "@/lib/drive/drive-route-context"
|
|
import { cn } from "@/lib/utils"
|
|
|
|
function formatSize(n: number) {
|
|
if (n < 1024) return `${n} o`
|
|
if (n < 1024 ** 2) return `${(n / 1024).toFixed(1)} Ko`
|
|
return `${(n / 1024 ** 2).toFixed(1)} Mo`
|
|
}
|
|
|
|
export function FileBrowser({
|
|
items,
|
|
view = "files",
|
|
rootId,
|
|
pathRef: pathRefProp,
|
|
isTrash,
|
|
onOpenItem,
|
|
mutations: mutationsProp,
|
|
allowShare: allowShareProp,
|
|
writable = true,
|
|
hideFavorite = false,
|
|
disableDnd = false,
|
|
onDownloadItem,
|
|
gridClassName,
|
|
publicShare,
|
|
}: {
|
|
items: DriveFileInfo[]
|
|
view?: DriveView
|
|
rootId?: string | null
|
|
pathRef?: DrivePathRef
|
|
isTrash?: boolean
|
|
onOpenItem?: (file: DriveFileInfo) => void
|
|
mutations?: ReturnType<typeof useDriveMutations>
|
|
allowShare?: boolean
|
|
writable?: boolean
|
|
hideFavorite?: boolean
|
|
disableDnd?: boolean
|
|
onDownloadItem?: (file: DriveFileInfo) => void
|
|
gridClassName?: string
|
|
publicShare?: PublicShareThumbContext
|
|
}) {
|
|
const router = useRouter()
|
|
const routeRoot = useDriveRouteRoot()
|
|
const viewMode = useDriveSettingsStore((s) => s.viewMode)
|
|
const openPreview = useDriveUIStore((s) => s.openPreview)
|
|
const pathRef = pathRefProp ?? pathRefFromRoute(view, rootId ?? null, "/")
|
|
const mutationsDefault = useDriveMutations(pathRef)
|
|
const mutations = mutationsProp ?? mutationsDefault
|
|
|
|
const openItem = (file: DriveFileInfo) => {
|
|
if (onOpenItem) {
|
|
onOpenItem(file)
|
|
return
|
|
}
|
|
openDriveItem(file, {
|
|
router,
|
|
openPreview,
|
|
view,
|
|
contextItems: items,
|
|
isTrash: Boolean(isTrash),
|
|
routeRoot,
|
|
})
|
|
}
|
|
|
|
const allowShare = allowShareProp ?? view !== "shared"
|
|
const { handleItemClick } = useDriveGridSelection(items, true)
|
|
|
|
if (viewMode === "grid") {
|
|
return (
|
|
<DriveGridView
|
|
items={items}
|
|
isTrash={isTrash}
|
|
inSharedView={view === "shared"}
|
|
allowShare={allowShare}
|
|
writable={writable}
|
|
hideFavorite={hideFavorite}
|
|
disableDnd={disableDnd}
|
|
mutations={mutations}
|
|
onDownloadItem={onDownloadItem}
|
|
gridClassName={gridClassName}
|
|
publicShare={publicShare}
|
|
onOpen={openItem}
|
|
onItemClick={handleItemClick}
|
|
/>
|
|
)
|
|
}
|
|
|
|
return (
|
|
<div>
|
|
<div
|
|
className={cn(
|
|
"sticky top-0 z-10 hidden items-center gap-3 border-b border-border bg-mail-surface py-2 text-xs font-medium text-muted-foreground sm:flex",
|
|
DRIVE_CARD_PAD_X
|
|
)}
|
|
aria-hidden
|
|
>
|
|
<span className="size-10 shrink-0" />
|
|
<span className="min-w-0 flex-1">Nom</span>
|
|
<span className="hidden w-16 shrink-0 text-right sm:block">Type</span>
|
|
<span className="hidden w-20 shrink-0 text-right sm:block">Taille</span>
|
|
<span className="hidden w-36 shrink-0 text-right md:block">Modifié</span>
|
|
</div>
|
|
<div className="divide-y divide-border">
|
|
{items.map((file) => (
|
|
<DriveFileContextMenu
|
|
key={file.path}
|
|
file={file}
|
|
allItems={items}
|
|
isTrash={isTrash}
|
|
allowShare={allowShare}
|
|
writable={writable}
|
|
hideFavorite={hideFavorite}
|
|
disableDnd={disableDnd}
|
|
mutations={mutations}
|
|
onDownloadRequest={
|
|
onDownloadItem ? () => onDownloadItem(file) : undefined
|
|
}
|
|
onOpen={() => openItem(file)}
|
|
onItemClick={handleItemClick}
|
|
>
|
|
<div
|
|
className={cn(
|
|
"flex w-full cursor-pointer items-center gap-3 py-2.5 text-left hover:bg-accent/50",
|
|
DRIVE_CARD_PAD_X
|
|
)}
|
|
>
|
|
<FileThumbnail
|
|
file={file}
|
|
variant="list"
|
|
inSharedView={view === "shared"}
|
|
publicShare={publicShare}
|
|
/>
|
|
<span className="min-w-0 flex-1 truncate font-medium text-[#3c4043] dark:text-[#e8eaed]">
|
|
{displayFileBaseName(file.name, file.type === "directory")}
|
|
</span>
|
|
<span className="hidden w-16 shrink-0 truncate text-right text-sm text-muted-foreground sm:block">
|
|
{displayFileFormatLabel(file.name, file.type === "directory")}
|
|
</span>
|
|
<span className="hidden w-20 shrink-0 text-right text-sm text-muted-foreground sm:block">
|
|
{file.type === "directory" ? "—" : formatSize(file.size)}
|
|
</span>
|
|
<DriveListModified
|
|
iso={file.last_modified}
|
|
className="hidden w-36 shrink-0 truncate text-right md:block"
|
|
/>
|
|
</div>
|
|
</DriveFileContextMenu>
|
|
))}
|
|
</div>
|
|
</div>
|
|
)
|
|
}
|