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

This commit is contained in:
Eric Gullickson
2026-02-06 22:15:39 -06:00
parent e4336ce9da
commit 75ce316aa5
2 changed files with 222 additions and 116 deletions

View File

@@ -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,