@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.
Files changed (522) hide show
  1. package/README.md +5 -5
  2. package/dist/chunks/2020-5wtzce5g.js +4 -0
  3. package/dist/chunks/adapter-5tphg7xe.js +4 -0
  4. package/dist/chunks/add-new-flow-psym14sn.js +4 -0
  5. package/dist/chunks/cf-account-picker-haqazq5r.js +4 -0
  6. package/dist/chunks/cf-settings-h2wrh6hq.js +4 -0
  7. package/dist/chunks/{color-area-0fj8a4ga.js → color-area-6rbra5dy.js} +2 -2
  8. package/dist/chunks/{color-field-xch8kx2g.js → color-field-gy56c94g.js} +3 -3
  9. package/dist/chunks/color-m7r1vk54.js +4 -0
  10. package/dist/chunks/{color-slider-jxd8v350.js → color-slider-sqqdyf6c.js} +2 -2
  11. package/dist/chunks/{combobox-p0efwjke.js → combobox-72h32ejk.js} +3 -3
  12. package/dist/chunks/components-r22xca09.js +4 -0
  13. package/dist/chunks/content-source-mmppmcyg.js +4 -0
  14. package/dist/chunks/convert-to-repeater-he70fc2b.js +4 -0
  15. package/dist/chunks/editor-ccd9jwsa.js +4 -0
  16. package/dist/chunks/entry-commands-6qxz9e8p.js +4 -0
  17. package/dist/chunks/extension-sections-0egb88dm.js +4 -0
  18. package/dist/chunks/file-ops-qnab36ek.js +4 -0
  19. package/dist/chunks/files-rcn56qvm.js +4 -0
  20. package/dist/chunks/format-host-yxz0kjjs.js +4 -0
  21. package/dist/chunks/fs-events-d1qxq4z4.js +4 -0
  22. package/dist/chunks/grid-open-4z1g062t.js +4 -0
  23. package/dist/chunks/{grid-view-d2wq9ezg.js → grid-view-qg1b5eqx.js} +25 -25
  24. package/dist/chunks/{icons-pnfz478q.js → icons-63bjtbs7.js} +2 -2
  25. package/dist/chunks/{iframe-entry-jdcktez8.js → iframe-entry-2zggzajv.js} +4 -4
  26. package/dist/chunks/{iframe-entry-zap785cw.js → iframe-entry-76j8vwwx.js} +4 -4
  27. package/dist/chunks/iframe-entry-99nr5zfb.js +5 -0
  28. package/dist/chunks/{iframe-entry-x0ygf2yr.js → iframe-entry-pkgmcgp0.js} +4 -4
  29. package/dist/chunks/iframe-host-ssv7kyj0.js +4 -0
  30. package/dist/chunks/{index-zpjmzqfk.js → index-32eqzv1k.js} +3 -3
  31. package/dist/chunks/index-f0jn7nnp.js +4 -0
  32. package/dist/chunks/{javascript-m54mnwp6.js → javascript-pjp734q4.js} +3 -3
  33. package/dist/chunks/jsonMode-njkvsa02.js +13 -0
  34. package/dist/chunks/jx-validate-ttasrbh7.js +4 -0
  35. package/dist/chunks/layers-bgyr11tr.js +4 -0
  36. package/dist/chunks/layers-panel-7ez66zeq.js +4 -0
  37. package/dist/chunks/{listbox-e74qjyq6.js → listbox-c421cf8c.js} +2 -2
  38. package/dist/chunks/lit-html-v9gh687x.js +4 -0
  39. package/dist/chunks/media-library-sq468wts.js +4 -0
  40. package/dist/chunks/media-picker-shfe59pt.js +4 -0
  41. package/dist/chunks/{menu-n6yzswmy.js → menu-bdpzbfvs.js} +2 -2
  42. package/dist/chunks/{monaco-binding-7gx83x3r.js → monaco-binding-vq1hgnn0.js} +3 -3
  43. package/dist/chunks/monaco-buffer-3afgwvbp.js +4 -0
  44. package/dist/chunks/monaco-setup-xrd2cbkp.js +4 -0
  45. package/dist/chunks/notify-kzrjr3fv.js +4 -0
  46. package/dist/chunks/parse-v77xtwv7.js +4 -0
  47. package/dist/chunks/platform-7v4rtd7m.js +4 -0
  48. package/dist/chunks/popover-b89sfej7.js +4 -0
  49. package/dist/chunks/publish-panel-2z9gw8ee.js +4 -0
  50. package/dist/chunks/publish-quick-qx2455cj.js +4 -0
  51. package/dist/chunks/publish-workspace-wrc1dgwx.js +4 -0
  52. package/dist/chunks/quick-search-n0t0eqxb.js +4 -0
  53. package/dist/chunks/references-9547rg5s.js +4 -0
  54. package/dist/chunks/right-panel-wsgnr9pn.js +4 -0
  55. package/dist/chunks/source-control-kwktr9y6.js +4 -0
  56. package/dist/chunks/{split-n2gfpm5m.js → split-c9zfdgxf.js} +2 -2
  57. package/dist/chunks/studio-03ct6yfv.js +9 -0
  58. package/dist/chunks/studio-07rcfje3.js +5 -0
  59. package/dist/chunks/studio-3e54qh39.js +7 -0
  60. package/dist/chunks/studio-3exxhz5g.js +5 -0
  61. package/dist/chunks/studio-3q40e3rj.js +5 -0
  62. package/dist/chunks/studio-3qeh9t0h.js +6 -0
  63. package/dist/chunks/studio-3qqjeep5.js +6 -0
  64. package/dist/chunks/studio-43sd2mam.js +4 -0
  65. package/dist/chunks/studio-4hp8pkyt.js +5 -0
  66. package/dist/chunks/studio-58xg6j2q.js +9 -0
  67. package/dist/chunks/studio-5g0rprdt.js +7 -0
  68. package/dist/chunks/{studio-2j1cb95x.js → studio-6m380wp7.js} +4 -4
  69. package/dist/chunks/studio-80jyh1xh.js +4 -0
  70. package/dist/chunks/studio-83mk4bgg.js +9 -0
  71. package/dist/chunks/{studio-v0jzqdjm.js → studio-881z1xrx.js} +4 -4
  72. package/dist/chunks/studio-8m0y2qe7.js +5 -0
  73. package/dist/chunks/{studio-d81xfh1g.js → studio-8tr6cfrc.js} +4 -4
  74. package/dist/chunks/studio-8vcvfs7r.js +6 -0
  75. package/dist/chunks/studio-9tmebf0s.js +5 -0
  76. package/dist/chunks/studio-a2bvaptz.js +5 -0
  77. package/dist/chunks/studio-b7y5mr30.js +5 -0
  78. package/dist/chunks/studio-bavb31r0.js +5 -0
  79. package/dist/chunks/{studio-dgz8d0c1.js → studio-bbe4c90a.js} +4 -4
  80. package/dist/chunks/studio-c05wdnt3.js +5 -0
  81. package/dist/chunks/studio-ccv2svc6.js +5 -0
  82. package/dist/chunks/studio-d5grtb9e.js +16 -0
  83. package/dist/chunks/studio-df0baea9.js +5 -0
  84. package/dist/chunks/studio-dgk4dqtx.js +7 -0
  85. package/dist/chunks/studio-e1g64q43.js +5 -0
  86. package/dist/chunks/studio-ed1hp6zf.js +6 -0
  87. package/dist/chunks/studio-ed3xx40h.js +7 -0
  88. package/dist/chunks/studio-f14e1zdj.js +5 -0
  89. package/dist/chunks/studio-fbhxxc5f.js +5 -0
  90. package/dist/chunks/studio-fyh0jc96.js +5 -0
  91. package/dist/chunks/studio-gcxk20n7.js +5 -0
  92. package/dist/chunks/studio-jaaz8ce9.js +5 -0
  93. package/dist/chunks/{studio-90pq9km1.js → studio-jcnsdaep.js} +4 -4
  94. package/dist/chunks/studio-jsgf2q5k.js +7 -0
  95. package/dist/chunks/{studio-0q988f9w.js → studio-k3xxbagr.js} +3 -3
  96. package/dist/chunks/{studio-5ve6bbep.js → studio-k7evxqh4.js} +4 -4
  97. package/dist/chunks/studio-kt3pjkwd.js +5 -0
  98. package/dist/chunks/studio-m8g16bgz.js +5 -0
  99. package/dist/chunks/studio-mn0476ag.js +5 -0
  100. package/dist/chunks/studio-mx1smyq0.js +5 -0
  101. package/dist/chunks/studio-n0c5h6mf.js +5 -0
  102. package/dist/chunks/{studio-485046te.js → studio-nh6d342n.js} +7 -7
  103. package/dist/chunks/studio-nqxqf8p2.js +4 -0
  104. package/dist/chunks/studio-p4nrkvqr.js +5 -0
  105. package/dist/chunks/{studio-1fxkaaea.js → studio-pbxa5fpc.js} +4 -4
  106. package/dist/chunks/studio-pgmvdv7z.js +7 -0
  107. package/dist/chunks/studio-ph84avkf.js +5 -0
  108. package/dist/chunks/{studio-tq0rtfwj.js → studio-q0mvbaq6.js} +4 -4
  109. package/dist/chunks/studio-q0tccd43.js +5 -0
  110. package/dist/chunks/studio-q7rtx6zq.js +14 -0
  111. package/dist/chunks/{studio-a3g98wjr.js → studio-qgh13jtz.js} +4 -4
  112. package/dist/chunks/studio-qmn1xc24.js +5 -0
  113. package/dist/chunks/studio-qwdqwkj0.js +5 -0
  114. package/dist/chunks/studio-r5qy30vx.js +5 -0
  115. package/dist/chunks/studio-rj9eamf8.js +5 -0
  116. package/dist/chunks/studio-rptgsk96.js +5 -0
  117. package/dist/chunks/studio-rthyg42z.js +928 -0
  118. package/dist/chunks/studio-s19tp1xr.js +5 -0
  119. package/dist/chunks/studio-s32578pn.js +5 -0
  120. package/dist/chunks/studio-svb7yyve.js +5 -0
  121. package/dist/chunks/studio-syreb644.js +5 -0
  122. package/dist/chunks/studio-tf9jryb1.js +10 -0
  123. package/dist/chunks/studio-tfkznv39.js +5 -0
  124. package/dist/chunks/studio-tft6r105.js +5 -0
  125. package/dist/chunks/studio-txf2kysx.js +5 -0
  126. package/dist/chunks/studio-v8867ddv.js +12 -0
  127. package/dist/chunks/studio-vxq7fcvv.js +5 -0
  128. package/dist/chunks/studio-w4rz9hdk.js +5 -0
  129. package/dist/chunks/studio-wbcjbhy1.js +9 -0
  130. package/dist/chunks/studio-wc649wss.js +5 -0
  131. package/dist/chunks/studio-wys23mxz.js +5 -0
  132. package/dist/chunks/studio-x1x167jh.js +5 -0
  133. package/dist/chunks/studio-x9hsze61.js +5 -0
  134. package/dist/chunks/studio-y0n7yxea.js +9 -0
  135. package/dist/chunks/studio-y3ahhdpx.js +5 -0
  136. package/dist/chunks/studio-z97c48fk.js +5 -0
  137. package/dist/chunks/studio-zat62m0c.js +5 -0
  138. package/dist/chunks/studio-zcd2e7yz.js +5 -0
  139. package/dist/chunks/studio-zz9qe3rw.js +64 -0
  140. package/dist/chunks/toast-1gv0h53h.js +4 -0
  141. package/dist/chunks/{toast-host-ke5z4ng7.js → toast-host-1yg5ar8d.js} +3 -3
  142. package/dist/chunks/{tooltip-5v8ngwj2.js → tooltip-yypz28gq.js} +3 -3
  143. package/dist/chunks/{tree-mdq3v5cw.js → tree-9xa4hm7n.js} +2 -2
  144. package/dist/chunks/tsMode-epyfz1hv.js +14 -0
  145. package/dist/chunks/workspace-dz7nxfhv.js +4 -0
  146. package/dist/chunks/workspace-home-xsd7hkjw.js +4 -0
  147. package/dist/chunks/{ws-client-nze0k6mv.js → ws-client-bv552sfx.js} +3 -3
  148. package/dist/iframe-entry.js +20 -16
  149. package/dist/manifest.json +77 -63
  150. package/dist/studio.js +103 -104
  151. package/dist/workers/ts.worker.js +3 -3
  152. package/package.json +12 -11
  153. package/src/browse/component-examples.ts +272 -0
  154. package/src/browse/library-commands.ts +64 -104
  155. package/src/browse/library-layouts.ts +263 -49
  156. package/src/browse/library-model.ts +181 -133
  157. package/src/browse/library-pane.ts +738 -446
  158. package/src/browse/library-preview.ts +149 -19
  159. package/src/browse/library-source.ts +308 -41
  160. package/src/browse/preview-root.ts +78 -0
  161. package/src/browse/preview-style.ts +155 -0
  162. package/src/canvas/asset-refs.ts +16 -1
  163. package/src/canvas/canvas-live-render.ts +222 -30
  164. package/src/canvas/canvas-origin.ts +37 -12
  165. package/src/canvas/canvas-page-context.ts +112 -0
  166. package/src/canvas/canvas-render.ts +113 -107
  167. package/src/canvas/canvas-utils.ts +57 -12
  168. package/src/canvas/iframe-drop.ts +107 -0
  169. package/src/canvas/iframe-entry.ts +24 -12
  170. package/src/canvas/iframe-host.ts +134 -62
  171. package/src/canvas/iframe-keys.ts +11 -0
  172. package/src/canvas/iframe-patch.ts +8 -7
  173. package/src/canvas/iframe-protocol.ts +24 -5
  174. package/src/canvas/iframe-render.ts +48 -1
  175. package/src/canvas/iframe-subtree.ts +5 -2
  176. package/src/canvas/npm-modules.ts +22 -0
  177. package/src/canvas/preview-navigate.ts +16 -0
  178. package/src/canvas/repeater-sources.ts +200 -0
  179. package/src/canvas/stage-scrollbar.ts +5 -1
  180. package/src/canvas/surface-registry.ts +6 -0
  181. package/src/commands/app-commands.ts +16 -6
  182. package/src/commands/budget.ts +10 -8
  183. package/src/commands/context.ts +35 -10
  184. package/src/commands/defaults.ts +69 -45
  185. package/src/commands/keymap.ts +9 -0
  186. package/src/commands/levels.ts +11 -5
  187. package/src/commands/live-context.ts +2 -0
  188. package/src/commands/registry.ts +10 -1
  189. package/src/content/collection-match.ts +6 -5
  190. package/src/content/collection-pages.ts +412 -0
  191. package/src/content/content-collections.ts +270 -0
  192. package/src/content/entry-commands.ts +51 -60
  193. package/src/content/entry-editor.ts +111 -18
  194. package/src/content/entry-fields.ts +13 -1
  195. package/src/content/entry-inspector.ts +225 -0
  196. package/src/content/entry-model.ts +17 -3
  197. package/src/content/entry-open.ts +80 -0
  198. package/src/content/entry-summaries.ts +440 -0
  199. package/src/content/file-record-ids.ts +80 -0
  200. package/src/content/file-records.ts +125 -0
  201. package/src/content/page-summaries.ts +129 -0
  202. package/src/content/record-entry.ts +201 -0
  203. package/src/content/writing-banner.ts +177 -0
  204. package/src/create/add-new-commands.ts +185 -0
  205. package/src/create/add-new-flow.ts +1116 -0
  206. package/src/create/add-new.ts +1014 -0
  207. package/src/create/element-name.ts +121 -0
  208. package/src/editor/convert-to-component.ts +67 -43
  209. package/src/editor/file-drop-action.ts +9 -1
  210. package/src/editor/inline-edit-apply.ts +44 -0
  211. package/src/editor/inline-edit.ts +10 -0
  212. package/src/editor/insert-component.ts +91 -0
  213. package/src/editor/insert-zone-action.ts +13 -4
  214. package/src/editor/shortcuts.ts +44 -22
  215. package/src/editor/slash-menu.ts +51 -8
  216. package/src/files/components.ts +74 -10
  217. package/src/files/file-ops.ts +15 -5
  218. package/src/files/files.ts +164 -150
  219. package/src/files/fs-events.ts +18 -7
  220. package/src/files/media-meta.ts +95 -1
  221. package/src/files/media-types.ts +55 -0
  222. package/src/files/media-upload.ts +209 -52
  223. package/src/files/new-file-name.ts +156 -0
  224. package/src/files/serialize-document.ts +13 -3
  225. package/src/format/format-host.ts +15 -0
  226. package/src/github/github-auth.ts +2 -2
  227. package/src/github/github-publish.ts +4 -3
  228. package/src/grid/grid-controller.ts +5 -1
  229. package/src/grid/grid-open.ts +0 -27
  230. package/src/grid/grid-panel.ts +54 -2
  231. package/src/grid/grid-reveal.ts +34 -0
  232. package/src/grid/grid-source.ts +3 -25
  233. package/src/grid/grid-view.ts +31 -6
  234. package/src/grid/sources/content-source.ts +75 -7
  235. package/src/grid/tabulator-tables.d.ts +6 -0
  236. package/src/hosting/document.ts +2 -2
  237. package/src/i18n/i18n-commands.ts +2 -1
  238. package/src/media/media-commands.ts +181 -0
  239. package/src/media/media-library-model.ts +232 -0
  240. package/src/media/media-library.ts +1283 -0
  241. package/src/media/media-pane.ts +47 -19
  242. package/src/packages/pull-package-sync.ts +1 -1
  243. package/src/panels/activity-panel.ts +21 -5
  244. package/src/panels/ai-chat/chat-markdown.ts +8 -8
  245. package/src/panels/block-action-bar.ts +11 -11
  246. package/src/panels/canvas-dnd-bridge.ts +5 -2
  247. package/src/panels/chat-panel.ts +6 -6
  248. package/src/panels/collections-panel.ts +306 -0
  249. package/src/panels/component-preview.ts +35 -13
  250. package/src/panels/data-explorer.ts +1 -1
  251. package/src/panels/data-grid.ts +4 -0
  252. package/src/panels/dnd.ts +17 -30
  253. package/src/panels/elements-panel.ts +9 -2
  254. package/src/panels/empty-state.ts +2 -2
  255. package/src/panels/formula-workspace.ts +2 -3
  256. package/src/panels/frontmatter-fields.ts +9 -9
  257. package/src/panels/git-diff-open.ts +9 -5
  258. package/src/panels/head-panel.ts +369 -103
  259. package/src/panels/i18n-panel.ts +11 -10
  260. package/src/panels/imports-panel.ts +2 -0
  261. package/src/panels/jump-bar.ts +27 -2
  262. package/src/panels/layers-panel.ts +36 -30
  263. package/src/panels/left-panel.ts +22 -8
  264. package/src/panels/navigator-panels.ts +23 -11
  265. package/src/panels/pane-context.ts +111 -29
  266. package/src/panels/pane-grid.ts +6 -6
  267. package/src/panels/panel-registry.ts +14 -9
  268. package/src/panels/properties-panel.ts +7 -3
  269. package/src/panels/right-panel.ts +199 -43
  270. package/src/panels/seo-modal.ts +41 -108
  271. package/src/panels/settings-menu.ts +52 -50
  272. package/src/panels/settings-pane.ts +268 -162
  273. package/src/panels/signals-panel.ts +3 -4
  274. package/src/panels/site-model.ts +367 -0
  275. package/src/panels/site-panel.ts +638 -0
  276. package/src/panels/style-panel.ts +37 -3
  277. package/src/panels/stylebook-doc.ts +142 -10
  278. package/src/panels/stylebook-layers-panel.ts +39 -80
  279. package/src/panels/stylebook-panel.ts +47 -10
  280. package/src/panels/styles-panel.ts +327 -0
  281. package/src/panels/tab-strip.ts +109 -25
  282. package/src/platform.ts +1 -1
  283. package/src/platforms/cloud.ts +28 -1
  284. package/src/platforms/default-platform.ts +4 -4
  285. package/src/platforms/devserver.ts +51 -25
  286. package/src/publish/deploy-checklist.ts +12 -7
  287. package/src/publish/pages-service.ts +38 -14
  288. package/src/publish/publish-changes.ts +491 -0
  289. package/src/publish/publish-commands.ts +83 -18
  290. package/src/publish/publish-ids.ts +49 -0
  291. package/src/publish/publish-quick.ts +148 -0
  292. package/src/publish/publish-workspace.ts +926 -0
  293. package/src/publish/source-control.ts +907 -0
  294. package/src/services/automation.ts +16 -20
  295. package/src/services/cf-settings.ts +4 -4
  296. package/src/services/connection.ts +2 -2
  297. package/src/services/directory-picker.ts +2 -2
  298. package/src/services/references.ts +0 -0
  299. package/src/services/render-critic.ts +21 -2
  300. package/src/services/settings/definitions.ts +25 -14
  301. package/src/settings/contributed-section.ts +49 -10
  302. package/src/settings/css-vars-editor.ts +93 -27
  303. package/src/settings/developer-panels.ts +43 -0
  304. package/src/settings/extension-sections.ts +20 -2
  305. package/src/settings/general-settings.ts +91 -21
  306. package/src/settings/preferences-dialog.ts +8 -1
  307. package/src/settings/project-sections.ts +27 -10
  308. package/src/settings/schema-field-ui.ts +3 -1
  309. package/src/settings/section-registry.ts +116 -11
  310. package/src/settings/settings-dialog.ts +192 -0
  311. package/src/settings/settings-document.ts +182 -162
  312. package/src/shell.ts +467 -431
  313. package/src/site-context.ts +64 -10
  314. package/src/state.ts +28 -9
  315. package/src/studio.ts +194 -41
  316. package/src/style/project-styles.ts +34 -0
  317. package/src/style/stylebook-specimens.ts +89 -0
  318. package/src/style/stylebook-target.ts +26 -0
  319. package/src/style/tag-inheritance.ts +105 -0
  320. package/src/style/variables-focus.ts +61 -0
  321. package/src/style/variables-view.ts +235 -0
  322. package/src/surfaces/add-new.json +1482 -0
  323. package/src/surfaces/add-new.ts +325 -0
  324. package/src/surfaces/ai-chat.ts +2 -2
  325. package/src/surfaces/boot-failure.json +4 -3
  326. package/src/surfaces/bottom-dock.json +1 -1
  327. package/src/surfaces/canvas-stage.json +30 -19
  328. package/src/surfaces/canvas-stage.ts +5 -5
  329. package/src/surfaces/collections-panel.json +615 -0
  330. package/src/surfaces/collections-panel.ts +168 -0
  331. package/src/surfaces/commandbar.json +241 -96
  332. package/src/surfaces/commandbar.ts +134 -99
  333. package/src/surfaces/empty-state.json +1 -1
  334. package/src/surfaces/entry-editor.json +136 -0
  335. package/src/surfaces/entry-editor.ts +21 -0
  336. package/src/surfaces/entry-inspector.json +371 -0
  337. package/src/surfaces/entry-inspector.ts +143 -0
  338. package/src/surfaces/inspector-dock.json +162 -14
  339. package/src/surfaces/inspector-dock.ts +46 -19
  340. package/src/surfaces/library-pane.json +670 -437
  341. package/src/surfaces/library-pane.ts +94 -59
  342. package/src/surfaces/media-browser.json +62 -6
  343. package/src/surfaces/media-browser.ts +15 -1
  344. package/src/surfaces/media-field.json +1 -1
  345. package/src/surfaces/media-library.json +1586 -0
  346. package/src/surfaces/media-library.ts +282 -0
  347. package/src/surfaces/media-pick-dialog.json +71 -0
  348. package/src/surfaces/media-pick-dialog.ts +132 -0
  349. package/src/surfaces/menu.ts +18 -0
  350. package/src/surfaces/pane-context.json +144 -77
  351. package/src/surfaces/pane-context.ts +24 -0
  352. package/src/surfaces/panel-deploy-checklist.json +12 -6
  353. package/src/surfaces/panel-deploy-checklist.ts +3 -1
  354. package/src/surfaces/panel-page.json +72 -2
  355. package/src/surfaces/panel-page.ts +38 -7
  356. package/src/surfaces/panel-signals.json +1 -1
  357. package/src/surfaces/panel-signals.ts +5 -5
  358. package/src/surfaces/panel-stylebook-layers.json +71 -204
  359. package/src/surfaces/panel-stylebook-layers.ts +0 -21
  360. package/src/surfaces/preferences.json +120 -48
  361. package/src/surfaces/preferences.ts +8 -0
  362. package/src/surfaces/publish-quick.json +428 -0
  363. package/src/surfaces/publish-quick.ts +165 -0
  364. package/src/surfaces/publish-workspace.json +2892 -0
  365. package/src/surfaces/publish-workspace.ts +391 -0
  366. package/src/surfaces/rail.json +1 -159
  367. package/src/surfaces/rail.ts +18 -75
  368. package/src/surfaces/schema-form.json +10 -2
  369. package/src/surfaces/schema-form.ts +2 -0
  370. package/src/surfaces/seo.json +1 -1
  371. package/src/surfaces/settings-contributed.json +5 -5
  372. package/src/surfaces/settings-contributed.ts +18 -2
  373. package/src/surfaces/settings-css-vars.json +44 -36
  374. package/src/surfaces/settings-css-vars.ts +77 -4
  375. package/src/surfaces/settings-deploy.json +2 -15
  376. package/src/surfaces/settings-deploy.ts +1 -1
  377. package/src/surfaces/settings-dialog.json +51 -0
  378. package/src/surfaces/settings-dialog.ts +169 -0
  379. package/src/surfaces/settings-overview.json +3 -3
  380. package/src/surfaces/settings-overview.ts +9 -2
  381. package/src/surfaces/settings-pane.json +269 -46
  382. package/src/surfaces/settings-pane.ts +85 -24
  383. package/src/surfaces/shell.json +2 -1
  384. package/src/surfaces/site-panel.json +1029 -0
  385. package/src/surfaces/site-panel.ts +233 -0
  386. package/src/surfaces/slash-menu.json +63 -21
  387. package/src/surfaces/slash-menu.ts +23 -0
  388. package/src/surfaces/statusbar.ts +39 -15
  389. package/src/surfaces/styles-panel.json +735 -0
  390. package/src/surfaces/styles-panel.ts +195 -0
  391. package/src/surfaces/styles-variables.json +149 -0
  392. package/src/surfaces/styles-variables.ts +145 -0
  393. package/src/surfaces/tab-strip.json +4 -4
  394. package/src/surfaces/welcome.ts +1 -1
  395. package/src/surfaces/writing-banner.json +94 -0
  396. package/src/surfaces/writing-banner.ts +80 -0
  397. package/src/tabs/bare-repeaters.ts +101 -0
  398. package/src/tabs/tab.ts +47 -7
  399. package/src/types.ts +21 -26
  400. package/src/ui/form-controls.ts +47 -8
  401. package/src/ui/layers.ts +13 -0
  402. package/src/ui/media-picker.ts +284 -40
  403. package/src/ui/regions.ts +7 -6
  404. package/src/ui/schema-form.ts +259 -27
  405. package/src/ui/virtual-window.ts +26 -1
  406. package/src/utils/base64.ts +3 -3
  407. package/src/utils/edit-display.ts +322 -67
  408. package/src/utils/local-day.ts +18 -0
  409. package/src/workspace/pane-derive.ts +4 -4
  410. package/src/workspace/session.ts +28 -7
  411. package/src/workspace/tab-workspace.ts +137 -0
  412. package/src/workspace/workspace-back.ts +189 -0
  413. package/src/workspace/workspace-home.ts +133 -0
  414. package/src/workspace/workspace-ids.ts +129 -0
  415. package/src/workspace/workspace-switch.ts +372 -0
  416. package/src/workspace/workspace.ts +125 -11
  417. package/styles/shell-frame.css +30 -7
  418. package/styles/shell-frame.json +15 -3
  419. package/dist/chunks/2020-f2gkpy8d.js +0 -4
  420. package/dist/chunks/adapter-4912g339.js +0 -4
  421. package/dist/chunks/cf-account-picker-wccaenh6.js +0 -4
  422. package/dist/chunks/cf-settings-br6105tr.js +0 -4
  423. package/dist/chunks/color-28ksk2qm.js +0 -4
  424. package/dist/chunks/components-db68vsn7.js +0 -4
  425. package/dist/chunks/content-source-1449qesq.js +0 -4
  426. package/dist/chunks/convert-to-repeater-5h457egj.js +0 -4
  427. package/dist/chunks/editor-x9jn86a7.js +0 -4
  428. package/dist/chunks/entry-commands-may24cpt.js +0 -4
  429. package/dist/chunks/extension-sections-pvr14vxr.js +0 -4
  430. package/dist/chunks/file-ops-x9v54pcj.js +0 -4
  431. package/dist/chunks/files-j3knqf0s.js +0 -4
  432. package/dist/chunks/format-host-tyre2trb.js +0 -4
  433. package/dist/chunks/fs-events-64ma9htc.js +0 -4
  434. package/dist/chunks/git-panel-84ps5dex.js +0 -4
  435. package/dist/chunks/iframe-entry-fvbk89gm.js +0 -5
  436. package/dist/chunks/iframe-host-ck6vejt5.js +0 -4
  437. package/dist/chunks/index-b8xw3vy9.js +0 -4
  438. package/dist/chunks/jsonMode-w15cmrcm.js +0 -13
  439. package/dist/chunks/jx-validate-at3zn8wa.js +0 -4
  440. package/dist/chunks/layers-h4xp1pss.js +0 -4
  441. package/dist/chunks/layers-panel-m5hw1d7g.js +0 -4
  442. package/dist/chunks/lit-html-8t8t3dnr.js +0 -4
  443. package/dist/chunks/media-picker-2cweexc5.js +0 -4
  444. package/dist/chunks/menu-ynw13y0s.js +0 -4
  445. package/dist/chunks/monaco-buffer-qzxn567r.js +0 -4
  446. package/dist/chunks/monaco-setup-gxf6656g.js +0 -4
  447. package/dist/chunks/notify-cj5zbrs2.js +0 -4
  448. package/dist/chunks/parse-b7ddhr8m.js +0 -4
  449. package/dist/chunks/platform-3dfws9js.js +0 -4
  450. package/dist/chunks/popover-jt2gxmzs.js +0 -4
  451. package/dist/chunks/publish-panel-1gvxbj21.js +0 -4
  452. package/dist/chunks/quick-search-0dajrwqg.js +0 -4
  453. package/dist/chunks/references-49qgt404.js +0 -4
  454. package/dist/chunks/right-panel-jm1bwe53.js +0 -4
  455. package/dist/chunks/section-registry-6kwc4fky.js +0 -4
  456. package/dist/chunks/studio-0rt52vpq.js +0 -5
  457. package/dist/chunks/studio-18vgbhs5.js +0 -5
  458. package/dist/chunks/studio-24mccdrj.js +0 -5
  459. package/dist/chunks/studio-2eh507zk.js +0 -9
  460. package/dist/chunks/studio-2hcbccfv.js +0 -5
  461. package/dist/chunks/studio-2jbs3rxv.js +0 -5
  462. package/dist/chunks/studio-4h8k4dw9.js +0 -5
  463. package/dist/chunks/studio-5f6n18kx.js +0 -5
  464. package/dist/chunks/studio-5gthpky6.js +0 -5
  465. package/dist/chunks/studio-6ep3js6b.js +0 -9
  466. package/dist/chunks/studio-6wkmf3wz.js +0 -9
  467. package/dist/chunks/studio-841rf3cg.js +0 -5
  468. package/dist/chunks/studio-8gmwgheg.js +0 -5
  469. package/dist/chunks/studio-8qm0ep50.js +0 -5
  470. package/dist/chunks/studio-924p1tm1.js +0 -6
  471. package/dist/chunks/studio-a3shpz9y.js +0 -5
  472. package/dist/chunks/studio-amsbaaar.js +0 -6
  473. package/dist/chunks/studio-at5spjbc.js +0 -7
  474. package/dist/chunks/studio-b2xv945e.js +0 -5
  475. package/dist/chunks/studio-bn5nkafw.js +0 -5
  476. package/dist/chunks/studio-bw6q5xjf.js +0 -9
  477. package/dist/chunks/studio-c7q0t9x1.js +0 -5
  478. package/dist/chunks/studio-camnhc96.js +0 -6
  479. package/dist/chunks/studio-cffqvnzd.js +0 -5
  480. package/dist/chunks/studio-efvfrsf8.js +0 -5
  481. package/dist/chunks/studio-er30bpcx.js +0 -5
  482. package/dist/chunks/studio-ezscgr64.js +0 -5
  483. package/dist/chunks/studio-ffrrncvz.js +0 -5
  484. package/dist/chunks/studio-fpphgn8y.js +0 -10
  485. package/dist/chunks/studio-j1kvhdjk.js +0 -4
  486. package/dist/chunks/studio-j430n16g.js +0 -7
  487. package/dist/chunks/studio-jjkg84nj.js +0 -5
  488. package/dist/chunks/studio-m0q32ars.js +0 -4
  489. package/dist/chunks/studio-m6bdst11.js +0 -5
  490. package/dist/chunks/studio-nv2cptd4.js +0 -64
  491. package/dist/chunks/studio-nwfrc98n.js +0 -5
  492. package/dist/chunks/studio-p1wgvp7r.js +0 -5
  493. package/dist/chunks/studio-pag2wncm.js +0 -5
  494. package/dist/chunks/studio-qvanvzfd.js +0 -5
  495. package/dist/chunks/studio-qwa64kt7.js +0 -5
  496. package/dist/chunks/studio-rk1zc4x3.js +0 -928
  497. package/dist/chunks/studio-se2r3ptc.js +0 -5
  498. package/dist/chunks/studio-sg2a0dh0.js +0 -5
  499. package/dist/chunks/studio-tjzjhe68.js +0 -5
  500. package/dist/chunks/studio-v2w7q8r1.js +0 -7
  501. package/dist/chunks/studio-v5vjq1h0.js +0 -4
  502. package/dist/chunks/studio-v8aga3vp.js +0 -14
  503. package/dist/chunks/studio-vfcdrfmv.js +0 -5
  504. package/dist/chunks/studio-vmfkgdjf.js +0 -5
  505. package/dist/chunks/studio-wt1816jj.js +0 -5
  506. package/dist/chunks/studio-wz73q5kq.js +0 -4
  507. package/dist/chunks/studio-y04qtxvp.js +0 -7
  508. package/dist/chunks/studio-y21g8zzg.js +0 -5
  509. package/dist/chunks/studio-y64hrt8p.js +0 -12
  510. package/dist/chunks/studio-ynn90f58.js +0 -16
  511. package/dist/chunks/studio-yxz682sx.js +0 -5
  512. package/dist/chunks/studio-zp7snvkq.js +0 -5
  513. package/dist/chunks/studio-zq4z6tm6.js +0 -5
  514. package/dist/chunks/toast-c9fn075p.js +0 -4
  515. package/dist/chunks/tsMode-sf49ee9x.js +0 -14
  516. package/dist/chunks/workspace-jtfahpee.js +0 -4
  517. package/src/panels/frontmatter-panel.ts +0 -711
  518. package/src/panels/git-panel.ts +0 -1108
  519. package/src/surfaces/doc-header.json +0 -776
  520. package/src/surfaces/doc-header.ts +0 -222
  521. package/src/surfaces/git-panel.json +0 -1880
  522. package/src/surfaces/git-panel.ts +0 -264
