@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
|
@@ -1,15 +1,15 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* The
|
|
2
|
+
* The Content home's four views, as geometry and projections rather than as markup.
|
|
3
3
|
*
|
|
4
|
-
* All
|
|
5
|
-
* re-read. What differs is the geometry, and the geometry is data
|
|
6
|
-
* than five hand-rolled scroll containers: the pane hands each
|
|
7
|
-
* metric, so virtualization is a property of the
|
|
8
|
-
* remembered to virtualize.
|
|
4
|
+
* All four draw the SAME rows — one scan, one collection, one filter — so switching view is a
|
|
5
|
+
* repaint, never a re-read. What differs is the geometry, and the geometry is data
|
|
6
|
+
* ({@link LAYOUT_METRICS}) rather than five hand-rolled scroll containers: the pane hands each
|
|
7
|
+
* layout a window computed from the metric, so virtualization is a property of the Content home
|
|
8
|
+
* rather than of whichever layout someone remembered to virtualize.
|
|
9
9
|
*
|
|
10
|
-
* **Two of them are grouped, and grouped lists are bounded differently.** Table
|
|
11
|
-
*
|
|
12
|
-
*
|
|
10
|
+
* **Two of them are grouped, and grouped lists are bounded differently.** Table and Cards are flat
|
|
11
|
+
* and uniform, so they window. Calendar and Board are grouped, and a window over a grouped list
|
|
12
|
+
* either breaks the groups or needs variable-height measurement; both draw text only (no live
|
|
13
13
|
* preview, so an item costs one `<li>`), and each caps what it draws and SAYS what it left out. A
|
|
14
14
|
* layout that silently truncated would be the same class of lie as "No files found".
|
|
15
15
|
*
|
|
@@ -20,12 +20,111 @@
|
|
|
20
20
|
|
|
21
21
|
import { isImage } from "../files/media-upload";
|
|
22
22
|
import { previewFileSrc } from "../files/media-paths";
|
|
23
|
+
import { localDay } from "../utils/local-day";
|
|
23
24
|
import { localeLabel } from "@jxsuite/schema/locale";
|
|
24
|
-
import {
|
|
25
|
+
import { fileToRoute } from "@jxsuite/site/routes";
|
|
26
|
+
import { PAGES_COLLECTION } from "../content/content-collections";
|
|
27
|
+
import { groupByDate, groupByFolder, libraryDate } from "./library-model";
|
|
28
|
+
import { entryFieldOfKey } from "./library-source";
|
|
29
|
+
import type { EntryFieldColumn } from "./library-source";
|
|
30
|
+
import type { EntryFieldTexts } from "../content/entry-summaries";
|
|
25
31
|
import type { LibraryFile, LibraryLayout } from "./library-model";
|
|
26
32
|
import type { GridColumn, GridCellValue } from "../grid/grid-source";
|
|
27
33
|
import type { LibraryGroup, LibraryRow } from "../surfaces/library-pane";
|
|
28
34
|
|
|
35
|
+
/** What a collection entry says about itself, once read: its title, status and date. */
|
|
36
|
+
export interface EntryFacts {
|
|
37
|
+
title: string;
|
|
38
|
+
/** "Draft", "Published", or "" for a collection with no draft workflow. */
|
|
39
|
+
status: string;
|
|
40
|
+
/** `YYYY-MM-DD`, or "". */
|
|
41
|
+
date: string;
|
|
42
|
+
/** The schema's fields as list text, keyed by field name, when the entry has been read. */
|
|
43
|
+
fields?: EntryFieldTexts | undefined;
|
|
44
|
+
/** A page's template, by name ("Base", "None"), once the page has been read. */
|
|
45
|
+
template?: string | undefined;
|
|
46
|
+
/**
|
|
47
|
+
* The entry's picture, as a preview URL: the field its schema declares an image (a post's
|
|
48
|
+
* `cover`), from `content/entry-summaries.ts`'s `entryThumb`. "" or absent for none.
|
|
49
|
+
*/
|
|
50
|
+
thumb?: string | undefined;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
/** The field a Board groups a collection by when it has no draft workflow, and its heading. */
|
|
54
|
+
export interface BoardField {
|
|
55
|
+
name: string;
|
|
56
|
+
title: string;
|
|
57
|
+
/** The schema's `enum`, when it declares one: the order the columns stand in. */
|
|
58
|
+
order: readonly string[];
|
|
59
|
+
/** The field holds a list: an entry stands in the column of each of its values. */
|
|
60
|
+
list?: boolean | undefined;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
/**
|
|
64
|
+
* The values one field's list text holds: each item of a list field (its text joins them with
|
|
65
|
+
* commas, as a CSV cell does), or the one value of any other field. Blank values are none.
|
|
66
|
+
*/
|
|
67
|
+
export function fieldValues(text: string | undefined, list: boolean | undefined): string[] {
|
|
68
|
+
if (text === undefined || text.trim() === "") {
|
|
69
|
+
return [];
|
|
70
|
+
}
|
|
71
|
+
if (!list) {
|
|
72
|
+
return [text];
|
|
73
|
+
}
|
|
74
|
+
return text
|
|
75
|
+
.split(",")
|
|
76
|
+
.map((value) => value.trim())
|
|
77
|
+
.filter((value) => value !== "");
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
/** A Board with more columns than this is a list of singletons, not a grouping. */
|
|
81
|
+
const BOARD_FIELD_MAX_GROUPS = 12;
|
|
82
|
+
|
|
83
|
+
/**
|
|
84
|
+
* The field a Board groups by when the entries have no status: the first listed field the schema
|
|
85
|
+
* gives an `enum`, else the first whose values actually repeat. A menu grouped by its `course` is a
|
|
86
|
+
* board; a menu grouped by its one folder is one column, which says nothing. `null` when no field
|
|
87
|
+
* groups the entries (every value unique, or every value the same), so the Board falls back to
|
|
88
|
+
* folders.
|
|
89
|
+
*
|
|
90
|
+
* @param fields The listed fields, in order ({@link entryFieldColumns}).
|
|
91
|
+
* @param enums Each field's declared `enum`, where it has one.
|
|
92
|
+
* @param facts What each entry says, as read so far.
|
|
93
|
+
*/
|
|
94
|
+
export function boardFieldOf(
|
|
95
|
+
fields: readonly EntryFieldColumn[],
|
|
96
|
+
enums: ReadonlyMap<string, readonly string[]>,
|
|
97
|
+
facts: readonly (EntryFacts | undefined)[],
|
|
98
|
+
): BoardField | null {
|
|
99
|
+
const declared = fields.find((field) => enums.has(field.name));
|
|
100
|
+
if (declared) {
|
|
101
|
+
return { ...declared, order: enums.get(declared.name)! };
|
|
102
|
+
}
|
|
103
|
+
for (const field of fields) {
|
|
104
|
+
if (field.measure) {
|
|
105
|
+
continue;
|
|
106
|
+
}
|
|
107
|
+
// A list field's every item is a value: `Patios, Stone` is two, not one string.
|
|
108
|
+
const values = facts.flatMap((entry) => fieldValues(entry?.fields?.[field.name], field.list));
|
|
109
|
+
const distinct = new Set(values).size;
|
|
110
|
+
if (distinct >= 2 && distinct < values.length && distinct <= BOARD_FIELD_MAX_GROUPS) {
|
|
111
|
+
return { ...field, order: [] };
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
return null;
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
/** A file's entry facts, or `undefined` for a file that is no entry or has not been read yet. */
|
|
118
|
+
export type EntryFactsOf = (file: LibraryFile) => EntryFacts | undefined;
|
|
119
|
+
|
|
120
|
+
/** Facts by path. Empty for Pages, and for a collection whose entries are still being read. */
|
|
121
|
+
export function entryFactsFrom(facts: ReadonlyMap<string, EntryFacts>): EntryFactsOf {
|
|
122
|
+
return (file) => facts.get(file.path);
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
/** No file has facts. */
|
|
126
|
+
const NO_FACTS: EntryFactsOf = entryFactsFrom(new Map());
|
|
127
|
+
|
|
29
128
|
/** The geometry a layout scrolls at. `itemWidth` of 0 means one item per row. */
|
|
30
129
|
export interface LayoutMetric {
|
|
31
130
|
/** Height of one row of items, in CSS pixels — the unit the window counts in. */
|
|
@@ -39,7 +138,7 @@ export interface LayoutMetric {
|
|
|
39
138
|
/**
|
|
40
139
|
* Per-layout geometry.
|
|
41
140
|
*
|
|
42
|
-
* These are nominal sizes that must match the
|
|
141
|
+
* These are nominal sizes that must match the Content home surface's own style block. They are
|
|
43
142
|
* approximate on purpose: the window's job is to keep the rendered count proportional to the
|
|
44
143
|
* viewport, and being one row out costs one row of overscan, not correctness.
|
|
45
144
|
*/
|
|
@@ -47,7 +146,6 @@ export const LAYOUT_METRICS: Readonly<Record<LibraryLayout, LayoutMetric>> = {
|
|
|
47
146
|
board: { itemWidth: 0, rowHeight: 0, windowed: false },
|
|
48
147
|
calendar: { itemWidth: 0, rowHeight: 0, windowed: false },
|
|
49
148
|
cards: { itemWidth: 200, rowHeight: 194, windowed: true },
|
|
50
|
-
media: { itemWidth: 132, rowHeight: 132, windowed: true },
|
|
51
149
|
table: { itemWidth: 0, rowHeight: 32, windowed: true },
|
|
52
150
|
};
|
|
53
151
|
|
|
@@ -86,20 +184,29 @@ export function formatSize(size: number | undefined): string {
|
|
|
86
184
|
return `${value < 10 ? value.toFixed(1) : Math.round(value)} ${units[unit]}`;
|
|
87
185
|
}
|
|
88
186
|
|
|
89
|
-
/**
|
|
187
|
+
/**
|
|
188
|
+
* An ISO timestamp as the local `YYYY-MM-DD` it fell on, or "" when there is none. Never invents
|
|
189
|
+
* "just now".
|
|
190
|
+
*/
|
|
90
191
|
export function formatModified(modified: string | undefined): string {
|
|
91
|
-
|
|
92
|
-
return "";
|
|
93
|
-
}
|
|
94
|
-
const parsed = new Date(modified);
|
|
95
|
-
return Number.isNaN(parsed.getTime()) ? "" : parsed.toISOString().slice(0, 10);
|
|
192
|
+
return modified ? localDay(new Date(modified)) : "";
|
|
96
193
|
}
|
|
97
194
|
|
|
98
|
-
/** The text one table cell shows for a file. */
|
|
99
|
-
export function cellText(file: LibraryFile, field: string): string {
|
|
195
|
+
/** The text one table cell shows for a file, and for an entry what it says about itself. */
|
|
196
|
+
export function cellText(file: LibraryFile, field: string, entry?: EntryFacts): string {
|
|
100
197
|
switch (field) {
|
|
101
|
-
case "
|
|
102
|
-
return
|
|
198
|
+
case "date": {
|
|
199
|
+
return entry?.date ?? "";
|
|
200
|
+
}
|
|
201
|
+
case "status": {
|
|
202
|
+
return entry?.status ?? "";
|
|
203
|
+
}
|
|
204
|
+
case "template": {
|
|
205
|
+
return entry?.template ?? "";
|
|
206
|
+
}
|
|
207
|
+
case "title": {
|
|
208
|
+
// Until the entry is read, the file name: the title is never blank while it loads.
|
|
209
|
+
return entry?.title ?? file.name;
|
|
103
210
|
}
|
|
104
211
|
case "locale": {
|
|
105
212
|
// The autonym, not the tag: the column exists so a reader can find their own language in it,
|
|
@@ -113,7 +220,8 @@ export function cellText(file: LibraryFile, field: string): string {
|
|
|
113
220
|
return file.name;
|
|
114
221
|
}
|
|
115
222
|
case "path": {
|
|
116
|
-
|
|
223
|
+
// A record is stored in its collection's file; its key (`prices.csv#3`) is no path.
|
|
224
|
+
return file.record?.source ?? file.path;
|
|
117
225
|
}
|
|
118
226
|
case "size": {
|
|
119
227
|
return formatSize(file.size);
|
|
@@ -121,8 +229,13 @@ export function cellText(file: LibraryFile, field: string): string {
|
|
|
121
229
|
case "type": {
|
|
122
230
|
return file.type;
|
|
123
231
|
}
|
|
232
|
+
case "url": {
|
|
233
|
+
// Only a page has a URL of its own; an entry's is its collection page's, read elsewhere.
|
|
234
|
+
return file.collection === PAGES_COLLECTION ? fileToRoute(file.path).urlPattern : "";
|
|
235
|
+
}
|
|
124
236
|
default: {
|
|
125
|
-
|
|
237
|
+
const own = entryFieldOfKey(field);
|
|
238
|
+
return own === null ? "" : (entry?.fields?.[own] ?? "");
|
|
126
239
|
}
|
|
127
240
|
}
|
|
128
241
|
}
|
|
@@ -134,40 +247,56 @@ export function cellTextOf(value: GridCellValue | undefined): string {
|
|
|
134
247
|
|
|
135
248
|
// ─── Rows ────────────────────────────────────────────────────────────────────
|
|
136
249
|
|
|
137
|
-
/** The four categories whose files are documents the runtime can render a preview of. */
|
|
138
|
-
const PREVIEWABLE = new Set(["Components", "Content", "Layouts", "Pages"]);
|
|
139
|
-
|
|
140
250
|
/**
|
|
141
251
|
* One file, as the surface reads it.
|
|
142
252
|
*
|
|
143
|
-
* `live` is whether this layout may draw a real document render at all: Cards may,
|
|
144
|
-
* does. Getting that from the caller rather than from the file is what keeps a
|
|
145
|
-
*
|
|
146
|
-
* Media layout exists to avoid.
|
|
253
|
+
* `live` is whether this layout may draw a real document render at all: Cards may, Table never
|
|
254
|
+
* does. Getting that from the caller rather than from the file is what keeps a row cheap. An image
|
|
255
|
+
* is drawn as itself; every other file in a collection is a document the runtime can render.
|
|
147
256
|
*
|
|
148
257
|
* @param file The scanned file.
|
|
149
258
|
* @param columns The Table's columns, from the grid source. Empty for a layout with no cells.
|
|
150
259
|
* @param live Whether a previewable document may claim the `doc` island.
|
|
260
|
+
* @param entry What the file says about itself, when it is a collection entry that has been read.
|
|
151
261
|
*/
|
|
152
262
|
export function libraryRow(
|
|
153
263
|
file: LibraryFile,
|
|
154
264
|
columns: readonly GridColumn[],
|
|
155
265
|
live: boolean,
|
|
266
|
+
entry?: EntryFacts,
|
|
156
267
|
): LibraryRow {
|
|
157
268
|
const image = isImage(file.ext);
|
|
269
|
+
// An entry is shown by its own picture (its `cover`), not by a render of its body text.
|
|
270
|
+
const thumb = entry?.thumb ?? "";
|
|
158
271
|
return {
|
|
159
|
-
|
|
160
|
-
|
|
272
|
+
// A record is a row of a file, not a document the runtime can render.
|
|
273
|
+
art:
|
|
274
|
+
image || thumb !== ""
|
|
275
|
+
? "image"
|
|
276
|
+
: live && file.collection !== null && !file.record
|
|
277
|
+
? "doc"
|
|
278
|
+
: "glyph",
|
|
279
|
+
cells: columns.map((column) => ({
|
|
280
|
+
field: column.field,
|
|
281
|
+
text: cellText(file, column.field, entry),
|
|
282
|
+
})),
|
|
161
283
|
meta: file.type,
|
|
162
|
-
name: file.name,
|
|
284
|
+
name: entry?.title ?? file.name,
|
|
163
285
|
path: file.path,
|
|
164
|
-
src: image ? previewFileSrc(file.path) :
|
|
286
|
+
src: image ? previewFileSrc(file.path) : thumb,
|
|
165
287
|
};
|
|
166
288
|
}
|
|
167
289
|
|
|
168
|
-
/** The text-only row both grouped layouts draw: a name, and the path it opens. */
|
|
169
|
-
function nameRow(file: LibraryFile): LibraryRow {
|
|
170
|
-
return {
|
|
290
|
+
/** The text-only row both grouped layouts draw: a name (an entry's title), and the path it opens. */
|
|
291
|
+
function nameRow(file: LibraryFile, entry?: EntryFacts): LibraryRow {
|
|
292
|
+
return {
|
|
293
|
+
art: "glyph",
|
|
294
|
+
cells: [],
|
|
295
|
+
meta: file.type,
|
|
296
|
+
name: entry?.title ?? file.name,
|
|
297
|
+
path: file.path,
|
|
298
|
+
src: "",
|
|
299
|
+
};
|
|
171
300
|
}
|
|
172
301
|
|
|
173
302
|
// ─── Calendar ────────────────────────────────────────────────────────────────
|
|
@@ -181,19 +310,27 @@ export interface CalendarView {
|
|
|
181
310
|
/**
|
|
182
311
|
* Calendar: one section per day, newest first, plus an explicit account of what it did not place.
|
|
183
312
|
*
|
|
184
|
-
* A file's day
|
|
185
|
-
* "now". Files with
|
|
186
|
-
* calendar that invents dates is worse than one that admits it cannot
|
|
313
|
+
* A file's day is an entry's own date field when it has one, else a `YYYY-MM-DD` filename prefix or
|
|
314
|
+
* the filesystem's mtime — never "now". Files with none are listed under "No date" rather than
|
|
315
|
+
* parked on today, because a calendar that invents dates is worse than one that admits it cannot
|
|
316
|
+
* place a file.
|
|
187
317
|
*
|
|
318
|
+
* @param factsOf What each entry says about itself; its `date` wins over the file's.
|
|
188
319
|
* @returns The day sections, and the sentence naming the older days it did not draw.
|
|
189
320
|
*/
|
|
190
|
-
export function calendarView(
|
|
191
|
-
|
|
321
|
+
export function calendarView(
|
|
322
|
+
files: readonly LibraryFile[],
|
|
323
|
+
factsOf: EntryFactsOf = NO_FACTS,
|
|
324
|
+
): CalendarView {
|
|
325
|
+
const { days, undated } = groupByDate(files, (file) => {
|
|
326
|
+
const own = factsOf(file)?.date;
|
|
327
|
+
return own || libraryDate(file);
|
|
328
|
+
});
|
|
192
329
|
const shown = days.slice(0, CALENDAR_DAY_LIMIT);
|
|
193
330
|
const hiddenDays = days.length - shown.length;
|
|
194
331
|
const groups: LibraryGroup[] = shown.map((day) => ({
|
|
195
332
|
count: "",
|
|
196
|
-
files: day.files.map((file) => nameRow(file)),
|
|
333
|
+
files: day.files.map((file) => nameRow(file, factsOf(file))),
|
|
197
334
|
id: day.date,
|
|
198
335
|
note: "",
|
|
199
336
|
noteState: "hidden",
|
|
@@ -203,7 +340,7 @@ export function calendarView(files: readonly LibraryFile[]): CalendarView {
|
|
|
203
340
|
if (undated.length > 0) {
|
|
204
341
|
groups.push({
|
|
205
342
|
count: "",
|
|
206
|
-
files: undated.slice(0, BOARD_COLUMN_LIMIT).map((file) => nameRow(file)),
|
|
343
|
+
files: undated.slice(0, BOARD_COLUMN_LIMIT).map((file) => nameRow(file, factsOf(file))),
|
|
207
344
|
/* Not a date, and it must never collide with one: the section's identity is what keeps its
|
|
208
345
|
node across a repaint, and a day is always `YYYY-MM-DD`, so a leading underscore pair cannot be one. */
|
|
209
346
|
id: "__undated",
|
|
@@ -224,13 +361,90 @@ export function calendarView(files: readonly LibraryFile[]): CalendarView {
|
|
|
224
361
|
|
|
225
362
|
// ─── Board ───────────────────────────────────────────────────────────────────
|
|
226
363
|
|
|
227
|
-
/**
|
|
228
|
-
|
|
229
|
-
|
|
364
|
+
/** The order a status Board's columns stand in: the work in progress first. */
|
|
365
|
+
const STATUS_ORDER = ["Draft", "Published"];
|
|
366
|
+
|
|
367
|
+
/** Group entries by their status, in {@link STATUS_ORDER}, then any other status by name. */
|
|
368
|
+
function groupByStatus(
|
|
369
|
+
files: readonly LibraryFile[],
|
|
370
|
+
factsOf: EntryFactsOf,
|
|
371
|
+
): { group: string; files: LibraryFile[] }[] {
|
|
372
|
+
const byStatus = new Map<string, LibraryFile[]>();
|
|
373
|
+
for (const file of files) {
|
|
374
|
+
const status = factsOf(file)?.status || "No status";
|
|
375
|
+
const bucket = byStatus.get(status);
|
|
376
|
+
if (bucket) {
|
|
377
|
+
bucket.push(file);
|
|
378
|
+
} else {
|
|
379
|
+
byStatus.set(status, [file]);
|
|
380
|
+
}
|
|
381
|
+
}
|
|
382
|
+
const rank = (status: string) => {
|
|
383
|
+
const at = STATUS_ORDER.indexOf(status);
|
|
384
|
+
return at === -1 ? STATUS_ORDER.length : at;
|
|
385
|
+
};
|
|
386
|
+
return [...byStatus.entries()]
|
|
387
|
+
.map(([group, grouped]) => ({ files: grouped, group }))
|
|
388
|
+
.toSorted((a, b) => rank(a.group) - rank(b.group) || a.group.localeCompare(b.group));
|
|
389
|
+
}
|
|
390
|
+
|
|
391
|
+
/** Group entries by one field's value, in the schema's `enum` order, then any other value by name. */
|
|
392
|
+
function groupByField(
|
|
393
|
+
files: readonly LibraryFile[],
|
|
394
|
+
factsOf: EntryFactsOf,
|
|
395
|
+
field: BoardField,
|
|
396
|
+
): { group: string; files: LibraryFile[] }[] {
|
|
397
|
+
const none = `No ${field.title.toLowerCase()}`;
|
|
398
|
+
const byValue = new Map<string, LibraryFile[]>();
|
|
399
|
+
for (const file of files) {
|
|
400
|
+
const values = fieldValues(factsOf(file)?.fields?.[field.name], field.list);
|
|
401
|
+
// An entry tagged twice stands in both columns: each is the set of entries with that tag.
|
|
402
|
+
for (const value of values.length === 0 ? [none] : new Set(values)) {
|
|
403
|
+
const bucket = byValue.get(value);
|
|
404
|
+
if (bucket) {
|
|
405
|
+
bucket.push(file);
|
|
406
|
+
} else {
|
|
407
|
+
byValue.set(value, [file]);
|
|
408
|
+
}
|
|
409
|
+
}
|
|
410
|
+
}
|
|
411
|
+
const rank = (value: string) => {
|
|
412
|
+
if (value === none) {
|
|
413
|
+
return Number.MAX_SAFE_INTEGER;
|
|
414
|
+
}
|
|
415
|
+
const at = field.order.indexOf(value);
|
|
416
|
+
return at === -1 ? field.order.length : at;
|
|
417
|
+
};
|
|
418
|
+
return [...byValue.entries()]
|
|
419
|
+
.map(([group, grouped]) => ({ files: grouped, group }))
|
|
420
|
+
.toSorted((a, b) => rank(a.group) - rank(b.group) || a.group.localeCompare(b.group));
|
|
421
|
+
}
|
|
422
|
+
|
|
423
|
+
/**
|
|
424
|
+
* Board: one column per status when the collection's entries have one (Draft, Published), else one
|
|
425
|
+
* per value of the field the collection is grouped by ({@link boardFieldOf}: a menu's `course`),
|
|
426
|
+
* else one per folder present; each capped and each stating its own total. A flat collection
|
|
427
|
+
* grouped by folder is one column, which says nothing, so a field is preferred to it.
|
|
428
|
+
*
|
|
429
|
+
* @param factsOf What each entry says about itself.
|
|
430
|
+
* @param field The field to group by when the entries have no status.
|
|
431
|
+
*/
|
|
432
|
+
export function boardView(
|
|
433
|
+
files: readonly LibraryFile[],
|
|
434
|
+
factsOf: EntryFactsOf = NO_FACTS,
|
|
435
|
+
field: BoardField | null = null,
|
|
436
|
+
): LibraryGroup[] {
|
|
437
|
+
const byStatus = files.some((file) => (factsOf(file)?.status ?? "") !== "");
|
|
438
|
+
const groups = byStatus
|
|
439
|
+
? groupByStatus(files, factsOf)
|
|
440
|
+
: field
|
|
441
|
+
? groupByField(files, factsOf, field)
|
|
442
|
+
: groupByFolder(files);
|
|
443
|
+
return groups.map((group) => {
|
|
230
444
|
const hidden = group.files.length - BOARD_COLUMN_LIMIT;
|
|
231
445
|
return {
|
|
232
446
|
count: String(group.files.length),
|
|
233
|
-
files: group.files.slice(0, BOARD_COLUMN_LIMIT).map((file) => nameRow(file)),
|
|
447
|
+
files: group.files.slice(0, BOARD_COLUMN_LIMIT).map((file) => nameRow(file, factsOf(file))),
|
|
234
448
|
id: group.group,
|
|
235
449
|
note: hidden > 0 ? `${hidden} more — switch to Table to see them.` : "",
|
|
236
450
|
noteState: hidden > 0 ? "shown" : "hidden",
|