Address Gadfly review on #15: real bugs + shared editor constants
Build image / build-and-push (push) Successful in 9s
Build image / build-and-push (push) Successful in 9s
Correctness / stuck-state: - PlopInspector: the planted date can now be cleared (blur commits null instead of being blocked); radius/count reset to the current value on invalid input. - applyPlantingPatch now applies removedAt too (completes the optimistic patch). - PlopMarker computes the count live from the current radius, so the on-canvas near-zoom label updates while resizing (not just the inspector). - GardenEditorPage clears focus when the focused object vanishes — deleted, or a stale ?focus id on load — so the canvas can't get stuck dimmed with no exit. - useRemovePlanting adopts the 409 current row, so a stale-version soft-remove can be retried instead of looping. - Placement is gated on plantable, so a deep-linked non-plantable focus can't try to POST a plop the server would 400. Dedup / perf (introduced by this PR): - editor/shared.ts: SELECT_COLOR, HANDLE_PX, MIN_RADIUS_CM, DIMMED_OPACITY, and an objectTransform() helper, now used by ObjectShape/SelectionOverlay/PlopLayer/ PlopOverlay/PlopMarker/GardenCanvas (unified the transform string + the two different dim opacities). - Dropped PlopMarker's always-false `dimmed` prop (dimming is at the group level). - Build plantsById once in the page and pass it to GardenCanvas. - Moved the livePlanting subscription into PlopInspector so a plop drag re-renders only the panel, not the whole page (matches the liveObject pattern). - Memoized PlopLayer's plop grouping so it doesn't rebuild every pan/zoom frame. Skipped: gesture-scaffolding hook extraction (risky churn in #11 code), elliptical clamp for circle objects (consistent with the server's rect bounds), optimistic create (matches useCreateObject). 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:
@@ -2,13 +2,11 @@ import { useEffect, useRef, type PointerEvent as ReactPointerEvent, type RefObje
|
||||
import { screenToWorld, worldToLocal, type Point } from '@/lib/geometry'
|
||||
import { useUpdatePlanting } from '@/lib/objects'
|
||||
import type { EditorPlanting } from '@/lib/plantings'
|
||||
import { HANDLE_PX, MIN_RADIUS_CM, SELECT_COLOR, objectTransform } from './shared'
|
||||
import { useEditorStore } from './store'
|
||||
import type { EditorObject } from './types'
|
||||
|
||||
const HANDLE_PX = 12
|
||||
const MIN_RADIUS_CM = 1
|
||||
const MAX_RADIUS_CM = 10_000
|
||||
const SELECT_COLOR = '#2f7a3e'
|
||||
|
||||
/**
|
||||
* Move/resize handles for the selected plop, rendered inside its parent object's
|
||||
@@ -127,7 +125,7 @@ export function PlopOverlay({
|
||||
|
||||
const r = plop.radiusCm
|
||||
return (
|
||||
<g transform={`translate(${object.xCm} ${object.yCm}) rotate(${object.rotationDeg})`}>
|
||||
<g transform={objectTransform(object)}>
|
||||
{/* Transparent body: drag to move (at least handle-sized so tiny plops stay grabbable). */}
|
||||
<circle
|
||||
cx={plop.xCm}
|
||||
|
||||
Reference in New Issue
Block a user