diff --git a/HERO_EDITOR.md b/HERO_EDITOR.md index 0a3f50e..931d003 100644 --- a/HERO_EDITOR.md +++ b/HERO_EDITOR.md @@ -115,8 +115,16 @@ layout adapts across viewports without breakpoint data. `version` is validated add/remove lines, align) and buttons editor (label/path/variant, add/remove). Verified: select shows the line editor, editing a line updates the canvas live, drag moved 50%→65%, add→3/delete→2 elements, empty-canvas click deselects. -- **Phase 4 — moon + badge + image + resize + snap grid.** Remaining element types, - resize handles, 8px snap. *Exit:* place a moon and an uploaded image, resize, publish. +- **Phase 4 — moon + badge + image + resize + snap grid** ✅ (verified 2026-06-28). + Tray adds moon/badge/image; property panels (moon: size/glow/color; badge: + text/colors/radius; image: upload/width/alt); corner resize handle (image→width%, + moon→size, text→box width); 8px snap-grid toggle with overlay; image placeholder + until a file is chosen. Verified: each type adds + edits, resize moved a moon + 64→104px, snap grid shows, and a published moon+badge render on the live portal. + +**Status: v1 feature-complete.** All phases verified end-to-end; ready for PR. +Deferred (noted in the design doc as follow-ups): 8-point resize (only a corner +handle for now), per-viewport layouts, server-side image compression. ## 8. Edge cases (from the doc, carried forward) - `JSON.parse` wrapped in try/catch + `version` check → fall back to `DEFAULT_LAYOUT`. diff --git a/client/src/components/HeroElement.jsx b/client/src/components/HeroElement.jsx index 9dfa88e..496719a 100644 --- a/client/src/components/HeroElement.jsx +++ b/client/src/components/HeroElement.jsx @@ -79,6 +79,17 @@ function Badge({ props }) { } function HeroImage({ props }) { + if (!props.src) { + // Editor placeholder until an image is chosen (a srcless image never ships live). + return ( +
@@ -308,9 +372,9 @@ function ElementPanel({ element, onProps, onRemove, onForward, onBack, onDeselec
{element.type === 'text_block' &&
Editing controls for this element type arrive in the next phase.
- )} + {element.type === 'moon' &&