diff --git a/frontend/package-lock.json b/frontend/package-lock.json index c884272c4..d9b11d099 100644 --- a/frontend/package-lock.json +++ b/frontend/package-lock.json @@ -10,6 +10,7 @@ "license": "SEE LICENSE IN https://raw.githubusercontent.com/Stirling-Tools/Stirling-PDF/refs/heads/main/proprietary/LICENSE", "dependencies": { "@atlaskit/pragmatic-drag-and-drop": "^1.7.7", + "@dnd-kit/core": "^6.3.1", "@embedpdf/core": "^1.3.14", "@embedpdf/engines": "^1.3.14", "@embedpdf/plugin-annotation": "^1.3.14", @@ -501,6 +502,63 @@ "node": ">=18" } }, + "node_modules/@dnd-kit/accessibility": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/@dnd-kit/accessibility/-/accessibility-3.1.1.tgz", + "integrity": "sha512-2P+YgaXF+gRsIihwwY1gCsQSYnu9Zyj2py8kY5fFvUM1qm2WA2u639R6YNVfU4GWr+ZM5mqEsfHZZLoRONbemw==", + "license": "MIT", + "dependencies": { + "tslib": "^2.0.0" + }, + "peerDependencies": { + "react": ">=16.8.0" + } + }, + "node_modules/@dnd-kit/accessibility/node_modules/tslib": { + "version": "2.8.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz", + "integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==", + "license": "0BSD" + }, + "node_modules/@dnd-kit/core": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/@dnd-kit/core/-/core-6.3.1.tgz", + "integrity": "sha512-xkGBRQQab4RLwgXxoqETICr6S5JlogafbhNsidmrkVv2YRs5MLwpjoF2qpiGjQt8S9AoxtIV603s0GIUpY5eYQ==", + "license": "MIT", + "dependencies": { + "@dnd-kit/accessibility": "^3.1.1", + "@dnd-kit/utilities": "^3.2.2", + "tslib": "^2.0.0" + }, + "peerDependencies": { + "react": ">=16.8.0", + "react-dom": ">=16.8.0" + } + }, + "node_modules/@dnd-kit/core/node_modules/tslib": { + "version": "2.8.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz", + "integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==", + "license": "0BSD" + }, + "node_modules/@dnd-kit/utilities": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/@dnd-kit/utilities/-/utilities-3.2.2.tgz", + "integrity": "sha512-+MKAJEOfaBe5SmV6t34p80MMKhjvUz0vRrvVJbPT0WElzaOJ/1xs+D+KDv+tD/NE5ujfrChEcshd4fLn0wpiqg==", + "license": "MIT", + "dependencies": { + "tslib": "^2.0.0" + }, + "peerDependencies": { + "react": ">=16.8.0" + } + }, + "node_modules/@dnd-kit/utilities/node_modules/tslib": { + "version": "2.8.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz", + "integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==", + "license": "0BSD" + }, "node_modules/@embedpdf/core": { "version": "1.3.14", "resolved": "https://registry.npmjs.org/@embedpdf/core/-/core-1.3.14.tgz", diff --git a/frontend/package.json b/frontend/package.json index 892e48569..b8fe67f00 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -6,6 +6,7 @@ "proxy": "http://localhost:8080", "dependencies": { "@atlaskit/pragmatic-drag-and-drop": "^1.7.7", + "@dnd-kit/core": "^6.3.1", "@embedpdf/core": "^1.3.14", "@embedpdf/engines": "^1.3.14", "@embedpdf/plugin-annotation": "^1.3.14", diff --git a/frontend/src/core/components/layout/Workbench.tsx b/frontend/src/core/components/layout/Workbench.tsx index 91595195d..dd7db2a5a 100644 --- a/frontend/src/core/components/layout/Workbench.tsx +++ b/frontend/src/core/components/layout/Workbench.tsx @@ -1,11 +1,13 @@ +import { useMemo } from 'react'; import { Box } from '@mantine/core'; import { useRainbowThemeContext } from '@app/components/shared/RainbowThemeProvider'; import { useToolWorkflow } from '@app/contexts/ToolWorkflowContext'; import { useFileHandler } from '@app/hooks/useFileHandler'; import { useFileState } from '@app/contexts/FileContext'; import { useNavigationState, useNavigationActions } from '@app/contexts/NavigationContext'; -import { isBaseWorkbench } from '@app/types/workbench'; import { useViewer } from '@app/contexts/ViewerContext'; +import { PageEditorProvider } from '@app/contexts/PageEditorContext'; +import { isBaseWorkbench } from '@app/types/workbench'; import { useAppConfig } from '@app/contexts/AppConfigContext'; import '@app/components/layout/Workbench.css'; @@ -24,11 +26,13 @@ export default function Workbench() { const { config } = useAppConfig(); // Use context-based hooks to eliminate all prop drilling - const { selectors } = useFileState(); + const { state, selectors } = useFileState(); const { workbench: currentView } = useNavigationState(); const { actions: navActions } = useNavigationActions(); const setCurrentView = navActions.setWorkbench; - const activeFiles = selectors.getFiles(); + + // Create stable reference for activeFiles based on file IDs + const activeFiles = useMemo(() => selectors.getFiles(), [state.files.ids]); const { previewFile, pageEditorFunctions, @@ -72,31 +76,28 @@ export default function Workbench() { const renderMainContent = () => { if (activeFiles.length === 0) { - return ( - - ); + return ; } switch (currentView) { - case "fileEditor": + case 'fileEditor': return ( { - setCurrentView("pageEditor"); + setCurrentView('pageEditor'); }, onMergeFiles: (filesToMerge) => { addFiles(filesToMerge); - setCurrentView("viewer"); - } + setCurrentView('viewer'); + }, })} /> ); - case "viewer": + case 'viewer': return ( ); - case "pageEditor": + case 'pageEditor': return ( <> - + {pageEditorFunctions && ( view.workbenchId === currentView && view.data != null); + const customView = customWorkbenchViews.find( + (view) => view.workbenchId === currentView && view.data != null, + ); if (customView) { const CustomComponent = customView.component; return ; @@ -152,45 +153,47 @@ export default function Workbench() { }; return ( - - {/* Top Controls */} - {activeFiles.length > 0 && ( - { - const stub = selectors.getStirlingFileStub(f.fileId); - return { fileId: f.fileId, name: f.name, versionNumber: stub?.versionNumber }; - })} - currentFileIndex={activeFileIndex} - onFileSelect={setActiveFileIndex} - /> - )} - - {/* Dismiss All Errors Button */} - - - {/* Main content area */} + 0 ? '3.5rem' : '0'), - }} + className="flex-1 h-full min-w-80 relative flex flex-col" + data-tour="workbench" + style={ + isRainbowMode + ? {} + : { backgroundColor: 'var(--bg-background)' } + } > - {renderMainContent()} - + {/* Top Controls */} + {activeFiles.length > 0 && ( + { + const stub = selectors.getStirlingFileStub(f.fileId); + return { fileId: f.fileId, name: f.name, versionNumber: stub?.versionNumber }; + })} + currentFileIndex={activeFileIndex} + onFileSelect={setActiveFileIndex} + /> + )} -