diff --git a/frontend/src/viewer/PdfViewer.tsx b/frontend/src/viewer/PdfViewer.tsx index 3ce3b73..c8be8d3 100644 --- a/frontend/src/viewer/PdfViewer.tsx +++ b/frontend/src/viewer/PdfViewer.tsx @@ -258,6 +258,34 @@ const PdfViewer = ({ src, title, className, viewportRef }: PdfViewerProps): JSX. focusTargetRef.current = null; }, [viewMode, viewportRef]); + // Auto-detect scrollbar contrast requirement + useEffect(() => { + const viewportElement = viewportRef?.current || containerRef.current?.closest('.document-viewer__viewport'); + if (!viewportElement || pages.length === 0 || viewportWidth <= 0 || viewportHeight <= 0) { + return; + } + + const page = pages[0]; + const pageAspect = page.width / page.height; + const viewportAspect = viewportWidth / viewportHeight; + + // If we are in 'fit-width' mode, the page usually covers the full width (white background). + // If we are in 'contain' mode, we check if the page is narrower than the viewport (gray background). + const hasHorizontalMargin = viewMode === 'contain' && pageAspect < viewportAspect; + + // If there is no margin (white page), we need the light scheme (dark scrollbar). + // If there is a margin (gray background), we use the default scheme (light scrollbar). + if (!hasHorizontalMargin) { + viewportElement.classList.add('document-viewer__viewport--light-scheme'); + } else { + viewportElement.classList.remove('document-viewer__viewport--light-scheme'); + } + + return () => { + viewportElement.classList.remove('document-viewer__viewport--light-scheme'); + }; + }, [viewMode, viewportRef, pages, viewportWidth, viewportHeight]); + useEffect(() => { if (!src || renderWidth <= 0) { return undefined; diff --git a/frontend/src/viewer/logic/useDetailWorkspace.ts b/frontend/src/viewer/logic/useDetailWorkspace.ts index fdffd6d..ecac2ae 100644 --- a/frontend/src/viewer/logic/useDetailWorkspace.ts +++ b/frontend/src/viewer/logic/useDetailWorkspace.ts @@ -90,6 +90,12 @@ const useDetailWorkspace = ({ }; }, [detailPanelControlRef, openDetailPanel, closeDetailPanel]); + useEffect(() => { + if (detailPanelOpen && activePreviewId) { + openDetailPanel(activePreviewId); + } + }, [detailPanelOpen, activePreviewId, openDetailPanel]); + // Prefetch folder ancestors for breadcrumb display useEffect(() => { const folderId = detailPanelDocument?.folder_id; diff --git a/frontend/src/viewer/styles/viewer.css b/frontend/src/viewer/styles/viewer.css index b44feda..68dc38f 100644 --- a/frontend/src/viewer/styles/viewer.css +++ b/frontend/src/viewer/styles/viewer.css @@ -381,12 +381,15 @@ justify-content: flex-start; max-height: 100%; grid-area: viewport; - background: var(--surface-subtle); - padding: 1.5vmin; box-sizing: border-box; --pdf-viewer-stack-padding: 1.5vmin; } +.document-viewer__viewport--light-scheme { + /* Force light theme scrollbars (dark handle) for visibility on white content */ + color-scheme: light; +} + .document-viewer__object { width: 100%; border: none;