@dfosco/storyboard 0.5.0-alpha.0
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 +152 -0
- package/dist/storyboard-ui.css +1 -0
- package/dist/storyboard-ui.js +21328 -0
- package/dist/storyboard-ui.js.map +1 -0
- package/dist/tailwind.css +2 -0
- package/dist/tiny-canvas.css +1 -0
- package/dist/tiny-canvas.js +389 -0
- package/package.json +121 -0
- package/paste.config.json +67 -0
- package/scaffold/AGENTS.md +432 -0
- 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/deploy.yml +103 -0
- package/scaffold/githooks/pre-push +114 -0
- package/scaffold/gitignore +64 -0
- package/scaffold/manifest.json +56 -0
- package/scaffold/preview.yml +181 -0
- package/scaffold/scripts/link.sh +26 -0
- package/scaffold/scripts/unlink.sh +10 -0
- package/scaffold/skills/agent-browser/SKILL.md +260 -0
- package/scaffold/skills/canvas/SKILL.md +364 -0
- package/scaffold/skills/create/SKILL.md +501 -0
- package/scaffold/skills/ship/SKILL.md +237 -0
- package/scaffold/skills/storyboard/SKILL.md +360 -0
- package/scaffold/skills/update-storyboard/SKILL.md +16 -0
- package/scaffold/skills/update-storyboard/update-storyboard-packages.sh +26 -0
- package/scaffold/skills/vitest/GENERATION.md +5 -0
- package/scaffold/skills/vitest/SKILL.md +52 -0
- package/scaffold/skills/vitest/references/advanced-environments.md +264 -0
- package/scaffold/skills/vitest/references/advanced-projects.md +300 -0
- package/scaffold/skills/vitest/references/advanced-type-testing.md +237 -0
- package/scaffold/skills/vitest/references/advanced-vi.md +249 -0
- package/scaffold/skills/vitest/references/core-cli.md +166 -0
- package/scaffold/skills/vitest/references/core-config.md +174 -0
- package/scaffold/skills/vitest/references/core-describe.md +193 -0
- package/scaffold/skills/vitest/references/core-expect.md +219 -0
- package/scaffold/skills/vitest/references/core-hooks.md +244 -0
- package/scaffold/skills/vitest/references/core-test-api.md +233 -0
- package/scaffold/skills/vitest/references/features-concurrency.md +250 -0
- package/scaffold/skills/vitest/references/features-context.md +238 -0
- package/scaffold/skills/vitest/references/features-coverage.md +207 -0
- package/scaffold/skills/vitest/references/features-filtering.md +211 -0
- package/scaffold/skills/vitest/references/features-mocking.md +265 -0
- package/scaffold/skills/vitest/references/features-snapshots.md +207 -0
- package/scaffold/skills/worktree/SKILL.md +93 -0
- package/scaffold/storyboard.config.json +44 -0
- package/src/canvas/Canvas.jsx +78 -0
- package/src/canvas/Draggable.jsx +235 -0
- package/src/canvas/index.d.ts +41 -0
- package/src/canvas/index.js +6 -0
- package/src/canvas/style.css +118 -0
- package/src/canvas/useResetCanvas.js +17 -0
- package/src/canvas/utils.js +136 -0
- package/src/core/assets/fonts/IoskeleyMono-Bold.woff2 +0 -0
- package/src/core/assets/fonts/IoskeleyMono-Italic.woff2 +0 -0
- package/src/core/assets/fonts/IoskeleyMono-Medium.woff2 +0 -0
- package/src/core/assets/fonts/IoskeleyMono-Regular.woff2 +0 -0
- package/src/core/assets/fonts/IoskeleyMono-SemiBold.woff2 +0 -0
- package/src/core/autosync/server.js +714 -0
- package/src/core/autosync/server.test.js +158 -0
- package/src/core/canvas/__tests__/agent-integration.test.js +596 -0
- package/src/core/canvas/__tests__/helpers/browser.js +95 -0
- package/src/core/canvas/__tests__/helpers/canvas-api.js +129 -0
- package/src/core/canvas/__tests__/helpers/perf.js +118 -0
- package/src/core/canvas/__tests__/helpers/setup.js +176 -0
- package/src/core/canvas/__tests__/helpers/tmux.js +130 -0
- package/src/core/canvas/__tests__/helpers/transcript.js +132 -0
- package/src/core/canvas/__tests__/terminal-integration.test.js +177 -0
- package/src/core/canvas/collision.js +292 -0
- package/src/core/canvas/collision.test.js +371 -0
- package/src/core/canvas/compact.js +83 -0
- package/src/core/canvas/deriveCanvasId.test.js +40 -0
- package/src/core/canvas/githubEmbeds.js +527 -0
- package/src/core/canvas/githubEmbeds.test.js +302 -0
- package/src/core/canvas/hot-pool.js +766 -0
- package/src/core/canvas/identity.js +107 -0
- package/src/core/canvas/identity.test.js +100 -0
- package/src/core/canvas/materializer.js +259 -0
- package/src/core/canvas/materializer.test.js +356 -0
- package/src/core/canvas/selectedWidgets.js +270 -0
- package/src/core/canvas/selectedWidgets.test.js +321 -0
- package/src/core/canvas/server.js +3134 -0
- package/src/core/canvas/server.test.js +379 -0
- package/src/core/canvas/terminal-config.js +330 -0
- package/src/core/canvas/terminal-registry.js +465 -0
- package/src/core/canvas/terminal-server.js +1436 -0
- package/src/core/canvas/writeGuard.js +53 -0
- package/src/core/cli/agent.js +85 -0
- package/src/core/cli/branch.js +386 -0
- package/src/core/cli/canvasAdd.js +241 -0
- package/src/core/cli/canvasBatch.js +98 -0
- package/src/core/cli/canvasBounds.js +160 -0
- package/src/core/cli/canvasRead.js +236 -0
- package/src/core/cli/canvasUpdate.js +179 -0
- package/src/core/cli/code.js +67 -0
- package/src/core/cli/compact.js +62 -0
- package/src/core/cli/create.js +674 -0
- package/src/core/cli/dev-helpers.js +53 -0
- package/src/core/cli/dev-helpers.test.js +53 -0
- package/src/core/cli/dev.js +430 -0
- package/src/core/cli/exit.js +38 -0
- package/src/core/cli/flags.js +174 -0
- package/src/core/cli/flags.test.js +155 -0
- package/src/core/cli/index.js +233 -0
- package/src/core/cli/intro.js +37 -0
- package/src/core/cli/proxy.js +319 -0
- package/src/core/cli/proxy.test.js +63 -0
- package/src/core/cli/schemas.js +223 -0
- package/src/core/cli/server.js +192 -0
- package/src/core/cli/serverUrl.js +61 -0
- package/src/core/cli/sessions.js +459 -0
- package/src/core/cli/setup.js +404 -0
- package/src/core/cli/terminal-commands.js +287 -0
- package/src/core/cli/terminal-messaging.js +231 -0
- package/src/core/cli/terminal-welcome.js +515 -0
- package/src/core/cli/updateVersion.js +124 -0
- package/src/core/comments/api.js +284 -0
- package/src/core/comments/api.test.js +282 -0
- package/src/core/comments/auth.js +151 -0
- package/src/core/comments/auth.test.js +167 -0
- package/src/core/comments/commentCache.js +109 -0
- package/src/core/comments/commentCache.test.js +48 -0
- package/src/core/comments/commentDrafts.js +68 -0
- package/src/core/comments/commentMode.js +63 -0
- package/src/core/comments/commentMode.test.js +90 -0
- package/src/core/comments/config.js +47 -0
- package/src/core/comments/config.test.js +77 -0
- package/src/core/comments/graphql.js +65 -0
- package/src/core/comments/graphql.test.js +95 -0
- package/src/core/comments/index.js +42 -0
- package/src/core/comments/metadata.js +52 -0
- package/src/core/comments/metadata.test.js +110 -0
- package/src/core/comments/queries.js +245 -0
- package/src/core/comments/ui/AuthModal.jsx +114 -0
- package/src/core/comments/ui/CommentOverlay.js +52 -0
- package/src/core/comments/ui/CommentWindow.jsx +329 -0
- package/src/core/comments/ui/CommentsDrawer.jsx +102 -0
- package/src/core/comments/ui/Composer.jsx +64 -0
- package/src/core/comments/ui/authModal.js +66 -0
- package/src/core/comments/ui/authModal.test.js +76 -0
- package/src/core/comments/ui/comment-cursor-dark.svg +1 -0
- package/src/core/comments/ui/comment-cursor.svg +1 -0
- package/src/core/comments/ui/comment-layout.css +142 -0
- package/src/core/comments/ui/commentWindow.js +121 -0
- package/src/core/comments/ui/comments.css +242 -0
- package/src/core/comments/ui/commentsDrawer.js +84 -0
- package/src/core/comments/ui/composer.js +136 -0
- package/src/core/comments/ui/index.js +14 -0
- package/src/core/comments/ui/mount.js +687 -0
- package/src/core/comments/ui/mount.test.js +336 -0
- package/src/core/data/dotPath.js +53 -0
- package/src/core/data/dotPath.test.js +114 -0
- package/src/core/data/loader.js +409 -0
- package/src/core/data/loader.test.js +599 -0
- package/src/core/data/viewfinder.js +363 -0
- package/src/core/data/viewfinder.test.js +456 -0
- package/src/core/devtools/devtools-consumer.js +28 -0
- package/src/core/devtools/devtools.js +144 -0
- package/src/core/devtools/devtools.test.js +75 -0
- package/src/core/devtools/sceneDebug.js +112 -0
- package/src/core/devtools/sceneDebug.test.js +141 -0
- package/src/core/index.js +124 -0
- package/src/core/inspector/fiberWalker.js +239 -0
- package/src/core/inspector/highlighter.js +275 -0
- package/src/core/inspector/mouseMode.js +259 -0
- package/src/core/lib/components/ui/alert/alert-action.jsx +11 -0
- package/src/core/lib/components/ui/alert/alert-description.jsx +11 -0
- package/src/core/lib/components/ui/alert/alert-title.jsx +11 -0
- package/src/core/lib/components/ui/alert/alert.jsx +25 -0
- package/src/core/lib/components/ui/alert/index.js +17 -0
- package/src/core/lib/components/ui/avatar/avatar-badge.jsx +22 -0
- package/src/core/lib/components/ui/avatar/avatar-fallback.jsx +18 -0
- package/src/core/lib/components/ui/avatar/avatar-group-count.jsx +19 -0
- package/src/core/lib/components/ui/avatar/avatar-group.jsx +19 -0
- package/src/core/lib/components/ui/avatar/avatar-image.jsx +15 -0
- package/src/core/lib/components/ui/avatar/avatar.jsx +19 -0
- package/src/core/lib/components/ui/avatar/index.js +22 -0
- package/src/core/lib/components/ui/badge/badge.jsx +31 -0
- package/src/core/lib/components/ui/badge/index.js +2 -0
- package/src/core/lib/components/ui/button/button.jsx +100 -0
- package/src/core/lib/components/ui/button/index.js +12 -0
- package/src/core/lib/components/ui/card/card-action.jsx +11 -0
- package/src/core/lib/components/ui/card/card-content.jsx +11 -0
- package/src/core/lib/components/ui/card/card-description.jsx +11 -0
- package/src/core/lib/components/ui/card/card-footer.jsx +11 -0
- package/src/core/lib/components/ui/card/card-header.jsx +19 -0
- package/src/core/lib/components/ui/card/card-title.jsx +11 -0
- package/src/core/lib/components/ui/card/card.jsx +17 -0
- package/src/core/lib/components/ui/card/index.js +25 -0
- package/src/core/lib/components/ui/checkbox/checkbox.jsx +29 -0
- package/src/core/lib/components/ui/checkbox/index.js +6 -0
- package/src/core/lib/components/ui/collapsible/collapsible-content.jsx +7 -0
- package/src/core/lib/components/ui/collapsible/collapsible-trigger.jsx +7 -0
- package/src/core/lib/components/ui/collapsible/collapsible.jsx +7 -0
- package/src/core/lib/components/ui/collapsible/index.js +13 -0
- package/src/core/lib/components/ui/dialog/dialog-close.jsx +7 -0
- package/src/core/lib/components/ui/dialog/dialog-content.jsx +34 -0
- package/src/core/lib/components/ui/dialog/dialog-description.jsx +15 -0
- package/src/core/lib/components/ui/dialog/dialog-footer.jsx +23 -0
- package/src/core/lib/components/ui/dialog/dialog-header.jsx +11 -0
- package/src/core/lib/components/ui/dialog/dialog-overlay.jsx +15 -0
- package/src/core/lib/components/ui/dialog/dialog-portal.jsx +4 -0
- package/src/core/lib/components/ui/dialog/dialog-title.jsx +15 -0
- package/src/core/lib/components/ui/dialog/dialog-trigger.jsx +7 -0
- package/src/core/lib/components/ui/dialog/dialog.jsx +4 -0
- package/src/core/lib/components/ui/dialog/index.js +34 -0
- package/src/core/lib/components/ui/dropdown-menu/dropdown-menu-checkbox-group.jsx +8 -0
- package/src/core/lib/components/ui/dropdown-menu/dropdown-menu-checkbox-item.jsx +30 -0
- package/src/core/lib/components/ui/dropdown-menu/dropdown-menu-content.jsx +22 -0
- package/src/core/lib/components/ui/dropdown-menu/dropdown-menu-group-heading.jsx +16 -0
- package/src/core/lib/components/ui/dropdown-menu/dropdown-menu-group.jsx +7 -0
- package/src/core/lib/components/ui/dropdown-menu/dropdown-menu-item.jsx +20 -0
- package/src/core/lib/components/ui/dropdown-menu/dropdown-menu-label.jsx +17 -0
- package/src/core/lib/components/ui/dropdown-menu/dropdown-menu-portal.jsx +4 -0
- package/src/core/lib/components/ui/dropdown-menu/dropdown-menu-radio-group.jsx +7 -0
- package/src/core/lib/components/ui/dropdown-menu/dropdown-menu-radio-item.jsx +29 -0
- package/src/core/lib/components/ui/dropdown-menu/dropdown-menu-separator.jsx +15 -0
- package/src/core/lib/components/ui/dropdown-menu/dropdown-menu-shortcut.jsx +16 -0
- package/src/core/lib/components/ui/dropdown-menu/dropdown-menu-sub-content.jsx +15 -0
- package/src/core/lib/components/ui/dropdown-menu/dropdown-menu-sub-trigger.jsx +23 -0
- package/src/core/lib/components/ui/dropdown-menu/dropdown-menu-sub.jsx +4 -0
- package/src/core/lib/components/ui/dropdown-menu/dropdown-menu-trigger.jsx +7 -0
- package/src/core/lib/components/ui/dropdown-menu/dropdown-menu.jsx +4 -0
- package/src/core/lib/components/ui/dropdown-menu/index.js +54 -0
- package/src/core/lib/components/ui/input/index.js +7 -0
- package/src/core/lib/components/ui/input/input.jsx +19 -0
- package/src/core/lib/components/ui/label/index.js +7 -0
- package/src/core/lib/components/ui/label/label.jsx +19 -0
- package/src/core/lib/components/ui/panel/index.js +24 -0
- package/src/core/lib/components/ui/panel/panel-body.jsx +11 -0
- package/src/core/lib/components/ui/panel/panel-close.jsx +16 -0
- package/src/core/lib/components/ui/panel/panel-content.jsx +29 -0
- package/src/core/lib/components/ui/panel/panel-footer.jsx +11 -0
- package/src/core/lib/components/ui/panel/panel-header.jsx +11 -0
- package/src/core/lib/components/ui/panel/panel-title.jsx +12 -0
- package/src/core/lib/components/ui/panel/panel.jsx +4 -0
- package/src/core/lib/components/ui/popover/index.js +28 -0
- package/src/core/lib/components/ui/popover/popover-close.jsx +7 -0
- package/src/core/lib/components/ui/popover/popover-content.jsx +22 -0
- package/src/core/lib/components/ui/popover/popover-description.jsx +11 -0
- package/src/core/lib/components/ui/popover/popover-header.jsx +11 -0
- package/src/core/lib/components/ui/popover/popover-portal.jsx +4 -0
- package/src/core/lib/components/ui/popover/popover-title.jsx +11 -0
- package/src/core/lib/components/ui/popover/popover-trigger.jsx +8 -0
- package/src/core/lib/components/ui/popover/popover.jsx +4 -0
- package/src/core/lib/components/ui/searchable-list.jsx +160 -0
- package/src/core/lib/components/ui/select/index.js +37 -0
- package/src/core/lib/components/ui/select/select-content.jsx +30 -0
- package/src/core/lib/components/ui/select/select-group-heading.jsx +17 -0
- package/src/core/lib/components/ui/select/select-group.jsx +15 -0
- package/src/core/lib/components/ui/select/select-item.jsx +26 -0
- package/src/core/lib/components/ui/select/select-label.jsx +11 -0
- package/src/core/lib/components/ui/select/select-portal.jsx +4 -0
- package/src/core/lib/components/ui/select/select-scroll-down-button.jsx +18 -0
- package/src/core/lib/components/ui/select/select-scroll-up-button.jsx +18 -0
- package/src/core/lib/components/ui/select/select-separator.jsx +15 -0
- package/src/core/lib/components/ui/select/select-trigger.jsx +25 -0
- package/src/core/lib/components/ui/select/select.jsx +4 -0
- package/src/core/lib/components/ui/separator/index.js +7 -0
- package/src/core/lib/components/ui/separator/separator.jsx +22 -0
- package/src/core/lib/components/ui/sheet/index.js +34 -0
- package/src/core/lib/components/ui/sheet/sheet-close.jsx +7 -0
- package/src/core/lib/components/ui/sheet/sheet-content.jsx +35 -0
- package/src/core/lib/components/ui/sheet/sheet-description.jsx +15 -0
- package/src/core/lib/components/ui/sheet/sheet-footer.jsx +11 -0
- package/src/core/lib/components/ui/sheet/sheet-header.jsx +11 -0
- package/src/core/lib/components/ui/sheet/sheet-overlay.jsx +15 -0
- package/src/core/lib/components/ui/sheet/sheet-portal.jsx +4 -0
- package/src/core/lib/components/ui/sheet/sheet-title.jsx +15 -0
- package/src/core/lib/components/ui/sheet/sheet-trigger.jsx +7 -0
- package/src/core/lib/components/ui/sheet/sheet.jsx +4 -0
- package/src/core/lib/components/ui/textarea/index.js +7 -0
- package/src/core/lib/components/ui/textarea/textarea.jsx +18 -0
- package/src/core/lib/components/ui/toggle/index.js +8 -0
- package/src/core/lib/components/ui/toggle/toggle.jsx +36 -0
- package/src/core/lib/components/ui/toggle-group/index.js +10 -0
- package/src/core/lib/components/ui/toggle-group/toggle-group-item.jsx +29 -0
- package/src/core/lib/components/ui/toggle-group/toggle-group.jsx +43 -0
- package/src/core/lib/components/ui/tooltip/index.js +3 -0
- package/src/core/lib/components/ui/tooltip/tooltip-content.jsx +21 -0
- package/src/core/lib/components/ui/tooltip/tooltip-trigger.jsx +23 -0
- package/src/core/lib/components/ui/tooltip/tooltip.jsx +11 -0
- package/src/core/lib/components/ui/trigger-button/index.js +6 -0
- package/src/core/lib/components/ui/trigger-button/trigger-button.css +38 -0
- package/src/core/lib/components/ui/trigger-button/trigger-button.jsx +63 -0
- package/src/core/lib/utils/index.js +6 -0
- package/src/core/logger/devLogger.js +238 -0
- package/src/core/logger/devLogger.test.js +193 -0
- package/src/core/modes/modes.css +98 -0
- package/src/core/modes/modes.js +492 -0
- package/src/core/modes/modes.test.js +562 -0
- package/src/core/mountStoryboardCore.js +478 -0
- package/src/core/rename-watcher/config.json +23 -0
- package/src/core/rename-watcher/watcher.js +531 -0
- package/src/core/scaffold.js +100 -0
- package/src/core/server/index.js +391 -0
- package/src/core/session/bodyClasses.js +128 -0
- package/src/core/session/bodyClasses.test.js +192 -0
- package/src/core/session/hashSubscribe.js +19 -0
- package/src/core/session/hashSubscribe.test.js +62 -0
- package/src/core/session/hideMode.js +424 -0
- package/src/core/session/hideMode.test.js +268 -0
- package/src/core/session/interceptHideParams.js +35 -0
- package/src/core/session/interceptHideParams.test.js +90 -0
- package/src/core/session/localStorage.js +134 -0
- package/src/core/session/localStorage.test.js +148 -0
- package/src/core/session/session.js +76 -0
- package/src/core/session/session.test.js +91 -0
- package/src/core/stores/canvasConfig.js +134 -0
- package/src/core/stores/canvasConfig.test.js +120 -0
- package/src/core/stores/commandActions.js +284 -0
- package/src/core/stores/commandPaletteConfig.js +31 -0
- package/src/core/stores/configSchema.js +232 -0
- package/src/core/stores/configSchema.test.js +72 -0
- package/src/core/stores/configStore.js +161 -0
- package/src/core/stores/customerModeConfig.js +30 -0
- package/src/core/stores/featureFlags.js +127 -0
- package/src/core/stores/paletteProviders.js +360 -0
- package/src/core/stores/paletteProviders.test.js +186 -0
- package/src/core/stores/plugins.js +40 -0
- package/src/core/stores/plugins.test.js +68 -0
- package/src/core/stores/recentArtifacts.js +68 -0
- package/src/core/stores/recentArtifacts.test.js +71 -0
- package/src/core/stores/sidePanelStore.ts +143 -0
- package/src/core/stores/themeStore.ts +291 -0
- package/src/core/stores/toolRegistry.js +227 -0
- package/src/core/stores/toolStateStore.js +183 -0
- package/src/core/stores/toolStateStore.test.js +220 -0
- package/src/core/stores/toolbarConfigStore.js +165 -0
- package/src/core/stores/uiConfig.js +64 -0
- package/src/core/stores/uiConfig.test.js +63 -0
- package/src/core/styles/tailwind.css +204 -0
- package/src/core/tools/handlers/autosync.js +12 -0
- package/src/core/tools/handlers/canvasAddWidget.js +11 -0
- package/src/core/tools/handlers/canvasAgents.js +20 -0
- package/src/core/tools/handlers/canvasToolbar.js +56 -0
- package/src/core/tools/handlers/commandPalette.js +9 -0
- package/src/core/tools/handlers/comments.js +16 -0
- package/src/core/tools/handlers/create.js +39 -0
- package/src/core/tools/handlers/devtools.js +122 -0
- package/src/core/tools/handlers/devtools.test.js +87 -0
- package/src/core/tools/handlers/featureFlags.js +21 -0
- package/src/core/tools/handlers/flows.js +68 -0
- package/src/core/tools/handlers/hideChrome.js +9 -0
- package/src/core/tools/handlers/hideToolbars.js +25 -0
- package/src/core/tools/handlers/inspector.js +19 -0
- package/src/core/tools/handlers/paletteTheme.js +35 -0
- package/src/core/tools/handlers/theme.js +9 -0
- package/src/core/tools/registry.js +26 -0
- package/src/core/tools/surfaces/canvasToolbar.js +10 -0
- package/src/core/tools/surfaces/commandList.js +10 -0
- package/src/core/tools/surfaces/mainToolbar.js +11 -0
- package/src/core/tools/surfaces/registry.js +19 -0
- package/src/core/ui/ActionMenuButton.jsx +114 -0
- package/src/core/ui/AutosyncMenuButton.css +67 -0
- package/src/core/ui/AutosyncMenuButton.jsx +242 -0
- package/src/core/ui/BranchSelect.jsx +29 -0
- package/src/core/ui/BranchSelect.module.css +30 -0
- package/src/core/ui/CanvasAgentsMenu.jsx +89 -0
- package/src/core/ui/CanvasCreateMenu.jsx +611 -0
- package/src/core/ui/CanvasSnap.css +27 -0
- package/src/core/ui/CanvasSnap.jsx +51 -0
- package/src/core/ui/CanvasUndoRedo.css +36 -0
- package/src/core/ui/CanvasUndoRedo.jsx +62 -0
- package/src/core/ui/CanvasZoomControl.css +53 -0
- package/src/core/ui/CanvasZoomControl.jsx +49 -0
- package/src/core/ui/CanvasZoomToFit.css +18 -0
- package/src/core/ui/CanvasZoomToFit.jsx +26 -0
- package/src/core/ui/CommandMenu.css +8 -0
- package/src/core/ui/CommandMenu.jsx +287 -0
- package/src/core/ui/CommandPalette.jsx +35 -0
- package/src/core/ui/CommandPaletteTrigger.jsx +25 -0
- package/src/core/ui/CommentsMenuButton.jsx +40 -0
- package/src/core/ui/CoreUIBar.css +47 -0
- package/src/core/ui/CoreUIBar.jsx +905 -0
- package/src/core/ui/CreateMenuButton.jsx +117 -0
- package/src/core/ui/HideChromeTrigger.jsx +48 -0
- package/src/core/ui/Icon.jsx +279 -0
- package/src/core/ui/InspectorPanel.css +109 -0
- package/src/core/ui/InspectorPanel.jsx +632 -0
- package/src/core/ui/PwaInstallBanner.css +42 -0
- package/src/core/ui/PwaInstallBanner.jsx +124 -0
- package/src/core/ui/SidePanel.jsx +261 -0
- package/src/core/ui/ThemeMenuButton.jsx +139 -0
- package/src/core/ui/core-ui-colors.css +129 -0
- package/src/core/ui/design-modes.ts +7 -0
- package/src/core/ui/sidepanel.css +301 -0
- package/src/core/ui/viewfinder.ts +7 -0
- package/src/core/ui-entry.js +30 -0
- package/src/core/utils/fuzzySearch.js +117 -0
- package/src/core/utils/fuzzySearch.test.js +119 -0
- package/src/core/utils/mobileViewport.js +57 -0
- package/src/core/utils/mobileViewport.test.js +68 -0
- package/src/core/utils/prodMode.js +38 -0
- package/src/core/utils/smoothCorners.js +20 -0
- package/src/core/vite/docs-handler.js +155 -0
- package/src/core/vite/server-plugin.js +797 -0
- package/src/core/workshop/features/createCanvas/CreateCanvasForm.jsx +260 -0
- package/src/core/workshop/features/createCanvas/index.js +14 -0
- package/src/core/workshop/features/createFlow/CreateFlowForm.jsx +334 -0
- package/src/core/workshop/features/createFlow/index.js +19 -0
- package/src/core/workshop/features/createFlow/server.js +663 -0
- package/src/core/workshop/features/createPage/CreatePageForm.jsx +304 -0
- package/src/core/workshop/features/createPage/index.js +11 -0
- package/src/core/workshop/features/createPrototype/CreatePrototypeForm.jsx +289 -0
- package/src/core/workshop/features/createPrototype/index.js +19 -0
- package/src/core/workshop/features/createPrototype/server.js +433 -0
- package/src/core/workshop/features/createStory/CreateStoryForm.jsx +208 -0
- package/src/core/workshop/features/createStory/index.js +14 -0
- package/src/core/workshop/features/registry-server.js +22 -0
- package/src/core/workshop/features/registry.js +28 -0
- package/src/core/workshop/features/templateIndex.js +155 -0
- package/src/core/workshop/ui/WorkshopPanel.jsx +98 -0
- package/src/core/workshop/ui/mount.ts +6 -0
- package/src/core/worktree/port.js +268 -0
- package/src/core/worktree/port.test.js +222 -0
- package/src/core/worktree/serverRegistry.js +120 -0
- package/src/internals/AuthModal/AuthModal.jsx +132 -0
- package/src/internals/AuthModal/AuthModal.module.css +221 -0
- package/src/internals/BranchBar/BranchBar.jsx +87 -0
- package/src/internals/BranchBar/BranchBar.module.css +247 -0
- package/src/internals/BranchBar/useBranches.js +93 -0
- package/src/internals/BranchBar/useBranches.test.js +68 -0
- package/src/internals/CommandPalette/CommandPalette.jsx +1361 -0
- package/src/internals/CommandPalette/CreateDialog.jsx +219 -0
- package/src/internals/CommandPalette/command-palette.css +180 -0
- package/src/internals/FlowError.module.css +30 -0
- package/src/internals/Icon.jsx +279 -0
- package/src/internals/StoryboardContext.js +3 -0
- package/src/internals/Viewfinder.jsx +1479 -0
- package/src/internals/Viewfinder.module.css +1540 -0
- package/src/internals/Workspace.jsx +7 -0
- package/src/internals/__mocks__/virtual-storyboard-data-index.js +4 -0
- package/src/internals/canvas/CanvasControls.jsx +112 -0
- package/src/internals/canvas/CanvasControls.module.css +135 -0
- package/src/internals/canvas/CanvasPage.bridge.test.jsx +387 -0
- package/src/internals/canvas/CanvasPage.dragdrop.test.jsx +350 -0
- package/src/internals/canvas/CanvasPage.jsx +3092 -0
- package/src/internals/canvas/CanvasPage.module.css +187 -0
- package/src/internals/canvas/CanvasPage.multiselect.test.jsx +358 -0
- package/src/internals/canvas/CanvasToolbar.jsx +73 -0
- package/src/internals/canvas/CanvasToolbar.module.css +92 -0
- package/src/internals/canvas/ComponentErrorBoundary.jsx +50 -0
- package/src/internals/canvas/ConnectorLayer.jsx +208 -0
- package/src/internals/canvas/ConnectorLayer.module.css +129 -0
- package/src/internals/canvas/MarqueeOverlay.jsx +20 -0
- package/src/internals/canvas/PageSelector.jsx +587 -0
- package/src/internals/canvas/PageSelector.module.css +261 -0
- package/src/internals/canvas/PageSelector.test.jsx +113 -0
- package/src/internals/canvas/WebGLContextPool.jsx +292 -0
- package/src/internals/canvas/WebGLContextPool.test.jsx +165 -0
- package/src/internals/canvas/canvasApi.js +164 -0
- package/src/internals/canvas/canvasReloadGuard.js +37 -0
- package/src/internals/canvas/canvasReloadGuard.test.js +27 -0
- package/src/internals/canvas/canvasTheme.js +118 -0
- package/src/internals/canvas/componentIsolate.jsx +165 -0
- package/src/internals/canvas/componentSetIsolate.jsx +257 -0
- package/src/internals/canvas/computeCanvasBounds.test.js +121 -0
- package/src/internals/canvas/connectorGeometry.js +132 -0
- package/src/internals/canvas/hotPoolDevLogs.js +25 -0
- package/src/internals/canvas/textSelection.js +10 -0
- package/src/internals/canvas/textSelection.test.js +26 -0
- package/src/internals/canvas/useCanvas.js +126 -0
- package/src/internals/canvas/useCanvas.test.js +26 -0
- package/src/internals/canvas/useMarqueeSelect.js +213 -0
- package/src/internals/canvas/useMarqueeSelect.test.js +78 -0
- package/src/internals/canvas/useUndoRedo.js +86 -0
- package/src/internals/canvas/useUndoRedo.test.js +231 -0
- package/src/internals/canvas/widgets/CodePenEmbed.jsx +293 -0
- package/src/internals/canvas/widgets/CodePenEmbed.module.css +161 -0
- package/src/internals/canvas/widgets/ComponentSetWidget.jsx +2 -0
- package/src/internals/canvas/widgets/ComponentSetWidget.module.css +89 -0
- package/src/internals/canvas/widgets/ComponentWidget.jsx +14 -0
- package/src/internals/canvas/widgets/ComponentWidget.module.css +0 -0
- package/src/internals/canvas/widgets/CropOverlay.jsx +179 -0
- package/src/internals/canvas/widgets/CropOverlay.module.css +154 -0
- package/src/internals/canvas/widgets/ExpandedPane.jsx +474 -0
- package/src/internals/canvas/widgets/ExpandedPane.module.css +179 -0
- package/src/internals/canvas/widgets/ExpandedPane.test.jsx +240 -0
- package/src/internals/canvas/widgets/ExpandedPaneTopBar.jsx +111 -0
- package/src/internals/canvas/widgets/ExpandedPaneTopBar.module.css +59 -0
- package/src/internals/canvas/widgets/ExpandedPaneTopBar.test.jsx +45 -0
- package/src/internals/canvas/widgets/FigmaEmbed.jsx +296 -0
- package/src/internals/canvas/widgets/FigmaEmbed.module.css +222 -0
- package/src/internals/canvas/widgets/FrozenTerminalOverlay.jsx +151 -0
- package/src/internals/canvas/widgets/FrozenTerminalOverlay.module.css +83 -0
- package/src/internals/canvas/widgets/ImageWidget.jsx +287 -0
- package/src/internals/canvas/widgets/ImageWidget.module.css +81 -0
- package/src/internals/canvas/widgets/LinkPreview.jsx +439 -0
- package/src/internals/canvas/widgets/LinkPreview.module.css +585 -0
- package/src/internals/canvas/widgets/LinkPreview.test.jsx +193 -0
- package/src/internals/canvas/widgets/MarkdownBlock.jsx +354 -0
- package/src/internals/canvas/widgets/MarkdownBlock.module.css +377 -0
- package/src/internals/canvas/widgets/MarkdownBlock.test.jsx +92 -0
- package/src/internals/canvas/widgets/PromptWidget.jsx +428 -0
- package/src/internals/canvas/widgets/PromptWidget.module.css +273 -0
- package/src/internals/canvas/widgets/PrototypeEmbed.jsx +463 -0
- package/src/internals/canvas/widgets/PrototypeEmbed.module.css +579 -0
- package/src/internals/canvas/widgets/PrototypeEmbed.test.jsx +10 -0
- package/src/internals/canvas/widgets/ResizeHandle.jsx +67 -0
- package/src/internals/canvas/widgets/ResizeHandle.module.css +29 -0
- package/src/internals/canvas/widgets/StickyNote.jsx +92 -0
- package/src/internals/canvas/widgets/StickyNote.module.css +70 -0
- package/src/internals/canvas/widgets/StickyNote.test.jsx +116 -0
- package/src/internals/canvas/widgets/StorySetWidget.jsx +208 -0
- package/src/internals/canvas/widgets/StorySetWidget.module.css +89 -0
- package/src/internals/canvas/widgets/StoryWidget.jsx +334 -0
- package/src/internals/canvas/widgets/StoryWidget.module.css +211 -0
- package/src/internals/canvas/widgets/TerminalReadWidget.jsx +146 -0
- package/src/internals/canvas/widgets/TerminalReadWidget.module.css +94 -0
- package/src/internals/canvas/widgets/TerminalWidget.jsx +704 -0
- package/src/internals/canvas/widgets/TerminalWidget.module.css +444 -0
- package/src/internals/canvas/widgets/TilesWidget.jsx +300 -0
- package/src/internals/canvas/widgets/TilesWidget.module.css +133 -0
- package/src/internals/canvas/widgets/WidgetChrome.jsx +580 -0
- package/src/internals/canvas/widgets/WidgetChrome.module.css +421 -0
- package/src/internals/canvas/widgets/WidgetWrapper.jsx +15 -0
- package/src/internals/canvas/widgets/WidgetWrapper.module.css +25 -0
- package/src/internals/canvas/widgets/codepenUrl.js +75 -0
- package/src/internals/canvas/widgets/codepenUrl.test.js +76 -0
- package/src/internals/canvas/widgets/embedInteraction.test.jsx +173 -0
- package/src/internals/canvas/widgets/embedOverlay.module.css +35 -0
- package/src/internals/canvas/widgets/embedTheme.js +148 -0
- package/src/internals/canvas/widgets/expandUtils.js +559 -0
- package/src/internals/canvas/widgets/expandUtils.test.js +155 -0
- package/src/internals/canvas/widgets/figmaUrl.js +118 -0
- package/src/internals/canvas/widgets/figmaUrl.test.js +139 -0
- package/src/internals/canvas/widgets/githubUrl.js +82 -0
- package/src/internals/canvas/widgets/githubUrl.test.js +74 -0
- package/src/internals/canvas/widgets/iframeDevLogs.js +49 -0
- package/src/internals/canvas/widgets/iframeDevLogs.test.jsx +81 -0
- package/src/internals/canvas/widgets/index.js +42 -0
- package/src/internals/canvas/widgets/pasteRules.js +295 -0
- package/src/internals/canvas/widgets/pasteRules.test.js +474 -0
- package/src/internals/canvas/widgets/snapshotDisplay.test.jsx +211 -0
- package/src/internals/canvas/widgets/tilePool.js +23 -0
- package/src/internals/canvas/widgets/tiles/diagonal-bl.png +0 -0
- package/src/internals/canvas/widgets/tiles/diagonal-br.png +0 -0
- package/src/internals/canvas/widgets/tiles/diagonal-tl.png +0 -0
- package/src/internals/canvas/widgets/tiles/leaf.png +0 -0
- package/src/internals/canvas/widgets/tiles/quarter-tl.png +0 -0
- package/src/internals/canvas/widgets/tiles/quarter-tr.png +0 -0
- package/src/internals/canvas/widgets/tiles/solid-a.png +0 -0
- package/src/internals/canvas/widgets/tiles/solid-b.png +0 -0
- package/src/internals/canvas/widgets/widgetConfig.js +291 -0
- package/src/internals/canvas/widgets/widgetConfig.test.js +68 -0
- package/src/internals/canvas/widgets/widgetIcons.jsx +190 -0
- package/src/internals/canvas/widgets/widgetProps.js +133 -0
- package/src/internals/context/FormContext.js +13 -0
- package/src/internals/context/FormContext.test.js +48 -0
- package/src/internals/context.jsx +481 -0
- package/src/internals/context.test.jsx +296 -0
- package/src/internals/hashPreserver.js +73 -0
- package/src/internals/hashPreserver.test.js +107 -0
- package/src/internals/hooks/useConfig.js +14 -0
- package/src/internals/hooks/useFeatureFlag.js +14 -0
- package/src/internals/hooks/useFlows.js +50 -0
- package/src/internals/hooks/useFlows.test.js +134 -0
- package/src/internals/hooks/useHideMode.js +31 -0
- package/src/internals/hooks/useHideMode.test.js +43 -0
- package/src/internals/hooks/useLocalStorage.js +57 -0
- package/src/internals/hooks/useLocalStorage.test.js +75 -0
- package/src/internals/hooks/useMode.js +43 -0
- package/src/internals/hooks/useObject.js +101 -0
- package/src/internals/hooks/useObject.test.js +74 -0
- package/src/internals/hooks/useOverride.js +84 -0
- package/src/internals/hooks/useOverride.test.js +71 -0
- package/src/internals/hooks/usePrototypeReloadGuard.js +64 -0
- package/src/internals/hooks/useRecord.js +158 -0
- package/src/internals/hooks/useRecord.test.js +221 -0
- package/src/internals/hooks/useScene.js +38 -0
- package/src/internals/hooks/useScene.test.js +66 -0
- package/src/internals/hooks/useSceneData.js +108 -0
- package/src/internals/hooks/useSceneData.test.js +136 -0
- package/src/internals/hooks/useSession.js +4 -0
- package/src/internals/hooks/useSession.test.js +8 -0
- package/src/internals/hooks/useThemeState.js +61 -0
- package/src/internals/hooks/useThemeState.test.js +66 -0
- package/src/internals/hooks/useUndoRedo.js +28 -0
- package/src/internals/hooks/useUndoRedo.test.js +64 -0
- package/src/internals/index.js +58 -0
- package/src/internals/story/ComponentSetPage.jsx +198 -0
- package/src/internals/story/ComponentSetPage.module.css +129 -0
- package/src/internals/story/StoryPage.jsx +147 -0
- package/src/internals/story/StoryPage.module.css +18 -0
- package/src/internals/test-utils.js +45 -0
- package/src/internals/vite/data-plugin.js +1508 -0
- package/src/internals/vite/data-plugin.test.js +1223 -0
- package/src/test-utils.js +44 -0
- package/toolbar.config.json +271 -0
- package/widgets.config.json +1537 -0
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Command Palette Config — runtime store for commandPalette config.
|
|
3
|
+
* Framework-agnostic (zero npm dependencies).
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import { getConfig } from './configStore.js'
|
|
7
|
+
|
|
8
|
+
let _config = { sections: [] }
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* Initialize the command palette config.
|
|
12
|
+
* @param {object} config - The commandPalette object from storyboard.config.json
|
|
13
|
+
*/
|
|
14
|
+
export function initCommandPaletteConfig(config) {
|
|
15
|
+
_config = { sections: [], ...config }
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* Get the current command palette config.
|
|
20
|
+
* Falls back to the unified config store if the legacy store wasn't initialized.
|
|
21
|
+
* @returns {{ sections: Array }}
|
|
22
|
+
*/
|
|
23
|
+
export function getCommandPaletteConfig() {
|
|
24
|
+
if (_config.sections.length === 0) {
|
|
25
|
+
const uc = getConfig('commandPalette')
|
|
26
|
+
if (uc?.sections?.length > 0) {
|
|
27
|
+
_config = { sections: [], ...uc }
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
return _config
|
|
31
|
+
}
|
|
@@ -0,0 +1,232 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Config Schema — canonical shape and defaults for storyboard.config.json.
|
|
3
|
+
*
|
|
4
|
+
* Every consumer of storyboard.config.json should import `getConfig()` to get
|
|
5
|
+
* a fully defaulted, validated config object. New keys added here are safe for
|
|
6
|
+
* existing projects — they always have defaults.
|
|
7
|
+
*
|
|
8
|
+
* @module configSchema
|
|
9
|
+
*/
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* @typedef {object} PasteRule
|
|
13
|
+
* @property {string} match — regex string tested against pasted URLs
|
|
14
|
+
* @property {string} widget — widget type to create (e.g. "figma-embed", "link-preview")
|
|
15
|
+
* @property {Record<string, string>} [propsMap] — static props merged into widget props
|
|
16
|
+
*/
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* @typedef {object} CanvasTerminalConfig
|
|
20
|
+
* @property {boolean} [resizable] — whether terminal widgets can be resized (default false)
|
|
21
|
+
* @property {number} [defaultWidth] — default width for new terminal widgets
|
|
22
|
+
* @property {number} [defaultHeight] — default height for new terminal widgets
|
|
23
|
+
* @property {number} [fontSize] — terminal font size
|
|
24
|
+
* @property {string} [fontFamily] — terminal font family
|
|
25
|
+
* @property {string} [prompt] — shell prompt string
|
|
26
|
+
* @property {string|null} [startupCommand] — skip welcome screen: "copilot", "shell", or a custom command. null shows welcome.
|
|
27
|
+
* @property {object|null} [defaultStartupSequence] — sequence of steps to run after terminal opens
|
|
28
|
+
*/
|
|
29
|
+
|
|
30
|
+
/**
|
|
31
|
+
* @typedef {object} CanvasZoomConfig
|
|
32
|
+
* @property {number} min — minimum zoom percentage (default 10)
|
|
33
|
+
* @property {number} max — maximum zoom percentage (default 250)
|
|
34
|
+
* @property {number} step — zoom increment/decrement step (default 10)
|
|
35
|
+
*/
|
|
36
|
+
|
|
37
|
+
/**
|
|
38
|
+
* @typedef {object} CanvasConfig
|
|
39
|
+
* @property {PasteRule[]} pasteRules — URL→widget conversion rules (evaluated in order, first match wins)
|
|
40
|
+
* @property {{ embedBehavior: string, ghGuard: string }} github — GitHub-specific embed settings
|
|
41
|
+
* @property {CanvasTerminalConfig} [terminal] — terminal widget settings
|
|
42
|
+
* @property {Record<string, CanvasAgentConfig>} [agents] — per-agent overrides
|
|
43
|
+
* @property {CanvasZoomConfig} [zoom] — zoom min/max/step settings
|
|
44
|
+
*/
|
|
45
|
+
|
|
46
|
+
/**
|
|
47
|
+
* @typedef {object} CanvasAgentConfig
|
|
48
|
+
* @property {string} [label] — display label
|
|
49
|
+
* @property {string} [icon] — icon name
|
|
50
|
+
* @property {string} [startupCommand] — command to run on startup
|
|
51
|
+
* @property {string} [resumeCommand] — command to browse/resume existing sessions (e.g. "copilot --resume")
|
|
52
|
+
* @property {string} [postStartup] — command sent after agent readiness (e.g. "/allow-all on")
|
|
53
|
+
* @property {string} [readinessSignal] — tmux pane text that signals the agent is ready (fragile, prefer readinessFile)
|
|
54
|
+
* @property {boolean} [readinessFile] — use a file-based SessionStart hook for readiness (writes --settings with hook, polls for signal file)
|
|
55
|
+
* @property {boolean} [resizable] — override terminal resizability for this agent
|
|
56
|
+
* @property {number} [defaultWidth] — override default width
|
|
57
|
+
* @property {number} [defaultHeight] — override default height
|
|
58
|
+
*/
|
|
59
|
+
|
|
60
|
+
/**
|
|
61
|
+
* @typedef {object} HotPoolConfig
|
|
62
|
+
* @property {boolean} [enabled] — enable/disable all pools (default: true)
|
|
63
|
+
* @property {boolean} [verbose] — log to Vite terminal (default: false)
|
|
64
|
+
* @property {number} [default_pool_size] — default baseline per pool (default: 1)
|
|
65
|
+
* @property {number} [default_max_pool_size] — default surge cap per pool (default: 3)
|
|
66
|
+
* @property {boolean} [load_balancer] — enable auto-scaling (default: true)
|
|
67
|
+
* @property {number} [load_balancer_cooldown_mins] — minutes idle before scale-down (default: 10)
|
|
68
|
+
* @property {Record<string, { pool_size?: number, max_pool_size?: number, webgl_ready_slots?: number }>} [pools] — per-pool overrides (terminal, prompt, copilot, claude, codex). webgl_ready_slots: how many front-of-queue sessions should start with PINNED WebGL priority (default: 0)
|
|
69
|
+
*/
|
|
70
|
+
|
|
71
|
+
/**
|
|
72
|
+
* @typedef {object} CommandPaletteConfig
|
|
73
|
+
* @property {string[]} providers — provider IDs to enable
|
|
74
|
+
* @property {string} ranking — result ranking strategy
|
|
75
|
+
* @property {CommandPaletteSection[]} [sections] — declarative palette sections
|
|
76
|
+
*/
|
|
77
|
+
|
|
78
|
+
/**
|
|
79
|
+
* @typedef {object} CommandPaletteSection
|
|
80
|
+
* @property {string} id — unique section identifier
|
|
81
|
+
* @property {string} [title] — section heading in the palette
|
|
82
|
+
* @property {string} [type] — "tool-menu" for sub-page entries
|
|
83
|
+
* @property {string} [label] — display label (for tool-menu entries)
|
|
84
|
+
* @property {string[]} [keywords] — search keywords
|
|
85
|
+
* @property {CommandPaletteSectionItem[]} [items] — static entries
|
|
86
|
+
* @property {string} [source] — dynamic data source: "canvases" | "prototypes" | "stories"
|
|
87
|
+
* @property {string} [order] — ordering: "recent" | "alphabetical" | "recent-changes"
|
|
88
|
+
* @property {number} [limit] — max items from dynamic source
|
|
89
|
+
* @property {CommandPaletteOption[]} [options] — sub-page options (for tool-menu type)
|
|
90
|
+
*/
|
|
91
|
+
|
|
92
|
+
/**
|
|
93
|
+
* @typedef {object} CommandPaletteSectionItem
|
|
94
|
+
* @property {string} type — "link" | "action"
|
|
95
|
+
* @property {string} label — display text
|
|
96
|
+
* @property {string} [url] — navigation URL (for links)
|
|
97
|
+
* @property {string} [action] — command action ID (for actions)
|
|
98
|
+
* @property {string[]} [keywords] — search keywords
|
|
99
|
+
*/
|
|
100
|
+
|
|
101
|
+
/**
|
|
102
|
+
* @typedef {object} CommandPaletteOption
|
|
103
|
+
* @property {string} label — display text
|
|
104
|
+
* @property {string} action — command action ID
|
|
105
|
+
* @property {*} [value] — action payload
|
|
106
|
+
*/
|
|
107
|
+
|
|
108
|
+
/**
|
|
109
|
+
* @typedef {object} CustomerModeConfig
|
|
110
|
+
* @property {boolean} enabled — master toggle for customer mode
|
|
111
|
+
* @property {boolean} hideChrome — hides all toolbars (except canvas tools), branchbar, cmd+k, cmd+.
|
|
112
|
+
* @property {boolean} hideHomepage — removes the storyboard homepage (leaves empty page)
|
|
113
|
+
* @property {string} protoHomepage — internal /path that replaces homepage; redirects from / and /workspace
|
|
114
|
+
*/
|
|
115
|
+
|
|
116
|
+
/**
|
|
117
|
+
* @typedef {object} StoryboardConfig
|
|
118
|
+
* @property {string} [customDomain]
|
|
119
|
+
* @property {string} [devDomain]
|
|
120
|
+
* @property {string} [devDomainColor] — CSS color for the BranchBar in local dev (default: blue)
|
|
121
|
+
* @property {{ owner: string, name: string }} [repository]
|
|
122
|
+
* @property {{ enabled: boolean }} [modes]
|
|
123
|
+
* @property {{ discussions: { category: string } }} [comments]
|
|
124
|
+
* @property {Record<string, boolean>} [plugins]
|
|
125
|
+
* @property {{ enabled?: boolean, features?: Record<string, boolean>, partials?: Array }} [workshop]
|
|
126
|
+
* @property {Record<string, boolean>} [featureFlags]
|
|
127
|
+
* @property {{ hide?: string[] }} [ui]
|
|
128
|
+
* @property {object} [toolbar]
|
|
129
|
+
* @property {CanvasConfig} [canvas]
|
|
130
|
+
* @property {HotPoolConfig} [hotPool]
|
|
131
|
+
* @property {CommandPaletteConfig} [commandPalette]
|
|
132
|
+
* @property {CustomerModeConfig} [customerMode]
|
|
133
|
+
*/
|
|
134
|
+
|
|
135
|
+
/** Built-in paste rules shipped with storyboard. */
|
|
136
|
+
export const builtinPasteRules = [
|
|
137
|
+
{
|
|
138
|
+
id: 'figma',
|
|
139
|
+
match: 'https?://(?:www\\.)?figma\\.com/',
|
|
140
|
+
widget: 'figma-embed',
|
|
141
|
+
propsMap: { width: 800, height: 450 },
|
|
142
|
+
},
|
|
143
|
+
]
|
|
144
|
+
|
|
145
|
+
/** Default config values. Every key here is safe to access without null checks. */
|
|
146
|
+
export const configDefaults = {
|
|
147
|
+
customDomain: '',
|
|
148
|
+
devDomain: '',
|
|
149
|
+
devDomainColor: '',
|
|
150
|
+
repository: { owner: '', name: '' },
|
|
151
|
+
modes: { enabled: false },
|
|
152
|
+
comments: { discussions: { category: 'Comments' } },
|
|
153
|
+
plugins: {},
|
|
154
|
+
workshop: {
|
|
155
|
+
enabled: false,
|
|
156
|
+
features: { createPrototype: true, createFlow: true, createCanvas: true },
|
|
157
|
+
},
|
|
158
|
+
featureFlags: {},
|
|
159
|
+
ui: {},
|
|
160
|
+
toolbar: {},
|
|
161
|
+
canvas: {
|
|
162
|
+
pasteRules: builtinPasteRules,
|
|
163
|
+
github: {
|
|
164
|
+
embedBehavior: 'link-preview', // "link-preview" | "rich-embed"
|
|
165
|
+
ghGuard: 'copy', // "copy" | "link" | "off"
|
|
166
|
+
},
|
|
167
|
+
zoom: {
|
|
168
|
+
min: 10,
|
|
169
|
+
max: 250,
|
|
170
|
+
step: 10,
|
|
171
|
+
},
|
|
172
|
+
terminal: {
|
|
173
|
+
resizable: false,
|
|
174
|
+
defaultWidth: 800,
|
|
175
|
+
defaultHeight: 450,
|
|
176
|
+
},
|
|
177
|
+
},
|
|
178
|
+
commandPalette: {
|
|
179
|
+
providers: ['prototypes', 'flows', 'canvases', 'pages'],
|
|
180
|
+
ranking: 'frecency',
|
|
181
|
+
sections: [],
|
|
182
|
+
},
|
|
183
|
+
customerMode: {
|
|
184
|
+
enabled: false,
|
|
185
|
+
hideChrome: false,
|
|
186
|
+
hideHomepage: false,
|
|
187
|
+
protoHomepage: '',
|
|
188
|
+
},
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
/**
|
|
192
|
+
* Deep-merge helper that replaces arrays instead of concatenating.
|
|
193
|
+
* Objects are recursively merged; all other values are overwritten.
|
|
194
|
+
*/
|
|
195
|
+
function mergeConfig(defaults, overrides) {
|
|
196
|
+
if (!overrides || typeof overrides !== 'object' || Array.isArray(overrides)) {
|
|
197
|
+
return overrides ?? defaults
|
|
198
|
+
}
|
|
199
|
+
const result = { ...defaults }
|
|
200
|
+
for (const key of Object.keys(overrides)) {
|
|
201
|
+
const val = overrides[key]
|
|
202
|
+
if (val === undefined) continue
|
|
203
|
+
if (Array.isArray(val)) {
|
|
204
|
+
// Arrays replace (e.g. pasteRules, providers) — no concat
|
|
205
|
+
result[key] = val
|
|
206
|
+
} else if (val && typeof val === 'object' && !Array.isArray(val) && typeof defaults[key] === 'object' && !Array.isArray(defaults[key])) {
|
|
207
|
+
result[key] = mergeConfig(defaults[key], val)
|
|
208
|
+
} else {
|
|
209
|
+
result[key] = val
|
|
210
|
+
}
|
|
211
|
+
}
|
|
212
|
+
return result
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
/**
|
|
216
|
+
* Return a fully defaulted config by merging user-provided values over defaults.
|
|
217
|
+
* Safe to call with an empty object or undefined — returns full defaults.
|
|
218
|
+
*
|
|
219
|
+
* @param {Partial<StoryboardConfig>} [raw={}]
|
|
220
|
+
* @returns {StoryboardConfig}
|
|
221
|
+
*/
|
|
222
|
+
export function getConfig(raw = {}) {
|
|
223
|
+
return mergeConfig(configDefaults, raw)
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
/**
|
|
227
|
+
* Return a copy of the bare defaults (no user overrides).
|
|
228
|
+
* @returns {StoryboardConfig}
|
|
229
|
+
*/
|
|
230
|
+
export function getConfigDefaults() {
|
|
231
|
+
return JSON.parse(JSON.stringify(configDefaults))
|
|
232
|
+
}
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
import { describe, it, expect } from 'vitest'
|
|
2
|
+
import { getConfig, getConfigDefaults, configDefaults, builtinPasteRules } from './configSchema.js'
|
|
3
|
+
|
|
4
|
+
describe('configSchema', () => {
|
|
5
|
+
describe('getConfigDefaults', () => {
|
|
6
|
+
it('returns a full defaults object', () => {
|
|
7
|
+
const d = getConfigDefaults()
|
|
8
|
+
expect(d.canvas).toBeDefined()
|
|
9
|
+
expect(d.commandPalette).toBeDefined()
|
|
10
|
+
expect(d.repository).toEqual({ owner: '', name: '' })
|
|
11
|
+
})
|
|
12
|
+
|
|
13
|
+
it('returns a fresh copy each time', () => {
|
|
14
|
+
const a = getConfigDefaults()
|
|
15
|
+
const b = getConfigDefaults()
|
|
16
|
+
expect(a).not.toBe(b)
|
|
17
|
+
expect(a).toEqual(b)
|
|
18
|
+
})
|
|
19
|
+
})
|
|
20
|
+
|
|
21
|
+
describe('getConfig', () => {
|
|
22
|
+
it('returns full defaults when called with empty object', () => {
|
|
23
|
+
const c = getConfig({})
|
|
24
|
+
expect(c.canvas.pasteRules).toEqual(builtinPasteRules)
|
|
25
|
+
expect(c.canvas.github.embedBehavior).toBe('link-preview')
|
|
26
|
+
expect(c.canvas.github.ghGuard).toBe('copy')
|
|
27
|
+
expect(c.commandPalette.providers).toEqual(['prototypes', 'flows', 'canvases', 'pages'])
|
|
28
|
+
expect(c.commandPalette.ranking).toBe('frecency')
|
|
29
|
+
expect(c.customerMode.enabled).toBe(false)
|
|
30
|
+
expect(c.customerMode.hideChrome).toBe(false)
|
|
31
|
+
expect(c.customerMode.hideHomepage).toBe(false)
|
|
32
|
+
expect(c.customerMode.protoHomepage).toBe('')
|
|
33
|
+
})
|
|
34
|
+
|
|
35
|
+
it('returns full defaults when called with undefined', () => {
|
|
36
|
+
const c = getConfig()
|
|
37
|
+
expect(c.canvas).toBeDefined()
|
|
38
|
+
expect(c.commandPalette).toBeDefined()
|
|
39
|
+
})
|
|
40
|
+
|
|
41
|
+
it('merges user config over defaults', () => {
|
|
42
|
+
const c = getConfig({
|
|
43
|
+
repository: { owner: 'test', name: 'repo' },
|
|
44
|
+
canvas: { github: { ghGuard: 'link' } },
|
|
45
|
+
})
|
|
46
|
+
expect(c.repository).toEqual({ owner: 'test', name: 'repo' })
|
|
47
|
+
expect(c.canvas.github.ghGuard).toBe('link')
|
|
48
|
+
// Other defaults preserved
|
|
49
|
+
expect(c.canvas.github.embedBehavior).toBe('link-preview')
|
|
50
|
+
expect(c.canvas.pasteRules).toEqual(builtinPasteRules)
|
|
51
|
+
})
|
|
52
|
+
|
|
53
|
+
it('replaces arrays instead of concatenating', () => {
|
|
54
|
+
const customRules = [{ id: 'custom', match: 'https://example.com', widget: 'link-preview' }]
|
|
55
|
+
const c = getConfig({ canvas: { pasteRules: customRules } })
|
|
56
|
+
expect(c.canvas.pasteRules).toEqual(customRules)
|
|
57
|
+
expect(c.canvas.pasteRules).not.toContainEqual(builtinPasteRules[0])
|
|
58
|
+
})
|
|
59
|
+
|
|
60
|
+
it('preserves existing keys not in defaults', () => {
|
|
61
|
+
const c = getConfig({ devDomain: 'my-project', featureFlags: { 'show-banner': true } })
|
|
62
|
+
expect(c.devDomain).toBe('my-project')
|
|
63
|
+
expect(c.featureFlags['show-banner']).toBe(true)
|
|
64
|
+
})
|
|
65
|
+
|
|
66
|
+
it('does not mutate configDefaults', () => {
|
|
67
|
+
const before = JSON.stringify(configDefaults)
|
|
68
|
+
getConfig({ canvas: { github: { ghGuard: 'off' } } })
|
|
69
|
+
expect(JSON.stringify(configDefaults)).toBe(before)
|
|
70
|
+
})
|
|
71
|
+
})
|
|
72
|
+
})
|
|
@@ -0,0 +1,161 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Unified Config Store — single source of truth for all storyboard configuration.
|
|
3
|
+
*
|
|
4
|
+
* Replaces the scattered init/store pattern with one reactive config object.
|
|
5
|
+
* Domain-specific stores (toolbarConfigStore, canvasConfig, etc.) become thin
|
|
6
|
+
* wrappers that delegate here — zero consumer changes needed.
|
|
7
|
+
*
|
|
8
|
+
* Override priority (lowest → highest):
|
|
9
|
+
* core defaults → widgets → paste → toolbar → commandPalette → storyboard.config.json → prototype
|
|
10
|
+
*
|
|
11
|
+
* Framework-agnostic (zero npm dependencies).
|
|
12
|
+
*/
|
|
13
|
+
|
|
14
|
+
import { deepMerge } from '../data/loader.js'
|
|
15
|
+
|
|
16
|
+
// ---------------------------------------------------------------------------
|
|
17
|
+
// Internal state
|
|
18
|
+
// ---------------------------------------------------------------------------
|
|
19
|
+
|
|
20
|
+
/** @type {object} Full merged config (set once at startup) */
|
|
21
|
+
let _baseConfig = {}
|
|
22
|
+
|
|
23
|
+
/** @type {Record<string, object>} Domain → prototype-level overrides */
|
|
24
|
+
let _prototypeOverrides = {}
|
|
25
|
+
|
|
26
|
+
/** @type {object} Final merged config (base + prototype overrides) */
|
|
27
|
+
let _mergedConfig = {}
|
|
28
|
+
|
|
29
|
+
/** @type {Set<Function>} */
|
|
30
|
+
const _listeners = new Set()
|
|
31
|
+
|
|
32
|
+
let _snapshotVersion = 0
|
|
33
|
+
|
|
34
|
+
// ---------------------------------------------------------------------------
|
|
35
|
+
// Initialization
|
|
36
|
+
// ---------------------------------------------------------------------------
|
|
37
|
+
|
|
38
|
+
/**
|
|
39
|
+
* Seed the unified config with the pre-merged config object.
|
|
40
|
+
* Called once at app startup (from the virtual module or mountStoryboardCore).
|
|
41
|
+
*
|
|
42
|
+
* @param {object} config - The unified config with all domains
|
|
43
|
+
*/
|
|
44
|
+
export function initConfig(config) {
|
|
45
|
+
_baseConfig = config || {}
|
|
46
|
+
_prototypeOverrides = {}
|
|
47
|
+
_recompute()
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
// ---------------------------------------------------------------------------
|
|
51
|
+
// Domain access
|
|
52
|
+
// ---------------------------------------------------------------------------
|
|
53
|
+
|
|
54
|
+
/**
|
|
55
|
+
* Get the full merged config or a specific domain slice.
|
|
56
|
+
*
|
|
57
|
+
* @param {string} [domain] - Optional domain key (e.g. 'toolbar', 'canvas')
|
|
58
|
+
* @returns {object}
|
|
59
|
+
*/
|
|
60
|
+
export function getConfig(domain) {
|
|
61
|
+
if (!domain) return _mergedConfig
|
|
62
|
+
return _mergedConfig[domain] || {}
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
// ---------------------------------------------------------------------------
|
|
66
|
+
// Prototype overrides
|
|
67
|
+
// ---------------------------------------------------------------------------
|
|
68
|
+
|
|
69
|
+
/**
|
|
70
|
+
* Set overrides for a specific domain from a prototype-local config file.
|
|
71
|
+
* Called on route change when entering a prototype with local config.
|
|
72
|
+
*
|
|
73
|
+
* @param {string} domain - Config domain (e.g. 'toolbar', 'widgets')
|
|
74
|
+
* @param {object} overrides - Prototype-level overrides to deep-merge
|
|
75
|
+
*/
|
|
76
|
+
export function setOverrides(domain, overrides) {
|
|
77
|
+
if (!overrides) return
|
|
78
|
+
_prototypeOverrides[domain] = overrides
|
|
79
|
+
_recompute()
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
/**
|
|
83
|
+
* Clear overrides for a specific domain.
|
|
84
|
+
*
|
|
85
|
+
* @param {string} domain
|
|
86
|
+
*/
|
|
87
|
+
export function clearOverrides(domain) {
|
|
88
|
+
if (!_prototypeOverrides[domain]) return
|
|
89
|
+
delete _prototypeOverrides[domain]
|
|
90
|
+
_recompute()
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
/**
|
|
94
|
+
* Clear all prototype overrides (e.g. when leaving a prototype).
|
|
95
|
+
*/
|
|
96
|
+
export function clearAllOverrides() {
|
|
97
|
+
if (Object.keys(_prototypeOverrides).length === 0) return
|
|
98
|
+
_prototypeOverrides = {}
|
|
99
|
+
_recompute()
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
// ---------------------------------------------------------------------------
|
|
103
|
+
// Reactivity
|
|
104
|
+
// ---------------------------------------------------------------------------
|
|
105
|
+
|
|
106
|
+
/**
|
|
107
|
+
* Subscribe to config changes. Compatible with external stores.
|
|
108
|
+
*
|
|
109
|
+
* @param {Function} callback - Called with the full merged config
|
|
110
|
+
* @returns {Function} Unsubscribe
|
|
111
|
+
*/
|
|
112
|
+
export function subscribeToConfig(callback) {
|
|
113
|
+
_listeners.add(callback)
|
|
114
|
+
callback(_mergedConfig)
|
|
115
|
+
return () => _listeners.delete(callback)
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
/**
|
|
119
|
+
* Snapshot version for useSyncExternalStore.
|
|
120
|
+
*
|
|
121
|
+
* @returns {string}
|
|
122
|
+
*/
|
|
123
|
+
export function getConfigSnapshot() {
|
|
124
|
+
return String(_snapshotVersion)
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
// ---------------------------------------------------------------------------
|
|
128
|
+
// Internal
|
|
129
|
+
// ---------------------------------------------------------------------------
|
|
130
|
+
|
|
131
|
+
function _recompute() {
|
|
132
|
+
if (Object.keys(_prototypeOverrides).length === 0) {
|
|
133
|
+
_mergedConfig = _baseConfig
|
|
134
|
+
} else {
|
|
135
|
+
const result = { ..._baseConfig }
|
|
136
|
+
for (const [domain, overrides] of Object.entries(_prototypeOverrides)) {
|
|
137
|
+
result[domain] = result[domain]
|
|
138
|
+
? deepMerge(result[domain], overrides)
|
|
139
|
+
: overrides
|
|
140
|
+
}
|
|
141
|
+
_mergedConfig = result
|
|
142
|
+
}
|
|
143
|
+
_snapshotVersion++
|
|
144
|
+
for (const cb of _listeners) {
|
|
145
|
+
try { cb(_mergedConfig) } catch (err) {
|
|
146
|
+
console.error('[storyboard] Error in config subscriber:', err)
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
// ---------------------------------------------------------------------------
|
|
152
|
+
// Test helpers
|
|
153
|
+
// ---------------------------------------------------------------------------
|
|
154
|
+
|
|
155
|
+
export function _resetConfig() {
|
|
156
|
+
_baseConfig = {}
|
|
157
|
+
_prototypeOverrides = {}
|
|
158
|
+
_mergedConfig = {}
|
|
159
|
+
_listeners.clear()
|
|
160
|
+
_snapshotVersion = 0
|
|
161
|
+
}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Customer Mode Config — runtime store for customerMode config.
|
|
3
|
+
* Framework-agnostic (zero npm dependencies).
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
let _config = { enabled: false, hideChrome: false, hideHomepage: false, protoHomepage: '' }
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* Initialize customer mode config.
|
|
10
|
+
* @param {object} config - The customerMode object from storyboard.config.json
|
|
11
|
+
*/
|
|
12
|
+
export function initCustomerModeConfig(config) {
|
|
13
|
+
_config = { enabled: false, hideChrome: false, hideHomepage: false, protoHomepage: '', ...config }
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* Get the current customer mode config.
|
|
18
|
+
* @returns {{ enabled: boolean, hideChrome: boolean, hideHomepage: boolean, protoHomepage: string }}
|
|
19
|
+
*/
|
|
20
|
+
export function getCustomerModeConfig() {
|
|
21
|
+
return _config
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* Check if customer mode is enabled.
|
|
26
|
+
* @returns {boolean}
|
|
27
|
+
*/
|
|
28
|
+
export function isCustomerMode() {
|
|
29
|
+
return _config.enabled
|
|
30
|
+
}
|
|
@@ -0,0 +1,127 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Feature flag system for Storyboard.
|
|
3
|
+
*
|
|
4
|
+
* Flags are defined in storyboard.config.json under "featureFlags" and
|
|
5
|
+
* initialized at app startup via the Vite data plugin.
|
|
6
|
+
*
|
|
7
|
+
* Read priority: localStorage → config defaults
|
|
8
|
+
* Write target: localStorage (persistent per-browser)
|
|
9
|
+
*
|
|
10
|
+
* All flag keys in localStorage are prefixed with "flag." to avoid
|
|
11
|
+
* collisions with scene overrides.
|
|
12
|
+
*/
|
|
13
|
+
|
|
14
|
+
import { getLocal, setLocal, removeLocal, getAllLocal } from '../session/localStorage.js'
|
|
15
|
+
|
|
16
|
+
const FLAG_PREFIX = 'flag.'
|
|
17
|
+
const BODY_CLASS_PREFIX = 'sb-ff-'
|
|
18
|
+
|
|
19
|
+
/** Built-in feature flag defaults — always available even if initFeatureFlags is never called. */
|
|
20
|
+
const BUILTIN_DEFAULTS = {
|
|
21
|
+
'canvas-auto-reload': false,
|
|
22
|
+
'prototype-auto-reload': true,
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
/** Module-level storage for config defaults */
|
|
26
|
+
let _defaults = {}
|
|
27
|
+
|
|
28
|
+
/**
|
|
29
|
+
* Sync body classes for active feature flags.
|
|
30
|
+
* Adds `sb-ff-{name}` for every flag that resolves to true,
|
|
31
|
+
* removes it for every flag that resolves to false.
|
|
32
|
+
*/
|
|
33
|
+
export function syncFlagBodyClasses() {
|
|
34
|
+
if (typeof document === 'undefined') return
|
|
35
|
+
for (const key of Object.keys(_defaults)) {
|
|
36
|
+
const cls = BODY_CLASS_PREFIX + key
|
|
37
|
+
if (getFlag(key)) {
|
|
38
|
+
document.body.classList.add(cls)
|
|
39
|
+
} else {
|
|
40
|
+
document.body.classList.remove(cls)
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
/**
|
|
46
|
+
* Initialize the feature flag system with config defaults.
|
|
47
|
+
* Only writes a default to localStorage when no user override exists yet,
|
|
48
|
+
* so toggled values survive across reloads.
|
|
49
|
+
* @param {Record<string, boolean>} defaults - Flag key → default value
|
|
50
|
+
*/
|
|
51
|
+
export function initFeatureFlags(defaults = {}) {
|
|
52
|
+
_defaults = { ...BUILTIN_DEFAULTS, ...defaults }
|
|
53
|
+
for (const [key, value] of Object.entries(_defaults)) {
|
|
54
|
+
if (getLocal(FLAG_PREFIX + key) === null) {
|
|
55
|
+
setLocal(FLAG_PREFIX + key, String(value))
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
syncFlagBodyClasses()
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
/**
|
|
62
|
+
* Read a flag value. Priority: localStorage → config default.
|
|
63
|
+
* @param {string} key - Flag key (without prefix)
|
|
64
|
+
* @returns {boolean}
|
|
65
|
+
*/
|
|
66
|
+
export function getFlag(key) {
|
|
67
|
+
const localVal = getLocal(FLAG_PREFIX + key)
|
|
68
|
+
if (localVal !== null) return localVal === 'true'
|
|
69
|
+
|
|
70
|
+
return _defaults[key] ?? BUILTIN_DEFAULTS[key] ?? false
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
/**
|
|
74
|
+
* Set a flag value. Writes to localStorage for persistence.
|
|
75
|
+
* @param {string} key - Flag key (without prefix)
|
|
76
|
+
* @param {boolean} value
|
|
77
|
+
*/
|
|
78
|
+
export function setFlag(key, value) {
|
|
79
|
+
setLocal(FLAG_PREFIX + key, String(value))
|
|
80
|
+
syncFlagBodyClasses()
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
/**
|
|
84
|
+
* Toggle a flag. Reads current value, writes opposite to localStorage.
|
|
85
|
+
* @param {string} key - Flag key (without prefix)
|
|
86
|
+
*/
|
|
87
|
+
export function toggleFlag(key) {
|
|
88
|
+
setFlag(key, !getFlag(key))
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
/**
|
|
92
|
+
* Get all flags with their default and current (resolved) values.
|
|
93
|
+
* @returns {Record<string, { default: boolean, current: boolean }>}
|
|
94
|
+
*/
|
|
95
|
+
export function getAllFlags() {
|
|
96
|
+
const allKeys = new Set([...Object.keys(BUILTIN_DEFAULTS), ...Object.keys(_defaults)])
|
|
97
|
+
const result = {}
|
|
98
|
+
for (const key of allKeys) {
|
|
99
|
+
result[key] = {
|
|
100
|
+
default: _defaults[key] ?? BUILTIN_DEFAULTS[key] ?? false,
|
|
101
|
+
current: getFlag(key),
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
return result
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
/**
|
|
108
|
+
* Reset all flags — removes localStorage overrides.
|
|
109
|
+
* Flags revert to config defaults.
|
|
110
|
+
*/
|
|
111
|
+
export function resetFlags() {
|
|
112
|
+
const allLocal = getAllLocal()
|
|
113
|
+
for (const localKey of Object.keys(allLocal)) {
|
|
114
|
+
if (localKey.startsWith(FLAG_PREFIX)) {
|
|
115
|
+
removeLocal(localKey)
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
syncFlagBodyClasses()
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
/**
|
|
122
|
+
* Get all registered flag keys.
|
|
123
|
+
* @returns {string[]}
|
|
124
|
+
*/
|
|
125
|
+
export function getFlagKeys() {
|
|
126
|
+
return [...new Set([...Object.keys(BUILTIN_DEFAULTS), ...Object.keys(_defaults)])]
|
|
127
|
+
}
|