@jxsuite/studio 6.1.2 → 8.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/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
|
@@ -9,32 +9,47 @@
|
|
|
9
9
|
* identical sentence — "No files found" — which is the lie §16 exists to end.
|
|
10
10
|
* {@link scanLibrary} returns {@link LibraryScan.failures} beside the files; the pane raises
|
|
11
11
|
* them as Problems with a Retry and refuses to call an incomplete listing empty.
|
|
12
|
-
* 2. **A
|
|
13
|
-
*
|
|
14
|
-
*
|
|
15
|
-
*
|
|
12
|
+
* 2. **A file is in one collection or in none.** The Library this model served filtered by FOLDER
|
|
13
|
+
* (Pages, Layouts, Components, Content, Media) and matched content with a third matcher of its
|
|
14
|
+
* own, which disagreed with the collection grid about the same entry. Every file now carries the
|
|
15
|
+
* key of the collection the Content workspace lists it under ({@link LibraryFile.collection}),
|
|
16
|
+
* from `content/content-collections.ts`, whose one matcher is `content/collection-match.ts`
|
|
17
|
+
* (studio.md §9.1.2).
|
|
16
18
|
*
|
|
17
19
|
* Everything here is pure over its inputs (the scan takes the platform as an argument) so the
|
|
18
20
|
* 300-page acceptance case can be measured without a DOM.
|
|
19
21
|
*/
|
|
20
22
|
|
|
21
23
|
import { MEDIA_EXTENSIONS, extensionOf } from "../files/media-upload";
|
|
24
|
+
import { PAGES_COLLECTION, collectionKeyOfPath } from "../content/content-collections";
|
|
25
|
+
import { isRoutedPageFile } from "@jxsuite/site/routes";
|
|
26
|
+
import { collectionForFile } from "../content/collection-match";
|
|
27
|
+
import { LOCALE_PLACEHOLDER } from "@jxsuite/schema/asset-paths";
|
|
22
28
|
import { projectState } from "../store";
|
|
23
29
|
import { notedListing } from "../files/asset-versions";
|
|
30
|
+
import { localDay } from "../utils/local-day";
|
|
24
31
|
import { errorMessage } from "@jxsuite/schema/parse";
|
|
32
|
+
import { isString } from "@jxsuite/schema/guards";
|
|
25
33
|
import { resolveI18n, servedLocaleOfPath } from "@jxsuite/schema/locale";
|
|
26
34
|
import type { ResolvedI18n } from "@jxsuite/schema/locale";
|
|
27
35
|
import type { ContentSectionEntry, DirEntry, StudioPlatform } from "../types";
|
|
36
|
+
import type { ProjectConfig } from "@jxsuite/schema/types";
|
|
28
37
|
|
|
29
38
|
// ─── Files ───────────────────────────────────────────────────────────────────
|
|
30
39
|
|
|
31
|
-
/** One
|
|
40
|
+
/** One scanned file, whichever layout is drawing it. */
|
|
32
41
|
export interface LibraryFile {
|
|
33
42
|
name: string;
|
|
34
43
|
path: string;
|
|
35
|
-
/** The
|
|
44
|
+
/** The extension, or `"file"` for a name without one. */
|
|
36
45
|
type: string;
|
|
37
|
-
|
|
46
|
+
/**
|
|
47
|
+
* The key of the collection the file is in (`pages`, or a collection's name), or `null` for a
|
|
48
|
+
* file in none: a template, a component, a media file, anything else.
|
|
49
|
+
*/
|
|
50
|
+
collection: string | null;
|
|
51
|
+
/** Whether the file is media by its extension — never an entry, whatever folder it is in. */
|
|
52
|
+
media: boolean;
|
|
38
53
|
ext: string;
|
|
39
54
|
/** Bytes, when the platform reported them. */
|
|
40
55
|
size?: number | undefined;
|
|
@@ -52,6 +67,13 @@ export interface LibraryFile {
|
|
|
52
67
|
* is in none.
|
|
53
68
|
*/
|
|
54
69
|
locale?: string | undefined;
|
|
70
|
+
/**
|
|
71
|
+
* Set when this row is one RECORD of a file-backed collection rather than a file: `path` is then
|
|
72
|
+
* the record's key (`prices.csv#3`), and `source` the file it is stored in, which is what opening
|
|
73
|
+
* it opens (`content/file-records.ts`); `row` is its place among the file's data rows, which is
|
|
74
|
+
* the row that file's grid lands on.
|
|
75
|
+
*/
|
|
76
|
+
record?: { source: string; row: number; fields: Readonly<Record<string, string>> } | undefined;
|
|
55
77
|
}
|
|
56
78
|
|
|
57
79
|
/** A directory the scan could not read. Its presence means the listing is INCOMPLETE, not empty. */
|
|
@@ -66,103 +88,117 @@ export interface LibraryScan {
|
|
|
66
88
|
failures: ScanFailure[];
|
|
67
89
|
}
|
|
68
90
|
|
|
69
|
-
// ───
|
|
91
|
+
// ─── The scan ────────────────────────────────────────────────────────────────
|
|
70
92
|
|
|
71
|
-
/** A
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
93
|
+
/** A project-relative path without `./`, backslashes or a trailing slash. */
|
|
94
|
+
function normalizeDir(path: string): string {
|
|
95
|
+
return path
|
|
96
|
+
.replaceAll("\\", "/")
|
|
97
|
+
.replace(/^(?:\.\/)+/, "")
|
|
98
|
+
.replace(/\/+$/, "");
|
|
77
99
|
}
|
|
78
100
|
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
];
|
|
87
|
-
|
|
88
|
-
/** The category keys, for a command's `enum` — so `library.setCategory` refuses an unknown one. */
|
|
89
|
-
export const LIBRARY_CATEGORY_KEYS: readonly string[] = LIBRARY_CATEGORIES.map((c) => c.key);
|
|
90
|
-
|
|
91
|
-
/** The category with this key, or undefined. */
|
|
92
|
-
export function libraryCategory(key: string): LibraryCategory | undefined {
|
|
93
|
-
return LIBRARY_CATEGORIES.find((c) => c.key === key);
|
|
101
|
+
/** Whether a `source` names one file (a CSV catalogue) rather than a directory to walk. */
|
|
102
|
+
function namesOneFile(source: string): boolean {
|
|
103
|
+
if (source.endsWith("/")) {
|
|
104
|
+
return false;
|
|
105
|
+
}
|
|
106
|
+
const base = source.slice(source.lastIndexOf("/") + 1);
|
|
107
|
+
return /\.[a-z\d]+$/i.test(base);
|
|
94
108
|
}
|
|
95
109
|
|
|
96
110
|
/**
|
|
97
|
-
* The
|
|
111
|
+
* The directories the Content scan walks: the conventional project directories that exist, plus
|
|
112
|
+
* every declared directory-collection `source` none of them already covers.
|
|
98
113
|
*
|
|
99
|
-
*
|
|
100
|
-
*
|
|
101
|
-
*
|
|
114
|
+
* The conventional list alone missed two real collections. A collection may live BESIDE the project
|
|
115
|
+
* (`sites/jxsuite.com` declares `content.docs.source: "../../docs"`), which no project directory
|
|
116
|
+
* can contain; and a collection created after the project opened (Add new › Collection) has its
|
|
117
|
+
* source under a `content/` that did not exist when the conventional list was read. Both were
|
|
118
|
+
* listed as empty, which is the lie {@link LibraryScan.failures} exists to end.
|
|
119
|
+
*
|
|
120
|
+
* A localized source is walked from the directory above its `{locale}` segment, which the walk
|
|
121
|
+
* descends into on its own. A file-backed source is a file, not a directory to walk.
|
|
122
|
+
*
|
|
123
|
+
* @param projectDirs The conventional directories present at the project root.
|
|
124
|
+
* @param config The project configuration whose `content` section declares the collections.
|
|
102
125
|
*/
|
|
103
|
-
export function
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
return "Media";
|
|
111
|
-
}
|
|
112
|
-
if (dir.startsWith("pages")) {
|
|
113
|
-
return "Pages";
|
|
114
|
-
}
|
|
115
|
-
if (dir.startsWith("layouts")) {
|
|
116
|
-
return "Layouts";
|
|
126
|
+
export function libraryScanDirs(
|
|
127
|
+
projectDirs: readonly string[],
|
|
128
|
+
config: ProjectConfig | null | undefined,
|
|
129
|
+
): readonly string[] {
|
|
130
|
+
const dirs: string[] = [];
|
|
131
|
+
for (const dir of projectDirs) {
|
|
132
|
+
dirs.push(normalizeDir(dir));
|
|
117
133
|
}
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
134
|
+
const extra: string[] = [];
|
|
135
|
+
/* SAFETY: `content` is the parser extension's section, collection name → entry object; only the
|
|
136
|
+
optional string `source` is read, and it is tested before use. */
|
|
137
|
+
const content = (config?.content ?? {}) as Record<string, ContentSectionEntry>;
|
|
138
|
+
for (const def of Object.values(content)) {
|
|
139
|
+
if (!isString(def.source) || def.source === "" || namesOneFile(def.source)) {
|
|
140
|
+
continue;
|
|
141
|
+
}
|
|
142
|
+
let source = normalizeDir(def.source);
|
|
143
|
+
const cut = source.indexOf(LOCALE_PLACEHOLDER);
|
|
144
|
+
if (cut !== -1) {
|
|
145
|
+
source = normalizeDir(source.slice(0, cut));
|
|
146
|
+
}
|
|
147
|
+
if (source === "" || source === ".") {
|
|
148
|
+
continue;
|
|
149
|
+
}
|
|
150
|
+
const covered = [...dirs, ...extra].some(
|
|
151
|
+
(dir) => source === dir || source.startsWith(`${dir}/`),
|
|
152
|
+
);
|
|
153
|
+
if (!covered) {
|
|
154
|
+
extra.push(source);
|
|
155
|
+
}
|
|
132
156
|
}
|
|
133
|
-
|
|
157
|
+
// The project's own list, unchanged, when every collection is already under it.
|
|
158
|
+
return extra.length === 0 ? projectDirs : [...projectDirs, ...extra];
|
|
134
159
|
}
|
|
135
160
|
|
|
136
161
|
/**
|
|
137
|
-
* The
|
|
162
|
+
* The collection a scanned file is an ENTRY of, or `null`.
|
|
163
|
+
*
|
|
164
|
+
* `collectionKeyOfPath` answers which collection's folder holds a file, which is the question a
|
|
165
|
+
* convert or a creation asks. A listing asks a narrower one: is this a file the collection's loader
|
|
166
|
+
* reads? A Markdown collection's folder may hold a `nav.json` beside its pages (the jxsuite docs
|
|
167
|
+
* do), and counting it made the Content home and the Site panel disagree about one collection. So a
|
|
168
|
+
* collection that DECLARES its format lists only the files carrying that format's extension; one
|
|
169
|
+
* that declares none is left to the loader's reading of the source, as before.
|
|
138
170
|
*
|
|
139
|
-
*
|
|
140
|
-
*
|
|
171
|
+
* Pages are judged the way the build's walk judges them: with `pageExtensions` given, a file under
|
|
172
|
+
* `pages/` is a page only when it carries one of them, so `index.json.bak` beside the home page is
|
|
173
|
+
* a file in the folder rather than a second page (it publishes nothing).
|
|
174
|
+
*
|
|
175
|
+
* @param path The project-relative file.
|
|
176
|
+
* @param pageExtensions The extensions the build routes (`routedPageExtensions`); omitted, a page's
|
|
177
|
+
* extension is not judged.
|
|
141
178
|
*/
|
|
142
|
-
export function
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
const content = (projectState?.projectConfig?.content ?? {}) as Record<
|
|
147
|
-
string,
|
|
148
|
-
ContentSectionEntry
|
|
149
|
-
>;
|
|
150
|
-
for (const [name, entry] of Object.entries(content)) {
|
|
151
|
-
if (!entry.source) {
|
|
152
|
-
continue;
|
|
153
|
-
}
|
|
154
|
-
const prefix = entry.source.replace(/^\.\//, "").replace(/\/$/, "");
|
|
155
|
-
if (filePath.startsWith(`${prefix}/`) || filePath === prefix) {
|
|
156
|
-
return name.charAt(0).toUpperCase() + name.slice(1);
|
|
157
|
-
}
|
|
179
|
+
export function entryCollectionOf(path: string, pageExtensions?: readonly string[]): string | null {
|
|
180
|
+
const key = collectionKeyOfPath(path);
|
|
181
|
+
if (key === null) {
|
|
182
|
+
return null;
|
|
158
183
|
}
|
|
159
|
-
|
|
184
|
+
if (key === PAGES_COLLECTION) {
|
|
185
|
+
return pageExtensions === undefined || isRoutedPageFile(path, pageExtensions) ? key : null;
|
|
186
|
+
}
|
|
187
|
+
const match = collectionForFile(path);
|
|
188
|
+
if (!match || match.name !== key || !match.def.format || match.ext === null) {
|
|
189
|
+
return key;
|
|
190
|
+
}
|
|
191
|
+
return path.toLowerCase().endsWith(match.ext.toLowerCase()) ? key : null;
|
|
160
192
|
}
|
|
161
193
|
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
194
|
+
/**
|
|
195
|
+
* Directory names never worth walking — a `node_modules` scan is minutes, not milliseconds.
|
|
196
|
+
*
|
|
197
|
+
* Not `build` or `dist`: the scan starts inside the project's own directories, never at its root
|
|
198
|
+
* where a build writes, and a collection is free to name a section `build` (the jxsuite docs file
|
|
199
|
+
* their CLI pages under `framework/build/`). Skipping the name dropped those entries silently.
|
|
200
|
+
*/
|
|
201
|
+
const SKIP_DIRS = new Set(["node_modules", ".git", ".jx", ".cache"]);
|
|
166
202
|
|
|
167
203
|
/**
|
|
168
204
|
* Walk one directory tree, collecting files and recording — never swallowing — what it could not
|
|
@@ -175,13 +211,18 @@ async function walk(
|
|
|
175
211
|
out: LibraryFile[],
|
|
176
212
|
failures: ScanFailure[],
|
|
177
213
|
i18n: ResolvedI18n | null,
|
|
214
|
+
optional = false,
|
|
215
|
+
pageExtensions?: readonly string[],
|
|
178
216
|
): Promise<void> {
|
|
179
217
|
let entries: DirEntry[];
|
|
180
218
|
try {
|
|
181
219
|
// Noted: the Library walks every media directory, so it is where most versions are learned.
|
|
182
220
|
entries = await notedListing(() => platform.listDirectory(dir));
|
|
183
221
|
} catch (error) {
|
|
184
|
-
|
|
222
|
+
// A declared collection's folder that does not exist yet is an empty collection, not a fault.
|
|
223
|
+
if (!optional) {
|
|
224
|
+
failures.push({ dir, error: errorMessage(error) });
|
|
225
|
+
}
|
|
185
226
|
return;
|
|
186
227
|
}
|
|
187
228
|
const subdirectories: string[] = [];
|
|
@@ -193,21 +234,23 @@ async function walk(
|
|
|
193
234
|
continue;
|
|
194
235
|
}
|
|
195
236
|
const ext = extensionOf(entry.name);
|
|
196
|
-
const category = categoryFor(entry.path, ext);
|
|
197
237
|
out.push({
|
|
198
|
-
|
|
238
|
+
collection: entryCollectionOf(entry.path, pageExtensions),
|
|
199
239
|
ext,
|
|
200
240
|
locale: servedLocaleOfPath(entry.path, i18n) ?? undefined,
|
|
241
|
+
media: MEDIA_EXTENSIONS.has(ext),
|
|
201
242
|
modified: entry.modified,
|
|
202
243
|
name: entry.name,
|
|
203
244
|
path: entry.path,
|
|
204
245
|
size: entry.size,
|
|
205
|
-
type:
|
|
246
|
+
type: ext || "file",
|
|
206
247
|
});
|
|
207
248
|
}
|
|
208
249
|
// Siblings in parallel, depth serialized per branch: the platform counts every call as in-flight,
|
|
209
250
|
// So `probe.idle()` already knows the scan is running without the Library declaring a source.
|
|
210
|
-
await Promise.all(
|
|
251
|
+
await Promise.all(
|
|
252
|
+
subdirectories.map((sub) => walk(sub, platform, out, failures, i18n, false, pageExtensions)),
|
|
253
|
+
);
|
|
211
254
|
}
|
|
212
255
|
|
|
213
256
|
/**
|
|
@@ -219,13 +262,19 @@ async function walk(
|
|
|
219
262
|
export async function scanLibrary(
|
|
220
263
|
dirs: readonly string[],
|
|
221
264
|
platform: Pick<StudioPlatform, "listDirectory">,
|
|
265
|
+
optional: ReadonlySet<string> = new Set(),
|
|
266
|
+
pageExtensions?: readonly string[],
|
|
222
267
|
): Promise<LibraryScan> {
|
|
223
268
|
const files: LibraryFile[] = [];
|
|
224
269
|
const failures: ScanFailure[] = [];
|
|
225
270
|
// Resolved ONCE for the whole walk. `resolveI18n` canonicalizes every declared tag through
|
|
226
271
|
// `Intl.Locale`, and a project with 300 pages would otherwise pay for that per file.
|
|
227
272
|
const { i18n } = resolveI18n(projectState?.projectConfig ?? {});
|
|
228
|
-
await Promise.all(
|
|
273
|
+
await Promise.all(
|
|
274
|
+
dirs.map((dir) =>
|
|
275
|
+
walk(dir, platform, files, failures, i18n, optional.has(dir), pageExtensions),
|
|
276
|
+
),
|
|
277
|
+
);
|
|
229
278
|
files.sort((a, b) => a.path.localeCompare(b.path));
|
|
230
279
|
return { failures, files };
|
|
231
280
|
}
|
|
@@ -233,25 +282,19 @@ export async function scanLibrary(
|
|
|
233
282
|
// ─── Filtering ───────────────────────────────────────────────────────────────
|
|
234
283
|
|
|
235
284
|
export interface LibraryFilter {
|
|
236
|
-
|
|
285
|
+
/** The collection key to keep: `pages`, or a declared collection's name. */
|
|
286
|
+
collection: string;
|
|
237
287
|
query: string;
|
|
238
288
|
/** A canonical tag, or "" for every language. Never a label — the labels are not unique. */
|
|
239
289
|
locale?: string;
|
|
240
290
|
}
|
|
241
291
|
|
|
242
|
-
/**
|
|
243
|
-
* Category, then text over name and path, then language. Returns the input array unchanged when
|
|
244
|
-
* nothing filters.
|
|
245
|
-
*/
|
|
292
|
+
/** Collection, then text over name and path, then language. */
|
|
246
293
|
export function filterLibrary(
|
|
247
294
|
files: readonly LibraryFile[],
|
|
248
295
|
filter: LibraryFilter,
|
|
249
296
|
): readonly LibraryFile[] {
|
|
250
|
-
let result = files;
|
|
251
|
-
const category = libraryCategory(filter.category);
|
|
252
|
-
if (category && category.key !== "all") {
|
|
253
|
-
result = result.filter((f) => f.category === category.label);
|
|
254
|
-
}
|
|
297
|
+
let result = files.filter((f) => f.collection === filter.collection);
|
|
255
298
|
const query = filter.query.trim().toLowerCase();
|
|
256
299
|
if (query) {
|
|
257
300
|
result = result.filter(
|
|
@@ -267,7 +310,8 @@ export function filterLibrary(
|
|
|
267
310
|
|
|
268
311
|
// ─── Layouts ─────────────────────────────────────────────────────────────────
|
|
269
312
|
|
|
270
|
-
|
|
313
|
+
/** The Content home's four views (studio.md §22.5), in the order its view switch draws them. */
|
|
314
|
+
export const LIBRARY_LAYOUTS = ["table", "cards", "calendar", "board"] as const;
|
|
271
315
|
|
|
272
316
|
export type LibraryLayout = (typeof LIBRARY_LAYOUTS)[number];
|
|
273
317
|
|
|
@@ -275,20 +319,16 @@ export const LIBRARY_LAYOUT_LABELS: Readonly<Record<LibraryLayout, string>> = {
|
|
|
275
319
|
board: "Board",
|
|
276
320
|
calendar: "Calendar",
|
|
277
321
|
cards: "Cards",
|
|
278
|
-
media: "Media",
|
|
279
322
|
table: "Table",
|
|
280
323
|
};
|
|
281
324
|
|
|
282
|
-
/** Whether a string names a layout — the guard behind `
|
|
325
|
+
/** Whether a string names a layout — the guard behind `content.setLayout`'s argument. */
|
|
283
326
|
export function isLibraryLayout(value: string): value is LibraryLayout {
|
|
284
327
|
return LIBRARY_LAYOUTS.some((layout) => layout === value);
|
|
285
328
|
}
|
|
286
329
|
|
|
287
|
-
/** Layouts that draw a live preview per item. Table and Board draw text
|
|
288
|
-
export const PREVIEW_LAYOUTS: ReadonlySet<LibraryLayout> = new Set<LibraryLayout>([
|
|
289
|
-
"cards",
|
|
290
|
-
"media",
|
|
291
|
-
]);
|
|
330
|
+
/** Layouts that draw a live preview per item. Table, Calendar and Board draw text. */
|
|
331
|
+
export const PREVIEW_LAYOUTS: ReadonlySet<LibraryLayout> = new Set<LibraryLayout>(["cards"]);
|
|
292
332
|
|
|
293
333
|
// ─── Derived axes (Calendar and Board) ───────────────────────────────────────
|
|
294
334
|
|
|
@@ -308,9 +348,10 @@ export function libraryDate(file: LibraryFile): string | null {
|
|
|
308
348
|
return prefix[1]!;
|
|
309
349
|
}
|
|
310
350
|
if (file.modified) {
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
351
|
+
// The day it was modified where the reader is, not in UTC (`utils/local-day.ts`).
|
|
352
|
+
const day = localDay(new Date(file.modified));
|
|
353
|
+
if (day) {
|
|
354
|
+
return day;
|
|
314
355
|
}
|
|
315
356
|
}
|
|
316
357
|
return null;
|
|
@@ -318,7 +359,7 @@ export function libraryDate(file: LibraryFile): string | null {
|
|
|
318
359
|
|
|
319
360
|
/**
|
|
320
361
|
* The locales this project DECLARES, canonical and in declaration order — the value space of the
|
|
321
|
-
*
|
|
362
|
+
* Content home's language facet and of `content.setLocale`'s `enum`.
|
|
322
363
|
*
|
|
323
364
|
* Read at call time rather than cached: `projectState` is a plain binding replaced wholesale on a
|
|
324
365
|
* project switch, so a cached list would describe the project before last.
|
|
@@ -330,10 +371,9 @@ export function projectLocales(): readonly string[] {
|
|
|
330
371
|
/**
|
|
331
372
|
* The locales actually PRESENT among these files, in the project's declaration order.
|
|
332
373
|
*
|
|
333
|
-
* Ordered by the project and not by the scan
|
|
334
|
-
*
|
|
335
|
-
*
|
|
336
|
-
* because {@link resolveI18n} guarantees it is `locales[0]`.
|
|
374
|
+
* Ordered by the project and not by the scan: a facet whose options reshuffle when a file is added
|
|
375
|
+
* is a facet nobody can build muscle memory for. Declaration order also puts the default locale
|
|
376
|
+
* first, because {@link resolveI18n} guarantees it is `locales[0]`.
|
|
337
377
|
*
|
|
338
378
|
* Only declared tags can appear — `localeOfPath` matches nothing else — so filtering the
|
|
339
379
|
* declaration through the presence set loses no file.
|
|
@@ -361,11 +401,14 @@ export interface LibraryDateGroups {
|
|
|
361
401
|
}
|
|
362
402
|
|
|
363
403
|
/** Calendar buckets, newest day first, plus the files no date could be derived for. */
|
|
364
|
-
export function groupByDate(
|
|
404
|
+
export function groupByDate(
|
|
405
|
+
files: readonly LibraryFile[],
|
|
406
|
+
dateOf: (file: LibraryFile) => string | null = libraryDate,
|
|
407
|
+
): LibraryDateGroups {
|
|
365
408
|
const byDay = new Map<string, LibraryFile[]>();
|
|
366
409
|
const undated: LibraryFile[] = [];
|
|
367
410
|
for (const file of files) {
|
|
368
|
-
const date =
|
|
411
|
+
const date = dateOf(file);
|
|
369
412
|
if (date === null) {
|
|
370
413
|
undated.push(file);
|
|
371
414
|
continue;
|
|
@@ -383,28 +426,33 @@ export function groupByDate(files: readonly LibraryFile[]): LibraryDateGroups {
|
|
|
383
426
|
return { days, undated };
|
|
384
427
|
}
|
|
385
428
|
|
|
386
|
-
/**
|
|
387
|
-
export function
|
|
429
|
+
/** The folder a file is in, project-relative: `pages/blog/a.md` → `pages/blog`. */
|
|
430
|
+
export function folderOf(path: string): string {
|
|
431
|
+
const slash = path.lastIndexOf("/");
|
|
432
|
+
return slash === -1 ? "." : path.slice(0, slash);
|
|
433
|
+
}
|
|
434
|
+
|
|
435
|
+
/**
|
|
436
|
+
* Board columns: one per folder the files are in, in path order.
|
|
437
|
+
*
|
|
438
|
+
* A collection is browsed one at a time, so a column per collection would be one column; the
|
|
439
|
+
* folders inside it (`pages/` and `pages/blog/`, a dated archive's years) are the grouping a
|
|
440
|
+
* collection already has on disk, and the one a Board can state without reading any file.
|
|
441
|
+
*/
|
|
442
|
+
export function groupByFolder(
|
|
388
443
|
files: readonly LibraryFile[],
|
|
389
444
|
): { group: string; files: LibraryFile[] }[] {
|
|
390
445
|
const byGroup = new Map<string, LibraryFile[]>();
|
|
391
446
|
for (const file of files) {
|
|
392
|
-
const
|
|
447
|
+
const folder = folderOf(file.path);
|
|
448
|
+
const bucket = byGroup.get(folder);
|
|
393
449
|
if (bucket) {
|
|
394
450
|
bucket.push(file);
|
|
395
451
|
} else {
|
|
396
|
-
byGroup.set(
|
|
452
|
+
byGroup.set(folder, [file]);
|
|
397
453
|
}
|
|
398
454
|
}
|
|
399
|
-
const order = LIBRARY_CATEGORIES.map((c) => c.label);
|
|
400
455
|
return [...byGroup.entries()]
|
|
401
456
|
.map(([group, groupFiles]) => ({ files: groupFiles, group }))
|
|
402
|
-
.toSorted((a, b) =>
|
|
403
|
-
const ai = order.indexOf(a.group);
|
|
404
|
-
const bi = order.indexOf(b.group);
|
|
405
|
-
if (ai === bi) {
|
|
406
|
-
return a.group.localeCompare(b.group);
|
|
407
|
-
}
|
|
408
|
-
return (ai === -1 ? order.length : ai) - (bi === -1 ? order.length : bi);
|
|
409
|
-
});
|
|
457
|
+
.toSorted((a, b) => a.group.localeCompare(b.group));
|
|
410
458
|
}
|