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:
@@ -0,0 +1,49 @@
|
||||
import { cn } from '@/lib/cn'
|
||||
import { OBJECT_KINDS, kindDef } from './kinds'
|
||||
import { useEditorStore } from './store'
|
||||
|
||||
/**
|
||||
* The object-kind palette. Tap a kind to arm it, then tap the canvas to place
|
||||
* (works on desktop and touch). Tapping the armed kind again disarms it.
|
||||
*/
|
||||
export function Palette() {
|
||||
const armedKind = useEditorStore((s) => s.armedKind)
|
||||
const setArmedKind = useEditorStore((s) => s.setArmedKind)
|
||||
const select = useEditorStore((s) => s.select)
|
||||
|
||||
return (
|
||||
<div className="flex flex-col gap-2">
|
||||
<div className="flex flex-wrap gap-1.5 md:flex-col">
|
||||
{OBJECT_KINDS.map((k) => {
|
||||
const active = armedKind === k.kind
|
||||
return (
|
||||
<button
|
||||
key={k.kind}
|
||||
type="button"
|
||||
onClick={() => {
|
||||
select(null)
|
||||
setArmedKind(active ? null : k.kind)
|
||||
}}
|
||||
className={cn(
|
||||
'flex items-center gap-2 rounded-md border px-2.5 py-1.5 text-sm font-medium outline-none transition-colors',
|
||||
'focus-visible:ring-2 focus-visible:ring-accent/40',
|
||||
active
|
||||
? 'border-accent bg-accent/10 text-accent-strong'
|
||||
: 'border-border bg-surface text-fg hover:bg-border/50',
|
||||
)}
|
||||
aria-pressed={active}
|
||||
>
|
||||
<span aria-hidden className="text-base leading-none">
|
||||
{k.icon}
|
||||
</span>
|
||||
<span>{k.label}</span>
|
||||
</button>
|
||||
)
|
||||
})}
|
||||
</div>
|
||||
{armedKind && (
|
||||
<p className="text-xs text-muted">Tap the canvas to place a {kindDef(armedKind)?.label ?? 'object'}.</p>
|
||||
)}
|
||||
</div>
|
||||
)
|
||||
}
|
||||
Reference in New Issue
Block a user