@jxsuite/studio 6.1.2 → 8.0.1
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/README.md +5 -5
- package/dist/chunks/2020-5wtzce5g.js +4 -0
- package/dist/chunks/adapter-5tphg7xe.js +4 -0
- package/dist/chunks/add-new-flow-psym14sn.js +4 -0
- package/dist/chunks/cf-account-picker-haqazq5r.js +4 -0
- package/dist/chunks/cf-settings-h2wrh6hq.js +4 -0
- package/dist/chunks/{color-area-0fj8a4ga.js → color-area-6rbra5dy.js} +2 -2
- package/dist/chunks/{color-field-xch8kx2g.js → color-field-gy56c94g.js} +3 -3
- package/dist/chunks/color-m7r1vk54.js +4 -0
- package/dist/chunks/{color-slider-jxd8v350.js → color-slider-sqqdyf6c.js} +2 -2
- package/dist/chunks/{combobox-p0efwjke.js → combobox-72h32ejk.js} +3 -3
- package/dist/chunks/components-r22xca09.js +4 -0
- package/dist/chunks/content-source-mmppmcyg.js +4 -0
- package/dist/chunks/convert-to-repeater-he70fc2b.js +4 -0
- package/dist/chunks/editor-ccd9jwsa.js +4 -0
- package/dist/chunks/entry-commands-6qxz9e8p.js +4 -0
- package/dist/chunks/extension-sections-0egb88dm.js +4 -0
- package/dist/chunks/file-ops-qnab36ek.js +4 -0
- package/dist/chunks/files-rcn56qvm.js +4 -0
- package/dist/chunks/format-host-yxz0kjjs.js +4 -0
- package/dist/chunks/fs-events-d1qxq4z4.js +4 -0
- package/dist/chunks/grid-open-4z1g062t.js +4 -0
- package/dist/chunks/{grid-view-d2wq9ezg.js → grid-view-qg1b5eqx.js} +25 -25
- package/dist/chunks/{icons-pnfz478q.js → icons-63bjtbs7.js} +2 -2
- package/dist/chunks/{iframe-entry-jdcktez8.js → iframe-entry-2zggzajv.js} +4 -4
- package/dist/chunks/{iframe-entry-zap785cw.js → iframe-entry-76j8vwwx.js} +4 -4
- package/dist/chunks/iframe-entry-99nr5zfb.js +5 -0
- package/dist/chunks/{iframe-entry-x0ygf2yr.js → iframe-entry-pkgmcgp0.js} +4 -4
- package/dist/chunks/iframe-host-ssv7kyj0.js +4 -0
- package/dist/chunks/{index-zpjmzqfk.js → index-32eqzv1k.js} +3 -3
- package/dist/chunks/index-f0jn7nnp.js +4 -0
- package/dist/chunks/{javascript-m54mnwp6.js → javascript-pjp734q4.js} +3 -3
- package/dist/chunks/jsonMode-njkvsa02.js +13 -0
- package/dist/chunks/jx-validate-ttasrbh7.js +4 -0
- package/dist/chunks/layers-bgyr11tr.js +4 -0
- package/dist/chunks/layers-panel-7ez66zeq.js +4 -0
- package/dist/chunks/{listbox-e74qjyq6.js → listbox-c421cf8c.js} +2 -2
- package/dist/chunks/lit-html-v9gh687x.js +4 -0
- package/dist/chunks/media-library-sq468wts.js +4 -0
- package/dist/chunks/media-picker-shfe59pt.js +4 -0
- package/dist/chunks/{menu-n6yzswmy.js → menu-bdpzbfvs.js} +2 -2
- package/dist/chunks/{monaco-binding-7gx83x3r.js → monaco-binding-vq1hgnn0.js} +3 -3
- package/dist/chunks/monaco-buffer-3afgwvbp.js +4 -0
- package/dist/chunks/monaco-setup-xrd2cbkp.js +4 -0
- package/dist/chunks/notify-kzrjr3fv.js +4 -0
- package/dist/chunks/parse-v77xtwv7.js +4 -0
- package/dist/chunks/platform-7v4rtd7m.js +4 -0
- package/dist/chunks/popover-b89sfej7.js +4 -0
- package/dist/chunks/publish-panel-2z9gw8ee.js +4 -0
- package/dist/chunks/publish-quick-qx2455cj.js +4 -0
- package/dist/chunks/publish-workspace-wrc1dgwx.js +4 -0
- package/dist/chunks/quick-search-n0t0eqxb.js +4 -0
- package/dist/chunks/references-9547rg5s.js +4 -0
- package/dist/chunks/right-panel-wsgnr9pn.js +4 -0
- package/dist/chunks/source-control-kwktr9y6.js +4 -0
- package/dist/chunks/{split-n2gfpm5m.js → split-c9zfdgxf.js} +2 -2
- package/dist/chunks/studio-03ct6yfv.js +9 -0
- package/dist/chunks/studio-07rcfje3.js +5 -0
- package/dist/chunks/studio-3e54qh39.js +7 -0
- package/dist/chunks/studio-3exxhz5g.js +5 -0
- package/dist/chunks/studio-3q40e3rj.js +5 -0
- package/dist/chunks/studio-3qeh9t0h.js +6 -0
- package/dist/chunks/studio-3qqjeep5.js +6 -0
- package/dist/chunks/studio-43sd2mam.js +4 -0
- package/dist/chunks/studio-4hp8pkyt.js +5 -0
- package/dist/chunks/studio-58xg6j2q.js +9 -0
- package/dist/chunks/studio-5g0rprdt.js +7 -0
- package/dist/chunks/{studio-2j1cb95x.js → studio-6m380wp7.js} +4 -4
- package/dist/chunks/studio-80jyh1xh.js +4 -0
- package/dist/chunks/studio-83mk4bgg.js +9 -0
- package/dist/chunks/{studio-v0jzqdjm.js → studio-881z1xrx.js} +4 -4
- package/dist/chunks/studio-8m0y2qe7.js +5 -0
- package/dist/chunks/{studio-d81xfh1g.js → studio-8tr6cfrc.js} +4 -4
- package/dist/chunks/studio-8vcvfs7r.js +6 -0
- package/dist/chunks/studio-9tmebf0s.js +5 -0
- package/dist/chunks/studio-a2bvaptz.js +5 -0
- package/dist/chunks/studio-b7y5mr30.js +5 -0
- package/dist/chunks/studio-bavb31r0.js +5 -0
- package/dist/chunks/{studio-dgz8d0c1.js → studio-bbe4c90a.js} +4 -4
- package/dist/chunks/studio-c05wdnt3.js +5 -0
- package/dist/chunks/studio-ccv2svc6.js +5 -0
- package/dist/chunks/studio-d5grtb9e.js +16 -0
- package/dist/chunks/studio-df0baea9.js +5 -0
- package/dist/chunks/studio-dgk4dqtx.js +7 -0
- package/dist/chunks/studio-e1g64q43.js +5 -0
- package/dist/chunks/studio-ed1hp6zf.js +6 -0
- package/dist/chunks/studio-ed3xx40h.js +7 -0
- package/dist/chunks/studio-f14e1zdj.js +5 -0
- package/dist/chunks/studio-fbhxxc5f.js +5 -0
- package/dist/chunks/studio-fyh0jc96.js +5 -0
- package/dist/chunks/studio-gcxk20n7.js +5 -0
- package/dist/chunks/studio-jaaz8ce9.js +5 -0
- package/dist/chunks/{studio-90pq9km1.js → studio-jcnsdaep.js} +4 -4
- package/dist/chunks/studio-jsgf2q5k.js +7 -0
- package/dist/chunks/{studio-0q988f9w.js → studio-k3xxbagr.js} +3 -3
- package/dist/chunks/{studio-5ve6bbep.js → studio-k7evxqh4.js} +4 -4
- package/dist/chunks/studio-kt3pjkwd.js +5 -0
- package/dist/chunks/studio-m8g16bgz.js +5 -0
- package/dist/chunks/studio-mn0476ag.js +5 -0
- package/dist/chunks/studio-mx1smyq0.js +5 -0
- package/dist/chunks/studio-n0c5h6mf.js +5 -0
- package/dist/chunks/{studio-485046te.js → studio-nh6d342n.js} +7 -7
- package/dist/chunks/studio-nqxqf8p2.js +4 -0
- package/dist/chunks/studio-p4nrkvqr.js +5 -0
- package/dist/chunks/{studio-1fxkaaea.js → studio-pbxa5fpc.js} +4 -4
- package/dist/chunks/studio-pgmvdv7z.js +7 -0
- package/dist/chunks/studio-ph84avkf.js +5 -0
- package/dist/chunks/{studio-tq0rtfwj.js → studio-q0mvbaq6.js} +4 -4
- package/dist/chunks/studio-q0tccd43.js +5 -0
- package/dist/chunks/studio-q7rtx6zq.js +14 -0
- package/dist/chunks/{studio-a3g98wjr.js → studio-qgh13jtz.js} +4 -4
- package/dist/chunks/studio-qmn1xc24.js +5 -0
- package/dist/chunks/studio-qwdqwkj0.js +5 -0
- package/dist/chunks/studio-r5qy30vx.js +5 -0
- package/dist/chunks/studio-rj9eamf8.js +5 -0
- package/dist/chunks/studio-rptgsk96.js +5 -0
- package/dist/chunks/studio-rthyg42z.js +928 -0
- package/dist/chunks/studio-s19tp1xr.js +5 -0
- package/dist/chunks/studio-s32578pn.js +5 -0
- package/dist/chunks/studio-svb7yyve.js +5 -0
- package/dist/chunks/studio-syreb644.js +5 -0
- package/dist/chunks/studio-tf9jryb1.js +10 -0
- package/dist/chunks/studio-tfkznv39.js +5 -0
- package/dist/chunks/studio-tft6r105.js +5 -0
- package/dist/chunks/studio-txf2kysx.js +5 -0
- package/dist/chunks/studio-v8867ddv.js +12 -0
- package/dist/chunks/studio-vxq7fcvv.js +5 -0
- package/dist/chunks/studio-w4rz9hdk.js +5 -0
- package/dist/chunks/studio-wbcjbhy1.js +9 -0
- package/dist/chunks/studio-wc649wss.js +5 -0
- package/dist/chunks/studio-wys23mxz.js +5 -0
- package/dist/chunks/studio-x1x167jh.js +5 -0
- package/dist/chunks/studio-x9hsze61.js +5 -0
- package/dist/chunks/studio-y0n7yxea.js +9 -0
- package/dist/chunks/studio-y3ahhdpx.js +5 -0
- package/dist/chunks/studio-z97c48fk.js +5 -0
- package/dist/chunks/studio-zat62m0c.js +5 -0
- package/dist/chunks/studio-zcd2e7yz.js +5 -0
- package/dist/chunks/studio-zz9qe3rw.js +64 -0
- package/dist/chunks/toast-1gv0h53h.js +4 -0
- package/dist/chunks/{toast-host-ke5z4ng7.js → toast-host-1yg5ar8d.js} +3 -3
- package/dist/chunks/{tooltip-5v8ngwj2.js → tooltip-yypz28gq.js} +3 -3
- package/dist/chunks/{tree-mdq3v5cw.js → tree-9xa4hm7n.js} +2 -2
- package/dist/chunks/tsMode-epyfz1hv.js +14 -0
- package/dist/chunks/workspace-dz7nxfhv.js +4 -0
- package/dist/chunks/workspace-home-xsd7hkjw.js +4 -0
- package/dist/chunks/{ws-client-nze0k6mv.js → ws-client-bv552sfx.js} +3 -3
- package/dist/iframe-entry.js +20 -16
- package/dist/manifest.json +77 -63
- package/dist/studio.js +103 -104
- package/dist/workers/ts.worker.js +3 -3
- package/package.json +12 -11
- package/src/browse/component-examples.ts +272 -0
- package/src/browse/library-commands.ts +64 -104
- package/src/browse/library-layouts.ts +263 -49
- package/src/browse/library-model.ts +181 -133
- package/src/browse/library-pane.ts +738 -446
- package/src/browse/library-preview.ts +149 -19
- package/src/browse/library-source.ts +308 -41
- package/src/browse/preview-root.ts +78 -0
- package/src/browse/preview-style.ts +155 -0
- package/src/canvas/asset-refs.ts +16 -1
- package/src/canvas/canvas-live-render.ts +222 -30
- package/src/canvas/canvas-origin.ts +37 -12
- package/src/canvas/canvas-page-context.ts +112 -0
- package/src/canvas/canvas-render.ts +113 -107
- package/src/canvas/canvas-utils.ts +57 -12
- package/src/canvas/iframe-drop.ts +107 -0
- package/src/canvas/iframe-entry.ts +24 -12
- package/src/canvas/iframe-host.ts +134 -62
- package/src/canvas/iframe-keys.ts +11 -0
- package/src/canvas/iframe-patch.ts +8 -7
- package/src/canvas/iframe-protocol.ts +24 -5
- package/src/canvas/iframe-render.ts +48 -1
- package/src/canvas/iframe-subtree.ts +5 -2
- package/src/canvas/npm-modules.ts +22 -0
- package/src/canvas/preview-navigate.ts +16 -0
- package/src/canvas/repeater-sources.ts +200 -0
- package/src/canvas/stage-scrollbar.ts +5 -1
- package/src/canvas/surface-registry.ts +6 -0
- package/src/commands/app-commands.ts +16 -6
- package/src/commands/budget.ts +10 -8
- package/src/commands/context.ts +35 -10
- package/src/commands/defaults.ts +69 -45
- package/src/commands/keymap.ts +9 -0
- package/src/commands/levels.ts +11 -5
- package/src/commands/live-context.ts +2 -0
- package/src/commands/registry.ts +10 -1
- package/src/content/collection-match.ts +6 -5
- package/src/content/collection-pages.ts +412 -0
- package/src/content/content-collections.ts +270 -0
- package/src/content/entry-commands.ts +51 -60
- package/src/content/entry-editor.ts +111 -18
- package/src/content/entry-fields.ts +13 -1
- package/src/content/entry-inspector.ts +225 -0
- package/src/content/entry-model.ts +17 -3
- package/src/content/entry-open.ts +80 -0
- package/src/content/entry-summaries.ts +440 -0
- package/src/content/file-record-ids.ts +80 -0
- package/src/content/file-records.ts +125 -0
- package/src/content/page-summaries.ts +129 -0
- package/src/content/record-entry.ts +201 -0
- package/src/content/writing-banner.ts +177 -0
- package/src/create/add-new-commands.ts +185 -0
- package/src/create/add-new-flow.ts +1116 -0
- package/src/create/add-new.ts +1014 -0
- package/src/create/element-name.ts +121 -0
- package/src/editor/convert-to-component.ts +67 -43
- package/src/editor/file-drop-action.ts +9 -1
- package/src/editor/inline-edit-apply.ts +44 -0
- package/src/editor/inline-edit.ts +10 -0
- package/src/editor/insert-component.ts +91 -0
- package/src/editor/insert-zone-action.ts +13 -4
- package/src/editor/shortcuts.ts +44 -22
- package/src/editor/slash-menu.ts +51 -8
- package/src/files/components.ts +74 -10
- package/src/files/file-ops.ts +15 -5
- package/src/files/files.ts +164 -150
- package/src/files/fs-events.ts +18 -7
- package/src/files/media-meta.ts +95 -1
- package/src/files/media-types.ts +55 -0
- package/src/files/media-upload.ts +209 -52
- package/src/files/new-file-name.ts +156 -0
- package/src/files/serialize-document.ts +13 -3
- package/src/format/format-host.ts +15 -0
- package/src/github/github-auth.ts +2 -2
- package/src/github/github-publish.ts +4 -3
- package/src/grid/grid-controller.ts +5 -1
- package/src/grid/grid-open.ts +0 -27
- package/src/grid/grid-panel.ts +54 -2
- package/src/grid/grid-reveal.ts +34 -0
- package/src/grid/grid-source.ts +3 -25
- package/src/grid/grid-view.ts +31 -6
- package/src/grid/sources/content-source.ts +75 -7
- package/src/grid/tabulator-tables.d.ts +6 -0
- package/src/hosting/document.ts +2 -2
- package/src/i18n/i18n-commands.ts +2 -1
- package/src/media/media-commands.ts +181 -0
- package/src/media/media-library-model.ts +232 -0
- package/src/media/media-library.ts +1283 -0
- package/src/media/media-pane.ts +47 -19
- package/src/packages/pull-package-sync.ts +1 -1
- package/src/panels/activity-panel.ts +21 -5
- package/src/panels/ai-chat/chat-markdown.ts +8 -8
- package/src/panels/block-action-bar.ts +11 -11
- package/src/panels/canvas-dnd-bridge.ts +5 -2
- package/src/panels/chat-panel.ts +6 -6
- package/src/panels/collections-panel.ts +306 -0
- package/src/panels/component-preview.ts +35 -13
- package/src/panels/data-explorer.ts +1 -1
- package/src/panels/data-grid.ts +4 -0
- package/src/panels/dnd.ts +17 -30
- package/src/panels/elements-panel.ts +9 -2
- package/src/panels/empty-state.ts +2 -2
- package/src/panels/formula-workspace.ts +2 -3
- package/src/panels/frontmatter-fields.ts +9 -9
- package/src/panels/git-diff-open.ts +9 -5
- package/src/panels/head-panel.ts +369 -103
- package/src/panels/i18n-panel.ts +11 -10
- package/src/panels/imports-panel.ts +2 -0
- package/src/panels/jump-bar.ts +27 -2
- package/src/panels/layers-panel.ts +36 -30
- package/src/panels/left-panel.ts +22 -8
- package/src/panels/navigator-panels.ts +23 -11
- package/src/panels/pane-context.ts +111 -29
- package/src/panels/pane-grid.ts +6 -6
- package/src/panels/panel-registry.ts +14 -9
- package/src/panels/properties-panel.ts +7 -3
- package/src/panels/right-panel.ts +199 -43
- package/src/panels/seo-modal.ts +41 -108
- package/src/panels/settings-menu.ts +52 -50
- package/src/panels/settings-pane.ts +268 -162
- package/src/panels/signals-panel.ts +3 -4
- package/src/panels/site-model.ts +367 -0
- package/src/panels/site-panel.ts +638 -0
- package/src/panels/style-panel.ts +37 -3
- package/src/panels/stylebook-doc.ts +142 -10
- package/src/panels/stylebook-layers-panel.ts +39 -80
- package/src/panels/stylebook-panel.ts +47 -10
- package/src/panels/styles-panel.ts +327 -0
- package/src/panels/tab-strip.ts +109 -25
- package/src/platform.ts +1 -1
- package/src/platforms/cloud.ts +28 -1
- package/src/platforms/default-platform.ts +4 -4
- package/src/platforms/devserver.ts +51 -25
- package/src/publish/deploy-checklist.ts +12 -7
- package/src/publish/pages-service.ts +38 -14
- package/src/publish/publish-changes.ts +491 -0
- package/src/publish/publish-commands.ts +83 -18
- package/src/publish/publish-ids.ts +49 -0
- package/src/publish/publish-quick.ts +148 -0
- package/src/publish/publish-workspace.ts +926 -0
- package/src/publish/source-control.ts +907 -0
- package/src/services/automation.ts +16 -20
- package/src/services/cf-settings.ts +4 -4
- package/src/services/connection.ts +2 -2
- package/src/services/directory-picker.ts +2 -2
- package/src/services/references.ts +0 -0
- package/src/services/render-critic.ts +21 -2
- package/src/services/settings/definitions.ts +25 -14
- package/src/settings/contributed-section.ts +49 -10
- package/src/settings/css-vars-editor.ts +93 -27
- package/src/settings/developer-panels.ts +43 -0
- package/src/settings/extension-sections.ts +20 -2
- package/src/settings/general-settings.ts +91 -21
- package/src/settings/preferences-dialog.ts +8 -1
- package/src/settings/project-sections.ts +27 -10
- package/src/settings/schema-field-ui.ts +3 -1
- package/src/settings/section-registry.ts +116 -11
- package/src/settings/settings-dialog.ts +192 -0
- package/src/settings/settings-document.ts +182 -162
- package/src/shell.ts +467 -431
- package/src/site-context.ts +64 -10
- package/src/state.ts +28 -9
- package/src/studio.ts +194 -41
- package/src/style/project-styles.ts +34 -0
- package/src/style/stylebook-specimens.ts +89 -0
- package/src/style/stylebook-target.ts +26 -0
- package/src/style/tag-inheritance.ts +105 -0
- package/src/style/variables-focus.ts +61 -0
- package/src/style/variables-view.ts +235 -0
- package/src/surfaces/add-new.json +1482 -0
- package/src/surfaces/add-new.ts +325 -0
- package/src/surfaces/ai-chat.ts +2 -2
- package/src/surfaces/boot-failure.json +4 -3
- package/src/surfaces/bottom-dock.json +1 -1
- package/src/surfaces/canvas-stage.json +30 -19
- package/src/surfaces/canvas-stage.ts +5 -5
- package/src/surfaces/collections-panel.json +615 -0
- package/src/surfaces/collections-panel.ts +168 -0
- package/src/surfaces/commandbar.json +241 -96
- package/src/surfaces/commandbar.ts +134 -99
- package/src/surfaces/empty-state.json +1 -1
- package/src/surfaces/entry-editor.json +136 -0
- package/src/surfaces/entry-editor.ts +21 -0
- package/src/surfaces/entry-inspector.json +371 -0
- package/src/surfaces/entry-inspector.ts +143 -0
- package/src/surfaces/inspector-dock.json +162 -14
- package/src/surfaces/inspector-dock.ts +46 -19
- package/src/surfaces/library-pane.json +670 -437
- package/src/surfaces/library-pane.ts +94 -59
- package/src/surfaces/media-browser.json +62 -6
- package/src/surfaces/media-browser.ts +15 -1
- package/src/surfaces/media-field.json +1 -1
- package/src/surfaces/media-library.json +1586 -0
- package/src/surfaces/media-library.ts +282 -0
- package/src/surfaces/media-pick-dialog.json +71 -0
- package/src/surfaces/media-pick-dialog.ts +132 -0
- package/src/surfaces/menu.ts +18 -0
- package/src/surfaces/pane-context.json +144 -77
- package/src/surfaces/pane-context.ts +24 -0
- package/src/surfaces/panel-deploy-checklist.json +12 -6
- package/src/surfaces/panel-deploy-checklist.ts +3 -1
- package/src/surfaces/panel-page.json +72 -2
- package/src/surfaces/panel-page.ts +38 -7
- package/src/surfaces/panel-signals.json +1 -1
- package/src/surfaces/panel-signals.ts +5 -5
- package/src/surfaces/panel-stylebook-layers.json +71 -204
- package/src/surfaces/panel-stylebook-layers.ts +0 -21
- package/src/surfaces/preferences.json +120 -48
- package/src/surfaces/preferences.ts +8 -0
- package/src/surfaces/publish-quick.json +428 -0
- package/src/surfaces/publish-quick.ts +165 -0
- package/src/surfaces/publish-workspace.json +2892 -0
- package/src/surfaces/publish-workspace.ts +391 -0
- package/src/surfaces/rail.json +1 -159
- package/src/surfaces/rail.ts +18 -75
- package/src/surfaces/schema-form.json +10 -2
- package/src/surfaces/schema-form.ts +2 -0
- package/src/surfaces/seo.json +1 -1
- package/src/surfaces/settings-contributed.json +5 -5
- package/src/surfaces/settings-contributed.ts +18 -2
- package/src/surfaces/settings-css-vars.json +44 -36
- package/src/surfaces/settings-css-vars.ts +77 -4
- package/src/surfaces/settings-deploy.json +2 -15
- package/src/surfaces/settings-deploy.ts +1 -1
- package/src/surfaces/settings-dialog.json +51 -0
- package/src/surfaces/settings-dialog.ts +169 -0
- package/src/surfaces/settings-overview.json +3 -3
- package/src/surfaces/settings-overview.ts +9 -2
- package/src/surfaces/settings-pane.json +269 -46
- package/src/surfaces/settings-pane.ts +85 -24
- package/src/surfaces/shell.json +2 -1
- package/src/surfaces/site-panel.json +1029 -0
- package/src/surfaces/site-panel.ts +233 -0
- package/src/surfaces/slash-menu.json +63 -21
- package/src/surfaces/slash-menu.ts +23 -0
- package/src/surfaces/statusbar.ts +39 -15
- package/src/surfaces/styles-panel.json +735 -0
- package/src/surfaces/styles-panel.ts +195 -0
- package/src/surfaces/styles-variables.json +149 -0
- package/src/surfaces/styles-variables.ts +145 -0
- package/src/surfaces/tab-strip.json +4 -4
- package/src/surfaces/welcome.ts +1 -1
- package/src/surfaces/writing-banner.json +94 -0
- package/src/surfaces/writing-banner.ts +80 -0
- package/src/tabs/bare-repeaters.ts +101 -0
- package/src/tabs/tab.ts +47 -7
- package/src/types.ts +21 -26
- package/src/ui/form-controls.ts +47 -8
- package/src/ui/layers.ts +13 -0
- package/src/ui/media-picker.ts +284 -40
- package/src/ui/regions.ts +7 -6
- package/src/ui/schema-form.ts +259 -27
- package/src/ui/virtual-window.ts +26 -1
- package/src/utils/base64.ts +3 -3
- package/src/utils/edit-display.ts +322 -67
- package/src/utils/local-day.ts +18 -0
- package/src/workspace/pane-derive.ts +4 -4
- package/src/workspace/session.ts +28 -7
- package/src/workspace/tab-workspace.ts +137 -0
- package/src/workspace/workspace-back.ts +189 -0
- package/src/workspace/workspace-home.ts +133 -0
- package/src/workspace/workspace-ids.ts +129 -0
- package/src/workspace/workspace-switch.ts +372 -0
- package/src/workspace/workspace.ts +125 -11
- package/styles/shell-frame.css +30 -7
- package/styles/shell-frame.json +15 -3
- package/dist/chunks/2020-f2gkpy8d.js +0 -4
- package/dist/chunks/adapter-4912g339.js +0 -4
- package/dist/chunks/cf-account-picker-wccaenh6.js +0 -4
- package/dist/chunks/cf-settings-br6105tr.js +0 -4
- package/dist/chunks/color-28ksk2qm.js +0 -4
- package/dist/chunks/components-db68vsn7.js +0 -4
- package/dist/chunks/content-source-1449qesq.js +0 -4
- package/dist/chunks/convert-to-repeater-5h457egj.js +0 -4
- package/dist/chunks/editor-x9jn86a7.js +0 -4
- package/dist/chunks/entry-commands-may24cpt.js +0 -4
- package/dist/chunks/extension-sections-pvr14vxr.js +0 -4
- package/dist/chunks/file-ops-x9v54pcj.js +0 -4
- package/dist/chunks/files-j3knqf0s.js +0 -4
- package/dist/chunks/format-host-tyre2trb.js +0 -4
- package/dist/chunks/fs-events-64ma9htc.js +0 -4
- package/dist/chunks/git-panel-84ps5dex.js +0 -4
- package/dist/chunks/iframe-entry-fvbk89gm.js +0 -5
- package/dist/chunks/iframe-host-ck6vejt5.js +0 -4
- package/dist/chunks/index-b8xw3vy9.js +0 -4
- package/dist/chunks/jsonMode-w15cmrcm.js +0 -13
- package/dist/chunks/jx-validate-at3zn8wa.js +0 -4
- package/dist/chunks/layers-h4xp1pss.js +0 -4
- package/dist/chunks/layers-panel-m5hw1d7g.js +0 -4
- package/dist/chunks/lit-html-8t8t3dnr.js +0 -4
- package/dist/chunks/media-picker-2cweexc5.js +0 -4
- package/dist/chunks/menu-ynw13y0s.js +0 -4
- package/dist/chunks/monaco-buffer-qzxn567r.js +0 -4
- package/dist/chunks/monaco-setup-gxf6656g.js +0 -4
- package/dist/chunks/notify-cj5zbrs2.js +0 -4
- package/dist/chunks/parse-b7ddhr8m.js +0 -4
- package/dist/chunks/platform-3dfws9js.js +0 -4
- package/dist/chunks/popover-jt2gxmzs.js +0 -4
- package/dist/chunks/publish-panel-1gvxbj21.js +0 -4
- package/dist/chunks/quick-search-0dajrwqg.js +0 -4
- package/dist/chunks/references-49qgt404.js +0 -4
- package/dist/chunks/right-panel-jm1bwe53.js +0 -4
- package/dist/chunks/section-registry-6kwc4fky.js +0 -4
- package/dist/chunks/studio-0rt52vpq.js +0 -5
- package/dist/chunks/studio-18vgbhs5.js +0 -5
- package/dist/chunks/studio-24mccdrj.js +0 -5
- package/dist/chunks/studio-2eh507zk.js +0 -9
- package/dist/chunks/studio-2hcbccfv.js +0 -5
- package/dist/chunks/studio-2jbs3rxv.js +0 -5
- package/dist/chunks/studio-4h8k4dw9.js +0 -5
- package/dist/chunks/studio-5f6n18kx.js +0 -5
- package/dist/chunks/studio-5gthpky6.js +0 -5
- package/dist/chunks/studio-6ep3js6b.js +0 -9
- package/dist/chunks/studio-6wkmf3wz.js +0 -9
- package/dist/chunks/studio-841rf3cg.js +0 -5
- package/dist/chunks/studio-8gmwgheg.js +0 -5
- package/dist/chunks/studio-8qm0ep50.js +0 -5
- package/dist/chunks/studio-924p1tm1.js +0 -6
- package/dist/chunks/studio-a3shpz9y.js +0 -5
- package/dist/chunks/studio-amsbaaar.js +0 -6
- package/dist/chunks/studio-at5spjbc.js +0 -7
- package/dist/chunks/studio-b2xv945e.js +0 -5
- package/dist/chunks/studio-bn5nkafw.js +0 -5
- package/dist/chunks/studio-bw6q5xjf.js +0 -9
- package/dist/chunks/studio-c7q0t9x1.js +0 -5
- package/dist/chunks/studio-camnhc96.js +0 -6
- package/dist/chunks/studio-cffqvnzd.js +0 -5
- package/dist/chunks/studio-efvfrsf8.js +0 -5
- package/dist/chunks/studio-er30bpcx.js +0 -5
- package/dist/chunks/studio-ezscgr64.js +0 -5
- package/dist/chunks/studio-ffrrncvz.js +0 -5
- package/dist/chunks/studio-fpphgn8y.js +0 -10
- package/dist/chunks/studio-j1kvhdjk.js +0 -4
- package/dist/chunks/studio-j430n16g.js +0 -7
- package/dist/chunks/studio-jjkg84nj.js +0 -5
- package/dist/chunks/studio-m0q32ars.js +0 -4
- package/dist/chunks/studio-m6bdst11.js +0 -5
- package/dist/chunks/studio-nv2cptd4.js +0 -64
- package/dist/chunks/studio-nwfrc98n.js +0 -5
- package/dist/chunks/studio-p1wgvp7r.js +0 -5
- package/dist/chunks/studio-pag2wncm.js +0 -5
- package/dist/chunks/studio-qvanvzfd.js +0 -5
- package/dist/chunks/studio-qwa64kt7.js +0 -5
- package/dist/chunks/studio-rk1zc4x3.js +0 -928
- package/dist/chunks/studio-se2r3ptc.js +0 -5
- package/dist/chunks/studio-sg2a0dh0.js +0 -5
- package/dist/chunks/studio-tjzjhe68.js +0 -5
- package/dist/chunks/studio-v2w7q8r1.js +0 -7
- package/dist/chunks/studio-v5vjq1h0.js +0 -4
- package/dist/chunks/studio-v8aga3vp.js +0 -14
- package/dist/chunks/studio-vfcdrfmv.js +0 -5
- package/dist/chunks/studio-vmfkgdjf.js +0 -5
- package/dist/chunks/studio-wt1816jj.js +0 -5
- package/dist/chunks/studio-wz73q5kq.js +0 -4
- package/dist/chunks/studio-y04qtxvp.js +0 -7
- package/dist/chunks/studio-y21g8zzg.js +0 -5
- package/dist/chunks/studio-y64hrt8p.js +0 -12
- package/dist/chunks/studio-ynn90f58.js +0 -16
- package/dist/chunks/studio-yxz682sx.js +0 -5
- package/dist/chunks/studio-zp7snvkq.js +0 -5
- package/dist/chunks/studio-zq4z6tm6.js +0 -5
- package/dist/chunks/toast-c9fn075p.js +0 -4
- package/dist/chunks/tsMode-sf49ee9x.js +0 -14
- package/dist/chunks/workspace-jtfahpee.js +0 -4
- package/src/panels/frontmatter-panel.ts +0 -711
- package/src/panels/git-panel.ts +0 -1108
- package/src/surfaces/doc-header.json +0 -776
- package/src/surfaces/doc-header.ts +0 -222
- package/src/surfaces/git-panel.json +0 -1880
- package/src/surfaces/git-panel.ts +0 -264
package/src/shell.ts
CHANGED
|
@@ -8,8 +8,8 @@
|
|
|
8
8
|
* per-render cleanup arrays. It stays a plain object, because wrapping a live editor instance and
|
|
9
9
|
* detached DOM nodes in a reactive proxy is an active hazard.
|
|
10
10
|
* - `shell` (here) holds UI **inputs** — which panel each dock shows, whether each dock is open and
|
|
11
|
-
* how wide, the focused region, the
|
|
12
|
-
*
|
|
11
|
+
* how wide, the focused region, the workspace, and the project-level state (source control, the
|
|
12
|
+
* stylebook selection, the settings tab) that a _document_ must not own.
|
|
13
13
|
*
|
|
14
14
|
* Because this record is reactive, a surface tracks it by reading it: the rail, the left panel and
|
|
15
15
|
* the toolbar all repaint from the effects they already run. The stand-in that preceded this —
|
|
@@ -22,7 +22,7 @@
|
|
|
22
22
|
*/
|
|
23
23
|
|
|
24
24
|
import { isBoolean, isJsonObject, isNumber, isString } from "@jxsuite/schema/guards";
|
|
25
|
-
import { effect, effectScope, reactive } from "./reactivity";
|
|
25
|
+
import { effect, effectScope, pauseTracking, reactive, resetTracking } from "./reactivity";
|
|
26
26
|
import { SETTINGS } from "./services/settings/definitions";
|
|
27
27
|
import { readStoredSetting, setSetting } from "./services/settings/kernel";
|
|
28
28
|
import { loadedMonaco } from "./services/monaco-lazy";
|
|
@@ -36,14 +36,22 @@ import {
|
|
|
36
36
|
booleanProperty,
|
|
37
37
|
enumArg,
|
|
38
38
|
enumProperty,
|
|
39
|
-
stringArg,
|
|
40
|
-
stringProperty,
|
|
41
39
|
} from "./commands/command-args";
|
|
42
40
|
import type { EffectScope } from "@vue/reactivity";
|
|
43
41
|
import type { JsonObject, JsonValue } from "@jxsuite/schema/types";
|
|
44
42
|
import type { LayoutHit } from "./canvas/iframe-protocol";
|
|
45
43
|
import type { GitBranchesResult, GitDiffState, GitLogEntry, GitStatusResult } from "./types";
|
|
46
44
|
import type { AnyCommand, CommandRegistry } from "./commands/registry";
|
|
45
|
+
import {
|
|
46
|
+
DEFAULT_WORKSPACE,
|
|
47
|
+
isWorkspaceId,
|
|
48
|
+
WORKSPACE_IDS,
|
|
49
|
+
WORKSPACES,
|
|
50
|
+
} from "./workspace/workspace-ids";
|
|
51
|
+
import type { WorkspaceId } from "./workspace/workspace-ids";
|
|
52
|
+
import { DEFAULT_PUBLISH_DESTINATION, DEFAULT_PUBLISH_TAB } from "./publish/publish-ids";
|
|
53
|
+
import type { PublishDestination, PublishTab } from "./publish/publish-ids";
|
|
54
|
+
import type { PagesDeploymentInfo } from "./publish/pages-service";
|
|
47
55
|
|
|
48
56
|
/**
|
|
49
57
|
* The three resizable docks around the pane grid: two flanking it, one under it.
|
|
@@ -54,7 +62,7 @@ import type { AnyCommand, CommandRegistry } from "./commands/registry";
|
|
|
54
62
|
* {@link INSPECTOR_TAB_IDS}, the same mechanism that selects Content, Style and Logic.
|
|
55
63
|
*
|
|
56
64
|
* `"bottom"` is the one the Bottom dock (§16.3) added. It is a dock like the other two — a collapse
|
|
57
|
-
* flag, a remembered size, a resize handle, a place in every
|
|
65
|
+
* flag, a remembered size, a resize handle, a place in every workspace's frame — and the reason
|
|
58
66
|
* `view.toggleBottomDock` had no idempotent setter for two phases is that it was not on this
|
|
59
67
|
* record. It sits under the PANE GRID rather than under the window (§16.3), so opening it never
|
|
60
68
|
* narrows the Navigator or the Inspector.
|
|
@@ -88,12 +96,13 @@ export type DockId = "left" | "right" | "bottom";
|
|
|
88
96
|
* `tests/panel-registry.test.ts` asserts the two agree, so the duplicate cannot drift.
|
|
89
97
|
*/
|
|
90
98
|
export const NAVIGATOR_PANEL_IDS = [
|
|
99
|
+
"site",
|
|
100
|
+
"collections",
|
|
101
|
+
"styles",
|
|
91
102
|
"files",
|
|
92
103
|
"search",
|
|
93
|
-
"git",
|
|
94
104
|
"i18n",
|
|
95
105
|
"layers",
|
|
96
|
-
"page",
|
|
97
106
|
"data",
|
|
98
107
|
"packages",
|
|
99
108
|
"insert",
|
|
@@ -101,6 +110,32 @@ export const NAVIGATOR_PANEL_IDS = [
|
|
|
101
110
|
|
|
102
111
|
export type NavigatorPanelId = (typeof NAVIGATOR_PANEL_IDS)[number];
|
|
103
112
|
|
|
113
|
+
/**
|
|
114
|
+
* The Navigator panels that exist only as one workspace's preset panel: no rail button, and no
|
|
115
|
+
* frame but that workspace's draws them. Collections is the Content workspace's Navigator (§22.5),
|
|
116
|
+
* and Styles the Styles workspace's (§7.1).
|
|
117
|
+
*
|
|
118
|
+
* The dock record is the WINDOW's, so `leftTab` is persisted whatever workspace wrote it; a window
|
|
119
|
+
* closed in Content stores `collections`. Every workspace's own frame replaces it on entry, but a
|
|
120
|
+
* window with no project open applies no workspace frame, and drew "Collections · project" over a
|
|
121
|
+
* rail that has no Collections button. {@link navigatorPanelOutsideWorkspace} is the guard both of
|
|
122
|
+
* those moments go through. `tests/panel-registry.test.ts` asserts this set is exactly the
|
|
123
|
+
* rail-less panels a preset pins, so it cannot drift from the records.
|
|
124
|
+
*/
|
|
125
|
+
export const WORKSPACE_ONLY_PANELS: ReadonlySet<NavigatorPanelId> = new Set([
|
|
126
|
+
"collections",
|
|
127
|
+
"styles",
|
|
128
|
+
]);
|
|
129
|
+
|
|
130
|
+
/**
|
|
131
|
+
* The Navigator panel to show when no workspace frame chooses one (boot, and no project open): the
|
|
132
|
+
* stored panel, unless it is {@link WORKSPACE_ONLY_PANELS workspace-only}, in which case the
|
|
133
|
+
* default workspace's own first panel.
|
|
134
|
+
*/
|
|
135
|
+
export function navigatorPanelOutsideWorkspace(stored: NavigatorPanelId | null): NavigatorPanelId {
|
|
136
|
+
return stored && !WORKSPACE_ONLY_PANELS.has(stored) ? stored : DEFAULT_PANEL_ID;
|
|
137
|
+
}
|
|
138
|
+
|
|
104
139
|
/**
|
|
105
140
|
* Panel ids a previous build persisted, and what they are called now.
|
|
106
141
|
*
|
|
@@ -111,8 +146,16 @@ export type NavigatorPanelId = (typeof NAVIGATOR_PANEL_IDS)[number];
|
|
|
111
146
|
*/
|
|
112
147
|
const RENAMED_PANEL_IDS = new Map<string, NavigatorPanelId>([
|
|
113
148
|
["blocks", "insert"],
|
|
114
|
-
|
|
149
|
+
/* Not a rename either — a MOVE. The Page panel is the Inspector's first tab now (§6), so the
|
|
150
|
+
Navigator has no panel of that name; a stored `page` (or the `head` it was before that) reopens
|
|
151
|
+
the Navigator on the Site panel, the Design workspace's own default, rather than on nothing. */
|
|
152
|
+
["head", "site"],
|
|
153
|
+
["page", "site"],
|
|
115
154
|
["imports", "packages"],
|
|
155
|
+
/* A move out of the Navigator altogether: Source Control is the Publish workspace's Review
|
|
156
|
+
changes and Branches now (§5.5, §22.8), so the Navigator has no panel of that name. A stored
|
|
157
|
+
`git` reopens on the Site panel, the Design workspace's own default, rather than on nothing. */
|
|
158
|
+
["git", "site"],
|
|
116
159
|
/* Not a rename — a MERGE. The State editor is part of the Data panel now (§5.6), so a
|
|
117
160
|
stored `leftTab: "state"` names a real place and lands on it, rather than returning `null` and
|
|
118
161
|
booting into the default the way `problems` does. Defining a value and watching it resolve are
|
|
@@ -120,21 +163,19 @@ const RENAMED_PANEL_IDS = new Map<string, NavigatorPanelId>([
|
|
|
120
163
|
["state", "data"],
|
|
121
164
|
]);
|
|
122
165
|
|
|
123
|
-
/**
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
export
|
|
128
|
-
return typeof value === "string" && NAVIGATOR_PANEL_IDS.some((id) => id === value);
|
|
129
|
-
}
|
|
166
|
+
/**
|
|
167
|
+
* The panel the Navigator wakes up on when nothing usable is stored: the Site panel, the project by
|
|
168
|
+
* route (§5.7), because a fresh project is opened to find a page rather than to edit one.
|
|
169
|
+
*/
|
|
170
|
+
export const DEFAULT_PANEL_ID: NavigatorPanelId = "site";
|
|
130
171
|
|
|
131
172
|
/**
|
|
132
173
|
* Narrow an id arriving from a `string`-typed roster, or throw naming where it came from.
|
|
133
174
|
*
|
|
134
|
-
* The lock on the door {@link NAVIGATOR_PANEL_IDS} describes, in one place so the rail and the
|
|
135
|
-
* dispatcher cannot disagree about what an undeclared id means. Both receive their
|
|
136
|
-
* `PanelRecord.id`, which is deliberately a `string` — the registry hosts the Bottom dock's
|
|
137
|
-
* too, and their ids are {@link BOTTOM_TAB_IDS}.
|
|
175
|
+
* The lock on the door {@link NAVIGATOR_PANEL_IDS} describes, in one place so the rail and the
|
|
176
|
+
* `panel.focus.*` dispatcher cannot disagree about what an undeclared id means. Both receive their
|
|
177
|
+
* id from `PanelRecord.id`, which is deliberately a `string` — the registry hosts the Bottom dock's
|
|
178
|
+
* panels too, and their ids are {@link BOTTOM_TAB_IDS}.
|
|
138
179
|
*
|
|
139
180
|
* It throws rather than returning null because `tests/panel-registry.test.ts` asserts the enum and
|
|
140
181
|
* the registry agree, so a failure here means the two have drifted — and the symptom of the last
|
|
@@ -174,24 +215,40 @@ export function migratePanelId(stored: JsonValue | undefined): NavigatorPanelId
|
|
|
174
215
|
}
|
|
175
216
|
|
|
176
217
|
/**
|
|
177
|
-
* The Inspector's
|
|
178
|
-
*
|
|
179
|
-
*
|
|
180
|
-
*
|
|
181
|
-
*
|
|
182
|
-
*
|
|
183
|
-
*
|
|
184
|
-
*
|
|
185
|
-
*
|
|
186
|
-
* DOM, so the CI checks can load it); `tests/right-panel.test.ts`
|
|
187
|
-
* way `tests/panel-registry.test.ts` does for the rail.
|
|
218
|
+
* The Inspector's LEAF ids, in strip order — every view the dock can show, and the values
|
|
219
|
+
* `view.setRightTab` accepts (§6).
|
|
220
|
+
*
|
|
221
|
+
* The strip draws three tabs, **Page · Element · Assistant**, and five leaves sit under them:
|
|
222
|
+
* `page`, then Element's three views (`properties` = Content, `style` = Style, `events` = Logic)
|
|
223
|
+
* behind a sub-switch, then `assistant`. The leaves stay addressable one by one because they are
|
|
224
|
+
* what scripts, chords and shots name — `view.setRightTab { tab: "style" }` shows Element with
|
|
225
|
+
* Style chosen — and a strip of three that addressed only itself would make Style unreachable by
|
|
226
|
+
* name. `commands/defaults.ts`'s `INSPECTOR_TABS` carries the titles and the strip grouping (a
|
|
227
|
+
* module with no state and no DOM, so the CI checks can load it); `tests/right-panel.test.ts`
|
|
228
|
+
* asserts the two agree, the same way `tests/panel-registry.test.ts` does for the rail.
|
|
188
229
|
*/
|
|
189
|
-
export const INSPECTOR_TAB_IDS = ["properties", "style", "events", "assistant"] as const;
|
|
230
|
+
export const INSPECTOR_TAB_IDS = ["page", "properties", "style", "events", "assistant"] as const;
|
|
190
231
|
|
|
191
232
|
export type InspectorTabId = (typeof INSPECTOR_TAB_IDS)[number];
|
|
192
233
|
|
|
193
|
-
/**
|
|
194
|
-
|
|
234
|
+
/**
|
|
235
|
+
* The leaf the Inspector falls back to — Page, the strip's first tab, which is what the dock shows
|
|
236
|
+
* when nothing is selected (§6: an undeclared stored id coerces to Page).
|
|
237
|
+
*/
|
|
238
|
+
export const DEFAULT_INSPECTOR_TAB: InspectorTabId = "page";
|
|
239
|
+
|
|
240
|
+
/** The Element tab's three leaves, in sub-switch order. */
|
|
241
|
+
export const ELEMENT_TAB_IDS = ["properties", "style", "events"] as const;
|
|
242
|
+
|
|
243
|
+
export type ElementTabId = (typeof ELEMENT_TAB_IDS)[number];
|
|
244
|
+
|
|
245
|
+
/** The Element leaf the strip lands on when the selection first arrives and none was used yet. */
|
|
246
|
+
export const DEFAULT_ELEMENT_TAB: ElementTabId = "properties";
|
|
247
|
+
|
|
248
|
+
/** Whether a leaf is one of the Element tab's three views. */
|
|
249
|
+
export function isElementTabId(value: unknown): value is ElementTabId {
|
|
250
|
+
return typeof value === "string" && ELEMENT_TAB_IDS.some((id) => id === value);
|
|
251
|
+
}
|
|
195
252
|
|
|
196
253
|
/** Whether a string is a declared Inspector tab id. */
|
|
197
254
|
export function isInspectorTabId(value: unknown): value is InspectorTabId {
|
|
@@ -268,57 +325,149 @@ export interface ShellGit {
|
|
|
268
325
|
*/
|
|
269
326
|
rev: number;
|
|
270
327
|
logEntries: GitLogEntry[] | null;
|
|
271
|
-
/** "changes" | "history" — the panel's sub-tab. */
|
|
272
|
-
subTab: string;
|
|
273
328
|
/** Epoch ms of the last successful refresh, or null when never refreshed. */
|
|
274
329
|
lastUpdated: number | null;
|
|
275
330
|
}
|
|
276
331
|
|
|
332
|
+
/**
|
|
333
|
+
* What the Publish workspace is showing (studio.md §22.8): which sub-tab, and which destination its
|
|
334
|
+
* Review changes and the quick publish dialog offer. Project level, like the repository both
|
|
335
|
+
* describe, and reset with it, so the next project opens on Review changes rather than on the last
|
|
336
|
+
* project's Branches.
|
|
337
|
+
*/
|
|
338
|
+
export interface ShellPublish {
|
|
339
|
+
tab: PublishTab;
|
|
340
|
+
destination: PublishDestination;
|
|
341
|
+
/** What the host said about the connected project's deployments, and for which Pages project. */
|
|
342
|
+
deploys: {
|
|
343
|
+
state: "idle" | "loading" | "loaded" | "failed";
|
|
344
|
+
rows: PagesDeploymentInfo[];
|
|
345
|
+
error: string;
|
|
346
|
+
project: string;
|
|
347
|
+
};
|
|
348
|
+
/** The last build check, and the change set it was run against (`publish/publish-changes.ts`). */
|
|
349
|
+
build: { state: "idle" | "running" | "passed" | "failed"; text: string; for: string };
|
|
350
|
+
/** The pull request Send for review last opened; `number` 0 for none. */
|
|
351
|
+
review: { number: number; url: string };
|
|
352
|
+
}
|
|
353
|
+
|
|
277
354
|
/** The stylebook catalogue's selection and filters — project level, like the styles they edit. */
|
|
278
355
|
export interface ShellStylebook {
|
|
279
356
|
selection: string | null;
|
|
280
|
-
/**
|
|
281
|
-
|
|
357
|
+
/**
|
|
358
|
+
* The custom property the Variables view is pointed at (`--accent`), chosen from the Outline's
|
|
359
|
+
* variable rows, or `null`. Which LIST the Outline draws is not stored here: it follows the view
|
|
360
|
+
* the pane is in (Elements or Variables), so the two can never disagree.
|
|
361
|
+
*/
|
|
362
|
+
variable: string | null;
|
|
363
|
+
/**
|
|
364
|
+
* The view the Styles workspace's home is in: Variables (`tokens`, the first visit's view, which
|
|
365
|
+
* is the most common reason to come here) or Elements (`stylebook`). Written whenever
|
|
366
|
+
* `project.json` is shown in one of the two, so the next visit, and Back from Code, return to the
|
|
367
|
+
* view the author was last in. Code is never the home: it is a view opened beside it.
|
|
368
|
+
*/
|
|
369
|
+
view: "stylebook" | "tokens";
|
|
282
370
|
filter: string;
|
|
283
371
|
customizedOnly: boolean;
|
|
284
372
|
}
|
|
285
373
|
|
|
286
374
|
/**
|
|
287
|
-
*
|
|
288
|
-
*
|
|
289
|
-
* A
|
|
290
|
-
*
|
|
291
|
-
*
|
|
292
|
-
*
|
|
293
|
-
*
|
|
294
|
-
*
|
|
295
|
-
*
|
|
296
|
-
*
|
|
297
|
-
*
|
|
298
|
-
*
|
|
299
|
-
* writers.
|
|
300
|
-
*
|
|
301
|
-
* **Editor kind is deliberately not in the tuple.** The shell redesign's layout tuple named it, but
|
|
302
|
-
* nothing in the shell can apply it: switching a pane's editor is `studio.ts`'s `setCanvasMode`,
|
|
303
|
-
* which this module does not have and cannot be handed without changing a bootstrap it does not
|
|
304
|
-
* own. A fourth field no writer could honour would recreate the defect this type exists to close,
|
|
305
|
-
* so the tuple is three fields and the fourth arrives with the pane record that can carry it.
|
|
375
|
+
* What a workspace does to the frame when it is entered (`docs/studio/interface.md`, "Workspaces").
|
|
376
|
+
*
|
|
377
|
+
* A preset is applied on EVERY entry and is not a lock (`specs/studio.md` §22.3). Entering a
|
|
378
|
+
* workspace draws the rail only where the rail has something to offer (Design), and opens or
|
|
379
|
+
* collapses the Navigator and the Inspector for the work the workspace is for; the dock toggles
|
|
380
|
+
* keep working inside it, and the next entry applies the preset again. The one thing carried from
|
|
381
|
+
* visit to visit is which Navigator panel a workspace that names none was showing, so Design comes
|
|
382
|
+
* back on the panel it was left on rather than on Styles' Outline.
|
|
383
|
+
*
|
|
384
|
+
* It replaces the four named layouts (Write · Design · Build · Ship) that preceded it. A layout was
|
|
385
|
+
* a tuple of panels with no job attached; a workspace owns its tabs, so switching to one changes
|
|
386
|
+
* WHAT is on screen, not only where the docks are.
|
|
306
387
|
*/
|
|
307
|
-
export interface
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
388
|
+
export interface WorkspacePreset {
|
|
389
|
+
id: WorkspaceId;
|
|
390
|
+
/** Whether the rail column is drawn at all. It has no toggle of its own, so this is a class. */
|
|
391
|
+
rail: boolean;
|
|
392
|
+
/**
|
|
393
|
+
* The Navigator on entry: open or collapsed, and on which panel. `panel` is applied on EVERY
|
|
394
|
+
* entry; `initial` is the panel a workspace that remembers its own opens on when it has nothing
|
|
395
|
+
* to remember yet — Design's Site panel (§22.3: "the Site panel, or the last Design panel").
|
|
396
|
+
*/
|
|
397
|
+
navigator: { open: boolean; panel?: NavigatorPanelId; initial?: NavigatorPanelId };
|
|
398
|
+
/**
|
|
399
|
+
* The Inspector: open or collapsed on entry, and the tab it selects when one is named. The tab is
|
|
400
|
+
* per-document state, so naming it costs no other document anything.
|
|
401
|
+
*
|
|
402
|
+
* `whileWriting` draws it over a collapsed `open` while the active tab is a document written on
|
|
403
|
+
* the canvas ({@link WorkspaceDeps.writingOnCanvas}): Content's entries are edited on the canvas,
|
|
404
|
+
* where element selection and the Inspector apply, and its Library and forms are not; Styles'
|
|
405
|
+
* Elements view selects element defaults on its canvas, and its Variables and Code views do not.
|
|
406
|
+
*/
|
|
407
|
+
inspector: { open: boolean; tab?: InspectorTabId; whileWriting?: boolean };
|
|
408
|
+
/**
|
|
409
|
+
* Whether each pane draws its document tab strip. Design and Content do: they are where several
|
|
410
|
+
* documents are open at once. Media, Styles and Publish draw their home surface alone, and what
|
|
411
|
+
* they open beside it (a media file, a comparison, `project.json` as Code) is left through the
|
|
412
|
+
* pane context bar's Back control (`workspace/workspace-back.ts`), so no strip is needed to get
|
|
413
|
+
* back. Projected as {@link TAB_STRIP_HIDDEN_CLASS} on `#app`.
|
|
414
|
+
*/
|
|
415
|
+
tabStrip: boolean;
|
|
320
416
|
}
|
|
321
417
|
|
|
418
|
+
/**
|
|
419
|
+
* The five presets.
|
|
420
|
+
*
|
|
421
|
+
* - **Design** draws the rail and both side docks: the canvas, its outline and its inspector.
|
|
422
|
+
* - **Content** opens the Navigator on the Collections panel and collapses the Inspector, drawing it
|
|
423
|
+
* while an entry is being written on the canvas.
|
|
424
|
+
* - **Media** and **Publish** collapse both side docks: each one's home is a surface that lays itself
|
|
425
|
+
* out (the media grid, the change list).
|
|
426
|
+
* - **Styles** opens the Navigator on the Styles panel (variables, element defaults and color
|
|
427
|
+
* schemes), and the Inspector on its Style tab only while the Elements view is on screen: that
|
|
428
|
+
* view selects an element default on a canvas, and the Inspector is where it is styled. Variables
|
|
429
|
+
* is edited in the view itself, and Code has no canvas, so both leave the pane its width.
|
|
430
|
+
*
|
|
431
|
+
* Only Design and Content draw a tab strip; the other three draw their home surface alone.
|
|
432
|
+
*/
|
|
433
|
+
export const WORKSPACE_PRESETS: Readonly<Record<WorkspaceId, WorkspacePreset>> = {
|
|
434
|
+
content: {
|
|
435
|
+
id: "content",
|
|
436
|
+
inspector: { open: false, whileWriting: true },
|
|
437
|
+
navigator: { open: true, panel: "collections" },
|
|
438
|
+
rail: false,
|
|
439
|
+
tabStrip: true,
|
|
440
|
+
},
|
|
441
|
+
design: {
|
|
442
|
+
id: "design",
|
|
443
|
+
inspector: { open: true },
|
|
444
|
+
navigator: { initial: "site", open: true },
|
|
445
|
+
rail: true,
|
|
446
|
+
tabStrip: true,
|
|
447
|
+
},
|
|
448
|
+
media: {
|
|
449
|
+
id: "media",
|
|
450
|
+
inspector: { open: false },
|
|
451
|
+
navigator: { open: false },
|
|
452
|
+
rail: false,
|
|
453
|
+
tabStrip: false,
|
|
454
|
+
},
|
|
455
|
+
publish: {
|
|
456
|
+
id: "publish",
|
|
457
|
+
inspector: { open: false },
|
|
458
|
+
navigator: { open: false },
|
|
459
|
+
rail: false,
|
|
460
|
+
tabStrip: false,
|
|
461
|
+
},
|
|
462
|
+
styles: {
|
|
463
|
+
id: "styles",
|
|
464
|
+
inspector: { open: false, tab: "style", whileWriting: true },
|
|
465
|
+
navigator: { open: true, panel: "styles" },
|
|
466
|
+
rail: false,
|
|
467
|
+
tabStrip: false,
|
|
468
|
+
},
|
|
469
|
+
};
|
|
470
|
+
|
|
322
471
|
export interface ShellState {
|
|
323
472
|
/** Which panel the Navigator dock shows. One of {@link NAVIGATOR_PANEL_IDS}. */
|
|
324
473
|
leftTab: string;
|
|
@@ -342,10 +491,11 @@ export interface ShellState {
|
|
|
342
491
|
*/
|
|
343
492
|
paneSplit: number;
|
|
344
493
|
focusRegion: FocusRegion;
|
|
345
|
-
/**
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
494
|
+
/**
|
|
495
|
+
* The workspace on screen — the top bar's selected tab, and the filter every pane's tab strip
|
|
496
|
+
* applies. Written by {@link enterWorkspace} alone. Persisted per project root.
|
|
497
|
+
*/
|
|
498
|
+
workspace: WorkspaceId;
|
|
349
499
|
/**
|
|
350
500
|
* Layout chrome the author clicked, or `null`: a header, a footer, anything contributed by the
|
|
351
501
|
* layout file. It is deliberately NOT a document selection: the node is not in the open page at
|
|
@@ -353,10 +503,9 @@ export interface ShellState {
|
|
|
353
503
|
* the element inspector. See {@link setLayoutSelection}.
|
|
354
504
|
*/
|
|
355
505
|
layoutSelection: LayoutHit | null;
|
|
356
|
-
/** Which section Project Settings opens on. */
|
|
357
|
-
settingsTab: string;
|
|
358
506
|
stylebook: ShellStylebook;
|
|
359
507
|
git: ShellGit;
|
|
508
|
+
publish: ShellPublish;
|
|
360
509
|
}
|
|
361
510
|
|
|
362
511
|
export const DOCK_STORAGE_KEY = "jx-studio-panel-widths";
|
|
@@ -364,9 +513,8 @@ export const DOCK_STORAGE_KEY = "jx-studio-panel-widths";
|
|
|
364
513
|
/**
|
|
365
514
|
* The per-project record's key prefix — one namespaced record per project root (§14.8).
|
|
366
515
|
*
|
|
367
|
-
* Namespaced because a
|
|
368
|
-
*
|
|
369
|
-
* key means opening the second silently rewrites the first.
|
|
516
|
+
* Namespaced because a workspace and its session are THIS project's: two projects sharing a key
|
|
517
|
+
* means opening the second silently rewrites the first.
|
|
370
518
|
*
|
|
371
519
|
* Dock geometry stays in {@link DOCK_STORAGE_KEY}, which is read at module scope, before any
|
|
372
520
|
* project root exists. It is workspace state — `resetProjectShell()` has always kept it across a
|
|
@@ -527,93 +675,31 @@ function freshGit(): ShellGit {
|
|
|
527
675
|
logEntries: null,
|
|
528
676
|
rev: 0,
|
|
529
677
|
status: null,
|
|
530
|
-
subTab: "changes",
|
|
531
678
|
};
|
|
532
679
|
}
|
|
533
680
|
|
|
534
|
-
function
|
|
535
|
-
return {
|
|
681
|
+
function freshPublish(): ShellPublish {
|
|
682
|
+
return {
|
|
683
|
+
build: { for: "", state: "idle", text: "" },
|
|
684
|
+
deploys: { error: "", project: "", rows: [], state: "idle" },
|
|
685
|
+
destination: DEFAULT_PUBLISH_DESTINATION,
|
|
686
|
+
review: { number: 0, url: "" },
|
|
687
|
+
tab: DEFAULT_PUBLISH_TAB,
|
|
688
|
+
};
|
|
536
689
|
}
|
|
537
690
|
|
|
538
|
-
/**
|
|
539
|
-
|
|
540
|
-
*
|
|
541
|
-
* Each is a real arrangement of surfaces that already exist, not a mode: Write puts the file set
|
|
542
|
-
* beside the prose and the Inspector on Content; Design opens the Outline against the Style tab;
|
|
543
|
-
* Build pairs Data with Logic; Ship opens Source Control and gives the whole width to the diff by
|
|
544
|
-
* collapsing the Inspector — which stays one ⌘B away, because a layout never removes.
|
|
545
|
-
*
|
|
546
|
-
* Written as a factory so every project gets its own objects: they are mutable records (a saved
|
|
547
|
-
* layout overwrites the one with its name) and a shared array literal would leak one project's
|
|
548
|
-
* edits into the next.
|
|
549
|
-
*/
|
|
550
|
-
function builtInLayouts(): LayoutPreset[] {
|
|
551
|
-
return [
|
|
552
|
-
{
|
|
553
|
-
bottomTab: "problems",
|
|
554
|
-
docks: {
|
|
555
|
-
bottom: { collapsed: true, size: 220 },
|
|
556
|
-
left: { collapsed: false, size: 240 },
|
|
557
|
-
/* WRITE COLLAPSES THE INSPECTOR. The shell redesign's layout arithmetic is the whole point
|
|
558
|
-
of this preset: 1600px − 56 rail − 240 navigator ≈ **1284px of page, 80%**, against
|
|
559
|
-
Design's 974. It shipped with the Inspector open at 280px, which is Design's number and
|
|
560
|
-
makes Write a Design with a different panel selected.
|
|
561
|
-
|
|
562
|
-
It does NOT re-open on selection. The shell redesign's sentence read "until something is
|
|
563
|
-
selected", and clicking a paragraph to put a caret in it IS a selection — a dock that
|
|
564
|
-
opened every time you clicked into prose would take the 80% back on the first keystroke.
|
|
565
|
-
`⌘⇧1`–`⌘⇧4` expand it (`focusInspectorTab` sets `collapsed: false` before it focuses), so
|
|
566
|
-
the Inspector is one chord away whenever it is wanted. */
|
|
567
|
-
right: { collapsed: true, size: 280 },
|
|
568
|
-
},
|
|
569
|
-
id: "write",
|
|
570
|
-
inspectorTab: "properties",
|
|
571
|
-
name: "Write",
|
|
572
|
-
navigatorPanel: "files",
|
|
573
|
-
},
|
|
574
|
-
{
|
|
575
|
-
bottomTab: "problems",
|
|
576
|
-
docks: {
|
|
577
|
-
bottom: { collapsed: true, size: 220 },
|
|
578
|
-
left: { collapsed: false, size: 240 },
|
|
579
|
-
right: { collapsed: false, size: 320 },
|
|
580
|
-
},
|
|
581
|
-
id: "design",
|
|
582
|
-
inspectorTab: "style",
|
|
583
|
-
name: "Design",
|
|
584
|
-
navigatorPanel: "layers",
|
|
585
|
-
},
|
|
586
|
-
{
|
|
587
|
-
bottomTab: "logic",
|
|
588
|
-
docks: {
|
|
589
|
-
bottom: { collapsed: true, size: 260 },
|
|
590
|
-
left: { collapsed: false, size: 280 },
|
|
591
|
-
right: { collapsed: false, size: 300 },
|
|
592
|
-
},
|
|
593
|
-
id: "build",
|
|
594
|
-
inspectorTab: "events",
|
|
595
|
-
name: "Build",
|
|
596
|
-
navigatorPanel: "data",
|
|
597
|
-
},
|
|
598
|
-
{
|
|
599
|
-
// The one built-in that OPENS the Bottom dock, on Activity: shipping is a long operation
|
|
600
|
-
// With a log, which is exactly what that tab is (§16.4 — Deploy folds into Activity).
|
|
601
|
-
bottomTab: "activity",
|
|
602
|
-
docks: {
|
|
603
|
-
bottom: { collapsed: false, size: 240 },
|
|
604
|
-
left: { collapsed: false, size: 300 },
|
|
605
|
-
right: { collapsed: true, size: 280 },
|
|
606
|
-
},
|
|
607
|
-
id: "ship",
|
|
608
|
-
inspectorTab: "properties",
|
|
609
|
-
name: "Ship",
|
|
610
|
-
navigatorPanel: "git",
|
|
611
|
-
},
|
|
612
|
-
];
|
|
613
|
-
}
|
|
691
|
+
/** The view the Styles workspace opens on until the author picks another: Variables. */
|
|
692
|
+
export const DEFAULT_STYLES_HOME_VIEW: ShellStylebook["view"] = "tokens";
|
|
614
693
|
|
|
615
|
-
|
|
616
|
-
|
|
694
|
+
function freshStylebook(): ShellStylebook {
|
|
695
|
+
return {
|
|
696
|
+
customizedOnly: false,
|
|
697
|
+
filter: "",
|
|
698
|
+
selection: null,
|
|
699
|
+
variable: null,
|
|
700
|
+
view: DEFAULT_STYLES_HOME_VIEW,
|
|
701
|
+
};
|
|
702
|
+
}
|
|
617
703
|
|
|
618
704
|
/**
|
|
619
705
|
* Build the whole record — nested collections complete — before it is handed to `reactive()`.
|
|
@@ -640,13 +726,12 @@ function createShellState(): ShellState {
|
|
|
640
726
|
focusRegion: "pane",
|
|
641
727
|
paneSplit: clampPaneSplit(saved.paneSplit),
|
|
642
728
|
git: freshGit(),
|
|
643
|
-
|
|
729
|
+
publish: freshPublish(),
|
|
644
730
|
layoutSelection: null,
|
|
645
|
-
|
|
646
|
-
leftTab: migratePanelId(saved.leftTab) ?? DEFAULT_PANEL_ID,
|
|
647
|
-
settingsTab: "stylebook",
|
|
731
|
+
leftTab: navigatorPanelOutsideWorkspace(migratePanelId(saved.leftTab)),
|
|
648
732
|
stylebook: freshStylebook(),
|
|
649
733
|
theme: readPersistedTheme(),
|
|
734
|
+
workspace: DEFAULT_WORKSPACE,
|
|
650
735
|
};
|
|
651
736
|
}
|
|
652
737
|
|
|
@@ -660,6 +745,29 @@ function createShellState(): ShellState {
|
|
|
660
745
|
*/
|
|
661
746
|
applyStartupProfile();
|
|
662
747
|
|
|
748
|
+
/**
|
|
749
|
+
* Storage keys a retired surface used to write, removed on boot so a stale preference never
|
|
750
|
+
* outlives the control that set it.
|
|
751
|
+
*
|
|
752
|
+
* `jx-studio-doc-header-expanded` was the Document Header card's fold-to-bar preference. Edit draws
|
|
753
|
+
* no card any more (studio.md §4.2), so nothing reads the key and nothing should be left holding
|
|
754
|
+
* it.
|
|
755
|
+
*/
|
|
756
|
+
export const RETIRED_STORAGE_KEYS: readonly string[] = ["jx-studio-doc-header-expanded"];
|
|
757
|
+
|
|
758
|
+
/** Drop every {@link RETIRED_STORAGE_KEYS} entry, tolerating unavailable storage. Never throws. */
|
|
759
|
+
export function forgetRetiredStorage(): void {
|
|
760
|
+
try {
|
|
761
|
+
for (const key of RETIRED_STORAGE_KEYS) {
|
|
762
|
+
localStorage.removeItem(key);
|
|
763
|
+
}
|
|
764
|
+
} catch {
|
|
765
|
+
// Storage blocked or unavailable: there is nothing stored to forget.
|
|
766
|
+
}
|
|
767
|
+
}
|
|
768
|
+
|
|
769
|
+
forgetRetiredStorage();
|
|
770
|
+
|
|
663
771
|
/*
|
|
664
772
|
* SAFETY: `reactive()` returns a deep proxy carrying its target's own members, and ShellState holds
|
|
665
773
|
* no refs for `UnwrapNestedRefs` to unwrap, so the proxy IS a ShellState. The type argument is
|
|
@@ -697,12 +805,17 @@ export function persistDocks(): void {
|
|
|
697
805
|
}
|
|
698
806
|
}
|
|
699
807
|
|
|
700
|
-
// ───
|
|
808
|
+
// ─── The project's record: its workspace, and its session ────────────────────
|
|
701
809
|
|
|
702
|
-
/**
|
|
810
|
+
/**
|
|
811
|
+
* What a project's namespaced record holds: the workspace it was left in, and the session.
|
|
812
|
+
*
|
|
813
|
+
* A record written by a build that had named layouts also carries `layouts` and `activeLayout`.
|
|
814
|
+
* Neither is read, and the next write drops them: the layouts they name were replaced by the
|
|
815
|
+
* workspaces, and there is nothing in them a workspace could adopt.
|
|
816
|
+
*/
|
|
703
817
|
interface PersistedProject {
|
|
704
|
-
|
|
705
|
-
activeLayout?: string;
|
|
818
|
+
workspace?: WorkspaceId;
|
|
706
819
|
/**
|
|
707
820
|
* §14.8's session — open documents per pane, the active one, and each one's view settings. A
|
|
708
821
|
* session this boot has not read yet is carried over as the stored JSON it was.
|
|
@@ -710,31 +823,15 @@ interface PersistedProject {
|
|
|
710
823
|
session?: PersistedSession | JsonValue | undefined;
|
|
711
824
|
}
|
|
712
825
|
|
|
713
|
-
/** The project whose
|
|
714
|
-
let
|
|
826
|
+
/** The project whose workspace is loaded, or `undefined` before the first sync. */
|
|
827
|
+
let _workspaceRoot: string | null | undefined;
|
|
715
828
|
|
|
716
|
-
/**
|
|
717
|
-
|
|
718
|
-
|
|
719
|
-
|
|
720
|
-
|
|
721
|
-
|
|
722
|
-
}
|
|
723
|
-
const { docks } = value;
|
|
724
|
-
return (
|
|
725
|
-
isString(value.id) &&
|
|
726
|
-
value.id !== "" &&
|
|
727
|
-
isString(value.name) &&
|
|
728
|
-
isNavigatorPanelId(value.navigatorPanel) &&
|
|
729
|
-
isInspectorTabId(value.inspectorTab) &&
|
|
730
|
-
isBottomTabId(value.bottomTab) &&
|
|
731
|
-
isJsonObject(docks) &&
|
|
732
|
-
DOCK_IDS.every((dock) => {
|
|
733
|
-
const entry = docks[dock];
|
|
734
|
-
return isJsonObject(entry) && isNumber(entry.size);
|
|
735
|
-
})
|
|
736
|
-
);
|
|
737
|
-
}
|
|
829
|
+
/**
|
|
830
|
+
* The Navigator panel each workspace whose preset names none was last showing, in this window. Not
|
|
831
|
+
* persisted: it is a convenience between two visits, and the preset is the statement of what a
|
|
832
|
+
* workspace looks like on entry.
|
|
833
|
+
*/
|
|
834
|
+
let _panels: Partial<Record<WorkspaceId, string>> = {};
|
|
738
835
|
|
|
739
836
|
/** The raw record for `root`, or `{}` for absent, corrupt or hand-edited storage. */
|
|
740
837
|
function rawPersistedProject(root: string | null): JsonObject {
|
|
@@ -751,36 +848,26 @@ function rawPersistedProject(root: string | null): JsonObject {
|
|
|
751
848
|
}
|
|
752
849
|
}
|
|
753
850
|
|
|
754
|
-
/**
|
|
755
|
-
|
|
756
|
-
|
|
757
|
-
|
|
758
|
-
|
|
759
|
-
|
|
760
|
-
|
|
761
|
-
|
|
762
|
-
|
|
763
|
-
|
|
764
|
-
|
|
765
|
-
|
|
766
|
-
|
|
767
|
-
const layouts = Array.isArray(parsed.layouts)
|
|
768
|
-
? parsed.layouts.flatMap((entry) => (isLayoutPreset(entry) ? [entry] : []))
|
|
769
|
-
: [];
|
|
770
|
-
if (layouts.length === 0) {
|
|
771
|
-
return fresh;
|
|
772
|
-
}
|
|
773
|
-
return {
|
|
774
|
-
activeLayout: isString(parsed.activeLayout) ? parsed.activeLayout : null,
|
|
775
|
-
layouts,
|
|
776
|
-
};
|
|
851
|
+
/**
|
|
852
|
+
* The workspace `root` was last left in: a missing, stale or unknown id (a layout id from the build
|
|
853
|
+
* that had named layouts, a workspace a later build renamed, a hand edit) is
|
|
854
|
+
* {@link DEFAULT_WORKSPACE}. Never throws: a stale record must not be the reason a project cannot
|
|
855
|
+
* open.
|
|
856
|
+
*
|
|
857
|
+
* The open sequence asks for it again AFTER restoring the session (`files/files.ts`), because
|
|
858
|
+
* restoring activates tabs and activating a tab enters that tab's workspace: a project left in
|
|
859
|
+
* Media, whose home tab is not a document the session records, would otherwise reopen in Design.
|
|
860
|
+
*/
|
|
861
|
+
export function persistedWorkspace(root: string | null): WorkspaceId {
|
|
862
|
+
const stored = rawPersistedProject(root).workspace;
|
|
863
|
+
return isWorkspaceId(stored) ? stored : DEFAULT_WORKSPACE;
|
|
777
864
|
}
|
|
778
865
|
|
|
779
866
|
/**
|
|
780
867
|
* The session `root` was last left in, or `null` when there is none to restore.
|
|
781
868
|
*
|
|
782
|
-
* Separate from {@link
|
|
783
|
-
*
|
|
869
|
+
* Separate from {@link syncProjectWorkspace} because the two are read at different moments: the
|
|
870
|
+
* workspace loads reactively the instant the project root changes, and the session is read once, by
|
|
784
871
|
* the open sequence, at the point where it would otherwise open the home page.
|
|
785
872
|
*/
|
|
786
873
|
export function persistedSession(root: string | null): PersistedSession | null {
|
|
@@ -806,13 +893,6 @@ export function markSessionRestored(root: string | null): void {
|
|
|
806
893
|
_sessionRoot = root;
|
|
807
894
|
}
|
|
808
895
|
|
|
809
|
-
/**
|
|
810
|
-
* Write the project's namespaced record. One key, one writer, one shape.
|
|
811
|
-
*
|
|
812
|
-
* The dock record's two-writer bug (`persistWidths` vs `applyPanelCollapse`, both on
|
|
813
|
-
* {@link DOCK_STORAGE_KEY}) is the reason this is a single function that serialises the whole
|
|
814
|
-
* record rather than a merge at each call site.
|
|
815
|
-
*/
|
|
816
896
|
/**
|
|
817
897
|
* Write the session on the way out — the moment the whole feature exists for.
|
|
818
898
|
*
|
|
@@ -825,6 +905,13 @@ export function flushSession(): void {
|
|
|
825
905
|
persistProjectShell();
|
|
826
906
|
}
|
|
827
907
|
|
|
908
|
+
/**
|
|
909
|
+
* Write the project's namespaced record. One key, one writer, one shape.
|
|
910
|
+
*
|
|
911
|
+
* The dock record's two-writer bug (`persistWidths` vs `applyPanelCollapse`, both on
|
|
912
|
+
* {@link DOCK_STORAGE_KEY}) is the reason this is a single function that serialises the whole
|
|
913
|
+
* record rather than a merge at each call site.
|
|
914
|
+
*/
|
|
828
915
|
export function persistProjectShell(): void {
|
|
829
916
|
const root = workspace.projectRoot;
|
|
830
917
|
if (!root) {
|
|
@@ -834,10 +921,9 @@ export function persistProjectShell(): void {
|
|
|
834
921
|
localStorage.setItem(
|
|
835
922
|
`${PROJECT_STORAGE_PREFIX}${root}`,
|
|
836
923
|
JSON.stringify({
|
|
837
|
-
activeLayout: shell.layout,
|
|
838
|
-
layouts: shell.layouts,
|
|
839
924
|
// Only for a project whose session has been read — see {@link markSessionRestored}.
|
|
840
925
|
session: root === _sessionRoot ? captureSession() : rawPersistedProject(root).session,
|
|
926
|
+
workspace: shell.workspace,
|
|
841
927
|
} satisfies PersistedProject),
|
|
842
928
|
);
|
|
843
929
|
} catch {
|
|
@@ -846,147 +932,99 @@ export function persistProjectShell(): void {
|
|
|
846
932
|
}
|
|
847
933
|
|
|
848
934
|
/**
|
|
849
|
-
* Load the
|
|
935
|
+
* Load the workspace belonging to `root`. Idempotent per root, so the effect can call it freely.
|
|
936
|
+
*
|
|
937
|
+
* The id is read by {@link persistedWorkspace}, so a stale one opens the project in
|
|
938
|
+
* {@link DEFAULT_WORKSPACE} and loading never throws.
|
|
850
939
|
*
|
|
851
|
-
*
|
|
852
|
-
*
|
|
853
|
-
*
|
|
940
|
+
* Opening a project ENTERS its workspace, so the workspace's preset is applied here too. The dock
|
|
941
|
+
* record is the window's rather than the project's, and without this a project closed while Media
|
|
942
|
+
* had collapsed both side docks left the next project's Design frame collapsed. The rail follows
|
|
943
|
+
* `shell.workspace` on its own, through {@link applyDockLayout}. No preset is applied for `null`
|
|
944
|
+
* (no project open): there is no workspace on screen to lay out.
|
|
854
945
|
*/
|
|
855
|
-
export function
|
|
856
|
-
if (root ===
|
|
946
|
+
export function syncProjectWorkspace(root: string | null): void {
|
|
947
|
+
if (root === _workspaceRoot) {
|
|
857
948
|
return;
|
|
858
949
|
}
|
|
859
|
-
|
|
860
|
-
|
|
861
|
-
shell.
|
|
862
|
-
|
|
863
|
-
|
|
864
|
-
|
|
865
|
-
|
|
866
|
-
|
|
867
|
-
|
|
868
|
-
|
|
869
|
-
|
|
870
|
-
|
|
871
|
-
|
|
872
|
-
|
|
873
|
-
|
|
874
|
-
|
|
875
|
-
|
|
876
|
-
|
|
877
|
-
}
|
|
878
|
-
|
|
879
|
-
/** A stable id for a saved layout's name: `My Layout` → `my-layout`. */
|
|
880
|
-
export function layoutIdFor(name: string): string {
|
|
881
|
-
const slug = name
|
|
882
|
-
.trim()
|
|
883
|
-
.toLowerCase()
|
|
884
|
-
.replaceAll(/[^a-z0-9]+/g, "-")
|
|
885
|
-
.replaceAll(/^-|-$/g, "");
|
|
886
|
-
return slug || "layout";
|
|
950
|
+
_workspaceRoot = root;
|
|
951
|
+
_panels = {};
|
|
952
|
+
shell.workspace = persistedWorkspace(root);
|
|
953
|
+
if (root === null) {
|
|
954
|
+
/* No frame to apply, but the Navigator is still on screen beside the rail: a panel only the
|
|
955
|
+
closed project's workspace drew (Collections, left in Content) is not this window's to show. */
|
|
956
|
+
shell.leftTab = navigatorPanelOutsideWorkspace(migratePanelId(shell.leftTab));
|
|
957
|
+
return;
|
|
958
|
+
}
|
|
959
|
+
/* Untracked: this runs inside the shell's project-root effect, which must depend on the root
|
|
960
|
+
alone and not on the panel and docks the preset reads and writes. */
|
|
961
|
+
pauseTracking();
|
|
962
|
+
try {
|
|
963
|
+
applyFrame(shell.workspace);
|
|
964
|
+
persistDocks();
|
|
965
|
+
} finally {
|
|
966
|
+
resetTracking();
|
|
967
|
+
}
|
|
887
968
|
}
|
|
888
969
|
|
|
889
|
-
/** What
|
|
890
|
-
export interface
|
|
970
|
+
/** What entering a workspace needs from the Inspector, whose tab lives on the active document. */
|
|
971
|
+
export interface WorkspaceDeps {
|
|
891
972
|
setInspectorTab: (tab: InspectorTabId) => void;
|
|
892
|
-
|
|
973
|
+
/**
|
|
974
|
+
* Whether the active tab is a document being written on the canvas, which is what draws a
|
|
975
|
+
* `whileWriting` Inspector ({@link WorkspacePreset.inspector}). Injected by
|
|
976
|
+
* `workspace/workspace-switch.ts`, which owns the rule that reads a tab; absent, it is `false`.
|
|
977
|
+
*/
|
|
978
|
+
writingOnCanvas?: () => boolean;
|
|
893
979
|
}
|
|
894
980
|
|
|
895
|
-
/**
|
|
896
|
-
|
|
897
|
-
|
|
898
|
-
|
|
899
|
-
* own (their saved layouts) and a typo in a command argument has to be reportable.
|
|
900
|
-
*/
|
|
901
|
-
export function applyLayout(id: string, deps: LayoutDeps): void {
|
|
902
|
-
const preset = layoutById(id);
|
|
903
|
-
if (!preset) {
|
|
904
|
-
throw new RangeError(
|
|
905
|
-
`no layout named "${id}" — this project has: ${shell.layouts.map((p) => p.id).join(", ")}`,
|
|
906
|
-
);
|
|
907
|
-
}
|
|
908
|
-
shell.layout = preset.id;
|
|
909
|
-
shell.leftTab = preset.navigatorPanel;
|
|
910
|
-
shell.bottomTab = preset.bottomTab;
|
|
911
|
-
for (const dock of DOCK_IDS) {
|
|
912
|
-
shell.docks[dock].collapsed = preset.docks[dock].collapsed;
|
|
913
|
-
shell.docks[dock].size = preset.docks[dock].size;
|
|
914
|
-
}
|
|
915
|
-
deps.setInspectorTab(preset.inspectorTab);
|
|
916
|
-
persistDocks();
|
|
917
|
-
persistProjectShell();
|
|
981
|
+
/** Whether a workspace's preset draws its Inspector, given whether a document is being written. */
|
|
982
|
+
export function presetInspectorOpen(id: WorkspaceId, writing: boolean): boolean {
|
|
983
|
+
const { inspector } = WORKSPACE_PRESETS[id];
|
|
984
|
+
return inspector.open || (inspector.whileWriting === true && writing);
|
|
918
985
|
}
|
|
919
986
|
|
|
920
|
-
/**
|
|
921
|
-
|
|
922
|
-
|
|
923
|
-
|
|
924
|
-
|
|
925
|
-
|
|
926
|
-
|
|
927
|
-
|
|
928
|
-
const id = layoutIdFor(trimmed);
|
|
929
|
-
const docks = perDock((dock) => ({
|
|
930
|
-
collapsed: shell.docks[dock].collapsed,
|
|
931
|
-
size: shell.docks[dock].size,
|
|
932
|
-
}));
|
|
933
|
-
const preset: LayoutPreset = {
|
|
934
|
-
bottomTab: isBottomTabId(shell.bottomTab) ? shell.bottomTab : DEFAULT_BOTTOM_TAB,
|
|
935
|
-
docks,
|
|
936
|
-
id,
|
|
937
|
-
inspectorTab: deps.inspectorTab(),
|
|
938
|
-
name: trimmed || id,
|
|
939
|
-
navigatorPanel: migratePanelId(shell.leftTab) ?? DEFAULT_PANEL_ID,
|
|
940
|
-
};
|
|
941
|
-
const existing = shell.layouts.findIndex((entry) => entry.id === id);
|
|
942
|
-
if (existing === -1) {
|
|
943
|
-
shell.layouts.push(preset);
|
|
944
|
-
} else {
|
|
945
|
-
shell.layouts.splice(existing, 1, preset);
|
|
987
|
+
/** Lay a workspace's preset out: the Navigator's panel, both side docks and the Inspector's tab. */
|
|
988
|
+
function applyFrame(id: WorkspaceId, deps?: WorkspaceDeps): void {
|
|
989
|
+
const preset = WORKSPACE_PRESETS[id];
|
|
990
|
+
const panel = migratePanelId(
|
|
991
|
+
preset.navigator.panel ?? _panels[id] ?? preset.navigator.initial ?? shell.leftTab,
|
|
992
|
+
);
|
|
993
|
+
if (panel) {
|
|
994
|
+
shell.leftTab = panel;
|
|
946
995
|
}
|
|
947
|
-
shell.
|
|
948
|
-
|
|
949
|
-
|
|
950
|
-
|
|
951
|
-
|
|
952
|
-
/** Rename a layout in place. The id — and therefore every reference to it — is unchanged. */
|
|
953
|
-
export function renameLayout(id: string, name: string): void {
|
|
954
|
-
const preset = layoutById(id);
|
|
955
|
-
const trimmed = name.trim();
|
|
956
|
-
if (!preset || !trimmed) {
|
|
957
|
-
return;
|
|
996
|
+
shell.docks.left.collapsed = !preset.navigator.open;
|
|
997
|
+
shell.docks.right.collapsed = !presetInspectorOpen(id, deps?.writingOnCanvas?.() === true);
|
|
998
|
+
if (preset.inspector.tab && deps) {
|
|
999
|
+
deps.setInspectorTab(preset.inspector.tab);
|
|
958
1000
|
}
|
|
959
|
-
preset.name = trimmed;
|
|
960
|
-
persistProjectShell();
|
|
961
1001
|
}
|
|
962
1002
|
|
|
963
1003
|
/**
|
|
964
|
-
*
|
|
965
|
-
*
|
|
1004
|
+
* Enter a workspace: lay its frame out by its {@link WORKSPACE_PRESETS} preset, which every entry
|
|
1005
|
+
* applies afresh (`specs/studio.md` §22.3).
|
|
1006
|
+
*
|
|
1007
|
+
* This is the frame half of a switch and the one writer of `shell.workspace`. Which TAB is on
|
|
1008
|
+
* screen is the other half, and it is not this module's: `workspace/workspace-switch.ts` activates
|
|
1009
|
+
* the workspace's tab, and activating any tab enters that tab's workspace through here.
|
|
1010
|
+
*
|
|
1011
|
+
* Re-entering the workspace already showing changes nothing, so the verb is idempotent and a dock
|
|
1012
|
+
* the author just toggled is not put back.
|
|
1013
|
+
*
|
|
1014
|
+
* @returns Whether the workspace changed.
|
|
966
1015
|
*/
|
|
967
|
-
export function
|
|
968
|
-
if (shell.
|
|
969
|
-
return;
|
|
970
|
-
}
|
|
971
|
-
const index = shell.layouts.findIndex((preset) => preset.id === id);
|
|
972
|
-
if (index === -1) {
|
|
973
|
-
return;
|
|
1016
|
+
export function enterWorkspace(id: WorkspaceId, deps?: WorkspaceDeps): boolean {
|
|
1017
|
+
if (shell.workspace === id) {
|
|
1018
|
+
return false;
|
|
974
1019
|
}
|
|
975
|
-
shell.
|
|
976
|
-
|
|
977
|
-
shell.layout = shell.layouts[0]!.id;
|
|
1020
|
+
if (!WORKSPACE_PRESETS[shell.workspace].navigator.panel) {
|
|
1021
|
+
_panels[shell.workspace] = shell.leftTab;
|
|
978
1022
|
}
|
|
1023
|
+
shell.workspace = id;
|
|
1024
|
+
applyFrame(id, deps);
|
|
1025
|
+
persistDocks();
|
|
979
1026
|
persistProjectShell();
|
|
980
|
-
|
|
981
|
-
|
|
982
|
-
/**
|
|
983
|
-
* Re-apply the active layout as declared — `View: Reset Layout`, always one action away.
|
|
984
|
-
*
|
|
985
|
-
* This is the escape hatch that makes a layout safe to drift from: drag a dock, collapse the
|
|
986
|
-
* Inspector, open a different panel, and one command puts the arrangement back.
|
|
987
|
-
*/
|
|
988
|
-
export function resetLayout(deps: LayoutDeps): void {
|
|
989
|
-
applyLayout(shell.layout, deps);
|
|
1027
|
+
return true;
|
|
990
1028
|
}
|
|
991
1029
|
|
|
992
1030
|
/**
|
|
@@ -1029,7 +1067,28 @@ export function applyChromeTheme(): void {
|
|
|
1029
1067
|
loadedMonaco()?.editor.setTheme(monacoTheme());
|
|
1030
1068
|
}
|
|
1031
1069
|
|
|
1032
|
-
/**
|
|
1070
|
+
/**
|
|
1071
|
+
* The `#app` class that takes the rail column out of the grid. `styles/shell-frame.json` owns what
|
|
1072
|
+
* it means; the rail has no toggle and no size, so it is a class and never a dock.
|
|
1073
|
+
*/
|
|
1074
|
+
export const RAIL_HIDDEN_CLASS = "rail-hidden";
|
|
1075
|
+
|
|
1076
|
+
/**
|
|
1077
|
+
* The `#app` class that takes every pane's tab strip out of the grid, in a workspace whose preset
|
|
1078
|
+
* draws none ({@link WorkspacePreset.tabStrip}). `styles/shell-frame.json` owns what it means; the
|
|
1079
|
+
* strips stay mounted underneath, so returning to Design repaints nothing.
|
|
1080
|
+
*/
|
|
1081
|
+
export const TAB_STRIP_HIDDEN_CLASS = "tabs-hidden";
|
|
1082
|
+
|
|
1083
|
+
/** Whether the workspace on screen draws pane tab strips. */
|
|
1084
|
+
export function workspaceDrawsTabStrip(id: WorkspaceId = shell.workspace): boolean {
|
|
1085
|
+
return WORKSPACE_PRESETS[id].tabStrip;
|
|
1086
|
+
}
|
|
1087
|
+
|
|
1088
|
+
/**
|
|
1089
|
+
* Project the dock record onto the shell grid: collapse classes on #app, sizes as CSS vars, and the
|
|
1090
|
+
* active workspace's rail and tab strips.
|
|
1091
|
+
*/
|
|
1033
1092
|
export function applyDockLayout(): void {
|
|
1034
1093
|
const root = document.documentElement;
|
|
1035
1094
|
for (const id of DOCK_IDS) {
|
|
@@ -1042,6 +1101,8 @@ export function applyDockLayout(): void {
|
|
|
1042
1101
|
for (const id of DOCK_IDS) {
|
|
1043
1102
|
app.classList.toggle(DOCK_CLASS[id], shell.docks[id].collapsed);
|
|
1044
1103
|
}
|
|
1104
|
+
app.classList.toggle(RAIL_HIDDEN_CLASS, !WORKSPACE_PRESETS[shell.workspace].rail);
|
|
1105
|
+
app.classList.toggle(TAB_STRIP_HIDDEN_CLASS, !WORKSPACE_PRESETS[shell.workspace].tabStrip);
|
|
1045
1106
|
}
|
|
1046
1107
|
|
|
1047
1108
|
let _scope: EffectScope | null = null;
|
|
@@ -1109,11 +1170,11 @@ export function mountShell(): void {
|
|
|
1109
1170
|
effect(() => {
|
|
1110
1171
|
applyChromeTheme();
|
|
1111
1172
|
});
|
|
1112
|
-
//
|
|
1113
|
-
//
|
|
1114
|
-
//
|
|
1173
|
+
// The workspace belongs to a project, and the project root is reactive: opening one loads its
|
|
1174
|
+
// Record with no boot-order hook to forget. `resetProjectShell()` runs while the OLD root is
|
|
1175
|
+
// Still set — it is the closing half of a switch — which is why the load cannot live there.
|
|
1115
1176
|
effect(() => {
|
|
1116
|
-
|
|
1177
|
+
syncProjectWorkspace(workspace.projectRoot);
|
|
1117
1178
|
});
|
|
1118
1179
|
/*
|
|
1119
1180
|
* §14.8's session, written whenever its SHAPE changes.
|
|
@@ -1251,21 +1312,21 @@ export function setLayoutSelection(selection: LayoutHit | null): void {
|
|
|
1251
1312
|
*
|
|
1252
1313
|
* Source control, the stylebook selection and the settings tab all describe _a_ project; carrying
|
|
1253
1314
|
* them into the next one showed the previous repository's branch, file count and "last updated"
|
|
1254
|
-
* time under the new project's name. Docks
|
|
1255
|
-
*
|
|
1315
|
+
* time under the new project's name. Docks and the active rail panel are deliberately kept: they
|
|
1316
|
+
* describe the window, not the project. The workspace is the project's, and the next
|
|
1317
|
+
* {@link syncProjectWorkspace} reads it from that project's own record.
|
|
1256
1318
|
*/
|
|
1257
1319
|
export function resetProjectShell(): void {
|
|
1258
1320
|
Object.assign(shell.git, freshGit());
|
|
1321
|
+
Object.assign(shell.publish, freshPublish());
|
|
1259
1322
|
Object.assign(shell.stylebook, freshStylebook());
|
|
1260
|
-
shell.settingsTab = "stylebook";
|
|
1261
1323
|
shell.layoutSelection = null;
|
|
1262
1324
|
// …and which project's session may be written, so the one being opened cannot be overwritten
|
|
1263
1325
|
// Before it has been read.
|
|
1264
1326
|
_sessionRoot = null;
|
|
1265
|
-
// Forget which project's
|
|
1266
|
-
//
|
|
1267
|
-
|
|
1268
|
-
_layoutRoot = undefined;
|
|
1327
|
+
// Forget which project's workspace is loaded, so the next `syncProjectWorkspace()` reloads even
|
|
1328
|
+
// If the same root is opened again.
|
|
1329
|
+
_workspaceRoot = undefined;
|
|
1269
1330
|
}
|
|
1270
1331
|
|
|
1271
1332
|
// ─── Commands ─────────────────────────────────────────────────────────────────
|
|
@@ -1287,6 +1348,14 @@ export interface ShellCommandDeps {
|
|
|
1287
1348
|
* screenshot that closed the assistant would silently also lose your Style tab.
|
|
1288
1349
|
*/
|
|
1289
1350
|
inspectorTab: () => InspectorTabId;
|
|
1351
|
+
/**
|
|
1352
|
+
* The tab the strip rests on when nothing chose one: Page with nothing selected, otherwise the
|
|
1353
|
+
* Element leaf last used (`specs/studio.md` §6). `view.setAssistant { open: false }` steps onto
|
|
1354
|
+
* it, so closing the Assistant with a node selected shows that node rather than the document.
|
|
1355
|
+
* Injected because the selection and the remembered leaf are per-document session state; absent
|
|
1356
|
+
* (the CI projection), it is {@link DEFAULT_INSPECTOR_TAB}.
|
|
1357
|
+
*/
|
|
1358
|
+
restingInspectorTab?: () => InspectorTabId;
|
|
1290
1359
|
/**
|
|
1291
1360
|
* Whether a dock tab's panel record is currently available — its own `when` holding.
|
|
1292
1361
|
*
|
|
@@ -1300,6 +1369,24 @@ export interface ShellCommandDeps {
|
|
|
1300
1369
|
* so a caller with no registry (the CI projection) is unaffected.
|
|
1301
1370
|
*/
|
|
1302
1371
|
panelAvailable?: (id: string) => boolean;
|
|
1372
|
+
/**
|
|
1373
|
+
* Show a workspace: enter it AND put its tabs on screen (its most recent tab, or its home).
|
|
1374
|
+
*
|
|
1375
|
+
* Injected for the reason the Inspector writers are: opening a workspace's home reaches the
|
|
1376
|
+
* Library, the settings document and the pane model, none of which this module may import. Absent
|
|
1377
|
+
* (the CI projection, a test with no panes), the verb enters the workspace's frame and nothing
|
|
1378
|
+
* else, which is still the state the argument names.
|
|
1379
|
+
*/
|
|
1380
|
+
showWorkspace?: (id: WorkspaceId) => void;
|
|
1381
|
+
}
|
|
1382
|
+
|
|
1383
|
+
/** Run {@link ShellCommandDeps.showWorkspace}, or enter the frame alone when none was handed in. */
|
|
1384
|
+
function showWorkspace(id: WorkspaceId, deps: ShellCommandDeps): void {
|
|
1385
|
+
if (deps.showWorkspace) {
|
|
1386
|
+
deps.showWorkspace(id);
|
|
1387
|
+
return;
|
|
1388
|
+
}
|
|
1389
|
+
enterWorkspace(id, deps);
|
|
1303
1390
|
}
|
|
1304
1391
|
|
|
1305
1392
|
/** The Navigator dock hosts a panel — the precondition its own verbs share. */
|
|
@@ -1476,7 +1563,7 @@ export function shellViewCommands(deps: ShellCommandDeps): AnyCommand[] {
|
|
|
1476
1563
|
duplicate title among 130 records. A palette row is a NAME, and two rows with one name is
|
|
1477
1564
|
the defect the registry exists to prevent, arriving through the registry itself.
|
|
1478
1565
|
`inspector.focus.assistant` is the row (it carries ⌘⇧4). This one keeps every other
|
|
1479
|
-
consumer — the `open` STATE that `setRightTab` cannot express, the
|
|
1566
|
+
consumer — the `open` STATE that `setRightTab` cannot express, the workspace presets, three
|
|
1480
1567
|
screenshot steps, `⌘J`'s legacy branch — none of which needs a row to work. */
|
|
1481
1568
|
menus: ["never"],
|
|
1482
1569
|
group: "4_docks",
|
|
@@ -1487,100 +1574,49 @@ export function shellViewCommands(deps: ShellCommandDeps): AnyCommand[] {
|
|
|
1487
1574
|
return;
|
|
1488
1575
|
}
|
|
1489
1576
|
if (deps.inspectorTab() === "assistant") {
|
|
1490
|
-
deps.setInspectorTab(DEFAULT_INSPECTOR_TAB);
|
|
1577
|
+
deps.setInspectorTab(deps.restingInspectorTab?.() ?? DEFAULT_INSPECTOR_TAB);
|
|
1491
1578
|
}
|
|
1492
1579
|
},
|
|
1493
1580
|
title: "Show Assistant",
|
|
1494
1581
|
},
|
|
1495
|
-
// ──
|
|
1496
|
-
//
|
|
1497
|
-
//
|
|
1498
|
-
// In a row, and `view.resetLayout` is the one action that puts a drifted arrangement back.
|
|
1582
|
+
// ── Workspaces ───────────────────────────────────────────────────────────
|
|
1583
|
+
// One SETTER, and one chord record per workspace. A chord cannot carry an argument, so ⌘1–5
|
|
1584
|
+
// Are five records that each run the setter's own path rather than five implementations of it.
|
|
1499
1585
|
{
|
|
1500
1586
|
args: argsSchema({
|
|
1501
|
-
|
|
1587
|
+
workspace: enumProperty(WORKSPACE_IDS, "Which workspace to show."),
|
|
1502
1588
|
}),
|
|
1503
1589
|
category: "View",
|
|
1504
|
-
id: "view.
|
|
1590
|
+
id: "view.setWorkspace",
|
|
1505
1591
|
level: "application",
|
|
1506
|
-
|
|
1507
|
-
|
|
1592
|
+
/* `never`, not `palette`: the five `workspace.focus.*` rows below are the palette's way in,
|
|
1593
|
+
each with its chord, and an arguments prompt beside them would be the same action under a
|
|
1594
|
+
second name. This record is the scripted door and the one the top bar's tabs run. */
|
|
1595
|
+
menus: ["never"],
|
|
1596
|
+
group: "4_workspaces",
|
|
1508
1597
|
requires: "an open project",
|
|
1509
1598
|
when: projectOpen,
|
|
1510
1599
|
/* No `aiTool`: application-level chrome, refused at registration
|
|
1511
1600
|
(`studio-ui-guidelines.md` §12.4). */
|
|
1512
1601
|
run: (_ctx, args) => {
|
|
1513
|
-
|
|
1602
|
+
showWorkspace(enumArg("view.setWorkspace", args, "workspace", WORKSPACE_IDS), deps);
|
|
1514
1603
|
},
|
|
1515
|
-
title: "Switch
|
|
1604
|
+
title: "Switch Workspace",
|
|
1516
1605
|
},
|
|
1517
|
-
{
|
|
1518
|
-
args: argsSchema({
|
|
1519
|
-
name: stringProperty("What to call this arrangement. An existing name is overwritten."),
|
|
1520
|
-
}),
|
|
1606
|
+
...WORKSPACES.map((entry, index): AnyCommand => ({
|
|
1521
1607
|
category: "View",
|
|
1522
|
-
id:
|
|
1608
|
+
id: `workspace.focus.${entry.id}`,
|
|
1609
|
+
keybinding: `mod+${index + 1}`,
|
|
1523
1610
|
level: "application",
|
|
1524
1611
|
menus: ["palette"],
|
|
1525
|
-
group: "
|
|
1526
|
-
requires: "an open project",
|
|
1527
|
-
when: projectOpen,
|
|
1528
|
-
run: (_ctx, args) => {
|
|
1529
|
-
saveLayout(stringArg("view.saveLayout", args, "name"), deps);
|
|
1530
|
-
},
|
|
1531
|
-
title: "Save Layout",
|
|
1532
|
-
},
|
|
1533
|
-
{
|
|
1534
|
-
args: argsSchema({
|
|
1535
|
-
layout: stringProperty("The layout's id."),
|
|
1536
|
-
name: stringProperty("Its new name. The id, and every reference to it, is unchanged."),
|
|
1537
|
-
}),
|
|
1538
|
-
category: "View",
|
|
1539
|
-
id: "view.renameLayout",
|
|
1540
|
-
level: "application",
|
|
1541
|
-
menus: ["palette"],
|
|
1542
|
-
group: "4_layouts",
|
|
1543
|
-
requires: "an open project",
|
|
1544
|
-
when: projectOpen,
|
|
1545
|
-
run: (_ctx, args) => {
|
|
1546
|
-
renameLayout(
|
|
1547
|
-
stringArg("view.renameLayout", args, "layout"),
|
|
1548
|
-
stringArg("view.renameLayout", args, "name"),
|
|
1549
|
-
);
|
|
1550
|
-
},
|
|
1551
|
-
title: "Rename Layout",
|
|
1552
|
-
},
|
|
1553
|
-
{
|
|
1554
|
-
args: argsSchema({
|
|
1555
|
-
layout: stringProperty("The layout's id. The last remaining layout is kept."),
|
|
1556
|
-
}),
|
|
1557
|
-
category: "View",
|
|
1558
|
-
id: "view.deleteLayout",
|
|
1559
|
-
level: "application",
|
|
1560
|
-
menus: ["palette"],
|
|
1561
|
-
group: "4_layouts",
|
|
1562
|
-
requires: "an open project",
|
|
1563
|
-
when: projectOpen,
|
|
1564
|
-
run: (_ctx, args) => {
|
|
1565
|
-
deleteLayout(stringArg("view.deleteLayout", args, "layout"));
|
|
1566
|
-
},
|
|
1567
|
-
title: "Delete Layout",
|
|
1568
|
-
},
|
|
1569
|
-
{
|
|
1570
|
-
// No `args`: this verb takes none. An empty schema would be a promise of parameters the
|
|
1571
|
-
// Palette would then prompt for and the record would ignore.
|
|
1572
|
-
category: "View",
|
|
1573
|
-
id: "view.resetLayout",
|
|
1574
|
-
level: "application",
|
|
1575
|
-
menus: ["palette"],
|
|
1576
|
-
group: "4_layouts",
|
|
1612
|
+
group: "4_workspaces",
|
|
1577
1613
|
requires: "an open project",
|
|
1578
1614
|
when: projectOpen,
|
|
1579
1615
|
run: () => {
|
|
1580
|
-
|
|
1616
|
+
showWorkspace(entry.id, deps);
|
|
1581
1617
|
},
|
|
1582
|
-
title:
|
|
1583
|
-
},
|
|
1618
|
+
title: `Go to ${entry.title}`,
|
|
1619
|
+
})),
|
|
1584
1620
|
{
|
|
1585
1621
|
args: argsSchema({
|
|
1586
1622
|
color: enumProperty(CHROME_THEMES, "The Studio chrome's theme."),
|