2025-07-16 17:53:50 +01:00
|
|
|
import React, { useState, useCallback} from "react";
|
2025-06-20 20:22:18 +01:00
|
|
|
import { useTranslation } from 'react-i18next';
|
2025-07-16 17:53:50 +01:00
|
|
|
import { useFileContext } from "../contexts/FileContext";
|
|
|
|
import { useToolManagement } from "../hooks/useToolManagement";
|
|
|
|
import { Group, Box, Button, Container } from "@mantine/core";
|
2025-06-20 20:22:18 +01:00
|
|
|
import { useRainbowThemeContext } from "../components/shared/RainbowThemeProvider";
|
|
|
|
import rainbowStyles from '../styles/rainbow.module.css';
|
|
|
|
|
|
|
|
import ToolPicker from "../components/tools/ToolPicker";
|
2025-06-20 17:51:24 +01:00
|
|
|
import TopControls from "../components/shared/TopControls";
|
2025-07-16 17:53:50 +01:00
|
|
|
import FileEditor from "../components/fileEditor/FileEditor";
|
2025-06-24 23:31:21 +01:00
|
|
|
import PageEditor from "../components/pageEditor/PageEditor";
|
|
|
|
import PageEditorControls from "../components/pageEditor/PageEditorControls";
|
2025-06-19 22:41:05 +01:00
|
|
|
import Viewer from "../components/viewer/Viewer";
|
2025-06-20 17:51:24 +01:00
|
|
|
import FileUploadSelector from "../components/shared/FileUploadSelector";
|
2025-06-20 20:22:18 +01:00
|
|
|
import ToolRenderer from "../components/tools/ToolRenderer";
|
|
|
|
import QuickAccessBar from "../components/shared/QuickAccessBar";
|
2025-06-27 18:00:35 +01:00
|
|
|
import { useMultipleEndpointsEnabled } from "../hooks/useEndpointConfig";
|
2025-06-20 20:22:18 +01:00
|
|
|
|
2025-05-21 21:47:44 +01:00
|
|
|
export default function HomePage() {
|
2025-06-20 20:22:18 +01:00
|
|
|
const { t } = useTranslation();
|
|
|
|
const { isRainbowMode } = useRainbowThemeContext();
|
|
|
|
|
2025-07-16 17:53:50 +01:00
|
|
|
// Get file context
|
|
|
|
const fileContext = useFileContext();
|
|
|
|
const { activeFiles, currentView, currentMode, setCurrentView, addFiles } = fileContext;
|
|
|
|
|
|
|
|
const {
|
|
|
|
selectedToolKey,
|
|
|
|
selectedTool,
|
|
|
|
toolParams,
|
|
|
|
toolRegistry,
|
|
|
|
selectTool,
|
|
|
|
clearToolSelection,
|
|
|
|
updateToolParams,
|
|
|
|
} = useToolManagement();
|
|
|
|
|
|
|
|
const [toolSelectedFiles, setToolSelectedFiles] = useState<File[]>([]);
|
2025-05-27 19:22:26 +01:00
|
|
|
const [sidebarsVisible, setSidebarsVisible] = useState(true);
|
2025-06-20 20:22:18 +01:00
|
|
|
const [leftPanelView, setLeftPanelView] = useState<'toolPicker' | 'toolContent'>('toolPicker');
|
|
|
|
const [readerMode, setReaderMode] = useState(false);
|
|
|
|
const [pageEditorFunctions, setPageEditorFunctions] = useState<any>(null);
|
2025-07-16 17:53:50 +01:00
|
|
|
const [previewFile, setPreviewFile] = useState<File | null>(null);
|
2025-06-20 20:22:18 +01:00
|
|
|
|
2025-05-21 21:47:44 +01:00
|
|
|
|
2025-06-27 18:00:35 +01:00
|
|
|
|
2025-06-20 20:22:18 +01:00
|
|
|
|
2025-06-27 18:00:35 +01:00
|
|
|
|
2025-06-20 20:22:18 +01:00
|
|
|
const handleToolSelect = useCallback(
|
|
|
|
(id: string) => {
|
2025-07-16 17:53:50 +01:00
|
|
|
selectTool(id);
|
2025-06-20 20:22:18 +01:00
|
|
|
if (toolRegistry[id]?.view) setCurrentView(toolRegistry[id].view);
|
2025-07-16 17:53:50 +01:00
|
|
|
setLeftPanelView('toolContent');
|
|
|
|
setReaderMode(false);
|
2025-06-20 20:22:18 +01:00
|
|
|
},
|
2025-07-16 17:53:50 +01:00
|
|
|
[selectTool, toolRegistry, setCurrentView]
|
2025-06-20 20:22:18 +01:00
|
|
|
);
|
|
|
|
|
|
|
|
const handleQuickAccessTools = useCallback(() => {
|
|
|
|
setLeftPanelView('toolPicker');
|
|
|
|
setReaderMode(false);
|
2025-07-16 17:53:50 +01:00
|
|
|
clearToolSelection();
|
|
|
|
}, [clearToolSelection]);
|
2025-06-20 20:22:18 +01:00
|
|
|
|
|
|
|
const handleReaderToggle = useCallback(() => {
|
|
|
|
setReaderMode(!readerMode);
|
|
|
|
}, [readerMode]);
|
|
|
|
|
|
|
|
const handleViewChange = useCallback((view: string) => {
|
2025-07-16 17:53:50 +01:00
|
|
|
setCurrentView(view as any);
|
|
|
|
}, [setCurrentView]);
|
2025-06-24 20:25:03 +01:00
|
|
|
|
2025-07-16 17:53:50 +01:00
|
|
|
const addToActiveFiles = useCallback(async (file: File) => {
|
|
|
|
const exists = activeFiles.some(f => f.name === file.name && f.size === file.size);
|
|
|
|
if (!exists) {
|
|
|
|
await addFiles([file]);
|
2025-06-24 20:25:03 +01:00
|
|
|
}
|
2025-07-16 17:53:50 +01:00
|
|
|
}, [activeFiles, addFiles]);
|
2025-06-20 20:22:18 +01:00
|
|
|
|
|
|
|
|
2025-05-21 21:47:44 +01:00
|
|
|
|
|
|
|
return (
|
2025-05-28 21:43:02 +01:00
|
|
|
<Group
|
|
|
|
align="flex-start"
|
|
|
|
gap={0}
|
2025-06-06 17:20:06 +01:00
|
|
|
className="min-h-screen w-screen overflow-hidden flex-nowrap flex"
|
2025-05-28 21:43:02 +01:00
|
|
|
>
|
2025-06-20 20:22:18 +01:00
|
|
|
{/* Quick Access Bar */}
|
|
|
|
<QuickAccessBar
|
|
|
|
onToolsClick={handleQuickAccessTools}
|
|
|
|
onReaderToggle={handleReaderToggle}
|
|
|
|
selectedToolKey={selectedToolKey}
|
|
|
|
toolRegistry={toolRegistry}
|
|
|
|
leftPanelView={leftPanelView}
|
|
|
|
readerMode={readerMode}
|
|
|
|
/>
|
|
|
|
|
2025-07-16 17:53:50 +01:00
|
|
|
{/* Left: Tool Picker or Selected Tool Panel */}
|
2025-06-20 20:22:18 +01:00
|
|
|
<div
|
2025-07-16 17:53:50 +01:00
|
|
|
className={`h-screen flex flex-col overflow-hidden bg-[var(--bg-surface)] border-r border-[var(--border-subtle)] transition-all duration-300 ease-out ${isRainbowMode ? rainbowStyles.rainbowPaper : ''}`}
|
2025-06-20 20:22:18 +01:00
|
|
|
style={{
|
2025-07-16 17:53:50 +01:00
|
|
|
width: sidebarsVisible && !readerMode ? '14vw' : '0',
|
|
|
|
padding: sidebarsVisible && !readerMode ? '1rem' : '0'
|
2025-06-20 20:22:18 +01:00
|
|
|
}}
|
|
|
|
>
|
|
|
|
<div
|
|
|
|
style={{
|
|
|
|
opacity: sidebarsVisible && !readerMode ? 1 : 0,
|
|
|
|
transition: 'opacity 0.3s cubic-bezier(0.25, 0.46, 0.45, 0.94)',
|
|
|
|
height: '100%',
|
|
|
|
display: 'flex',
|
|
|
|
flexDirection: 'column'
|
|
|
|
}}
|
|
|
|
>
|
|
|
|
{leftPanelView === 'toolPicker' ? (
|
|
|
|
// Tool Picker View
|
|
|
|
<div className="flex-1 flex flex-col">
|
|
|
|
<ToolPicker
|
|
|
|
selectedToolKey={selectedToolKey}
|
|
|
|
onSelect={handleToolSelect}
|
|
|
|
toolRegistry={toolRegistry}
|
|
|
|
/>
|
|
|
|
</div>
|
|
|
|
) : (
|
|
|
|
// Selected Tool Content View
|
|
|
|
<div className="flex-1 flex flex-col">
|
|
|
|
{/* Back button */}
|
|
|
|
<div className="mb-4">
|
|
|
|
<Button
|
|
|
|
variant="subtle"
|
|
|
|
size="sm"
|
2025-07-16 17:53:50 +01:00
|
|
|
onClick={handleQuickAccessTools}
|
2025-06-20 20:22:18 +01:00
|
|
|
className="text-sm"
|
|
|
|
>
|
2025-06-20 21:46:37 +01:00
|
|
|
← {t("fileUpload.backToTools", "Back to Tools")}
|
2025-06-20 20:22:18 +01:00
|
|
|
</Button>
|
|
|
|
</div>
|
|
|
|
|
|
|
|
{/* Tool title */}
|
|
|
|
<div className="mb-4">
|
|
|
|
<h2 className="text-lg font-semibold">{selectedTool?.name}</h2>
|
|
|
|
</div>
|
|
|
|
|
|
|
|
{/* Tool content */}
|
|
|
|
<div className="flex-1 min-h-0">
|
|
|
|
<ToolRenderer
|
|
|
|
selectedToolKey={selectedToolKey}
|
2025-07-16 17:53:50 +01:00
|
|
|
toolSelectedFiles={toolSelectedFiles}
|
|
|
|
onPreviewFile={setPreviewFile}
|
2025-06-20 20:22:18 +01:00
|
|
|
/>
|
|
|
|
</div>
|
|
|
|
</div>
|
|
|
|
)}
|
|
|
|
</div>
|
|
|
|
</div>
|
|
|
|
|
|
|
|
{/* Main View */}
|
2025-06-20 17:51:24 +01:00
|
|
|
<Box
|
2025-06-18 18:12:15 +01:00
|
|
|
className="flex-1 h-screen min-w-80 relative flex flex-col"
|
2025-06-20 17:51:24 +01:00
|
|
|
style={{
|
2025-06-18 18:12:15 +01:00
|
|
|
backgroundColor: 'var(--bg-background)'
|
|
|
|
}}
|
2025-06-18 14:16:39 +01:00
|
|
|
>
|
2025-06-05 21:59:18 +01:00
|
|
|
{/* Top Controls */}
|
|
|
|
<TopControls
|
|
|
|
currentView={currentView}
|
2025-06-20 20:22:18 +01:00
|
|
|
setCurrentView={handleViewChange}
|
2025-07-16 17:53:50 +01:00
|
|
|
selectedToolKey={selectedToolKey}
|
2025-06-05 21:59:18 +01:00
|
|
|
/>
|
2025-05-28 21:43:02 +01:00
|
|
|
{/* Main content area */}
|
2025-07-16 17:53:50 +01:00
|
|
|
<Box
|
|
|
|
className="flex-1 min-h-0 relative z-10"
|
|
|
|
style={{
|
|
|
|
transition: 'opacity 0.15s ease-in-out',
|
|
|
|
}}
|
|
|
|
>
|
|
|
|
{!activeFiles[0] ? (
|
2025-06-20 20:22:18 +01:00
|
|
|
<Container size="lg" p="xl" h="100%" style={{ display: 'flex', alignItems: 'center', justifyContent: 'center' }}>
|
|
|
|
<FileUploadSelector
|
2025-06-24 23:31:21 +01:00
|
|
|
title={currentView === "viewer"
|
|
|
|
? t("fileUpload.selectPdfToView", "Select a PDF to view")
|
2025-06-20 21:46:37 +01:00
|
|
|
: t("fileUpload.selectPdfToEdit", "Select a PDF to edit")
|
|
|
|
}
|
|
|
|
subtitle={t("fileUpload.chooseFromStorage", "Choose a file from storage or upload a new PDF")}
|
2025-06-20 20:22:18 +01:00
|
|
|
onFileSelect={(file) => {
|
|
|
|
addToActiveFiles(file);
|
|
|
|
}}
|
2025-07-16 17:53:50 +01:00
|
|
|
onFilesSelect={(files) => {
|
|
|
|
files.forEach(addToActiveFiles);
|
|
|
|
}}
|
2025-06-20 20:22:18 +01:00
|
|
|
accept={["application/pdf"]}
|
|
|
|
loading={false}
|
2025-07-16 17:53:50 +01:00
|
|
|
showRecentFiles={true}
|
|
|
|
maxRecentFiles={8}
|
2025-06-20 20:22:18 +01:00
|
|
|
/>
|
|
|
|
</Container>
|
|
|
|
) : currentView === "fileEditor" ? (
|
|
|
|
<FileEditor
|
|
|
|
onOpenPageEditor={(file) => {
|
|
|
|
handleViewChange("pageEditor");
|
|
|
|
}}
|
|
|
|
onMergeFiles={(filesToMerge) => {
|
|
|
|
// Add merged files to active set
|
|
|
|
filesToMerge.forEach(addToActiveFiles);
|
|
|
|
handleViewChange("viewer");
|
|
|
|
}}
|
2025-05-27 19:22:26 +01:00
|
|
|
/>
|
2025-06-20 20:22:18 +01:00
|
|
|
) : currentView === "viewer" ? (
|
|
|
|
<Viewer
|
|
|
|
sidebarsVisible={sidebarsVisible}
|
|
|
|
setSidebarsVisible={setSidebarsVisible}
|
2025-07-16 17:53:50 +01:00
|
|
|
previewFile={previewFile}
|
|
|
|
{...(previewFile && {
|
|
|
|
onClose: () => {
|
|
|
|
setPreviewFile(null); // Clear preview file
|
|
|
|
const previousMode = sessionStorage.getItem('previousMode');
|
|
|
|
if (previousMode === 'split') {
|
|
|
|
selectTool('split');
|
|
|
|
setCurrentView('split');
|
|
|
|
setLeftPanelView('toolContent');
|
|
|
|
sessionStorage.removeItem('previousMode');
|
|
|
|
} else {
|
|
|
|
setCurrentView('fileEditor');
|
|
|
|
}
|
|
|
|
}
|
|
|
|
})}
|
2025-06-20 20:22:18 +01:00
|
|
|
/>
|
|
|
|
) : currentView === "pageEditor" ? (
|
|
|
|
<>
|
|
|
|
<PageEditor
|
|
|
|
onFunctionsReady={setPageEditorFunctions}
|
2025-06-19 19:47:44 +01:00
|
|
|
/>
|
2025-07-16 17:53:50 +01:00
|
|
|
{pageEditorFunctions && (
|
2025-06-20 20:22:18 +01:00
|
|
|
<PageEditorControls
|
|
|
|
onClosePdf={pageEditorFunctions.closePdf}
|
|
|
|
onUndo={pageEditorFunctions.handleUndo}
|
|
|
|
onRedo={pageEditorFunctions.handleRedo}
|
|
|
|
canUndo={pageEditorFunctions.canUndo}
|
|
|
|
canRedo={pageEditorFunctions.canRedo}
|
|
|
|
onRotate={pageEditorFunctions.handleRotate}
|
|
|
|
onDelete={pageEditorFunctions.handleDelete}
|
|
|
|
onSplit={pageEditorFunctions.handleSplit}
|
2025-06-24 20:25:03 +01:00
|
|
|
onExportSelected={pageEditorFunctions.onExportSelected}
|
|
|
|
onExportAll={pageEditorFunctions.onExportAll}
|
2025-06-20 20:22:18 +01:00
|
|
|
exportLoading={pageEditorFunctions.exportLoading}
|
|
|
|
selectionMode={pageEditorFunctions.selectionMode}
|
|
|
|
selectedPages={pageEditorFunctions.selectedPages}
|
|
|
|
/>
|
|
|
|
)}
|
|
|
|
</>
|
2025-07-16 17:53:50 +01:00
|
|
|
) : currentView === "split" ? (
|
|
|
|
<FileEditor
|
|
|
|
toolMode={true}
|
|
|
|
multiSelect={false}
|
|
|
|
showUpload={true}
|
|
|
|
showBulkActions={true}
|
|
|
|
onFileSelect={(files) => {
|
|
|
|
setToolSelectedFiles(files);
|
|
|
|
}}
|
2025-06-20 20:22:18 +01:00
|
|
|
/>
|
2025-07-16 17:53:50 +01:00
|
|
|
) : selectedToolKey && selectedTool ? (
|
|
|
|
<ToolRenderer
|
|
|
|
selectedToolKey={selectedToolKey}
|
|
|
|
/>
|
|
|
|
) : (
|
|
|
|
<Container size="lg" p="xl" h="100%" style={{ display: 'flex', alignItems: 'center', justifyContent: 'center' }}>
|
|
|
|
<FileUploadSelector
|
|
|
|
title="File Management"
|
|
|
|
subtitle="Choose files from storage or upload new PDFs"
|
|
|
|
onFileSelect={(file) => {
|
|
|
|
addToActiveFiles(file);
|
|
|
|
}}
|
|
|
|
onFilesSelect={(files) => {
|
|
|
|
files.forEach(addToActiveFiles);
|
|
|
|
}}
|
|
|
|
accept={["application/pdf"]}
|
|
|
|
loading={false}
|
|
|
|
showRecentFiles={true}
|
|
|
|
maxRecentFiles={8}
|
|
|
|
/>
|
|
|
|
</Container>
|
2025-06-20 20:22:18 +01:00
|
|
|
)}
|
|
|
|
</Box>
|
2025-05-21 21:47:44 +01:00
|
|
|
</Box>
|
|
|
|
</Group>
|
|
|
|
);
|
|
|
|
}
|