From 3243be433f212c4ed6cbfa38fff7c2aa7ac6ef62 Mon Sep 17 00:00:00 2001 From: Jean-Luc Makiola Date: Sun, 15 Mar 2026 17:11:18 +0100 Subject: [PATCH] feat(05-01): redesign ImageUpload as hero area and move to top of forms - Full-width 4:3 aspect ratio hero image area with rounded corners - Placeholder state: gray background with ImagePlus icon and helper text - Preview state: object-cover image with circular X remove button - Upload state: semi-transparent spinner overlay - Entire area clickable to upload/replace image - Moved ImageUpload to first element in both ItemForm and CandidateForm - Removed redundant "Image" label wrappers Co-Authored-By: Claude Opus 4.6 (1M context) --- src/client/components/CandidateForm.tsx | 21 +-- src/client/components/ImageUpload.tsx | 208 +++++++++++++++--------- src/client/components/ItemForm.tsx | 21 +-- 3 files changed, 146 insertions(+), 104 deletions(-) diff --git a/src/client/components/CandidateForm.tsx b/src/client/components/CandidateForm.tsx index c0b2ad5..a34c273 100644 --- a/src/client/components/CandidateForm.tsx +++ b/src/client/components/CandidateForm.tsx @@ -134,6 +134,14 @@ export function CandidateForm({ return (
+ {/* Image */} + + setForm((f) => ({ ...f, imageFilename: filename })) + } + /> + {/* Name */}
- ); + function handleRemove(e: React.MouseEvent) { + e.stopPropagation(); + onChange(null); + } + + return ( +
+ {/* Hero image area */} +
inputRef.current?.click()} + className="relative w-full aspect-[4/3] rounded-xl overflow-hidden cursor-pointer group" + > + {value ? ( + <> + Item + {/* Remove button */} + + + ) : ( +
+ {/* ImagePlus icon */} + + + + + + + + + Click to add photo + +
+ )} + + {/* Upload spinner overlay */} + {uploading && ( +
+ + + + +
+ )} +
+ + + {error &&

{error}

} +
+ ); } diff --git a/src/client/components/ItemForm.tsx b/src/client/components/ItemForm.tsx index 7d6cc87..15e8211 100644 --- a/src/client/components/ItemForm.tsx +++ b/src/client/components/ItemForm.tsx @@ -118,6 +118,14 @@ export function ItemForm({ mode, itemId }: ItemFormProps) { return ( + {/* Image */} + + setForm((f) => ({ ...f, imageFilename: filename })) + } + /> + {/* Name */}