feat: Introduce PreviewContext and document a new spatial workspace architecture.

This commit is contained in:
2025-11-27 01:14:18 +01:00
parent 9ba581f64e
commit 82243b4170
6 changed files with 131 additions and 144 deletions
@@ -1,4 +1,4 @@
import React, { useCallback, useEffect, useMemo, useRef, useState } from 'react';
import React, { useCallback, useEffect, useMemo, useRef } from 'react';
import { DocumentsList, DocumentsGrid } from '../DocumentsView';
import type { DragEvent, ReactNode, RefObject } from 'react';
import type {
@@ -10,7 +10,7 @@ import type {
} from '../../types/documents';
import DesktopWorkspace from '../../desktop/DesktopWorkspace';
import { isTagTransferEvent } from '../tagTransfer';
import PreviewZoomOverlay from '../../detail/PreviewZoomOverlay';
import { usePreviewContext } from '../../preview/PreviewContext';
import { isPointerModifierEvent, isPrimaryPointerEvent } from '../useEntryPointer';
import {
WorkspaceSelectionProvider,
@@ -109,7 +109,6 @@ const DocumentsPanelInner: React.FC<DocumentsPanelInnerProps> = ({
isSearchLoading = false,
viewMode = 'list',
onViewModeChange,
ensureDownloadUrl,
onRefresh = () => { },
sortField,
sortDirection,
@@ -317,73 +316,7 @@ const DocumentsPanelInner: React.FC<DocumentsPanelInnerProps> = ({
const isDeskView = viewMode === 'desk';
const gridIconSize = DEFAULT_GRID_ICON_SIZE;
const [previewDoc, setPreviewDoc] = useState<Document | null>(null);
useEffect(() => {
if (previewDoc && !rows.find(d => d.id === previewDoc.id)) {
setPreviewDoc(null);
}
}, [previewDoc, rows]);
const [previewUrl, setPreviewUrl] = useState<string | null>(null);
const overlayDocument = useMemo(() => {
if (!previewDoc || !previewUrl) {
return previewDoc;
}
return {
...previewDoc,
documentLink: {
url: previewUrl,
alt: previewDoc.title,
mimeType: previewDoc.mime_type,
},
};
}, [previewDoc, previewUrl]);
useEffect(() => {
if (!previewDoc) {
setPreviewUrl(null);
return;
}
let cancelled = false;
if (ensureDownloadUrl) {
ensureDownloadUrl(previewDoc.id)
.then((entry) => {
if (!cancelled && entry?.url) {
setPreviewUrl(entry.url);
}
})
.catch(() => {
if (!cancelled) {
setPreviewUrl(null);
}
});
}
return () => {
cancelled = true;
};
}, [previewDoc, ensureDownloadUrl]);
const closePreviewOverlay = useCallback(() => {
setPreviewDoc(null);
setPreviewUrl(null);
}, []);
const handleDocumentPreviewZoom = useCallback(
(doc) => {
if (!doc || !doc.id) {
return;
}
if (!ensureDownloadUrl) {
return;
}
setPreviewDoc(doc);
},
[ensureDownloadUrl],
);
const { openPreview } = usePreviewContext();
const isTagDragEvent = useCallback((event) => isTagTransferEvent(event), []);
@@ -431,17 +364,15 @@ const DocumentsPanelInner: React.FC<DocumentsPanelInnerProps> = ({
if (!doc) {
return;
}
if (event) {
event.preventDefault();
event.stopPropagation();
}
if (event?.altKey) {
handleDocumentPreviewZoom(doc);
if (event && (event.altKey || (event.button === 1))) {
openPreview(doc);
return;
}
onDocumentActivate?.(doc.id);
if (onDocumentActivate) {
onDocumentActivate(doc);
}
},
[handleDocumentPreviewZoom, onDocumentActivate],
[onDocumentActivate, openPreview],
);
const handleFolderClick = useCallback(
@@ -521,7 +452,6 @@ const DocumentsPanelInner: React.FC<DocumentsPanelInnerProps> = ({
onCorrespondentClick: toggleCorrespondentFilter,
tenantId: currentTenantId,
viewId,
onPreview: handleDocumentPreviewZoom,
};
const renderBody = () => {
@@ -578,11 +508,6 @@ const DocumentsPanelInner: React.FC<DocumentsPanelInnerProps> = ({
>
{renderBody()}
</section>
<PreviewZoomOverlay
open={Boolean(previewUrl)}
onClose={closePreviewOverlay}
document={overlayDocument}
/>
</>
);
};