@dfosco/storyboard-core 3.3.1 → 3.3.2
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/dist/storyboard-ui.js +7374 -7350
- package/dist/storyboard-ui.js.map +1 -1
- package/package.json +1 -1
- package/src/CoreUIBar.svelte +3 -0
- package/src/inspector/highlighter.js +16 -11
- package/src/vite/server-plugin.js +24 -5
- package/src/workshop/features/createPrototype/CreatePrototypeForm.svelte +2 -2
- package/src/workshop/features/createPrototype/server.js +10 -15
- package/toolbar.config.json +1 -0
package/package.json
CHANGED
package/src/CoreUIBar.svelte
CHANGED
|
@@ -57,6 +57,8 @@
|
|
|
57
57
|
// Roving tabindex: only one button in the toolbar is tabbable at a time
|
|
58
58
|
let activeToolbarIndex = $state(-1)
|
|
59
59
|
|
|
60
|
+
const isLocalDev = typeof window !== 'undefined' && (window as any).__SB_LOCAL_DEV__ === true
|
|
61
|
+
|
|
60
62
|
const commandMenuConfig = $derived(isMenuHidden('command') ? null : config.menus?.command)
|
|
61
63
|
const shortcutsConfig = $derived((config as any).shortcuts || {})
|
|
62
64
|
|
|
@@ -65,6 +67,7 @@
|
|
|
65
67
|
const orderedMenus = $derived(Object.entries(allMenus)
|
|
66
68
|
.filter(([key]) => key !== 'command')
|
|
67
69
|
.filter(([key]) => !isMenuHidden(key))
|
|
70
|
+
.filter(([, menu]) => !menu.localOnly || isLocalDev)
|
|
68
71
|
.map(([key, menu]) => ({ key, ...menu })))
|
|
69
72
|
|
|
70
73
|
// Discover menus with sidepanel property
|
|
@@ -5,22 +5,27 @@
|
|
|
5
5
|
* avoiding the full shiki bundle that registers 200+ lazy-loaded
|
|
6
6
|
* language chunks (which break in deployed/static environments).
|
|
7
7
|
*
|
|
8
|
-
*
|
|
9
|
-
*
|
|
10
|
-
*
|
|
8
|
+
* Import specifiers are computed via template literals so consumer
|
|
9
|
+
* bundlers (Rollup, esbuild) can't statically analyze them — they
|
|
10
|
+
* skip dynamic imports with variable specifiers instead of erroring.
|
|
11
|
+
* Returns null when shiki is unavailable.
|
|
11
12
|
*/
|
|
13
|
+
|
|
14
|
+
// Variable indirection prevents any bundler from statically resolving
|
|
15
|
+
const SHIKI = 'shiki'
|
|
16
|
+
|
|
12
17
|
export async function createInspectorHighlighter() {
|
|
13
18
|
try {
|
|
14
19
|
const [shikiCore, oniguruma, tsx, jsx, javascript, typescript, githubDark, wasm] =
|
|
15
20
|
await Promise.all([
|
|
16
|
-
import(
|
|
17
|
-
import(
|
|
18
|
-
import(
|
|
19
|
-
import(
|
|
20
|
-
import(
|
|
21
|
-
import(
|
|
22
|
-
import(
|
|
23
|
-
import(
|
|
21
|
+
import(/* @vite-ignore */ `${SHIKI}/core`).catch(() => null),
|
|
22
|
+
import(/* @vite-ignore */ `${SHIKI}/engine/oniguruma`).catch(() => null),
|
|
23
|
+
import(/* @vite-ignore */ `${SHIKI}/dist/langs/tsx.mjs`).catch(() => null),
|
|
24
|
+
import(/* @vite-ignore */ `${SHIKI}/dist/langs/jsx.mjs`).catch(() => null),
|
|
25
|
+
import(/* @vite-ignore */ `${SHIKI}/dist/langs/javascript.mjs`).catch(() => null),
|
|
26
|
+
import(/* @vite-ignore */ `${SHIKI}/dist/langs/typescript.mjs`).catch(() => null),
|
|
27
|
+
import(/* @vite-ignore */ `${SHIKI}/dist/themes/github-dark.mjs`).catch(() => null),
|
|
28
|
+
import(/* @vite-ignore */ `${SHIKI}/wasm`).catch(() => null),
|
|
24
29
|
])
|
|
25
30
|
|
|
26
31
|
if (!shikiCore || !oniguruma || !tsx || !jsx || !javascript || !typescript || !githubDark || !wasm) {
|
|
@@ -176,13 +176,32 @@ export default function storyboardServer() {
|
|
|
176
176
|
},
|
|
177
177
|
|
|
178
178
|
transformIndexHtml() {
|
|
179
|
-
|
|
179
|
+
const tags = []
|
|
180
180
|
|
|
181
|
-
|
|
181
|
+
// Inject local dev flag so the UI can gate dev-only tools
|
|
182
|
+
tags.push({
|
|
182
183
|
tag: 'script',
|
|
183
|
-
|
|
184
|
-
injectTo: '
|
|
185
|
-
})
|
|
184
|
+
children: 'window.__SB_LOCAL_DEV__=true',
|
|
185
|
+
injectTo: 'head',
|
|
186
|
+
})
|
|
187
|
+
|
|
188
|
+
// Inject base path so the inspector UI can resolve static assets
|
|
189
|
+
// (e.g. inspector.json) when deployed under a subpath
|
|
190
|
+
tags.push({
|
|
191
|
+
tag: 'script',
|
|
192
|
+
children: `window.__STORYBOARD_BASE_PATH__=${JSON.stringify(base)}`,
|
|
193
|
+
injectTo: 'head',
|
|
194
|
+
})
|
|
195
|
+
|
|
196
|
+
for (const src of clientScripts) {
|
|
197
|
+
tags.push({
|
|
198
|
+
tag: 'script',
|
|
199
|
+
attrs: { type: 'module', src: base + src.replace(/^\//, '') },
|
|
200
|
+
injectTo: 'body',
|
|
201
|
+
})
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
return tags
|
|
186
205
|
},
|
|
187
206
|
|
|
188
207
|
// Build-time: emit a static JSON with source files so the inspector
|
|
@@ -62,8 +62,8 @@
|
|
|
62
62
|
const canSubmit = $derived(!!kebabName && !nameError && !submitting && (!isExternal || (!!externalUrl.trim() && !urlError)))
|
|
63
63
|
|
|
64
64
|
const templateLabel = $derived(partial ? partials.find(p => p.name === partial)?.name ?? partial : 'No template')
|
|
65
|
-
const templates = $derived(partials.filter(p => p.directory === 'template'))
|
|
66
|
-
const recipes = $derived(partials.filter(p => p.directory === 'recipe'))
|
|
65
|
+
const templates = $derived(partials.filter(p => p.directory === 'template' || p.directory === 'templates'))
|
|
66
|
+
const recipes = $derived(partials.filter(p => p.directory === 'recipe' || p.directory === 'recipes'))
|
|
67
67
|
let templateMenuOpen = $state(false)
|
|
68
68
|
|
|
69
69
|
function getApiUrl() {
|
|
@@ -20,10 +20,12 @@ import path from 'node:path'
|
|
|
20
20
|
|
|
21
21
|
const FLOW_SKELETON = JSON.stringify({ $global: [] }, null, 2) + '\n'
|
|
22
22
|
|
|
23
|
-
/**
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
23
|
+
/**
|
|
24
|
+
* Check whether a partial entry is a template (vs recipe).
|
|
25
|
+
* Accepts both singular and plural forms: "template" or "templates".
|
|
26
|
+
*/
|
|
27
|
+
function isTemplate(partialEntry) {
|
|
28
|
+
return partialEntry.directory === 'template' || partialEntry.directory === 'templates'
|
|
27
29
|
}
|
|
28
30
|
|
|
29
31
|
// ---------------------------------------------------------------------------
|
|
@@ -118,10 +120,9 @@ function generateBlankIndexJsx(componentName, title) {
|
|
|
118
120
|
* @param {string} title - Human-readable title
|
|
119
121
|
*/
|
|
120
122
|
function generateIndexJsx({ partialEntry, componentFile, componentName, title }) {
|
|
121
|
-
const
|
|
122
|
-
const importPath = `@/${typeDir}/${partialEntry.name}/${componentFile}`
|
|
123
|
+
const importPath = `@/${partialEntry.directory}/${partialEntry.name}/${componentFile}`
|
|
123
124
|
|
|
124
|
-
if (partialEntry
|
|
125
|
+
if (isTemplate(partialEntry)) {
|
|
125
126
|
return `import ${componentFile} from '${importPath}'
|
|
126
127
|
|
|
127
128
|
export default function ${componentName}() {
|
|
@@ -303,16 +304,10 @@ export function createPrototypesHandler(ctx) {
|
|
|
303
304
|
if (!partialEntry) {
|
|
304
305
|
content = generateBlankIndexJsx(componentName, title)
|
|
305
306
|
} else {
|
|
306
|
-
const
|
|
307
|
-
if (!typeDir) {
|
|
308
|
-
sendJson(res, 400, { error: `Invalid directory "${partialEntry.directory}". Must be "recipe" or "template".` })
|
|
309
|
-
return
|
|
310
|
-
}
|
|
311
|
-
|
|
312
|
-
const partialDir = path.join(root, 'src', typeDir, partialEntry.name)
|
|
307
|
+
const partialDir = path.join(root, 'src', partialEntry.directory, partialEntry.name)
|
|
313
308
|
const componentFile = findComponentFile(partialDir)
|
|
314
309
|
if (!componentFile) {
|
|
315
|
-
sendJson(res, 400, { error: `No .jsx or .tsx file found in src/${
|
|
310
|
+
sendJson(res, 400, { error: `No .jsx or .tsx file found in src/${partialEntry.directory}/${partialEntry.name}/` })
|
|
316
311
|
return
|
|
317
312
|
}
|
|
318
313
|
|