chore: Change crop to remove locked aspect ratio
All checks were successful
Deploy to Staging / Build Images (pull_request) Successful in 3m21s
Deploy to Staging / Deploy to Staging (pull_request) Successful in 22s
Deploy to Staging / Verify Staging (pull_request) Successful in 8s
Deploy to Staging / Notify Staging Ready (pull_request) Successful in 7s
Deploy to Staging / Notify Staging Failure (pull_request) Has been skipped
All checks were successful
Deploy to Staging / Build Images (pull_request) Successful in 3m21s
Deploy to Staging / Deploy to Staging (pull_request) Successful in 22s
Deploy to Staging / Verify Staging (pull_request) Successful in 8s
Deploy to Staging / Notify Staging Ready (pull_request) Successful in 7s
Deploy to Staging / Notify Staging Failure (pull_request) Has been skipped
This commit is contained in:
@@ -25,11 +25,13 @@ export const CropTool: React.FC<CropToolProps> = ({
|
||||
const imageAreaRef = useRef<HTMLDivElement>(null);
|
||||
const [imageMaxHeight, setImageMaxHeight] = useState(0);
|
||||
|
||||
const { cropArea, isDragging, resetCrop, executeCrop, handleDragStart } =
|
||||
const { cropArea, cropDrawn, isDragging, resetCrop, executeCrop, handleDragStart, handleDrawStart } =
|
||||
useImageCrop({
|
||||
aspectRatio: lockAspectRatio ? aspectRatio : undefined,
|
||||
});
|
||||
|
||||
const showCropArea = cropDrawn || (isDragging && cropArea.width > 1 && cropArea.height > 1);
|
||||
|
||||
// Measure available height for the image so the crop container
|
||||
// matches the rendered image exactly (fixes mobile crop offset)
|
||||
useEffect(() => {
|
||||
@@ -108,126 +110,150 @@ export const CropTool: React.FC<CropToolProps> = ({
|
||||
draggable={false}
|
||||
/>
|
||||
|
||||
{/* Draw surface for free-form rectangle drawing */}
|
||||
{!cropDrawn && (
|
||||
<Box
|
||||
onMouseDown={handleDrawStart}
|
||||
onTouchStart={handleDrawStart}
|
||||
sx={{
|
||||
position: 'absolute',
|
||||
inset: 0,
|
||||
cursor: 'crosshair',
|
||||
zIndex: 5,
|
||||
touchAction: 'none',
|
||||
}}
|
||||
/>
|
||||
)}
|
||||
|
||||
{/* Dark overlay outside crop area */}
|
||||
<Box
|
||||
sx={{
|
||||
position: 'absolute',
|
||||
inset: 0,
|
||||
pointerEvents: 'none',
|
||||
}}
|
||||
>
|
||||
{/* Top overlay */}
|
||||
<Box
|
||||
sx={{
|
||||
position: 'absolute',
|
||||
top: 0,
|
||||
left: 0,
|
||||
right: 0,
|
||||
height: `${cropArea.y}%`,
|
||||
backgroundColor: 'rgba(0, 0, 0, 0.6)',
|
||||
}}
|
||||
/>
|
||||
{/* Bottom overlay */}
|
||||
<Box
|
||||
sx={{
|
||||
position: 'absolute',
|
||||
bottom: 0,
|
||||
left: 0,
|
||||
right: 0,
|
||||
height: `${100 - cropArea.y - cropArea.height}%`,
|
||||
backgroundColor: 'rgba(0, 0, 0, 0.6)',
|
||||
}}
|
||||
/>
|
||||
{/* Left overlay */}
|
||||
<Box
|
||||
sx={{
|
||||
position: 'absolute',
|
||||
top: `${cropArea.y}%`,
|
||||
left: 0,
|
||||
width: `${cropArea.x}%`,
|
||||
height: `${cropArea.height}%`,
|
||||
backgroundColor: 'rgba(0, 0, 0, 0.6)',
|
||||
}}
|
||||
/>
|
||||
{/* Right overlay */}
|
||||
<Box
|
||||
sx={{
|
||||
position: 'absolute',
|
||||
top: `${cropArea.y}%`,
|
||||
right: 0,
|
||||
width: `${100 - cropArea.x - cropArea.width}%`,
|
||||
height: `${cropArea.height}%`,
|
||||
backgroundColor: 'rgba(0, 0, 0, 0.6)',
|
||||
}}
|
||||
/>
|
||||
</Box>
|
||||
|
||||
{/* Crop area with handles */}
|
||||
<Box
|
||||
sx={{
|
||||
position: 'absolute',
|
||||
top: `${cropArea.y}%`,
|
||||
left: `${cropArea.x}%`,
|
||||
width: `${cropArea.width}%`,
|
||||
height: `${cropArea.height}%`,
|
||||
border: '2px solid white',
|
||||
boxSizing: 'border-box',
|
||||
}}
|
||||
>
|
||||
{/* Move handle (center area) */}
|
||||
<CropHandleArea
|
||||
handle="move"
|
||||
onDragStart={handleDragStart}
|
||||
sx={{
|
||||
position: 'absolute',
|
||||
inset: 8,
|
||||
cursor: 'move',
|
||||
}}
|
||||
/>
|
||||
|
||||
{/* Corner handles */}
|
||||
<CropHandle handle="nw" onDragStart={handleDragStart} position="top-left" />
|
||||
<CropHandle handle="ne" onDragStart={handleDragStart} position="top-right" />
|
||||
<CropHandle handle="sw" onDragStart={handleDragStart} position="bottom-left" />
|
||||
<CropHandle handle="se" onDragStart={handleDragStart} position="bottom-right" />
|
||||
|
||||
{/* Edge handles */}
|
||||
<CropHandle handle="n" onDragStart={handleDragStart} position="top" />
|
||||
<CropHandle handle="s" onDragStart={handleDragStart} position="bottom" />
|
||||
<CropHandle handle="w" onDragStart={handleDragStart} position="left" />
|
||||
<CropHandle handle="e" onDragStart={handleDragStart} position="right" />
|
||||
|
||||
{/* Grid lines for alignment */}
|
||||
{showCropArea && (
|
||||
<Box
|
||||
sx={{
|
||||
position: 'absolute',
|
||||
inset: 0,
|
||||
display: 'grid',
|
||||
gridTemplateColumns: '1fr 1fr 1fr',
|
||||
gridTemplateRows: '1fr 1fr 1fr',
|
||||
pointerEvents: 'none',
|
||||
opacity: isDragging ? 1 : 0.5,
|
||||
transition: 'opacity 0.2s',
|
||||
}}
|
||||
>
|
||||
{Array.from({ length: 9 }).map((_, i) => (
|
||||
<Box
|
||||
key={i}
|
||||
sx={{
|
||||
borderRight: i % 3 !== 2 ? '1px solid rgba(255,255,255,0.3)' : 'none',
|
||||
borderBottom: i < 6 ? '1px solid rgba(255,255,255,0.3)' : 'none',
|
||||
}}
|
||||
/>
|
||||
))}
|
||||
{/* Top overlay */}
|
||||
<Box
|
||||
sx={{
|
||||
position: 'absolute',
|
||||
top: 0,
|
||||
left: 0,
|
||||
right: 0,
|
||||
height: `${cropArea.y}%`,
|
||||
backgroundColor: 'rgba(0, 0, 0, 0.6)',
|
||||
}}
|
||||
/>
|
||||
{/* Bottom overlay */}
|
||||
<Box
|
||||
sx={{
|
||||
position: 'absolute',
|
||||
bottom: 0,
|
||||
left: 0,
|
||||
right: 0,
|
||||
height: `${100 - cropArea.y - cropArea.height}%`,
|
||||
backgroundColor: 'rgba(0, 0, 0, 0.6)',
|
||||
}}
|
||||
/>
|
||||
{/* Left overlay */}
|
||||
<Box
|
||||
sx={{
|
||||
position: 'absolute',
|
||||
top: `${cropArea.y}%`,
|
||||
left: 0,
|
||||
width: `${cropArea.x}%`,
|
||||
height: `${cropArea.height}%`,
|
||||
backgroundColor: 'rgba(0, 0, 0, 0.6)',
|
||||
}}
|
||||
/>
|
||||
{/* Right overlay */}
|
||||
<Box
|
||||
sx={{
|
||||
position: 'absolute',
|
||||
top: `${cropArea.y}%`,
|
||||
right: 0,
|
||||
width: `${100 - cropArea.x - cropArea.width}%`,
|
||||
height: `${cropArea.height}%`,
|
||||
backgroundColor: 'rgba(0, 0, 0, 0.6)',
|
||||
}}
|
||||
/>
|
||||
</Box>
|
||||
</Box>
|
||||
)}
|
||||
|
||||
{/* Crop area border and handles */}
|
||||
{showCropArea && (
|
||||
<Box
|
||||
sx={{
|
||||
position: 'absolute',
|
||||
top: `${cropArea.y}%`,
|
||||
left: `${cropArea.x}%`,
|
||||
width: `${cropArea.width}%`,
|
||||
height: `${cropArea.height}%`,
|
||||
border: '2px solid white',
|
||||
boxSizing: 'border-box',
|
||||
}}
|
||||
>
|
||||
{/* Handles only appear after drawing is complete */}
|
||||
{cropDrawn && (
|
||||
<>
|
||||
{/* Move handle (center area) */}
|
||||
<CropHandleArea
|
||||
handle="move"
|
||||
onDragStart={handleDragStart}
|
||||
sx={{
|
||||
position: 'absolute',
|
||||
inset: 8,
|
||||
cursor: 'move',
|
||||
}}
|
||||
/>
|
||||
|
||||
{/* Corner handles */}
|
||||
<CropHandle handle="nw" onDragStart={handleDragStart} position="top-left" />
|
||||
<CropHandle handle="ne" onDragStart={handleDragStart} position="top-right" />
|
||||
<CropHandle handle="sw" onDragStart={handleDragStart} position="bottom-left" />
|
||||
<CropHandle handle="se" onDragStart={handleDragStart} position="bottom-right" />
|
||||
|
||||
{/* Edge handles */}
|
||||
<CropHandle handle="n" onDragStart={handleDragStart} position="top" />
|
||||
<CropHandle handle="s" onDragStart={handleDragStart} position="bottom" />
|
||||
<CropHandle handle="w" onDragStart={handleDragStart} position="left" />
|
||||
<CropHandle handle="e" onDragStart={handleDragStart} position="right" />
|
||||
</>
|
||||
)}
|
||||
|
||||
{/* Grid lines for alignment */}
|
||||
<Box
|
||||
sx={{
|
||||
position: 'absolute',
|
||||
inset: 0,
|
||||
display: 'grid',
|
||||
gridTemplateColumns: '1fr 1fr 1fr',
|
||||
gridTemplateRows: '1fr 1fr 1fr',
|
||||
pointerEvents: 'none',
|
||||
opacity: isDragging ? 1 : 0.5,
|
||||
transition: 'opacity 0.2s',
|
||||
}}
|
||||
>
|
||||
{Array.from({ length: 9 }).map((_, i) => (
|
||||
<Box
|
||||
key={i}
|
||||
sx={{
|
||||
borderRight: i % 3 !== 2 ? '1px solid rgba(255,255,255,0.3)' : 'none',
|
||||
borderBottom: i < 6 ? '1px solid rgba(255,255,255,0.3)' : 'none',
|
||||
}}
|
||||
/>
|
||||
))}
|
||||
</Box>
|
||||
</Box>
|
||||
)}
|
||||
</Box>
|
||||
</Box>
|
||||
|
||||
{/* Instructions */}
|
||||
<Box sx={{ px: 2, py: 1, textAlign: 'center' }}>
|
||||
<Typography variant="body2" sx={{ color: 'rgba(255, 255, 255, 0.7)' }}>
|
||||
Drag to adjust crop area
|
||||
{cropDrawn ? 'Drag handles to adjust crop area' : 'Tap and drag to select crop area'}
|
||||
</Typography>
|
||||
</Box>
|
||||
|
||||
@@ -255,7 +281,7 @@ export const CropTool: React.FC<CropToolProps> = ({
|
||||
onClick={handleReset}
|
||||
startIcon={<RefreshIcon />}
|
||||
sx={{ color: 'white' }}
|
||||
disabled={isProcessing}
|
||||
disabled={isProcessing || !cropDrawn}
|
||||
>
|
||||
Reset
|
||||
</Button>
|
||||
@@ -271,7 +297,7 @@ export const CropTool: React.FC<CropToolProps> = ({
|
||||
|
||||
<IconButton
|
||||
onClick={handleConfirm}
|
||||
disabled={isProcessing}
|
||||
disabled={isProcessing || !cropDrawn}
|
||||
aria-label="Confirm crop"
|
||||
sx={{
|
||||
width: 56,
|
||||
|
||||
Reference in New Issue
Block a user