@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
package/src/CoreUIBar.svelte
DELETED
|
@@ -1,847 +0,0 @@
|
|
|
1
|
-
<!--
|
|
2
|
-
CoreUIBar — unified floating button bar for the storyboard devtools.
|
|
3
|
-
|
|
4
|
-
Fixed bottom-right. Always shows the ⌘ command button (rightmost).
|
|
5
|
-
Mode-specific buttons appear to its left at a smaller size.
|
|
6
|
-
Hue follows the active mode's collar color via --trigger-* CSS custom
|
|
7
|
-
properties set in modes.css.
|
|
8
|
-
|
|
9
|
-
Initializes the command action registry and registers core handlers.
|
|
10
|
-
-->
|
|
11
|
-
|
|
12
|
-
<script lang="ts">
|
|
13
|
-
import { onMount, onDestroy, untrack } from 'svelte'
|
|
14
|
-
import './core-ui-colors.css'
|
|
15
|
-
import CommandPalette from './CommandPalette.svelte'
|
|
16
|
-
import * as Panel from './lib/components/ui/panel/index.js'
|
|
17
|
-
import PwaInstallBanner from './PwaInstallBanner.svelte'
|
|
18
|
-
import { TriggerButton } from './lib/components/ui/trigger-button/index.js'
|
|
19
|
-
import * as Tooltip from './lib/components/ui/tooltip/index.js'
|
|
20
|
-
import Icon from './svelte-plugin-ui/components/Icon.svelte'
|
|
21
|
-
import { modeState } from './svelte-plugin-ui/stores/modeStore.js'
|
|
22
|
-
import { sidePanelState, togglePanel } from './stores/sidePanelStore.js'
|
|
23
|
-
import { initCommandActions, registerCommandAction, getActionChildren, hasChildrenProvider, isExcludedByRoute, setRoutingBasePath, setDynamicActions, clearDynamicActions } from './commandActions.js'
|
|
24
|
-
import { isMobile, subscribeToMobile } from './mobileViewport.js'
|
|
25
|
-
import { isMenuHidden } from './uiConfig.js'
|
|
26
|
-
import { subscribeToToolbarConfig, getToolbarConfig } from './toolbarConfigStore.js'
|
|
27
|
-
import { initToolbarToolStates, getToolbarToolState, isToolbarToolLocalOnly, subscribeToToolbarToolStates } from './toolStateStore.js'
|
|
28
|
-
import defaultToolbarConfig from '../toolbar.config.json'
|
|
29
|
-
|
|
30
|
-
interface Props { basePath?: string; toolbarConfig?: any; customHandlers?: Record<string, () => Promise<any>> }
|
|
31
|
-
let { basePath = '/', toolbarConfig, customHandlers = {} }: Props = $props()
|
|
32
|
-
|
|
33
|
-
// Reactive toolbar config — subscribes to the config store for prototype overrides.
|
|
34
|
-
// Falls back to the prop (for backward compat) or the bundled defaults.
|
|
35
|
-
let storeConfig = $state(getToolbarConfig())
|
|
36
|
-
let unsubConfig: (() => void) | null = null
|
|
37
|
-
|
|
38
|
-
$effect(() => {
|
|
39
|
-
unsubConfig = subscribeToToolbarConfig((cfg: any) => { storeConfig = cfg })
|
|
40
|
-
return () => { if (unsubConfig) unsubConfig() }
|
|
41
|
-
})
|
|
42
|
-
|
|
43
|
-
$effect(() => {
|
|
44
|
-
const unsub = subscribeToToolbarToolStates(() => { toolStateVersion++ })
|
|
45
|
-
return unsub
|
|
46
|
-
})
|
|
47
|
-
|
|
48
|
-
// Use store config if available, otherwise fall back to prop or defaults
|
|
49
|
-
const config = $derived(
|
|
50
|
-
(storeConfig && Object.keys(storeConfig).length > 0)
|
|
51
|
-
? storeConfig
|
|
52
|
-
: (toolbarConfig || defaultToolbarConfig)
|
|
53
|
-
)
|
|
54
|
-
|
|
55
|
-
// Re-seed tool states whenever config changes (e.g. prototype override on navigation)
|
|
56
|
-
$effect(() => {
|
|
57
|
-
const tools = config.tools || {}
|
|
58
|
-
// untrack so the synchronous _notify() → toolStateVersion++ inside
|
|
59
|
-
// initToolbarToolStates doesn't get tracked as a dependency of this effect
|
|
60
|
-
untrack(() => initToolbarToolStates(tools, { isLocalDev }))
|
|
61
|
-
})
|
|
62
|
-
|
|
63
|
-
let visible = $state(true)
|
|
64
|
-
// Hide the entire toolbar when loaded inside a prototype embed iframe
|
|
65
|
-
const isEmbed = typeof window !== 'undefined' && new URLSearchParams(window.location.search).has('_sb_embed')
|
|
66
|
-
let commandMenuOpen = $state(false)
|
|
67
|
-
let toolComponents: Record<string, any> = $state({})
|
|
68
|
-
let toolData: Record<string, any> = $state({})
|
|
69
|
-
let navVersion = $state(0)
|
|
70
|
-
let origPushState: typeof history.pushState
|
|
71
|
-
let origReplaceState: typeof history.replaceState
|
|
72
|
-
let bumpNav: () => void
|
|
73
|
-
let chromeObserver: MutationObserver | null = null
|
|
74
|
-
let SidePanel: any = $state(null)
|
|
75
|
-
let toolbarEl: HTMLElement | null = $state(null)
|
|
76
|
-
let canvasActive = $state(false)
|
|
77
|
-
let activeCanvasId = $state('')
|
|
78
|
-
let canvasZoom = $state(100)
|
|
79
|
-
let toolStateVersion = $state(0)
|
|
80
|
-
|
|
81
|
-
// Mobile viewport state — on narrow screens, toolbar tools move into the command menu
|
|
82
|
-
let isMobileState = $state(isMobile())
|
|
83
|
-
let unsubMobile: (() => void) | null = null
|
|
84
|
-
let mobileActionsRegistered = false
|
|
85
|
-
|
|
86
|
-
// Roving tabindex: only one button in the toolbar is tabbable at a time
|
|
87
|
-
let activeToolbarIndex = $state(-1)
|
|
88
|
-
|
|
89
|
-
const isLocalDev = typeof window !== 'undefined' && (window as any).__SB_LOCAL_DEV__ === true && !new URLSearchParams(window.location.search).has('prodMode')
|
|
90
|
-
|
|
91
|
-
/**
|
|
92
|
-
* Resolve a handler reference to a module loader function.
|
|
93
|
-
* Format: "core:name" → core registry, "custom:name" → client handlers
|
|
94
|
-
*/
|
|
95
|
-
function resolveHandlerModule(
|
|
96
|
-
ref: string,
|
|
97
|
-
coreModules: Record<string, Function>,
|
|
98
|
-
custom: Record<string, () => Promise<any>>
|
|
99
|
-
): Function | null {
|
|
100
|
-
const colonIdx = ref.indexOf(':')
|
|
101
|
-
if (colonIdx === -1) return coreModules[ref] || null
|
|
102
|
-
const prefix = ref.slice(0, colonIdx)
|
|
103
|
-
const name = ref.slice(colonIdx + 1)
|
|
104
|
-
if (prefix === 'core') return coreModules[name] || null
|
|
105
|
-
if (prefix === 'custom') return custom[name] || null
|
|
106
|
-
return null
|
|
107
|
-
}
|
|
108
|
-
|
|
109
|
-
// Resolve tools → menus compatibility layer.
|
|
110
|
-
// New config uses `tools` (flat map with toolbar target); legacy uses `menus`.
|
|
111
|
-
// When `tools` exists, derive the menus-compatible structures from it.
|
|
112
|
-
function resolveMenus(cfg: any): Record<string, any> {
|
|
113
|
-
if (cfg.tools) {
|
|
114
|
-
const result: Record<string, any> = {}
|
|
115
|
-
for (const [key, tool] of Object.entries(cfg.tools as Record<string, any>)) {
|
|
116
|
-
if (tool.surface === 'command-list' || tool.surface === 'canvas-toolbar') continue
|
|
117
|
-
// Map new render/toolbar fields to legacy menu fields for rendering compat
|
|
118
|
-
const menu: any = { ...tool }
|
|
119
|
-
if (tool.render === 'menu' && tool.handler) {
|
|
120
|
-
menu.action = tool.handler
|
|
121
|
-
}
|
|
122
|
-
result[key] = { ...menu, _toolId: key }
|
|
123
|
-
}
|
|
124
|
-
return result
|
|
125
|
-
}
|
|
126
|
-
return cfg.menus || {}
|
|
127
|
-
}
|
|
128
|
-
|
|
129
|
-
function resolveCommandConfig(cfg: any): any {
|
|
130
|
-
if (cfg.command) {
|
|
131
|
-
// Build command menu config from new schema
|
|
132
|
-
const actions: any[] = []
|
|
133
|
-
actions.push({ type: 'header', label: 'Command Menu' })
|
|
134
|
-
|
|
135
|
-
// Add command-list tools as actions
|
|
136
|
-
if (cfg.tools) {
|
|
137
|
-
for (const [toolKey, tool] of Object.entries(cfg.tools as Record<string, any>)) {
|
|
138
|
-
if (tool.surface !== 'command-list') continue
|
|
139
|
-
if (tool.render === 'separator') {
|
|
140
|
-
actions.push({ type: 'separator' })
|
|
141
|
-
continue
|
|
142
|
-
}
|
|
143
|
-
actions.push({
|
|
144
|
-
id: tool.handler || `core/${tool.label?.toLowerCase().replace(/\s+/g, '-')}`,
|
|
145
|
-
label: tool.label || tool.ariaLabel,
|
|
146
|
-
type: tool.render || 'default',
|
|
147
|
-
url: tool.url || null,
|
|
148
|
-
modes: tool.modes || ['*'],
|
|
149
|
-
toolKey,
|
|
150
|
-
localOnly: !tool.prod,
|
|
151
|
-
})
|
|
152
|
-
}
|
|
153
|
-
}
|
|
154
|
-
|
|
155
|
-
return {
|
|
156
|
-
ariaLabel: 'Command Menu',
|
|
157
|
-
trigger: 'command',
|
|
158
|
-
icon: cfg.command.icon,
|
|
159
|
-
meta: cfg.command.meta,
|
|
160
|
-
default: true,
|
|
161
|
-
modes: ['*'],
|
|
162
|
-
actions,
|
|
163
|
-
}
|
|
164
|
-
}
|
|
165
|
-
return cfg.menus?.command || null
|
|
166
|
-
}
|
|
167
|
-
|
|
168
|
-
const commandMenuConfig = $derived(
|
|
169
|
-
isMenuHidden('command') ? null : resolveCommandConfig(config)
|
|
170
|
-
)
|
|
171
|
-
const shortcutsConfig = $derived({
|
|
172
|
-
...((config as any).shortcuts || {}),
|
|
173
|
-
...(config.command?.shortcut ? { openCommandMenu: config.command.shortcut } : {}),
|
|
174
|
-
})
|
|
175
|
-
|
|
176
|
-
// Build ordered menu list from JSON key order (excluding command, which is always rightmost)
|
|
177
|
-
const allMenus = $derived(resolveMenus(config))
|
|
178
|
-
const orderedMenus = $derived(Object.entries(allMenus)
|
|
179
|
-
.filter(([key]) => key !== 'command')
|
|
180
|
-
.filter(([key]) => !isMenuHidden(key))
|
|
181
|
-
.filter(([key]) => {
|
|
182
|
-
void toolStateVersion
|
|
183
|
-
return getToolbarToolState(key) !== 'disabled'
|
|
184
|
-
})
|
|
185
|
-
.map(([key, menu]) => ({ key, ...menu })))
|
|
186
|
-
|
|
187
|
-
// Discover menus with sidepanel property
|
|
188
|
-
const sidepanelMenus = $derived(orderedMenus.filter(menu => menu.sidepanel))
|
|
189
|
-
|
|
190
|
-
// Canvas toolbar tools — only visible when a canvas page is active
|
|
191
|
-
const canvasMenus = $derived(
|
|
192
|
-
config.tools
|
|
193
|
-
? Object.entries(config.tools as Record<string, any>)
|
|
194
|
-
.filter(([, tool]) => tool.surface === 'canvas-toolbar')
|
|
195
|
-
.filter(([, tool]) => tool.prod || isLocalDev)
|
|
196
|
-
.map(([key, tool]) => ({ key, ...tool }))
|
|
197
|
-
: []
|
|
198
|
-
)
|
|
199
|
-
|
|
200
|
-
function menuVisibleInMode(menu: any, mode: string): boolean {
|
|
201
|
-
if (!menu?.modes) return false
|
|
202
|
-
if (isExcludedByRoute(menu)) return false
|
|
203
|
-
return menu.modes.includes('*') || menu.modes.includes(mode)
|
|
204
|
-
}
|
|
205
|
-
|
|
206
|
-
// Menus that are visible in the current mode, reversed so JSON top→bottom = right→left
|
|
207
|
-
const visibleMenus = $derived(
|
|
208
|
-
orderedMenus
|
|
209
|
-
.filter(menu => {
|
|
210
|
-
void navVersion
|
|
211
|
-
void toolStateVersion
|
|
212
|
-
const toolState = getToolbarToolState(menu.key)
|
|
213
|
-
if (toolState === 'hidden') return false
|
|
214
|
-
if (menu.render === 'separator') return true
|
|
215
|
-
if (!menuVisibleInMode(menu, $modeState.mode)) return false
|
|
216
|
-
if (menu.render === 'sidepanel') return true
|
|
217
|
-
// For tools with components, check if loaded
|
|
218
|
-
if (!toolComponents[menu.key]) return false
|
|
219
|
-
// For action-menu tools (those with a getChildren handler), hide when empty.
|
|
220
|
-
// Custom-component menus (e.g. ThemeMenuButton) render their own content.
|
|
221
|
-
const actionId = menu.handler || menu.action
|
|
222
|
-
if (actionId && menu.render === 'menu' && hasChildrenProvider(actionId)) {
|
|
223
|
-
return getActionChildren(actionId).length > 0
|
|
224
|
-
}
|
|
225
|
-
return true
|
|
226
|
-
})
|
|
227
|
-
.reverse()
|
|
228
|
-
)
|
|
229
|
-
|
|
230
|
-
// Clean separators: remove leading, trailing, and consecutive
|
|
231
|
-
const cleanedMenus = $derived.by(() => {
|
|
232
|
-
const result: typeof visibleMenus = []
|
|
233
|
-
for (const item of visibleMenus) {
|
|
234
|
-
if (item.render === 'separator') {
|
|
235
|
-
// Skip if first item or previous was also a separator
|
|
236
|
-
if (result.length === 0 || result[result.length - 1].render === 'separator') continue
|
|
237
|
-
result.push(item)
|
|
238
|
-
} else {
|
|
239
|
-
result.push(item)
|
|
240
|
-
}
|
|
241
|
-
}
|
|
242
|
-
// Remove trailing separator
|
|
243
|
-
while (result.length > 0 && result[result.length - 1].render === 'separator') result.pop()
|
|
244
|
-
return result
|
|
245
|
-
})
|
|
246
|
-
|
|
247
|
-
// Total toolbar item count (visible menus + command menu if present)
|
|
248
|
-
const toolbarItemCount = $derived(
|
|
249
|
-
cleanedMenus.filter(m => m.render !== 'separator').length + (commandMenuConfig ? 1 : 0)
|
|
250
|
-
)
|
|
251
|
-
|
|
252
|
-
// Command menu is always the last item (rightmost)
|
|
253
|
-
const commandMenuIndex = $derived(
|
|
254
|
-
commandMenuConfig ? cleanedMenus.filter(m => m.render !== 'separator').length : -1
|
|
255
|
-
)
|
|
256
|
-
|
|
257
|
-
function getTabindex(index: number): number {
|
|
258
|
-
if (activeToolbarIndex < 0) {
|
|
259
|
-
// No item focused yet — make the last item (command menu) tabbable as default
|
|
260
|
-
return index === toolbarItemCount - 1 ? 0 : -1
|
|
261
|
-
}
|
|
262
|
-
return index === activeToolbarIndex ? 0 : -1
|
|
263
|
-
}
|
|
264
|
-
|
|
265
|
-
function focusToolbarItem(index: number) {
|
|
266
|
-
activeToolbarIndex = index
|
|
267
|
-
if (!toolbarEl) return
|
|
268
|
-
const buttons = toolbarEl.querySelectorAll<HTMLElement>('[data-slot="button"]')
|
|
269
|
-
buttons[index]?.focus()
|
|
270
|
-
}
|
|
271
|
-
|
|
272
|
-
function handleToolbarKeydown(e: KeyboardEvent) {
|
|
273
|
-
if (toolbarItemCount === 0) return
|
|
274
|
-
const current = activeToolbarIndex < 0 ? toolbarItemCount - 1 : activeToolbarIndex
|
|
275
|
-
|
|
276
|
-
if (e.key === 'ArrowRight') {
|
|
277
|
-
e.preventDefault()
|
|
278
|
-
focusToolbarItem((current + 1) % toolbarItemCount)
|
|
279
|
-
} else if (e.key === 'ArrowLeft') {
|
|
280
|
-
e.preventDefault()
|
|
281
|
-
focusToolbarItem((current - 1 + toolbarItemCount) % toolbarItemCount)
|
|
282
|
-
} else if (e.key === 'Home') {
|
|
283
|
-
e.preventDefault()
|
|
284
|
-
focusToolbarItem(0)
|
|
285
|
-
} else if (e.key === 'End') {
|
|
286
|
-
e.preventDefault()
|
|
287
|
-
focusToolbarItem(toolbarItemCount - 1)
|
|
288
|
-
} else if (e.key === 'ArrowDown') {
|
|
289
|
-
// Menus open upward — block Bits UI's default ArrowDown-to-open
|
|
290
|
-
e.preventDefault()
|
|
291
|
-
e.stopPropagation()
|
|
292
|
-
} else if (e.key === 'ArrowUp') {
|
|
293
|
-
e.preventDefault()
|
|
294
|
-
// If a menu is already open, focus its last item
|
|
295
|
-
const openContent = document.querySelector<HTMLElement>('[data-slot="dropdown-menu-content"]')
|
|
296
|
-
if (openContent) {
|
|
297
|
-
const items = openContent.querySelectorAll<HTMLElement>('[role="menuitem"], [role="menuitemcheckbox"], [role="menuitemradio"]')
|
|
298
|
-
if (items.length > 0) items[items.length - 1].focus()
|
|
299
|
-
return
|
|
300
|
-
}
|
|
301
|
-
// Otherwise, open the focused button's dropdown (if it has one)
|
|
302
|
-
const focusedBtn = toolbarEl?.querySelector<HTMLElement>('[data-slot="button"]:focus')
|
|
303
|
-
if (focusedBtn?.getAttribute('aria-haspopup')) {
|
|
304
|
-
focusedBtn.click()
|
|
305
|
-
// After menu renders, focus its last item
|
|
306
|
-
requestAnimationFrame(() => {
|
|
307
|
-
const content = document.querySelector<HTMLElement>('[data-slot="dropdown-menu-content"]')
|
|
308
|
-
if (content) {
|
|
309
|
-
const items = content.querySelectorAll<HTMLElement>('[role="menuitem"], [role="menuitemcheckbox"], [role="menuitemradio"]')
|
|
310
|
-
if (items.length > 0) items[items.length - 1].focus()
|
|
311
|
-
}
|
|
312
|
-
})
|
|
313
|
-
}
|
|
314
|
-
}
|
|
315
|
-
}
|
|
316
|
-
|
|
317
|
-
function handleKeydown(e: KeyboardEvent) {
|
|
318
|
-
const hideKey = shortcutsConfig.hideChrome?.key || '.'
|
|
319
|
-
const openKey = shortcutsConfig.openCommandMenu?.key
|
|
320
|
-
|
|
321
|
-
if (e.key === hideKey && (e.metaKey || e.ctrlKey)) {
|
|
322
|
-
e.preventDefault()
|
|
323
|
-
visible = !visible
|
|
324
|
-
document.documentElement.classList.toggle('storyboard-chrome-hidden', !visible)
|
|
325
|
-
}
|
|
326
|
-
// Configurable shortcut to open the command menu (works even when hidden)
|
|
327
|
-
if (openKey && e.key === openKey && (e.metaKey || e.ctrlKey)) {
|
|
328
|
-
e.preventDefault()
|
|
329
|
-
document.dispatchEvent(new CustomEvent('storyboard:toggle-palette'))
|
|
330
|
-
}
|
|
331
|
-
// Config-driven tool shortcuts (e.g. Cmd+D for docs, Cmd+I for inspector)
|
|
332
|
-
for (const menu of cleanedMenus) {
|
|
333
|
-
const shortcut = menu.shortcut
|
|
334
|
-
if (!shortcut?.key) continue
|
|
335
|
-
if (e.key === shortcut.key && (e.metaKey || e.ctrlKey) && !e.shiftKey) {
|
|
336
|
-
const toolState = getToolbarToolState(menu.key)
|
|
337
|
-
// Inactive and disabled tools don't respond to shortcuts
|
|
338
|
-
if (toolState === 'inactive' || toolState === 'disabled') break
|
|
339
|
-
if (menu.sidepanel) {
|
|
340
|
-
e.preventDefault()
|
|
341
|
-
togglePanel(menu.sidepanel)
|
|
342
|
-
}
|
|
343
|
-
break
|
|
344
|
-
}
|
|
345
|
-
}
|
|
346
|
-
}
|
|
347
|
-
|
|
348
|
-
onMount(async () => {
|
|
349
|
-
window.addEventListener('keydown', handleKeydown)
|
|
350
|
-
setRoutingBasePath(basePath)
|
|
351
|
-
|
|
352
|
-
// Sync visible state when storyboard-chrome-hidden is toggled externally
|
|
353
|
-
// (e.g. from command palette or other UI)
|
|
354
|
-
chromeObserver = new MutationObserver(() => {
|
|
355
|
-
const hidden = document.documentElement.classList.contains('storyboard-chrome-hidden')
|
|
356
|
-
if (visible === !hidden) return
|
|
357
|
-
visible = !hidden
|
|
358
|
-
})
|
|
359
|
-
chromeObserver.observe(document.documentElement, { attributes: true, attributeFilter: ['class'] })
|
|
360
|
-
|
|
361
|
-
// Re-evaluate action menus and prototype toolbar config on SPA navigation
|
|
362
|
-
const { getPrototypeMetadata } = await import('./loader.js')
|
|
363
|
-
const { setPrototypeToolbarConfig, clearPrototypeToolbarConfig } = await import('./toolbarConfigStore.js')
|
|
364
|
-
|
|
365
|
-
function syncPrototypeToolbar() {
|
|
366
|
-
let pathname = window.location.pathname
|
|
367
|
-
const base = basePath.replace(/\/+$/, '')
|
|
368
|
-
if (base && pathname.startsWith(base)) pathname = pathname.slice(base.length)
|
|
369
|
-
const firstSegment = pathname.replace(/^\//, '').split('/')[0] || null
|
|
370
|
-
if (firstSegment) {
|
|
371
|
-
const meta = getPrototypeMetadata(firstSegment)
|
|
372
|
-
if (meta?.toolbarConfig) {
|
|
373
|
-
setPrototypeToolbarConfig(meta.toolbarConfig)
|
|
374
|
-
} else {
|
|
375
|
-
clearPrototypeToolbarConfig()
|
|
376
|
-
}
|
|
377
|
-
} else {
|
|
378
|
-
clearPrototypeToolbarConfig()
|
|
379
|
-
}
|
|
380
|
-
}
|
|
381
|
-
|
|
382
|
-
bumpNav = () => { navVersion++; syncPrototypeToolbar(); syncMobileActions() }
|
|
383
|
-
window.addEventListener('popstate', bumpNav)
|
|
384
|
-
origPushState = history.pushState.bind(history)
|
|
385
|
-
history.pushState = (...args: any[]) => { origPushState(...args); bumpNav() }
|
|
386
|
-
origReplaceState = history.replaceState.bind(history)
|
|
387
|
-
history.replaceState = (...args: any[]) => { origReplaceState(...args); bumpNav() }
|
|
388
|
-
|
|
389
|
-
// Apply prototype toolbar config for the initial route
|
|
390
|
-
syncPrototypeToolbar()
|
|
391
|
-
|
|
392
|
-
// Seed the command action registry from config
|
|
393
|
-
if (commandMenuConfig) {
|
|
394
|
-
initCommandActions(commandMenuConfig)
|
|
395
|
-
}
|
|
396
|
-
|
|
397
|
-
// Register sidepanel toggle actions
|
|
398
|
-
for (const menu of sidepanelMenus) {
|
|
399
|
-
registerCommandAction(`core:${menu.key}`, () => {
|
|
400
|
-
togglePanel(menu.sidepanel)
|
|
401
|
-
})
|
|
402
|
-
}
|
|
403
|
-
|
|
404
|
-
// Load all tool modules from the registry
|
|
405
|
-
const { coreHandlers } = await import('./tools/registry.js')
|
|
406
|
-
const toolConfigs = config.tools || {}
|
|
407
|
-
const ctx = { basePath, showFlowInfoDialog }
|
|
408
|
-
|
|
409
|
-
for (const [toolId, toolConfig] of Object.entries(toolConfigs as Record<string, any>)) {
|
|
410
|
-
// Skip non-tool entries (separators have no handler)
|
|
411
|
-
if (toolConfig.render === 'separator') continue
|
|
412
|
-
|
|
413
|
-
// Skip disabled tools — don't load their modules at all
|
|
414
|
-
if (getToolbarToolState(toolId) === 'disabled') continue
|
|
415
|
-
|
|
416
|
-
// Resolve handler module via core:/custom: prefix
|
|
417
|
-
const handlerRef = toolConfig.handler || `core:${toolId}`
|
|
418
|
-
const loadModule = resolveHandlerModule(handlerRef, coreHandlers, customHandlers)
|
|
419
|
-
if (!loadModule) continue
|
|
420
|
-
|
|
421
|
-
try {
|
|
422
|
-
const mod = await loadModule()
|
|
423
|
-
const toolCtx = { ...ctx, config: toolConfig }
|
|
424
|
-
|
|
425
|
-
// Run guard — skip if guard returns false
|
|
426
|
-
if (mod.guard) {
|
|
427
|
-
const ok = await mod.guard(toolCtx)
|
|
428
|
-
if (!ok) continue
|
|
429
|
-
}
|
|
430
|
-
|
|
431
|
-
// Run setup
|
|
432
|
-
if (mod.setup) {
|
|
433
|
-
const setupResult = await mod.setup(toolCtx)
|
|
434
|
-
if (setupResult) {
|
|
435
|
-
toolData[toolId] = setupResult
|
|
436
|
-
}
|
|
437
|
-
}
|
|
438
|
-
|
|
439
|
-
// Register handler as command action
|
|
440
|
-
if (mod.handler) {
|
|
441
|
-
const handlerResult = await mod.handler(toolCtx)
|
|
442
|
-
const actionId = toolConfig.handler || `core:${toolId}`
|
|
443
|
-
// Store handler result in toolData for component access
|
|
444
|
-
if (handlerResult && !handlerResult.getChildren) {
|
|
445
|
-
toolData[toolId] = { ...(toolData[toolId] || {}), ...handlerResult }
|
|
446
|
-
}
|
|
447
|
-
registerCommandAction(actionId, handlerResult)
|
|
448
|
-
}
|
|
449
|
-
|
|
450
|
-
// Load component
|
|
451
|
-
if (mod.component) {
|
|
452
|
-
const component = await mod.component(toolConfig.render)
|
|
453
|
-
toolComponents[toolId] = component
|
|
454
|
-
}
|
|
455
|
-
} catch { /* tool failed to load — skip gracefully */ }
|
|
456
|
-
}
|
|
457
|
-
|
|
458
|
-
// Load side panel component
|
|
459
|
-
try {
|
|
460
|
-
if (sidepanelMenus.length > 0) {
|
|
461
|
-
const mod = await import('./SidePanel.svelte')
|
|
462
|
-
SidePanel = mod.default
|
|
463
|
-
}
|
|
464
|
-
} catch {}
|
|
465
|
-
|
|
466
|
-
// Listen for canvas mount/unmount events (React↔Svelte bridge)
|
|
467
|
-
document.addEventListener('storyboard:canvas:mounted', handleCanvasMounted)
|
|
468
|
-
document.addEventListener('storyboard:canvas:unmounted', handleCanvasUnmounted)
|
|
469
|
-
document.addEventListener('storyboard:canvas:zoom-changed', handleZoomChanged)
|
|
470
|
-
document.addEventListener('storyboard:canvas:status', handleCanvasMounted)
|
|
471
|
-
syncCanvasBridgeState()
|
|
472
|
-
|
|
473
|
-
// Subscribe to mobile viewport changes and sync mobile command actions
|
|
474
|
-
syncMobileActions()
|
|
475
|
-
unsubMobile = subscribeToMobile((mobile: boolean) => {
|
|
476
|
-
isMobileState = mobile
|
|
477
|
-
syncMobileActions()
|
|
478
|
-
})
|
|
479
|
-
})
|
|
480
|
-
|
|
481
|
-
onDestroy(() => {
|
|
482
|
-
window.removeEventListener('keydown', handleKeydown)
|
|
483
|
-
if (bumpNav) window.removeEventListener('popstate', bumpNav)
|
|
484
|
-
if (origPushState) history.pushState = origPushState
|
|
485
|
-
if (origReplaceState) history.replaceState = origReplaceState
|
|
486
|
-
if (unsubMobile) unsubMobile()
|
|
487
|
-
clearDynamicActions('mobile-toolbar')
|
|
488
|
-
chromeObserver?.disconnect()
|
|
489
|
-
document.removeEventListener('storyboard:canvas:mounted', handleCanvasMounted)
|
|
490
|
-
document.removeEventListener('storyboard:canvas:unmounted', handleCanvasUnmounted)
|
|
491
|
-
document.removeEventListener('storyboard:canvas:zoom-changed', handleZoomChanged)
|
|
492
|
-
document.removeEventListener('storyboard:canvas:status', handleCanvasMounted)
|
|
493
|
-
})
|
|
494
|
-
|
|
495
|
-
function handleCanvasMounted(e: Event) {
|
|
496
|
-
canvasActive = true
|
|
497
|
-
const detail = (e as CustomEvent).detail
|
|
498
|
-
activeCanvasId = detail?.canvasId || detail?.name || ''
|
|
499
|
-
canvasZoom = detail?.zoom ?? 100
|
|
500
|
-
syncMobileActions()
|
|
501
|
-
}
|
|
502
|
-
|
|
503
|
-
function handleCanvasUnmounted() {
|
|
504
|
-
canvasActive = false
|
|
505
|
-
activeCanvasId = ''
|
|
506
|
-
canvasZoom = 100
|
|
507
|
-
syncMobileActions()
|
|
508
|
-
}
|
|
509
|
-
|
|
510
|
-
function handleZoomChanged(e: Event) {
|
|
511
|
-
if (!canvasActive) canvasActive = true
|
|
512
|
-
canvasZoom = (e as CustomEvent).detail?.zoom ?? canvasZoom
|
|
513
|
-
}
|
|
514
|
-
|
|
515
|
-
function syncCanvasBridgeState() {
|
|
516
|
-
if (typeof window === 'undefined') return
|
|
517
|
-
const state = (window as any).__storyboardCanvasBridgeState
|
|
518
|
-
if (state && typeof state === 'object') {
|
|
519
|
-
canvasActive = state.active === true
|
|
520
|
-
activeCanvasId = state.canvasId || state.name || ''
|
|
521
|
-
canvasZoom = typeof state.zoom === 'number' ? state.zoom : 100
|
|
522
|
-
}
|
|
523
|
-
if (!canvasActive) {
|
|
524
|
-
document.dispatchEvent(new CustomEvent('storyboard:canvas:status-request'))
|
|
525
|
-
}
|
|
526
|
-
}
|
|
527
|
-
|
|
528
|
-
/**
|
|
529
|
-
* Sync mobile command actions — when in mobile viewport, toolbar tools
|
|
530
|
-
* become dynamic command actions in the ⌘ menu.
|
|
531
|
-
*/
|
|
532
|
-
async function syncMobileActions() {
|
|
533
|
-
if (!isMobileState) {
|
|
534
|
-
if (mobileActionsRegistered) {
|
|
535
|
-
clearDynamicActions('mobile-toolbar')
|
|
536
|
-
mobileActionsRegistered = false
|
|
537
|
-
}
|
|
538
|
-
return
|
|
539
|
-
}
|
|
540
|
-
|
|
541
|
-
const actions: any[] = []
|
|
542
|
-
const handlers: Record<string, any> = {}
|
|
543
|
-
const toolConfigs = config.tools || {}
|
|
544
|
-
|
|
545
|
-
// Main-toolbar tools → command actions
|
|
546
|
-
actions.push({ type: 'header', label: 'Tools', id: '_mobile_header' })
|
|
547
|
-
|
|
548
|
-
for (const [key, tool] of Object.entries(toolConfigs as Record<string, any>)) {
|
|
549
|
-
if (tool.surface !== 'main-toolbar') continue
|
|
550
|
-
if (tool.render === 'separator') continue
|
|
551
|
-
if (!tool.prod && !isLocalDev) continue
|
|
552
|
-
if (getToolbarToolState(key) === 'disabled') continue
|
|
553
|
-
if (isExcludedByRoute(tool)) continue
|
|
554
|
-
|
|
555
|
-
// Always use mobile:-prefixed ids to avoid clobbering shared desktop handlers
|
|
556
|
-
const mobileId = `mobile:${key}`
|
|
557
|
-
const desktopActionId = tool.handler || `core:${key}`
|
|
558
|
-
|
|
559
|
-
// Menu tools with getChildren → submenu (delegate to existing desktop handler)
|
|
560
|
-
if (tool.render === 'menu' && hasChildrenProvider(desktopActionId)) {
|
|
561
|
-
actions.push({
|
|
562
|
-
id: mobileId,
|
|
563
|
-
label: tool.label || tool.ariaLabel,
|
|
564
|
-
type: 'submenu',
|
|
565
|
-
modes: tool.modes || ['*'],
|
|
566
|
-
excludeRoutes: tool.excludeRoutes,
|
|
567
|
-
toolKey: key,
|
|
568
|
-
localOnly: !tool.prod,
|
|
569
|
-
})
|
|
570
|
-
handlers[mobileId] = {
|
|
571
|
-
getChildren: () => getActionChildren(desktopActionId),
|
|
572
|
-
}
|
|
573
|
-
}
|
|
574
|
-
// Sidepanel tools → default action (toggle panel)
|
|
575
|
-
else if (tool.render === 'sidepanel') {
|
|
576
|
-
actions.push({
|
|
577
|
-
id: mobileId,
|
|
578
|
-
label: tool.ariaLabel || tool.label || key,
|
|
579
|
-
type: 'default',
|
|
580
|
-
modes: tool.modes || ['*'],
|
|
581
|
-
excludeRoutes: tool.excludeRoutes,
|
|
582
|
-
toolKey: key,
|
|
583
|
-
localOnly: !tool.prod,
|
|
584
|
-
})
|
|
585
|
-
handlers[mobileId] = () => { togglePanel(tool.sidepanel) }
|
|
586
|
-
}
|
|
587
|
-
// Button tools (e.g. comments) — only if the desktop guard passed (component loaded)
|
|
588
|
-
else if (tool.render === 'button' && toolComponents[key]) {
|
|
589
|
-
try {
|
|
590
|
-
if (key === 'comments') {
|
|
591
|
-
const { toggleCommentMode, isCommentModeActive } = await import('./comments/commentMode.js')
|
|
592
|
-
const { isAuthenticated } = await import('./comments/auth.js')
|
|
593
|
-
const { openAuthModal } = await import('./comments/ui/authModal.js')
|
|
594
|
-
actions.push({
|
|
595
|
-
id: mobileId,
|
|
596
|
-
label: tool.ariaLabel || 'Comments',
|
|
597
|
-
type: 'toggle',
|
|
598
|
-
modes: tool.modes || ['*'],
|
|
599
|
-
excludeRoutes: tool.excludeRoutes,
|
|
600
|
-
toolKey: key,
|
|
601
|
-
localOnly: !tool.prod,
|
|
602
|
-
})
|
|
603
|
-
handlers[mobileId] = {
|
|
604
|
-
execute: async () => {
|
|
605
|
-
if (!isAuthenticated()) {
|
|
606
|
-
const user = await openAuthModal()
|
|
607
|
-
if (!user) return
|
|
608
|
-
}
|
|
609
|
-
toggleCommentMode()
|
|
610
|
-
},
|
|
611
|
-
getState: () => isCommentModeActive(),
|
|
612
|
-
}
|
|
613
|
-
}
|
|
614
|
-
} catch { /* comments module not available */ }
|
|
615
|
-
}
|
|
616
|
-
}
|
|
617
|
-
|
|
618
|
-
// Theme tool — special handling (component-only, no handler in registry)
|
|
619
|
-
if (toolConfigs.theme && toolComponents.theme) {
|
|
620
|
-
// Only add if not already handled above (theme has no getChildren in registry)
|
|
621
|
-
if (!actions.some(a => a.id === 'mobile:theme')) {
|
|
622
|
-
try {
|
|
623
|
-
const { themeState, setTheme, THEMES } = await import('./stores/themeStore.js')
|
|
624
|
-
actions.push({
|
|
625
|
-
id: 'mobile:theme',
|
|
626
|
-
label: 'Theme',
|
|
627
|
-
type: 'submenu',
|
|
628
|
-
modes: ['*'],
|
|
629
|
-
toolKey: 'theme',
|
|
630
|
-
localOnly: !toolConfigs.theme.prod,
|
|
631
|
-
})
|
|
632
|
-
handlers['mobile:theme'] = {
|
|
633
|
-
getChildren: () => {
|
|
634
|
-
const current = themeState.theme
|
|
635
|
-
return THEMES.map((t: any) => ({
|
|
636
|
-
id: `theme:${t.value}`,
|
|
637
|
-
label: t.label,
|
|
638
|
-
type: 'toggle' as const,
|
|
639
|
-
active: current === t.value,
|
|
640
|
-
execute: () => setTheme(t.value),
|
|
641
|
-
}))
|
|
642
|
-
},
|
|
643
|
-
}
|
|
644
|
-
} catch { /* theme store not available */ }
|
|
645
|
-
}
|
|
646
|
-
}
|
|
647
|
-
|
|
648
|
-
// Canvas toolbar stays visible on mobile — no need to duplicate canvas tools here
|
|
649
|
-
|
|
650
|
-
setDynamicActions('mobile-toolbar', actions, handlers)
|
|
651
|
-
mobileActionsRegistered = true
|
|
652
|
-
}
|
|
653
|
-
|
|
654
|
-
// Flow info dialog state — driven by core/show-flow-info action
|
|
655
|
-
let flowDialogOpen = $state(false)
|
|
656
|
-
let flowName = $state('default')
|
|
657
|
-
let flowJson = $state('')
|
|
658
|
-
let flowError: string | null = $state(null)
|
|
659
|
-
|
|
660
|
-
function showFlowInfoDialog(name: string, json: string, error: string | null) {
|
|
661
|
-
flowName = name
|
|
662
|
-
flowJson = json
|
|
663
|
-
flowError = error
|
|
664
|
-
flowDialogOpen = true
|
|
665
|
-
}
|
|
666
|
-
</script>
|
|
667
|
-
|
|
668
|
-
{#if !isEmbed}
|
|
669
|
-
{#if visible && canvasActive && canvasMenus.length > 0}
|
|
670
|
-
<div
|
|
671
|
-
class="fixed bottom-6 left-6 z-[9999] font-sans flex items-center gap-3"
|
|
672
|
-
role="toolbar"
|
|
673
|
-
aria-label="Canvas toolbar"
|
|
674
|
-
>
|
|
675
|
-
{#each canvasMenus as canvasTool (canvasTool.key)}
|
|
676
|
-
{#if toolComponents[canvasTool.key]}
|
|
677
|
-
{@const CanvasToolComponent = toolComponents[canvasTool.key]}
|
|
678
|
-
{#if canvasTool.render === 'menu'}
|
|
679
|
-
<Tooltip.Root>
|
|
680
|
-
<Tooltip.Trigger>
|
|
681
|
-
<span data-local-only={isToolbarToolLocalOnly(canvasTool.key) || undefined}>
|
|
682
|
-
<CanvasToolComponent
|
|
683
|
-
config={canvasTool}
|
|
684
|
-
data={toolData[canvasTool.key]}
|
|
685
|
-
canvasName={activeCanvasId}
|
|
686
|
-
zoom={canvasZoom}
|
|
687
|
-
tabindex={0}
|
|
688
|
-
/>
|
|
689
|
-
</span>
|
|
690
|
-
</Tooltip.Trigger>
|
|
691
|
-
<Tooltip.Content side="top">{canvasTool.ariaLabel || canvasTool.key}</Tooltip.Content>
|
|
692
|
-
</Tooltip.Root>
|
|
693
|
-
{:else}
|
|
694
|
-
<CanvasToolComponent
|
|
695
|
-
config={canvasTool}
|
|
696
|
-
data={toolData[canvasTool.key]}
|
|
697
|
-
canvasName={activeCanvasId}
|
|
698
|
-
zoom={canvasZoom}
|
|
699
|
-
tabindex={0}
|
|
700
|
-
/>
|
|
701
|
-
{/if}
|
|
702
|
-
{/if}
|
|
703
|
-
{/each}
|
|
704
|
-
</div>
|
|
705
|
-
{/if}
|
|
706
|
-
<div
|
|
707
|
-
id="storyboard-controls"
|
|
708
|
-
class="fixed bottom-6 right-6 z-[9999] font-sans flex items-end gap-3"
|
|
709
|
-
data-core-ui-bar
|
|
710
|
-
role="toolbar"
|
|
711
|
-
tabindex="0"
|
|
712
|
-
aria-label="Storyboard controls"
|
|
713
|
-
onkeydown={handleToolbarKeydown}
|
|
714
|
-
bind:this={toolbarEl}
|
|
715
|
-
>
|
|
716
|
-
{#if visible && !isMobileState}
|
|
717
|
-
{#each cleanedMenus as menu, i (menu.key)}
|
|
718
|
-
{#if menu.render === 'separator'}
|
|
719
|
-
<div class="toolbar-separator" aria-hidden="true"></div>
|
|
720
|
-
{:else}
|
|
721
|
-
<Tooltip.Root>
|
|
722
|
-
<Tooltip.Trigger>
|
|
723
|
-
{#if menu.render === 'sidepanel'}
|
|
724
|
-
{@const toolState = getToolbarToolState(menu.key)}
|
|
725
|
-
<TriggerButton
|
|
726
|
-
active={$sidePanelState.open && $sidePanelState.activeTab === menu.sidepanel}
|
|
727
|
-
inactive={toolState === 'inactive'}
|
|
728
|
-
dimmed={toolState === 'dimmed'}
|
|
729
|
-
localOnly={isToolbarToolLocalOnly(menu.key)}
|
|
730
|
-
size="icon-xl"
|
|
731
|
-
aria-label={menu.ariaLabel || menu.key}
|
|
732
|
-
tabindex={getTabindex(i)}
|
|
733
|
-
onfocus={() => { activeToolbarIndex = i }}
|
|
734
|
-
onclick={() => togglePanel(menu.sidepanel)}
|
|
735
|
-
>
|
|
736
|
-
<Icon name={menu.icon || menu.key} size={16} {...(menu.meta || {})} />
|
|
737
|
-
</TriggerButton>
|
|
738
|
-
{:else if toolComponents[menu.key]}
|
|
739
|
-
{@const toolState = getToolbarToolState(menu.key)}
|
|
740
|
-
{@const ToolComponent = toolComponents[menu.key]}
|
|
741
|
-
<span
|
|
742
|
-
data-tool-state={toolState}
|
|
743
|
-
data-local-only={isToolbarToolLocalOnly(menu.key) || undefined}
|
|
744
|
-
class={toolState === 'inactive' ? 'tool-inactive' : toolState === 'dimmed' ? 'tool-dimmed' : ''}
|
|
745
|
-
>
|
|
746
|
-
<ToolComponent
|
|
747
|
-
config={menu}
|
|
748
|
-
data={toolData[menu.key]}
|
|
749
|
-
tabindex={getTabindex(i)}
|
|
750
|
-
localOnly={isToolbarToolLocalOnly(menu.key)}
|
|
751
|
-
{basePath}
|
|
752
|
-
/>
|
|
753
|
-
</span>
|
|
754
|
-
{/if}
|
|
755
|
-
</Tooltip.Trigger>
|
|
756
|
-
<Tooltip.Content side="top">{menu.ariaLabel || menu.key}</Tooltip.Content>
|
|
757
|
-
</Tooltip.Root>
|
|
758
|
-
{/if}
|
|
759
|
-
{/each}
|
|
760
|
-
{/if}
|
|
761
|
-
{#if commandMenuConfig}
|
|
762
|
-
<div class={visible ? '' : 'default-button-dimmed'}>
|
|
763
|
-
<Tooltip.Root>
|
|
764
|
-
<Tooltip.Trigger>
|
|
765
|
-
<CommandPalette tabindex={getTabindex(commandMenuIndex)} icon={commandMenuConfig.icon} iconMeta={commandMenuConfig.meta} />
|
|
766
|
-
</Tooltip.Trigger>
|
|
767
|
-
<Tooltip.Content side="top">Command Menu</Tooltip.Content>
|
|
768
|
-
</Tooltip.Root>
|
|
769
|
-
</div>
|
|
770
|
-
{/if}
|
|
771
|
-
</div>
|
|
772
|
-
{/if}
|
|
773
|
-
|
|
774
|
-
{#if !isEmbed && SidePanel}
|
|
775
|
-
<SidePanel onClose={() => focusToolbarItem(activeToolbarIndex < 0 ? toolbarItemCount - 1 : activeToolbarIndex)} />
|
|
776
|
-
{/if}
|
|
777
|
-
|
|
778
|
-
{#if !isEmbed}
|
|
779
|
-
<PwaInstallBanner />
|
|
780
|
-
{/if}
|
|
781
|
-
|
|
782
|
-
<!-- Flow info panel (previously inside CommandMenu) -->
|
|
783
|
-
<Panel.Root bind:open={flowDialogOpen}>
|
|
784
|
-
<Panel.Content>
|
|
785
|
-
<Panel.Header>
|
|
786
|
-
<Panel.Title>Flow: {flowName}</Panel.Title>
|
|
787
|
-
<Panel.Close />
|
|
788
|
-
</Panel.Header>
|
|
789
|
-
<Panel.Body>
|
|
790
|
-
{#if flowError}
|
|
791
|
-
<span class="text-destructive text-sm">{flowError}</span>
|
|
792
|
-
{:else}
|
|
793
|
-
<pre class="m-0 bg-transparent text-sm font-mono leading-relaxed whitespace-pre-wrap break-words">{flowJson}</pre>
|
|
794
|
-
{/if}
|
|
795
|
-
</Panel.Body>
|
|
796
|
-
</Panel.Content>
|
|
797
|
-
</Panel.Root>
|
|
798
|
-
|
|
799
|
-
<style>
|
|
800
|
-
.toolbar-separator {
|
|
801
|
-
width: 1px;
|
|
802
|
-
height: 20px;
|
|
803
|
-
background: var(--sb--trigger-border, var(--color-slate-400));
|
|
804
|
-
opacity: 0.4;
|
|
805
|
-
flex-shrink: 0;
|
|
806
|
-
}
|
|
807
|
-
|
|
808
|
-
.default-button-dimmed {
|
|
809
|
-
opacity: 0.3;
|
|
810
|
-
transition: opacity 200ms;
|
|
811
|
-
}
|
|
812
|
-
|
|
813
|
-
.default-button-dimmed:hover,
|
|
814
|
-
.default-button-dimmed:focus-within {
|
|
815
|
-
opacity: 1;
|
|
816
|
-
}
|
|
817
|
-
|
|
818
|
-
.tool-inactive {
|
|
819
|
-
opacity: 0.45;
|
|
820
|
-
pointer-events: none;
|
|
821
|
-
}
|
|
822
|
-
.tool-dimmed {
|
|
823
|
-
opacity: 0.3;
|
|
824
|
-
transition: opacity 200ms;
|
|
825
|
-
}
|
|
826
|
-
.tool-dimmed:hover,
|
|
827
|
-
.tool-dimmed:focus-within {
|
|
828
|
-
opacity: 1;
|
|
829
|
-
}
|
|
830
|
-
[data-local-only] {
|
|
831
|
-
position: relative;
|
|
832
|
-
}
|
|
833
|
-
[data-local-only]::after {
|
|
834
|
-
content: '';
|
|
835
|
-
position: absolute;
|
|
836
|
-
top: -1px;
|
|
837
|
-
right: -1px;
|
|
838
|
-
width: 8px;
|
|
839
|
-
height: 8px;
|
|
840
|
-
background: hsl(212, 92%, 45%);
|
|
841
|
-
border-radius: 50%;
|
|
842
|
-
border: 2px solid var(--sb--sc-border-color, transparent);
|
|
843
|
-
box-sizing: content-box;
|
|
844
|
-
pointer-events: none;
|
|
845
|
-
z-index: 1;
|
|
846
|
-
}
|
|
847
|
-
</style>
|