Image Studio: cover crop + unified gallery + konva annotation + avatar crop + logo upload - #146
Merged
important-new merged 29 commits intoJun 15, 2026
Merged
Conversation
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…sk 4) Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
- Renumber 0005_bent_gamma_corps -> 0006 to avoid collision with the pre-existing 0005_email_identity_and_signature migration from PR InspectorHub#145. Journal entry idx 5 / tag 0006_bent_gamma_corps; snapshot renamed to 0006_snapshot.json (prevId already chains off email-identity snapshot). - Wrap JSON.parse of the crop form field in try/catch so malformed JSON returns 400 BadRequest instead of an unhandled 500. - resolveCoverUrl: use ?? instead of || for coverImageKey fallback. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…r action (Task 8) Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…:hmr; Dependabot #14 left open)
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…rds) Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…p editor to PhotoAnnotator
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
File input now opens the round AvatarCropper instead of uploading the raw file; the baked 512² JPEG is submitted through the existing photoFetcher / photo-upload intent unchanged. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Logos keep their original format (transparent PNG/SVG): no crop, no bake. Just upload + object-contain fit preview. Part of the Image Studio effort. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Branch on intent before the conform parse (mirrors settings-profile's photo-upload). Relays the multipart logo to POST /api/admin/branding/logo via api.adminBranding.branding.logo.$post. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Replaces the dead file input with LogoUploader driven by a useFetcher. Optimistically reflects the new logoUrl on successful upload. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Reject logos over 2MB or outside png/svg/jpeg/webp before storing to R2. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…ered by overlay) Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Unified image module (
app/components/image-studio/) sharing crop/preview/bake primitives across the app.Features
CoverCropper(react-easy-crop): preset ratios (3:2/16:9/1.91:1/4:3) + landscape↔portrait swap + zoom + rule-of-thirds + live preview. Client bakes a 2048px JPEG →POST /api/inspections/:id/cover→ storescover_image_key+ re-editablecover_croptransform (migration 0006, additive). Report/OG/PDF read the baked key first, falling back to the uncropped source./mediaendpoint, with Set-as-cover / Annotate actions in the lightbox toolbar. Thin isolation wrappers around both single-maintainer libs.PhotoAnnotator(react-konva) replaces the hand-rolled SVG PhotoStudio render layer; circle/arrow/freehand/label/measure + zoom; now actually persists (composite PNG + node-tree JSON via the existingsaveAnnotationendpoint — previouslyonSavediscarded annotations).AvatarCropper(round 512² crop) on the inspector profile photo, reusing the shared bake util.LogoUploaderwith fit-preview, transparent PNG/SVG passthrough (no crop/bake), + backend size/MIME guard.Notes
0006is additive (ADD COLUMN cover_crop, cover_image_key) — no FK/recreate.🤖 Generated with Claude Code