diff --git a/frontend/src/components/pageEditor/DragDropGrid.tsx b/frontend/src/components/pageEditor/DragDropGrid.tsx index 245b12991..5829d0375 100644 --- a/frontend/src/components/pageEditor/DragDropGrid.tsx +++ b/frontend/src/components/pageEditor/DragDropGrid.tsx @@ -1,4 +1,4 @@ -import React, { useRef, useEffect } from 'react'; +import React, { useRef, useEffect, useState, useCallback } from 'react'; import { Box } from '@mantine/core'; import { useVirtualizer } from '@tanstack/react-virtual'; import { dropTargetForElements } from '@atlaskit/pragmatic-drag-and-drop/element/adapter'; @@ -31,15 +31,56 @@ const DragDropGrid = ({ const itemRefs = useRef>(new Map()); const containerRef = useRef(null); - - // Grid configuration - const ITEMS_PER_ROW = 4; + // Responsive grid configuration + const [itemsPerRow, setItemsPerRow] = useState(4); + const ITEM_WIDTH = 320; // 20rem (page width) + const ITEM_GAP = 24; // 1.5rem gap between items const ITEM_HEIGHT = 340; // 20rem + gap const OVERSCAN = items.length > 1000 ? 8 : 4; // More overscan for large documents + // Calculate items per row based on container width + const calculateItemsPerRow = useCallback(() => { + if (!containerRef.current) return 4; // Default fallback + + const containerWidth = containerRef.current.offsetWidth; + if (containerWidth === 0) return 4; // Container not measured yet + + // Calculate how many items fit: (width - gap) / (itemWidth + gap) + const availableWidth = containerWidth - ITEM_GAP; // Account for first gap + const itemWithGap = ITEM_WIDTH + ITEM_GAP; + const calculated = Math.floor(availableWidth / itemWithGap); + + return Math.max(1, calculated); // At least 1 item per row + }, []); + + // Update items per row when container resizes + useEffect(() => { + const updateLayout = () => { + const newItemsPerRow = calculateItemsPerRow(); + setItemsPerRow(newItemsPerRow); + }; + + // Initial calculation + updateLayout(); + + // Listen for window resize + window.addEventListener('resize', updateLayout); + + // Use ResizeObserver for container size changes + const resizeObserver = new ResizeObserver(updateLayout); + if (containerRef.current) { + resizeObserver.observe(containerRef.current); + } + + return () => { + window.removeEventListener('resize', updateLayout); + resizeObserver.disconnect(); + }; + }, [calculateItemsPerRow]); + // Virtualization with react-virtual library const rowVirtualizer = useVirtualizer({ - count: Math.ceil(items.length / ITEMS_PER_ROW), + count: Math.ceil(items.length / itemsPerRow), getScrollElement: () => containerRef.current?.closest('[data-scrolling-container]') as Element, estimateSize: () => ITEM_HEIGHT, overscan: OVERSCAN, @@ -64,8 +105,8 @@ const DragDropGrid = ({ }} > {rowVirtualizer.getVirtualItems().map((virtualRow) => { - const startIndex = virtualRow.index * ITEMS_PER_ROW; - const endIndex = Math.min(startIndex + ITEMS_PER_ROW, items.length); + const startIndex = virtualRow.index * itemsPerRow; + const endIndex = Math.min(startIndex + itemsPerRow, items.length); const rowItems = items.slice(startIndex, endIndex); return ( diff --git a/frontend/src/components/pageEditor/PageEditor.tsx b/frontend/src/components/pageEditor/PageEditor.tsx index 28b262376..71b5e5b7d 100644 --- a/frontend/src/components/pageEditor/PageEditor.tsx +++ b/frontend/src/components/pageEditor/PageEditor.tsx @@ -1179,7 +1179,7 @@ const PageEditor = ({ )} {showLoading && ( - + @@ -1215,7 +1215,7 @@ const PageEditor = ({ )} {displayDocument && ( - + {/* Enhanced Processing Status */} {globalProcessing && processingProgress < 100 && ( diff --git a/frontend/src/hooks/useThumbnailGeneration.ts b/frontend/src/hooks/useThumbnailGeneration.ts index 85dd91998..2fe92477b 100644 --- a/frontend/src/hooks/useThumbnailGeneration.ts +++ b/frontend/src/hooks/useThumbnailGeneration.ts @@ -19,7 +19,7 @@ let batchTimer: number | null = null; const activeRequests = new Map>(); // Batch processing configuration -const BATCH_SIZE = 50; // Process thumbnails in batches of 50 +const BATCH_SIZE = 20; // Process thumbnails in batches of 20 for better UI responsiveness const BATCH_DELAY = 100; // Wait 100ms to collect requests before processing const PRIORITY_BATCH_DELAY = 50; // Faster processing for the first batch (visible pages) diff --git a/frontend/src/services/thumbnailGenerationService.ts b/frontend/src/services/thumbnailGenerationService.ts index 9946fba9f..17f8faa9a 100644 --- a/frontend/src/services/thumbnailGenerationService.ts +++ b/frontend/src/services/thumbnailGenerationService.ts @@ -64,7 +64,7 @@ export class ThumbnailGenerationService { const allResults: ThumbnailResult[] = []; let completed = 0; - const batchSize = 5; // Small batches for UI responsiveness + const batchSize = 3; // Smaller batches for better UI responsiveness // Process pages in small batches for (let i = 0; i < pageNumbers.length; i += batchSize) {