"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 selectionAnchorPath: string | null expandedSidebarPaths: Set 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) => 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 ) => void closePreview: () => void stepPreview: (delta: number) => void updatePreviewFavorite: (path: string, favorite: boolean) => void removePreviewFile: (path: string) => void } export const useDriveUIStore = create((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 }