{
diff --git a/frontend/src/preview/PdfViewer.tsx b/frontend/src/preview/PdfViewer.tsx
index a16c06b..97c7e81 100644
--- a/frontend/src/preview/PdfViewer.tsx
+++ b/frontend/src/preview/PdfViewer.tsx
@@ -379,7 +379,8 @@ const PdfViewer = ({ src, title, className, viewportRef }: PdfViewerProps): JSX.
const stackStyle = useMemo
(() => ({
'--pdf-viewer-viewport-width': `${viewportWidth}px`,
'--pdf-viewer-viewport-height': `${viewportHeight}px`,
- }), [viewportHeight, viewportWidth]);
+ cursor: viewMode === 'fit-width' ? 'zoom-out' : 'zoom-in',
+ }), [viewportHeight, viewportWidth, viewMode]);
const toggleViewMode = useCallback(() => {
setViewMode((prev) => (prev === 'fit-width' ? 'contain' : 'fit-width'));
diff --git a/frontend/src/preview/PreviewContext.tsx b/frontend/src/preview/PreviewContext.tsx
index ba662e2..5408f75 100644
--- a/frontend/src/preview/PreviewContext.tsx
+++ b/frontend/src/preview/PreviewContext.tsx
@@ -21,9 +21,10 @@ export const usePreviewContext = () => {
interface PreviewProviderProps {
children: React.ReactNode;
ensureDownloadUrl?: (docId: Identifier) => Promise;
+ onNavigate?: (documentId: Identifier) => void;
}
-export const PreviewProvider: React.FC = ({ children, ensureDownloadUrl }) => {
+export const PreviewProvider: React.FC = ({ children, ensureDownloadUrl, onNavigate }) => {
const [previewDoc, setPreviewDoc] = useState(null);
const [previewUrl, setPreviewUrl] = useState(null);
@@ -36,6 +37,13 @@ export const PreviewProvider: React.FC = ({ children, ensu
setPreviewUrl(null);
}, []);
+ const handleMaximize = useCallback(() => {
+ if (previewDoc && onNavigate) {
+ onNavigate(previewDoc.id);
+ closePreview();
+ }
+ }, [previewDoc, onNavigate, closePreview]);
+
useEffect(() => {
if (!previewDoc) {
setPreviewUrl(null);
@@ -87,6 +95,7 @@ export const PreviewProvider: React.FC = ({ children, ensu
diff --git a/frontend/src/styles/detail/detail-panels.css b/frontend/src/styles/detail/detail-panels.css
index 24fd5aa..dec6b3f 100644
--- a/frontend/src/styles/detail/detail-panels.css
+++ b/frontend/src/styles/detail/detail-panels.css
@@ -75,6 +75,28 @@
margin-left: auto;
}
+/* Dark theme variant for preview zoom overlay */
+.panel-header--dark {
+ background: var(--overlay-dark);
+ color: var(--text-on-dark);
+ pointer-events: auto;
+}
+
+.panel-header--dark .icon-button,
+.panel-header--dark button,
+.panel-header--dark a.icon-button {
+ color: var(--text-on-dark);
+ opacity: 0.75;
+ pointer-events: auto;
+}
+
+.panel-header--dark .icon-button:hover:not([disabled]),
+.panel-header--dark button:hover:not([disabled]),
+.panel-header--dark a.icon-button:hover {
+ background: var(--surface-hover);
+ opacity: 1;
+}
+
.panel-body {
padding: 0.5rem 1rem;
}
diff --git a/frontend/src/styles/preview/preview-zoom.css b/frontend/src/styles/preview/preview-zoom.css
index 6b8f970..cb85e33 100644
--- a/frontend/src/styles/preview/preview-zoom.css
+++ b/frontend/src/styles/preview/preview-zoom.css
@@ -6,10 +6,12 @@
display: flex;
align-items: center;
justify-content: center;
- z-index: 2000000;
- cursor: zoom-out;
+ z-index: 6000000;
+ cursor: default;
opacity: 0;
pointer-events: none;
+ backdrop-filter: blur(8px);
+ -webkit-backdrop-filter: blur(8px);
}
.preview-zoom-backdrop--visible {
@@ -23,8 +25,9 @@
display: flex;
align-items: center;
justify-content: center;
- z-index: 3000000;
+ z-index: 6000001;
--preview-padding: 1.5vmin;
+ --header-clearance: calc(2.5rem + 0.5rem);
}
.preview-zoom__stage--pdf {
@@ -42,6 +45,8 @@
display: flex;
align-items: center;
justify-content: center;
+ padding-top: var(--header-clearance);
+ box-sizing: border-box;
}
.preview-zoom__scroll--pdf {
@@ -60,6 +65,8 @@
}
.preview-zoom__scroll--native {
+ width: 100%;
+ height: 100%;
overflow: auto;
cursor: zoom-out;
justify-content: flex-start;
@@ -73,6 +80,8 @@
display: flex;
justify-content: center;
align-items: flex-start;
+ padding-top: var(--header-clearance);
+ box-sizing: border-box;
}
.preview-zoom__pdf-viewer {
@@ -93,4 +102,23 @@
z-index: -1;
pointer-events: none;
border-radius: inherit;
+}
+
+/* Header positioning for preview zoom overlay */
+.preview-zoom-backdrop .panel-header--dark {
+ position: absolute;
+ top: 0;
+ left: 0;
+ right: 0;
+ z-index: 6000002;
+ cursor: default;
+ backdrop-filter: blur(4px);
+ -webkit-backdrop-filter: blur(4px);
+ pointer-events: auto;
+ box-shadow: 0 1rem 0.5rem var(--shadow-subtle);
+}
+
+/* Prevent header clicks from closing backdrop */
+.preview-zoom-backdrop .panel-header--dark * {
+ pointer-events: auto;
}
\ No newline at end of file