This commit is contained in:
Reece
2026-01-06 22:42:44 +00:00
parent b63527c575
commit 4ccd950fe4
2 changed files with 92 additions and 6 deletions
@@ -1,5 +1,6 @@
import { useCallback } from 'react';
import { useCallback, useRef } from 'react';
import { Box } from '@mantine/core';
import html2canvas from 'html2canvas';
import { useRainbowThemeContext } from '@app/components/shared/RainbowThemeProvider';
import { useToolWorkflow } from '@app/contexts/ToolWorkflowContext';
import { useFileHandler } from '@app/hooks/useFileHandler';
@@ -29,8 +30,10 @@ export default function Workbench() {
const { selectors } = useFileState();
const { workbench: currentView, viewerTransition } = useNavigationState();
const { actions: navActions } = useNavigationActions();
const setCurrentView = navActions.setWorkbench;
const activeFiles = selectors.getFiles();
// Ref for capturing screenshot during TopControls transitions
const mainContentRef = useRef<HTMLDivElement>(null);
const {
previewFile,
pageEditorFunctions,
@@ -83,10 +86,87 @@ export default function Workbench() {
handleToolSelect('convert');
sessionStorage.removeItem('previousMode');
} else {
setCurrentView('fileEditor');
navActions.setWorkbench('fileEditor');
}
};
// Capture screenshot helper for TopControls transitions
const captureMainContentScreenshot = useCallback(async (): Promise<string | null> => {
if (!mainContentRef.current) return null;
try {
const canvas = await html2canvas(mainContentRef.current, {
backgroundColor: null,
scale: 1,
logging: false,
useCORS: true,
width: window.innerWidth,
height: window.innerHeight,
windowWidth: window.innerWidth,
windowHeight: window.innerHeight,
x: 0,
y: 0,
});
return canvas.toDataURL('image/png');
} catch (error) {
console.warn('Failed to capture screenshot:', error);
return null;
}
}, []);
// Wrapper for setCurrentView that adds transition when switching to viewer
const setCurrentView = useCallback(async (view: typeof currentView) => {
// If switching to viewer from fileEditor or pageEditor, add transition
if (view === 'viewer' && (currentView === 'fileEditor' || currentView === 'pageEditor')) {
const screenshot = await captureMainContentScreenshot();
// Get the active file's thumbnail for the zoom animation
const activeFile = activeFiles[activeFileIndex];
const activeStub = activeFile ? selectors.getStirlingFileStub(activeFile.fileId) : null;
const thumbnailUrl = activeStub?.thumbnailUrl || '';
if (screenshot && thumbnailUrl && activeFile) {
// Find the actual file card element in the DOM
const fileCard = document.querySelector(`[data-file-id="${activeFile.fileId}"]`) as HTMLElement;
let sourceRect: DOMRect;
if (fileCard) {
// Find the thumbnail image inside the card
const thumbnailImg = fileCard.querySelector('img') as HTMLImageElement;
if (thumbnailImg) {
sourceRect = thumbnailImg.getBoundingClientRect();
} else {
// Fallback to card position if no image found
sourceRect = fileCard.getBoundingClientRect();
}
} else {
// Fallback to center if card not found (might be scrolled out of view)
const centerX = window.innerWidth / 2;
const centerY = window.innerHeight / 2;
const thumbnailSize = 200;
sourceRect = new DOMRect(
centerX - thumbnailSize / 2,
centerY - thumbnailSize / 2,
thumbnailSize,
thumbnailSize
);
}
navActions.startViewerTransition(
sourceRect,
thumbnailUrl,
currentView,
screenshot
);
}
}
navActions.setWorkbench(view);
}, [currentView, navActions, captureMainContentScreenshot, activeFiles, activeFileIndex, selectors]);
const renderMainContent = () => {
// During viewer transition with screenshot, show screenshot overlay
if (viewerTransition.isAnimating && viewerTransition.editorScreenshotUrl) {
@@ -256,6 +336,7 @@ export default function Workbench() {
{/* Main content area */}
<Box
ref={mainContentRef}
className={`flex-1 min-h-0 relative z-10 ${styles.workbenchScrollable}`}
style={{
transition: 'opacity 0.15s ease-in-out',
@@ -133,8 +133,13 @@ export const ViewerZoomTransition: React.FC = () => {
};
}, [viewerTransition.isAnimating, actions]);
// Don't render if not animating or missing data
if (!viewerTransition.isAnimating || !viewerTransition.sourceRect || !viewerTransition.sourceThumbnailUrl) {
// Don't render if not animating
if (!viewerTransition.isAnimating) {
return null;
}
// If no sourceRect or thumbnail, we're transitioning from TopControls (screenshot only, no thumbnail zoom)
if (!viewerTransition.sourceRect || !viewerTransition.sourceThumbnailUrl) {
return null;
}
@@ -149,7 +154,7 @@ export const ViewerZoomTransition: React.FC = () => {
height: `${sourceRect.height}px`,
borderRadius: '8px',
overflow: 'hidden',
zIndex: 1,
zIndex: 10000,
};
// Calculate target styles based on PDF page position (if found)