@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/media/media-pane.ts
CHANGED
|
@@ -29,9 +29,16 @@
|
|
|
29
29
|
|
|
30
30
|
import { effect, effectScope } from "../reactivity";
|
|
31
31
|
import { paneRegion } from "../ui/regions";
|
|
32
|
+
import { localDay } from "../utils/local-day";
|
|
32
33
|
import { mediaSiteUrl, previewFileSrc } from "../files/media-paths";
|
|
33
|
-
import {
|
|
34
|
-
|
|
34
|
+
import {
|
|
35
|
+
formatBytes,
|
|
36
|
+
loadMediaMeta,
|
|
37
|
+
mediaMetaSettled,
|
|
38
|
+
peekMediaMeta,
|
|
39
|
+
recordImageSize,
|
|
40
|
+
} from "../files/media-meta";
|
|
41
|
+
import { FONT_EXTENSIONS, extensionOf, mediaKind } from "../files/media-upload";
|
|
35
42
|
import { loadMediaUsages, mediaUsageHeadline, peekMediaUsages } from "../files/media-usage";
|
|
36
43
|
import { mountMediaSurface } from "../surfaces/media-pane";
|
|
37
44
|
import type { MediaStage, MediaSurfaceHandle, MediaView } from "../surfaces/media-pane";
|
|
@@ -43,9 +50,6 @@ import type { CanvasSurface } from "../canvas/canvas-surface";
|
|
|
43
50
|
/** The `canvasMode` the media viewer draws under. */
|
|
44
51
|
export const MEDIA_MODE = "media";
|
|
45
52
|
|
|
46
|
-
/** Extensions the viewer renders as a font specimen rather than as a file it cannot show. */
|
|
47
|
-
const FONT_EXTENSIONS = new Set([".woff", ".woff2", ".ttf", ".otf"]);
|
|
48
|
-
|
|
49
53
|
/** The pangram the font specimen is set in — short, and every letter of the alphabet once. */
|
|
50
54
|
const SPECIMEN = "The quick brown fox jumps over the lazy dog";
|
|
51
55
|
|
|
@@ -97,9 +101,11 @@ export function detachMediaPane(paneId: string): void {
|
|
|
97
101
|
* Which element the stage should draw this file in.
|
|
98
102
|
*
|
|
99
103
|
* A font is decided by extension before anything else: `mediaKind` calls a `.woff2` a plain file,
|
|
100
|
-
* and a file the browser cannot render is the last answer here rather than the first.
|
|
104
|
+
* and a file the browser cannot render is the last answer here rather than the first. Exported
|
|
105
|
+
* because the Media workspace's detail pane (`media/media-library.ts`) asks the same question, and
|
|
106
|
+
* two answers to it would drift.
|
|
101
107
|
*/
|
|
102
|
-
function
|
|
108
|
+
export function mediaStageFor(path: string): MediaStage {
|
|
103
109
|
const ext = extensionOf(path);
|
|
104
110
|
if (FONT_EXTENSIONS.has(ext)) {
|
|
105
111
|
return "font";
|
|
@@ -112,7 +118,7 @@ function stageFor(path: string): MediaStage {
|
|
|
112
118
|
}
|
|
113
119
|
|
|
114
120
|
/** Kind, dimensions, size and modified time — each omitted rather than zeroed when unknown. */
|
|
115
|
-
function factsLine(path: string, meta: MediaMeta | null): string {
|
|
121
|
+
export function factsLine(path: string, meta: MediaMeta | null): string {
|
|
116
122
|
const facts: string[] = [mediaKind({ name: path })];
|
|
117
123
|
if (meta?.width != null && meta.height != null) {
|
|
118
124
|
facts.push(`${meta.width} × ${meta.height}`);
|
|
@@ -121,7 +127,8 @@ function factsLine(path: string, meta: MediaMeta | null): string {
|
|
|
121
127
|
facts.push(formatBytes(meta.bytes));
|
|
122
128
|
}
|
|
123
129
|
if (meta?.modified) {
|
|
124
|
-
|
|
130
|
+
// The local day it was modified on (`utils/local-day.ts`), not the UTC one.
|
|
131
|
+
facts.push(`modified ${localDay(new Date(meta.modified))}`);
|
|
125
132
|
}
|
|
126
133
|
return facts.join(" · ");
|
|
127
134
|
}
|
|
@@ -131,8 +138,30 @@ function specimenFamily(path: string): string {
|
|
|
131
138
|
return `jx-specimen-${path.replaceAll(/[^a-zA-Z0-9]/g, "-")}`;
|
|
132
139
|
}
|
|
133
140
|
|
|
141
|
+
/** What a font specimen draws: its scoped face, the custom property naming it, and the pangram. */
|
|
142
|
+
export interface FontSpecimen {
|
|
143
|
+
/** A `@font-face` rule for the generated family, loading the file from its preview src. */
|
|
144
|
+
fontFace: string;
|
|
145
|
+
/** `--jx-specimen-family: "<family>"`, the one inline declaration a specimen element carries. */
|
|
146
|
+
specimenFamily: string;
|
|
147
|
+
specimen: string;
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
/**
|
|
151
|
+
* The specimen for a font file, shared by the viewer and the Media workspace's detail pane, so a
|
|
152
|
+
* font is shown by being USED in both and the face is scoped the same way in both.
|
|
153
|
+
*/
|
|
154
|
+
export function specimenOf(path: string): FontSpecimen {
|
|
155
|
+
const family = specimenFamily(path);
|
|
156
|
+
return {
|
|
157
|
+
fontFace: `@font-face { font-family: "${family}"; src: url("${previewFileSrc(path)}"); }`,
|
|
158
|
+
specimen: SPECIMEN,
|
|
159
|
+
specimenFamily: `--jx-specimen-family: "${family}"`,
|
|
160
|
+
};
|
|
161
|
+
}
|
|
162
|
+
|
|
134
163
|
/** Which documents reference this file, or the honest reason there is no list. */
|
|
135
|
-
function usageOf(
|
|
164
|
+
export function usageOf(
|
|
136
165
|
usage: UsageState | null,
|
|
137
166
|
): Pick<MediaView, "usageState" | "usageHeadline" | "usageFiles"> {
|
|
138
167
|
const headline = mediaUsageHeadline(usage);
|
|
@@ -179,11 +208,10 @@ export function renderMediaMode(surface: CanvasSurface, tab: Tab): void {
|
|
|
179
208
|
detachMediaPane(paneId);
|
|
180
209
|
|
|
181
210
|
const path = tab.documentPath ?? "";
|
|
182
|
-
const family = specimenFamily(path);
|
|
183
211
|
const src = previewFileSrc(path);
|
|
184
212
|
const ref = mediaSiteUrl(path);
|
|
185
213
|
const ext = extensionOf(path);
|
|
186
|
-
const kind =
|
|
214
|
+
const kind = mediaStageFor(path);
|
|
187
215
|
|
|
188
216
|
let panel: ActiveMediaPane | null = null;
|
|
189
217
|
const redraw = () => {
|
|
@@ -197,25 +225,25 @@ export function renderMediaMode(surface: CanvasSurface, tab: Tab): void {
|
|
|
197
225
|
const usage = peekMediaUsages(path);
|
|
198
226
|
/* Asked on the first paint that finds it missing, never on every paint: both loaders cache and
|
|
199
227
|
de-duplicate in flight, and both repaint through `redraw` when they land. */
|
|
200
|
-
if (
|
|
228
|
+
if (!mediaMetaSettled(path)) {
|
|
201
229
|
void loadMediaMeta(path).then(redraw);
|
|
202
230
|
}
|
|
203
231
|
if (usage === null || usage.status === "pending") {
|
|
204
232
|
void loadMediaUsages(path).then(redraw);
|
|
205
233
|
}
|
|
234
|
+
/* The face is scoped to the generated family name, so two specimens open side by side cannot
|
|
235
|
+
claim the same one. Written only for a font: every other stage carries an empty sheet. */
|
|
236
|
+
const specimen = specimenOf(path);
|
|
206
237
|
return {
|
|
207
238
|
extLabel: ext || "this file",
|
|
208
239
|
facts: factsLine(path, meta),
|
|
209
|
-
|
|
210
|
-
claim the same one. Written only for a font: every other stage carries an empty sheet. */
|
|
211
|
-
fontFace:
|
|
212
|
-
kind === "font" ? `@font-face { font-family: "${family}"; src: url("${src}"); }` : "",
|
|
240
|
+
fontFace: kind === "font" ? specimen.fontFace : "",
|
|
213
241
|
kind,
|
|
214
242
|
name: path.split("/").pop() ?? "",
|
|
215
243
|
ref,
|
|
216
244
|
region: paneRegion(paneId, "media"),
|
|
217
|
-
specimen:
|
|
218
|
-
specimenFamily:
|
|
245
|
+
specimen: specimen.specimen,
|
|
246
|
+
specimenFamily: specimen.specimenFamily,
|
|
219
247
|
src,
|
|
220
248
|
...usageOf(usage),
|
|
221
249
|
};
|
|
@@ -346,7 +346,7 @@ export async function autoSyncProjectOnOpen(): Promise<void> {
|
|
|
346
346
|
const platform = getPlatform();
|
|
347
347
|
try {
|
|
348
348
|
/* The status is host wire data. A host may leave `remotes` out (as `deploy-checklist.ts` and
|
|
349
|
-
`
|
|
349
|
+
`publish-changes.ts` also allow), which reads as "nothing to sync"; a host that sends no status at
|
|
350
350
|
all throws on the first read and is caught below the same way, so a malformed status never
|
|
351
351
|
aborts the project open that awaits this. */
|
|
352
352
|
const status = await platform.gitStatus();
|
|
@@ -43,6 +43,7 @@ import { reactive } from "../reactivity";
|
|
|
43
43
|
import { now } from "../services/clock";
|
|
44
44
|
import { notify } from "../services/notify";
|
|
45
45
|
import type { NotifyOptions } from "../services/notify";
|
|
46
|
+
import type { CommandArgValues } from "../commands/command-args";
|
|
46
47
|
import { registerPanel } from "./panel-registry";
|
|
47
48
|
import type { PanelBody } from "./panel-registry";
|
|
48
49
|
import type {
|
|
@@ -180,7 +181,10 @@ export interface ActivityHandle {
|
|
|
180
181
|
* The log goes into the notification's `detail`, so the persistent, inspectable error view §16.4
|
|
181
182
|
* asks for is the Problems row, not a modal that has to stay open to be read.
|
|
182
183
|
*/
|
|
183
|
-
fail: (
|
|
184
|
+
fail: (
|
|
185
|
+
message: string,
|
|
186
|
+
opts?: { action?: string; actionArgs?: CommandArgValues; path?: string },
|
|
187
|
+
) => void;
|
|
184
188
|
}
|
|
185
189
|
|
|
186
190
|
/**
|
|
@@ -237,7 +241,10 @@ export function beginActivity(options: ActivityOptions): ActivityHandle {
|
|
|
237
241
|
finish("done", status);
|
|
238
242
|
},
|
|
239
243
|
entry: live,
|
|
240
|
-
fail(
|
|
244
|
+
fail(
|
|
245
|
+
message: string,
|
|
246
|
+
opts: { action?: string; actionArgs?: CommandArgValues; path?: string } = {},
|
|
247
|
+
) {
|
|
241
248
|
// An operation that has already ended does not get to raise a Problem: the first outcome is
|
|
242
249
|
// The one that happened, and a late `fail()` after a successful `done()` would put a failure
|
|
243
250
|
// On a list whose whole promise is that everything on it still needs fixing.
|
|
@@ -253,6 +260,9 @@ export function beginActivity(options: ActivityOptions): ActivityHandle {
|
|
|
253
260
|
if (opts.action !== undefined) {
|
|
254
261
|
notice.action = opts.action;
|
|
255
262
|
}
|
|
263
|
+
if (opts.actionArgs !== undefined) {
|
|
264
|
+
notice.actionArgs = opts.actionArgs;
|
|
265
|
+
}
|
|
256
266
|
if (opts.path !== undefined) {
|
|
257
267
|
notice.path = opts.path;
|
|
258
268
|
}
|
|
@@ -381,8 +391,14 @@ function stepView(step: ActivityStep, index: number): ActivityStepView {
|
|
|
381
391
|
};
|
|
382
392
|
}
|
|
383
393
|
|
|
384
|
-
/**
|
|
385
|
-
|
|
394
|
+
/**
|
|
395
|
+
* One operation, as a document reads it.
|
|
396
|
+
*
|
|
397
|
+
* Exported because the Activity feed is not its only reader: Publish › Deploys draws a running
|
|
398
|
+
* deploy's steps from the same record (studio.md §22.8), and a second projection of one activity
|
|
399
|
+
* would be a second set of glyphs for the same states.
|
|
400
|
+
*/
|
|
401
|
+
export function activityRowView(entry: ActivityEntry): ActivityRowView {
|
|
386
402
|
const lines = entry.log.length;
|
|
387
403
|
return {
|
|
388
404
|
cancellable: entry.cancellable,
|
|
@@ -423,7 +439,7 @@ export function activityView(): ActivityView {
|
|
|
423
439
|
clearLabel: `Clear ${finished} finished`,
|
|
424
440
|
hasFinished: finished > 0,
|
|
425
441
|
hasRows: activities.length > 0,
|
|
426
|
-
rows: activities.map((entry) =>
|
|
442
|
+
rows: activities.map((entry) => activityRowView(entry)),
|
|
427
443
|
};
|
|
428
444
|
}
|
|
429
445
|
|
|
@@ -1,15 +1,15 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Chat-markdown.ts — memoized markdown rendering for assistant chat messages.
|
|
3
3
|
*
|
|
4
|
-
* Wraps @jxsuite/markup/md-html (sanitized markdown → HTML) with a per-message cache
|
|
5
|
-
*
|
|
6
|
-
*
|
|
4
|
+
* Wraps @jxsuite/markup/md-html (sanitized markdown → HTML) with a per-message cache keyed by
|
|
5
|
+
* message id + content length, so re-renders during streaming only re-parse the message that
|
|
6
|
+
* actually grew.
|
|
7
7
|
*
|
|
8
|
-
* The HTML ends up in `[part="md"]`, the assistant surface's island — this app's ONE injection
|
|
9
|
-
*
|
|
10
|
-
*
|
|
11
|
-
*
|
|
12
|
-
*
|
|
8
|
+
* The HTML ends up in `[part="md"]`, the assistant surface's island — this app's ONE injection sink
|
|
9
|
+
* — and it goes through the Trusted Types policy on the way THERE, in `surfaces/ai-chat.ts`.
|
|
10
|
+
* md-html already sanitizes — raw HTML dropped, javascript: URLs stripped — and the policy asserts
|
|
11
|
+
* that it did, rather than taking a comment's word for it. A `createHTML` that passed its input
|
|
12
|
+
* through unchanged would satisfy the API and defend nothing.
|
|
13
13
|
*
|
|
14
14
|
* **It returns markup, not a template.** It used to hand back a `TemplateResult` wrapping
|
|
15
15
|
* `unsafeHTML` (which stringified the trusted value straight back again); the assistant is a Jx
|
|
@@ -230,11 +230,11 @@ function barPosition(anchor: {
|
|
|
230
230
|
"the stage showing the active tab", which was the same answer only while a tab could be on
|
|
231
231
|
screen in one place; with a document displayed in two panes it picked whichever came first in
|
|
232
232
|
the grid, and clipped the bar against a stage the author is not typing in.
|
|
233
|
-
…and against the box that SCROLLS, where the stage has one
|
|
234
|
-
|
|
235
|
-
still inside the stage while nobody can see it — and the bar
|
|
236
|
-
pointing at a node
|
|
237
|
-
the viewport, as it always was. */
|
|
233
|
+
…and against the box that SCROLLS, where the stage has one: Edit's page scroller. Over a
|
|
234
|
+
collection entry the writing banner stands above it in the same stage cell, so a node
|
|
235
|
+
scrolled up under the banner is still inside the stage while nobody can see it — and the bar
|
|
236
|
+
would float over the banner, pointing at a node it covers. Everywhere else there is no
|
|
237
|
+
scroller and the stage is the viewport, as it always was. */
|
|
238
238
|
const surface = activeCanvasSurface();
|
|
239
239
|
const viewport = panelOfSurface(surface)?.scrollContainer ?? stageOf(surface);
|
|
240
240
|
const box = viewport ? rectOf(viewport) : null;
|
|
@@ -244,9 +244,9 @@ function barPosition(anchor: {
|
|
|
244
244
|
/* ABOVE the anchor where the bar fits above it INSIDE that viewport, and BELOW it where it does
|
|
245
245
|
not. The flip used to be decided against a flat 80 in WINDOW coordinates, the app's own top
|
|
246
246
|
chrome, which is the same answer only while the viewport starts near the top of the window.
|
|
247
|
-
Edit's scroller
|
|
248
|
-
its bottom was still on screen put the bar ON the
|
|
249
|
-
|
|
247
|
+
Edit's scroller can start under the writing banner, so an anchor whose top had scrolled under
|
|
248
|
+
it while its bottom was still on screen put the bar ON the banner, taking its clicks. Flipped
|
|
249
|
+
is better than hidden: the element is visible, so its bar should be, and
|
|
250
250
|
past the clip above the anchor's bottom edge is inside the viewport, so the flipped bar is too.
|
|
251
251
|
The fallback is that same 80px of chrome, for a stage no pass has measured yet. */
|
|
252
252
|
const ceiling = box ? box.top : 80 - BAR_CLEARANCE;
|
|
@@ -257,7 +257,7 @@ function barPosition(anchor: {
|
|
|
257
257
|
/* Below it, and kept INSIDE the viewport: an element taller than what is left of the scroller has
|
|
258
258
|
its bottom edge off screen, and the bar would follow it there — over the status bar, or over
|
|
259
259
|
whatever the pane below is showing. Clamped, it stands on that element's last visible strip,
|
|
260
|
-
still pointing at it and still
|
|
260
|
+
still pointing at it and still inside the scroller. */
|
|
261
261
|
const below = anchor.top + anchor.height + 4;
|
|
262
262
|
return {
|
|
263
263
|
left: anchor.left,
|
|
@@ -1273,8 +1273,8 @@ function hideBar(): void {
|
|
|
1273
1273
|
* The document + selection the bar is currently suppressed FOR, or null while it is free to draw.
|
|
1274
1274
|
*
|
|
1275
1275
|
* **Why a key and not a boolean.** The bar is `position: fixed` and clamped into the window, so it
|
|
1276
|
-
* can sit over the
|
|
1277
|
-
*
|
|
1276
|
+
* can sit over the pane context bar, the Inspector and the docks; an author working in the
|
|
1277
|
+
* Inspector's Logic tab reported it "blocking a part of the interface that the user needs to
|
|
1278
1278
|
* utilize". Hiding it on a chrome pointerdown is half an answer — {@link dismissBlockActionBar}
|
|
1279
1279
|
* alone would flash back on the very next repaint, because the bar is re-rendered from the
|
|
1280
1280
|
* `toolbarRefresh` seam on every selection snapshot and from `renderOnly("overlays")` on zoom/pan.
|
|
@@ -25,7 +25,7 @@
|
|
|
25
25
|
*/
|
|
26
26
|
|
|
27
27
|
import { monitorForElements } from "@atlaskit/pragmatic-drag-and-drop/element/adapter";
|
|
28
|
-
import { displayTagName } from "@jxsuite/schema/guards";
|
|
28
|
+
import { displayTagName, isString } from "@jxsuite/schema/guards";
|
|
29
29
|
import {
|
|
30
30
|
beginDragSession,
|
|
31
31
|
clearDropIndicator,
|
|
@@ -101,7 +101,10 @@ function cursorOf(location: MonitorDragArgs["location"]): ViewportPoint {
|
|
|
101
101
|
*/
|
|
102
102
|
function dragSrcOf(data: ElementDragPayload["data"]): DragSrcKind | null {
|
|
103
103
|
if (data.type === "block") {
|
|
104
|
-
|
|
104
|
+
/* SAFETY: every minter of a "block" payload sets `fragment` to the JxMutableNode it inserts;
|
|
105
|
+
only a string tag is read off it, and anything else crosses as no tag (placed as a block). */
|
|
106
|
+
const tag = (data.fragment as JxMutableNode | undefined)?.tagName;
|
|
107
|
+
return isString(tag) ? { tag, type: "block" } : { type: "block" };
|
|
105
108
|
}
|
|
106
109
|
if (data.type === "tree-node" && Array.isArray(data.path)) {
|
|
107
110
|
/* SAFETY: both minters of a "tree-node" payload, an Outline row's `getInitialData` and the block
|
package/src/panels/chat-panel.ts
CHANGED
|
@@ -19,12 +19,12 @@
|
|
|
19
19
|
*
|
|
20
20
|
* **The assistant's SURFACE document is what this module defers.** Mounting `surfaces/ai-chat.ts`
|
|
21
21
|
* costs a traced 100–290 ms of connectedCallback at boot (its island projections; see
|
|
22
|
-
* `scripts/perf/REPORT.md`), paid on every window open although the document is invisible until
|
|
23
|
-
*
|
|
24
|
-
*
|
|
25
|
-
*
|
|
26
|
-
*
|
|
27
|
-
*
|
|
22
|
+
* `scripts/perf/REPORT.md`), paid on every window open although the document is invisible until the
|
|
23
|
+
* tab is picked. Binding is the same seam (`bindAiPanelHost`) and it is now deferred to the first
|
|
24
|
+
* time the Assistant tab is actually shown or revealed: `renderAiPanel` no-ops while the surface is
|
|
25
|
+
* null, and the surface's own watcher projects whatever the machinery wrote before that point, so a
|
|
26
|
+
* prompt seeded into a boot the reader never spends in the tab is not lost — it is one more message
|
|
27
|
+
* waiting when the body first appears.
|
|
28
28
|
*
|
|
29
29
|
* **This module is the SEAM, and it has no markup of its own.** The assistant is a Jx document
|
|
30
30
|
* (`surfaces/ai-chat.json`), and a document CLEARS the host it is given — so it needs a container
|
|
@@ -0,0 +1,306 @@
|
|
|
1
|
+
/// <reference lib="dom" />
|
|
2
|
+
/**
|
|
3
|
+
* The Collections panel — the Content workspace's Navigator panel (`specs/studio.md` §22.5).
|
|
4
|
+
*
|
|
5
|
+
* Two lists, chosen by what the focused pane shows:
|
|
6
|
+
*
|
|
7
|
+
* - **The collections.** The built-in Pages and every collection `project.json` declares, in
|
|
8
|
+
* declaration order, each with its entry count (from the Content home's scan,
|
|
9
|
+
* `browse/library-pane.ts`) and its saved grid views beneath it (`grid/grid-layout.ts`), and **+
|
|
10
|
+
* New collection** at the foot. Choosing one shows it in the Content home
|
|
11
|
+
* (`content.showCollection`); choosing a saved view opens the collection's grid on it.
|
|
12
|
+
* - **One collection's entries**, while an entry of it is the focused document: thumbnail, title and
|
|
13
|
+
* status (`content/entry-summaries.ts`), under **‹ <Collection>** to go back, with **+ New
|
|
14
|
+
* <item>** at the foot. Choosing one opens it where it is written (`content/entry-open.ts`).
|
|
15
|
+
*
|
|
16
|
+
* The markup is `surfaces/collections-panel.json`; this module is the flow. It is registered with
|
|
17
|
+
* no rail button: Content has no rail, and the workspace's frame opens the Navigator on it
|
|
18
|
+
* (`shell.ts`'s `WORKSPACE_PRESETS`).
|
|
19
|
+
*
|
|
20
|
+
* @docs studio/projects/browse
|
|
21
|
+
*/
|
|
22
|
+
|
|
23
|
+
import { nothing } from "lit-html";
|
|
24
|
+
import { projectState, renderOnly } from "../store";
|
|
25
|
+
import { activeTab } from "../workspace/workspace";
|
|
26
|
+
import { runActiveReported } from "../commands/run-reported";
|
|
27
|
+
import {
|
|
28
|
+
PAGES_COLLECTION,
|
|
29
|
+
collectionKeyOfPath,
|
|
30
|
+
contentCollection,
|
|
31
|
+
contentCollections,
|
|
32
|
+
} from "../content/content-collections";
|
|
33
|
+
import {
|
|
34
|
+
collectionCounts,
|
|
35
|
+
collectionEntryPaths,
|
|
36
|
+
collectionView,
|
|
37
|
+
shownCollectionKey,
|
|
38
|
+
} from "../browse/library-pane";
|
|
39
|
+
import { localeLabel, localeOfPath, resolveI18n } from "@jxsuite/schema/locale";
|
|
40
|
+
import { entryLocale } from "../content/collection-pages";
|
|
41
|
+
import { onEntrySummariesRead, peekEntrySummaries } from "../content/entry-summaries";
|
|
42
|
+
import { openEntry } from "../content/entry-open";
|
|
43
|
+
import { workspaceHomeTabId } from "../workspace/workspace-ids";
|
|
44
|
+
import { makeGridTabId, parseGridTabId } from "../grid/grid-source";
|
|
45
|
+
import { applySavedView, listSavedViews } from "../grid/grid-layout";
|
|
46
|
+
import {
|
|
47
|
+
emptyCollectionsPanelValues,
|
|
48
|
+
mountCollectionsPanelSurface,
|
|
49
|
+
} from "../surfaces/collections-panel";
|
|
50
|
+
import { registerPanel } from "./panel-registry";
|
|
51
|
+
import type {
|
|
52
|
+
CollectionEntryRow,
|
|
53
|
+
CollectionRow,
|
|
54
|
+
CollectionsPanelActions,
|
|
55
|
+
CollectionsPanelSurfaceHandle,
|
|
56
|
+
CollectionsPanelValues,
|
|
57
|
+
} from "../surfaces/collections-panel";
|
|
58
|
+
import type { Tab } from "../tabs/tab";
|
|
59
|
+
|
|
60
|
+
/** The `source` every command run from here reports under. */
|
|
61
|
+
const SOURCE = "Collections";
|
|
62
|
+
|
|
63
|
+
/** The grid tab id a collection's saved views are stored under. */
|
|
64
|
+
export function collectionGridId(key: string): string {
|
|
65
|
+
return key === PAGES_COLLECTION
|
|
66
|
+
? makeGridTabId({ kind: "pages" })
|
|
67
|
+
: makeGridTabId({ kind: "collection", name: key });
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
/**
|
|
71
|
+
* The declared collection an entry tab is writing, or `null`: the focused document is a file a
|
|
72
|
+
* declared collection owns. Pages are Design's, so a page tab lists the collections. A file-backed
|
|
73
|
+
* collection's file is no entry either: its grid lists its records, so the panel lists the
|
|
74
|
+
* collections with that one selected.
|
|
75
|
+
*/
|
|
76
|
+
export function writingCollection(tab: Tab | null): string | null {
|
|
77
|
+
const key = collectionKeyOfPath(tab?.documentPath);
|
|
78
|
+
return key !== null && key !== PAGES_COLLECTION && !contentCollection(key)?.fileBacked
|
|
79
|
+
? key
|
|
80
|
+
: null;
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
/** The file-backed collection whose file a tab holds, or `null`. */
|
|
84
|
+
function fileCollectionOf(tab: Tab): string | null {
|
|
85
|
+
const key = collectionKeyOfPath(tab.documentPath);
|
|
86
|
+
return key !== null && contentCollection(key)?.fileBacked === true ? key : null;
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
/** The collection the focused pane is showing, for the list's selected row, or `null`. */
|
|
90
|
+
function shownKey(tab: Tab | null): string | null {
|
|
91
|
+
if (!tab) {
|
|
92
|
+
return null;
|
|
93
|
+
}
|
|
94
|
+
if (tab.id === workspaceHomeTabId("content")) {
|
|
95
|
+
return shownCollectionKey();
|
|
96
|
+
}
|
|
97
|
+
const grid = parseGridTabId(tab.id);
|
|
98
|
+
if (grid?.kind === "pages") {
|
|
99
|
+
return PAGES_COLLECTION;
|
|
100
|
+
}
|
|
101
|
+
return grid?.kind === "collection" ? grid.name : fileCollectionOf(tab);
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
/** The collection list. */
|
|
105
|
+
function collectionRows(tab: Tab | null): CollectionRow[] {
|
|
106
|
+
const counts = collectionCounts();
|
|
107
|
+
const selected = shownKey(tab);
|
|
108
|
+
return contentCollections().map((collection) => {
|
|
109
|
+
const count = counts?.get(collection.key);
|
|
110
|
+
return {
|
|
111
|
+
count: counts === null ? "" : String(count ?? 0),
|
|
112
|
+
key: collection.key,
|
|
113
|
+
selected: collection.key === selected ? "true" : "false",
|
|
114
|
+
title: collection.title,
|
|
115
|
+
views: listSavedViews(collectionGridId(collection.key)).map((view) => ({
|
|
116
|
+
key: `${collection.key}\n${view.name}`,
|
|
117
|
+
name: view.name,
|
|
118
|
+
})),
|
|
119
|
+
};
|
|
120
|
+
});
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
/** Everything the panel draws right now. */
|
|
124
|
+
export function collectionsPanelValues(): CollectionsPanelValues {
|
|
125
|
+
const values = emptyCollectionsPanelValues();
|
|
126
|
+
if (!projectState) {
|
|
127
|
+
return values;
|
|
128
|
+
}
|
|
129
|
+
const tab = activeTab.value;
|
|
130
|
+
const writing = writingCollection(tab);
|
|
131
|
+
if (writing === null) {
|
|
132
|
+
return { ...values, body: "list", collections: collectionRows(tab) };
|
|
133
|
+
}
|
|
134
|
+
const collection = contentCollection(writing);
|
|
135
|
+
const counts = collectionCounts();
|
|
136
|
+
const paths = collectionEntryPaths(writing);
|
|
137
|
+
const summaries = counts === null ? null : peekEntrySummaries(writing, paths);
|
|
138
|
+
/* A multilingual collection's entries say which language each is in, and the list keeps to the
|
|
139
|
+
language the collection's view is filtered to: three translations of one exhibition are three
|
|
140
|
+
rows, and an unlabelled list of them reads as one entry listed thrice. */
|
|
141
|
+
const filter = collectionView(writing).locale;
|
|
142
|
+
const entries: CollectionEntryRow[] = (summaries ?? []).flatMap((entry) => {
|
|
143
|
+
const locale = entryLocale(entry.path) ?? "";
|
|
144
|
+
if (filter !== "" && locale !== filter) {
|
|
145
|
+
return [];
|
|
146
|
+
}
|
|
147
|
+
return [
|
|
148
|
+
{
|
|
149
|
+
art: entry.thumb === "" ? "glyph" : "image",
|
|
150
|
+
lang: locale,
|
|
151
|
+
locale: locale === "" ? "" : localeLabel(locale),
|
|
152
|
+
path: entry.path,
|
|
153
|
+
selected: entry.path === tab?.documentPath ? "true" : "false",
|
|
154
|
+
status: entry.status,
|
|
155
|
+
thumb: entry.thumb,
|
|
156
|
+
title: entry.title,
|
|
157
|
+
},
|
|
158
|
+
];
|
|
159
|
+
});
|
|
160
|
+
return {
|
|
161
|
+
...values,
|
|
162
|
+
backTitle: collection?.title ?? writing,
|
|
163
|
+
backCount: counts === null ? "" : String(paths.length),
|
|
164
|
+
body: "entries",
|
|
165
|
+
entries,
|
|
166
|
+
entriesState: summaries === null ? "loading" : entries.length === 0 ? "empty" : "listed",
|
|
167
|
+
newLabel: `New ${collection?.item ?? "entry"}`,
|
|
168
|
+
};
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
// ─── Actions ─────────────────────────────────────────────────────────────────
|
|
172
|
+
|
|
173
|
+
/**
|
|
174
|
+
* Open a collection's grid on a saved view.
|
|
175
|
+
*
|
|
176
|
+
* The view is written onto the grid's working layout first, so a grid opened now loads it. A grid
|
|
177
|
+
* already on screen has loaded its layout, so it is told through `grid.applyView`, the command the
|
|
178
|
+
* grid's own picker runs.
|
|
179
|
+
*/
|
|
180
|
+
async function applyCollectionView(key: string, name: string): Promise<void> {
|
|
181
|
+
const gridId = collectionGridId(key);
|
|
182
|
+
const showing = activeTab.value?.id === gridId;
|
|
183
|
+
applySavedView(gridId, name);
|
|
184
|
+
if (showing) {
|
|
185
|
+
await runActiveReported("grid.applyView", { name }, SOURCE);
|
|
186
|
+
return;
|
|
187
|
+
}
|
|
188
|
+
const { openCollectionGrid, openPagesGrid } = await import("../grid/grid-open");
|
|
189
|
+
if (key === PAGES_COLLECTION) {
|
|
190
|
+
openPagesGrid();
|
|
191
|
+
} else {
|
|
192
|
+
openCollectionGrid(key);
|
|
193
|
+
}
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
const ACTIONS: CollectionsPanelActions = {
|
|
197
|
+
applyView: (key, name) => {
|
|
198
|
+
const [collection = ""] = key.split("\n");
|
|
199
|
+
void applyCollectionView(collection, name);
|
|
200
|
+
},
|
|
201
|
+
back: () => {
|
|
202
|
+
const writing = writingCollection(activeTab.value);
|
|
203
|
+
if (writing !== null) {
|
|
204
|
+
void runActiveReported("content.showCollection", { collection: writing }, SOURCE);
|
|
205
|
+
}
|
|
206
|
+
},
|
|
207
|
+
newCollection: () => {
|
|
208
|
+
void runActiveReported("file.new", { kind: "collection" }, SOURCE);
|
|
209
|
+
},
|
|
210
|
+
newEntry: () => {
|
|
211
|
+
const writing = writingCollection(activeTab.value);
|
|
212
|
+
void runActiveReported(
|
|
213
|
+
"file.new",
|
|
214
|
+
writing === null
|
|
215
|
+
? { kind: "entry" }
|
|
216
|
+
: { collection: writing, kind: "entry", ...newEntryLocale(writing) },
|
|
217
|
+
SOURCE,
|
|
218
|
+
);
|
|
219
|
+
},
|
|
220
|
+
openEntry: (path) => {
|
|
221
|
+
void openEntry(path);
|
|
222
|
+
},
|
|
223
|
+
showCollection: (key) => {
|
|
224
|
+
void runActiveReported("content.showCollection", { collection: key }, SOURCE);
|
|
225
|
+
},
|
|
226
|
+
};
|
|
227
|
+
|
|
228
|
+
/**
|
|
229
|
+
* The language a new entry starts in from the entries list: the one the entry being written is in,
|
|
230
|
+
* else the one the collection's view is filtered to. Nothing when neither says, which leaves the
|
|
231
|
+
* dialog on the site's default.
|
|
232
|
+
*/
|
|
233
|
+
export function newEntryLocale(collection: string): { locale?: string } {
|
|
234
|
+
const { i18n } = resolveI18n(projectState?.projectConfig ?? {});
|
|
235
|
+
const path = activeTab.value?.documentPath ?? null;
|
|
236
|
+
const own = path === null ? null : localeOfPath(path, i18n);
|
|
237
|
+
const locale = own ?? collectionView(collection).locale;
|
|
238
|
+
return locale === "" ? {} : { locale };
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
// ─── Mounting ────────────────────────────────────────────────────────────────
|
|
242
|
+
|
|
243
|
+
interface StandingPanel {
|
|
244
|
+
host: HTMLElement;
|
|
245
|
+
handle: CollectionsPanelSurfaceHandle;
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
let _standing: StandingPanel | null = null;
|
|
249
|
+
let _unlisten: (() => void) | null = null;
|
|
250
|
+
|
|
251
|
+
/** Repaint the Navigator, which repaints this panel when it is the one showing. */
|
|
252
|
+
function repaint(): void {
|
|
253
|
+
renderOnly("leftPanel");
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
/** Mount the surface into `host`, or bring the one already there up to date. */
|
|
257
|
+
function mountInto(host: HTMLElement): void {
|
|
258
|
+
_unlisten ??= onEntrySummariesRead(repaint);
|
|
259
|
+
if (_standing && (_standing.host !== host || !_standing.handle.connected())) {
|
|
260
|
+
_standing.handle.dispose();
|
|
261
|
+
_standing = null;
|
|
262
|
+
}
|
|
263
|
+
if (_standing) {
|
|
264
|
+
_standing.handle.update(collectionsPanelValues());
|
|
265
|
+
return;
|
|
266
|
+
}
|
|
267
|
+
_standing = {
|
|
268
|
+
handle: mountCollectionsPanelSurface(host, collectionsPanelValues(), ACTIONS),
|
|
269
|
+
host,
|
|
270
|
+
};
|
|
271
|
+
}
|
|
272
|
+
|
|
273
|
+
/**
|
|
274
|
+
* The Navigator's content area inside a panel body, where a mounted document goes (the reason is
|
|
275
|
+
* `panels/elements-panel.ts`'s: the body is lit's part, and its child is the box a panel owns).
|
|
276
|
+
*/
|
|
277
|
+
function contentArea(body: HTMLElement): HTMLElement {
|
|
278
|
+
return body.querySelector<HTMLElement>(".panel-content") ?? body;
|
|
279
|
+
}
|
|
280
|
+
|
|
281
|
+
/**
|
|
282
|
+
* Contribute the Collections panel: project level (it lists the project's collections), no rail
|
|
283
|
+
* button (Content has no rail), the Content workspace's Navigator.
|
|
284
|
+
*/
|
|
285
|
+
export function registerCollectionsPanel(): void {
|
|
286
|
+
registerPanel({
|
|
287
|
+
id: "collections",
|
|
288
|
+
title: "Collections",
|
|
289
|
+
level: "project",
|
|
290
|
+
dock: "navigator",
|
|
291
|
+
icon: "stack",
|
|
292
|
+
rail: false,
|
|
293
|
+
render: () => nothing,
|
|
294
|
+
afterRender: (_ctx, host) => {
|
|
295
|
+
mountInto(contentArea(host));
|
|
296
|
+
},
|
|
297
|
+
});
|
|
298
|
+
}
|
|
299
|
+
|
|
300
|
+
/** Forget the mounted panel — tests, and a project switch. */
|
|
301
|
+
export function resetCollectionsPanel(): void {
|
|
302
|
+
_standing?.handle.dispose();
|
|
303
|
+
_standing = null;
|
|
304
|
+
_unlisten?.();
|
|
305
|
+
_unlisten = null;
|
|
306
|
+
}
|