mirror of
https://github.com/Frooodle/Stirling-PDF.git
synced 2025-09-08 17:51:20 +02:00
Page editor tweaks
This commit is contained in:
parent
35820e8a24
commit
759055a96d
@ -97,27 +97,8 @@ export class DeletePagesCommand extends PageCommand {
|
|||||||
}
|
}
|
||||||
|
|
||||||
undo(): void {
|
undo(): void {
|
||||||
let restoredPages = [...this.pdfDocument.pages];
|
// Simply restore to the previous state (before deletion)
|
||||||
|
this.setPdfDocument(this.previousState);
|
||||||
// Insert deleted pages back at their original positions
|
|
||||||
this.deletedPages
|
|
||||||
.sort((a, b) => (this.deletedPositions.get(a.id) || 0) - (this.deletedPositions.get(b.id) || 0))
|
|
||||||
.forEach(page => {
|
|
||||||
const originalIndex = this.deletedPositions.get(page.id) || 0;
|
|
||||||
restoredPages.splice(originalIndex, 0, page);
|
|
||||||
});
|
|
||||||
|
|
||||||
// Update page numbers
|
|
||||||
restoredPages = restoredPages.map((page, index) => ({
|
|
||||||
...page,
|
|
||||||
pageNumber: index + 1
|
|
||||||
}));
|
|
||||||
|
|
||||||
this.setPdfDocument({
|
|
||||||
...this.pdfDocument,
|
|
||||||
pages: restoredPages,
|
|
||||||
totalPages: restoredPages.length
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
get description(): string {
|
get description(): string {
|
||||||
|
@ -101,11 +101,11 @@ const PageEditor = ({
|
|||||||
const { executeCommand, undo, redo, canUndo, canRedo } = useUndoRedo();
|
const { executeCommand, undo, redo, canUndo, canRedo } = useUndoRedo();
|
||||||
|
|
||||||
// Convert enhanced processed files to Page Editor format
|
// Convert enhanced processed files to Page Editor format
|
||||||
const convertToPageEditorFormat = useCallback((enhancedFile: EnhancedProcessedFile, fileName: string): PDFDocument => {
|
const convertToPageEditorFormat = useCallback((enhancedFile: EnhancedProcessedFile, fileName: string, originalFile: File): PDFDocument => {
|
||||||
return {
|
return {
|
||||||
id: enhancedFile.id,
|
id: enhancedFile.id,
|
||||||
name: fileName,
|
name: fileName,
|
||||||
file: null as any, // We don't need the file reference in the converted format
|
file: originalFile, // Keep reference to original file for export functionality
|
||||||
pages: enhancedFile.pages.map(page => ({
|
pages: enhancedFile.pages.map(page => ({
|
||||||
...page,
|
...page,
|
||||||
// Ensure compatibility with existing page editor types
|
// Ensure compatibility with existing page editor types
|
||||||
@ -126,7 +126,7 @@ const PageEditor = ({
|
|||||||
// Single file - use enhanced processed file
|
// Single file - use enhanced processed file
|
||||||
const enhancedFile = enhancedProcessedFiles.get(activeFiles[0]);
|
const enhancedFile = enhancedProcessedFiles.get(activeFiles[0]);
|
||||||
if (enhancedFile) {
|
if (enhancedFile) {
|
||||||
const pdfDoc = convertToPageEditorFormat(enhancedFile, activeFiles[0].name);
|
const pdfDoc = convertToPageEditorFormat(enhancedFile, activeFiles[0].name, activeFiles[0]);
|
||||||
setMergedPdfDocument(pdfDoc);
|
setMergedPdfDocument(pdfDoc);
|
||||||
setFilename(activeFiles[0].name.replace(/\.pdf$/i, ''));
|
setFilename(activeFiles[0].name.replace(/\.pdf$/i, ''));
|
||||||
}
|
}
|
||||||
@ -158,7 +158,7 @@ const PageEditor = ({
|
|||||||
const mergedDocument: PDFDocument = {
|
const mergedDocument: PDFDocument = {
|
||||||
id: `merged-${Date.now()}`,
|
id: `merged-${Date.now()}`,
|
||||||
name: filenames.join(' + '),
|
name: filenames.join(' + '),
|
||||||
file: null as any,
|
file: activeFiles[0], // Use first file as reference for export operations
|
||||||
pages: allPages,
|
pages: allPages,
|
||||||
totalPages: totalPages
|
totalPages: totalPages
|
||||||
};
|
};
|
||||||
@ -458,7 +458,6 @@ const PageEditor = ({
|
|||||||
const animateReorder = useCallback((pageId: string, targetIndex: number) => {
|
const animateReorder = useCallback((pageId: string, targetIndex: number) => {
|
||||||
if (!mergedPdfDocument || isAnimating) return;
|
if (!mergedPdfDocument || isAnimating) return;
|
||||||
|
|
||||||
|
|
||||||
// In selection mode, if the dragged page is selected, move all selected pages
|
// In selection mode, if the dragged page is selected, move all selected pages
|
||||||
const pagesToMove = selectionMode && selectedPages.includes(pageId)
|
const pagesToMove = selectionMode && selectedPages.includes(pageId)
|
||||||
? selectedPages
|
? selectedPages
|
||||||
@ -467,94 +466,104 @@ const PageEditor = ({
|
|||||||
const originalIndex = mergedPdfDocument.pages.findIndex(p => p.id === pageId);
|
const originalIndex = mergedPdfDocument.pages.findIndex(p => p.id === pageId);
|
||||||
if (originalIndex === -1 || originalIndex === targetIndex) return;
|
if (originalIndex === -1 || originalIndex === targetIndex) return;
|
||||||
|
|
||||||
|
// Skip animation for large documents (500+ pages) to improve performance
|
||||||
|
const isLargeDocument = mergedPdfDocument.pages.length > 500;
|
||||||
|
|
||||||
|
if (isLargeDocument) {
|
||||||
|
// For large documents, just execute the command without animation
|
||||||
|
if (pagesToMove.length > 1) {
|
||||||
|
const command = new MovePagesCommand(mergedPdfDocument, setPdfDocument, pagesToMove, targetIndex);
|
||||||
|
executeCommand(command);
|
||||||
|
} else {
|
||||||
|
const command = new ReorderPageCommand(mergedPdfDocument, setPdfDocument, pageId, targetIndex);
|
||||||
|
executeCommand(command);
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
setIsAnimating(true);
|
setIsAnimating(true);
|
||||||
|
|
||||||
// Get current positions of all pages by querying DOM directly
|
// For smaller documents, determine which pages might be affected by the move
|
||||||
|
const startIndex = Math.min(originalIndex, targetIndex);
|
||||||
|
const endIndex = Math.max(originalIndex, targetIndex);
|
||||||
|
const affectedPageIds = mergedPdfDocument.pages
|
||||||
|
.slice(Math.max(0, startIndex - 5), Math.min(mergedPdfDocument.pages.length, endIndex + 5))
|
||||||
|
.map(p => p.id);
|
||||||
|
|
||||||
|
// Only capture positions for potentially affected pages
|
||||||
const currentPositions = new Map<string, { x: number; y: number }>();
|
const currentPositions = new Map<string, { x: number; y: number }>();
|
||||||
const allCurrentElements = Array.from(document.querySelectorAll('[data-page-id]'));
|
|
||||||
|
|
||||||
|
affectedPageIds.forEach(pageId => {
|
||||||
// Capture positions from actual DOM elements
|
const element = document.querySelector(`[data-page-id="${pageId}"]`);
|
||||||
allCurrentElements.forEach((element) => {
|
if (element) {
|
||||||
const pageId = element.getAttribute('data-page-id');
|
|
||||||
if (pageId) {
|
|
||||||
const rect = element.getBoundingClientRect();
|
const rect = element.getBoundingClientRect();
|
||||||
currentPositions.set(pageId, { x: rect.left, y: rect.top });
|
currentPositions.set(pageId, { x: rect.left, y: rect.top });
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// Execute the reorder command
|
||||||
// Execute the reorder - for multi-page, we use a different command
|
|
||||||
if (pagesToMove.length > 1) {
|
if (pagesToMove.length > 1) {
|
||||||
// Multi-page move - use MovePagesCommand
|
|
||||||
const command = new MovePagesCommand(mergedPdfDocument, setPdfDocument, pagesToMove, targetIndex);
|
const command = new MovePagesCommand(mergedPdfDocument, setPdfDocument, pagesToMove, targetIndex);
|
||||||
executeCommand(command);
|
executeCommand(command);
|
||||||
} else {
|
} else {
|
||||||
// Single page move
|
|
||||||
const command = new ReorderPageCommand(mergedPdfDocument, setPdfDocument, pageId, targetIndex);
|
const command = new ReorderPageCommand(mergedPdfDocument, setPdfDocument, pageId, targetIndex);
|
||||||
executeCommand(command);
|
executeCommand(command);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Wait for state update and DOM to update, then get new positions and animate
|
// Animate only the affected pages
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
requestAnimationFrame(() => {
|
requestAnimationFrame(() => {
|
||||||
requestAnimationFrame(() => {
|
requestAnimationFrame(() => {
|
||||||
const newPositions = new Map<string, { x: number; y: number }>();
|
const newPositions = new Map<string, { x: number; y: number }>();
|
||||||
|
|
||||||
// Re-get all page elements after state update
|
// Get new positions only for affected pages
|
||||||
const allPageElements = Array.from(document.querySelectorAll('[data-page-id]'));
|
affectedPageIds.forEach(pageId => {
|
||||||
|
const element = document.querySelector(`[data-page-id="${pageId}"]`);
|
||||||
allPageElements.forEach((element) => {
|
if (element) {
|
||||||
const pageId = element.getAttribute('data-page-id');
|
|
||||||
if (pageId) {
|
|
||||||
const rect = element.getBoundingClientRect();
|
const rect = element.getBoundingClientRect();
|
||||||
newPositions.set(pageId, { x: rect.left, y: rect.top });
|
newPositions.set(pageId, { x: rect.left, y: rect.top });
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
let animationCount = 0;
|
const elementsToAnimate: HTMLElement[] = [];
|
||||||
|
|
||||||
// Calculate and apply animations using DOM elements directly
|
// Apply animations only to pages that actually moved
|
||||||
allPageElements.forEach((element) => {
|
affectedPageIds.forEach(pageId => {
|
||||||
const pageId = element.getAttribute('data-page-id');
|
const element = document.querySelector(`[data-page-id="${pageId}"]`) as HTMLElement;
|
||||||
if (!pageId) return;
|
if (!element) return;
|
||||||
|
|
||||||
const currentPos = currentPositions.get(pageId);
|
const currentPos = currentPositions.get(pageId);
|
||||||
const newPos = newPositions.get(pageId);
|
const newPos = newPositions.get(pageId);
|
||||||
|
|
||||||
if (element && currentPos && newPos) {
|
if (currentPos && newPos) {
|
||||||
const deltaX = currentPos.x - newPos.x;
|
const deltaX = currentPos.x - newPos.x;
|
||||||
const deltaY = currentPos.y - newPos.y;
|
const deltaY = currentPos.y - newPos.y;
|
||||||
|
|
||||||
|
|
||||||
if (Math.abs(deltaX) > 1 || Math.abs(deltaY) > 1) {
|
if (Math.abs(deltaX) > 1 || Math.abs(deltaY) > 1) {
|
||||||
animationCount++;
|
elementsToAnimate.push(element);
|
||||||
const htmlElement = element as HTMLElement;
|
|
||||||
// Apply initial transform (from new position back to old position)
|
// Apply initial transform
|
||||||
htmlElement.style.transform = `translate(${deltaX}px, ${deltaY}px)`;
|
element.style.transform = `translate(${deltaX}px, ${deltaY}px)`;
|
||||||
htmlElement.style.transition = 'none';
|
element.style.transition = 'none';
|
||||||
|
|
||||||
// Force reflow
|
// Force reflow
|
||||||
htmlElement.offsetHeight;
|
element.offsetHeight;
|
||||||
|
|
||||||
// Animate to final position
|
// Animate to final position
|
||||||
htmlElement.style.transition = 'transform 0.4s cubic-bezier(0.25, 0.46, 0.45, 0.94)';
|
element.style.transition = 'transform 0.3s cubic-bezier(0.25, 0.46, 0.45, 0.94)';
|
||||||
htmlElement.style.transform = 'translate(0px, 0px)';
|
element.style.transform = 'translate(0px, 0px)';
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// Clean up after animation (only for animated elements)
|
||||||
// Clean up after animation
|
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
const elementsToCleanup = Array.from(document.querySelectorAll('[data-page-id]'));
|
elementsToAnimate.forEach((element) => {
|
||||||
elementsToCleanup.forEach((element) => {
|
element.style.transform = '';
|
||||||
const htmlElement = element as HTMLElement;
|
element.style.transition = '';
|
||||||
htmlElement.style.transform = '';
|
|
||||||
htmlElement.style.transition = '';
|
|
||||||
});
|
});
|
||||||
setIsAnimating(false);
|
setIsAnimating(false);
|
||||||
}, 400);
|
}, 300);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
}, 10); // Small delay to allow state update
|
}, 10); // Small delay to allow state update
|
||||||
|
@ -56,7 +56,7 @@ const PageEditorControls = ({
|
|||||||
return (
|
return (
|
||||||
<div
|
<div
|
||||||
style={{
|
style={{
|
||||||
position: 'fixed',
|
position: 'absolute',
|
||||||
left: '50%',
|
left: '50%',
|
||||||
bottom: '20px',
|
bottom: '20px',
|
||||||
transform: 'translateX(-50%)',
|
transform: 'translateX(-50%)',
|
||||||
|
Loading…
Reference in New Issue
Block a user