Field editor: palette, select/move/resize/rotate, inspector, optimistic sync (#11) (#30)
Build image / build-and-push (push) Successful in 13s
Build image / build-and-push (push) Successful in 13s
Co-authored-by: Steve Dudenhoeffer <[email protected]>
This commit was merged in pull request #30.
This commit is contained in:
+28
-4
@@ -1,9 +1,10 @@
|
||||
import { create } from 'zustand'
|
||||
import type { Viewport } from '@/lib/geometry'
|
||||
import type { EditorObject } from './types'
|
||||
|
||||
// Ephemeral editor state only (per DESIGN § State): the viewport, the current
|
||||
// selection, and which object is "focused" (zoomed into for plops, #15). All
|
||||
// server state stays in react-query. Selection interactions grow in #11.
|
||||
// selection, the object being live-edited mid-gesture, and the palette kind
|
||||
// armed for tap-to-place. All server state stays in react-query.
|
||||
|
||||
export const MIN_SCALE = 0.05 // px per cm — fully zoomed out
|
||||
export const MAX_SCALE = 20 // px per cm — fully zoomed in
|
||||
@@ -17,16 +18,39 @@ interface EditorState {
|
||||
|
||||
focusedObjectId: number | null
|
||||
setFocusedObject: (id: number | null) => void
|
||||
|
||||
// During a move/resize/rotate, the object's live geometry is held here so the
|
||||
// canvas renders it instantly; the PATCH fires only on gesture end.
|
||||
liveObject: EditorObject | null
|
||||
setLiveObject: (o: EditorObject | null) => void
|
||||
|
||||
// The palette kind armed for tap-to-place (mobile-friendly; also set while
|
||||
// dragging a kind from the palette). null when nothing is armed.
|
||||
armedKind: string | null
|
||||
setArmedKind: (kind: string | null) => void
|
||||
|
||||
// True while an object move/resize/rotate is in progress, so the viewport's
|
||||
// pan gesture stands down (both listen on the same svg).
|
||||
objectDragging: boolean
|
||||
setObjectDragging: (v: boolean) => void
|
||||
}
|
||||
|
||||
export const useEditorStore = create<EditorState>((set) => ({
|
||||
viewport: { tx: 0, ty: 0, scale: 1 },
|
||||
setViewport: (next) =>
|
||||
set((s) => ({ viewport: typeof next === 'function' ? next(s.viewport) : next })),
|
||||
setViewport: (next) => set((s) => ({ viewport: typeof next === 'function' ? next(s.viewport) : next })),
|
||||
|
||||
selectedId: null,
|
||||
select: (id) => set({ selectedId: id }),
|
||||
|
||||
focusedObjectId: null,
|
||||
setFocusedObject: (id) => set({ focusedObjectId: id }),
|
||||
|
||||
liveObject: null,
|
||||
setLiveObject: (o) => set({ liveObject: o }),
|
||||
|
||||
armedKind: null,
|
||||
setArmedKind: (kind) => set({ armedKind: kind }),
|
||||
|
||||
objectDragging: false,
|
||||
setObjectDragging: (v) => set({ objectDragging: v }),
|
||||
}))
|
||||
|
||||
Reference in New Issue
Block a user