@@ -8,21 +8,31 @@
8
8
  * path.
9
9
  */
10
10
 
11
- import { isNonNullObject } from "@jxsuite/schema/guards";
11
+ import { isNonNullObject, isString } from "@jxsuite/schema/guards";
12
12
  import { getFormats, loadExtensions, loadFormats } from "../format/format-host";
13
- import { registerSettingsSection, unregisterSettingsSection } from "./section-registry";
13
+ import {
14
+ DEFAULT_SETTINGS_GROUP,
15
+ isSettingsGroupId,
16
+ registerSettingsSection,
17
+ unregisterSettingsSection,
18
+ } from "./section-registry";
14
19
  import { renderContributedSection } from "./contributed-section";
15
20
  import { dataSectionActions } from "../panels/data-grid";
16
21
  import type { ExtensionContributionInfo } from "../types";
17
22
  import type { JsonSchema } from "../ui/schema-form";
18
23
  import type { ContributedSectionOptions, SettingsContribution } from "./contributed-section";
24
+ import type { SettingsGroupId } from "./section-registry";
19
25
 
20
26
  /** The `$studio.settings` block shape consumed here (nav metadata + the renderer inputs). */
21
27
  interface StudioSettingsBlock {
22
28
  icon?: string;
23
29
  label?: string;
30
+ /** The nav group: `general`, `integrations` (the default) or `advanced`. */
31
+ group?: string;
24
32
  order?: number;
25
33
  layout?: "map" | "form";
34
+ /** The sentence the section body opens with, in place of its group's (extensions.md §9.1). */
35
+ intro?: string;
26
36
  entry?: SettingsContribution["settings"]["entry"];
27
37
  }
