- Updated .env.example to include configuration for OnlyOffice Document Server. - Modified the workspace configuration to remove the drive-suite path. - Adjusted TypeScript environment imports for consistency. - Enhanced Next.js configuration to disable canvas in Webpack. - Updated package.json to include new dependencies for OnlyOffice and PDF.js. - Added global styles for OnlyOffice theme integration in the CSS. - Created new layout and page components for the Drive feature, including public sharing and editing functionalities. - Updated metadata handling across various layouts to reflect the new app structure.
108 lines
3.2 KiB
TypeScript
108 lines
3.2 KiB
TypeScript
"use client"
|
|
|
|
import { useCallback, useEffect } from "react"
|
|
import type { DriveFileInfo } from "@/lib/api/types"
|
|
import { isFromDriveMenu, isCardOpenSuppressed } from "@/lib/drive/drive-menu-guard"
|
|
import { useDriveUIStore } from "@/lib/stores/drive-ui-store"
|
|
|
|
export function useDriveGridSelection(items: DriveFileInfo[], enabled: boolean) {
|
|
const selectedPaths = useDriveUIStore((s) => s.selectedPaths)
|
|
const selectionAnchorPath = useDriveUIStore((s) => s.selectionAnchorPath)
|
|
const setSelectedPaths = useDriveUIStore((s) => s.setSelectedPaths)
|
|
const setSelectionAnchor = useDriveUIStore((s) => s.setSelectionAnchor)
|
|
const clearSelection = useDriveUIStore((s) => s.clearSelection)
|
|
const toggleSelect = useDriveUIStore((s) => s.toggleSelect)
|
|
|
|
const orderedPaths = items.map((i) => i.path)
|
|
|
|
const selectOnly = useCallback(
|
|
(path: string) => {
|
|
setSelectedPaths([path])
|
|
setSelectionAnchor(path)
|
|
},
|
|
[setSelectedPaths, setSelectionAnchor]
|
|
)
|
|
|
|
const selectRangeTo = useCallback(
|
|
(path: string) => {
|
|
const anchor = selectionAnchorPath ?? path
|
|
const from = orderedPaths.indexOf(anchor)
|
|
const to = orderedPaths.indexOf(path)
|
|
if (from < 0 || to < 0) {
|
|
selectOnly(path)
|
|
return
|
|
}
|
|
const lo = Math.min(from, to)
|
|
const hi = Math.max(from, to)
|
|
setSelectedPaths(orderedPaths.slice(lo, hi + 1))
|
|
},
|
|
[orderedPaths, selectOnly, selectionAnchorPath, setSelectedPaths]
|
|
)
|
|
|
|
const handleItemClick = useCallback(
|
|
(file: DriveFileInfo, e: React.MouseEvent) => {
|
|
if (isFromDriveMenu(e.target) || isCardOpenSuppressed()) {
|
|
e.stopPropagation()
|
|
e.preventDefault()
|
|
return
|
|
}
|
|
if (e.shiftKey) {
|
|
e.preventDefault()
|
|
selectRangeTo(file.path)
|
|
setSelectionAnchor(file.path)
|
|
return
|
|
}
|
|
if (e.ctrlKey || e.metaKey) {
|
|
e.preventDefault()
|
|
toggleSelect(file.path, !selectedPaths.has(file.path))
|
|
setSelectionAnchor(file.path)
|
|
return
|
|
}
|
|
selectOnly(file.path)
|
|
},
|
|
[
|
|
selectOnly,
|
|
selectRangeTo,
|
|
selectedPaths,
|
|
setSelectionAnchor,
|
|
toggleSelect,
|
|
]
|
|
)
|
|
|
|
const selectAll = useCallback(() => {
|
|
setSelectedPaths(orderedPaths)
|
|
if (orderedPaths[0]) setSelectionAnchor(orderedPaths[0])
|
|
}, [orderedPaths, setSelectedPaths, setSelectionAnchor])
|
|
|
|
useEffect(() => {
|
|
if (!enabled) return
|
|
const onKeyDown = (e: KeyboardEvent) => {
|
|
if (!(e.ctrlKey || e.metaKey) || e.key.toLowerCase() !== "a") return
|
|
const target = e.target as HTMLElement | null
|
|
if (!target) return
|
|
if (
|
|
target.closest(
|
|
'input, textarea, select, [contenteditable="true"], [data-drive-search], [data-drive-header]'
|
|
)
|
|
) {
|
|
return
|
|
}
|
|
if (!target.closest("[data-drive-marquee-surface], [data-drive-browser-main]")) {
|
|
return
|
|
}
|
|
e.preventDefault()
|
|
selectAll()
|
|
}
|
|
window.addEventListener("keydown", onKeyDown)
|
|
return () => window.removeEventListener("keydown", onKeyDown)
|
|
}, [enabled, selectAll])
|
|
|
|
return {
|
|
selectedPaths,
|
|
selectOnly,
|
|
handleItemClick,
|
|
selectAll,
|
|
clearSelection,
|
|
}
|
|
}
|