diff --git a/frontend/src/components/DeepLinks.tsx b/frontend/src/components/DeepLinks.tsx index 79f1fc2ef..e0222d2b9 100644 --- a/frontend/src/components/DeepLinks.tsx +++ b/frontend/src/components/DeepLinks.tsx @@ -2,7 +2,7 @@ import React from 'react'; import { Link } from 'react-router-dom'; import { Button, Stack, Text, Group } from '@mantine/core'; -const DeepLinks: React.FC = () => { +const DeepLinks = () => { const commonLinks = [ { name: "Split PDF Pages 1-5", diff --git a/frontend/src/components/FileCard.standalone.tsx b/frontend/src/components/FileCard.standalone.tsx index 4d140689b..6f2a10f04 100644 --- a/frontend/src/components/FileCard.standalone.tsx +++ b/frontend/src/components/FileCard.standalone.tsx @@ -14,7 +14,7 @@ interface FileCardProps { onDoubleClick?: () => void; } -const FileCard: React.FC = ({ file, onRemove, onDoubleClick }) => { +const FileCard = ({ file, onRemove, onDoubleClick }: FileCardProps) => { const { t } = useTranslation(); const { thumbnail: thumb, isGenerating } = useIndexedDBThumbnail(file); diff --git a/frontend/src/components/FileManager.tsx b/frontend/src/components/FileManager.tsx index b436cd87b..c975274f4 100644 --- a/frontend/src/components/FileManager.tsx +++ b/frontend/src/components/FileManager.tsx @@ -23,13 +23,13 @@ interface FileManagerProps { setCurrentView?: (view: string) => void; } -const FileManager: React.FC = ({ +const FileManager = ({ files = [], setFiles, allowMultiple = true, setPdfFile, setCurrentView, -}) => { +}: FileManagerProps) => { const { t } = useTranslation(); const [loading, setLoading] = useState(false); const [storageStats, setStorageStats] = useState(null); diff --git a/frontend/src/components/LanguageSelector.tsx b/frontend/src/components/LanguageSelector.tsx index 8a3337ccc..16fe55faa 100644 --- a/frontend/src/components/LanguageSelector.tsx +++ b/frontend/src/components/LanguageSelector.tsx @@ -5,7 +5,7 @@ import { supportedLanguages } from '../i18n'; import LanguageIcon from '@mui/icons-material/Language'; import styles from './LanguageSelector.module.css'; -const LanguageSelector: React.FC = () => { +const LanguageSelector = () => { const { i18n } = useTranslation(); const theme = useMantineTheme(); const { colorScheme } = useMantineColorScheme(); diff --git a/frontend/src/components/PageEditor.tsx b/frontend/src/components/PageEditor.tsx index c807010ad..19debef0d 100644 --- a/frontend/src/components/PageEditor.tsx +++ b/frontend/src/components/PageEditor.tsx @@ -42,14 +42,31 @@ export interface PageEditorProps { setFile?: (file: { file: File; url: string } | null) => void; downloadUrl?: string | null; setDownloadUrl?: (url: string | null) => void; + + // Optional callbacks to expose internal functions + onFunctionsReady?: (functions: { + handleUndo: () => void; + handleRedo: () => void; + canUndo: boolean; + canRedo: boolean; + handleRotate: (direction: 'left' | 'right') => void; + handleDelete: () => void; + handleSplit: () => void; + showExportPreview: (selectedOnly: boolean) => void; + exportLoading: boolean; + selectionMode: boolean; + selectedPages: string[]; + closePdf: () => void; + }) => void; } -const PageEditor: React.FC = ({ +const PageEditor = ({ file, setFile, downloadUrl, setDownloadUrl, -}) => { + onFunctionsReady, +}: PageEditorProps) => { const { t } = useTranslation(); const { processPDFFile, loading: pdfLoading } = usePDFProcessor(); @@ -207,7 +224,7 @@ const PageEditor: React.FC = ({ const handleDragStart = useCallback((pageId: string) => { setDraggedPage(pageId); - + // Check if this is a multi-page drag in selection mode if (selectionMode && selectedPages.includes(pageId) && selectedPages.length > 1) { setMultiPageDrag({ @@ -231,7 +248,7 @@ const PageEditor: React.FC = ({ e.preventDefault(); if (!draggedPage) return; - + // Update drag position for multi-page indicator if (multiPageDrag) { setDragPosition({ x: e.clientX, y: e.clientY }); @@ -274,12 +291,12 @@ const PageEditor: React.FC = ({ const animateReorder = useCallback((pageId: string, targetIndex: number) => { if (!pdfDocument || isAnimating) return; - + // In selection mode, if the dragged page is selected, move all selected pages - const pagesToMove = selectionMode && selectedPages.includes(pageId) - ? selectedPages + const pagesToMove = selectionMode && selectedPages.includes(pageId) + ? selectedPages : [pageId]; - + const originalIndex = pdfDocument.pages.findIndex(p => p.id === pageId); if (originalIndex === -1 || originalIndex === targetIndex) return; @@ -310,11 +327,11 @@ const PageEditor: React.FC = ({ requestAnimationFrame(() => { requestAnimationFrame(() => { const newPositions = new Map(); - + // Get the updated document from the state after command execution // The command has already updated the document, so we need to get the new order const currentDoc = pdfDocument; // This should be the updated version after command - + currentDoc.pages.forEach((page) => { const element = pageRefs.current.get(page.id); if (element) { @@ -328,18 +345,18 @@ const PageEditor: React.FC = ({ const element = pageRefs.current.get(page.id); const currentPos = currentPositions.get(page.id); const newPos = newPositions.get(page.id); - + if (element && currentPos && newPos) { const deltaX = currentPos.x - newPos.x; const deltaY = currentPos.y - newPos.y; - + // Apply initial transform (from new position back to old position) element.style.transform = `translate(${deltaX}px, ${deltaY}px)`; element.style.transition = 'none'; - + // Force reflow element.offsetHeight; - + // Animate to final position element.style.transition = 'transform 0.4s cubic-bezier(0.25, 0.46, 0.45, 0.94)'; element.style.transform = 'translate(0px, 0px)'; @@ -374,12 +391,12 @@ const PageEditor: React.FC = ({ } animateReorder(draggedPage, targetIndex); - + setDraggedPage(null); setDropTarget(null); setMultiPageDrag(null); setDragPosition(null); - + const moveCount = multiPageDrag ? multiPageDrag.count : 1; setStatus(`${moveCount > 1 ? `${moveCount} pages` : 'Page'} reordered`); }, [draggedPage, pdfDocument, animateReorder, multiPageDrag]); @@ -394,8 +411,8 @@ const PageEditor: React.FC = ({ if (!pdfDocument) return; const rotation = direction === 'left' ? -90 : 90; - const pagesToRotate = selectionMode - ? selectedPages + const pagesToRotate = selectionMode + ? selectedPages : pdfDocument.pages.map(p => p.id); if (selectionMode && selectedPages.length === 0) return; @@ -415,8 +432,8 @@ const PageEditor: React.FC = ({ const handleDelete = useCallback(() => { if (!pdfDocument) return; - const pagesToDelete = selectionMode - ? selectedPages + const pagesToDelete = selectionMode + ? selectedPages : pdfDocument.pages.map(p => p.id); if (selectionMode && selectedPages.length === 0) return; @@ -438,8 +455,8 @@ const PageEditor: React.FC = ({ const handleSplit = useCallback(() => { if (!pdfDocument) return; - const pagesToSplit = selectionMode - ? selectedPages + const pagesToSplit = selectionMode + ? selectedPages : pdfDocument.pages.map(p => p.id); if (selectionMode && selectedPages.length === 0) return; @@ -521,6 +538,45 @@ const PageEditor: React.FC = ({ } }, [redo]); + const closePdf = useCallback(() => { + setPdfDocument(null); + setFile && setFile(null); + }, [setFile]); + + // Expose functions to parent component + useEffect(() => { + if (onFunctionsReady) { + onFunctionsReady({ + handleUndo, + handleRedo, + canUndo, + canRedo, + handleRotate, + handleDelete, + handleSplit, + showExportPreview, + exportLoading, + selectionMode, + selectedPages, + closePdf, + }); + } + }, [ + onFunctionsReady, + handleUndo, + handleRedo, + canUndo, + canRedo, + handleRotate, + handleDelete, + handleSplit, + showExportPreview, + exportLoading, + selectionMode, + selectedPages, + closePdf + ]); + if (!pdfDocument) { return ( @@ -580,7 +636,7 @@ const PageEditor: React.FC = ({ transform: scale(1.05); box-shadow: 0 10px 30px rgba(0,0,0,0.3); } - + .multi-drag-indicator { position: fixed; background: rgba(59, 130, 246, 0.9); @@ -595,7 +651,7 @@ const PageEditor: React.FC = ({ transform: translate(-50%, -50%); backdrop-filter: blur(4px); } - + @keyframes pulse { 0%, 100% { opacity: 1; @@ -616,7 +672,7 @@ const PageEditor: React.FC = ({ placeholder="Enter filename" style={{ minWidth: 200 }} /> -