@dfosco/storyboard-core 4.2.0-beta.2 → 4.2.0-beta.21
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/commandpalette.config.json +109 -24
- package/dist/storyboard-ui.css +1 -1
- package/dist/storyboard-ui.js +17379 -28568
- package/dist/storyboard-ui.js.map +1 -1
- package/dist/tailwind.css +1 -1
- package/package.json +5 -2
- package/scaffold/agents/prompt-agent.agent.md +181 -0
- package/scaffold/agents/terminal-agent.agent.md +351 -0
- package/scaffold/codex/config.toml +246 -0
- package/scaffold/manifest.json +5 -0
- package/scaffold/skills/canvas/SKILL.md +5 -4
- package/scaffold/skills/ship/SKILL.md +1 -1
- package/scaffold/storyboard.config.json +14 -1
- package/scaffold/toolbar.config.json +1 -1
- package/src/ActionMenuButton.jsx +100 -0
- package/src/AutosyncMenuButton.css +67 -0
- package/src/AutosyncMenuButton.jsx +241 -0
- package/src/BranchSelect.jsx +29 -0
- package/src/BranchSelect.module.css +30 -0
- package/src/CanvasAgentsMenu.jsx +87 -0
- package/src/CanvasCreateMenu.jsx +609 -0
- package/src/CanvasSnap.css +27 -0
- package/src/CanvasSnap.jsx +51 -0
- package/src/CanvasUndoRedo.css +36 -0
- package/src/CanvasUndoRedo.jsx +62 -0
- package/src/CanvasZoomControl.css +53 -0
- package/src/CanvasZoomControl.jsx +49 -0
- package/src/CanvasZoomToFit.css +18 -0
- package/src/CanvasZoomToFit.jsx +26 -0
- package/src/CommandMenu.css +8 -0
- package/src/CommandMenu.jsx +286 -0
- package/src/CommandPalette.jsx +35 -0
- package/src/CommandPaletteTrigger.jsx +25 -0
- package/src/CommentsMenuButton.jsx +38 -0
- package/src/CoreUIBar.css +47 -0
- package/src/CoreUIBar.jsx +855 -0
- package/src/CreateMenuButton.jsx +116 -0
- package/src/HideChromeTrigger.jsx +40 -0
- package/src/InspectorPanel.css +109 -0
- package/src/InspectorPanel.jsx +629 -0
- package/src/PwaInstallBanner.css +42 -0
- package/src/PwaInstallBanner.jsx +124 -0
- package/src/SidePanel.jsx +260 -0
- package/src/ThemeMenuButton.jsx +136 -0
- package/src/autosync/server.js +202 -5
- package/src/autosync/server.test.js +112 -0
- package/src/canvas/__tests__/agent-integration.test.js +593 -0
- package/src/canvas/__tests__/helpers/browser.js +95 -0
- package/src/canvas/__tests__/helpers/canvas-api.js +129 -0
- package/src/canvas/__tests__/helpers/perf.js +118 -0
- package/src/canvas/__tests__/helpers/setup.js +176 -0
- package/src/canvas/__tests__/helpers/tmux.js +130 -0
- package/src/canvas/__tests__/helpers/transcript.js +129 -0
- package/src/canvas/__tests__/terminal-integration.test.js +175 -0
- package/src/canvas/hot-pool.js +757 -0
- package/src/canvas/materializer.js +31 -0
- package/src/canvas/materializer.test.js +56 -0
- package/src/canvas/selectedWidgets.js +65 -7
- package/src/canvas/server.js +1801 -22
- package/src/canvas/server.test.js +239 -0
- package/src/canvas/terminal-config.js +331 -0
- package/src/canvas/terminal-registry.js +38 -0
- package/src/canvas/terminal-server.js +1037 -29
- package/src/canvas/writeGuard.js +51 -3
- package/src/canvasConfig.js +67 -1
- package/src/canvasConfig.test.js +79 -1
- package/src/cli/agent.js +85 -0
- package/src/cli/branch.js +232 -0
- package/src/cli/canvasAdd.js +59 -12
- package/src/cli/canvasBatch.js +98 -0
- package/src/cli/canvasBounds.js +1 -1
- package/src/cli/canvasRead.js +1 -1
- package/src/cli/canvasUpdate.js +179 -0
- package/src/cli/create.js +38 -14
- package/src/cli/dev.js +157 -83
- package/src/cli/exit.js +23 -24
- package/src/cli/index.js +55 -2
- package/src/cli/proxy.js +96 -37
- package/src/cli/schemas.js +22 -4
- package/src/cli/server.js +148 -25
- package/src/cli/serverUrl.js +8 -3
- package/src/cli/sessions.js +131 -5
- package/src/cli/setup.js +109 -11
- package/src/cli/terminal-commands.js +16 -8
- package/src/cli/terminal-messaging.js +231 -0
- package/src/cli/terminal-welcome.js +365 -33
- package/src/commandActions.js +1 -0
- package/src/commandPaletteConfig.js +9 -0
- package/src/comments/auth.js +2 -1
- package/src/comments/ui/AuthModal.jsx +114 -0
- package/src/comments/ui/CommentWindow.jsx +329 -0
- package/src/comments/ui/CommentsDrawer.jsx +102 -0
- package/src/comments/ui/Composer.jsx +64 -0
- package/src/comments/ui/authModal.test.js +1 -1
- package/src/comments/ui/commentWindow.js +16 -17
- package/src/comments/ui/commentsDrawer.js +25 -26
- package/src/comments/ui/composer.js +23 -24
- package/src/comments/ui/index.js +2 -3
- package/src/configSchema.js +59 -1
- package/src/configStore.js +161 -0
- package/src/core-ui-colors.css +12 -0
- package/src/devtools.js +17 -19
- package/src/devtools.test.js +18 -9
- package/src/featureFlags.js +12 -5
- package/src/fuzzySearch.test.js +10 -0
- package/src/index.js +14 -2
- package/src/lib/components/ui/alert/alert-action.jsx +11 -0
- package/src/lib/components/ui/alert/alert-description.jsx +11 -0
- package/src/lib/components/ui/alert/alert-title.jsx +11 -0
- package/src/lib/components/ui/alert/alert.jsx +25 -0
- package/src/lib/components/ui/alert/index.js +15 -15
- package/src/lib/components/ui/avatar/avatar-badge.jsx +22 -0
- package/src/lib/components/ui/avatar/avatar-fallback.jsx +18 -0
- package/src/lib/components/ui/avatar/avatar-group-count.jsx +19 -0
- package/src/lib/components/ui/avatar/avatar-group.jsx +19 -0
- package/src/lib/components/ui/avatar/avatar-image.jsx +15 -0
- package/src/lib/components/ui/avatar/avatar.jsx +19 -0
- package/src/lib/components/ui/avatar/index.js +20 -20
- package/src/lib/components/ui/badge/badge.jsx +31 -0
- package/src/lib/components/ui/badge/index.js +2 -2
- package/src/lib/components/ui/button/button.jsx +100 -0
- package/src/lib/components/ui/button/index.js +9 -9
- package/src/lib/components/ui/card/card-action.jsx +11 -0
- package/src/lib/components/ui/card/card-content.jsx +11 -0
- package/src/lib/components/ui/card/card-description.jsx +11 -0
- package/src/lib/components/ui/card/card-footer.jsx +11 -0
- package/src/lib/components/ui/card/card-header.jsx +19 -0
- package/src/lib/components/ui/card/card-title.jsx +11 -0
- package/src/lib/components/ui/card/card.jsx +17 -0
- package/src/lib/components/ui/card/index.js +23 -23
- package/src/lib/components/ui/checkbox/checkbox.jsx +29 -0
- package/src/lib/components/ui/checkbox/index.js +5 -5
- package/src/lib/components/ui/collapsible/collapsible-content.jsx +7 -0
- package/src/lib/components/ui/collapsible/collapsible-trigger.jsx +7 -0
- package/src/lib/components/ui/collapsible/collapsible.jsx +7 -0
- package/src/lib/components/ui/collapsible/index.js +11 -11
- package/src/lib/components/ui/dialog/dialog-close.jsx +7 -0
- package/src/lib/components/ui/dialog/dialog-content.jsx +34 -0
- package/src/lib/components/ui/dialog/dialog-description.jsx +15 -0
- package/src/lib/components/ui/dialog/dialog-footer.jsx +23 -0
- package/src/lib/components/ui/dialog/dialog-header.jsx +11 -0
- package/src/lib/components/ui/dialog/dialog-overlay.jsx +15 -0
- package/src/lib/components/ui/dialog/dialog-portal.jsx +4 -0
- package/src/lib/components/ui/dialog/dialog-title.jsx +15 -0
- package/src/lib/components/ui/dialog/dialog-trigger.jsx +7 -0
- package/src/lib/components/ui/dialog/dialog.jsx +4 -0
- package/src/lib/components/ui/dialog/index.js +32 -32
- package/src/lib/components/ui/dropdown-menu/dropdown-menu-checkbox-group.jsx +8 -0
- package/src/lib/components/ui/dropdown-menu/dropdown-menu-checkbox-item.jsx +30 -0
- package/src/lib/components/ui/dropdown-menu/dropdown-menu-content.jsx +22 -0
- package/src/lib/components/ui/dropdown-menu/dropdown-menu-group-heading.jsx +16 -0
- package/src/lib/components/ui/dropdown-menu/dropdown-menu-group.jsx +7 -0
- package/src/lib/components/ui/dropdown-menu/dropdown-menu-item.jsx +20 -0
- package/src/lib/components/ui/dropdown-menu/dropdown-menu-label.jsx +17 -0
- package/src/lib/components/ui/dropdown-menu/dropdown-menu-portal.jsx +4 -0
- package/src/lib/components/ui/dropdown-menu/dropdown-menu-radio-group.jsx +7 -0
- package/src/lib/components/ui/dropdown-menu/dropdown-menu-radio-item.jsx +29 -0
- package/src/lib/components/ui/dropdown-menu/dropdown-menu-separator.jsx +15 -0
- package/src/lib/components/ui/dropdown-menu/dropdown-menu-shortcut.jsx +16 -0
- package/src/lib/components/ui/dropdown-menu/dropdown-menu-sub-content.jsx +15 -0
- package/src/lib/components/ui/dropdown-menu/dropdown-menu-sub-trigger.jsx +23 -0
- package/src/lib/components/ui/dropdown-menu/dropdown-menu-sub.jsx +4 -0
- package/src/lib/components/ui/dropdown-menu/dropdown-menu-trigger.jsx +7 -0
- package/src/lib/components/ui/dropdown-menu/dropdown-menu.jsx +4 -0
- package/src/lib/components/ui/dropdown-menu/index.js +52 -52
- package/src/lib/components/ui/input/index.js +5 -5
- package/src/lib/components/ui/input/input.jsx +19 -0
- package/src/lib/components/ui/label/index.js +5 -5
- package/src/lib/components/ui/label/label.jsx +19 -0
- package/src/lib/components/ui/panel/index.js +21 -21
- package/src/lib/components/ui/panel/panel-body.jsx +11 -0
- package/src/lib/components/ui/panel/panel-close.jsx +16 -0
- package/src/lib/components/ui/panel/panel-content.jsx +29 -0
- package/src/lib/components/ui/panel/panel-footer.jsx +11 -0
- package/src/lib/components/ui/panel/panel-header.jsx +11 -0
- package/src/lib/components/ui/panel/panel-title.jsx +12 -0
- package/src/lib/components/ui/panel/panel.jsx +4 -0
- package/src/lib/components/ui/popover/index.js +26 -26
- package/src/lib/components/ui/popover/popover-close.jsx +7 -0
- package/src/lib/components/ui/popover/popover-content.jsx +22 -0
- package/src/lib/components/ui/popover/popover-description.jsx +11 -0
- package/src/lib/components/ui/popover/popover-header.jsx +11 -0
- package/src/lib/components/ui/popover/popover-portal.jsx +4 -0
- package/src/lib/components/ui/popover/popover-title.jsx +11 -0
- package/src/lib/components/ui/popover/popover-trigger.jsx +8 -0
- package/src/lib/components/ui/popover/popover.jsx +4 -0
- package/src/lib/components/ui/searchable-list.jsx +159 -0
- package/src/lib/components/ui/select/index.js +35 -35
- package/src/lib/components/ui/select/select-content.jsx +30 -0
- package/src/lib/components/ui/select/select-group-heading.jsx +17 -0
- package/src/lib/components/ui/select/select-group.jsx +15 -0
- package/src/lib/components/ui/select/select-item.jsx +26 -0
- package/src/lib/components/ui/select/select-label.jsx +11 -0
- package/src/lib/components/ui/select/select-portal.jsx +4 -0
- package/src/lib/components/ui/select/select-scroll-down-button.jsx +18 -0
- package/src/lib/components/ui/select/select-scroll-up-button.jsx +18 -0
- package/src/lib/components/ui/select/select-separator.jsx +15 -0
- package/src/lib/components/ui/select/select-trigger.jsx +25 -0
- package/src/lib/components/ui/select/select.jsx +4 -0
- package/src/lib/components/ui/separator/index.js +5 -5
- package/src/lib/components/ui/separator/separator.jsx +22 -0
- package/src/lib/components/ui/sheet/index.js +32 -32
- package/src/lib/components/ui/sheet/sheet-close.jsx +7 -0
- package/src/lib/components/ui/sheet/sheet-content.jsx +35 -0
- package/src/lib/components/ui/sheet/sheet-description.jsx +15 -0
- package/src/lib/components/ui/sheet/sheet-footer.jsx +11 -0
- package/src/lib/components/ui/sheet/sheet-header.jsx +11 -0
- package/src/lib/components/ui/sheet/sheet-overlay.jsx +15 -0
- package/src/lib/components/ui/sheet/sheet-portal.jsx +4 -0
- package/src/lib/components/ui/sheet/sheet-title.jsx +15 -0
- package/src/lib/components/ui/sheet/sheet-trigger.jsx +7 -0
- package/src/lib/components/ui/sheet/sheet.jsx +4 -0
- package/src/lib/components/ui/textarea/index.js +5 -5
- package/src/lib/components/ui/textarea/textarea.jsx +18 -0
- package/src/lib/components/ui/toggle/index.js +6 -9
- package/src/lib/components/ui/toggle/toggle.jsx +36 -0
- package/src/lib/components/ui/toggle-group/index.js +8 -8
- package/src/lib/components/ui/toggle-group/toggle-group-item.jsx +29 -0
- package/src/lib/components/ui/toggle-group/toggle-group.jsx +43 -0
- package/src/lib/components/ui/tooltip/index.js +3 -3
- package/src/lib/components/ui/tooltip/tooltip-content.jsx +21 -0
- package/src/lib/components/ui/tooltip/tooltip-trigger.jsx +23 -0
- package/src/lib/components/ui/tooltip/tooltip.jsx +11 -0
- package/src/lib/components/ui/trigger-button/index.js +3 -3
- package/src/lib/components/ui/trigger-button/trigger-button.css +38 -0
- package/src/lib/components/ui/trigger-button/trigger-button.jsx +63 -0
- package/src/logger/devLogger.js +238 -0
- package/src/logger/devLogger.test.js +193 -0
- package/src/modes.test.js +4 -4
- package/src/mountStoryboardCore.js +123 -27
- package/src/paletteProviders.js +3 -0
- package/src/paletteProviders.test.js +2 -2
- package/src/server/index.js +98 -36
- package/src/sidepanel.css +214 -0
- package/src/styles/tailwind.css +1 -1
- package/src/svelte-plugin-ui/__tests__/ModeSwitch.test.ts +8 -8
- package/src/svelte-plugin-ui/__tests__/ToolbarShell.test.ts +11 -10
- package/src/svelte-plugin-ui/components/Icon.css +11 -0
- package/src/svelte-plugin-ui/components/Icon.jsx +281 -0
- package/src/svelte-plugin-ui/components/ModeSwitch.css +90 -0
- package/src/svelte-plugin-ui/components/ModeSwitch.jsx +47 -0
- package/src/svelte-plugin-ui/components/ToolbarShell.css +80 -0
- package/src/svelte-plugin-ui/components/ToolbarShell.jsx +84 -0
- package/src/svelte-plugin-ui/components/Viewfinder.css +412 -0
- package/src/svelte-plugin-ui/components/Viewfinder.jsx +512 -0
- package/src/svelte-plugin-ui/mount.ts +12 -16
- package/src/toolRegistry.js +4 -4
- package/src/toolbarConfigStore.js +30 -0
- package/src/tools/handlers/autosync.js +1 -1
- package/src/tools/handlers/canvasAddWidget.js +1 -1
- package/src/tools/handlers/canvasAgents.js +19 -0
- package/src/tools/handlers/canvasToolbar.js +8 -8
- package/src/tools/handlers/commandPalette.js +9 -0
- package/src/tools/handlers/comments.js +1 -1
- package/src/tools/handlers/create.js +1 -1
- package/src/tools/handlers/devtools.js +16 -0
- package/src/tools/handlers/devtools.test.js +38 -0
- package/src/tools/handlers/flows.js +1 -1
- package/src/tools/handlers/hideChrome.js +9 -0
- package/src/tools/handlers/paletteTheme.js +35 -0
- package/src/tools/handlers/theme.js +1 -1
- package/src/tools/registry.js +4 -1
- package/src/tools/surfaces/commandList.js +3 -3
- package/src/tools/surfaces/mainToolbar.js +3 -3
- package/src/tools/surfaces/registry.js +4 -4
- package/src/ui/design-modes.ts +2 -2
- package/src/ui/viewfinder.ts +1 -1
- package/src/vite/server-plugin.js +242 -60
- package/src/workshop/features/createCanvas/CreateCanvasForm.jsx +260 -0
- package/src/workshop/features/createCanvas/index.js +1 -1
- package/src/workshop/features/createFlow/CreateFlowForm.jsx +334 -0
- package/src/workshop/features/createFlow/index.js +1 -1
- package/src/workshop/features/createPage/CreatePageForm.jsx +304 -0
- package/src/workshop/features/createPage/index.js +1 -1
- package/src/workshop/features/createPrototype/CreatePrototypeForm.jsx +289 -0
- package/src/workshop/features/createPrototype/index.js +1 -1
- package/src/workshop/features/createPrototype/server.js +98 -0
- package/src/workshop/features/createStory/CreateStoryForm.jsx +208 -0
- package/src/workshop/features/createStory/index.js +1 -1
- package/src/workshop/ui/WorkshopPanel.jsx +98 -0
- package/src/workshop/ui/mount.ts +1 -1
- package/src/worktree/port.js +48 -0
- package/src/worktree/serverRegistry.js +120 -0
- package/toolbar.config.json +93 -42
- package/widgets.config.json +580 -12
- package/src/ActionMenuButton.svelte +0 -119
- package/src/AutosyncMenuButton.svelte +0 -397
- package/src/CanvasCreateMenu.svelte +0 -295
- package/src/CanvasSnap.svelte +0 -87
- package/src/CanvasUndoRedo.svelte +0 -108
- package/src/CanvasZoomControl.svelte +0 -111
- package/src/CanvasZoomToFit.svelte +0 -52
- package/src/CommandMenu.svelte +0 -249
- package/src/CommandPalette.svelte +0 -33
- package/src/CommentsMenuButton.svelte +0 -53
- package/src/CoreUIBar.svelte +0 -847
- package/src/CreateMenuButton.svelte +0 -133
- package/src/DocPanel.svelte +0 -299
- package/src/InspectorPanel.svelte +0 -745
- package/src/PwaInstallBanner.svelte +0 -124
- package/src/SidePanel.svelte +0 -480
- package/src/ThemeMenuButton.svelte +0 -132
- package/src/comments/ui/AuthModal.svelte +0 -108
- package/src/comments/ui/CommentWindow.svelte +0 -333
- package/src/comments/ui/CommentsDrawer.svelte +0 -96
- package/src/comments/ui/Composer.svelte +0 -65
- package/src/lib/components/ui/alert/alert-action.svelte +0 -19
- package/src/lib/components/ui/alert/alert-description.svelte +0 -22
- package/src/lib/components/ui/alert/alert-title.svelte +0 -22
- package/src/lib/components/ui/alert/alert.svelte +0 -38
- package/src/lib/components/ui/avatar/avatar-badge.svelte +0 -25
- package/src/lib/components/ui/avatar/avatar-fallback.svelte +0 -20
- package/src/lib/components/ui/avatar/avatar-group-count.svelte +0 -22
- package/src/lib/components/ui/avatar/avatar-group.svelte +0 -22
- package/src/lib/components/ui/avatar/avatar-image.svelte +0 -17
- package/src/lib/components/ui/avatar/avatar.svelte +0 -24
- package/src/lib/components/ui/badge/badge.svelte +0 -44
- package/src/lib/components/ui/button/button.svelte +0 -108
- package/src/lib/components/ui/card/card-action.svelte +0 -21
- package/src/lib/components/ui/card/card-content.svelte +0 -19
- package/src/lib/components/ui/card/card-description.svelte +0 -19
- package/src/lib/components/ui/card/card-footer.svelte +0 -18
- package/src/lib/components/ui/card/card-header.svelte +0 -21
- package/src/lib/components/ui/card/card-title.svelte +0 -14
- package/src/lib/components/ui/card/card.svelte +0 -21
- package/src/lib/components/ui/checkbox/checkbox.svelte +0 -39
- package/src/lib/components/ui/collapsible/collapsible-content.svelte +0 -7
- package/src/lib/components/ui/collapsible/collapsible-trigger.svelte +0 -7
- package/src/lib/components/ui/collapsible/collapsible.svelte +0 -11
- package/src/lib/components/ui/dialog/dialog-close.svelte +0 -11
- package/src/lib/components/ui/dialog/dialog-content.svelte +0 -42
- package/src/lib/components/ui/dialog/dialog-description.svelte +0 -17
- package/src/lib/components/ui/dialog/dialog-footer.svelte +0 -29
- package/src/lib/components/ui/dialog/dialog-header.svelte +0 -19
- package/src/lib/components/ui/dialog/dialog-overlay.svelte +0 -17
- package/src/lib/components/ui/dialog/dialog-portal.svelte +0 -7
- package/src/lib/components/ui/dialog/dialog-title.svelte +0 -17
- package/src/lib/components/ui/dialog/dialog-trigger.svelte +0 -11
- package/src/lib/components/ui/dialog/dialog.svelte +0 -7
- package/src/lib/components/ui/dropdown-menu/dropdown-menu-checkbox-group.svelte +0 -16
- package/src/lib/components/ui/dropdown-menu/dropdown-menu-checkbox-item.svelte +0 -40
- package/src/lib/components/ui/dropdown-menu/dropdown-menu-content.svelte +0 -27
- package/src/lib/components/ui/dropdown-menu/dropdown-menu-group-heading.svelte +0 -18
- package/src/lib/components/ui/dropdown-menu/dropdown-menu-group.svelte +0 -7
- package/src/lib/components/ui/dropdown-menu/dropdown-menu-item.svelte +0 -24
- package/src/lib/components/ui/dropdown-menu/dropdown-menu-label.svelte +0 -20
- package/src/lib/components/ui/dropdown-menu/dropdown-menu-portal.svelte +0 -7
- package/src/lib/components/ui/dropdown-menu/dropdown-menu-radio-group.svelte +0 -16
- package/src/lib/components/ui/dropdown-menu/dropdown-menu-radio-item.svelte +0 -34
- package/src/lib/components/ui/dropdown-menu/dropdown-menu-separator.svelte +0 -17
- package/src/lib/components/ui/dropdown-menu/dropdown-menu-shortcut.svelte +0 -19
- package/src/lib/components/ui/dropdown-menu/dropdown-menu-sub-content.svelte +0 -17
- package/src/lib/components/ui/dropdown-menu/dropdown-menu-sub-trigger.svelte +0 -27
- package/src/lib/components/ui/dropdown-menu/dropdown-menu-sub.svelte +0 -7
- package/src/lib/components/ui/dropdown-menu/dropdown-menu-trigger.svelte +0 -7
- package/src/lib/components/ui/dropdown-menu/dropdown-menu.svelte +0 -7
- package/src/lib/components/ui/input/input.svelte +0 -40
- package/src/lib/components/ui/label/label.svelte +0 -20
- package/src/lib/components/ui/panel/panel-body.svelte +0 -13
- package/src/lib/components/ui/panel/panel-close.svelte +0 -16
- package/src/lib/components/ui/panel/panel-content.svelte +0 -33
- package/src/lib/components/ui/panel/panel-footer.svelte +0 -13
- package/src/lib/components/ui/panel/panel-header.svelte +0 -16
- package/src/lib/components/ui/panel/panel-title.svelte +0 -14
- package/src/lib/components/ui/panel/panel.svelte +0 -15
- package/src/lib/components/ui/popover/popover-close.svelte +0 -7
- package/src/lib/components/ui/popover/popover-content.svelte +0 -27
- package/src/lib/components/ui/popover/popover-description.svelte +0 -19
- package/src/lib/components/ui/popover/popover-header.svelte +0 -19
- package/src/lib/components/ui/popover/popover-portal.svelte +0 -7
- package/src/lib/components/ui/popover/popover-title.svelte +0 -19
- package/src/lib/components/ui/popover/popover-trigger.svelte +0 -17
- package/src/lib/components/ui/popover/popover.svelte +0 -7
- package/src/lib/components/ui/select/select-content.svelte +0 -40
- package/src/lib/components/ui/select/select-group-heading.svelte +0 -19
- package/src/lib/components/ui/select/select-group.svelte +0 -17
- package/src/lib/components/ui/select/select-item.svelte +0 -38
- package/src/lib/components/ui/select/select-label.svelte +0 -18
- package/src/lib/components/ui/select/select-portal.svelte +0 -7
- package/src/lib/components/ui/select/select-scroll-down-button.svelte +0 -20
- package/src/lib/components/ui/select/select-scroll-up-button.svelte +0 -20
- package/src/lib/components/ui/select/select-separator.svelte +0 -17
- package/src/lib/components/ui/select/select-trigger.svelte +0 -27
- package/src/lib/components/ui/select/select.svelte +0 -11
- package/src/lib/components/ui/separator/separator.svelte +0 -23
- package/src/lib/components/ui/sheet/sheet-close.svelte +0 -7
- package/src/lib/components/ui/sheet/sheet-content.svelte +0 -43
- package/src/lib/components/ui/sheet/sheet-description.svelte +0 -17
- package/src/lib/components/ui/sheet/sheet-footer.svelte +0 -18
- package/src/lib/components/ui/sheet/sheet-header.svelte +0 -19
- package/src/lib/components/ui/sheet/sheet-overlay.svelte +0 -17
- package/src/lib/components/ui/sheet/sheet-portal.svelte +0 -7
- package/src/lib/components/ui/sheet/sheet-title.svelte +0 -17
- package/src/lib/components/ui/sheet/sheet-trigger.svelte +0 -7
- package/src/lib/components/ui/sheet/sheet.svelte +0 -7
- package/src/lib/components/ui/textarea/textarea.svelte +0 -21
- package/src/lib/components/ui/toggle/toggle.svelte +0 -45
- package/src/lib/components/ui/toggle-group/toggle-group-item.svelte +0 -35
- package/src/lib/components/ui/toggle-group/toggle-group.svelte +0 -63
- package/src/lib/components/ui/tooltip/tooltip-content.svelte +0 -24
- package/src/lib/components/ui/tooltip/tooltip-trigger.svelte +0 -27
- package/src/lib/components/ui/tooltip/tooltip.svelte +0 -9
- package/src/lib/components/ui/trigger-button/trigger-button.svelte +0 -106
- package/src/svelte-plugin-ui/components/Icon.svelte +0 -181
- package/src/svelte-plugin-ui/components/ModeSwitch.svelte +0 -121
- package/src/svelte-plugin-ui/components/ToolbarShell.svelte +0 -150
- package/src/svelte-plugin-ui/components/Viewfinder.svelte +0 -1001
- package/src/tools/handlers/docs.js +0 -11
- package/src/workshop/features/createCanvas/CreateCanvasForm.svelte +0 -139
- package/src/workshop/features/createFlow/CreateFlowForm.svelte +0 -314
- package/src/workshop/features/createPage/CreatePageForm.svelte +0 -249
- package/src/workshop/features/createPrototype/CreatePrototypeForm.svelte +0 -287
- package/src/workshop/features/createStory/CreateStoryForm.svelte +0 -161
- package/src/workshop/ui/WorkshopPanel.svelte +0 -97
|
@@ -0,0 +1,512 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Viewfinder — prototype index and flow dashboard.
|
|
3
|
+
*
|
|
4
|
+
* Full-page component that lists prototypes as expandable groups,
|
|
5
|
+
* each showing its flows. Global flows (not belonging to any prototype)
|
|
6
|
+
* appear as an "Other flows" group.
|
|
7
|
+
*
|
|
8
|
+
* Mounted via mountViewfinder() from the viewfinder plugin entry point.
|
|
9
|
+
*/
|
|
10
|
+
|
|
11
|
+
import React, { useState, useMemo, useEffect, useCallback } from 'react'
|
|
12
|
+
import './Viewfinder.css'
|
|
13
|
+
import { buildPrototypeIndex } from '../../viewfinder.js'
|
|
14
|
+
import { getLocal, setLocal } from '../../localStorage.js'
|
|
15
|
+
import { Icon } from './Icon.jsx'
|
|
16
|
+
|
|
17
|
+
const VIEW_MODE_KEY = 'viewfinder.viewMode'
|
|
18
|
+
const EXPANDED_KEY = 'viewfinder.expanded'
|
|
19
|
+
|
|
20
|
+
function loadExpanded() {
|
|
21
|
+
const raw = getLocal(EXPANDED_KEY)
|
|
22
|
+
if (!raw) return {}
|
|
23
|
+
try { return JSON.parse(raw) } catch { return {} }
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
function formatName(name) {
|
|
27
|
+
return name
|
|
28
|
+
.split('-')
|
|
29
|
+
.map((w) => w.charAt(0).toUpperCase() + w.slice(1))
|
|
30
|
+
.join(' ')
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
function placeholderSvg(name) {
|
|
34
|
+
const h = (function hashStr(s) {
|
|
35
|
+
let v = 0
|
|
36
|
+
for (let i = 0; i < s.length; i++) v = ((v << 5) - v + s.charCodeAt(i)) | 0
|
|
37
|
+
return Math.abs(v)
|
|
38
|
+
})(name)
|
|
39
|
+
|
|
40
|
+
let rects = ''
|
|
41
|
+
for (let i = 0; i < 12; i++) {
|
|
42
|
+
const s = h * (i + 1)
|
|
43
|
+
const x = (s * 7 + i * 31) % 320
|
|
44
|
+
const y = (s * 13 + i * 17) % 200
|
|
45
|
+
const w = 20 + (s * (i + 3)) % 80
|
|
46
|
+
const ht = 8 + (s * (i + 7)) % 40
|
|
47
|
+
const opacity = 0.06 + ((s * (i + 2)) % 20) / 100
|
|
48
|
+
const fill = i % 3 === 0 ? 'var(--sb--placeholder-accent)' : i % 3 === 1 ? 'var(--sb--placeholder-fg)' : 'var(--sb--placeholder-muted)'
|
|
49
|
+
rects += `<rect x="${x}" y="${y}" width="${w}" height="${ht}" rx="2" fill="${fill}" opacity="${opacity}" />`
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
let lines = ''
|
|
53
|
+
for (let i = 0; i < 6; i++) {
|
|
54
|
+
const s = h * (i + 5)
|
|
55
|
+
const y = 10 + (s % 180)
|
|
56
|
+
lines += `<line x1="0" y1="${y}" x2="320" y2="${y}" stroke="var(--sb--placeholder-grid)" stroke-width="0.5" opacity="0.4" />`
|
|
57
|
+
}
|
|
58
|
+
for (let i = 0; i < 8; i++) {
|
|
59
|
+
const s = h * (i + 9)
|
|
60
|
+
const x = 10 + (s % 300)
|
|
61
|
+
lines += `<line x1="${x}" y1="0" x2="${x}" y2="200" stroke="var(--sb--placeholder-grid)" stroke-width="0.5" opacity="0.3" />`
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
return `<svg viewBox="0 0 320 200" xmlns="http://www.w3.org/2000/svg" aria-hidden="true"><rect width="320" height="200" fill="var(--sb--placeholder-bg)" />${lines}${rects}</svg>`
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
/* ── Author block ── */
|
|
68
|
+
function AuthorBlock({ author, gitAuthor }) {
|
|
69
|
+
if (author) {
|
|
70
|
+
const authors = Array.isArray(author) ? author : [author]
|
|
71
|
+
return (
|
|
72
|
+
<div className="author">
|
|
73
|
+
<span className="authorAvatars">
|
|
74
|
+
{authors.map((a) => (
|
|
75
|
+
<img key={a} src={`https://github.com/${a}.png?size=48`} alt={a} className="authorAvatar" />
|
|
76
|
+
))}
|
|
77
|
+
</span>
|
|
78
|
+
<span className="authorName">{authors.join(', ')}</span>
|
|
79
|
+
</div>
|
|
80
|
+
)
|
|
81
|
+
}
|
|
82
|
+
if (gitAuthor) {
|
|
83
|
+
return <p className="authorPlain">{gitAuthor}</p>
|
|
84
|
+
}
|
|
85
|
+
return null
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
/* ── Proto entry ── */
|
|
89
|
+
function ProtoEntry({ proto, isExpanded, toggle, withBase, showThumbnails }) {
|
|
90
|
+
if (proto.isExternal) {
|
|
91
|
+
return (
|
|
92
|
+
<section className="protoGroup">
|
|
93
|
+
<a className="listItem" href={proto.externalUrl} target="_blank" rel="noopener noreferrer">
|
|
94
|
+
<div className="cardBody">
|
|
95
|
+
<p className="protoName">
|
|
96
|
+
{proto.icon && <span className="protoIcon">{proto.icon}</span>}
|
|
97
|
+
{proto.name}
|
|
98
|
+
<span className="externalBadge">
|
|
99
|
+
<Icon size={12} color="var(--fgColor-muted)" name="primer/link-external" offsetY={-2} />
|
|
100
|
+
external
|
|
101
|
+
</span>
|
|
102
|
+
</p>
|
|
103
|
+
{proto.description && <p className="protoDesc">{proto.description}</p>}
|
|
104
|
+
<AuthorBlock author={proto.author} gitAuthor={proto.gitAuthor} />
|
|
105
|
+
</div>
|
|
106
|
+
</a>
|
|
107
|
+
</section>
|
|
108
|
+
)
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
if (proto.hideFlows && proto.flows.length === 1) {
|
|
112
|
+
return (
|
|
113
|
+
<section className="protoGroup">
|
|
114
|
+
<a className="listItem" href={withBase(proto.flows[0].route)}>
|
|
115
|
+
<div className="cardBody">
|
|
116
|
+
<p className={`protoName${proto.dirName === '__global__' ? ' otherflows' : ''}`}>
|
|
117
|
+
{proto.icon && <span className="protoIcon">{proto.icon}</span>}
|
|
118
|
+
{proto.name}
|
|
119
|
+
</p>
|
|
120
|
+
{proto.description && <p className="protoDesc">{proto.description}</p>}
|
|
121
|
+
<AuthorBlock author={proto.author} gitAuthor={proto.gitAuthor} />
|
|
122
|
+
</div>
|
|
123
|
+
</a>
|
|
124
|
+
</section>
|
|
125
|
+
)
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
if (proto.flows.length > 0) {
|
|
129
|
+
const expanded = isExpanded(proto.dirName)
|
|
130
|
+
return (
|
|
131
|
+
<section className="protoGroup">
|
|
132
|
+
<button
|
|
133
|
+
className="listItem protoHeader"
|
|
134
|
+
onClick={() => toggle(proto.dirName)}
|
|
135
|
+
aria-expanded={expanded}
|
|
136
|
+
>
|
|
137
|
+
<div className="cardBody">
|
|
138
|
+
<p className={`protoName${proto.dirName === '__global__' ? ' otherflows' : ''}`}>
|
|
139
|
+
{proto.icon && <span className="protoIcon">{proto.icon}</span>}
|
|
140
|
+
{proto.name}
|
|
141
|
+
<span className="protoChevron">
|
|
142
|
+
{expanded
|
|
143
|
+
? <Icon size={12} color="var(--fgColor-disabled)" name="primer/chevron-down" offsetY={-3} offsetX={2} />
|
|
144
|
+
: <Icon size={12} color="var(--fgColor-disabled)" name="primer/chevron-right" offsetY={-3} offsetX={2} />
|
|
145
|
+
}
|
|
146
|
+
</span>
|
|
147
|
+
</p>
|
|
148
|
+
{proto.description && <p className="protoDesc">{proto.description}</p>}
|
|
149
|
+
<AuthorBlock author={proto.author} gitAuthor={proto.gitAuthor} />
|
|
150
|
+
</div>
|
|
151
|
+
</button>
|
|
152
|
+
|
|
153
|
+
{!(proto.hideFlows && proto.flows.length === 1) && expanded && proto.flows.length > 0 && (
|
|
154
|
+
<div className="flowList">
|
|
155
|
+
{proto.flows.map((flow) => (
|
|
156
|
+
<a key={flow.key} href={withBase(flow.route)} className="listItem flowItem">
|
|
157
|
+
{showThumbnails && (
|
|
158
|
+
<div className="thumbnail" dangerouslySetInnerHTML={{ __html: placeholderSvg(flow.key) }} />
|
|
159
|
+
)}
|
|
160
|
+
<div className="cardBody">
|
|
161
|
+
<p className="protoName">{flow.meta?.title || formatName(flow.name)}</p>
|
|
162
|
+
{flow.meta?.description && <p className="flowDesc">{flow.meta.description}</p>}
|
|
163
|
+
</div>
|
|
164
|
+
</a>
|
|
165
|
+
))}
|
|
166
|
+
</div>
|
|
167
|
+
)}
|
|
168
|
+
</section>
|
|
169
|
+
)
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
// Prototype with no flows — navigates directly
|
|
173
|
+
return (
|
|
174
|
+
<section className="protoGroup">
|
|
175
|
+
<a className="listItem" href={withBase(`/${proto.dirName}`)}>
|
|
176
|
+
<div className="cardBody">
|
|
177
|
+
<p className={`protoName${proto.dirName === '__global__' ? ' otherflows' : ''}`}>
|
|
178
|
+
{proto.icon && <span className="protoIcon">{proto.icon}</span>}
|
|
179
|
+
{proto.name}
|
|
180
|
+
</p>
|
|
181
|
+
{proto.description && <p className="protoDesc">{proto.description}</p>}
|
|
182
|
+
<AuthorBlock author={proto.author} gitAuthor={proto.gitAuthor} />
|
|
183
|
+
</div>
|
|
184
|
+
</a>
|
|
185
|
+
</section>
|
|
186
|
+
)
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
/* ── Canvas entry ── */
|
|
190
|
+
function CanvasEntry({ canvas, withBase }) {
|
|
191
|
+
const authors = canvas.author
|
|
192
|
+
? (Array.isArray(canvas.author) ? canvas.author : [canvas.author])
|
|
193
|
+
: null
|
|
194
|
+
|
|
195
|
+
return (
|
|
196
|
+
<section className="protoGroup">
|
|
197
|
+
<a className="listItem" href={withBase(canvas.route)}>
|
|
198
|
+
<div className="cardBody">
|
|
199
|
+
<p className="protoName">
|
|
200
|
+
<span className="protoIcon">{canvas.icon || ''}</span>
|
|
201
|
+
{canvas.name}
|
|
202
|
+
</p>
|
|
203
|
+
{canvas.description && <p className="protoDesc">{canvas.description}</p>}
|
|
204
|
+
{authors ? (
|
|
205
|
+
<div className="author">
|
|
206
|
+
<span className="authorAvatars">
|
|
207
|
+
{authors.map((a) => (
|
|
208
|
+
<img key={a} src={`https://github.com/${a}.png?size=48`} alt={a} className="authorAvatar" />
|
|
209
|
+
))}
|
|
210
|
+
</span>
|
|
211
|
+
<span className="authorName">{authors.join(', ')}</span>
|
|
212
|
+
</div>
|
|
213
|
+
) : canvas.gitAuthor ? (
|
|
214
|
+
<p className="authorPlain">{canvas.gitAuthor}</p>
|
|
215
|
+
) : null}
|
|
216
|
+
</div>
|
|
217
|
+
</a>
|
|
218
|
+
</section>
|
|
219
|
+
)
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
/* ── Folder section ── */
|
|
223
|
+
function FolderSection({ folder, isExpanded, toggle, renderItems, itemKey = 'prototypes' }) {
|
|
224
|
+
const key = `folder:${folder.dirName}`
|
|
225
|
+
const expanded = isExpanded(key)
|
|
226
|
+
const items = folder[itemKey] || []
|
|
227
|
+
|
|
228
|
+
return (
|
|
229
|
+
<section className={`folderGroup${expanded ? ' folderGroupOpen' : ''}`}>
|
|
230
|
+
<button
|
|
231
|
+
className="folderHeader"
|
|
232
|
+
onClick={() => toggle(key)}
|
|
233
|
+
aria-expanded={expanded}
|
|
234
|
+
>
|
|
235
|
+
<p className="folderName">
|
|
236
|
+
<span>
|
|
237
|
+
{expanded
|
|
238
|
+
? <Icon size={20} offsetY={-1.5} name="folder-open" color="#54aeff" />
|
|
239
|
+
: <Icon size={20} offsetY={-1.5} name="folder" color="#54aeff" />
|
|
240
|
+
}
|
|
241
|
+
</span>
|
|
242
|
+
{folder.name}
|
|
243
|
+
</p>
|
|
244
|
+
{folder.description && <p className="folderDesc">{folder.description}</p>}
|
|
245
|
+
</button>
|
|
246
|
+
{expanded && items.length > 0 && (
|
|
247
|
+
<div className="folderContent">
|
|
248
|
+
{renderItems(items)}
|
|
249
|
+
</div>
|
|
250
|
+
)}
|
|
251
|
+
</section>
|
|
252
|
+
)
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
/* ── Main Viewfinder component ── */
|
|
256
|
+
export function Viewfinder({
|
|
257
|
+
title = 'Storyboard',
|
|
258
|
+
subtitle = '',
|
|
259
|
+
basePath = '/',
|
|
260
|
+
knownRoutes = [],
|
|
261
|
+
showThumbnails = false,
|
|
262
|
+
hideDefaultFlow = false,
|
|
263
|
+
}) {
|
|
264
|
+
const prototypeIndex = useMemo(() => buildPrototypeIndex(knownRoutes), [knownRoutes])
|
|
265
|
+
|
|
266
|
+
const globalFlows = useMemo(() => {
|
|
267
|
+
return hideDefaultFlow
|
|
268
|
+
? prototypeIndex.globalFlows.filter((f) => f.key !== 'default')
|
|
269
|
+
: prototypeIndex.globalFlows
|
|
270
|
+
}, [prototypeIndex, hideDefaultFlow])
|
|
271
|
+
|
|
272
|
+
const ungroupedProtos = prototypeIndex.prototypes
|
|
273
|
+
const folders = prototypeIndex.folders || []
|
|
274
|
+
|
|
275
|
+
const otherFlows = useMemo(() => {
|
|
276
|
+
if (globalFlows.length === 0) return null
|
|
277
|
+
return {
|
|
278
|
+
name: 'Other flows',
|
|
279
|
+
dirName: '__global__',
|
|
280
|
+
description: null,
|
|
281
|
+
author: null,
|
|
282
|
+
gitAuthor: null,
|
|
283
|
+
lastModified: null,
|
|
284
|
+
icon: null,
|
|
285
|
+
team: null,
|
|
286
|
+
tags: null,
|
|
287
|
+
flows: globalFlows,
|
|
288
|
+
}
|
|
289
|
+
}, [globalFlows])
|
|
290
|
+
|
|
291
|
+
const totalProtos = ungroupedProtos.length + folders.reduce((sum, f) => sum + f.prototypes.length, 0)
|
|
292
|
+
|
|
293
|
+
// Sorting
|
|
294
|
+
const [sortBy, setSortBy] = useState('updated')
|
|
295
|
+
const sortedProtos = prototypeIndex.sorted?.[sortBy]?.prototypes ?? ungroupedProtos
|
|
296
|
+
const sortedFolders = prototypeIndex.sorted?.[sortBy]?.folders ?? folders
|
|
297
|
+
|
|
298
|
+
// Canvases
|
|
299
|
+
const ungroupedCanvases = prototypeIndex.canvases || []
|
|
300
|
+
const sortedCanvases = prototypeIndex.sorted?.[sortBy]?.canvases ?? ungroupedCanvases
|
|
301
|
+
const totalCanvases = ungroupedCanvases.length + folders.reduce((sum, f) => sum + (f.canvases?.length || 0), 0)
|
|
302
|
+
|
|
303
|
+
// View mode
|
|
304
|
+
const [viewMode, setViewMode] = useState(() =>
|
|
305
|
+
getLocal(VIEW_MODE_KEY) === 'canvases' ? 'canvases' : 'prototypes'
|
|
306
|
+
)
|
|
307
|
+
|
|
308
|
+
useEffect(() => {
|
|
309
|
+
setLocal(VIEW_MODE_KEY, viewMode)
|
|
310
|
+
}, [viewMode])
|
|
311
|
+
|
|
312
|
+
// Canvas folders
|
|
313
|
+
const canvasFolders = useMemo(() => {
|
|
314
|
+
const src = prototypeIndex.sorted?.[sortBy]?.folders ?? folders
|
|
315
|
+
return src
|
|
316
|
+
.filter((f) => f.canvases && f.canvases.length > 0)
|
|
317
|
+
.map((f) => ({ ...f, prototypes: [], canvases: f.canvases }))
|
|
318
|
+
}, [prototypeIndex, sortBy, folders])
|
|
319
|
+
|
|
320
|
+
// Proto-only folders
|
|
321
|
+
const protoOnlyFolders = useMemo(() => {
|
|
322
|
+
const src = prototypeIndex.sorted?.[sortBy]?.folders ?? folders
|
|
323
|
+
return src
|
|
324
|
+
.filter((f) => f.prototypes.length > 0)
|
|
325
|
+
.map((f) => ({ ...f, canvases: [] }))
|
|
326
|
+
}, [prototypeIndex, sortBy, folders])
|
|
327
|
+
|
|
328
|
+
// Expanded state
|
|
329
|
+
const [expanded, setExpanded] = useState(loadExpanded)
|
|
330
|
+
|
|
331
|
+
const isExpandedFn = useCallback((dirName) => expanded[dirName] ?? false, [expanded])
|
|
332
|
+
|
|
333
|
+
const toggleFn = useCallback((dirName) => {
|
|
334
|
+
setExpanded((prev) => {
|
|
335
|
+
const next = { ...prev, [dirName]: !(prev[dirName] ?? false) }
|
|
336
|
+
setLocal(EXPANDED_KEY, JSON.stringify(next))
|
|
337
|
+
return next
|
|
338
|
+
})
|
|
339
|
+
}, [])
|
|
340
|
+
|
|
341
|
+
// URL helpers
|
|
342
|
+
const withBase = useCallback((route) => {
|
|
343
|
+
const normalizedRoute = route.startsWith('/') ? route : `/${route}`
|
|
344
|
+
const normalizedBase = (basePath || '/').replace(/\/+$/, '')
|
|
345
|
+
if (!normalizedBase || normalizedBase === '/') return normalizedRoute
|
|
346
|
+
return `${normalizedBase}${normalizedRoute}`.replace(/\/+/g, '/')
|
|
347
|
+
}, [basePath])
|
|
348
|
+
|
|
349
|
+
// Branch switching
|
|
350
|
+
const branches = (typeof window !== 'undefined' && Array.isArray(window.__SB_BRANCHES__))
|
|
351
|
+
? window.__SB_BRANCHES__
|
|
352
|
+
: null
|
|
353
|
+
|
|
354
|
+
const branchBasePath = (basePath || '/storyboard-source/').replace(/\/branch--[^/]*\/$/, '/')
|
|
355
|
+
const currentBranch = useMemo(() => {
|
|
356
|
+
const m = (basePath || '').match(/\/branch--([^/]+)\/?$/)
|
|
357
|
+
return m ? m[1] : 'main'
|
|
358
|
+
}, [basePath])
|
|
359
|
+
|
|
360
|
+
function handleBranchChange(e) {
|
|
361
|
+
const folder = e.target.value
|
|
362
|
+
if (folder) {
|
|
363
|
+
window.location.href = `${branchBasePath}${folder}/`
|
|
364
|
+
}
|
|
365
|
+
}
|
|
366
|
+
|
|
367
|
+
return (
|
|
368
|
+
<div className="container">
|
|
369
|
+
<header className="header">
|
|
370
|
+
<div className="headerTop">
|
|
371
|
+
<div>
|
|
372
|
+
<h1 className="title">{title}</h1>
|
|
373
|
+
{subtitle && <p className="subtitle">{subtitle}</p>}
|
|
374
|
+
</div>
|
|
375
|
+
</div>
|
|
376
|
+
<div className="controlsRow">
|
|
377
|
+
{/* View mode toggle */}
|
|
378
|
+
<div className="sortToggle">
|
|
379
|
+
<button
|
|
380
|
+
className={`sortButton${viewMode === 'prototypes' ? ' sortButtonActive' : ''}`}
|
|
381
|
+
onClick={() => setViewMode('prototypes')}
|
|
382
|
+
>
|
|
383
|
+
Prototypes
|
|
384
|
+
</button>
|
|
385
|
+
<button
|
|
386
|
+
className={`sortButton${viewMode === 'canvases' ? ' sortButtonActive' : ''}`}
|
|
387
|
+
onClick={() => setViewMode('canvases')}
|
|
388
|
+
>
|
|
389
|
+
Canvas
|
|
390
|
+
</button>
|
|
391
|
+
</div>
|
|
392
|
+
{/* Sort toggle — hidden for now */}
|
|
393
|
+
<div className="sortToggle" style={{ display: 'none' }}>
|
|
394
|
+
<button
|
|
395
|
+
className={`sortButton${sortBy === 'updated' ? ' sortButtonActive' : ''}`}
|
|
396
|
+
onClick={() => setSortBy('updated')}
|
|
397
|
+
>
|
|
398
|
+
<Icon name="primer/clock" size={14} color="var(--fgColor-muted)" />
|
|
399
|
+
Last updated
|
|
400
|
+
</button>
|
|
401
|
+
<button
|
|
402
|
+
className={`sortButton${sortBy === 'title' ? ' sortButtonActive' : ''}`}
|
|
403
|
+
onClick={() => setSortBy('title')}
|
|
404
|
+
>
|
|
405
|
+
<Icon name="primer/sort-asc" size={14} color="var(--fgColor-muted)" />
|
|
406
|
+
Title A–Z
|
|
407
|
+
</button>
|
|
408
|
+
</div>
|
|
409
|
+
{branches && branches.length > 0 && (
|
|
410
|
+
<div className="branchDropdown">
|
|
411
|
+
<span className="branchIcon">
|
|
412
|
+
<Icon size={16} color="var(--fgColor-muted)" offsetY={-1} offsetX={2} name="primer/git-branch" />
|
|
413
|
+
</span>
|
|
414
|
+
<select
|
|
415
|
+
className="branchSelect"
|
|
416
|
+
onChange={handleBranchChange}
|
|
417
|
+
aria-label="Switch branch"
|
|
418
|
+
defaultValue=""
|
|
419
|
+
>
|
|
420
|
+
<option value="" disabled>{currentBranch}</option>
|
|
421
|
+
{branches.map((b) => (
|
|
422
|
+
<option key={b.folder} value={b.folder}>{b.branch}</option>
|
|
423
|
+
))}
|
|
424
|
+
</select>
|
|
425
|
+
</div>
|
|
426
|
+
)}
|
|
427
|
+
</div>
|
|
428
|
+
</header>
|
|
429
|
+
|
|
430
|
+
{viewMode === 'prototypes' && totalProtos === 0 && folders.length === 0 ? (
|
|
431
|
+
<p className="empty">No flows found. Add a <code>*.flow.json</code> file to get started.</p>
|
|
432
|
+
) : viewMode === 'canvases' && totalCanvases === 0 ? (
|
|
433
|
+
<p className="empty">No canvases found. Add a <code>*.canvas.jsonl</code> file to get started.</p>
|
|
434
|
+
) : (
|
|
435
|
+
<div className="list">
|
|
436
|
+
{viewMode === 'prototypes' ? (
|
|
437
|
+
<>
|
|
438
|
+
{protoOnlyFolders.map((folder) => (
|
|
439
|
+
<FolderSection
|
|
440
|
+
key={folder.dirName}
|
|
441
|
+
folder={folder}
|
|
442
|
+
isExpanded={isExpandedFn}
|
|
443
|
+
toggle={toggleFn}
|
|
444
|
+
renderItems={(protos) =>
|
|
445
|
+
protos.map((proto) => (
|
|
446
|
+
<ProtoEntry
|
|
447
|
+
key={proto.dirName}
|
|
448
|
+
proto={proto}
|
|
449
|
+
isExpanded={isExpandedFn}
|
|
450
|
+
toggle={toggleFn}
|
|
451
|
+
withBase={withBase}
|
|
452
|
+
showThumbnails={showThumbnails}
|
|
453
|
+
/>
|
|
454
|
+
))
|
|
455
|
+
}
|
|
456
|
+
/>
|
|
457
|
+
))}
|
|
458
|
+
|
|
459
|
+
{sortedProtos.map((proto) => (
|
|
460
|
+
<ProtoEntry
|
|
461
|
+
key={proto.dirName}
|
|
462
|
+
proto={proto}
|
|
463
|
+
isExpanded={isExpandedFn}
|
|
464
|
+
toggle={toggleFn}
|
|
465
|
+
withBase={withBase}
|
|
466
|
+
showThumbnails={showThumbnails}
|
|
467
|
+
/>
|
|
468
|
+
))}
|
|
469
|
+
|
|
470
|
+
{otherFlows && (
|
|
471
|
+
<ProtoEntry
|
|
472
|
+
proto={otherFlows}
|
|
473
|
+
isExpanded={isExpandedFn}
|
|
474
|
+
toggle={toggleFn}
|
|
475
|
+
withBase={withBase}
|
|
476
|
+
showThumbnails={showThumbnails}
|
|
477
|
+
/>
|
|
478
|
+
)}
|
|
479
|
+
</>
|
|
480
|
+
) : (
|
|
481
|
+
<>
|
|
482
|
+
<div className="canvasWarning">
|
|
483
|
+
<Icon size={14} name="primer/alert" color="#9a6700" offsetY={-1} />
|
|
484
|
+
<span>Canvas is an experimental feature. Use with caution.</span>
|
|
485
|
+
</div>
|
|
486
|
+
{canvasFolders.map((folder) => (
|
|
487
|
+
<FolderSection
|
|
488
|
+
key={folder.dirName}
|
|
489
|
+
folder={folder}
|
|
490
|
+
isExpanded={isExpandedFn}
|
|
491
|
+
toggle={toggleFn}
|
|
492
|
+
itemKey="canvases"
|
|
493
|
+
renderItems={(canvases) =>
|
|
494
|
+
canvases.map((canvas) => (
|
|
495
|
+
<CanvasEntry key={canvas.dirName} canvas={canvas} withBase={withBase} />
|
|
496
|
+
))
|
|
497
|
+
}
|
|
498
|
+
/>
|
|
499
|
+
))}
|
|
500
|
+
|
|
501
|
+
{sortedCanvases.map((canvas) => (
|
|
502
|
+
<CanvasEntry key={canvas.dirName} canvas={canvas} withBase={withBase} />
|
|
503
|
+
))}
|
|
504
|
+
</>
|
|
505
|
+
)}
|
|
506
|
+
</div>
|
|
507
|
+
)}
|
|
508
|
+
</div>
|
|
509
|
+
)
|
|
510
|
+
}
|
|
511
|
+
|
|
512
|
+
export default Viewfinder
|
|
@@ -1,19 +1,20 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Generic mount utility for
|
|
2
|
+
* Generic mount utility for React plugin components.
|
|
3
3
|
*
|
|
4
|
-
* Provides a framework-agnostic way to mount
|
|
4
|
+
* Provides a framework-agnostic way to mount React components into any
|
|
5
5
|
* DOM target. Handles shared style injection (idempotent) and returns
|
|
6
6
|
* a destroy handle for cleanup.
|
|
7
7
|
*
|
|
8
8
|
* Usage:
|
|
9
9
|
* import { mountSveltePlugin } from '@dfosco/storyboard-core/svelte-plugin-ui'
|
|
10
|
-
* import MyComponent from './MyComponent.
|
|
10
|
+
* import MyComponent from './MyComponent.jsx'
|
|
11
11
|
*
|
|
12
12
|
* const handle = mountSveltePlugin(document.body, MyComponent, { someProp: 'value' })
|
|
13
13
|
* // later: handle.destroy()
|
|
14
14
|
*/
|
|
15
15
|
|
|
16
|
-
import {
|
|
16
|
+
import { createElement, type ComponentType } from 'react'
|
|
17
|
+
import { createRoot, type Root } from 'react-dom/client'
|
|
17
18
|
|
|
18
19
|
const STYLE_ID = 'sb-svelte-ui-styles'
|
|
19
20
|
|
|
@@ -69,28 +70,25 @@ export function injectStyles(): Promise<void> {
|
|
|
69
70
|
export interface PluginHandle {
|
|
70
71
|
/** Remove the component and its wrapper from the DOM */
|
|
71
72
|
destroy: () => void
|
|
72
|
-
/** The wrapper element containing the
|
|
73
|
+
/** The wrapper element containing the React component */
|
|
73
74
|
element: HTMLElement
|
|
74
75
|
/** Resolves when all styles are loaded and the component is ready to show */
|
|
75
76
|
ready: Promise<void>
|
|
76
77
|
}
|
|
77
78
|
|
|
78
79
|
/**
|
|
79
|
-
* Mount a
|
|
80
|
+
* Mount a React component into a DOM target.
|
|
80
81
|
*
|
|
81
82
|
* @param target - DOM element to append the component wrapper to
|
|
82
|
-
* @param ComponentClass -
|
|
83
|
+
* @param ComponentClass - React component
|
|
83
84
|
* @param props - Props to pass to the component
|
|
84
85
|
* @returns Handle with destroy() method and a `ready` promise
|
|
85
86
|
*/
|
|
86
87
|
export function mountSveltePlugin<T extends Record<string, unknown>>(
|
|
87
88
|
target: HTMLElement,
|
|
88
|
-
ComponentClass:
|
|
89
|
+
ComponentClass: ComponentType<T>,
|
|
89
90
|
props?: T,
|
|
90
91
|
): PluginHandle {
|
|
91
|
-
// Fire-and-forget — styles are either already present (Vite bundle)
|
|
92
|
-
// or will load in parallel. The `ready` promise on PluginHandle can
|
|
93
|
-
// be awaited by callers that need to wait for CSS.
|
|
94
92
|
const stylesReady = injectStyles()
|
|
95
93
|
|
|
96
94
|
const wrapper = document.createElement('div')
|
|
@@ -98,16 +96,14 @@ export function mountSveltePlugin<T extends Record<string, unknown>>(
|
|
|
98
96
|
wrapper.style.display = 'contents'
|
|
99
97
|
target.appendChild(wrapper)
|
|
100
98
|
|
|
101
|
-
const
|
|
102
|
-
|
|
103
|
-
props: props ?? ({} as T),
|
|
104
|
-
})
|
|
99
|
+
const root: Root = createRoot(wrapper)
|
|
100
|
+
root.render(createElement(ComponentClass, props ?? ({} as T)))
|
|
105
101
|
|
|
106
102
|
return {
|
|
107
103
|
element: wrapper,
|
|
108
104
|
ready: stylesReady,
|
|
109
105
|
destroy() {
|
|
110
|
-
unmount(
|
|
106
|
+
root.unmount()
|
|
111
107
|
wrapper.remove()
|
|
112
108
|
},
|
|
113
109
|
}
|
package/src/toolRegistry.js
CHANGED
|
@@ -2,8 +2,8 @@
|
|
|
2
2
|
* Tool Registry — config-driven state management for toolbar tools.
|
|
3
3
|
*
|
|
4
4
|
* Every tool is declared in toolbar.config.json under the `tools` key.
|
|
5
|
-
* Each tool specifies a `toolbar` target (
|
|
6
|
-
* command-
|
|
5
|
+
* Each tool specifies a `toolbar` target (command-toolbar, canvas-toolbar,
|
|
6
|
+
* command-palette) and a `render` type (button, menu, sidepanel, submenu, link).
|
|
7
7
|
*
|
|
8
8
|
* Code modules register themselves via registerToolModule() to provide
|
|
9
9
|
* component, handler, setup, and guard functions.
|
|
@@ -58,7 +58,7 @@ export function initToolRegistry(config) {
|
|
|
58
58
|
*
|
|
59
59
|
* @param {string} id - Tool id (matches key in toolbar.config.json tools)
|
|
60
60
|
* @param {object} mod
|
|
61
|
-
* @param {Function} [mod.component] - () => import('./SomeComponent.
|
|
61
|
+
* @param {Function} [mod.component] - () => import('./SomeComponent.jsx')
|
|
62
62
|
* @param {object|Function} [mod.handler] - Command action handler
|
|
63
63
|
* @param {Function} [mod.setup] - async (ctx) => void — called once at mount
|
|
64
64
|
* @param {Function} [mod.guard] - async (ctx) => boolean — return false to hide
|
|
@@ -117,7 +117,7 @@ export function getToolModule(id) {
|
|
|
117
117
|
/**
|
|
118
118
|
* Get tools for a specific toolbar target, filtered by mode and visibility.
|
|
119
119
|
*
|
|
120
|
-
* @param {string} toolbar - "
|
|
120
|
+
* @param {string} toolbar - "command-toolbar" | "canvas-toolbar" | "command-palette"
|
|
121
121
|
* @param {string} mode - Current mode name
|
|
122
122
|
* @param {object} [options]
|
|
123
123
|
* @param {boolean} [options.isLocalDev] - Whether running in local dev
|
|
@@ -25,6 +25,9 @@ let _mergedConfig = {}
|
|
|
25
25
|
/** @type {Set<Function>} */
|
|
26
26
|
const _listeners = new Set()
|
|
27
27
|
|
|
28
|
+
/** @type {object|null} Client-repo toolbar overrides (set by virtual module before mount) */
|
|
29
|
+
let _clientOverrides = null
|
|
30
|
+
|
|
28
31
|
let _snapshotVersion = 0
|
|
29
32
|
|
|
30
33
|
// ---------------------------------------------------------------------------
|
|
@@ -122,6 +125,32 @@ function _recompute() {
|
|
|
122
125
|
}
|
|
123
126
|
}
|
|
124
127
|
|
|
128
|
+
// ---------------------------------------------------------------------------
|
|
129
|
+
// Client overrides (set by Vite data plugin before mountStoryboardCore runs)
|
|
130
|
+
// ---------------------------------------------------------------------------
|
|
131
|
+
|
|
132
|
+
/**
|
|
133
|
+
* Store client-repo toolbar overrides from a root toolbar.config.json.
|
|
134
|
+
* Called from the generated virtual module at import time.
|
|
135
|
+
*
|
|
136
|
+
* @param {object} config - Client toolbar config (tools, surfaces, etc.)
|
|
137
|
+
*/
|
|
138
|
+
export function setClientToolbarOverrides(config) {
|
|
139
|
+
_clientOverrides = config
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
/**
|
|
143
|
+
* Consume and clear pending client overrides.
|
|
144
|
+
* Called once by mountStoryboardCore during toolbar config init.
|
|
145
|
+
*
|
|
146
|
+
* @returns {object|null}
|
|
147
|
+
*/
|
|
148
|
+
export function consumeClientToolbarOverrides() {
|
|
149
|
+
const overrides = _clientOverrides
|
|
150
|
+
_clientOverrides = null
|
|
151
|
+
return overrides
|
|
152
|
+
}
|
|
153
|
+
|
|
125
154
|
// ---------------------------------------------------------------------------
|
|
126
155
|
// Test helpers
|
|
127
156
|
// ---------------------------------------------------------------------------
|
|
@@ -129,6 +158,7 @@ function _recompute() {
|
|
|
129
158
|
export function _resetToolbarConfig() {
|
|
130
159
|
_baseConfig = {}
|
|
131
160
|
_prototypeConfig = null
|
|
161
|
+
_clientOverrides = null
|
|
132
162
|
_mergedConfig = {}
|
|
133
163
|
_listeners.clear()
|
|
134
164
|
_snapshotVersion = 0
|