28
38
 
@@ -30,7 +40,9 @@ interface StudioSettingsBlock {
30
40
  export interface DerivedSettingsSection {
31
41
  key: string;
32
42
  label: string;
43
+ group: SettingsGroupId;
33
44
  icon?: string | undefined;
45
+ intro?: string | undefined;
34
46
  order: number;
35
47
  contribution: SettingsContribution;
36
48
  }
@@ -85,7 +97,11 @@ export function deriveSettingsSection(
85
97
  settings: sectionSettings,
86
98
  title: label,
87
99
  },
100
+ /* A group the nav does not draw falls back to the default rather than hiding the section:
101
+ an extension naming a group from a later vocabulary still gets its section listed. */
102
+ group: isSettingsGroupId(settings.group) ? settings.group : DEFAULT_SETTINGS_GROUP,
88
103
  icon: settings.icon,
104
+ intro: isString(settings.intro) ? settings.intro : undefined,
89
105
  key,
90
106
  label,
91
107
  order: settings.order ?? DEFAULT_SECTION_ORDER,
@@ -144,7 +160,9 @@ async function runSync(): Promise<void> {
144
160
  }
145
161
  const { contribution } = derived;
146
162
  registerSettingsSection({
163
+ group: derived.group,
147
164
  icon: derived.icon,
165
+ intro: derived.intro,
148
166
  key: derived.key,
149
167
  label: derived.label,
150
168
  order: derived.order,
@@ -21,8 +21,12 @@ import { errorMessage } from "@jxsuite/schema/parse";
21
21
  import { projectState } from "../store";
22
22
  import { updateSiteConfig } from "../site-context";
23
23
  import { activeRegistry } from "../commands/active-registry";
24
+ import { runActiveReported } from "../commands/run-reported";
25
+ import { closeSettingsDialog } from "./settings-dialog";
24
26
  import { getPlatform } from "../platform";
25
27
  import { mountOverviewSurface } from "../surfaces/settings-overview";
28
+ import { previewAssetSrcFor } from "../canvas/asset-refs";
29
+ import { PROJECT_CONFIG_PATH } from "../tabs/tab";
26
30
 
27
31
  import type {
28
32
  OverviewActions,
@@ -90,6 +94,65 @@ function headWithDescription(head: JxHeadEntry[], text: string): JxHeadEntry[] {
90
94
  );
91
95
  }
92
96
 
97
+ // ─── Favicon ($head link) ───────────────────────────────────────────────────
98
+
99
+ /**
100
+ * True for a `<link>` whose `rel` names the `icon` relation.
101
+ *
102
+ * `rel` is a set of space-separated, ASCII case-insensitive tokens (HTML Standard, link types), so
103
+ * the legacy `rel="shortcut icon"` every favicon snippet still carries is the same relation as
104
+ * `rel="icon"`. `apple-touch-icon` is a different token and is not the favicon.
105
+ */
106
+ function isIconLink(entry: JxHeadEntry): boolean {
107
+ const rel = entry.attributes?.rel;
108
+ return (
109
+ entry.tagName === "link" &&
110
+ isString(rel) &&
111
+ rel
112
+ .toLowerCase()
113
+ .split(/\s+/u)
114
+ .some((token) => token === "icon")
115
+ );
116
+ }
117
+
118
+ /**
119
+ * The site favicon. Like the description it is not a top-level `project.json` key (the composed
120
+ * schema is closed, and no compiler stage reads one): it is the `<link rel="icon">` in `$head`,
121
+ * which is what every starter and `@jxsuite/create` write and what the browser reads
122
+ * (`site-architecture.md` §2).
123
+ */
124
+ function readFavicon(cfg: ProjectConfig): string {
125
+ const href = (cfg.$head ?? []).find((e) => isIconLink(e))?.attributes?.href;
126
+ return isString(href) ? href : "";
127
+ }
128
+
129
+ /**
130
+ * `$head` with the icon link pointing at `href`.
131
+ *
132
+ * The existing link is rewritten in place, so its position among the head entries and any other
133
+ * attribute an author gave it (`sizes`, a media query) survive. `type` is the one attribute that is
134
+ * dropped: it describes the file being replaced, and a new upload may be a different format.
135
+ */
136
+ function headWithFavicon(head: JxHeadEntry[], href: string): JxHeadEntry[] {
137
+ if (!head.some((e) => isIconLink(e))) {
138
+ return [...head, { attributes: { href, rel: "icon" }, tagName: "link" }];
139
+ }
140
+ return head.map((entry) => {
141
+ if (!isIconLink(entry)) {
142
+ return entry;
143
+ }
144
+ const { type: _type, ...attributes } = entry.attributes ?? {};
145
+ return { ...entry, attributes: { ...attributes, href } };
146
+ });
147
+ }
148
+
149
+ /** The file name an uploaded favicon is stored under: `favicon` plus the upload's own extension. */
150
+ function faviconFileName(file: File): string {
151
+ const dot = file.name.lastIndexOf(".");
152
+ const ext = dot > 0 ? file.name.slice(dot + 1).toLowerCase() : "";
153
+ return /^[a-z0-9]+$/u.test(ext) ? `favicon.${ext}` : "favicon.ico";
154
+ }
155
+
93
156
  /**
94
157
  * The patch that _removes_ `url`. `undefined` survives the object spread inside `updateSiteConfig`
95
158
  * and `JSON.stringify` then drops the key, so clearing the field clears the setting instead of
@@ -100,31 +163,36 @@ function headWithDescription(head: JxHeadEntry[], text: string): JxHeadEntry[] {
100
163
  */
101
164
  const CLEAR_URL: ProjectConfigPatch = { url: undefined };
102
165
 
166
+ /** The record the Global Styles button is drawn from: **Go to Styles**, the workspace's ⌘4. */
167
+ const STYLES_COMMAND = "workspace.focus.styles";
168
+
103
169
  // ─── Projection ──────────────────────────────────────────────────────────────
104
170
 
105
171
  /**
106
172
  * What the surface should be showing, from the configuration and the registry as they stand now.
107
173
  *
108
- * The Project Styles button is rendered FROM the `styles.open` record, so it is disabled rather
109
- * than absent when it cannot act (`studio-ui-guidelines.md` §12.3) and it cannot drift from the
110
- * palette row or the gear menu. The record's TITLE, and nothing else off the registry:
174
+ * The Global Styles button is rendered FROM the `workspace.focus.styles` record (**Go to Styles**,
175
+ * ⌘4), whose run is `view.setWorkspace { workspace: "styles" }`, so it is disabled rather than
176
+ * absent when it cannot act (`studio-ui-guidelines.md` §12.3) and it cannot drift from the palette
177
+ * row or the switcher's tab. The record's TITLE, and nothing else off the registry:
111
178
  * `disabledReason` would be the `studio-ui-guidelines.md` §12.3 shape for a control that can be
112
- * inapplicable, but this one cannot be — `styles.open` is gated on `ctx.project.open` and Overview
113
- * is a section of the project's own configuration document, so by the time this renders the answer
114
- * is always yes. Asking anyway would also be a FOCUS read inside a function that was handed a
115
- * container, which is what `scripts/check-pane-singletons.ts` rule 4 forbids: a pane-scoped surface
116
- * must not report the focused pane's state. A project-level verb happens to read the same in every
117
- * pane, but the way to be right about that is not to ask. The one thing that can genuinely be
118
- * missing is the registry itself (bootstrap order, a test), and that is an existence check, not a
119
- * state read.
179
+ * inapplicable, but this one cannot be — the switch is gated on `ctx.project.open` and Overview is
180
+ * a section of the project's own configuration, so by the time this renders the answer is always
181
+ * yes. Asking anyway would also be a FOCUS read inside a function that was handed a container,
182
+ * which is what `scripts/check-pane-singletons.ts` rule 4 forbids: a pane-scoped surface must not
183
+ * report the focused pane's state. A project-level verb happens to read the same in every pane, but
184
+ * the way to be right about that is not to ask. The one thing that can genuinely be missing is the
185
+ * registry itself (bootstrap order, a test), and that is an existence check, not a state read.
120
186
  */
121
187
  function values(container: HTMLElement): OverviewValues {
122
188
  const cfg = config();
123
- const command = activeRegistry()?.get("styles.open");
189
+ const command = activeRegistry()?.get(STYLES_COMMAND);
124
190
  return {
125
191
  description: readDescription(cfg),
126
192
  error: errors.get(container) ?? null,
127
- favicon: isString(cfg.favicon) ? cfg.favicon : "",
193
+ favicon: readFavicon(cfg),
194
+ // `project.json` authored it, whatever tab is in front: the section is project-level.
195
+ faviconSrc: previewAssetSrcFor(readFavicon(cfg), PROJECT_CONFIG_PATH),
128
196
  name: cfg.name ?? "",
129
197
  stylesDisabled: command === undefined,
130
198
  stylesTitle: command?.title ?? "",
@@ -178,29 +246,31 @@ function actions(container: HTMLElement): OverviewActions {
178
246
  if (!file) {
179
247
  return;
180
248
  }
249
+ // `public/` is copied to the site root verbatim, so `public/favicon.svg` is `/favicon.svg`.
250
+ const name = faviconFileName(file);
181
251
  try {
182
- await getPlatform().uploadFile("public/favicon.ico", file);
252
+ await getPlatform().uploadFile(`public/${name}`, file);
183
253
  } catch (error) {
184
254
  reject("favicon", `Could not upload the favicon — ${errorMessage(error)}`);
185
255
  return;
186
256
  }
187
- await persist({ favicon: "/favicon.ico" }, "favicon");
257
+ await persist({ $head: headWithFavicon(config().$head ?? [], `/${name}`) }, "favicon");
188
258
  });
189
259
  input.click();
190
260
  };
191
261
 
192
262
  return {
193
263
  /*
194
- * Project Styles is the SAME document in a different editor, and `styles.open` is the one place
195
- * that says so. This used to write `session.ui.canvasMode` here directly — a second
264
+ * Global styles are the Styles workspace's, and the workspace switch is the one place that
265
+ * says how to get there. This used to write `session.ui.canvasMode` here directly — a second
196
266
  * implementation of a capability, `studio-ui-guidelines.md` §12.5's defect in miniature: the
197
267
  * button and the command could disagree about what "open Project Styles" means, and only one of
198
- * them was reachable by name. The mode is still a fact about the TAB, and there is exactly one
199
- * `project.json` tab, so `revealTab`'s `focusPane` puts the keyboard on whichever pane holds
200
- * it.
268
+ * them was reachable by name. Overview is drawn in the settings dialog, so the dialog closes
269
+ * first: left up, it would cover the workspace the reader just asked for.
201
270
  */
202
271
  openStyles: () => {
203
- void activeRegistry()?.run("styles.open");
272
+ closeSettingsDialog();
273
+ void runActiveReported("view.setWorkspace", { workspace: "styles" }, "Settings");
204
274
  },
205
275
  setDescription: (value: string) => {
206
276
  echo({ description: value });
@@ -11,7 +11,8 @@
11
11
  * Four sections, and each one closes a hole the shell redesign named:
12
12
  *
13
13
  * - **Appearance** — the chrome theme. `shell.theme` and `view.setTheme` already existed; nothing
14
- * rendered them, so the only way to change the theme was to run a command by hand.
14
+ * rendered them, so the only way to change the theme was to run a command by hand. Beside it,
15
+ * **Show developer panels**, which puts Files and Packages on the Design rail (§5.1).
15
16
  * - **Assistant** — the provider key. It used to live in `Assistant: Settings…`, a dialog reachable
16
17
  * only from inside the assistant panel, which meant a key had to be configured from the surface
17
18
  * that was broken for want of one. That dialog is deleted; this is where it went.
@@ -62,6 +63,7 @@ import {
62
63
  } from "./preferences-accounts";
63
64
  import { applyKeybindingOverrides, rebindCommand, resetKeybinding } from "./preferences-keymap";
64
65
  import { openPreferencesSurface } from "../surfaces/preferences";
66
+ import { developerPanelsShown, setDeveloperPanelsShown } from "./developer-panels";
65
67
 
66
68
  import type { ShortcutRow } from "../commands/reference";
67
69
  import type { RebindResult } from "./preferences-keymap";
@@ -550,6 +552,7 @@ function view(): PreferencesView {
550
552
  sectionTitle: active?.title ?? "",
551
553
  sections: sectionsView(),
552
554
  themes: themesView(),
555
+ developerPanels: developerPanelsShown(),
553
556
  ...(_section === "keyboard" ? keyboardView() : KEYBOARD_IDLE),
554
557
  };
555
558
  }
@@ -612,6 +615,10 @@ export function openPreferences(section?: string): Promise<null> {
612
615
  onResetBinding: resetBinding,
613
616
  onSelectSection: selectSection,
614
617
  onSetTheme: setTheme,
618
+ onSetDeveloperPanels: (show: boolean) => {
619
+ setDeveloperPanelsShown(show);
620
+ repaint();
621
+ },
615
622
  onShowConflict: showConflict,
616
623
  onToggleKeystroke: toggleKeystroke,
617
624
  onToggleRebind: toggleRebind,
@@ -1,6 +1,6 @@
1
1
  /// <reference lib="dom" />
2
2
  /**
3
- * The two Project Settings sections the document adds directly — Deploy and Raw JSON.
3
+ * Two direct views of `project.json`: Deploy (the build adapter) and Raw JSON (the file itself).
4
4
  *
5
5
  * They live together because each is a small, direct view of ONE `project.json` key and neither
6
6
  * owns a dialog, a picker or a schema form: `build.adapter` (one enum), and the file itself.
@@ -12,8 +12,11 @@
12
12
  * error plumbing both still share.
13
13
  *
14
14
  * **Raw JSON does not open a second editor.** It shows what is on disk and hands the author to the
15
- * Code editor over the SAME tab — one document, three editors (§17.1), so switching to the text and
16
- * back keeps one undo stack instead of forking two.
15
+ * Code editor over the `project.json` tab (§17.1): the host says how, through `editAsCode`, because
16
+ * the section sits in the settings dialog and the tab it opens is the Styles workspace's.
17
+ *
18
+ * **Deploy is no longer a Project Settings section.** Hosting moved to the Publish workspace
19
+ * (§17.1's Moved footnote), which hosts `renderDeploySection`; the renderer is unchanged.
17
20
  *
18
21
  * **The markup left.** Each section is a Jx document over the kit — `surfaces/settings-deploy.json`
19
22
  * and `surfaces/settings-rawjson.json`, mounted by the adapters beside them — and what is here is
@@ -29,9 +32,8 @@
29
32
  */
30
33
 
31
34
  import { errorMessage } from "@jxsuite/schema/parse";
32
- import { projectState, updateUi } from "../store";
35
+ import { projectState } from "../store";
33
36
  import { serializeProjectConfig } from "../tabs/project-config";
34
- import { tabOfContainer } from "../canvas/canvas-surface";
35
37
  import { updateSiteConfig } from "../site-context";
36
38
  import { mountDeploySurface } from "../surfaces/settings-deploy";
37
39
  import { mountRawJsonSurface } from "../surfaces/settings-rawjson";
@@ -40,9 +42,6 @@ import type { DeployActions, DeploySurfaceHandle, DeployValues } from "../surfac
40
42
  import type { RawJsonSurfaceHandle, RawJsonValues } from "../surfaces/settings-rawjson";
41
43
  import type { ProjectConfig } from "@jxsuite/schema/types";
42
44
 
43
- /** The mode the Code editor draws under — `tabs/tab.ts`'s `EDITOR_KIND_BY_MODE` maps it to `code`. */
44
- const CODE_MODE = "source";
45
-
46
45
  /**
47
46
  * The last failed write per rendered section container.
48
47
  *
@@ -151,6 +150,17 @@ export function renderDeploySection(container: HTMLElement): void {
151
150
  );
152
151
  }
153
152
 
153
+ /**
154
+ * Take the Deploy section out of a container its host is leaving (Publish › Hosting, when its pane
155
+ * is torn down). Idempotent.
156
+ *
157
+ * @param {HTMLElement} container
158
+ */
159
+ export function disposeDeploySection(container: HTMLElement): void {
160
+ deployMounts.get(container)?.dispose();
161
+ deployMounts.delete(container);
162
+ }
163
+
154
164
  // ─── Raw JSON ─────────────────────────────────────────────────────────────────
155
165
 
156
166
  /** The surface mounted in each Raw JSON container. */
@@ -166,12 +176,19 @@ function rawJsonValues(): RawJsonValues {
166
176
  return { json: serializeProjectConfig(config()) };
167
177
  }
168
178
 
179
+ /** What the Raw JSON section asks its host to do. */
180
+ export interface RawJsonSectionActions {
181
+ /** Open `project.json` in the Code editor, leaving wherever the section is drawn. */
182
+ editAsCode: () => void;
183
+ }
184
+
169
185
  /**
170
186
  * `project.json` as it is written, and the way into editing it as text.
171
187
  *
172
188
  * @param {HTMLElement} container
189
+ * @param {RawJsonSectionActions} actions
173
190
  */
174
- export function renderRawJsonSection(container: HTMLElement): void {
191
+ export function renderRawJsonSection(container: HTMLElement, actions: RawJsonSectionActions): void {
175
192
  const standing = rawJsonMounts.get(container);
176
193
  if (standing?.connected()) {
177
194
  standing.update(rawJsonValues());
@@ -181,7 +198,7 @@ export function renderRawJsonSection(container: HTMLElement): void {
181
198
  rawJsonMounts.set(
182
199
  container,
183
200
  mountRawJsonSurface(container, rawJsonValues(), {
184
- editAsCode: () => updateUi(tabOfContainer(container), "canvasMode", CODE_MODE),
201
+ editAsCode: actions.editAsCode,
185
202
  }),
186
203
  );
187
204
  }
@@ -12,6 +12,7 @@
12
12
  */
13
13
 
14
14
  import { isMediaFormat } from "../utils/studio-utils";
15
+ import { localDay } from "../utils/local-day";
15
16
 
16
17
  export interface SchemaProperty {
17
18
  type?: string;
@@ -102,7 +103,8 @@ export function schemaForType(type: string, format?: string) {
102
103
  */
103
104
  export function yamlDefault(type: string, format?: string) {
104
105
  if (format === "date") {
105
- return new Date().toISOString().split("T")[0];
106
+ // Today where the author is: a UTC "today" is tomorrow every evening west of Greenwich.
107
+ return localDay(new Date());
106
108
  }
107
109
  if (isMediaFormat(format)) {
108
110
  return '""';
@@ -3,15 +3,16 @@
3
3
  *
4
4
  * `registerSettingsSection` is a **preserved public contract** (specs/extensions.md §9.1): an
5
5
  * extension's `project` class declares a `$studio.settings` block and `settings/extension-sections`
6
- * turns it into one of these records. Project Settings moved out of a modal and into a document in
7
- * the pane (§17.1); the registry did not move with it, because a section is a contribution to
8
- * CONFIGURATION, not to a dialog. Splitting it out is what lets the host be replaced without the
9
- * contribution point being touched.
6
+ * turns it into one of these records. Project Settings has moved host twice — a modal, then a
7
+ * document in the pane, and now a dialog again (§17.1) — and the registry moved with neither,
8
+ * because a section is a contribution to CONFIGURATION, not to whatever draws it. Splitting it out
9
+ * is what lets the host be replaced without the contribution point being touched.
10
10
  *
11
- * **This module holds no renderer and imports nothing.** That is load-bearing rather than tidy:
12
- * `panels/settings-pane.ts` is reached from `canvas/canvas-render.ts`, so anything this module
13
- * imports becomes part of the canvas's import graph. The section RENDERERS are registered by
14
- * `settings/settings-document.ts`, which the app loads when it registers its commands.
11
+ * **This module holds no renderer and imports nothing.** That is load-bearing rather than tidy: the
12
+ * gear menu (`panels/settings-menu.ts`) enumerates these sections from the top bar, so anything
13
+ * this module imports becomes part of the chrome's import graph. The section RENDERERS are
14
+ * registered by `settings/settings-document.ts`, which the app loads when it registers its
15
+ * commands.
15
16
  *
16
17
  * **What is requested and what is displayed are two variables, and unregistering touches neither.**
17
18
  * The modal had one, and its `unregisterSettingsSection` reset it to `"general"` — which is half of
@@ -22,10 +23,57 @@
22
23
  * the key comes back.
23
24
  */
24
25
 
26
+ /**
27
+ * The three groups the Project Settings nav is drawn in (§17.1), in display order.
28
+ *
29
+ * - **General** is what every author sets: the site's name, address and icon, and its languages.
30
+ * - **Integrations** is what an extension adds, and so where every contributed section lands unless
31
+ * it says otherwise (`specs/extensions.md` §9.1, `group`).
32
+ * - **Advanced** is the project's machinery, marked "For developers": rendering contexts, the site
33
+ * head, data shapes, packages and the raw file.
34
+ *
35
+ * `intro` is the sentence the body opens with while a section of that group is showing: what the
36
+ * group is FOR, so the reader learns that Advanced is the risky one from a sentence rather than
37
+ * from a two-word qualifier. General's sections need no preamble, so it has none.
38
+ */
39
+ export const SETTINGS_GROUPS = [
40
+ { id: "general", intro: "", label: "General", note: "" },
41
+ {
42
+ id: "integrations",
43
+ intro: "Turn on what your site needs. Each one adds its own options where you use it.",
44
+ label: "Integrations",
45
+ note: "",
46
+ },
47
+ {
48
+ id: "advanced",
49
+ intro: "Changes here affect every page. Most sites never need them.",
50
+ label: "Advanced",
51
+ note: "For developers",
52
+ },
53
+ ] as const;
54
+
55
+ /** A settings group's id. */
56
+ export type SettingsGroupId = (typeof SETTINGS_GROUPS)[number]["id"];
57
+
58
+ /** Where a section with no `group` is listed: the extension default `extensions.md` §9.1 names. */
59
+ export const DEFAULT_SETTINGS_GROUP: SettingsGroupId = "integrations";
60
+
61
+ /**
62
+ * Whether a value names one of {@link SETTINGS_GROUPS}.
63
+ *
64
+ * @param {unknown} value
65
+ * @returns {boolean}
66
+ */
67
+ export function isSettingsGroupId(value: unknown): value is SettingsGroupId {
68
+ return SETTINGS_GROUPS.some((group) => group.id === value);
69
+ }
70
+
25
71
  /** A Project Settings section: an inner-nav entry plus a renderer for the content area. */
26
72
  export interface SettingsSection {
27
73
  key: string;
28
74
  label: string;
75
+ /** Which nav group lists the section. Absent means {@link DEFAULT_SETTINGS_GROUP}. */
76
+ group?: SettingsGroupId | undefined;
29
77
  /**
30
78
  * Nav icon name (reserved for future nav treatments).
31
79
  *
@@ -37,7 +85,20 @@ export interface SettingsSection {
37
85
  icon?: string | undefined;
38
86
  /** Sort position — lower orders render higher in the inner nav. */
39
87
  order: number;
40
- render: (container: HTMLElement) => void;
88
+ /**
89
+ * The sentence the body opens with while THIS section shows, in place of its group's `intro`.
90
+ *
91
+ * A group's sentence says what the group is for, and a section that is not that (Content Types is
92
+ * a list of the project's collections, not something to turn on) says what it is instead. Absent
93
+ * or empty, the group's sentence stands.
94
+ */
95
+ intro?: string | undefined;
96
+ /**
97
+ * Draw the section into `container`. A renderer that returns a promise is awaited, so a section
98
+ * whose first paint needs IO fails where the reader is looking: a rejection, like a throw, is
99
+ * shown in the body in place of the section (`panels/settings-pane.ts`).
100
+ */
101
+ render: (container: HTMLElement) => void | Promise<void>;
41
102
  }
42
103
 
43
104
  /** Where a settings document lands when nobody named a section. */
@@ -110,9 +171,53 @@ export function sortedSettingsSections(): SettingsSection[] {
110
171
  return [...sections.values()].toSorted((a, b) => a.order - b.order);
111
172
  }
112
173
 
113
- /** Every registered section key, built-ins and contributions alike, in display order. */
174
+ /** One nav group and the sections listed under it. */
175
+ export interface SettingsSectionGroup {
176
+ id: SettingsGroupId;
177
+ label: string;
178
+ /** A qualifier drawn beside the label ("For developers"), or the empty string. */
179
+ note: string;
180
+ /** What the body opens with while one of this group's sections shows, or the empty string. */
181
+ intro: string;
182
+ sections: SettingsSection[];
183
+ }
184
+
185
+ /**
186
+ * The registered sections in their nav groups: groups in {@link SETTINGS_GROUPS} order, sections in
187
+ * `order` within each. A group with no section is left out, so an empty heading is never drawn.
188
+ *
189
+ * @returns {SettingsSectionGroup[]}
190
+ */
191
+ export function groupedSettingsSections(): SettingsSectionGroup[] {
192
+ const sorted = sortedSettingsSections();
193
+ return SETTINGS_GROUPS.flatMap((group) => {
194
+ const listed = sorted.filter(
195
+ (section) => (section.group ?? DEFAULT_SETTINGS_GROUP) === group.id,
196
+ );
197
+ return listed.length === 0
198
+ ? []
199
+ : [
200
+ {
201
+ id: group.id,
202
+ intro: group.intro,
203
+ label: group.label,
204
+ note: group.note,
205
+ sections: listed,
206
+ },
207
+ ];
208
+ });
209
+ }
210
+
211
+ /**
212
+ * Every registered section key, built-ins and contributions alike, in display order.
213
+ *
214
+ * Display order is the GROUPED order (General, then Integrations, then Advanced), so the gear's
215
+ * submenu and a refusal naming the registered keys list them as the reader sees them.
216
+ *
217
+ * @returns {string[]}
218
+ */
114
219
  export function settingsSectionKeys(): string[] {
115
- return sortedSettingsSections().map((section) => section.key);
220
+ return groupedSettingsSections().flatMap((group) => group.sections.map((section) => section.key));
116
221
  }
117
222
 
118
223
  /**