diff --git a/frontend/src/components/tools/crop/CropAreaSelector.tsx b/frontend/src/components/tools/crop/CropAreaSelector.tsx index ead99d234..d92f464cd 100644 --- a/frontend/src/components/tools/crop/CropAreaSelector.tsx +++ b/frontend/src/components/tools/crop/CropAreaSelector.tsx @@ -43,7 +43,7 @@ const CropAreaSelector: React.FC = ({ // Convert PDF crop area to DOM coordinates for display const domRect = pdfToDOMCoordinates(cropArea, pdfBounds); - // Handle mouse down on overlay (start dragging) + // Handle mouse down on overlay (start dragging or resizing) const handleOverlayMouseDown = useCallback((e: React.MouseEvent) => { if (disabled || !containerRef.current) return; @@ -54,18 +54,18 @@ const CropAreaSelector: React.FC = ({ const x = e.clientX - rect.left; const y = e.clientY - rect.top; - // Check if we're clicking on a resize handle + // Check if we're clicking on a resize handle first (higher priority) const handle = getResizeHandle(x, y, domRect); if (handle) { setIsResizing(handle); setInitialCropArea(cropArea); - } else { - // Check if we're clicking within the crop area for dragging - if (isPointInCropArea(x, y, domRect)) { - setIsDragging(true); - setDragStart({ x: x - domRect.x, y: y - domRect.y }); - } + setIsDragging(false); // Ensure we're not dragging when resizing + } else if (isPointInCropArea(x, y, domRect)) { + // Only allow dragging if we're not on a resize handle + setIsDragging(true); + setIsResizing(null); // Ensure we're not resizing when dragging + setDragStart({ x: x - domRect.x, y: y - domRect.y }); } }, [disabled, cropArea, domRect]); @@ -211,15 +211,15 @@ const CropAreaSelector: React.FC = ({ function getResizeHandle(x: number, y: number, domRect: DOMRect): ResizeHandle { const handleSize = 8; - const tolerance = 4; + const tolerance = handleSize; - // Corner handles + // Corner handles (check these first, they have priority) if (isNear(x, domRect.x, tolerance) && isNear(y, domRect.y, tolerance)) return 'nw'; if (isNear(x, domRect.x + domRect.width, tolerance) && isNear(y, domRect.y, tolerance)) return 'ne'; if (isNear(x, domRect.x, tolerance) && isNear(y, domRect.y + domRect.height, tolerance)) return 'sw'; if (isNear(x, domRect.x + domRect.width, tolerance) && isNear(y, domRect.y + domRect.height, tolerance)) return 'se'; - // Edge handles + // Edge handles (only if not in corner area) if (isNear(x, domRect.x + domRect.width / 2, tolerance) && isNear(y, domRect.y, tolerance)) return 'n'; if (isNear(x, domRect.x + domRect.width, tolerance) && isNear(y, domRect.y + domRect.height / 2, tolerance)) return 'e'; if (isNear(x, domRect.x + domRect.width / 2, tolerance) && isNear(y, domRect.y + domRect.height, tolerance)) return 's'; diff --git a/frontend/src/components/tools/crop/CropSettings.tsx b/frontend/src/components/tools/crop/CropSettings.tsx index b5506bec8..aa2d1fdc1 100644 --- a/frontend/src/components/tools/crop/CropSettings.tsx +++ b/frontend/src/components/tools/crop/CropSettings.tsx @@ -1,28 +1,24 @@ -import React, { useMemo, useState, useEffect } from "react"; +import { useMemo, useState, useEffect } from "react"; import { Stack, Text, Box, Group, NumberInput, ActionIcon, Center, Alert } from "@mantine/core"; import { useTranslation } from "react-i18next"; import RestartAltIcon from "@mui/icons-material/RestartAlt"; -import InfoIcon from "@mui/icons-material/Info"; import { CropParametersHook } from "../../../hooks/tools/crop/useCropParameters"; import { useSelectedFiles } from "../../../contexts/file/fileHooks"; -import { useFileContext } from "../../../contexts/FileContext"; -import DocumentThumbnail from "../../shared/filePreview/DocumentThumbnail"; import CropAreaSelector from "./CropAreaSelector"; import { calculatePDFBounds, PDFBounds, - CropArea, - getPDFAspectRatio, - createFullPDFCropArea + CropArea } from "../../../utils/cropCoordinates"; import { pdfWorkerManager } from "../../../services/pdfWorkerManager"; +import DocumentThumbnail from "../../shared/filePreview/DocumentThumbnail"; interface CropSettingsProps { parameters: CropParametersHook; disabled?: boolean; } -const CONTAINER_SIZE = 400; // Larger container for better crop precision +const CONTAINER_SIZE = 250; // Fit within actual pane width const CropSettings = ({ parameters, disabled = false }: CropSettingsProps) => { const { t } = useTranslation(); @@ -41,7 +37,6 @@ const CropSettings = ({ parameters, disabled = false }: CropSettingsProps) => { // Get thumbnail for the selected file const [thumbnail, setThumbnail] = useState(null); const [pdfBounds, setPdfBounds] = useState(null); - const [loading, setLoading] = useState(false); useEffect(() => { const loadPDFDimensions = async () => { @@ -52,7 +47,6 @@ const CropSettings = ({ parameters, disabled = false }: CropSettingsProps) => { } setThumbnail(selectedStub.thumbnailUrl || null); - setLoading(true); try { // Get PDF dimensions from the actual file @@ -95,8 +89,6 @@ const CropSettings = ({ parameters, disabled = false }: CropSettingsProps) => { if (parameters.parameters.width === 595 && parameters.parameters.height === 842) { parameters.resetToFullPDF(bounds); } - } finally { - setLoading(false); } }; @@ -106,6 +98,7 @@ const CropSettings = ({ parameters, disabled = false }: CropSettingsProps) => { // Current crop area const cropArea = parameters.getCropArea(); + // Handle crop area changes from the selector const handleCropAreaChange = (newCropArea: CropArea) => { if (pdfBounds) { @@ -139,19 +132,6 @@ const CropSettings = ({ parameters, disabled = false }: CropSettingsProps) => { return Math.round((cropAreaSize / totalArea) * 100); }, [cropArea, pdfBounds]); - // Get aspect ratio information - const aspectRatioInfo = useMemo(() => { - if (!pdfBounds) return null; - const pdfRatio = getPDFAspectRatio(pdfBounds); - const cropRatio = cropArea.width / cropArea.height; - - return { - pdf: pdfRatio.toFixed(2), - crop: cropRatio.toFixed(2), - orientation: pdfRatio > 1 ? 'Landscape' : 'Portrait' - }; - }, [pdfBounds, cropArea]); - if (!selectedStub || !pdfBounds) { return (
@@ -222,14 +202,6 @@ const CropSettings = ({ parameters, disabled = false }: CropSettingsProps) => { {t("crop.info.percentage", "Area: {{percentage}}%", { percentage: cropPercentage })} - {aspectRatioInfo && ( - - {t("crop.info.ratio", "Ratio: {{ratio}} ({{orientation}})", { - ratio: aspectRatioInfo.crop, - orientation: parseFloat(aspectRatioInfo.crop) > 1 ? 'Landscape' : 'Portrait' - })} - - )} @@ -289,28 +261,6 @@ const CropSettings = ({ parameters, disabled = false }: CropSettingsProps) => { /> - {/* PDF Dimensions Info */} - } - color="blue" - variant="light" - style={{ fontSize: '0.75rem' }} - > - - {t("crop.info.pdfDimensions", "PDF Size: {{width}} × {{height}} points", { - width: Math.round(pdfBounds.actualWidth), - height: Math.round(pdfBounds.actualHeight) - })} - - {aspectRatioInfo && ( - - {t("crop.info.aspectRatio", "Aspect Ratio: {{ratio}} ({{orientation}})", { - ratio: aspectRatioInfo.pdf, - orientation: aspectRatioInfo.orientation - })} - - )} - {/* Validation Alert */} {!isCropValid && ( diff --git a/frontend/src/utils/cropCoordinates.ts b/frontend/src/utils/cropCoordinates.ts index ce961ab98..5309a9734 100644 --- a/frontend/src/utils/cropCoordinates.ts +++ b/frontend/src/utils/cropCoordinates.ts @@ -59,7 +59,7 @@ export const calculatePDFBounds = ( const thumbnailWidth = actualPDFWidth * scale; const thumbnailHeight = actualPDFHeight * scale; - // Calculate centering offsets + // Calculate centering offsets - these represent where the thumbnail is positioned within the container const offsetX = (containerWidth - thumbnailWidth) / 2; const offsetY = (containerHeight - thumbnailHeight) / 2;