Add plops editor: focus mode, place/move/resize, semantic zoom (#15)
Pansy's core vision: click into a bed, plop plants in its corners, zoom out and still see what's planted where. Built on the field editor (#11), PlantPicker (#13), and plantings API (#14). Data layer - lib/plantings.ts: ServerPlanting zod shape, EditorPlanting, effectiveCount, and a client mirror of the derived-count formula (computeDerivedCount) for live resize display; unit-tested. - lib/objects.ts: /full now types plantings + plants; useCreatePlanting / useUpdatePlanting / useRemovePlanting patch the same FullGarden cache with the #11 optimistic + 409-rollback contract. A soft-remove drops the plop from the active list. Editor - store: selectedPlantingId / livePlanting / armedPlant (mutually-exclusive object vs plop selection). - Focus mode: "Plant here" (object inspector) → focusedObjectId; the canvas animates fitToRect to the object and dims the rest; a breadcrumb / Escape / empty-tap exits. focusedObjectId mirrors to ?focus (deep-linkable, survives reload). - Placing: "+ Add plant" opens the PlantPicker; the chosen plant stays armed for repeat placement; tapping inside the focused object drops a plop (default radius max(1.5·spacing, 15cm)) in the object's local frame. - Manipulating: PlopOverlay (drag to move, edge handle to resize, one PATCH per gesture) + PlopInspector (change plant, radius, count override vs live derived, label, planted date, soft-remove). - PlopMarker semantic zoom (px/cm bands): far = flat color patch + a dominant- plant tint on the object; mid = circle + emoji; near = + name + count. Plops render inside each object's rotated group, so moving/rotating a bed carries them with no planting writes. tsc --noEmit clean; 24/24 vitest; production build green. Co-Authored-By: Claude Opus 4.8 (1M context) <[email protected]> Claude-Session: https://claude.ai/code/session_01JdQpdYYsTgtkJBxbcpAszi
This commit is contained in:
@@ -26,10 +26,12 @@ export function Inspector({
|
||||
object,
|
||||
gardenId,
|
||||
unit,
|
||||
onFocus,
|
||||
}: {
|
||||
object: EditorObject
|
||||
gardenId: number
|
||||
unit: UnitPref
|
||||
onFocus?: () => void
|
||||
}) {
|
||||
const update = useUpdateObject(gardenId)
|
||||
const del = useDeleteObject(gardenId)
|
||||
@@ -94,6 +96,12 @@ export function Inspector({
|
||||
</button>
|
||||
</div>
|
||||
|
||||
{object.plantable && onFocus && (
|
||||
<Button onClick={onFocus} className="w-full">
|
||||
🌱 Plant here
|
||||
</Button>
|
||||
)}
|
||||
|
||||
<TextField
|
||||
label="Name"
|
||||
name="name"
|
||||
|
||||
Reference in New Issue
Block a user