Add image cropping to uploads (profile, event, …) #120
Labels
No labels
app:activities
app:chat
app:events
app:forum
app:libra
app:market
app:restaurant
app:tasks
app:wallet
app:webapp
bug
enhancement
No milestone
No project
No assignees
1 participant
Notifications
Due date
No due date set.
Dependencies
No dependencies set.
Reference
aiolabs/webapp#120
Loading…
Add table
Add a link
Reference in a new issue
No description provided.
Delete branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
From the 17 Jun design review: when adding any photo (profile, event, etc.), let the user crop the area they want.
Current state
src/modules/base/components/ImageUpload.vue(shared across profile/event/market) already does client-side resize + re-encode (1920px max edge, WebP, ~1MB) via the image service — but there's no interactive crop. No crop library is installed. The pipeline is:handleFileSelect/handleDrop→uploadFiles(files)→imageService.uploadImages(files, { compress }).Proposed approach
Insert a crop step between file-select and the existing compress→upload:
uploadFiles()→ resize/encode → upload (unchanged downstream).Decision (resolved 2026-06-24): Cropper.js v2, integrated directly — no wrapper
The original suggestion (
vue-advanced-cropper, "recommended / maintained") was wrong on maintenance and is dropped. Library health was re-checked against the npm registry (not SEO comparison articles, which are stale here):^1(v1, maintenance-mode) — does NOT get you v2Why direct, not a wrapper: the only maintained Vue wrapper (
vue-picture-cropper) is pinned to cropperjs v1; there is no maintained Vue wrapper on v2. Cropper.js v2 is a TypeScript rewrite shipped as framework-agnostic Web Components, so the cleanest path is to drive it from a small Vue component via a ref + lifecycle — one maximally-supported MIT dependency, no wrapper layer to go stale, integration we control.Verified against v2 source/docs:
import Cropper from 'cropperjs'(default export =Cropperclass).new Cropper(img, { container }).cropper.getCropperSelection()→CropperSelection;selection.aspectRatio/selection.initialCoverage;await selection.$toCanvas()→HTMLCanvasElement→canvas.toBlob(cb, 'image/webp', q).<cropper-*>elements are created in JS, never written in a Vue template), noapp.config.compilerOptions.isCustomElementchange is needed — the Vue template compiler never sees custom elements.pnpm add cropperjs@^2.Integration sketch
1. New
ImageCropDialog.vue(base module) — a thin Cropper.js v2 wrapper:2. Wire into
ImageUpload.vue— intercept selected files when cropping is enabled, then hand the cropped File(s) to the existinguploadFiles()(downstream untouched):Call sites: avatar (
ProfileSettings) →<ImageUpload crop :crop-aspect-ratio="1" />; event banner →:crop-aspect-ratio="16/9"; market/free →cropwith no ratio. Multi-image uploads crop sequentially via the queue.Notes / open implementation details
<cropper-canvas>and rebuild on each newsrc(handled above via:key+getCropperCanvas().remove()). Worth a careful review.ImageUpload.vuestay; the crop dialog sits inside the same component so those guards still wrap the flow.cropperjs@^2); tree-shakeable, import-on-demand.From the 2026-06-17 webapp design review. Decision corrected 2026-06-24 after re-verifying library maintenance against the npm registry.