ultisuite-client/lib/stores/drive-ui-store.ts
R3D347HR4Y 6ec95262af Add OnlyOffice integration and update project configurations
- 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.
2026-06-07 15:49:21 +02:00

160 lines
5.4 KiB
TypeScript

"use client"
import { create } from "zustand"
import type { DriveDragItem } from "@/lib/drive/drive-dnd"
export interface DrivePreviewTarget {
path: string
name: string
mime_type: string
is_favorite: boolean
mailAttachmentId?: string
mailMessageId?: string
}
export interface DrivePreviewContext {
allowShare: boolean
isTrash: boolean
publicShare?: { token: string; password?: string; canEdit: boolean }
mailSource?: boolean
mailMessageId?: string
}
interface DriveUIState {
sidebarCollapsed: boolean
selectedPaths: Set<string>
selectionAnchorPath: string | null
expandedSidebarPaths: Set<string>
sharePath: string | null
shareItemType: "file" | "directory" | null
previewFiles: DrivePreviewTarget[]
previewIndex: number
previewContext: DrivePreviewContext | null
/** Ignore grid card open clicks until this timestamp (menu dropdown ghost click). */
suppressCardOpenUntil: number
draggingItems: DriveDragItem[] | null
/** Multi-select mode on xs/sm — tap toggles selection instead of opening. */
selectionMode: boolean
setSelectionMode: (v: boolean) => void
enterSelectionMode: (path: string) => void
setSidebarCollapsed: (v: boolean) => void
blockCardOpen: (ms?: number) => void
toggleSelect: (path: string, selected: boolean) => void
setSelectedPaths: (paths: Iterable<string>) => void
setSelectionAnchor: (path: string | null) => void
clearSelection: () => void
setDraggingItems: (items: DriveDragItem[] | null) => void
toggleSidebarPath: (path: string) => void
ensureSidebarPathsExpanded: (paths: string[]) => void
setSharePath: (path: string | null, itemType?: "file" | "directory" | null) => void
openPreview: (
files: DrivePreviewTarget[],
index: number,
context?: Partial<DrivePreviewContext>
) => void
closePreview: () => void
stepPreview: (delta: number) => void
updatePreviewFavorite: (path: string, favorite: boolean) => void
removePreviewFile: (path: string) => void
}
export const useDriveUIStore = create<DriveUIState>((set, get) => ({
sidebarCollapsed: false,
selectionMode: false,
selectedPaths: new Set(),
selectionAnchorPath: null,
expandedSidebarPaths: new Set(["/", "/__shared_root__"]),
sharePath: null,
shareItemType: null,
previewFiles: [],
previewIndex: -1,
previewContext: null,
suppressCardOpenUntil: 0,
draggingItems: null,
setSidebarCollapsed: (sidebarCollapsed) => set({ sidebarCollapsed }),
setSelectionMode: (selectionMode) => set({ selectionMode }),
enterSelectionMode: (path) =>
set({
selectionMode: true,
selectedPaths: new Set([path]),
selectionAnchorPath: path,
}),
blockCardOpen: (ms = 700) =>
set({ suppressCardOpenUntil: Date.now() + ms }),
toggleSelect: (path, selected) => {
const next = new Set(get().selectedPaths)
if (selected) next.add(path)
else next.delete(path)
set({ selectedPaths: next })
},
setSelectedPaths: (paths) => set({ selectedPaths: new Set(paths) }),
setSelectionAnchor: (selectionAnchorPath) => set({ selectionAnchorPath }),
clearSelection: () =>
set({ selectedPaths: new Set(), selectionAnchorPath: null, selectionMode: false }),
setDraggingItems: (draggingItems) => set({ draggingItems }),
toggleSidebarPath: (path) => {
const next = new Set(get().expandedSidebarPaths)
if (next.has(path)) next.delete(path)
else next.add(path)
set({ expandedSidebarPaths: next })
},
ensureSidebarPathsExpanded: (paths) => {
const next = new Set(get().expandedSidebarPaths)
let changed = false
for (const path of paths) {
if (!next.has(path)) {
next.add(path)
changed = true
}
}
if (changed) set({ expandedSidebarPaths: next })
},
setSharePath: (sharePath, shareItemType = null) => set({ sharePath, shareItemType }),
openPreview: (previewFiles, previewIndex, context) =>
set({
previewFiles,
previewIndex,
previewContext: {
allowShare: context?.allowShare ?? true,
isTrash: context?.isTrash ?? false,
publicShare: context?.publicShare,
mailSource: context?.mailSource ?? false,
mailMessageId: context?.mailMessageId,
},
}),
closePreview: () => set({ previewFiles: [], previewIndex: -1, previewContext: null }),
stepPreview: (delta) => {
const { previewFiles, previewIndex } = get()
if (previewFiles.length === 0) return
const next = previewIndex + delta
if (next < 0 || next >= previewFiles.length) return
set({ previewIndex: next })
},
updatePreviewFavorite: (path, favorite) =>
set({
previewFiles: get().previewFiles.map((f) =>
f.path === path ? { ...f, is_favorite: favorite } : f
),
}),
removePreviewFile: (path) => {
const { previewFiles, previewIndex } = get()
const idx = previewFiles.findIndex((f) => f.path === path)
if (idx < 0) return
const next = previewFiles.filter((f) => f.path !== path)
if (next.length === 0) {
set({ previewFiles: [], previewIndex: -1, previewContext: null })
return
}
let newIndex = previewIndex
if (idx < previewIndex) newIndex = previewIndex - 1
else if (idx === previewIndex) newIndex = Math.min(previewIndex, next.length - 1)
set({ previewFiles: next, previewIndex: newIndex })
},
}))
export function usePreviewFile() {
const files = useDriveUIStore((s) => s.previewFiles)
const index = useDriveUIStore((s) => s.previewIndex)
return index >= 0 ? (files[index] ?? null) : null
}