feat: image cropping / resizing T0

This commit is contained in:
fsylvain committed 2026-09-28 07:46:12 +02:00
1 parent cb05b38f36
commit e15f444603
18 files changed
+1869 -46

No files matched your search

+19 -3
View File
@@ -252,7 +252,7 @@ Responsive Below lg , the details panel becomes a right slideover, opened with i
### ImageUploader
Opens from the editor's image button in a small modal. Files are checked in the browser before anything is sent. After a successful upload the image goes in at the cursor and the modal closes.
Opens from the editor's image button in a small modal. Files are checked in the browser before anything is sent. A JPEG, PNG or WEBP then goes through a crop-and-resize step before it uploads; an SVG skips straight to uploading. After a successful upload the image goes in at the cursor and the modal closes.
Drop an image here Choose file PNG, JPEG, WEBP, SVG · max 10 MB
@@ -262,9 +262,21 @@ Drop to upload
dragging over
north-wall.jpg 62%
Crop and resize north-wall.jpg · 3.9 MB
Uploading 2.4 of 3.9 MB
crop, default: whole image selected, width "1600 px"
Crop and resize north-wall.jpg · 3.9 MB
crop, ratio locked to 16:9
Crop and resize north-wall.jpg · 3.9 MB
crop, crop narrower than the chosen width
north-wall.jpg 43%
Uploading 180 of 420 KB
uploading
@@ -282,6 +294,10 @@ server error
Built from UModal title="Add an image" › UFileUpload accept="image/png,image/jpeg,image/webp,image/svg+xml" :multiple="false" layout="list" + UProgress size="xs" . Uploads go through XMLHttpRequest , because fetch has no upload progress, as FormData with the field name file . The 201 location is inserted with insertImage(location, '') .
Crop and resize A JPEG, PNG or WEBP opens on a 640px-wide modal (`md.crop`) between the file picker and the upload, replacing the "Add an image" title with "Crop and resize" and the filename/size as the description. The stage shows the image with the crop frame starting as the whole image: a rule-of-thirds grid (lines at 33.3 %/66.6 %), four 12×12 px corner handles, and a pixel-size label (mono, bottom-left, dark pill) that tracks the frame's current size. The frame is `tabindex="0"`, `aria-label="Crop area. Arrow keys move it, Shift and arrow keys resize it."`; dragging moves it, dragging a handle resizes it, arrow keys nudge it by 1 px and Shift+arrow keys resize it.
Aspect ratio is a `radiogroup` of five pills — Original, Free, 16:9, 4:3, 1:1 — plus Rotate and Reset actions above it. Width is a second `radiogroup` — Original, 1600 px (default), 1200 px, 800 px. A mono line below reads "Uploads as {width} × {height} px · about {size}", where the estimated size is shown in KB under 1 MB and in MB above it. When the chosen width is larger than the crop's own width, the output stays at the crop's size (never upscaled) and an info row explains why: "The crop is {crop width} px wide, so it's uploaded at that size. Enlarging it would make it blurry." The footer becomes "Choose another file" (back to the file picker, `data-act="upload-pick"` from `idle`) and "Upload image" (starts the upload with the cropped, resized file). SVGs never see this step: they upload as soon as they're chosen. The "in progress" state afterwards reports the resized file's size, e.g. "Uploading 180 of 420 KB".
Validation Before uploading, the uploader checks both the MIME type and the file extension, and that size ≤ 10 × 1024 × 1024 . The size error names the file size: "north-wall.tif is 14.2 MB. Images can be up to 10 MB." A server 400 shows the same message as a client-side rejection.
Props, emits articleId: number . Emits uploaded(location) , close . A 401 hands off to the global session flow. A 404 means the article was deleted, which the editor handles.