feat: Design tab, live style editing, route-aware artboards, canvas onboarding

Design tab (4-tab inspector: Design / Props / Diff / Graph)
- Click any component in a live artboard to inspect computed CSS
- Typography, Layout, Visual sections auto-populated from getComputedStyle
- Every property is inline-editable; changes apply live via PATCH_ELEMENT_STYLE
- Zero source-code modifications — purely in-browser style overrides

Protocol additions (packages/renderer)
- REQUEST_ELEMENT_STYLES / ELEMENT_STYLES round-trip for CSS inspection
- PATCH_ELEMENT_STYLE for live style patching

Live SDK (packages/live-sdk)
- respondWithStyles(): reads 30 curated computed CSS properties
- patchElementStyle(): applies inline style override to fiber's DOM element

Canvas store
- selectedComponentStyles: current element's CSS map
- styleEditEvent mailbox: Design tab → LiveArtboard style dispatch (Zustand v5 compatible)

Route-aware artboards
- Each artboard now has an optional route (e.g. /dashboard)
- buildSrc(base, route) helper in Artboard.tsx
- Route field editable in Inspector Props tab, persisted to metadata_jsonb

On-canvas onboarding
- Empty canvas now shows 3-step guide: press A → CLI command → paste URL
- CLI command shown inline in a highlighted code block

Changelog and Handoff updated

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
SinachPat
2026-04-30 22:04:37 +01:00
co-authored by Claude Sonnet 4.6
parent 8514ffdc1a
commit edada3091e
10 changed files with 669 additions and 35 deletions
+23 -2
View File
@@ -30,6 +30,18 @@ interface CanvasStore {
selectedComponentId: string | null;
selectedComponentData: FiberNode | null;
selectComponent: (id: string | null, data: FiberNode | null) => void;
// ── Component computed styles (populated by ELEMENT_STYLES response) ────────
/** Computed CSS property map for the currently-selected component DOM element. */
selectedComponentStyles: Record<string, string> | null;
setComponentStyles: (styles: Record<string, string> | null) => void;
// ── Style edit mailbox ──────────────────────────────────────────────────────
// The Design tab drops a patch here; the owning LiveArtboard picks it up,
// forwards it to the iframe, then clears it.
styleEditEvent: { artboardId: string; nodeId: string; property: string; value: string } | null;
patchStyleEdit: (artboardId: string, nodeId: string, property: string, value: string) => void;
clearStyleEdit: () => void;
}
export const useCanvas = create<CanvasStore>((set) => ({
@@ -38,7 +50,7 @@ export const useCanvas = create<CanvasStore>((set) => ({
selectedArtboardId: null,
selectArtboard: (id) =>
set({ selectedArtboardId: id, selectedComponentId: null, selectedComponentData: null }),
set({ selectedArtboardId: id, selectedComponentId: null, selectedComponentData: null, selectedComponentStyles: null }),
workspaceId: null,
projectId: null,
@@ -58,5 +70,14 @@ export const useCanvas = create<CanvasStore>((set) => ({
selectedComponentId: null,
selectedComponentData: null,
selectComponent: (id, data) => set({ selectedComponentId: id, selectedComponentData: data }),
selectComponent: (id, data) =>
set({ selectedComponentId: id, selectedComponentData: data, selectedComponentStyles: null }),
selectedComponentStyles: null,
setComponentStyles: (styles) => set({ selectedComponentStyles: styles }),
styleEditEvent: null,
patchStyleEdit: (artboardId, nodeId, property, value) =>
set({ styleEditEvent: { artboardId, nodeId, property, value } }),
clearStyleEdit: () => set({ styleEditEvent: null }),
}));