This turns the canvas foundation (#9) into the real field editor: load a garden from the server, drag object kinds in from a palette, and select/move/resize/rotate them with changes synced optimistically. After this issue, the "landscaping UI" half of pansy's vision works end-to-end; plops inside beds come in #15.
Scope
Wire GardenCanvas into /gardens/:id via react-query on GET /gardens/:id/full; delete the mock-data demo route.
Palette (web/src/editor/Palette.tsx): the seven object kinds with icons + sensible default sizes (bed 120×240 cm, grow bag ⌀40, container ⌀60, in-ground 200×200, tree ⌀300 canopy, path 100×300, structure 200×200). Desktop: drag from palette onto the canvas. Mobile: tap a kind → tap the canvas to place. POST on placement.
Selection: click/tap an object → selection outline + handles; click empty space clears. Drag body to move; corner handles resize (center-compensated so the opposite edge stays put); a rotate handle above the object snaps to 15° with Shift/long-press for free rotation; Delete/Backspace (with confirm for plantable objects that contain plantings).
Inspector (web/src/editor/Inspector.tsx): desktop right panel / mobile bottom sheet for the selected object — name, kind (read-only), dimensions + position (unit-aware inputs), rotation, color override, notes, plantable toggle, delete.
Optimistic sync: local state moves instantly during gestures; one PATCH on gesture end carrying version; on 409, roll back to the server's current row, refetch, and toast "updated elsewhere". Queue-depth 1 per object (drop intermediate states).
?focus=objectId param: on load, zoomToFit that object (groundwork for #15's focus mode).
z-order: paths/structures render under beds; explicit z_index respected; no UI for reordering yet (Inspector numeric input is fine).
Desktop: drag a bed from the palette, move/resize/rotate it, set its name in the inspector, reload — everything persisted.
Phone: place and move an object with touch; inspector opens as a bottom sheet; pinch-zoom still works while an object is selected.
Open the same garden in two browsers, move the same object in both → the loser gets a rollback + toast, no silent divergence.
Network tab shows one PATCH per completed gesture, not a stream.
Part of epic #20 · Design: [DESIGN.md](https://gitea.stevedudenhoeffer.com/steve/pansy/src/branch/main/DESIGN.md)
## Context
This turns the canvas foundation (#9) into the real field editor: load a garden from the server, drag object kinds in from a palette, and select/move/resize/rotate them with changes synced optimistically. After this issue, the "landscaping UI" half of pansy's vision works end-to-end; plops inside beds come in #15.
## Scope
- [ ] Wire `GardenCanvas` into `/gardens/:id` via react-query on `GET /gardens/:id/full`; delete the mock-data demo route.
- [ ] `Palette` (`web/src/editor/Palette.tsx`): the seven object kinds with icons + sensible default sizes (bed 120×240 cm, grow bag ⌀40, container ⌀60, in-ground 200×200, tree ⌀300 canopy, path 100×300, structure 200×200). Desktop: drag from palette onto the canvas. Mobile: tap a kind → tap the canvas to place. POST on placement.
- [ ] Selection: click/tap an object → selection outline + handles; click empty space clears. Drag body to move; corner handles resize (center-compensated so the opposite edge stays put); a rotate handle above the object snaps to 15° with Shift/long-press for free rotation; Delete/Backspace (with confirm for plantable objects that contain plantings).
- [ ] `Inspector` (`web/src/editor/Inspector.tsx`): desktop right panel / mobile bottom sheet for the selected object — name, kind (read-only), dimensions + position (unit-aware inputs), rotation, color override, notes, plantable toggle, delete.
- [ ] Optimistic sync: local state moves instantly during gestures; **one PATCH on gesture end** carrying `version`; on 409, roll back to the server's `current` row, refetch, and toast "updated elsewhere". Queue-depth 1 per object (drop intermediate states).
- [ ] `?focus=objectId` param: on load, `zoomToFit` that object (groundwork for #15's focus mode).
- [ ] z-order: paths/structures render under beds; explicit `z_index` respected; no UI for reordering yet (Inspector numeric input is fine).
## Out of scope
- Plops/focus interactions (#15). Read-only viewer mode (#17). Undo/redo (post-v1). Multi-select.
## Key files & patterns
- Gestures/viewport from #9; API + 409 envelope from #7/#10; component map in `DESIGN.md` § Frontend layout.
## Dependencies
Blocked by #8, #9, #10.
## Acceptance criteria
- Desktop: drag a bed from the palette, move/resize/rotate it, set its name in the inspector, reload — everything persisted.
- Phone: place and move an object with touch; inspector opens as a bottom sheet; pinch-zoom still works while an object is selected.
- Open the same garden in two browsers, move the same object in both → the loser gets a rollback + toast, no silent divergence.
- Network tab shows one PATCH per completed gesture, not a stream.
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.
Part of epic #20 · Design: DESIGN.md
Context
This turns the canvas foundation (#9) into the real field editor: load a garden from the server, drag object kinds in from a palette, and select/move/resize/rotate them with changes synced optimistically. After this issue, the "landscaping UI" half of pansy's vision works end-to-end; plops inside beds come in #15.
Scope
GardenCanvasinto/gardens/:idvia react-query onGET /gardens/:id/full; delete the mock-data demo route.Palette(web/src/editor/Palette.tsx): the seven object kinds with icons + sensible default sizes (bed 120×240 cm, grow bag ⌀40, container ⌀60, in-ground 200×200, tree ⌀300 canopy, path 100×300, structure 200×200). Desktop: drag from palette onto the canvas. Mobile: tap a kind → tap the canvas to place. POST on placement.Inspector(web/src/editor/Inspector.tsx): desktop right panel / mobile bottom sheet for the selected object — name, kind (read-only), dimensions + position (unit-aware inputs), rotation, color override, notes, plantable toggle, delete.version; on 409, roll back to the server'scurrentrow, refetch, and toast "updated elsewhere". Queue-depth 1 per object (drop intermediate states).?focus=objectIdparam: on load,zoomToFitthat object (groundwork for #15's focus mode).z_indexrespected; no UI for reordering yet (Inspector numeric input is fine).Out of scope
Key files & patterns
DESIGN.md§ Frontend layout.Dependencies
Blocked by #8, #9, #10.
Acceptance criteria