feat: Remove documentLink prop and onNavigatorSnapshot logic, and add openDetailPanel and closeDetailPanel to document shell.
This commit is contained in:
@@ -1,5 +1,5 @@
|
||||
import React, { useCallback, useEffect, useMemo } from 'react';
|
||||
import type { ReactNode } from 'react';
|
||||
import type { ReactNode, ComponentProps } from 'react';
|
||||
import { useNavigate } from 'react-router-dom';
|
||||
import {
|
||||
DocumentsFilterProvider,
|
||||
@@ -13,25 +13,24 @@ import { PanelManagerProvider, usePanelManager } from './PanelManagerContext';
|
||||
import Sidebar from '../sidebar/Sidebar';
|
||||
import useDocumentsShell from './useDocumentsShell';
|
||||
|
||||
const DocumentsRouteContent: React.FC = () => {
|
||||
const {
|
||||
sidebarProps,
|
||||
surfaceConfig,
|
||||
documentsFilter,
|
||||
} = useDocumentsShell();
|
||||
const navigate = useNavigate();
|
||||
const DocumentsInner: React.FC<{
|
||||
sidebarProps: ComponentProps<typeof Sidebar> | null;
|
||||
surfaceConfig: any;
|
||||
onNavigate: (documentId: string) => void;
|
||||
}> = ({ sidebarProps, surfaceConfig, onNavigate }) => {
|
||||
const { openPreview } = usePreviewContext();
|
||||
const { collapsed: sidebarCollapsed } = useSidebarContext();
|
||||
const {
|
||||
sidebarSuppressed,
|
||||
expandSidebar,
|
||||
openDetailPanel,
|
||||
} = usePanelManager();
|
||||
|
||||
const { openPreview } = usePreviewContext();
|
||||
|
||||
const { openDetailPanel } = surfaceConfig;
|
||||
const sidebarHidden = sidebarCollapsed || sidebarSuppressed;
|
||||
|
||||
const handleHeaderBreadcrumbClick = useCallback((crumb: DocumentsHeaderBreadcrumb) => {
|
||||
const navigate = useNavigate();
|
||||
|
||||
const handleBreadcrumbNavigate = useCallback((crumb: DocumentsHeaderBreadcrumb) => {
|
||||
if (!crumb || !crumb.id) {
|
||||
return;
|
||||
}
|
||||
@@ -39,10 +38,6 @@ const DocumentsRouteContent: React.FC = () => {
|
||||
navigate(target);
|
||||
}, [navigate]);
|
||||
|
||||
const handleDocumentNavigate = useCallback((documentId: string) => {
|
||||
navigate(`/documents/${documentId}`);
|
||||
}, [navigate]);
|
||||
|
||||
const handleOpenSidepanel = useCallback((docId: string) => {
|
||||
if (openDetailPanel) {
|
||||
openDetailPanel({ documentIds: [docId] });
|
||||
@@ -51,9 +46,9 @@ const DocumentsRouteContent: React.FC = () => {
|
||||
|
||||
const documentsTablePropsWithNav = useMemo(() => (
|
||||
surfaceConfig.documentsTableProps
|
||||
? { ...surfaceConfig.documentsTableProps, onBreadcrumbNavigate: handleHeaderBreadcrumbClick }
|
||||
? { ...surfaceConfig.documentsTableProps, onBreadcrumbNavigate: handleBreadcrumbNavigate }
|
||||
: null
|
||||
), [surfaceConfig.documentsTableProps, handleHeaderBreadcrumbClick]);
|
||||
), [surfaceConfig.documentsTableProps, handleBreadcrumbNavigate]);
|
||||
|
||||
const { surface } = useWorkspaceSurface({
|
||||
sidebarHidden,
|
||||
@@ -87,30 +82,58 @@ const DocumentsRouteContent: React.FC = () => {
|
||||
);
|
||||
};
|
||||
|
||||
const content = renderSurface();
|
||||
return (
|
||||
<DocumentOpenProvider
|
||||
onOpenViewer={onNavigate}
|
||||
onOpenPreview={openPreview}
|
||||
onOpenSidepanel={handleOpenSidepanel}
|
||||
>
|
||||
{renderSurface()}
|
||||
</DocumentOpenProvider>
|
||||
);
|
||||
};
|
||||
|
||||
const DocumentsRouteContent: React.FC = () => {
|
||||
const {
|
||||
sidebarProps,
|
||||
surfaceConfig,
|
||||
documentsFilter,
|
||||
} = useDocumentsShell();
|
||||
const navigate = useNavigate();
|
||||
|
||||
const handleDocumentNavigate = useCallback((documentId: string) => {
|
||||
navigate(`/documents/${documentId}`);
|
||||
}, [navigate]);
|
||||
|
||||
return (
|
||||
<DocumentsFilterProvider value={documentsFilter}>
|
||||
<PreviewProvider
|
||||
onNavigate={handleDocumentNavigate}
|
||||
>
|
||||
<DocumentOpenProvider
|
||||
onOpenViewer={handleDocumentNavigate}
|
||||
onOpenPreview={openPreview}
|
||||
onOpenSidepanel={handleOpenSidepanel}
|
||||
>
|
||||
{content}
|
||||
</DocumentOpenProvider>
|
||||
<DocumentsInner
|
||||
sidebarProps={sidebarProps}
|
||||
surfaceConfig={surfaceConfig}
|
||||
onNavigate={handleDocumentNavigate}
|
||||
/>
|
||||
</PreviewProvider>
|
||||
</DocumentsFilterProvider>
|
||||
);
|
||||
};
|
||||
|
||||
const DocumentsRoute: React.FC = () => (
|
||||
<SidebarProvider>
|
||||
<PanelManagerProvider>
|
||||
<DocumentsRouteContent />
|
||||
</PanelManagerProvider>
|
||||
</SidebarProvider>
|
||||
);
|
||||
const DocumentsRoute: React.FC = () => {
|
||||
const { surfaceConfig } = useDocumentsShell();
|
||||
const { detailPanelOpen, closeDetailPanel } = surfaceConfig;
|
||||
|
||||
return (
|
||||
<SidebarProvider>
|
||||
<PanelManagerProvider
|
||||
isOpen={detailPanelOpen}
|
||||
onClose={closeDetailPanel}
|
||||
>
|
||||
<DocumentsRouteContent />
|
||||
</PanelManagerProvider>
|
||||
</SidebarProvider>
|
||||
);
|
||||
};
|
||||
|
||||
export default DocumentsRoute;
|
||||
|
||||
@@ -89,9 +89,11 @@ const applyPanelWidthToRoot = (panel: PanelKey, width: number, active: boolean):
|
||||
|
||||
interface PanelManagerProviderProps {
|
||||
children: ReactNode;
|
||||
isOpen?: boolean;
|
||||
onClose?: () => void;
|
||||
}
|
||||
|
||||
export const PanelManagerProvider: React.FC<PanelManagerProviderProps> = ({ children }) => {
|
||||
export const PanelManagerProvider: React.FC<PanelManagerProviderProps> = ({ children, isOpen, onClose }) => {
|
||||
const { collapsed, setCollapsed } = useSidebarContext();
|
||||
const initialSidebarWidth = readStoredWidth('sidebar', DEFAULT_SIDEBAR_WIDTH);
|
||||
const initialDetailWidth = readStoredWidth('detail', DEFAULT_DETAIL_WIDTH);
|
||||
@@ -100,7 +102,13 @@ export const PanelManagerProvider: React.FC<PanelManagerProviderProps> = ({ chil
|
||||
const [detailWidth, setDetailWidthState] = useState(() => clampPanelWidth('detail', initialDetailWidth));
|
||||
const [resizingPanel, setResizingPanel] = useState(null);
|
||||
const [sidebarSuppressed, setSidebarSuppressed] = useState(false);
|
||||
const [detailPanelOpen, setDetailPanelOpen] = useState(false);
|
||||
const [detailPanelOpen, setDetailPanelOpen] = useState(Boolean(isOpen));
|
||||
|
||||
useEffect(() => {
|
||||
if (isOpen !== undefined) {
|
||||
setDetailPanelOpen(isOpen);
|
||||
}
|
||||
}, [isOpen]);
|
||||
|
||||
const detailCloseHandlerRef = useRef(null);
|
||||
const panelWidthsRef = useRef({ sidebar: sidebarWidth, detail: detailWidth });
|
||||
@@ -109,7 +117,11 @@ export const PanelManagerProvider: React.FC<PanelManagerProviderProps> = ({ chil
|
||||
const closeDetailPanel = useCallback(() => {
|
||||
const handler = detailCloseHandlerRef.current;
|
||||
handler?.();
|
||||
}, []);
|
||||
onClose?.();
|
||||
if (isOpen === undefined) {
|
||||
setDetailPanelOpen(false);
|
||||
}
|
||||
}, [onClose, isOpen]);
|
||||
|
||||
useEffect(() => {
|
||||
panelWidthsRef.current.sidebar = sidebarWidth;
|
||||
@@ -228,11 +240,16 @@ export const PanelManagerProvider: React.FC<PanelManagerProviderProps> = ({ chil
|
||||
}, []);
|
||||
|
||||
const setDetailActive = useCallback(
|
||||
(isOpen) => {
|
||||
setDetailPanelOpen(Boolean(isOpen));
|
||||
handlePanelLayoutChange('detail', isOpen ? 'opened' : 'closed');
|
||||
(active) => {
|
||||
if (isOpen === undefined) {
|
||||
setDetailPanelOpen(Boolean(active));
|
||||
}
|
||||
if (!active) {
|
||||
onClose?.();
|
||||
}
|
||||
handlePanelLayoutChange('detail', active ? 'opened' : 'closed');
|
||||
},
|
||||
[handlePanelLayoutChange],
|
||||
[handlePanelLayoutChange, isOpen, onClose],
|
||||
);
|
||||
|
||||
const expandSidebar = useCallback(() => {
|
||||
@@ -394,8 +411,8 @@ export const usePanelResizeBindings = (
|
||||
|
||||
const handleProps = enabled
|
||||
? {
|
||||
onPointerDown: handlePointerDown,
|
||||
}
|
||||
onPointerDown: handlePointerDown,
|
||||
}
|
||||
: {};
|
||||
|
||||
return {
|
||||
|
||||
@@ -6,7 +6,10 @@ import type Sidebar from '../sidebar/Sidebar';
|
||||
import type { UseWorkspaceSurfaceArgs } from './useWorkspaceSurface';
|
||||
import type { Identifier } from '../types/identifiers';
|
||||
|
||||
type WorkspaceSurfaceConfig = Omit<UseWorkspaceSurfaceArgs, 'sidebarHidden' | 'onExpandSidebar'>;
|
||||
type WorkspaceSurfaceConfig = Omit<UseWorkspaceSurfaceArgs, 'sidebarHidden' | 'onExpandSidebar'> & {
|
||||
openDetailPanel?: (args: { documentIds?: Identifier[] }) => void;
|
||||
closeDetailPanel?: () => void;
|
||||
};
|
||||
|
||||
interface DocumentsShellView {
|
||||
sidebarProps: ComponentProps<typeof Sidebar> | null;
|
||||
@@ -23,8 +26,9 @@ const useDocumentsShell = (): DocumentsShellView => {
|
||||
documentsTableProps: (shell.documentsTableProps ?? null) as WorkspaceSurfaceConfig['documentsTableProps'],
|
||||
detailPanelProps: (shell.detailPanelProps ?? null) as WorkspaceSurfaceConfig['detailPanelProps'],
|
||||
detailPanelOpen: Boolean(shell.detailPanelOpen),
|
||||
openDetailPanel: shell.openDetailPanel as WorkspaceSurfaceConfig['openDetailPanel'],
|
||||
closeDetailPanel: shell.closeDetailPanel as WorkspaceSurfaceConfig['closeDetailPanel'],
|
||||
previewWorkspaceDocument: shell.previewWorkspaceDocument,
|
||||
documentLink: shell.documentLink,
|
||||
previewDocumentId: (shell.previewDocumentId as Identifier | null | undefined) ?? null,
|
||||
closeDocumentPreview: shell.closeDocumentPreview as WorkspaceSurfaceConfig['closeDocumentPreview'],
|
||||
ensurePreviewData: shell.ensurePreviewData as WorkspaceSurfaceConfig['ensurePreviewData'],
|
||||
|
||||
@@ -36,7 +36,6 @@ export interface UseWorkspaceSurfaceArgs {
|
||||
detailPanelProps?: DetailPanelProps;
|
||||
detailPanelOpen?: boolean;
|
||||
previewWorkspaceDocument?: unknown;
|
||||
documentLink?: unknown;
|
||||
previewDocumentId?: Identifier | null;
|
||||
ensureAssetUrl?: EnsureAssetUrl;
|
||||
ensurePreviewData?: EnsurePreviewData;
|
||||
@@ -56,7 +55,6 @@ export const useWorkspaceSurface = ({
|
||||
detailPanelProps,
|
||||
detailPanelOpen = false,
|
||||
previewWorkspaceDocument,
|
||||
documentLink,
|
||||
previewDocumentId,
|
||||
ensureAssetUrl,
|
||||
ensurePreviewData,
|
||||
@@ -181,7 +179,6 @@ export const useWorkspaceSurface = ({
|
||||
const viewer = (
|
||||
<DocumentViewerPanel
|
||||
document={previewWorkspaceDocument || null}
|
||||
documentLink={documentLink}
|
||||
hydrateDocument={ensurePreviewData}
|
||||
tagLookupById={tagLookupById}
|
||||
tagOptions={tagOptions}
|
||||
@@ -214,7 +211,6 @@ export const useWorkspaceSurface = ({
|
||||
}, [
|
||||
showPreviewWorkspace,
|
||||
previewWorkspaceDocument,
|
||||
documentLink,
|
||||
ensurePreviewData,
|
||||
ensureAssetUrl,
|
||||
getDocumentAsset,
|
||||
|
||||
@@ -5,6 +5,7 @@ import { getTagColorStyle } from '../utils/colors';
|
||||
import type { DocumentId } from '../types/identifiers';
|
||||
import type { Document } from '../types/documents';
|
||||
import { LayoutCard } from './LayoutSystem';
|
||||
import { useCardPointer } from './useCardPointer';
|
||||
|
||||
const preventAll = (event?: React.SyntheticEvent | Event | null) => {
|
||||
if (!event) return;
|
||||
@@ -21,16 +22,18 @@ interface DesktopDocumentCardProps {
|
||||
docTagTokens?: string;
|
||||
ensureAssetUrl?: (...args: any[]) => Promise<unknown>;
|
||||
getDocumentAsset?: (...args: any[]) => unknown;
|
||||
handleNavigatorSnapshot?: (...args: any[]) => void;
|
||||
cardPointerHandlers?: React.HTMLAttributes<HTMLDivElement>;
|
||||
onDocumentActivate?: (id: string, event?: any) => void;
|
||||
onSelect: (ids: string[], extend?: boolean) => void;
|
||||
onDeselect: (ids: string[]) => void;
|
||||
selection: string[];
|
||||
requestCanvasFocus?: () => void;
|
||||
onTagDragEnter?: (event: React.DragEvent<HTMLDivElement>, docId: DocumentId) => void;
|
||||
onTagDragOver?: (event: React.DragEvent<HTMLDivElement>, docId: DocumentId) => void;
|
||||
onTagDragLeave?: (event: React.DragEvent<HTMLDivElement>, docId: DocumentId) => void;
|
||||
onTagDrop?: (event: React.DragEvent<HTMLDivElement>, doc: Document) => void;
|
||||
onDocTagDragStart?: (event: React.DragEvent<HTMLElement>, doc: Document, tag: any) => void;
|
||||
onDocTagDragEnd?: (event: React.DragEvent<HTMLElement>) => void;
|
||||
layoutCard?: LayoutCard;
|
||||
layoutCard: LayoutCard;
|
||||
}
|
||||
|
||||
const DesktopDocumentCard: React.FC<DesktopDocumentCardProps> = ({
|
||||
@@ -42,9 +45,11 @@ const DesktopDocumentCard: React.FC<DesktopDocumentCardProps> = ({
|
||||
docTagTokens,
|
||||
ensureAssetUrl,
|
||||
getDocumentAsset,
|
||||
handleNavigatorSnapshot,
|
||||
cardPointerHandlers,
|
||||
onDocumentActivate,
|
||||
onSelect,
|
||||
onDeselect,
|
||||
selection,
|
||||
requestCanvasFocus,
|
||||
onTagDragEnter,
|
||||
onTagDragOver,
|
||||
onTagDragLeave,
|
||||
@@ -53,6 +58,16 @@ const DesktopDocumentCard: React.FC<DesktopDocumentCardProps> = ({
|
||||
onDocTagDragEnd,
|
||||
layoutCard,
|
||||
}) => {
|
||||
const cardPointerHandlers = useCardPointer(
|
||||
layoutCard,
|
||||
!!selected,
|
||||
selection,
|
||||
onSelect,
|
||||
onDeselect,
|
||||
onDocumentActivate,
|
||||
requestCanvasFocus
|
||||
);
|
||||
|
||||
const correspondents = useMemo(() => resolveCorrespondents(doc), [doc]);
|
||||
const tags = Array.isArray(doc?.tags) ? doc.tags : [];
|
||||
|
||||
@@ -108,7 +123,6 @@ const DesktopDocumentCard: React.FC<DesktopDocumentCardProps> = ({
|
||||
title={doc.title}
|
||||
ensureAssetUrl={ensureAssetUrl}
|
||||
getDocumentAsset={getDocumentAsset}
|
||||
onNavigatorSnapshot={handleNavigatorSnapshot}
|
||||
shouldLoad={shouldLoad}
|
||||
/>
|
||||
{correspondents.length > 0 && (
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { useEffect, useMemo } from 'react';
|
||||
import { useMemo } from 'react';
|
||||
import type { JSX } from 'react';
|
||||
import { resolveDocumentAssetUrl } from '../asset_manager';
|
||||
import type { Identifier } from '../types/identifiers';
|
||||
@@ -14,19 +14,11 @@ type EnsureAssetUrl = (
|
||||
|
||||
type GetDocumentAsset = (document: Document | null, assetType: string) => Asset | null;
|
||||
|
||||
interface NavigatorSnapshot {
|
||||
url: string | null;
|
||||
alt?: string;
|
||||
width: number | null;
|
||||
height: number | null;
|
||||
}
|
||||
|
||||
interface DesktopPreviewCardProps {
|
||||
doc: Document | null;
|
||||
title?: string;
|
||||
ensureAssetUrl?: EnsureAssetUrl | null;
|
||||
getDocumentAsset?: GetDocumentAsset;
|
||||
onNavigatorSnapshot?: (docId: Identifier, snapshot: NavigatorSnapshot | null) => void;
|
||||
shouldLoad?: boolean;
|
||||
}
|
||||
|
||||
@@ -35,7 +27,6 @@ const DesktopPreviewCard = ({
|
||||
title,
|
||||
ensureAssetUrl,
|
||||
getDocumentAsset,
|
||||
onNavigatorSnapshot,
|
||||
shouldLoad = true,
|
||||
}: DesktopPreviewCardProps): JSX.Element => {
|
||||
const currentUrl = useMemo(() => {
|
||||
@@ -46,41 +37,6 @@ const DesktopPreviewCard = ({
|
||||
});
|
||||
}, [doc, ensureAssetUrl, getDocumentAsset, shouldLoad]);
|
||||
|
||||
const currentMetadata = useMemo(() => {
|
||||
if (!doc || !getDocumentAsset) return null;
|
||||
const asset = getDocumentAsset(doc, 'thumbnail');
|
||||
return asset?.metadata || null;
|
||||
}, [doc, getDocumentAsset]);
|
||||
const docId = doc?.id ?? null;
|
||||
|
||||
const metadataWidth = Number((currentMetadata as { width?: number } | null)?.width);
|
||||
const metadataHeight = Number((currentMetadata as { height?: number } | null)?.height);
|
||||
|
||||
useEffect(() => {
|
||||
if (!onNavigatorSnapshot || !docId) {
|
||||
return undefined;
|
||||
}
|
||||
if (!currentUrl) {
|
||||
onNavigatorSnapshot(docId, null);
|
||||
return undefined;
|
||||
}
|
||||
const snapshot = {
|
||||
url: currentUrl,
|
||||
alt: title,
|
||||
width: Number.isFinite(metadataWidth) && metadataWidth > 0 ? metadataWidth : null,
|
||||
height: Number.isFinite(metadataHeight) && metadataHeight > 0 ? metadataHeight : null,
|
||||
};
|
||||
onNavigatorSnapshot(docId, snapshot);
|
||||
return () => onNavigatorSnapshot(docId, null);
|
||||
}, [
|
||||
docId,
|
||||
currentUrl,
|
||||
title,
|
||||
metadataWidth,
|
||||
metadataHeight,
|
||||
onNavigatorSnapshot,
|
||||
]);
|
||||
|
||||
const hasPreview = Boolean(currentUrl);
|
||||
const cardClasses = ['desk-item__card'];
|
||||
if (!hasPreview) cardClasses.push('desk-item__card--empty');
|
||||
|
||||
@@ -9,7 +9,6 @@ import { LayoutStore, LayoutCard } from './LayoutSystem';
|
||||
import DesktopDocumentCard from './DesktopDocumentCard';
|
||||
import usePreviewMetadata from './hooks/usePreviewMetadata';
|
||||
import useDeskTagInteractions from './tags/useDeskTagInteractions';
|
||||
import { useCardPointer } from './useCardPointer';
|
||||
import '../styles/workspace/workspace-layout.css';
|
||||
import '../styles/workspace/workspace-items.css';
|
||||
import '../styles/workspace/workspace-cards.css';
|
||||
@@ -21,17 +20,6 @@ import type { DocumentsListEntry, Document } from '../types/documents';
|
||||
import { useAppState } from '../app/appState';
|
||||
import { useDocumentOpen } from '../contexts/DocumentOpenContext';
|
||||
|
||||
type TagLike = { id?: Identifier | null; label?: string; color?: string | null } | null;
|
||||
type OverlaySource = { url: string; alt?: string | null; mimeType?: string | null; };
|
||||
|
||||
export interface DeskDocument {
|
||||
id?: Identifier | null;
|
||||
title?: string;
|
||||
tags?: TagLike[] | null;
|
||||
documentLink?: OverlaySource | null;
|
||||
[key: string]: unknown;
|
||||
}
|
||||
|
||||
interface DocumentSizeInfo {
|
||||
width: number;
|
||||
height: number;
|
||||
@@ -39,7 +27,7 @@ interface DocumentSizeInfo {
|
||||
}
|
||||
|
||||
// Fallback size computation
|
||||
const computeFallbackCardSize = (_doc: DeskDocument, defaultSize: number = 200): DocumentSizeInfo => {
|
||||
const computeFallbackCardSize = (_doc: Document, defaultSize: number = 200): DocumentSizeInfo => {
|
||||
const size = Math.round(defaultSize * (1 / Math.SQRT2));
|
||||
return { width: size, height: size, source: 'fallback' };
|
||||
};
|
||||
@@ -55,29 +43,6 @@ export interface DesktopWorkspaceProps {
|
||||
defaultCardSize?: number;
|
||||
}
|
||||
|
||||
// Wrapper to handle hooks per card
|
||||
const DesktopDocumentContainer: React.FC<React.ComponentProps<typeof DesktopDocumentCard> & {
|
||||
onSelect: (ids: string[], extend?: boolean) => void;
|
||||
onDeselect: (ids: string[]) => void;
|
||||
onDocumentActivate?: (id: string, event?: any) => void;
|
||||
selection: string[];
|
||||
requestCanvasFocus?: () => void;
|
||||
}> = React.memo((props) => {
|
||||
const { layoutCard, selected, onSelect, onDeselect, onDocumentActivate, selection, requestCanvasFocus } = props;
|
||||
|
||||
// We assume layoutCard is always present in this context
|
||||
const cardPointerHandlers = useCardPointer(layoutCard!, !!selected, selection, onSelect, onDeselect, onDocumentActivate, requestCanvasFocus);
|
||||
|
||||
return (
|
||||
<DesktopDocumentCard
|
||||
{...props}
|
||||
cardPointerHandlers={cardPointerHandlers}
|
||||
/>
|
||||
);
|
||||
});
|
||||
|
||||
DesktopDocumentContainer.displayName = 'DesktopDocumentContainer';
|
||||
|
||||
const DesktopWorkspaceContent: React.FC<DesktopWorkspaceProps> = ({
|
||||
entries,
|
||||
ensureAssetUrl,
|
||||
@@ -102,7 +67,7 @@ const DesktopWorkspaceContent: React.FC<DesktopWorkspaceProps> = ({
|
||||
.filter((entry): entry is { type: 'document'; document: Document } & DocumentsListEntry =>
|
||||
entry.type === 'document' && !!entry.document
|
||||
)
|
||||
.map(entry => entry.document as DeskDocument);
|
||||
.map(entry => entry.document);
|
||||
}, [entries]);
|
||||
|
||||
// Layout System Initialization
|
||||
@@ -189,7 +154,7 @@ const DesktopWorkspaceContent: React.FC<DesktopWorkspaceProps> = ({
|
||||
|
||||
const metadataMap = usePreviewMetadata(items, getDocumentAsset, ensureAssetUrl);
|
||||
|
||||
const ensureDocumentSize = useCallback((doc: DeskDocument): DocumentSizeInfo => {
|
||||
const ensureDocumentSize = useCallback((doc: Document): DocumentSizeInfo => {
|
||||
if (doc.id) {
|
||||
const meta = metadataMap.get(String(doc.id));
|
||||
if (meta && meta.width && meta.height)
|
||||
@@ -404,7 +369,7 @@ const DesktopWorkspaceContent: React.FC<DesktopWorkspaceProps> = ({
|
||||
});
|
||||
|
||||
return (
|
||||
<DesktopDocumentContainer
|
||||
<DesktopDocumentCard
|
||||
key={docId}
|
||||
doc={doc}
|
||||
style={{
|
||||
@@ -421,7 +386,6 @@ const DesktopWorkspaceContent: React.FC<DesktopWorkspaceProps> = ({
|
||||
docTagTokens=""
|
||||
ensureAssetUrl={ensureAssetUrl}
|
||||
getDocumentAsset={getDocumentAsset}
|
||||
handleNavigatorSnapshot={() => { }}
|
||||
onDocumentActivate={(_id, event) => {
|
||||
const isPreview = event && ((event as any).altKey || (event as any).button === 1);
|
||||
openDocument(doc, isPreview ? 'preview' : 'sidepanel');
|
||||
|
||||
@@ -6,12 +6,6 @@ import MediaViewer from './MediaViewer';
|
||||
|
||||
import type { Document } from '../types/documents';
|
||||
|
||||
interface DocumentLink {
|
||||
url?: string;
|
||||
mimeType?: string;
|
||||
filename?: string;
|
||||
}
|
||||
|
||||
interface ContentTabConfig {
|
||||
id?: string;
|
||||
label?: string;
|
||||
@@ -29,7 +23,6 @@ type LayoutMode = 'split' | 'stacked' | (string & {});
|
||||
|
||||
interface DocumentViewerLayoutProps {
|
||||
document?: Document | null;
|
||||
documentLink?: DocumentLink | null;
|
||||
summaryProps?: Record<string, unknown>;
|
||||
metadataPayload?: unknown;
|
||||
contentTabConfig?: ContentTabConfig | null;
|
||||
@@ -43,7 +36,6 @@ interface DocumentViewerLayoutProps {
|
||||
|
||||
const DocumentViewerLayout = ({
|
||||
document,
|
||||
documentLink,
|
||||
summaryProps = {},
|
||||
metadataPayload,
|
||||
contentTabConfig,
|
||||
@@ -58,28 +50,27 @@ const DocumentViewerLayout = ({
|
||||
const viewportRef = useRef<HTMLDivElement>(null);
|
||||
|
||||
const previewContent = useMemo(() => {
|
||||
if (!document || !documentLink?.url) {
|
||||
if (!document) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const normalizedMimeType = (documentLink.mimeType
|
||||
|| document.mime_type
|
||||
|| '')
|
||||
.toLowerCase();
|
||||
const normalizedFilename = documentLink.filename
|
||||
|| document.filename
|
||||
|| document.original_name
|
||||
|| '';
|
||||
const downloadUrl = document.current_version?.download?.url;
|
||||
if (!downloadUrl) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const normalizedMimeType = (document.mime_type || '').toLowerCase();
|
||||
const normalizedFilename = document.filename;
|
||||
|
||||
const isPdf = normalizedMimeType === 'application/pdf'
|
||||
|| normalizedMimeType === 'application/x-pdf';
|
||||
|
||||
if (isPdf) {
|
||||
const documentTitle = document.title
|
||||
|| document.filename
|
||||
|| document.original_name;
|
||||
const documentTitle = document.title;
|
||||
|
||||
return (
|
||||
<PdfViewer
|
||||
src={documentLink.url}
|
||||
src={downloadUrl}
|
||||
title={documentTitle ? `Preview of ${documentTitle}` : undefined}
|
||||
viewportRef={viewportRef}
|
||||
/>
|
||||
@@ -88,23 +79,23 @@ const DocumentViewerLayout = ({
|
||||
|
||||
return (
|
||||
<MediaViewer
|
||||
src={documentLink.url}
|
||||
src={downloadUrl}
|
||||
mimeType={normalizedMimeType}
|
||||
filename={normalizedFilename}
|
||||
alt={`Preview of ${document.title}`}
|
||||
/>
|
||||
);
|
||||
}, [document, documentLink, viewportRef]);
|
||||
}, [document, viewportRef]);
|
||||
|
||||
const renderViewportPane = useCallback(() => (
|
||||
<div className="document-viewer__viewport" ref={viewportRef}>
|
||||
{!documentLink?.url ? (
|
||||
{!document?.current_version?.download?.url ? (
|
||||
<div className="document-viewer__message">{previewLoadingMessage}</div>
|
||||
) : (
|
||||
previewContent
|
||||
)}
|
||||
</div>
|
||||
), [previewContent, documentLink?.url, previewLoadingMessage, viewportRef]);
|
||||
), [previewContent, document?.current_version?.download?.url, previewLoadingMessage, viewportRef]);
|
||||
|
||||
const viewportPane = renderViewportPane();
|
||||
|
||||
|
||||
@@ -230,24 +230,6 @@ const DocumentViewerPanel: React.FC<DocumentViewerPanelProps> = ({
|
||||
const panelRef = useRef<HTMLDivElement | HTMLFormElement | HTMLElement | null>(null);
|
||||
const isStackedLayout = useViewerLayoutMode(panelRef, document?.id);
|
||||
|
||||
const resolvedDocumentLink = useMemo(() => {
|
||||
if (!document) {
|
||||
return null;
|
||||
}
|
||||
const downloadUrl = document.current_version?.download?.url;
|
||||
const href = downloadUrl;
|
||||
if (!href) {
|
||||
return null;
|
||||
}
|
||||
const mimeType = document.mime_type;
|
||||
const filename = document.current_version?.filename || document.filename || document.title || null;
|
||||
return {
|
||||
url: href,
|
||||
mimeType,
|
||||
filename,
|
||||
};
|
||||
}, [document]);
|
||||
|
||||
const {
|
||||
panelStyle: managedDetailPanelStyle,
|
||||
handleProps: managedResizeHandleProps,
|
||||
@@ -407,7 +389,6 @@ const DocumentViewerPanel: React.FC<DocumentViewerPanelProps> = ({
|
||||
<section className={viewerClassName}>
|
||||
<DocumentViewerLayout
|
||||
document={document}
|
||||
documentLink={resolvedDocumentLink}
|
||||
summaryProps={summaryProps}
|
||||
metadataPayload={metadataPayload}
|
||||
contentTabConfig={contentTabConfig}
|
||||
|
||||
Reference in New Issue
Block a user