From f57bb9f6ebb2c96fce686378e8643a56c26d9a0e Mon Sep 17 00:00:00 2001 From: Nils Schneider Date: Thu, 4 Dec 2025 02:21:11 +0100 Subject: [PATCH] introduce a unified document viewer component. --- frontend/src/app/useWorkspaceSurface.tsx | 6 +- frontend/src/detail/PreviewZoomOverlay.tsx | 35 ++---------- frontend/src/preview/DocumentViewerLayout.tsx | 47 +++------------ frontend/src/preview/DocumentViewerPanel.tsx | 16 +++--- .../src/preview/UnifiedDocumentViewer.tsx | 57 +++++++++++++++++++ frontend/src/styles/preview/preview-zoom.css | 7 +-- 6 files changed, 82 insertions(+), 86 deletions(-) create mode 100644 frontend/src/preview/UnifiedDocumentViewer.tsx diff --git a/frontend/src/app/useWorkspaceSurface.tsx b/frontend/src/app/useWorkspaceSurface.tsx index 93b2ebe..0c6b2be 100644 --- a/frontend/src/app/useWorkspaceSurface.tsx +++ b/frontend/src/app/useWorkspaceSurface.tsx @@ -116,8 +116,8 @@ export const useWorkspaceSurface = ({ @@ -194,7 +194,7 @@ export const useWorkspaceSurface = ({ ensurePreviewData={ensurePreviewData} notifyApiError={notifyApiError} sidebarToggle={sidebarToggle} - onClosePanel={closeDocumentPreview} + onClose={closeDocumentPreview} resolveFolderPath={resolveFolderPath} /> ); diff --git a/frontend/src/detail/PreviewZoomOverlay.tsx b/frontend/src/detail/PreviewZoomOverlay.tsx index a8e4579..e61293c 100644 --- a/frontend/src/detail/PreviewZoomOverlay.tsx +++ b/frontend/src/detail/PreviewZoomOverlay.tsx @@ -1,7 +1,6 @@ import React, { useEffect, useRef, useState } from 'react'; import { createPortal } from 'react-dom'; -import PdfViewer from '../preview/PdfViewer'; -import MediaViewer from '../preview/MediaViewer'; +import UnifiedDocumentViewer from '../preview/UnifiedDocumentViewer'; import PanelHeader from '../ui/PanelHeader'; import { IconX, DownloadIcon, FileInfoIcon } from '../ui/icons'; @@ -14,16 +13,6 @@ interface PreviewZoomOverlayProps { document?: Document | null; } -type DisplayKind = 'image' | 'pdf'; - -const determineDisplayKind = (doc?: Document | null): DisplayKind => { - const type = doc?.mime_type?.toLowerCase?.() || ''; - if (type.includes('pdf')) { - return 'pdf'; - } - return 'image'; -}; - const PreviewZoomOverlay: React.FC = ({ open = false, onClose, @@ -41,7 +30,6 @@ const PreviewZoomOverlay: React.FC = ({ } const downloadUrl = lastDocumentRef.current?.current_version?.download?.url; - const displayKind = determineDisplayKind(lastDocumentRef.current); const documentTitle = lastDocumentRef.current?.title || undefined; useEffect(() => { @@ -172,23 +160,10 @@ const PreviewZoomOverlay: React.FC = ({ ref={scrollRef} tabIndex={-1} > - {displayKind === 'pdf' ? ( - - ) : ( - e.stopPropagation()} - mimeType={lastDocumentRef.current?.mime_type || undefined} - /> - )} + diff --git a/frontend/src/preview/DocumentViewerLayout.tsx b/frontend/src/preview/DocumentViewerLayout.tsx index 872565a..a34ad3d 100644 --- a/frontend/src/preview/DocumentViewerLayout.tsx +++ b/frontend/src/preview/DocumentViewerLayout.tsx @@ -1,8 +1,7 @@ import { useCallback, useMemo, useRef } from 'react'; import type { JSX } from 'react'; import DocumentInfoPanel from '../documents/DocumentInfoPanel'; -import PdfViewer from './PdfViewer'; -import MediaViewer from './MediaViewer'; +import UnifiedDocumentViewer from './UnifiedDocumentViewer'; import type { Document } from '../types/documents'; @@ -33,7 +32,6 @@ interface DocumentViewerLayoutProps { previewLoadingMessage?: string; layoutMode?: LayoutMode; } - const DocumentViewerLayout = ({ document, summaryProps = {}, @@ -49,43 +47,12 @@ const DocumentViewerLayout = ({ const isStacked = layoutMode === 'stacked'; const viewportRef = useRef(null); - const previewContent = useMemo(() => { - if (!document) { - return null; - } - - 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; - - return ( - - ); - } - - return ( - - ); - }, [document, viewportRef]); + const previewContent = useMemo(() => ( + + ), [document, viewportRef]); const renderViewportPane = useCallback(() => (
diff --git a/frontend/src/preview/DocumentViewerPanel.tsx b/frontend/src/preview/DocumentViewerPanel.tsx index e9366b8..7d659b5 100644 --- a/frontend/src/preview/DocumentViewerPanel.tsx +++ b/frontend/src/preview/DocumentViewerPanel.tsx @@ -39,10 +39,10 @@ interface DocumentViewerPanelProps extends DocumentSummarySectionProps { ensurePreviewData?: (docId: DocumentId, options?: { signal?: AbortSignal }) => Promise; notifyApiError?: (error: unknown, fallbackMessage?: string) => void; sidebarToggle?: ReactNode; - onClosePanel?: () => void; + onClose?: () => void; resolveFolderPath?: (doc: Document | null) => Array<{ id?: string; name?: string }>; variant?: 'viewer' | 'sidebar'; - onMaximizePanel?: (args: { documentIds: Array }) => void; + onMaximize?: (args: { documentIds: Array }) => void; sidebarMode?: SidebarMode; } @@ -95,10 +95,10 @@ const DocumentViewerPanel: React.FC = ({ ensurePreviewData, notifyApiError, sidebarToggle = null, - onClosePanel, + onClose, resolveFolderPath, variant = 'viewer', - onMaximizePanel, + onMaximize, sidebarMode = 'overlay', }) => { const navigate = useNavigate(); @@ -299,7 +299,7 @@ const DocumentViewerPanel: React.FC = ({ canZoom: Boolean(document), }); - const maximizeButton = isSidebarVariant && onMaximizePanel + const maximizeButton = isSidebarVariant && onMaximize ? (