@jxsuite/studio 2.0.0 → 2.1.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/canvas.html +21 -0
- package/dist/chunks/Overlay.dev-qfjzkms8.js +23 -0
- package/dist/chunks/{Overlay.dev-cszx7yn5.js.map → Overlay.dev-qfjzkms8.js.map} +1 -1
- package/dist/chunks/{adapter-z8fkmbmv.js → adapter-qfnesn5v.js} +2 -2
- package/dist/chunks/{cf-settings-mmyv436d.js → cf-settings-73sh5z4p.js} +3 -3
- package/dist/chunks/{components-0hzentwq.js → components-2bpqp4mq.js} +5 -7
- package/dist/chunks/{components-0hzentwq.js.map → components-2bpqp4mq.js.map} +1 -1
- package/dist/chunks/content-source-34gnkbnn.js +38 -0
- package/dist/chunks/content-source-34gnkbnn.js.map +9 -0
- package/dist/chunks/convert-to-repeater-t8kxre5s.js +258 -0
- package/dist/chunks/convert-to-repeater-t8kxre5s.js.map +10 -0
- package/dist/chunks/extension-sections-6mqydz35.js +301 -0
- package/dist/chunks/extension-sections-6mqydz35.js.map +11 -0
- package/dist/chunks/files-8kn321h1.js +70 -0
- package/dist/chunks/files-8kn321h1.js.map +9 -0
- package/dist/chunks/{format-host-2c188n41.js → format-host-mkwsmt8d.js} +3 -3
- package/dist/chunks/git-panel-tjbr191d.js +51 -0
- package/dist/chunks/git-panel-tjbr191d.js.map +9 -0
- package/dist/chunks/{index-baeg2x3y.js → index-7pxchcce.js} +4 -3
- package/dist/chunks/{index-baeg2x3y.js.map → index-7pxchcce.js.map} +3 -3
- package/dist/chunks/{jx-validate-qx8degj7.js → jx-validate-v6qgknrs.js} +3 -3
- package/dist/chunks/layers-panel-87pb25km.js +58 -0
- package/dist/chunks/layers-panel-87pb25km.js.map +9 -0
- package/dist/chunks/{monaco-setup-zjdp9zdw.js → monaco-setup-e0yh25j4.js} +4 -75
- package/dist/chunks/{monaco-setup-zjdp9zdw.js.map → monaco-setup-e0yh25j4.js.map} +3 -4
- package/dist/chunks/publish-panel-m0fcgdrt.js +21 -0
- package/dist/chunks/publish-panel-m0fcgdrt.js.map +9 -0
- package/dist/chunks/quick-search-rhs6cbsb.js +53 -0
- package/dist/chunks/quick-search-rhs6cbsb.js.map +9 -0
- package/dist/chunks/right-panel-zpdxd98t.js +37 -0
- package/dist/chunks/right-panel-zpdxd98t.js.map +9 -0
- package/dist/chunks/section-registry-zmckaxf4.js +30 -0
- package/dist/chunks/section-registry-zmckaxf4.js.map +9 -0
- package/dist/chunks/sp-overlay.dev-9ran0sfq.js +18 -0
- package/dist/chunks/sp-overlay.dev-9ran0sfq.js.map +9 -0
- package/dist/chunks/sp-popover.dev-rebmdncr.js +9 -0
- package/dist/chunks/sp-popover.dev-rebmdncr.js.map +9 -0
- package/dist/chunks/sp-progress-circle.dev-5vkppfkt.js +15 -0
- package/dist/chunks/sp-progress-circle.dev-5vkppfkt.js.map +9 -0
- package/dist/chunks/sp-tooltip.dev-ykqrg8h5.js +15 -0
- package/dist/chunks/sp-tooltip.dev-ykqrg8h5.js.map +9 -0
- package/dist/chunks/{sp-tray.dev-pb2fsd65.js → sp-tray.dev-ey59vfh7.js} +10 -8
- package/dist/chunks/{sp-tray.dev-pb2fsd65.js.map → sp-tray.dev-ey59vfh7.js.map} +2 -2
- package/dist/chunks/{studio-9qr6fq7p.js → studio-0rqqhrdy.js} +10 -378
- package/dist/chunks/{studio-9qr6fq7p.js.map → studio-0rqqhrdy.js.map} +4 -14
- package/dist/chunks/{studio-5x6tqqec.js → studio-2sj1jj3v.js} +10 -8
- package/dist/chunks/{studio-5x6tqqec.js.map → studio-2sj1jj3v.js.map} +2 -2
- package/dist/chunks/{studio-h3fw0wn8.js → studio-3fk1ac9z.js} +6 -4
- package/dist/chunks/{studio-h3fw0wn8.js.map → studio-3fk1ac9z.js.map} +2 -2
- package/dist/chunks/studio-41exgzhq.js +6690 -0
- package/dist/chunks/studio-41exgzhq.js.map +38 -0
- package/dist/chunks/{studio-7v2bpweq.js → studio-4mqb9a0j.js} +6 -4
- package/dist/chunks/{studio-7v2bpweq.js.map → studio-4mqb9a0j.js.map} +2 -2
- package/dist/chunks/studio-50k77cca.js +1787 -0
- package/dist/chunks/studio-50k77cca.js.map +18 -0
- package/dist/chunks/{studio-56v3zwk6.js → studio-6a0h7sne.js} +10 -8
- package/dist/chunks/{studio-56v3zwk6.js.map → studio-6a0h7sne.js.map} +2 -2
- package/dist/chunks/studio-6f0am8f2.js +53 -0
- package/dist/chunks/studio-6f0am8f2.js.map +10 -0
- package/dist/chunks/studio-6nmjc5qk.js +7002 -0
- package/dist/chunks/studio-6nmjc5qk.js.map +32 -0
- package/dist/chunks/studio-7afd21nw.js +67 -0
- package/dist/chunks/studio-7afd21nw.js.map +10 -0
- package/dist/chunks/{studio-xze4zrs1.js → studio-7bmdvzne.js} +2 -2
- package/dist/chunks/studio-7bmdvzne.js.map +10 -0
- package/dist/chunks/studio-8jpzqk5s.js +128 -0
- package/dist/chunks/studio-8jpzqk5s.js.map +10 -0
- package/dist/chunks/studio-94m77tgk.js +1482 -0
- package/dist/chunks/studio-94m77tgk.js.map +13 -0
- package/dist/chunks/studio-9je6w5sq.js +1000 -0
- package/dist/chunks/studio-9je6w5sq.js.map +16 -0
- package/dist/chunks/{studio-w7c6kvk7.js → studio-a7pzveq1.js} +2 -2
- package/dist/chunks/{studio-97qcgvdn.js → studio-adn0z1k3.js} +14 -8
- package/dist/chunks/{studio-97qcgvdn.js.map → studio-adn0z1k3.js.map} +3 -3
- package/dist/chunks/{studio-kr88ryr7.js → studio-bsxxx3x2.js} +17 -15
- package/dist/chunks/{studio-kr88ryr7.js.map → studio-bsxxx3x2.js.map} +7 -6
- package/dist/chunks/studio-bw5dz6km.js +608 -0
- package/dist/chunks/studio-bw5dz6km.js.map +21 -0
- package/dist/chunks/studio-c6s5getc.js +4232 -0
- package/dist/chunks/studio-c6s5getc.js.map +39 -0
- package/dist/chunks/studio-cjm7fdjf.js +451 -0
- package/dist/chunks/studio-cjm7fdjf.js.map +14 -0
- package/dist/chunks/{studio-cx91mnh8.js → studio-ckwz4d3x.js} +53 -53
- package/dist/chunks/{studio-cx91mnh8.js.map → studio-ckwz4d3x.js.map} +5 -5
- package/dist/chunks/studio-dg7zyt5x.js +28 -0
- package/dist/chunks/studio-dg7zyt5x.js.map +10 -0
- package/dist/chunks/studio-dzcyvvvz.js +166 -0
- package/dist/chunks/studio-dzcyvvvz.js.map +10 -0
- package/dist/chunks/{studio-7kqe41sa.js → studio-evkr5d3b.js} +15 -7
- package/dist/chunks/{studio-7kqe41sa.js.map → studio-evkr5d3b.js.map} +5 -4
- package/dist/chunks/studio-f12h6177.js +411 -0
- package/dist/chunks/studio-f12h6177.js.map +13 -0
- package/dist/chunks/studio-hbp1s8m9.js +1817 -0
- package/dist/chunks/studio-hbp1s8m9.js.map +14 -0
- package/dist/chunks/studio-k2sxjph5.js +15295 -0
- package/dist/chunks/studio-k2sxjph5.js.map +235 -0
- package/dist/chunks/studio-myje51t3.js +385 -0
- package/dist/chunks/studio-myje51t3.js.map +12 -0
- package/dist/chunks/studio-na6rwzhw.js +353 -0
- package/dist/chunks/studio-na6rwzhw.js.map +11 -0
- package/dist/chunks/{studio-4k0m4fmp.js → studio-p471gg5n.js} +126 -3
- package/dist/chunks/studio-p471gg5n.js.map +14 -0
- package/dist/chunks/{studio-9bjwf0d4.js → studio-rgwcpast.js} +5 -46
- package/dist/chunks/{studio-9bjwf0d4.js.map → studio-rgwcpast.js.map} +4 -5
- package/dist/chunks/{studio-hhj92gcr.js → studio-s519zc99.js} +3 -3
- package/dist/chunks/studio-sas7mt3k.js +75 -0
- package/dist/chunks/studio-sas7mt3k.js.map +10 -0
- package/dist/chunks/studio-t5wqwzdh.js +74 -0
- package/dist/chunks/studio-t5wqwzdh.js.map +10 -0
- package/dist/chunks/{studio-9qpspwfn.js → studio-temv5bw4.js} +5 -5
- package/dist/chunks/{studio-9qpspwfn.js.map → studio-temv5bw4.js.map} +1 -1
- package/dist/chunks/{studio-qkvt37c0.js → studio-tr20m8g8.js} +669 -18
- package/dist/chunks/studio-tr20m8g8.js.map +9 -0
- package/dist/chunks/{studio-ygzav7z5.js → studio-v96qfnww.js} +5514 -4291
- package/dist/chunks/studio-v96qfnww.js.map +54 -0
- package/dist/chunks/studio-vcetc91k.js +659 -0
- package/dist/chunks/studio-vcetc91k.js.map +10 -0
- package/dist/chunks/{studio-n9zmpxjg.js → studio-vmymjefp.js} +2972 -4937
- package/dist/chunks/studio-vmymjefp.js.map +98 -0
- package/dist/chunks/{studio-bghqfmea.js → studio-wwseqyw0.js} +2 -2
- package/dist/chunks/studio-x9hmy5kr.js +390 -0
- package/dist/chunks/studio-x9hmy5kr.js.map +10 -0
- package/dist/chunks/studio-xa0ce0n7.js +335 -0
- package/dist/chunks/studio-xa0ce0n7.js.map +10 -0
- package/dist/chunks/studio-xm3dbxvn.js +378 -0
- package/dist/chunks/studio-xm3dbxvn.js.map +19 -0
- package/dist/chunks/{studio-nqw433kv.js → studio-xmvbhg31.js} +2 -2
- package/dist/chunks/studio-zv37yrfa.js +1054 -0
- package/dist/chunks/studio-zv37yrfa.js.map +13 -0
- package/dist/chunks/{ws-client-q7hkz3j9.js → ws-client-654ts66j.js} +6 -4
- package/dist/chunks/ws-client-654ts66j.js.map +11 -0
- package/dist/iframe-entry.js +668 -230
- package/dist/studio.js +23711 -35185
- package/index.html +35 -4685
- package/package.json +17 -15
- package/src/about/about-modal.ts +42 -11
- package/src/browse/library-commands.ts +240 -0
- package/src/browse/library-layouts.ts +369 -0
- package/src/browse/library-model.ts +396 -0
- package/src/browse/library-pane.ts +1049 -0
- package/src/browse/library-preview.ts +252 -0
- package/src/browse/library-source.ts +150 -0
- package/src/canvas/canvas-helpers.ts +33 -9
- package/src/canvas/canvas-live-render.ts +45 -29
- package/src/canvas/canvas-patcher.ts +151 -31
- package/src/canvas/canvas-perf.ts +46 -7
- package/src/canvas/canvas-render.ts +1092 -220
- package/src/canvas/canvas-surface.ts +240 -0
- package/src/canvas/canvas-utils.ts +1166 -124
- package/src/canvas/iframe-drop.ts +2 -1
- package/src/canvas/iframe-entry.ts +241 -4
- package/src/canvas/iframe-host.ts +1226 -143
- package/src/canvas/iframe-inline-edit.ts +31 -0
- package/src/canvas/iframe-interaction.ts +76 -16
- package/src/canvas/iframe-keys.ts +107 -45
- package/src/canvas/iframe-overlay.ts +38 -1
- package/src/canvas/iframe-protocol.ts +137 -2
- package/src/canvas/iframe-render.ts +70 -2
- package/src/canvas/iframe-slash.ts +6 -0
- package/src/canvas/path-mapping.ts +56 -6
- package/src/canvas/surface-registry.ts +292 -0
- package/src/collab/collab-commands.ts +244 -0
- package/src/collab/collab-session.ts +198 -32
- package/src/collab/collab-state.ts +28 -2
- package/src/collab/presence-chips.ts +100 -9
- package/src/commands/active-registry.ts +42 -0
- package/src/commands/app-commands.ts +176 -0
- package/src/commands/budget.ts +158 -0
- package/src/commands/command-args.ts +253 -0
- package/src/commands/context.ts +387 -0
- package/src/commands/defaults.ts +580 -0
- package/src/commands/keymap.ts +571 -0
- package/src/commands/levels.ts +345 -0
- package/src/commands/live-context.ts +193 -0
- package/src/commands/reference.ts +227 -0
- package/src/commands/registry.ts +293 -0
- package/src/component-props.ts +3 -2
- package/src/content/draft-state.ts +106 -0
- package/src/content/entry-commands.ts +282 -0
- package/src/content/entry-editor.ts +327 -0
- package/src/content/entry-fields.ts +116 -0
- package/src/content/entry-model.ts +175 -0
- package/src/editor/canvas-context-menu.ts +17 -11
- package/src/editor/canvas-slash-bridge.ts +11 -4
- package/src/editor/context-menu.ts +804 -204
- package/src/editor/convert-to-component.ts +31 -10
- package/src/editor/convert-to-repeater.ts +3 -2
- package/src/editor/inline-edit-apply.ts +5 -5
- package/src/editor/inline-edit.ts +86 -50
- package/src/editor/insert-zone-action.ts +1 -1
- package/src/editor/shortcuts.ts +1043 -329
- package/src/editor/slash-menu.ts +1 -0
- package/src/files/elements.ts +166 -0
- package/src/files/file-ops.ts +178 -31
- package/src/files/files.ts +898 -268
- package/src/files/fs-events.ts +21 -0
- package/src/files/media-meta.ts +203 -0
- package/src/files/media-paths.ts +141 -0
- package/src/files/media-upload.ts +7 -3
- package/src/files/media-usage.ts +189 -0
- package/src/github/github-auth.ts +235 -33
- package/src/github/github-publish.ts +80 -21
- package/src/grid/grid-controller.ts +152 -12
- package/src/grid/grid-layout.ts +225 -20
- package/src/grid/grid-open.ts +120 -0
- package/src/grid/grid-panel.ts +554 -39
- package/src/grid/grid-source.ts +27 -1
- package/src/grid/redirects-grid.ts +599 -0
- package/src/grid/redirects.ts +398 -0
- package/src/grid/sources/content-source.ts +108 -2
- package/src/i18n/i18n-commands.ts +322 -0
- package/src/new-project/add-repo-modal.ts +8 -10
- package/src/new-project/import-tab.ts +34 -9
- package/src/new-project/location-fields.ts +9 -1
- package/src/new-project/new-project-modal.ts +270 -262
- package/src/packages/jxsuite-update.ts +97 -48
- package/src/packages/pull-package-sync.ts +18 -9
- package/src/page-params.ts +2 -1
- package/src/panels/activity-bar.ts +152 -91
- package/src/panels/activity-panel.ts +481 -0
- package/src/panels/ai-chat/chat-markdown.ts +8 -3
- package/src/panels/ai-chat/chat-view.ts +245 -18
- package/src/panels/ai-chat/composer.ts +31 -5
- package/src/panels/ai-chat/sessions-view.ts +17 -10
- package/src/panels/ai-panel.ts +279 -120
- package/src/panels/block-action-bar.ts +1115 -224
- package/src/panels/bottom-dock.ts +337 -0
- package/src/panels/canvas-dnd-bridge.ts +37 -8
- package/src/panels/chat-panel.ts +29 -12
- package/src/panels/data-explorer.ts +254 -112
- package/src/panels/data-grid.ts +10 -4
- package/src/panels/dnd.ts +28 -51
- package/src/panels/editors.ts +434 -107
- package/src/panels/elements-panel.ts +66 -2
- package/src/panels/empty-state.ts +112 -0
- package/src/panels/events-panel.ts +596 -82
- package/src/panels/formula-workspace.ts +408 -218
- package/src/panels/frontmatter-fields.ts +51 -10
- package/src/panels/frontmatter-panel.ts +357 -79
- package/src/panels/git-panel.ts +375 -164
- package/src/panels/head-panel.ts +791 -85
- package/src/panels/i18n-panel.ts +592 -0
- package/src/panels/imports-panel.ts +95 -85
- package/src/panels/jump-bar.ts +584 -0
- package/src/panels/layers-panel.ts +1106 -328
- package/src/panels/left-panel.ts +109 -204
- package/src/panels/navigator-panels.ts +131 -0
- package/src/panels/overlays.ts +7 -2
- package/src/panels/pane-context.ts +1477 -0
- package/src/panels/pane-grid.ts +406 -0
- package/src/panels/panel-registry.ts +340 -0
- package/src/panels/panel-scheduler.ts +75 -0
- package/src/panels/problems-panel.ts +234 -0
- package/src/panels/properties-panel.ts +946 -1139
- package/src/panels/provenance.ts +258 -0
- package/src/panels/quick-search.ts +791 -122
- package/src/panels/right-panel.ts +228 -102
- package/src/panels/seo-modal.ts +395 -0
- package/src/panels/settings-pane.ts +203 -0
- package/src/panels/signals-panel.ts +354 -137
- package/src/panels/statement-editor.ts +41 -25
- package/src/panels/statusbar.ts +342 -106
- package/src/panels/style-panel.ts +974 -463
- package/src/panels/style-utils.ts +3 -3
- package/src/panels/stylebook-doc.ts +4 -2
- package/src/panels/stylebook-layers-panel.ts +3 -2
- package/src/panels/stylebook-panel.ts +51 -26
- package/src/panels/tab-strip.ts +1058 -78
- package/src/panels/target-line.ts +274 -0
- package/src/panels/toolbar.ts +631 -484
- package/src/panels/welcome-screen.ts +301 -198
- package/src/platform-errors.ts +26 -3
- package/src/platform.ts +96 -2
- package/src/platforms/cloud.ts +71 -8
- package/src/platforms/devserver.ts +92 -29
- package/src/publish/deploy-checklist.ts +383 -0
- package/src/publish/pages-service.ts +10 -1
- package/src/publish/publish-commands.ts +218 -0
- package/src/publish/publish-panel.ts +110 -16
- package/src/recent-projects.ts +3 -2
- package/src/services/a11y-report.ts +505 -0
- package/src/services/ai-models.ts +75 -2
- package/src/services/ai-project-tools.ts +29 -10
- package/src/services/ai-system-prompt.ts +53 -14
- package/src/services/ai-tools.ts +39 -3
- package/src/services/ai-writes.ts +154 -0
- package/src/services/announce.ts +97 -0
- package/src/services/automation.ts +424 -175
- package/src/services/cem-export.ts +9 -4
- package/src/services/clock.ts +61 -0
- package/src/services/document-assistant.ts +36 -8
- package/src/services/idle.ts +179 -0
- package/src/services/import-client.ts +26 -0
- package/src/services/monaco-buffer.ts +627 -0
- package/src/services/monaco-lazy.ts +36 -0
- package/src/services/notify.ts +271 -0
- package/src/services/profile.ts +155 -0
- package/src/services/references.ts +0 -0
- package/src/services/token-lint.ts +3 -2
- package/src/services/tool-executor.ts +53 -7
- package/src/services/trusted-types.ts +123 -0
- package/src/settings/contexts-section.ts +427 -0
- package/src/settings/contributed-section.ts +149 -11
- package/src/settings/css-vars-editor.ts +306 -349
- package/src/settings/defs-editor.ts +93 -34
- package/src/settings/dependencies-editor.ts +7 -7
- package/src/settings/extension-sections.ts +37 -5
- package/src/settings/general-settings.ts +204 -121
- package/src/settings/locales-section.ts +347 -0
- package/src/settings/preferences-accounts.ts +140 -0
- package/src/settings/preferences-dialog.ts +620 -0
- package/src/settings/preferences-keymap.ts +270 -0
- package/src/settings/project-sections.ts +260 -0
- package/src/settings/section-registry.ts +169 -0
- package/src/settings/settings-document.ts +385 -0
- package/src/shell.ts +1549 -0
- package/src/site-context.ts +45 -20
- package/src/state.ts +14 -275
- package/src/store.ts +88 -43
- package/src/studio.ts +790 -346
- package/src/style/live-preview.ts +36 -0
- package/src/style/project-styles.ts +349 -0
- package/src/style/token-ref.ts +123 -0
- package/src/tabs/patch-ops.ts +16 -4
- package/src/tabs/project-config.ts +416 -0
- package/src/tabs/selection.ts +323 -0
- package/src/tabs/tab.ts +182 -47
- package/src/tabs/transact.ts +209 -28
- package/src/types.ts +68 -13
- package/src/ui/ai-credentials-form.ts +39 -35
- package/src/ui/ai-managed-connect.ts +113 -0
- package/src/ui/dynamic-slot.ts +224 -81
- package/src/ui/expression-editor.ts +71 -63
- package/src/ui/field-input.ts +4 -6
- package/src/ui/field-row.ts +215 -38
- package/src/ui/form-controls.ts +194 -7
- package/src/ui/layers.ts +492 -69
- package/src/ui/media-picker.ts +115 -25
- package/src/ui/panel-resize.ts +109 -91
- package/src/ui/progress-modal.ts +131 -50
- package/src/ui/regions.ts +462 -0
- package/src/ui/schema-form.ts +229 -45
- package/src/ui/spectrum.ts +24 -8
- package/src/ui/timing.ts +49 -0
- package/src/ui/value-selector.ts +20 -0
- package/src/ui/value-source.ts +348 -0
- package/src/ui/virtual-window.ts +400 -0
- package/src/utils/edit-display.ts +3 -2
- package/src/utils/inherited-style.ts +67 -37
- package/src/view.ts +64 -78
- package/src/workspace/pane-derive.ts +1258 -0
- package/src/workspace/session.ts +317 -0
- package/src/workspace/workspace.ts +1345 -23
- package/styles/canvas.css +653 -0
- package/styles/forced-colors.css +106 -0
- package/styles/inspector.css +1454 -0
- package/styles/overlays.css +2704 -0
- package/styles/panels.css +1701 -0
- package/styles/shell.css +1423 -0
- package/styles/tokens.css +151 -0
- package/dist/chunks/Overlay.dev-cszx7yn5.js +0 -22
- package/dist/chunks/extension-sections-qct0gt8f.js +0 -531
- package/dist/chunks/extension-sections-qct0gt8f.js.map +0 -12
- package/dist/chunks/files-02zn5y24.js +0 -50
- package/dist/chunks/files-02zn5y24.js.map +0 -9
- package/dist/chunks/git-panel-mbb0y0hz.js +0 -28
- package/dist/chunks/git-panel-mbb0y0hz.js.map +0 -9
- package/dist/chunks/layers-panel-9qekmqk1.js +0 -26
- package/dist/chunks/layers-panel-9qekmqk1.js.map +0 -9
- package/dist/chunks/settings-modal-gj0hrah4.js +0 -29
- package/dist/chunks/settings-modal-gj0hrah4.js.map +0 -9
- package/dist/chunks/sp-overlay.dev-earn5as8.js +0 -17
- package/dist/chunks/sp-overlay.dev-earn5as8.js.map +0 -9
- package/dist/chunks/sp-popover.dev-frxtfejn.js +0 -8
- package/dist/chunks/sp-popover.dev-frxtfejn.js.map +0 -9
- package/dist/chunks/sp-progress-circle.dev-7tvw34h8.js +0 -14
- package/dist/chunks/sp-progress-circle.dev-7tvw34h8.js.map +0 -9
- package/dist/chunks/sp-tooltip.dev-a9fywesm.js +0 -21
- package/dist/chunks/sp-tooltip.dev-a9fywesm.js.map +0 -10
- package/dist/chunks/studio-4k0m4fmp.js.map +0 -13
- package/dist/chunks/studio-568nx4t5.js +0 -469
- package/dist/chunks/studio-568nx4t5.js.map +0 -14
- package/dist/chunks/studio-9smfzqhc.js +0 -19
- package/dist/chunks/studio-9smfzqhc.js.map +0 -10
- package/dist/chunks/studio-asvf0j9e.js +0 -429
- package/dist/chunks/studio-asvf0j9e.js.map +0 -13
- package/dist/chunks/studio-d77qm3pk.js +0 -3427
- package/dist/chunks/studio-d77qm3pk.js.map +0 -26
- package/dist/chunks/studio-j6gqyjf4.js +0 -1854
- package/dist/chunks/studio-j6gqyjf4.js.map +0 -18
- package/dist/chunks/studio-n9zmpxjg.js.map +0 -115
- package/dist/chunks/studio-qkvt37c0.js.map +0 -9
- package/dist/chunks/studio-rq0vxb19.js +0 -3744
- package/dist/chunks/studio-rq0vxb19.js.map +0 -22
- package/dist/chunks/studio-wd6ewdvd.js +0 -853
- package/dist/chunks/studio-wd6ewdvd.js.map +0 -12
- package/dist/chunks/studio-xq0t7n5t.js +0 -140
- package/dist/chunks/studio-xq0t7n5t.js.map +0 -10
- package/dist/chunks/studio-xze4zrs1.js.map +0 -10
- package/dist/chunks/studio-ygzav7z5.js.map +0 -46
- package/dist/chunks/studio-zmy7241e.js +0 -399
- package/dist/chunks/studio-zmy7241e.js.map +0 -12
- package/dist/chunks/ws-client-q7hkz3j9.js.map +0 -11
- package/src/browse/browse-modal.ts +0 -69
- package/src/browse/browse.ts +0 -904
- package/src/canvas/canvas-diff.ts +0 -216
- package/src/canvas/nested-site-style.ts +0 -58
- package/src/new-project/design-fields.ts +0 -264
- package/src/new-project/templates.ts +0 -61
- package/src/panels/tab-bar.ts +0 -548
- package/src/settings/settings-modal.ts +0 -203
- /package/dist/chunks/{adapter-z8fkmbmv.js.map → adapter-qfnesn5v.js.map} +0 -0
- /package/dist/chunks/{cf-settings-mmyv436d.js.map → cf-settings-73sh5z4p.js.map} +0 -0
- /package/dist/chunks/{format-host-2c188n41.js.map → format-host-mkwsmt8d.js.map} +0 -0
- /package/dist/chunks/{jx-validate-qx8degj7.js.map → jx-validate-v6qgknrs.js.map} +0 -0
- /package/dist/chunks/{studio-w7c6kvk7.js.map → studio-a7pzveq1.js.map} +0 -0
- /package/dist/chunks/{studio-hhj92gcr.js.map → studio-s519zc99.js.map} +0 -0
- /package/dist/chunks/{studio-bghqfmea.js.map → studio-wwseqyw0.js.map} +0 -0
- /package/dist/chunks/{studio-nqw433kv.js.map → studio-xmvbhg31.js.map} +0 -0
|
@@ -1,24 +1,37 @@
|
|
|
1
1
|
/// <reference lib="dom" />
|
|
2
2
|
/**
|
|
3
|
-
* New Project modal — a two-step wizard.
|
|
4
|
-
* of four tabs: a built-in Template, a Starter Site, an Import of an existing site, or an Agent
|
|
5
|
-
* prompt. Step 2 ("New Project Parameters") collects the project identity plus a design quickstart
|
|
6
|
-
* (colors, fonts, logo, breakpoints — a creation-time subset of the settings modal), prefilled from
|
|
7
|
-
* the chosen source and customizable before anything is written.
|
|
3
|
+
* New Project modal — a two-step wizard.
|
|
8
4
|
*
|
|
9
|
-
*
|
|
5
|
+
* **Step 1 · Choose a starting point.** Starters lead: the first thing offered is a complete site
|
|
6
|
+
* you can look at. The gallery ends with one **Start from scratch** card — the minimal scaffold —
|
|
7
|
+
* because a first-run choice between four breakpoint presets described by media-query direction is
|
|
8
|
+
* a choice nobody can make. Two further sources sit on their own tabs: an **Import** of an existing
|
|
9
|
+
* site, and an **Agent** prompt.
|
|
10
|
+
*
|
|
11
|
+
* **Step 2 · Name your project.** Name and location, nothing else. A project's URL, deployment
|
|
12
|
+
* adapter and design tokens are settings, not creation-time decisions, so they live in the
|
|
13
|
+
* project's own settings surface where they can be changed more than once.
|
|
14
|
+
*
|
|
15
|
+
* Import and Agent need working AI, so both are gated until credentials exist — a key stored in
|
|
16
|
+
* this browser, or a backend that holds its own (managed cloud platforms, env-keyed dev servers).
|
|
17
|
+
* While gated they offer the same two paths as the assistant sidebar: connect Cloudflare for
|
|
18
|
+
* Workers AI, or bring a key.
|
|
19
|
+
*
|
|
20
|
+
* @docs studio/projects/create
|
|
10
21
|
*/
|
|
11
22
|
|
|
12
23
|
import { html } from "lit-html";
|
|
13
24
|
import { errorMessage } from "@jxsuite/schema/parse";
|
|
14
25
|
import { openModal } from "../ui/layers";
|
|
26
|
+
import { enumArg, enumProperty } from "../commands/command-args";
|
|
27
|
+
import type { AnyCommand, CommandRegistry } from "../commands/registry";
|
|
15
28
|
import { getPlatform } from "../platform";
|
|
16
29
|
import { installUrlOf } from "../platform-errors";
|
|
17
|
-
import {
|
|
30
|
+
import { hasAiCredentials } from "../services/ai-models";
|
|
18
31
|
import { setPendingAgentPrompt } from "../services/agent-seed";
|
|
32
|
+
import { initProjectRepo } from "../files/files";
|
|
19
33
|
import { createAiCredentialsForm } from "../ui/ai-credentials-form";
|
|
20
|
-
import {
|
|
21
|
-
import { collectDesign, renderDesignFields, resetDesignFields } from "./design-fields";
|
|
34
|
+
import { createManagedConnect } from "../ui/ai-managed-connect";
|
|
22
35
|
import {
|
|
23
36
|
collectDestination,
|
|
24
37
|
loadLocationOptions,
|
|
@@ -40,28 +53,21 @@ import type { ProjectConfig } from "@jxsuite/schema/types";
|
|
|
40
53
|
import type { CreateProjectDestination, StarterInfo } from "../types";
|
|
41
54
|
import type { ImportTabCtx } from "./import-tab";
|
|
42
55
|
|
|
43
|
-
type NewProjectTab =
|
|
56
|
+
type NewProjectTab = (typeof NEW_PROJECT_TABS)[number];
|
|
44
57
|
type WizardStep = "source" | "params";
|
|
45
58
|
|
|
46
59
|
let _handle: ReturnType<typeof openModal> | null = null;
|
|
47
60
|
|
|
48
|
-
let _form = {
|
|
49
|
-
adapter: "static",
|
|
50
|
-
description: "",
|
|
51
|
-
directory: "",
|
|
52
|
-
name: "",
|
|
53
|
-
url: "",
|
|
54
|
-
};
|
|
61
|
+
let _form = { directory: "", name: "" };
|
|
55
62
|
|
|
56
|
-
let _tab: NewProjectTab = "
|
|
63
|
+
let _tab: NewProjectTab = "starter";
|
|
57
64
|
let _step: WizardStep = "source";
|
|
58
|
-
|
|
65
|
+
/** The step-1 choice on the Starters tab: a starter id, or `""` for "Start from scratch". */
|
|
59
66
|
let _starter = "";
|
|
67
|
+
/** Set once the user picks a card, so an arriving starter list stops overriding their choice. */
|
|
68
|
+
let _starterTouched = false;
|
|
60
69
|
let _agentPrompt = "";
|
|
61
70
|
|
|
62
|
-
/** Which source the Parameters step was last seeded for — Back/Next keeps user edits intact. */
|
|
63
|
-
let _paramsSeededFor = "";
|
|
64
|
-
|
|
65
71
|
let _error = "";
|
|
66
72
|
|
|
67
73
|
/**
|
|
@@ -89,7 +95,7 @@ function focusNameField() {
|
|
|
89
95
|
|
|
90
96
|
let _creating = false;
|
|
91
97
|
|
|
92
|
-
/** Starter templates offered in the
|
|
98
|
+
/** Starter templates offered in the gallery (empty until loaded / on platforms without starters). */
|
|
93
99
|
let _starters: StarterInfo[] = [];
|
|
94
100
|
|
|
95
101
|
let _resolve: ((result: { root: string; config: ProjectConfig } | null) => void) | null = null;
|
|
@@ -98,48 +104,64 @@ let _resolve: ((result: { root: string; config: ProjectConfig } | null) => void)
|
|
|
98
104
|
// Before a platform is registered (the form fetches models through the platform on edit).
|
|
99
105
|
let _credsForm: ReturnType<typeof createAiCredentialsForm> | null = null;
|
|
100
106
|
|
|
107
|
+
function rerenderIfOpen() {
|
|
108
|
+
if (_handle) {
|
|
109
|
+
renderModal();
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
|
|
101
113
|
function credsForm() {
|
|
102
114
|
_credsForm ??= createAiCredentialsForm({
|
|
103
|
-
onSaved:
|
|
104
|
-
|
|
105
|
-
renderModal();
|
|
106
|
-
}
|
|
107
|
-
},
|
|
108
|
-
requestRender: () => {
|
|
109
|
-
if (_handle) {
|
|
110
|
-
renderModal();
|
|
111
|
-
}
|
|
112
|
-
},
|
|
115
|
+
onSaved: rerenderIfOpen,
|
|
116
|
+
requestRender: rerenderIfOpen,
|
|
113
117
|
});
|
|
114
118
|
return _credsForm;
|
|
115
119
|
}
|
|
116
120
|
|
|
121
|
+
/**
|
|
122
|
+
* The keyless "Connect Cloudflare" option shown beside the key form on managed platforms — the same
|
|
123
|
+
* controller the assistant sidebar uses. Lazy for the same reason as the form above.
|
|
124
|
+
*/
|
|
125
|
+
let _managedConnect: ReturnType<typeof createManagedConnect> | null = null;
|
|
126
|
+
|
|
127
|
+
function managedConnect() {
|
|
128
|
+
_managedConnect ??= createManagedConnect({ requestRender: rerenderIfOpen });
|
|
129
|
+
return _managedConnect;
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
/**
|
|
133
|
+
* The Import and Agent tabs need working AI, which a managed platform can supply without any local
|
|
134
|
+
* key. Probe on every gated render so the Cloudflare option appears as soon as the backend
|
|
135
|
+
* answers.
|
|
136
|
+
*/
|
|
137
|
+
function aiGateOpen(): boolean {
|
|
138
|
+
if (hasAiCredentials()) {
|
|
139
|
+
return true;
|
|
140
|
+
}
|
|
141
|
+
managedConnect().ensureProbe();
|
|
142
|
+
return false;
|
|
143
|
+
}
|
|
144
|
+
|
|
117
145
|
/**
|
|
118
146
|
* Open the New Project modal. Returns a promise that resolves with the created project info (or
|
|
119
147
|
* null if cancelled).
|
|
120
148
|
*
|
|
149
|
+
* @param {{ tab?: NewProjectTab }} [options] Which source tab to open on; defaults to Starters.
|
|
121
150
|
* @returns {Promise<{ root: string; config: object } | null>}
|
|
122
151
|
*/
|
|
123
|
-
export function openNewProjectModal(options?: { tab?:
|
|
152
|
+
export function openNewProjectModal(options?: { tab?: NewProjectTab }): Promise<{
|
|
124
153
|
root: string;
|
|
125
154
|
config: ProjectConfig;
|
|
126
155
|
} | null> {
|
|
127
156
|
if (_handle) {
|
|
128
157
|
return Promise.resolve(null);
|
|
129
158
|
}
|
|
130
|
-
_form = {
|
|
131
|
-
|
|
132
|
-
description: "",
|
|
133
|
-
directory: "",
|
|
134
|
-
name: "",
|
|
135
|
-
url: "",
|
|
136
|
-
};
|
|
137
|
-
_tab = options?.tab ?? "template";
|
|
159
|
+
_form = { directory: "", name: "" };
|
|
160
|
+
_tab = options?.tab ?? "starter";
|
|
138
161
|
_step = "source";
|
|
139
|
-
_template = "blank";
|
|
140
162
|
_starter = "";
|
|
163
|
+
_starterTouched = false;
|
|
141
164
|
_agentPrompt = "";
|
|
142
|
-
_paramsSeededFor = "";
|
|
143
165
|
_error = "";
|
|
144
166
|
_nameError = "";
|
|
145
167
|
_errorInstallUrl = "";
|
|
@@ -147,12 +169,10 @@ export function openNewProjectModal(options?: { tab?: "template" | "starter" }):
|
|
|
147
169
|
_starters = [];
|
|
148
170
|
_dirDerived = true;
|
|
149
171
|
resetImportTab();
|
|
150
|
-
resetDesignFields();
|
|
151
172
|
resetLocationFields();
|
|
152
173
|
|
|
153
174
|
// Load the destination options (repo-mode owners) and starter templates in the background,
|
|
154
|
-
// Re-rendering when they arrive.
|
|
155
|
-
// Its empty note.
|
|
175
|
+
// Re-rendering when they arrive. A platform without starters shows the scratch card alone.
|
|
156
176
|
const platform = getPlatform();
|
|
157
177
|
loadLocationOptions(() => {
|
|
158
178
|
if (_handle) {
|
|
@@ -164,7 +184,8 @@ export function openNewProjectModal(options?: { tab?: "template" | "starter" }):
|
|
|
164
184
|
.listStarters()
|
|
165
185
|
.then((starters) => {
|
|
166
186
|
_starters = starters;
|
|
167
|
-
|
|
187
|
+
// Starters lead: the gallery opens with a real site selected, not an empty scaffold.
|
|
188
|
+
if (!_starterTouched) {
|
|
168
189
|
_starter = starters[0]?.id ?? "";
|
|
169
190
|
}
|
|
170
191
|
if (_handle) {
|
|
@@ -172,7 +193,7 @@ export function openNewProjectModal(options?: { tab?: "template" | "starter" }):
|
|
|
172
193
|
}
|
|
173
194
|
})
|
|
174
195
|
.catch(() => {
|
|
175
|
-
/* Non-fatal: the
|
|
196
|
+
/* Non-fatal: the gallery keeps the scratch card. */
|
|
176
197
|
});
|
|
177
198
|
}
|
|
178
199
|
|
|
@@ -182,10 +203,17 @@ export function openNewProjectModal(options?: { tab?: "template" | "starter" }):
|
|
|
182
203
|
});
|
|
183
204
|
}
|
|
184
205
|
|
|
206
|
+
/**
|
|
207
|
+
* Dismiss the wizard. Available from every step, and from the underlay and Escape — a running
|
|
208
|
+
* import is aborted on the way out rather than trapping the user behind it.
|
|
209
|
+
*/
|
|
185
210
|
export function closeNewProjectModal() {
|
|
186
|
-
if (!_handle || _creating
|
|
211
|
+
if (!_handle || _creating) {
|
|
187
212
|
return;
|
|
188
213
|
}
|
|
214
|
+
if (isImportRunning()) {
|
|
215
|
+
cancelImport(importCtxFor(renderModal));
|
|
216
|
+
}
|
|
189
217
|
_handle.close();
|
|
190
218
|
_handle = null;
|
|
191
219
|
if (_resolve) {
|
|
@@ -207,6 +235,15 @@ function finish(result: { root: string; config: ProjectConfig }) {
|
|
|
207
235
|
}
|
|
208
236
|
}
|
|
209
237
|
|
|
238
|
+
/**
|
|
239
|
+
* Every path out of the wizard that produced a project: initialise version control for it, then
|
|
240
|
+
* hand it to the caller. A scaffold is not a repository, and Delete and Rename are one click away.
|
|
241
|
+
*/
|
|
242
|
+
async function finishCreated(result: { root: string; config: ProjectConfig }) {
|
|
243
|
+
await initProjectRepo(result.root);
|
|
244
|
+
finish(result);
|
|
245
|
+
}
|
|
246
|
+
|
|
210
247
|
function deriveSlug(name: string): string {
|
|
211
248
|
return name
|
|
212
249
|
.toLowerCase()
|
|
@@ -214,12 +251,9 @@ function deriveSlug(name: string): string {
|
|
|
214
251
|
.replaceAll(/^-|-$/g, "");
|
|
215
252
|
}
|
|
216
253
|
|
|
217
|
-
/** The human label of the chosen source, shown as context on the
|
|
254
|
+
/** The human label of the chosen source, shown as context on the Name step. */
|
|
218
255
|
function sourceLabel(): string {
|
|
219
256
|
switch (_tab) {
|
|
220
|
-
case "starter": {
|
|
221
|
-
return `Starter Site · ${_starters.find((s) => s.id === _starter)?.name ?? _starter}`;
|
|
222
|
-
}
|
|
223
257
|
case "import": {
|
|
224
258
|
return "Import";
|
|
225
259
|
}
|
|
@@ -227,52 +261,79 @@ function sourceLabel(): string {
|
|
|
227
261
|
return "Agent";
|
|
228
262
|
}
|
|
229
263
|
default: {
|
|
230
|
-
return
|
|
264
|
+
return _starter
|
|
265
|
+
? `Starter site · ${_starters.find((s) => s.id === _starter)?.name ?? _starter}`
|
|
266
|
+
: "Start from scratch";
|
|
231
267
|
}
|
|
232
268
|
}
|
|
233
269
|
}
|
|
234
270
|
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
271
|
+
/** The import tab's context object — rebuilt per render so it closes over current state. */
|
|
272
|
+
function importCtxFor(rerender: () => void): ImportTabCtx {
|
|
273
|
+
return {
|
|
274
|
+
aiGateOpen,
|
|
238
275
|
credsForm: credsForm(),
|
|
239
276
|
form: _form,
|
|
240
|
-
|
|
241
|
-
|
|
277
|
+
managedConnect: managedConnect(),
|
|
278
|
+
onDone: (result) => {
|
|
279
|
+
// See above: the discard is deliberate, and `void` as a statement is what says so.
|
|
280
|
+
void finishCreated(result);
|
|
281
|
+
},
|
|
282
|
+
rerender,
|
|
242
283
|
resolveDestination: () => validateParams(),
|
|
243
284
|
};
|
|
285
|
+
}
|
|
244
286
|
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
287
|
+
/**
|
|
288
|
+
* Validate the Name step, returning the destination to create at (null when something is missing —
|
|
289
|
+
* the reason is already rendered inline and the modal re-drawn). The slug is derived from the name
|
|
290
|
+
* when left blank, but the destination itself is never guessed.
|
|
291
|
+
*/
|
|
292
|
+
function validateParams(): CreateProjectDestination | null {
|
|
293
|
+
if (!_form.name.trim()) {
|
|
294
|
+
_nameError = "Project name is required";
|
|
295
|
+
renderModal();
|
|
296
|
+
focusNameField();
|
|
297
|
+
return null;
|
|
298
|
+
}
|
|
299
|
+
if (!_form.directory.trim()) {
|
|
300
|
+
_form.directory = deriveSlug(_form.name);
|
|
301
|
+
}
|
|
302
|
+
const destination = collectDestination(_form.directory);
|
|
303
|
+
if (!destination) {
|
|
304
|
+
_nameError = "";
|
|
305
|
+
renderModal();
|
|
306
|
+
focusNameField();
|
|
307
|
+
return null;
|
|
308
|
+
}
|
|
309
|
+
return destination;
|
|
310
|
+
}
|
|
311
|
+
|
|
312
|
+
function renderModal() {
|
|
313
|
+
const platform = getPlatform();
|
|
314
|
+
const importCtx = importCtxFor(renderModal);
|
|
315
|
+
|
|
316
|
+
const onInput = (field: "name" | "directory") => (e: Event) => {
|
|
317
|
+
_form[field] = (e.target as HTMLInputElement).value;
|
|
318
|
+
if (field === "name") {
|
|
319
|
+
_nameError = "";
|
|
320
|
+
// Auto-derive the directory slug from the name while the user hasn't typed one.
|
|
321
|
+
if (!_form.directory) {
|
|
253
322
|
_dirDerived = true;
|
|
254
323
|
}
|
|
255
|
-
if (_dirDerived
|
|
324
|
+
if (_dirDerived) {
|
|
256
325
|
_form.directory = deriveSlug(_form.name);
|
|
257
326
|
}
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
renderModal();
|
|
262
|
-
};
|
|
263
|
-
|
|
264
|
-
const onAdapterChange = (e: Event) => {
|
|
265
|
-
_form.adapter = (e.target as HTMLInputElement).value;
|
|
266
|
-
renderModal();
|
|
267
|
-
};
|
|
268
|
-
|
|
269
|
-
const selectTemplate = (id: string) => {
|
|
270
|
-
_template = id;
|
|
327
|
+
} else {
|
|
328
|
+
_dirDerived = false;
|
|
329
|
+
}
|
|
271
330
|
renderModal();
|
|
272
331
|
};
|
|
273
332
|
|
|
274
333
|
const selectStarter = (id: string) => {
|
|
275
334
|
_starter = id;
|
|
335
|
+
_starterTouched = true;
|
|
336
|
+
_error = "";
|
|
276
337
|
renderModal();
|
|
277
338
|
};
|
|
278
339
|
|
|
@@ -288,11 +349,6 @@ function renderModal() {
|
|
|
288
349
|
// ─── Step transitions ──────────────────────────────────────────────────────
|
|
289
350
|
|
|
290
351
|
const goNext = () => {
|
|
291
|
-
if (_tab === "starter" && !_starter) {
|
|
292
|
-
_error = "Choose a starter site";
|
|
293
|
-
renderModal();
|
|
294
|
-
return;
|
|
295
|
-
}
|
|
296
352
|
if (_tab === "import" && !validateImportSource(importCtx)) {
|
|
297
353
|
return;
|
|
298
354
|
}
|
|
@@ -301,28 +357,6 @@ function renderModal() {
|
|
|
301
357
|
renderModal();
|
|
302
358
|
return;
|
|
303
359
|
}
|
|
304
|
-
|
|
305
|
-
// Seed the Parameters step from the chosen source — only when the source changed, so Back +
|
|
306
|
-
// Next round-trips keep the user's edits.
|
|
307
|
-
const seedKey = `${_tab}:${_template}:${_starter}`;
|
|
308
|
-
if (_paramsSeededFor !== seedKey) {
|
|
309
|
-
_paramsSeededFor = seedKey;
|
|
310
|
-
if (_tab === "starter") {
|
|
311
|
-
const meta = _starters.find((s) => s.id === _starter);
|
|
312
|
-
if (meta && !_form.description.trim()) {
|
|
313
|
-
_form.description = meta.tagline;
|
|
314
|
-
}
|
|
315
|
-
resetDesignFields({
|
|
316
|
-
...(meta?.accent ? { accent: meta.accent } : {}),
|
|
317
|
-
mediaNote: "Leave empty to keep the starter's breakpoints.",
|
|
318
|
-
});
|
|
319
|
-
} else if (_tab === "template" || _tab === "agent") {
|
|
320
|
-
const templateId = _tab === "agent" ? "blank" : _template;
|
|
321
|
-
const meta = PROJECT_TEMPLATES.find((t) => t.id === templateId);
|
|
322
|
-
resetDesignFields(meta ? { media: meta.media } : {});
|
|
323
|
-
}
|
|
324
|
-
}
|
|
325
|
-
|
|
326
360
|
_step = "params";
|
|
327
361
|
_error = "";
|
|
328
362
|
renderModal();
|
|
@@ -340,32 +374,11 @@ function renderModal() {
|
|
|
340
374
|
|
|
341
375
|
// ─── Submission ────────────────────────────────────────────────────────────
|
|
342
376
|
|
|
343
|
-
/**
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
const validateParams = (): CreateProjectDestination | null => {
|
|
349
|
-
if (!_form.name.trim()) {
|
|
350
|
-
_nameError = "Project name is required";
|
|
351
|
-
renderModal();
|
|
352
|
-
focusNameField();
|
|
353
|
-
return null;
|
|
354
|
-
}
|
|
355
|
-
if (!_form.directory.trim()) {
|
|
356
|
-
_form.directory = deriveSlug(_form.name);
|
|
357
|
-
}
|
|
358
|
-
const destination = collectDestination(_form.directory);
|
|
359
|
-
if (!destination) {
|
|
360
|
-
_nameError = "";
|
|
361
|
-
renderModal();
|
|
362
|
-
focusNameField();
|
|
363
|
-
return null;
|
|
364
|
-
}
|
|
365
|
-
return destination;
|
|
366
|
-
};
|
|
367
|
-
|
|
368
|
-
const onSubmit = async () => {
|
|
377
|
+
/** Create the project from the chosen source, then run `after` with the result. */
|
|
378
|
+
const create = async (
|
|
379
|
+
source: { starter: string } | { template: string },
|
|
380
|
+
after: (result: { root: string; config: ProjectConfig }) => void | Promise<void>,
|
|
381
|
+
) => {
|
|
369
382
|
const destination = validateParams();
|
|
370
383
|
if (!destination) {
|
|
371
384
|
return;
|
|
@@ -377,14 +390,8 @@ function renderModal() {
|
|
|
377
390
|
renderModal();
|
|
378
391
|
|
|
379
392
|
try {
|
|
380
|
-
const
|
|
381
|
-
|
|
382
|
-
..._form,
|
|
383
|
-
destination,
|
|
384
|
-
...(_tab === "starter" && _starter ? { starter: _starter } : { template: _template }),
|
|
385
|
-
...(design ? { design } : {}),
|
|
386
|
-
});
|
|
387
|
-
finish(result);
|
|
393
|
+
const result = await getPlatform().createProject({ ..._form, destination, ...source });
|
|
394
|
+
await after(result);
|
|
388
395
|
} catch (error) {
|
|
389
396
|
_creating = false;
|
|
390
397
|
captureError(error);
|
|
@@ -392,90 +399,66 @@ function renderModal() {
|
|
|
392
399
|
}
|
|
393
400
|
};
|
|
394
401
|
|
|
395
|
-
const
|
|
396
|
-
|
|
397
|
-
if (!destination) {
|
|
398
|
-
return;
|
|
399
|
-
}
|
|
400
|
-
|
|
401
|
-
_creating = true;
|
|
402
|
-
_error = "";
|
|
403
|
-
_nameError = "";
|
|
404
|
-
renderModal();
|
|
402
|
+
const onSubmit = () =>
|
|
403
|
+
create(_starter ? { starter: _starter } : { template: "blank" }, finishCreated);
|
|
405
404
|
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
const result = await getPlatform().createProject({
|
|
409
|
-
..._form,
|
|
410
|
-
destination,
|
|
411
|
-
template: "blank",
|
|
412
|
-
...(design ? { design } : {}),
|
|
413
|
-
});
|
|
405
|
+
const onAgentSubmit = () =>
|
|
406
|
+
create({ template: "blank" }, async (result) => {
|
|
414
407
|
// The window that opens the project consumes this and hands the prompt to the assistant.
|
|
415
408
|
setPendingAgentPrompt(result.root, _agentPrompt.trim());
|
|
416
|
-
|
|
417
|
-
}
|
|
418
|
-
_creating = false;
|
|
419
|
-
captureError(error);
|
|
420
|
-
renderModal();
|
|
421
|
-
}
|
|
422
|
-
};
|
|
409
|
+
await finishCreated(result);
|
|
410
|
+
});
|
|
423
411
|
|
|
424
412
|
// ─── Step 1: source selection ──────────────────────────────────────────────
|
|
425
413
|
|
|
426
|
-
const
|
|
414
|
+
const starterSourceTpl = () => html`
|
|
415
|
+
<div class="new-project-tab-intro">
|
|
416
|
+
Every starter is a complete site copied in as plain files you own — open it, look at it, then
|
|
417
|
+
make it yours.
|
|
418
|
+
</div>
|
|
427
419
|
<div class="new-project-templates">
|
|
428
|
-
${
|
|
429
|
-
(
|
|
420
|
+
${_starters.map(
|
|
421
|
+
(s) => html`
|
|
430
422
|
<button
|
|
431
423
|
type="button"
|
|
432
|
-
class="new-project-template ${
|
|
433
|
-
@click=${() =>
|
|
434
|
-
title=${
|
|
424
|
+
class="new-project-template ${_starter === s.id ? "selected" : ""}"
|
|
425
|
+
@click=${() => selectStarter(s.id)}
|
|
426
|
+
title=${s.description}
|
|
435
427
|
>
|
|
436
|
-
<
|
|
428
|
+
<img class="new-project-template-thumb" src=${s.thumbnail} alt="" />
|
|
437
429
|
<div class="new-project-template-body">
|
|
438
|
-
<div class="new-project-template-name">${
|
|
439
|
-
<div class="new-project-template-tag">${
|
|
430
|
+
<div class="new-project-template-name">${s.name}</div>
|
|
431
|
+
<div class="new-project-template-tag">${s.tagline}</div>
|
|
440
432
|
</div>
|
|
441
433
|
</button>
|
|
442
434
|
`,
|
|
443
435
|
)}
|
|
436
|
+
<button
|
|
437
|
+
type="button"
|
|
438
|
+
class="new-project-template new-project-scratch ${_starter === "" ? "selected" : ""}"
|
|
439
|
+
@click=${() => selectStarter("")}
|
|
440
|
+
>
|
|
441
|
+
<div class="new-project-template-blank">+</div>
|
|
442
|
+
<div class="new-project-template-body">
|
|
443
|
+
<div class="new-project-template-name">Start from scratch</div>
|
|
444
|
+
<div class="new-project-template-tag">An empty site with one page</div>
|
|
445
|
+
</div>
|
|
446
|
+
</button>
|
|
444
447
|
</div>
|
|
445
448
|
`;
|
|
446
449
|
|
|
447
|
-
const starterSourceTpl = () =>
|
|
448
|
-
_starters.length > 0
|
|
449
|
-
? html`
|
|
450
|
-
<div class="new-project-templates">
|
|
451
|
-
${_starters.map(
|
|
452
|
-
(s) => html`
|
|
453
|
-
<button
|
|
454
|
-
type="button"
|
|
455
|
-
class="new-project-template ${_starter === s.id ? "selected" : ""}"
|
|
456
|
-
@click=${() => selectStarter(s.id)}
|
|
457
|
-
title=${s.description}
|
|
458
|
-
>
|
|
459
|
-
<img class="new-project-template-thumb" src=${s.thumbnail} alt="" />
|
|
460
|
-
<div class="new-project-template-body">
|
|
461
|
-
<div class="new-project-template-name">${s.name}</div>
|
|
462
|
-
<div class="new-project-template-tag">${s.tagline}</div>
|
|
463
|
-
</div>
|
|
464
|
-
</button>
|
|
465
|
-
`,
|
|
466
|
-
)}
|
|
467
|
-
</div>
|
|
468
|
-
`
|
|
469
|
-
: html`<div class="new-project-tab-intro">No starter sites are available.</div>`;
|
|
470
|
-
|
|
471
450
|
const agentSourceTpl = () => {
|
|
472
|
-
if (!
|
|
451
|
+
if (!aiGateOpen()) {
|
|
473
452
|
return html`
|
|
474
453
|
<div class="new-project-tab-intro">
|
|
475
|
-
The agent uses your AI provider to build the site.
|
|
476
|
-
|
|
454
|
+
The agent uses your AI provider to build the site.
|
|
455
|
+
${
|
|
456
|
+
managedConnect().canOffer()
|
|
457
|
+
? "Connect Cloudflare, or add an OpenAI-compatible API key, to continue."
|
|
458
|
+
: "Add an OpenAI-compatible API key to continue."
|
|
459
|
+
}
|
|
477
460
|
</div>
|
|
478
|
-
<div class="new-project-creds">${credsForm().render()}</div>
|
|
461
|
+
<div class="new-project-creds">${managedConnect().render()} ${credsForm().render()}</div>
|
|
479
462
|
`;
|
|
480
463
|
}
|
|
481
464
|
return html`
|
|
@@ -500,9 +483,6 @@ function renderModal() {
|
|
|
500
483
|
|
|
501
484
|
const sourceBodyTpl = () => {
|
|
502
485
|
switch (_tab) {
|
|
503
|
-
case "starter": {
|
|
504
|
-
return starterSourceTpl();
|
|
505
|
-
}
|
|
506
486
|
case "import": {
|
|
507
487
|
return renderImportSource(importCtx);
|
|
508
488
|
}
|
|
@@ -510,14 +490,15 @@ function renderModal() {
|
|
|
510
490
|
return agentSourceTpl();
|
|
511
491
|
}
|
|
512
492
|
default: {
|
|
513
|
-
return
|
|
493
|
+
return starterSourceTpl();
|
|
514
494
|
}
|
|
515
495
|
}
|
|
516
496
|
};
|
|
517
497
|
|
|
518
|
-
// ─── Step 2:
|
|
498
|
+
// ─── Step 2: name + location ───────────────────────────────────────────────
|
|
519
499
|
|
|
520
|
-
const
|
|
500
|
+
const paramsBodyTpl = () => html`
|
|
501
|
+
<div class="new-project-step-context">${sourceLabel()}</div>
|
|
521
502
|
<label class="new-project-field">
|
|
522
503
|
<span class="new-project-label">Project Name *</span>
|
|
523
504
|
<sp-textfield
|
|
@@ -541,47 +522,14 @@ function renderModal() {
|
|
|
541
522
|
rerender: renderModal,
|
|
542
523
|
slug: _form.directory,
|
|
543
524
|
})}
|
|
544
|
-
`;
|
|
545
|
-
|
|
546
|
-
const paramsBodyTpl = () => html`
|
|
547
|
-
<div class="new-project-step-context">${sourceLabel()}</div>
|
|
548
|
-
<div class="new-project-step-heading">New Project Parameters</div>
|
|
549
|
-
${nameDirFieldsTpl()}
|
|
550
525
|
${
|
|
551
526
|
_tab === "import"
|
|
552
527
|
? renderImportStatus()
|
|
553
528
|
: html`
|
|
554
|
-
<
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
.value=${_form.description}
|
|
559
|
-
@input=${onInput("description")}
|
|
560
|
-
style="width: 100%"
|
|
561
|
-
></sp-textfield>
|
|
562
|
-
</label>
|
|
563
|
-
|
|
564
|
-
<label class="new-project-field">
|
|
565
|
-
<span class="new-project-label">Production URL</span>
|
|
566
|
-
<sp-textfield
|
|
567
|
-
placeholder="https://example.com"
|
|
568
|
-
.value=${_form.url}
|
|
569
|
-
@input=${onInput("url")}
|
|
570
|
-
style="width: 100%"
|
|
571
|
-
></sp-textfield>
|
|
572
|
-
</label>
|
|
573
|
-
|
|
574
|
-
<label class="new-project-field">
|
|
575
|
-
<span class="new-project-label">Deployment Adapter</span>
|
|
576
|
-
<sp-picker label="Adapter" .value=${_form.adapter} @change=${onAdapterChange}>
|
|
577
|
-
<sp-menu-item value="static">Static</sp-menu-item>
|
|
578
|
-
<sp-menu-item value="cloudflare-pages">Cloudflare Pages</sp-menu-item>
|
|
579
|
-
<sp-menu-item value="node">Node</sp-menu-item>
|
|
580
|
-
<sp-menu-item value="bun">Bun</sp-menu-item>
|
|
581
|
-
</sp-picker>
|
|
582
|
-
</label>
|
|
583
|
-
|
|
584
|
-
${renderDesignFields({ rerender: renderModal })}
|
|
529
|
+
<div class="new-project-tab-intro">
|
|
530
|
+
The site's address, deployment target and design tokens are project settings — set
|
|
531
|
+
them from Settings once the project is open.
|
|
532
|
+
</div>
|
|
585
533
|
`
|
|
586
534
|
}
|
|
587
535
|
`;
|
|
@@ -589,7 +537,14 @@ function renderModal() {
|
|
|
589
537
|
// ─── Footer ────────────────────────────────────────────────────────────────
|
|
590
538
|
|
|
591
539
|
const footerTpl = () => {
|
|
540
|
+
const cancel = html`
|
|
541
|
+
<sp-button variant="secondary" ?disabled=${_creating} @click=${closeNewProjectModal}>
|
|
542
|
+
Cancel
|
|
543
|
+
</sp-button>
|
|
544
|
+
`;
|
|
592
545
|
if (isImportRunning()) {
|
|
546
|
+
// One cancel, not two: the run's own Cancel is the step's Cancel, and dismissing the modal
|
|
547
|
+
// (Escape, the underlay, the header ✕) aborts the run on the way out.
|
|
593
548
|
return html`
|
|
594
549
|
<sp-button variant="secondary" @click=${() => cancelImport(importCtx)}>
|
|
595
550
|
Cancel Import
|
|
@@ -597,9 +552,9 @@ function renderModal() {
|
|
|
597
552
|
`;
|
|
598
553
|
}
|
|
599
554
|
if (_step === "source") {
|
|
600
|
-
const gated = (_tab === "import" || _tab === "agent") && !
|
|
555
|
+
const gated = (_tab === "import" || _tab === "agent") && !aiGateOpen();
|
|
601
556
|
return html`
|
|
602
|
-
|
|
557
|
+
${cancel}
|
|
603
558
|
${gated ? "" : html`<sp-button variant="accent" @click=${goNext}>Next</sp-button>`}
|
|
604
559
|
`;
|
|
605
560
|
}
|
|
@@ -622,6 +577,7 @@ function renderModal() {
|
|
|
622
577
|
</sp-button>
|
|
623
578
|
`;
|
|
624
579
|
return html`
|
|
580
|
+
${cancel}
|
|
625
581
|
<sp-button variant="secondary" ?disabled=${_creating} @click=${goBack}>Back</sp-button>
|
|
626
582
|
${primary}
|
|
627
583
|
`;
|
|
@@ -636,16 +592,11 @@ function renderModal() {
|
|
|
636
592
|
|
|
637
593
|
const tpl = html`
|
|
638
594
|
<sp-underlay open @close=${closeNewProjectModal}></sp-underlay>
|
|
639
|
-
<div
|
|
640
|
-
class="new-project-modal"
|
|
641
|
-
@keydown=${(e: KeyboardEvent) => {
|
|
642
|
-
if (e.key === "Escape") {
|
|
643
|
-
closeNewProjectModal();
|
|
644
|
-
}
|
|
645
|
-
}}
|
|
646
|
-
>
|
|
595
|
+
<div class="new-project-modal" data-jx-region="overlay.dialog:new-project">
|
|
647
596
|
<div class="new-project-modal-header">
|
|
648
|
-
<h2 class="new-project-modal-title">
|
|
597
|
+
<h2 class="new-project-modal-title">
|
|
598
|
+
${_step === "source" ? "Choose a starting point" : "Name your project"}
|
|
599
|
+
</h2>
|
|
649
600
|
<sp-action-button quiet size="s" @click=${closeNewProjectModal} title="Close">
|
|
650
601
|
<sp-icon-close slot="icon"></sp-icon-close>
|
|
651
602
|
</sp-action-button>
|
|
@@ -655,8 +606,7 @@ function renderModal() {
|
|
|
655
606
|
? html`
|
|
656
607
|
<div class="new-project-tabs">
|
|
657
608
|
<sp-tabs selected=${_tab} quiet @change=${onTabChange}>
|
|
658
|
-
<sp-tab value="
|
|
659
|
-
<sp-tab value="starter" label="Starter Site"></sp-tab>
|
|
609
|
+
<sp-tab value="starter" label="Starters"></sp-tab>
|
|
660
610
|
${platform.importSite ? html`<sp-tab value="import" label="Import"></sp-tab>` : ""}
|
|
661
611
|
<sp-tab value="agent" label="Agent"></sp-tab>
|
|
662
612
|
</sp-tabs>
|
|
@@ -684,10 +634,68 @@ function renderModal() {
|
|
|
684
634
|
`;
|
|
685
635
|
|
|
686
636
|
if (!_handle) {
|
|
687
|
-
_handle = openModal(tpl);
|
|
637
|
+
_handle = openModal(tpl, { label: "New Project", onDismiss: closeNewProjectModal });
|
|
688
638
|
} else {
|
|
689
639
|
_handle.update(tpl);
|
|
690
640
|
}
|
|
691
641
|
}
|
|
692
642
|
|
|
693
643
|
let _dirDerived = true;
|
|
644
|
+
|
|
645
|
+
// ─── Commands ─────────────────────────────────────────────────────────────────
|
|
646
|
+
|
|
647
|
+
/** The wizard's source tabs, in strip order — the declared values of `project.new`'s `tab`. */
|
|
648
|
+
export const NEW_PROJECT_TABS = ["starter", "import", "agent"] as const;
|
|
649
|
+
|
|
650
|
+
/**
|
|
651
|
+
* Open the New Project wizard.
|
|
652
|
+
*
|
|
653
|
+
* `tab` is declared as an enum rather than passed through, because the two non-default tabs are AI
|
|
654
|
+
* gated: naming one that does not exist would open the wizard on Starters and a shot would record
|
|
655
|
+
* that as "the Import tab". The wizard resolves the returned promise when the project is created or
|
|
656
|
+
* dismissed; the command deliberately does not await it — opening a modal is the action, and
|
|
657
|
+
* blocking `run` until a human finishes a wizard would hold the palette open behind it.
|
|
658
|
+
*
|
|
659
|
+
* @returns {AnyCommand[]}
|
|
660
|
+
*/
|
|
661
|
+
export function newProjectCommands(): AnyCommand[] {
|
|
662
|
+
return [
|
|
663
|
+
{
|
|
664
|
+
args: {
|
|
665
|
+
additionalProperties: false,
|
|
666
|
+
properties: {
|
|
667
|
+
tab: enumProperty(NEW_PROJECT_TABS, "Which source tab to open on. Defaults to Starters."),
|
|
668
|
+
},
|
|
669
|
+
required: [],
|
|
670
|
+
type: "object",
|
|
671
|
+
},
|
|
672
|
+
category: "Project",
|
|
673
|
+
id: "project.new",
|
|
674
|
+
level: "application",
|
|
675
|
+
menus: ["commandbar/overflow", "palette"],
|
|
676
|
+
group: "1_file",
|
|
677
|
+
aiTool: {
|
|
678
|
+
description:
|
|
679
|
+
"Open the New Project wizard, optionally on the Starters, Import or Agent tab.",
|
|
680
|
+
name: "open_new_project",
|
|
681
|
+
},
|
|
682
|
+
run: (_commandCtx, args) => {
|
|
683
|
+
const tab =
|
|
684
|
+
(args as { tab?: unknown }).tab === undefined
|
|
685
|
+
? undefined
|
|
686
|
+
: enumArg("project.new", args, "tab", NEW_PROJECT_TABS);
|
|
687
|
+
void openNewProjectModal(tab === undefined ? {} : { tab });
|
|
688
|
+
},
|
|
689
|
+
title: "New Project…",
|
|
690
|
+
},
|
|
691
|
+
];
|
|
692
|
+
}
|
|
693
|
+
|
|
694
|
+
/**
|
|
695
|
+
* Register the New Project verb.
|
|
696
|
+
*
|
|
697
|
+
* @param {CommandRegistry} registry
|
|
698
|
+
*/
|
|
699
|
+
export function registerNewProjectCommands(registry: CommandRegistry): void {
|
|
700
|
+
registry.registerAll(newProjectCommands());
|
|
701
|
+
}
|