@heycys/gallery 0.1.1 → 0.2.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 (473) hide show
  1. package/THIRD-PARTY-NOTICES.md +2 -2
  2. package/browser/editor/components/align.mjs +58 -0
  3. package/browser/editor/components/code/index.mjs +1 -1
  4. package/browser/editor/components/columns/page.mjs +4 -4
  5. package/browser/editor/components/embed/index.mjs +2 -2
  6. package/browser/editor/components/embed/page.mjs +1 -1
  7. package/browser/editor/components/file/page.mjs +4 -4
  8. package/browser/editor/components/flowchart/add.mjs +7 -6
  9. package/browser/editor/components/flowchart/page.mjs +1 -1
  10. package/browser/editor/components/heading/index.mjs +7 -6
  11. package/browser/editor/components/icons.mjs +11 -0
  12. package/browser/editor/components/image/crop.mjs +6 -9
  13. package/browser/editor/components/image/index.mjs +2 -0
  14. package/browser/editor/components/image/page.mjs +172 -90
  15. package/browser/editor/components/installed/index.mjs +15 -4
  16. package/browser/editor/components/installed/page.mjs +103 -25
  17. package/browser/editor/components/installed/served.mjs +6 -5
  18. package/browser/editor/components/instances.mjs +18 -0
  19. package/browser/editor/components/list/page.mjs +3 -6
  20. package/browser/editor/components/media/icons.mjs +13 -8
  21. package/browser/editor/components/media/page.mjs +5 -3
  22. package/browser/editor/components/media/toolbar.mjs +12 -3
  23. package/browser/editor/components/paragraph/index.mjs +4 -3
  24. package/browser/editor/components/registry.mjs +30 -9
  25. package/browser/editor/components/table/index.mjs +61 -2
  26. package/browser/editor/components/table/page.mjs +1 -1
  27. package/browser/editor/page/after/index.mjs +288 -0
  28. package/browser/editor/page/align.mjs +91 -0
  29. package/browser/editor/page/annotate/card.mjs +3 -6
  30. package/browser/editor/page/autosave.mjs +310 -37
  31. package/browser/editor/page/beside.mjs +5 -6
  32. package/browser/editor/page/block-menu/index.mjs +6 -3
  33. package/browser/editor/page/blocks.mjs +3 -1
  34. package/browser/editor/page/board/client.mjs +57 -0
  35. package/browser/editor/page/board/hint.mjs +182 -0
  36. package/browser/editor/page/board/history.mjs +119 -0
  37. package/browser/editor/page/board/index.mjs +1059 -0
  38. package/browser/editor/page/board/motion.mjs +177 -0
  39. package/browser/editor/page/board/settings.mjs +210 -0
  40. package/browser/editor/page/caret.mjs +1 -1
  41. package/browser/editor/page/changes/bar.mjs +6 -14
  42. package/browser/editor/page/changes/index.mjs +2 -2
  43. package/browser/editor/page/clipboard/import/html.mjs +29 -6
  44. package/browser/editor/page/clipboard/import/inline.mjs +32 -0
  45. package/browser/editor/page/clipboard/import/markdown.mjs +58 -13
  46. package/browser/editor/page/clipboard/import/read.mjs +6 -1
  47. package/browser/editor/page/clipboard/import/to-blocks.mjs +44 -12
  48. package/browser/editor/page/clipboard/import/yuque.mjs +622 -0
  49. package/browser/editor/page/clipboard/index.mjs +133 -15
  50. package/browser/editor/page/clipboard/own/blocks.mjs +13 -14
  51. package/browser/editor/page/clipboard/own/chart-keys.mjs +41 -28
  52. package/browser/editor/page/clipboard/own/describe.mjs +6 -2
  53. package/browser/editor/page/clipboard/own/selection.mjs +1 -1
  54. package/browser/editor/page/columns/index.mjs +48 -46
  55. package/browser/editor/page/commit.mjs +80 -22
  56. package/browser/editor/page/conflicts.mjs +7 -7
  57. package/browser/editor/page/core.mjs +34 -16
  58. package/browser/editor/page/custom-page.mjs +110 -0
  59. package/browser/editor/page/editor.mjs +71 -17
  60. package/browser/editor/page/emoji-picker/styles.mjs +7 -12
  61. package/browser/editor/page/emoji-picker/upload.mjs +2 -2
  62. package/browser/editor/page/handle/index.mjs +5 -8
  63. package/browser/editor/page/history.mjs +41 -6
  64. package/browser/editor/page/insert/index.mjs +20 -22
  65. package/browser/editor/page/links/index.mjs +5 -3
  66. package/browser/editor/page/links/pages.mjs +27 -9
  67. package/browser/editor/page/look.mjs +54 -3
  68. package/browser/editor/page/margin.mjs +18 -3
  69. package/browser/editor/page/media-menu/index.mjs +6 -7
  70. package/browser/editor/page/menu.mjs +33 -14
  71. package/browser/editor/page/notices.mjs +2 -2
  72. package/browser/editor/page/page-objects.mjs +9 -2
  73. package/browser/editor/page/panel.mjs +4 -9
  74. package/browser/editor/page/present-links.mjs +15 -5
  75. package/browser/editor/page/present-shell.mjs +63 -0
  76. package/browser/editor/page/resize/index.mjs +42 -29
  77. package/browser/editor/page/selection/index.mjs +10 -2
  78. package/browser/editor/page/served.mjs +14 -0
  79. package/browser/editor/page/session.mjs +48 -4
  80. package/browser/editor/page/slash-menu/index.mjs +3 -3
  81. package/browser/editor/page/table/binding.mjs +87 -0
  82. package/browser/editor/page/table/cells.mjs +102 -46
  83. package/browser/editor/page/table/index.mjs +24 -9
  84. package/browser/editor/page/table/pictures.mjs +299 -0
  85. package/browser/editor/page/table/views.mjs +103 -0
  86. package/browser/editor/page/table/widths.mjs +82 -10
  87. package/browser/editor/page/text-select/index.mjs +26 -12
  88. package/browser/editor/page/todo-writes.mjs +75 -0
  89. package/browser/editor/page/typing/index.mjs +97 -15
  90. package/browser/editor/page/typing/leave.mjs +19 -5
  91. package/browser/editor/page/ui.mjs +13 -0
  92. package/browser/shared/block-packs.mjs +419 -0
  93. package/browser/shared/board-places.mjs +224 -0
  94. package/browser/shared/card-size.mjs +59 -0
  95. package/browser/shared/colors.mjs +3 -2
  96. package/browser/shared/component-catalog.mjs +330 -46
  97. package/browser/shared/component-source.mjs +39 -0
  98. package/browser/shared/components/heading.mjs +2 -1
  99. package/browser/shared/components/index.mjs +12 -3
  100. package/browser/shared/components/installed.mjs +35 -3
  101. package/browser/shared/components/page.mjs +20 -8
  102. package/browser/shared/components/paragraph.mjs +8 -1
  103. package/browser/shared/components/state.mjs +5 -1
  104. package/browser/shared/components/table.mjs +1 -0
  105. package/browser/shared/document-look.mjs +10 -5
  106. package/browser/shared/drafts.mjs +432 -0
  107. package/browser/shared/emoji/line-icons.mjs +37 -0
  108. package/browser/shared/extension-sidebar.mjs +126 -0
  109. package/browser/shared/extensions.mjs +79 -0
  110. package/browser/shared/file-table.mjs +101 -0
  111. package/browser/shared/http.mjs +9 -0
  112. package/browser/shared/i18n/en.mjs +330 -27
  113. package/browser/shared/json-layout.mjs +47 -0
  114. package/browser/shared/net-cache.mjs +133 -0
  115. package/browser/shared/net-keys.mjs +32 -0
  116. package/browser/shared/net-policy.mjs +177 -0
  117. package/browser/shared/outline-shape.mjs +128 -0
  118. package/browser/shared/outline.mjs +359 -67
  119. package/browser/shared/pack-manifest.mjs +88 -0
  120. package/browser/shared/page-address.mjs +6 -3
  121. package/browser/shared/page-cards.mjs +308 -0
  122. package/browser/shared/page-links.mjs +69 -6
  123. package/browser/shared/pages.mjs +500 -0
  124. package/browser/shared/paths.mjs +6 -0
  125. package/browser/shared/pinyin.mjs +92 -0
  126. package/browser/shared/present-step.mjs +17 -0
  127. package/browser/shared/preview-server.mjs +3 -7
  128. package/browser/shared/session.mjs +8 -1
  129. package/browser/shared/shipped-blocks.mjs +299 -0
  130. package/browser/shared/sidebar-head.mjs +70 -0
  131. package/browser/shared/table-chart.mjs +33 -1
  132. package/browser/shared/todos.mjs +83 -0
  133. package/browser/shared/user-directory.mjs +24 -0
  134. package/browser/shared/versions.mjs +14 -0
  135. package/browser/shared/web-links.mjs +139 -0
  136. package/browser/shared/workspace-columns.mjs +120 -0
  137. package/browser/shared/workspace-name.mjs +154 -0
  138. package/browser/shared/workspace-query.mjs +125 -0
  139. package/browser/shared/workspace-registry.mjs +272 -0
  140. package/browser/shared/workspace.mjs +171 -20
  141. package/dist/chunk-2OHANJ6Q.mjs +2 -0
  142. package/dist/chunk-3MBRL2PM.mjs +16 -0
  143. package/dist/chunk-4OKWZY5E.mjs +2 -0
  144. package/dist/chunk-4OZWXZE5.mjs +5 -0
  145. package/dist/chunk-5K44HLTZ.mjs +2 -0
  146. package/dist/{chunk-5ZKJ3H4P.mjs → chunk-5XA2ZBAE.mjs} +3 -3
  147. package/dist/{chunk-4FS7Z7WR.mjs → chunk-67N2QJYT.mjs} +1 -1
  148. package/dist/chunk-6KBYRA2C.mjs +2 -0
  149. package/dist/chunk-6N3PX4XX.mjs +8 -0
  150. package/dist/{chunk-V5JTW2LH.mjs → chunk-6QBHU4DF.mjs} +1 -1
  151. package/dist/chunk-7JDX4E65.mjs +13 -0
  152. package/dist/chunk-7M2BQQGZ.mjs +2 -0
  153. package/dist/chunk-7OG26PGF.mjs +2 -0
  154. package/dist/chunk-AHN3NFKJ.mjs +3 -0
  155. package/dist/chunk-ALZ6ZENZ.mjs +3 -0
  156. package/dist/chunk-AR5D57ZD.mjs +170 -0
  157. package/dist/{chunk-W3BGBJQW.mjs → chunk-BFJGHSQN.mjs} +1 -1
  158. package/dist/{chunk-LS4F7JUM.mjs → chunk-BZ5RAF7L.mjs} +1 -1
  159. package/dist/chunk-CMA72MAG.mjs +2 -0
  160. package/dist/{chunk-LCTHTZIL.mjs → chunk-DAZL73VK.mjs} +91 -91
  161. package/dist/{chunk-Y6RLRPG3.mjs → chunk-DJISHPUL.mjs} +1 -1
  162. package/dist/chunk-DR73Y2UJ.mjs +3 -0
  163. package/dist/{chunk-FDLXYYG4.mjs → chunk-EAIFITAV.mjs} +1 -1
  164. package/dist/{chunk-TMYZB6AV.mjs → chunk-EKNHM3P4.mjs} +1 -1
  165. package/dist/chunk-EP25HDAJ.mjs +2 -0
  166. package/dist/{chunk-GB5SOYQJ.mjs → chunk-ERLAIBOA.mjs} +2 -2
  167. package/dist/chunk-EURLTOTZ.mjs +4 -0
  168. package/dist/chunk-F4ZA6JRZ.mjs +3 -0
  169. package/dist/chunk-F6HVDZR4.mjs +2 -0
  170. package/dist/chunk-FDMAXMQA.mjs +2 -0
  171. package/dist/chunk-FETSREUN.mjs +5 -0
  172. package/dist/chunk-GHOYKMQ3.mjs +4 -0
  173. package/dist/{chunk-2B5E4CDJ.mjs → chunk-GPIWQ4X4.mjs} +1 -1
  174. package/dist/chunk-HDWTZ763.mjs +12 -0
  175. package/dist/chunk-HPOI4ZX7.mjs +6 -0
  176. package/dist/{chunk-BGGDRNYQ.mjs → chunk-HXG7EOPJ.mjs} +1 -1
  177. package/dist/chunk-IA4PSIMD.mjs +2 -0
  178. package/dist/{chunk-E7LWZRXY.mjs → chunk-ITOH5EGO.mjs} +1 -1
  179. package/dist/chunk-IV64FFI4.mjs +2 -0
  180. package/dist/chunk-J43Z6LSS.mjs +2 -0
  181. package/dist/chunk-J5PUIV3Y.mjs +4 -0
  182. package/dist/chunk-JA7G53PC.mjs +2 -0
  183. package/dist/chunk-JEUK3ZO7.mjs +2 -0
  184. package/dist/chunk-JLTZF4LA.mjs +2 -0
  185. package/dist/chunk-JZT7I2OJ.mjs +2 -0
  186. package/dist/chunk-K5XATEOO.mjs +2 -0
  187. package/dist/chunk-L2SUIS5S.mjs +2 -0
  188. package/dist/chunk-L7UP52JO.mjs +2 -0
  189. package/dist/chunk-LM4XFQHZ.mjs +2 -0
  190. package/dist/chunk-MN7BZL4R.mjs +2 -0
  191. package/dist/chunk-MTYYHM2G.mjs +15 -0
  192. package/dist/chunk-MXUBKDRO.mjs +15 -0
  193. package/dist/chunk-NAMN3RAF.mjs +2 -0
  194. package/dist/{chunk-SYGN7GLU.mjs → chunk-OEXWRJME.mjs} +1 -1
  195. package/dist/chunk-OFHXGWOX.mjs +2 -0
  196. package/dist/chunk-ORID3AE7.mjs +166 -0
  197. package/dist/chunk-PAREWQGB.mjs +4 -0
  198. package/dist/chunk-PGDE24N5.mjs +2 -0
  199. package/dist/chunk-POTA2FV4.mjs +2 -0
  200. package/dist/chunk-PUOQ65NC.mjs +2 -0
  201. package/dist/chunk-Q4UEPUWF.mjs +2 -0
  202. package/dist/chunk-QE5RG76S.mjs +549 -0
  203. package/dist/chunk-R2ZDLJYT.mjs +10 -0
  204. package/dist/{chunk-7DTINW6U.mjs → chunk-SQ6Y2ZMA.mjs} +2 -2
  205. package/dist/chunk-SWUTTZCN.mjs +2 -0
  206. package/dist/chunk-TANZRINB.mjs +2 -0
  207. package/dist/chunk-TR7TWGHB.mjs +2 -0
  208. package/dist/chunk-U5XL7D6A.mjs +3 -0
  209. package/dist/{chunk-XNROSH2T.mjs → chunk-U7NZI6N4.mjs} +2 -2
  210. package/dist/chunk-UGWMMEJ5.mjs +15 -0
  211. package/dist/chunk-UJQJKNGK.mjs +2 -0
  212. package/dist/chunk-UYVCQK3H.mjs +22 -0
  213. package/dist/chunk-VFX2KNHP.mjs +4 -0
  214. package/dist/chunk-VS7JIGJW.mjs +24 -0
  215. package/dist/chunk-W7665ZEC.mjs +6 -0
  216. package/dist/chunk-WQDQWCX5.mjs +2 -0
  217. package/dist/chunk-YI43RG4P.mjs +2 -0
  218. package/dist/chunk-YLPSMDIS.mjs +5 -0
  219. package/dist/chunk-YNAWBAYN.mjs +3 -0
  220. package/dist/chunk-YROX2O22.mjs +2 -0
  221. package/dist/chunk-ZDLPUOAG.mjs +6 -0
  222. package/dist/{chunk-IVDLMMBD.mjs → chunk-ZHEHPMBK.mjs} +1 -1
  223. package/dist/chunk-ZQS6H473.mjs +16 -0
  224. package/dist/chunk-ZTHICSSF.mjs +2 -0
  225. package/dist/chunk-ZWWC4KLF.mjs +20 -0
  226. package/dist/cli.mjs +1 -1
  227. package/dist/server.mjs +1 -1
  228. package/dist/{chunk-U6KNPJPR.mjs → update-fetch.mjs} +1 -1
  229. package/dist/worker.mjs +1 -1
  230. package/kit/board.css +95 -0
  231. package/kit/board.js +250 -0
  232. package/kit/charts.js +5 -71
  233. package/kit/code.js +17 -17
  234. package/kit/report.css +335 -18
  235. package/kit/runtime.js +1638 -125
  236. package/kit/state.js +10 -1
  237. package/kit/tables.js +130 -43
  238. package/kit/ui.js +79 -35
  239. package/package.json +2 -1
  240. package/packs/gallery/card/component.json +14 -0
  241. package/packs/gallery/card/example.html +10 -0
  242. package/packs/gallery/card/preview.svg +1 -0
  243. package/packs/gallery/card/style.css +6 -0
  244. package/packs/gallery/card/template.html +6 -0
  245. package/packs/gallery/card/writing.md +14 -0
  246. package/packs/gallery/chart-card/component.json +15 -0
  247. package/packs/gallery/chart-card/example.html +14 -0
  248. package/packs/gallery/chart-card/kit.js +130 -0
  249. package/packs/gallery/chart-card/preview.svg +1 -0
  250. package/packs/gallery/chart-card/style.css +42 -0
  251. package/packs/gallery/chart-card/template.html +13 -0
  252. package/packs/gallery/chart-card/writing.md +20 -0
  253. package/packs/gallery/chart-view/component.json +20 -0
  254. package/packs/gallery/chart-view/example.html +13 -0
  255. package/packs/gallery/chart-view/kit.js +355 -0
  256. package/packs/gallery/chart-view/preview.svg +1 -0
  257. package/packs/gallery/chart-view/style.css +94 -0
  258. package/packs/gallery/chart-view/template.html +3 -0
  259. package/packs/gallery/chart-view/writing.md +22 -0
  260. package/packs/gallery/countdown/component.json +18 -0
  261. package/packs/gallery/countdown/example.html +3 -0
  262. package/packs/gallery/countdown/kit.js +216 -0
  263. package/packs/gallery/countdown/preview.svg +1 -0
  264. package/packs/gallery/countdown/style.css +118 -0
  265. package/packs/gallery/countdown/template.html +3 -0
  266. package/packs/gallery/countdown/writing.md +22 -0
  267. package/packs/gallery/habit/component.json +14 -0
  268. package/packs/gallery/habit/example.html +3 -0
  269. package/packs/gallery/habit/kit.js +334 -0
  270. package/packs/gallery/habit/preview.svg +1 -0
  271. package/packs/gallery/habit/style.css +174 -0
  272. package/packs/gallery/habit/template.html +3 -0
  273. package/packs/gallery/habit/writing.md +21 -0
  274. package/packs/gallery/heatmap/component.json +18 -0
  275. package/packs/gallery/heatmap/example.html +3 -0
  276. package/packs/gallery/heatmap/kit.js +513 -0
  277. package/packs/gallery/heatmap/preview.svg +1 -0
  278. package/packs/gallery/heatmap/style.css +189 -0
  279. package/packs/gallery/heatmap/template.html +3 -0
  280. package/packs/gallery/heatmap/writing.md +21 -0
  281. package/packs/gallery/kanban/component.json +18 -0
  282. package/packs/gallery/kanban/example.html +12 -0
  283. package/packs/gallery/kanban/kit.js +540 -0
  284. package/packs/gallery/kanban/preview.svg +1 -0
  285. package/packs/gallery/kanban/style.css +212 -0
  286. package/packs/gallery/kanban/template.html +3 -0
  287. package/packs/gallery/kanban/writing.md +20 -0
  288. package/packs/gallery/metric/component.json +22 -0
  289. package/packs/gallery/metric/example.html +15 -0
  290. package/packs/gallery/metric/kit.js +248 -0
  291. package/packs/gallery/metric/preview.svg +1 -0
  292. package/packs/gallery/metric/style.css +92 -0
  293. package/packs/gallery/metric/template.html +3 -0
  294. package/packs/gallery/metric/writing.md +23 -0
  295. package/packs/gallery/note/component.json +14 -0
  296. package/packs/gallery/note/example.html +3 -0
  297. package/packs/gallery/note/kit.js +129 -0
  298. package/packs/gallery/note/preview.svg +1 -0
  299. package/packs/gallery/note/style.css +97 -0
  300. package/packs/gallery/note/template.html +3 -0
  301. package/packs/gallery/note/writing.md +18 -0
  302. package/packs/gallery/pack.json +8 -0
  303. package/packs/gallery/recent/component.json +13 -0
  304. package/packs/gallery/recent/example.html +1 -0
  305. package/packs/gallery/recent/kit.js +293 -0
  306. package/packs/gallery/recent/preview.svg +1 -0
  307. package/packs/gallery/recent/style.css +85 -0
  308. package/packs/gallery/recent/template.html +1 -0
  309. package/packs/gallery/recent/writing.md +15 -0
  310. package/packs/gallery/static/component.json +13 -0
  311. package/packs/gallery/static/example.html +11 -0
  312. package/packs/gallery/static/preview.svg +1 -0
  313. package/packs/gallery/static/style.css +171 -0
  314. package/packs/gallery/static/template.html +1 -0
  315. package/packs/gallery/static/writing.md +18 -0
  316. package/packs/gallery/stats/component.json +13 -0
  317. package/packs/gallery/stats/example.html +1 -0
  318. package/packs/gallery/stats/kit.js +347 -0
  319. package/packs/gallery/stats/preview.svg +1 -0
  320. package/packs/gallery/stats/style.css +73 -0
  321. package/packs/gallery/stats/template.html +1 -0
  322. package/packs/gallery/stats/writing.md +11 -0
  323. package/packs/gallery/today/component.json +12 -0
  324. package/packs/gallery/today/example.html +1 -0
  325. package/packs/gallery/today/kit.js +220 -0
  326. package/packs/gallery/today/preview.svg +1 -0
  327. package/packs/gallery/today/style.css +149 -0
  328. package/packs/gallery/today/template.html +1 -0
  329. package/packs/gallery/today/writing.md +14 -0
  330. package/packs/gallery/todos/component.json +19 -0
  331. package/packs/gallery/todos/example.html +3 -0
  332. package/packs/gallery/todos/kit.js +489 -0
  333. package/packs/gallery/todos/preview.svg +1 -0
  334. package/packs/gallery/todos/style.css +214 -0
  335. package/packs/gallery/todos/template.html +3 -0
  336. package/packs/gallery/todos/writing.md +30 -0
  337. package/packs/gallery/weather/component.json +19 -0
  338. package/packs/gallery/weather/example.html +3 -0
  339. package/packs/gallery/weather/kit.js +387 -0
  340. package/packs/gallery/weather/preview.svg +1 -0
  341. package/packs/gallery/weather/style.css +140 -0
  342. package/packs/gallery/weather/template.html +3 -0
  343. package/packs/gallery/weather/writing.md +26 -0
  344. package/packs/gallery-soft/countdown/component.json +18 -0
  345. package/packs/gallery-soft/countdown/example.html +3 -0
  346. package/packs/gallery-soft/countdown/kit.js +206 -0
  347. package/packs/gallery-soft/countdown/preview.svg +1 -0
  348. package/packs/gallery-soft/countdown/style.css +211 -0
  349. package/packs/gallery-soft/countdown/template.html +3 -0
  350. package/packs/gallery-soft/countdown/writing.md +24 -0
  351. package/packs/gallery-soft/habit/component.json +14 -0
  352. package/packs/gallery-soft/habit/example.html +3 -0
  353. package/packs/gallery-soft/habit/kit.js +366 -0
  354. package/packs/gallery-soft/habit/preview.svg +1 -0
  355. package/packs/gallery-soft/habit/style.css +251 -0
  356. package/packs/gallery-soft/habit/template.html +3 -0
  357. package/packs/gallery-soft/habit/writing.md +23 -0
  358. package/packs/gallery-soft/heatmap/component.json +18 -0
  359. package/packs/gallery-soft/heatmap/example.html +3 -0
  360. package/packs/gallery-soft/heatmap/kit.js +498 -0
  361. package/packs/gallery-soft/heatmap/preview.svg +1 -0
  362. package/packs/gallery-soft/heatmap/style.css +181 -0
  363. package/packs/gallery-soft/heatmap/template.html +3 -0
  364. package/packs/gallery-soft/heatmap/writing.md +23 -0
  365. package/packs/gallery-soft/note/component.json +14 -0
  366. package/packs/gallery-soft/note/example.html +3 -0
  367. package/packs/gallery-soft/note/kit.js +162 -0
  368. package/packs/gallery-soft/note/preview.svg +1 -0
  369. package/packs/gallery-soft/note/style.css +148 -0
  370. package/packs/gallery-soft/note/template.html +3 -0
  371. package/packs/gallery-soft/note/writing.md +20 -0
  372. package/packs/gallery-soft/pack.json +8 -0
  373. package/packs/gallery-soft/recent/component.json +13 -0
  374. package/packs/gallery-soft/recent/example.html +1 -0
  375. package/packs/gallery-soft/recent/kit.js +335 -0
  376. package/packs/gallery-soft/recent/preview.svg +1 -0
  377. package/packs/gallery-soft/recent/style.css +160 -0
  378. package/packs/gallery-soft/recent/template.html +1 -0
  379. package/packs/gallery-soft/recent/writing.md +17 -0
  380. package/packs/gallery-soft/static/component.json +13 -0
  381. package/packs/gallery-soft/static/example.html +12 -0
  382. package/packs/gallery-soft/static/preview.svg +1 -0
  383. package/packs/gallery-soft/static/style.css +186 -0
  384. package/packs/gallery-soft/static/template.html +1 -0
  385. package/packs/gallery-soft/static/writing.md +20 -0
  386. package/packs/gallery-soft/stats/component.json +13 -0
  387. package/packs/gallery-soft/stats/example.html +1 -0
  388. package/packs/gallery-soft/stats/kit.js +341 -0
  389. package/packs/gallery-soft/stats/preview.svg +1 -0
  390. package/packs/gallery-soft/stats/style.css +119 -0
  391. package/packs/gallery-soft/stats/template.html +1 -0
  392. package/packs/gallery-soft/stats/writing.md +13 -0
  393. package/packs/gallery-soft/today/component.json +12 -0
  394. package/packs/gallery-soft/today/example.html +1 -0
  395. package/packs/gallery-soft/today/kit.js +222 -0
  396. package/packs/gallery-soft/today/preview.svg +1 -0
  397. package/packs/gallery-soft/today/style.css +178 -0
  398. package/packs/gallery-soft/today/template.html +1 -0
  399. package/packs/gallery-soft/today/writing.md +16 -0
  400. package/packs/gallery-soft/todos/component.json +19 -0
  401. package/packs/gallery-soft/todos/example.html +3 -0
  402. package/packs/gallery-soft/todos/kit.js +527 -0
  403. package/packs/gallery-soft/todos/preview.svg +1 -0
  404. package/packs/gallery-soft/todos/style.css +212 -0
  405. package/packs/gallery-soft/todos/template.html +3 -0
  406. package/packs/gallery-soft/todos/writing.md +32 -0
  407. package/packs/gallery-soft/weather/component.json +19 -0
  408. package/packs/gallery-soft/weather/example.html +3 -0
  409. package/packs/gallery-soft/weather/kit.js +411 -0
  410. package/packs/gallery-soft/weather/preview.svg +1 -0
  411. package/packs/gallery-soft/weather/style.css +185 -0
  412. package/packs/gallery-soft/weather/template.html +3 -0
  413. package/packs/gallery-soft/weather/writing.md +28 -0
  414. package/release.json +12 -10
  415. package/sdk/doc-kit.d.ts +396 -5
  416. package/sdk/doc-state.d.ts +2 -0
  417. package/skill/SKILL.md +56 -23
  418. package/skill/references/block-script.md +140 -0
  419. package/skill/references/building-blocks.md +257 -0
  420. package/skill/references/extensions.md +59 -0
  421. package/skill/references/pages-and-data.md +225 -0
  422. package/skill/references/writing-html.md +8 -4
  423. package/skill/sdk/doc-kit.d.ts +396 -5
  424. package/skill/sdk/doc-state.d.ts +2 -0
  425. package/web/assets/index-BM_K-Auu.css +1 -0
  426. package/web/assets/index-DRslOBiv.js +15 -0
  427. package/web/index.html +2 -2
  428. package/dist/chunk-3HIRPVLU.mjs +0 -2
  429. package/dist/chunk-5MHMDLZD.mjs +0 -4
  430. package/dist/chunk-64K7IPLO.mjs +0 -255
  431. package/dist/chunk-6QXGZM36.mjs +0 -8
  432. package/dist/chunk-6RGJOMJP.mjs +0 -16
  433. package/dist/chunk-AJ73XJF3.mjs +0 -2
  434. package/dist/chunk-AUZGSZJH.mjs +0 -13
  435. package/dist/chunk-BFE45AKL.mjs +0 -2
  436. package/dist/chunk-BXO2ZY5P.mjs +0 -2
  437. package/dist/chunk-CEH4MRCC.mjs +0 -2
  438. package/dist/chunk-CY2FNNAB.mjs +0 -16
  439. package/dist/chunk-DFUDV4LX.mjs +0 -2
  440. package/dist/chunk-DKXG4XDG.mjs +0 -2
  441. package/dist/chunk-EZQ34M3F.mjs +0 -124
  442. package/dist/chunk-EZY3WC6Z.mjs +0 -15
  443. package/dist/chunk-FUKQNOQS.mjs +0 -9
  444. package/dist/chunk-JPOSLGOC.mjs +0 -6
  445. package/dist/chunk-JVHHHGEA.mjs +0 -3
  446. package/dist/chunk-L3QKH4OK.mjs +0 -26
  447. package/dist/chunk-LAE5NQ4B.mjs +0 -2
  448. package/dist/chunk-LEF6DRCK.mjs +0 -59
  449. package/dist/chunk-NO5NJCHO.mjs +0 -2
  450. package/dist/chunk-NQPVAU63.mjs +0 -2
  451. package/dist/chunk-NSKUTQ5J.mjs +0 -5
  452. package/dist/chunk-O35FIXRB.mjs +0 -2
  453. package/dist/chunk-P2CAZPDP.mjs +0 -3
  454. package/dist/chunk-PL6GHLGD.mjs +0 -15
  455. package/dist/chunk-QJIR2BLP.mjs +0 -6
  456. package/dist/chunk-QUPLVPB2.mjs +0 -7
  457. package/dist/chunk-R7BNENLY.mjs +0 -4
  458. package/dist/chunk-S6O4UHLC.mjs +0 -2
  459. package/dist/chunk-SGJWQKEI.mjs +0 -2
  460. package/dist/chunk-TX6JH7TR.mjs +0 -2
  461. package/dist/chunk-TYK6VNAB.mjs +0 -10
  462. package/dist/chunk-UALRNVSE.mjs +0 -4
  463. package/dist/chunk-V3HXVQEM.mjs +0 -2
  464. package/dist/chunk-V5VXUJKG.mjs +0 -2
  465. package/dist/chunk-VBXMADMP.mjs +0 -2
  466. package/dist/chunk-VNV55RUA.mjs +0 -2
  467. package/dist/chunk-VPD2PS35.mjs +0 -2
  468. package/dist/chunk-W4VKN3GF.mjs +0 -7
  469. package/dist/chunk-W5BXXPDJ.mjs +0 -3
  470. package/dist/chunk-XUNHRCOG.mjs +0 -6
  471. package/skill/references/building-components.md +0 -367
  472. package/web/assets/index-Bh74DfsV.css +0 -1
  473. package/web/assets/index-UW0RyFFt.js +0 -13
@@ -1,17 +1,20 @@
1
1
  import { isUtf8 } from "node:buffer";
2
2
  import { createHash } from "node:crypto";
3
- import { lstatSync, readFileSync, realpathSync, statSync } from "node:fs";
3
+ import { existsSync, lstatSync, readFileSync, readdirSync, realpathSync, statSync } from "node:fs";
4
4
  import fs from "node:fs/promises";
5
5
  import path from "node:path";
6
6
  import { parseFragment, serializeOuter } from "parse5";
7
7
  import { isInstance, parseCompound, parsePart, parseSelector, partOf } from "./components/index.mjs";
8
- import { ATTRIBUTE, NO_TEXT, PACKAGE_ID, PACKAGE_MARK, SLOT, instanceMatch, refusedInCopy, settingState } from "./components/installed.mjs";
8
+ import { ATTRIBUTE, NO_TEXT, PACKAGE_ID, PACKAGE_MARK, SLOT, inDocumentMenus, instanceMatch, refusedInCopy, settingState } from "./components/installed.mjs";
9
9
  import { writeAtomic } from "./files.mjs";
10
10
  import { attr, walk } from "./html-tree.mjs";
11
+ import { HOST, NET, netHostsOf } from "./net-policy.mjs";
11
12
  import { inLanguage, refusal, said, saying, told } from "./i18n/index.mjs";
13
+ import { DEFAULT_PACK, OWN_SCOPE, PACK_FILE, PACK_ID, readPackManifest } from "./pack-manifest.mjs";
12
14
  import { DEVICE_NAMES, PACKAGE_MANIFEST, WORKSPACE_MARK, findWorkspace, layoutOf, markerOf, packageFolders } from "./workspace.mjs";
13
15
 
14
- // 组件包: what the workspace's component packages say of themselves to Gallery, read from
16
+ // 组件包, custom blocks (自定义块) as the UI and the Agent's documents call them: what the workspace's
17
+ // component packages say of themselves to Gallery, read from
15
18
  // <workspace>/components/<scope>/<name>/component.json, plain data, whose code no system runs here. A
16
19
  // package is a description as a kit component's is (src/shared/components/): its id, where its
17
20
  // instances are, its parts and what it leaves on a page, so that what reads a built-in's reads a
@@ -19,19 +22,22 @@ import { DEVICE_NAMES, PACKAGE_MANIFEST, WORKSPACE_MARK, findWorkspace, layoutOf
19
22
  // A manifest offers only FIELDS, no unit, box, host, rank or category: those are the engines', and a
20
23
  // field it does not know keeps its package from loading.
21
24
  //
22
- // The catalog is { packages, problems, settings, stamp }. `packages`, by id, are those that load. A
25
+ // The catalog is { packages, problems, settings, packs, stamp }. `packages`, by id, are those that load. A
23
26
  // package that does not load (a manifest that does not read as one, one for an apiVersion this Gallery
24
27
  // does not run, which counts as disabled, or one the settings turned off) stands in `problems`, by its
25
28
  // id in lowercase, as an instance names it, with why (`problem`, said()'s, in either language by
26
29
  // problemIn), and touches nothing else: its instances show as those of a package that is not there,
27
30
  // and whoever reads them says why. `settings` is what gallery.json says of the components (设置 › 组件列表,
28
- // componentSettings): `hidden` and `disabled`, by the id of a package or the name of a built-in
29
- // component, and `problem` where the file cannot be read as saying anything (settingsNow). A package
30
- // hidden runs as any other and is left out of the lists that offer one, each of which reads its state
31
- // (menuOf, packageStates); one disabled is one that does not load, so that nothing that loads a
31
+ // componentSettings): `hidden`, `disabled`, `shown` and `unlisted`, by the id of a package (`hidden` the name of a
32
+ // built-in component too), `packs` and `packsOff`, the packs' switches (a pack off: none of its blocks offered,
33
+ // as one unlisted), and `problem` where the file cannot be read as saying anything (settingsNow). `packs`, by
34
+ // the scope of a block (a pack: ./pack-manifest.mjs), what its pack.json names it, or null for a scope with
35
+ // none or one that does not read (who lists it says it by its scope).
36
+ // A package the document's menus do not offer (inDocumentMenus: hidden, unlisted, or a custom page's alone and not
37
+ // shown) runs as any other and is left out of those menus, which read its state (menuOf, packageStates); one disabled is one that does not load, so that nothing that loads a
32
38
  // package has a case for it. A stamp is a hash of what files hold: `stamp`, of a package, over what
33
39
  // reaches a page of it (STAMPED and the files `assets` names), of one that does not load over those
34
- // and why, and of the catalog, over its packages', what is hidden and whether gallery.json reads;
40
+ // and why, and of the catalog, over its packages', what is hidden, shown and unlisted and whether gallery.json reads;
35
41
  // `definition`, over the manifest alone, is what a page's commit is to be held to.
36
42
  //
37
43
  // readCatalog reads the disk; what reads a catalog for use (the scan, the checks, a page) asks
@@ -43,14 +49,38 @@ import { DEVICE_NAMES, PACKAGE_MANIFEST, WORKSPACE_MARK, findWorkspace, layoutOf
43
49
  /** The apiVersion this Gallery runs. */
44
50
  export const API_VERSION = 1;
45
51
 
46
- /** The kit's files a package may ask for by id in `assets`, as src/render/assets.mjs names them (the others are on every page). */
52
+ /** The kit's files a package may ask for by id in `assets`, as src/render/assets.mjs names them (the others are on every page, or, the board's, on every custom page). */
47
53
  export const KIT_ASSETS = new Set(["code", "state", "sheets", "tokens", "dialogs", "katex-styles", "katex", "katex-auto-render", "math", "d3", "charts", "tables"]);
48
54
 
49
55
  // What a manifest may hold, a part of one and its `runtime`.
50
- const FIELDS = ["id", "apiVersion", "version", "name", "description", "words", "parts", "runtime", "assets", "markdown", "schema"];
56
+ const FIELDS = ["id", "apiVersion", "version", "name", "description", "words", "parts", "runtime", "assets", "markdown", "schema", "places", "card", "settings", "needs"];
51
57
  const PART_FIELDS = ["at", "edit", "optional", "min", "max"];
52
58
  const RUNTIME_FIELDS = ["generated", "attrs"];
53
59
 
60
+ // Where a block may stand (`places`, notes/plans/custom-blocks-spec-2026-11-07.md section 1): in a
61
+ // document's flow, on a custom page's board as a card. One that says nothing is a document's, as every
62
+ // package before the field was.
63
+ const PLACES = ["document", "page"];
64
+ const DOCUMENT_ONLY = ["document"];
65
+ // What `card` says of a card on a board, in cells of the grid: a row is 12 of them, and a card at most
66
+ // 24 high.
67
+ const CARD_FIELDS = ["sizes", "w", "h", "min", "max", "resize", "fit", "bare", "consent"];
68
+ const GRID = { w: 12, h: 24 };
69
+ const FITS = ["fixed", "content"];
70
+ const NO_CARD = { sizes: null, any: false, w: 4, h: null, min: { w: 1, h: 1 }, max: { ...GRID }, resize: false, fit: "fixed", bare: false };
71
+ // A card setting: its key, a JavaScript name as a block reads it from its settings part; its kinds,
72
+ // each a field of the form the board draws; `required`: the card shows nothing until the setting holds a
73
+ // value (a weather card's city), which gallery page check says of a card that has none.
74
+ const SETTING_FIELDS = ["key", "label", "type", "options", "default", "required"];
75
+ const SETTING_KEY = /^[a-z][a-zA-Z0-9]*$/;
76
+ const SETTING_TYPES = ["text", "number", "select", "date", "switch", "document"];
77
+ const DATE = /^\d{4}-\d{2}-\d{2}$/;
78
+ /** The data part a block with settings keeps their values in, JSON, as the board's form writes them. */
79
+ export const SETTINGS_PART = "settings";
80
+ // What a block asks to use: the workspace's data, the keyed tables of its document, the network of a
81
+ // host (lowercase, no port and no path, "*." first for its subdomains: ./net-policy.mjs HOST).
82
+ const NEEDS = ["workspace", "tables"];
83
+
54
84
  // What a package's part may be edited as: its text, its data through the kit's edit, the document's
55
85
  // blocks (a slot, marked data-doc-slot="<name>" in its markup), or not at all.
56
86
  const EDITS = ["text", "data", "flow", "none"];
@@ -149,7 +179,7 @@ const notTooLong = (bytes, name) => {
149
179
  };
150
180
 
151
181
  const onlyFields = (table, fields, where = "") => {
152
- for (const key of Object.keys(table)) if (!fields.includes(key)) fail(said("{0} 不是组件包能写的字段", `${where}${key}`));
182
+ for (const key of Object.keys(table)) if (!fields.includes(key)) fail(said("{0} 不是自定义块的清单能写的字段", `${where}${key}`));
153
183
  };
154
184
  const required = (manifest, fields) => {
155
185
  for (const field of fields) if (manifest[field] === undefined) fail(said("缺少 {0}", field));
@@ -210,7 +240,7 @@ function runtimeOf(runtime, id) {
210
240
  if (!isTable(attrs)) fail(said("{0} 要写成一张表", "runtime.attrs"));
211
241
  for (const names of Object.values(attrs)) {
212
242
  if (!Array.isArray(names) || !names.every(isWords)) fail(said("{0} 要写成一串文字", "runtime.attrs"));
213
- for (const name of names) if (OWN_NAME.test(name)) fail(said("{0} 是 Gallery 自己的名字,组件包不能用", name));
243
+ for (const name of names) if (OWN_NAME.test(name)) fail(said("{0} 是 Gallery 自己的名字,自定义块不能用", name));
214
244
  }
215
245
  const made = (selector) => {
216
246
  const written = scoped(selector, "runtime.generated");
@@ -223,14 +253,140 @@ function runtimeOf(runtime, id) {
223
253
  };
224
254
  }
225
255
 
256
+ const isCount = (value, most) => Number.isInteger(value) && value >= 1 && value <= most;
257
+ const twice = (list) => list.find((value, index) => list.indexOf(value) !== index);
258
+
259
+ // `places`: one place or both, each once.
260
+ function placesOf(places) {
261
+ if (places === undefined) return DOCUMENT_ONLY;
262
+ if (!Array.isArray(places) || places.length === 0 || !places.every((place) => PLACES.includes(place))) fail(said("places 要写成 document、page 中的一个或两个,如 [\"document\"]"));
263
+ if (twice(places)) fail(said("places 里 {0} 写了两次", twice(places)));
264
+ return [...places];
265
+ }
266
+
267
+ // `card`: as a board reads it, every field there (NO_CARD's where the manifest says nothing; `h` null:
268
+ // the fewest whole cells its content takes). With `sizes`, the first is the default, and no w or h is
269
+ // written beside them; a min or a max beside them frees the card (`any`): the sizes are the common ones
270
+ // its 大小 menu lists, any whole size between min and max is its too (resizing by the corner, a place),
271
+ // and each of the sizes stands inside them. `consent` ({ zh, en }, where it says one) is what the kit's
272
+ // banner on its card says while it waits for the reader to let it online (允许联网之后显示天气), in place of
273
+ // the kit's own line (允许联网之后显示内容).
274
+ function cardOf(card) {
275
+ if (card === undefined) return NO_CARD;
276
+ if (!isTable(card)) fail(said("{0} 要写成一张表", "card"));
277
+ onlyFields(card, CARD_FIELDS, "card.");
278
+ const sized = (pair) => Array.isArray(pair) && pair.length === 2 && isCount(pair[0], GRID.w) && isCount(pair[1], GRID.h);
279
+ if (card.sizes !== undefined) {
280
+ if (!Array.isArray(card.sizes) || card.sizes.length === 0 || !card.sizes.every(sized)) fail(said("card.sizes 要写成 [宽, 高] 的一串,宽 1 到 {0} 格,高 1 到 {1} 格", GRID.w, GRID.h));
281
+ const repeated = twice(card.sizes.map((pair) => pair.join("x")));
282
+ if (repeated) fail(said("card.sizes 里 {0} 写了两次", repeated));
283
+ const beside = ["w", "h"].find((field) => card[field] !== undefined);
284
+ if (beside) fail(said("写了 card.sizes,就不再写 card.{0}:第一种大小是默认的", beside));
285
+ }
286
+ for (const axis of ["w", "h"]) if (card[axis] !== undefined && !isCount(card[axis], GRID[axis])) fail(said("{0} 要写成 1 到 {1} 的整数", `card.${axis}`, GRID[axis]));
287
+ const bounds = {};
288
+ for (const bound of ["min", "max"]) {
289
+ const value = card[bound];
290
+ if (value === undefined) continue;
291
+ if (!isTable(value)) fail(said("{0} 要写成 { w, h },单位是格", `card.${bound}`));
292
+ onlyFields(value, ["w", "h"], `card.${bound}.`);
293
+ for (const axis of ["w", "h"]) if (value[axis] !== undefined && !isCount(value[axis], GRID[axis])) fail(said("{0} 要写成 1 到 {1} 的整数", `card.${bound}.${axis}`, GRID[axis]));
294
+ bounds[bound] = value;
295
+ }
296
+ const min = { w: bounds.min?.w ?? 1, h: bounds.min?.h ?? 1 };
297
+ const max = { w: bounds.max?.w ?? GRID.w, h: bounds.max?.h ?? GRID.h };
298
+ const w = card.sizes ? card.sizes[0][0] : card.w ?? NO_CARD.w;
299
+ const h = card.sizes ? card.sizes[0][1] : card.h ?? null;
300
+ const any = Boolean(card.sizes) && (card.min !== undefined || card.max !== undefined);
301
+ if (any) {
302
+ const outside = card.sizes.find(([width, height]) => width < min.w || width > max.w || height < min.h || height > max.h);
303
+ if (outside) fail(said("card.sizes 里 {0} 不在 card.min 到 card.max 之间", outside.join("x")));
304
+ }
305
+ for (const axis of ["w", "h"]) {
306
+ if (min[axis] > max[axis]) fail(said("card.min.{0} 比 card.max.{0} 大", axis));
307
+ const value = { w, h }[axis];
308
+ if (value !== null && !card.sizes && (value < min[axis] || value > max[axis])) fail(said("默认的 card.{0} 是 {1},不在 card.min 到 card.max 之间({2} 到 {3})", axis, value, min[axis], max[axis]));
309
+ }
310
+ for (const flag of ["resize", "bare"]) if (card[flag] !== undefined && typeof card[flag] !== "boolean") fail(said("{0} 要写成 true 或 false", `card.${flag}`));
311
+ if (card.fit !== undefined && !FITS.includes(card.fit)) fail(said("card.fit 只能是 fixed 或 content"));
312
+ if (card.consent !== undefined) bothLanguages(card.consent, "card.consent");
313
+ return {
314
+ sizes: card.sizes ? card.sizes.map(([width, height]) => [width, height]) : null,
315
+ any, w, h, min, max,
316
+ resize: card.resize ?? false,
317
+ fit: card.fit ?? "fixed",
318
+ bare: card.bare ?? false,
319
+ ...(card.consent !== undefined ? { consent: { zh: card.consent.zh, en: card.consent.en } } : {}),
320
+ };
321
+ }
322
+
323
+ // Whether `value` can be the default of a setting of `type` (with its `options`).
324
+ const fitsSetting = (value, { type, options }) => ({
325
+ text: typeof value === "string",
326
+ number: typeof value === "number" && Number.isFinite(value),
327
+ select: options?.includes(value),
328
+ date: typeof value === "string" && DATE.test(value),
329
+ switch: typeof value === "boolean",
330
+ document: typeof value === "string",
331
+ })[type];
332
+
333
+ // `settings`: the fields of a card's form, each key once; a block with any keeps their values in a JSON
334
+ // data part of its own (SETTINGS_PART), which its parts are to name.
335
+ function settingsOf(settings, parts) {
336
+ if (settings === undefined) return [];
337
+ if (!Array.isArray(settings)) fail(said("{0} 要写成一串字段", "settings"));
338
+ const keys = [];
339
+ settings.forEach((setting, index) => {
340
+ const where = `settings[${index}]`;
341
+ if (!isTable(setting)) fail(said("{0} 要写成一张表", where));
342
+ onlyFields(setting, SETTING_FIELDS, `${where}.`);
343
+ if (typeof setting.key !== "string" || !SETTING_KEY.test(setting.key)) fail(said("{0} 的 key 以小写字母开头,只用字母和数字(如 city、startDate)", where));
344
+ if (keys.includes(setting.key)) fail(said("settings 里 key {0} 写了两次", setting.key));
345
+ keys.push(setting.key);
346
+ bothLanguages(setting.label, `${where}.label`);
347
+ if (!SETTING_TYPES.includes(setting.type)) fail(said("{0} 的 type 只能是 {1}", where, SETTING_TYPES.join(", ")));
348
+ if (setting.type === "select") {
349
+ if (!Array.isArray(setting.options) || setting.options.length === 0 || !setting.options.every(isWords)) fail(said("{0} 是 select,要有 options:一串文字", where));
350
+ if (twice(setting.options)) fail(said("{0} 的 options 里 {1} 写了两次", where, twice(setting.options)));
351
+ } else if (setting.options !== undefined) fail(said("{0} 不是 select,不写 options", where));
352
+ if (setting.default !== undefined && !fitsSetting(setting.default, setting)) fail(said("{0} 的 default 和它的 type {1} 不符", where, setting.type));
353
+ if (setting.required !== undefined && typeof setting.required !== "boolean") fail(said("{0} 的 required 要写 true 或 false", where));
354
+ });
355
+ const part = parts[SETTINGS_PART];
356
+ if (settings.length > 0 && !(part?.edit === "data" && tailTags(part.at).every((tag) => tag === "script") && tailTags(part.at).length > 0)) {
357
+ fail(said("写了 settings,parts 里就要有一个名为 settings、edit 为 data 的部分,它是一个 <script type=\"application/json\">,存卡片设置的值"));
358
+ }
359
+ return settings.map((setting) => ({ ...setting }));
360
+ }
361
+
362
+ // `needs`: what a block asks to use, each once.
363
+ function needsOf(needs) {
364
+ if (needs === undefined) return [];
365
+ if (!Array.isArray(needs)) fail(said("{0} 要写成一串文字", "needs"));
366
+ for (const need of needs) {
367
+ if (typeof need === "string" && (NEEDS.includes(need) || (need.startsWith(NET) && HOST.test(need.slice(NET.length))))) continue;
368
+ fail(said("needs 里的 {0} 不认识:只认 workspace、tables 和 net:<域名>(小写的主机名,不带端口和路径,可以以 *. 开头)", typeof need === "string" ? need : JSON.stringify(need)));
369
+ }
370
+ if (twice(needs)) fail(said("needs 里 {0} 写了两次", twice(needs)));
371
+ return [...needs];
372
+ }
373
+
374
+ // What a block that may stand on a custom page cannot hold: a slot, whose blocks are a document's,
375
+ // which no page has the editor and the rendering of.
376
+ function pageParts(places, parts) {
377
+ if (!places.includes("page")) return;
378
+ const slot = Object.entries(parts).find(([, part]) => part.edit === "flow");
379
+ if (slot) fail(said("places 里有 page,就不能有插槽:{0} 的 edit 是 flow,插槽放的是文档的块,自定义页上没有", `parts.${slot[0]}`));
380
+ }
381
+
226
382
  // `assets`: the kit's files a package asks for, by id, and files of its own, by their path in its folder.
227
383
  function assetsOf(assets, folder) {
228
384
  if (assets === undefined) return { kit: [], own: [] };
229
385
  if (!Array.isArray(assets) || !assets.every(isWords)) fail(said("{0} 要写成一串文字", "assets"));
230
386
  const own = assets.filter((asset) => !KIT_ASSETS.has(asset));
231
387
  for (const asset of own) {
232
- if (!OWN_FILE.test(asset)) fail(said("assets 里的 {0} 既不是套件的资源,也不是包里的文件", asset));
233
- if (!ownPath(folder, asset)) fail(said("assets 写了 {0},包里没有这个文件", asset));
388
+ if (!OWN_FILE.test(asset)) fail(said("assets 里的 {0} 既不是套件的资源,也不是块的文件夹里的文件", asset));
389
+ if (!ownPath(folder, asset)) fail(said("assets 写了 {0},块的文件夹里没有这个文件", asset));
234
390
  }
235
391
  return { kit: assets.filter((asset) => KIT_ASSETS.has(asset)), own };
236
392
  }
@@ -245,12 +401,12 @@ function packageOf(id, folder, text) {
245
401
  fail(said("component.json 不是 JSON:{0}", error.message));
246
402
  }
247
403
  if (!isTable(manifest)) fail(said("component.json 写的不是一个对象"));
248
- if (!PACKAGE_ID.test(id)) fail(said("{0} 不能做组件包的 id:范围和名字都只用小写字母、数字和连字符", id));
249
- for (const name of id.split("/")) if (DEVICE_NAMES.has(name)) fail(said("{0} 不能做组件包的 id:{1} 是 Windows 留给设备的名字", id, name));
404
+ if (!PACKAGE_ID.test(id)) fail(said("{0} 不能做自定义块的 id:范围和名字都只用小写字母、数字和连字符", id));
405
+ for (const name of id.split("/")) if (DEVICE_NAMES.has(name)) fail(said("{0} 不能做自定义块的 id:{1} 是 Windows 留给设备的名字", id, name));
250
406
  if (manifest.id !== id) fail(said("清单的 id 是 {0},和它的文件夹 {1} 不一样", String(manifest.id), id));
251
407
  required(manifest, ["apiVersion"]);
252
408
  if (!Number.isInteger(manifest.apiVersion) || manifest.apiVersion < 1) fail(said("apiVersion 要写成一个正整数"));
253
- if (manifest.apiVersion !== API_VERSION) throw refusal(said("这个组件包要 apiVersion {0},这一版 Gallery 只支持 {1}", manifest.apiVersion, API_VERSION), { disabled: true, version: isWords(manifest.version) ? manifest.version : null });
409
+ if (manifest.apiVersion !== API_VERSION) throw refusal(said("这个自定义块要 apiVersion {0},这一版 Gallery 只支持 {1}", manifest.apiVersion, API_VERSION), { disabled: true, version: isWords(manifest.version) ? manifest.version : null });
254
410
  onlyFields(manifest, FIELDS);
255
411
  required(manifest, ["version", "name", "description", "parts"]);
256
412
  if (!isWords(manifest.version)) fail(said("{0} 要写成文字", "version"));
@@ -263,6 +419,11 @@ function packageOf(id, folder, text) {
263
419
  const { kit, own } = assetsOf(manifest.assets, folder);
264
420
  if (manifest.markdown !== undefined && !MARKDOWN.includes(manifest.markdown)) fail(said("markdown 只能是 parts 或 text"));
265
421
  if (manifest.schema !== undefined && !(Number.isInteger(manifest.schema) && manifest.schema >= 1)) fail(said("schema 要写成一个正整数"));
422
+ const places = placesOf(manifest.places);
423
+ pageParts(places, manifest.parts);
424
+ const card = cardOf(manifest.card);
425
+ const settings = settingsOf(manifest.settings, manifest.parts);
426
+ const needs = needsOf(manifest.needs);
266
427
  const template = ownFile(folder, TEMPLATE);
267
428
  if (template) notTooLong(template, TEMPLATE);
268
429
  return {
@@ -278,6 +439,10 @@ function packageOf(id, folder, text) {
278
439
  words: manifest.words ?? "",
279
440
  assets: kit,
280
441
  markdown: manifest.markdown ?? "parts",
442
+ places,
443
+ card,
444
+ settings,
445
+ needs,
281
446
  files: [...new Set([...SERVED.filter((file) => ownPath(folder, file)), ...own])],
282
447
  template: template && wordsOf(template),
283
448
  folder,
@@ -305,10 +470,20 @@ const workspaceRoot = () => findWorkspace().root;
305
470
 
306
471
  // A file edited by hand holds what it holds: of its lists, what can be an id is read, once each, and
307
472
  // the rest is passed over, one that names nothing there doing nothing. An id may be of a package that
308
- // comes back, so it stays. Only a package can be disabled.
473
+ // comes back, so it stays. Only a package can be disabled or unlisted.
309
474
  const NAMED = /^[a-z0-9][a-z0-9-]*(?:\/[a-z0-9][a-z0-9-]*)?$/;
310
475
  const idsIn = (list, shape) => [...new Set(Array.isArray(list) ? list.filter((id) => typeof id === "string" && shape.test(id)) : [])];
311
- const settingsIn = (file) => ({ hidden: idsIn(file?.components?.hidden, NAMED), disabled: idsIn(file?.components?.disabled, PACKAGE_ID) });
476
+ // `net`, the reader's consents (a block's card, 设置 › 组件列表): of each package by its id, the hosts of its
477
+ // needs it was allowed to reach, those that can be a needs' host (./net-policy.mjs HOST), once each; a
478
+ // package with none named none.
479
+ const consentsIn = (net) => Object.fromEntries(Object.entries(isTable(net) ? net : {}).filter(([id]) => PACKAGE_ID.test(id)).map(([id, hosts]) => [id, idsIn(hosts, HOST)]).filter(([, hosts]) => hosts.length > 0));
480
+ // `packs`, the packs' switches (设置 › 组件列表's pack cards): { "<pack id>": { "enabled": false } }, by id, a
481
+ // pack it names none of on; what is no pack's id or says no boolean is passed over.
482
+ const switchesIn = (packs) => Object.fromEntries(Object.entries(isTable(packs) ? packs : {}).filter(([id, entry]) => PACK_ID.test(id) && typeof entry?.enabled === "boolean").map(([id, entry]) => [id, entry.enabled]));
483
+ const settingsIn = (file) => {
484
+ const packs = switchesIn(file?.components?.packs);
485
+ return { hidden: idsIn(file?.components?.hidden, NAMED), disabled: idsIn(file?.components?.disabled, PACKAGE_ID), shown: idsIn(file?.components?.shown, PACKAGE_ID), unlisted: idsIn(file?.components?.unlisted, PACKAGE_ID), net: consentsIn(file?.components?.net), packs, packsOff: Object.keys(packs).filter((id) => packs[id] === false).sort() };
486
+ };
312
487
 
313
488
  // gallery.json's text (null: no file) as what it holds, `value`, or `problem`, why it cannot be taken
314
489
  // for a workspace's: what the catalog goes on through (settingsNow) and no writer writes over.
@@ -329,8 +504,11 @@ function fileAt(root) {
329
504
  }
330
505
 
331
506
  /**
332
- * What gallery.json says of the components: { hidden, disabled }, ids of packages and, in `hidden`,
333
- * names of built-in components. One that is not there says nothing, and neither does one that does not
507
+ * What gallery.json says of the components: { hidden, disabled, shown, unlisted, net, packs, packsOff }, ids of packages and, in
508
+ * `hidden`, names of built-in components (inDocumentMenus reads `hidden`, `shown` and `unlisted`; a block
509
+ * unlisted, 设置 › 组件列表's master switch off, is offered by no menu and no library); `net` the hosts
510
+ * each package was allowed to reach, by its id (consentsIn); `packs` each pack's switch named there, by its id (true on,
511
+ * false off), `packsOff` the ids of those off. One that is not there says nothing, and neither does one that does not
334
512
  * read or is another program's: what goes on using a workspace goes by the catalog (readCatalog).
335
513
  */
336
514
  export const componentSettings = (root = workspaceRoot()) => settingsIn(fileAt(root).value);
@@ -339,12 +517,17 @@ export const componentSettings = (root = workspaceRoot()) => settingsIn(fileAt(r
339
517
  const NOT_WRITABLE = ["EPERM", "EACCES", "EBUSY", "EROFS"];
340
518
 
341
519
  /**
342
- * gallery.json with `id` hidden or not and disabled or not, as `hidden` and `disabled` say (true,
343
- * false, or left out for as it is), written at once and with all else it holds kept. A file that does
520
+ * gallery.json with the pack `pack` on or off, as `enabled` says (components.packs, its entry's other fields
521
+ * kept), or with `id` hidden or not, shown or not, disabled or not and unlisted or not, as `hidden`,
522
+ * `shown`, `disabled` and `unlisted` say (true, false, or left out for as it is), written at once and with
523
+ * all else it holds kept; `shown` and `unlisted` are written where they hold an id or were there already
524
+ * (a block no entry names is listed). `net`, the hosts `id` is allowed
525
+ * to reach (a list: its consent, all it names in place of what was there; [] takes it back), written in
526
+ * components.net under its id, which goes with its last host, and components.net with its last id. A file that does
344
527
  * not read, is another program's, changed under this write or cannot be written is refused, and stays
345
528
  * as it is: it is not this write's to mend.
346
529
  */
347
- export async function writeComponentSettings(root, { id, hidden, disabled }) {
530
+ export async function writeComponentSettings(root, { id, hidden, shown, disabled, unlisted, net, pack, enabled }) {
348
531
  const file = layoutOf(root).marker;
349
532
  const text = await fs.readFile(file, "utf8").catch((error) => {
350
533
  if (error.code === "ENOENT") return null;
@@ -353,8 +536,26 @@ export async function writeComponentSettings(root, { id, hidden, disabled }) {
353
536
  const { value, problem } = fileOf(text);
354
537
  if (problem) fail(problem);
355
538
  const named = (list, on) => (on === undefined ? list : on ? [...new Set([...list, id])] : list.filter((other) => other !== id));
356
- const { hidden: wasHidden, disabled: wasDisabled } = settingsIn(value);
357
- const components = { ...(isTable(value?.components) ? value.components : {}), hidden: named(wasHidden, hidden), disabled: named(wasDisabled, disabled) };
539
+ const { hidden: wasHidden, disabled: wasDisabled, shown: wasShown, unlisted: wasUnlisted } = settingsIn(value);
540
+ const before = isTable(value?.components) ? value.components : {};
541
+ const nowShown = named(wasShown, shown);
542
+ const nowUnlisted = named(wasUnlisted, unlisted);
543
+ const components = {
544
+ ...before, hidden: named(wasHidden, hidden), disabled: named(wasDisabled, disabled),
545
+ ...(nowShown.length > 0 || Object.hasOwn(before, "shown") ? { shown: nowShown } : {}),
546
+ ...(nowUnlisted.length > 0 || Object.hasOwn(before, "unlisted") ? { unlisted: nowUnlisted } : {}),
547
+ };
548
+ if (pack !== undefined) {
549
+ const switches = isTable(before.packs) ? before.packs : {};
550
+ components.packs = { ...switches, [pack]: { ...(isTable(switches[pack]) ? switches[pack] : {}), enabled: enabled === true } };
551
+ }
552
+ if (net !== undefined) {
553
+ const consents = { ...(isTable(before.net) ? before.net : {}) };
554
+ if (net.length > 0) consents[id] = [...new Set(net)];
555
+ else delete consents[id];
556
+ if (Object.keys(consents).length > 0) components.net = consents;
557
+ else delete components.net;
558
+ }
358
559
  const written = await writeAtomic(file, `${JSON.stringify({ ...(value ?? WORKSPACE_MARK), components }, null, 2)}\n`, { expect: text }).catch((error) => {
359
560
  if (NOT_WRITABLE.includes(error.code)) fail(said("gallery.json 写不进去:可能是只读的,或被别的程序占着"));
360
561
  throw error;
@@ -368,31 +569,60 @@ const turnedOff = (found) => ({ ...found, off: true, disabled: true, problem: sa
368
569
 
369
570
  const NO_SETTINGS = settingsIn(null);
370
571
 
371
- /** The stamp of a catalog: of what its packages are, those that do not load and why too, of what is hidden and of why gallery.json does not read, neither of which changes a package. */
372
- export const catalogStamp = ({ packages, problems, settings = NO_SETTINGS }) => hashOf((hash) => {
572
+ /** The stamp of a catalog: of what its packages are, those that do not load and why too, of what is hidden, shown and unlisted, the packs off and their names, and of why gallery.json does not read, none of which changes a package. */
573
+ export const catalogStamp = ({ packages, problems, settings = NO_SETTINGS, packs = new Map() }) => hashOf((hash) => {
373
574
  for (const { id, stamp } of [...packages.values(), ...problems.values()].sort(byId)) hash.update(`${id} ${stamp}\n`);
374
575
  hash.update(`hidden ${[...settings.hidden].sort().join(" ")}\n`);
576
+ hash.update(`shown ${[...settings.shown].sort().join(" ")}\n`);
577
+ hash.update(`unlisted ${[...(settings.unlisted ?? [])].sort().join(" ")}\n`);
578
+ hash.update(`net ${consentPairs(settings).join(" ")}\n`);
579
+ hash.update(`packs off ${(settings.packsOff ?? []).join(" ")}\n`);
580
+ for (const [scope, name] of [...packs].sort(([a], [b]) => (a < b ? -1 : 1))) hash.update(`pack ${scope} ${JSON.stringify(name)}\n`);
375
581
  hash.update(`settings ${settings.problem?.message ?? ""}\n`);
376
582
  });
377
583
 
584
+ // The consents of `settings` as "<id>@<host>", sorted: what the stamp and the settings line say of them.
585
+ const consentPairs = ({ net = {} }) => Object.entries(net).flatMap(([id, hosts]) => hosts.map((host) => `${id}@${host}`)).sort();
586
+
378
587
  // The settings a catalog goes by: what gallery.json says or, while it cannot be read as saying
379
588
  // anything, what was in use (`held`, a broken manifest's hold, for a slip by hand), with why (`problem`).
380
589
  function settingsNow(root, held) {
381
590
  const { value, problem } = fileAt(root);
382
- return problem ? { hidden: held.hidden, disabled: held.disabled, problem } : settingsIn(value);
591
+ return problem ? { hidden: held.hidden, disabled: held.disabled, shown: held.shown ?? [], unlisted: held.unlisted ?? [], net: held.net ?? {}, packs: held.packs ?? {}, packsOff: held.packsOff ?? [], problem } : settingsIn(value);
383
592
  }
384
593
 
594
+ // What runs before the catalog reads the blocks of a workspace that holds Gallery's own (the scopes of
595
+ // Gallery's packs, `ownScopes`): (root, ids) -> anything. A server sets it as it starts
596
+ // (shared/shipped-blocks.mjs followOnRead: a copy as it was added brought up to Gallery's first), so that
597
+ // this file imports nothing of the package's paths, reading whichever workspace it is given; a command sets none.
598
+ let beforeRead = null;
599
+ let ownScopes = [];
600
+
601
+ /** `run(root, ids)` runs before each read of a workspace's blocks that finds Gallery's own (`ids`, those of `scopes`, the scopes of Gallery's packs), from now on in this process. */
602
+ export const beforeCatalogRead = (run, scopes = ["gallery"]) => {
603
+ beforeRead = run;
604
+ ownScopes = [...scopes];
605
+ };
606
+
385
607
  /**
386
608
  * The workspace's packages as they are on disk now: the catalog, whatever a package or gallery.json
387
609
  * holds. `held`: the settings of the catalog in use, for a file that does not read; a process with
388
610
  * none has nothing to go by. `on`: a package read as its files say whatever gallery.json says of it,
389
- * for what holds it to them (gallery component check).
611
+ * for what holds it to them (gallery block check). In a server, Gallery's own blocks as they were
612
+ * added are brought up to Gallery's first (beforeCatalogRead).
390
613
  */
391
614
  export function readCatalog(root = workspaceRoot(), held = NO_SETTINGS, { on = null } = {}) {
392
615
  const settings = settingsNow(root, held);
393
616
  const packages = new Map();
394
617
  const problems = new Map();
395
- for (const { id, folder } of packageFolders(root)) {
618
+ const folders = packageFolders(root);
619
+ const own = folders.map(({ id }) => id).filter((id) => ownScopes.includes(id.split("/")[0]));
620
+ if (beforeRead && own.length > 0) {
621
+ try {
622
+ beforeRead(root, own);
623
+ } catch {} // what it could not do leaves the blocks as they are
624
+ }
625
+ for (const { id, folder } of folders) {
396
626
  const found = readPackage(id, folder);
397
627
  (found.problem ? problems : packages).set(found.id, found);
398
628
  }
@@ -402,7 +632,31 @@ export function readCatalog(root = workspaceRoot(), held = NO_SETTINGS, { on = n
402
632
  problems.set(id, turnedOff(packages.get(id)));
403
633
  packages.delete(id);
404
634
  }
405
- return { packages, problems, settings, stamp: catalogStamp({ packages, problems, settings }) };
635
+ const packs = packNames(root, folders.map(({ id }) => id.split("/")[0]));
636
+ return { packages, problems, settings, packs, stamp: catalogStamp({ packages, problems, settings, packs }) };
637
+ }
638
+
639
+ /**
640
+ * What the pack.json of each scope of `scopes` (and of each folder of components/ that holds one) names
641
+ * it: a Map, by scope, of { zh, en }, or null where it has none or one that does not read (a scope of
642
+ * blocks with no pack.json is a pack of its own by its scope's name, the default pack, local/, by its own:
643
+ * ./pack-manifest.mjs DEFAULT_PACK, ./block-packs.mjs).
644
+ */
645
+ export function packNames(root, scopes = []) {
646
+ const { components } = layoutOf(root);
647
+ let withFile = [];
648
+ try {
649
+ withFile = readdirSync(components).filter((name) => PACK_ID.test(name) && existsSync(path.join(components, name, PACK_FILE)));
650
+ } catch {}
651
+ const names = new Map();
652
+ for (const scope of [...new Set([...scopes, ...withFile])].sort()) {
653
+ let name = null;
654
+ try {
655
+ name = scope === OWN_SCOPE ? DEFAULT_PACK.name : readPackManifest(readFileSync(path.join(components, scope, PACK_FILE), "utf8")).name;
656
+ } catch {}
657
+ names.set(scope, name);
658
+ }
659
+ return names;
406
660
  }
407
661
 
408
662
  const kept = new Map(); // a workspace's root -> the catalog in use
@@ -429,12 +683,18 @@ const bothProblems = (problem) => ({ zh: problemIn("zh", problem), en: problemIn
429
683
  /** Why gallery.json cannot be read, in both languages, as 设置 › 组件列表 says it, or null. */
430
684
  export const settingsProblem = ({ settings }) => (settings.problem ? bothProblems(settings.problem) : null);
431
685
 
432
- // What a package is now: "normal", "hidden", "disabled" (turned off, or for an apiVersion this Gallery
433
- // does not run), or "broken", one that does not load of itself.
434
- const stateOf = (found, settings) => (found.problem ? (found.disabled ? "disabled" : "broken") : settingState(found.id, settings));
686
+ // What a package is now: "normal" (the document's menus offer it: inDocumentMenus), "hidden" (they do
687
+ // not), "disabled" (turned off, or for an apiVersion this Gallery does not run), or "broken", one that
688
+ // does not load of itself.
689
+ const stateOf = (found, settings) => (found.problem ? (found.disabled ? "disabled" : "broken") : settingState(found.id, settings, found.places));
435
690
 
436
- /** What the kit is told of a package: where its instances are, its parts, what it leaves on a page and how far its content's shape goes. */
437
- export const descriptionOf = ({ id, match, parts, runtime, schema }) => ({ id, match, parts, ...(runtime ? { runtime } : {}), ...(schema !== undefined ? { schema } : {}) });
691
+ /**
692
+ * What the kit is told of a package: where its instances are, its parts, what it leaves on a page, how far
693
+ * its content's shape goes, and what it uses (`needs`, where it names any: the kit gives an instance
694
+ * context.workspace for "workspace", context.fetch for a host of the net and context.table() for
695
+ * "tables"), and the line its card's consent banner says (`consent`, its card's, where it says one).
696
+ */
697
+ export const descriptionOf = ({ id, match, parts, runtime, schema, needs, card }) => ({ id, match, parts, ...(runtime ? { runtime } : {}), ...(schema !== undefined ? { schema } : {}), ...(needs?.length ? { needs } : {}), ...(card?.consent ? { consent: card.consent } : {}) });
438
698
 
439
699
  /**
440
700
  * What the kit is told of a catalog, each by DocKit.describe, the one way a page learns a package's
@@ -509,7 +769,7 @@ export function instanceMarkup(text, id) {
509
769
  function readTemplate({ id, template, parts }) {
510
770
  if (!template) return {};
511
771
  const read = instanceMarkup(template, id);
512
- if (!read) return { problem: said("template.html 要是这个组件包的一个实例,有自己的结束标签,此外什么都没有") };
772
+ if (!read) return { problem: said("template.html 要是这个自定义块的一个实例,有自己的结束标签,此外什么都没有") };
513
773
  const held = [];
514
774
  walk({ childNodes: [read.root] }, (node) => { if (refusedInCopy(node.tagName, node.attrs)) held.push(node.tagName); });
515
775
  if (held.length > 0) return { problem: said("template.html 里的 <{0}> 进不了新建的块:脚本、事件、样式和 Gallery 自己的标记都不写在模板里", held[0]) };
@@ -520,7 +780,7 @@ function readTemplate({ id, template, parts }) {
520
780
  return short ? { problem: said("template.html 的 {0} 和清单写的数目不符", short[0]) } : { markup: read.markup };
521
781
  }
522
782
 
523
- /** Why no menu offers the template of `found`, said()'s, for `gallery component check` to say, or null: it has none, or one no reason keeps out. */
783
+ /** Why no menu offers the template of `found`, said()'s, for `gallery block check` to say, or null: it has none, or one no reason keeps out. */
524
784
  export const templateProblem = (found) => readTemplate(found).problem ?? null;
525
785
 
526
786
  /** The markup of an instance of `found` as a new one is written, or null: it has no template a menu offers. */
@@ -530,12 +790,16 @@ export const templateOf = (found) => readTemplate(found).markup ?? null;
530
790
  * What the page the editor runs on holds of a catalog: its MAP's `components` (src/editor/service.mjs),
531
791
  * no route and no dynamic import. One entry for each package that loads, by id: { id, version, name:
532
792
  * { zh, en }, description: { zh, en }, words, definition, stamp, template (the markup "/" puts in: one
533
- * instance of it, or null), preview (the address of its picture, or null), state ("normal", or "hidden": a menu offers what is "normal" and reads no setting), markdown, assets (the kit's files it asks for,
793
+ * instance of it, or null), preview (the address of its picture, or null), state ("normal", or "hidden": a menu offers what is "normal" and reads no setting), places (which the page's
794
+ * settingState reads with gallery.json's lists as its event stream says them), needs, settings (the fields of its 设置 form, a
795
+ * manifest's `settings`, [] where it has none), markdown, assets (the kit's files it asks for,
534
796
  * by id), tags (packageTags: what loads it in a page that was served without it, the line that tells the
535
- * kit of its parts among them) }. A page knows what it holds of a package's parts from the kit
797
+ * kit of its parts among them), pack ({ id, name }: the pack it is of, its scope, and what its pack.json names
798
+ * it, null where none does: a menu writes the pack's name after a block's in grey where two packs offer
799
+ * blocks of one name) }. A page knows what it holds of a package's parts from the kit
536
800
  * (descriptionsOf), and of one that came after it was served from these tags.
537
801
  */
538
- export const menuOf = ({ packages, settings = NO_SETTINGS }) => [...packages.values()].sort(byId).map((found) => ({
802
+ export const menuOf = ({ packages, settings = NO_SETTINGS, packs = new Map() }) => [...packages.values()].sort(byId).map((found) => ({
539
803
  id: found.id,
540
804
  version: found.version,
541
805
  name: found.name,
@@ -546,28 +810,48 @@ export const menuOf = ({ packages, settings = NO_SETTINGS }) => [...packages.val
546
810
  template: templateOf(found),
547
811
  preview: found.files.includes("preview.svg") ? packageAddress(found, "preview.svg") : null,
548
812
  state: stateOf(found, settings),
813
+ places: found.places,
814
+ needs: found.needs,
815
+ settings: found.settings,
549
816
  markdown: found.markdown,
550
817
  assets: found.assets,
551
818
  tags: packageTags(found),
819
+ pack: { id: found.id.split("/")[0], name: packs.get(found.id.split("/")[0]) ?? null },
552
820
  }));
553
821
 
554
822
  /**
555
823
  * The workspace's packages as who lists them says them, by id: { id, version, name, description (what
556
824
  * a manifest says, null where it does not read), state ("normal", "hidden", "disabled" or "broken":
557
825
  * stateOf), reason ({ zh, en }, why it does not load of itself, or null), template (whether it has one
558
- * a menu can put in: with none, none can), hidden and disabled (what gallery.json says of it) }.
826
+ * a menu can put in: with none, none can), places and needs (what its manifest says, null where it does
827
+ * not read), hidden, shown, disabled and unlisted (what gallery.json says of it), allowed (the hosts of its needs
828
+ * the reader allowed it to reach, gallery.json's components.net: its switch 允许联网 is on while it holds
829
+ * every host its needs name) and menu (whether its switch
830
+ * 在文档菜单里显示 is on: inDocumentMenus, whatever `disabled` and `unlisted` say, which are switches of their
831
+ * own: the row's master switch is on while it is not unlisted, nor its pack's) and pack (the pack it is of: its scope) }.
559
832
  */
560
833
  export const packageStates = ({ packages, problems, settings = NO_SETTINGS }) => [...packages.values(), ...problems.values()].sort(byId).map((found) => ({
561
834
  id: found.id,
835
+ pack: found.id.split("/")[0],
562
836
  version: found.version ?? null,
563
837
  name: found.name ?? null,
564
838
  description: found.description ?? null,
565
839
  state: stateOf(found, settings),
566
840
  reason: found.problem && !found.off ? bothProblems(found.problem) : null,
567
841
  template: Boolean(templateOf(found)),
842
+ places: found.places ?? null,
843
+ needs: found.needs ?? null,
568
844
  hidden: settings.hidden.includes(found.id),
845
+ shown: settings.shown.includes(found.id),
569
846
  disabled: settings.disabled.includes(found.id),
847
+ unlisted: (settings.unlisted ?? []).includes(found.id),
848
+ allowed: (settings.net?.[found.id] ?? []).filter((host) => netHostsOf(found.needs).includes(host)),
849
+ menu: inDocumentMenus(found.places, { ...settings, disabled: [], unlisted: [], packsOff: [] }, found.id),
570
850
  }));
571
851
 
572
- /** The message that tells a page of `settings` on its event stream, its two lists by commas: what it offers follows them, whatever it holds. */
573
- export const settingsLine = ({ hidden, disabled }) => `settings ${hidden.join(",")} ${disabled.join(",")}`;
852
+ /**
853
+ * The message that tells a page of `settings` on its event stream, its six lists by commas (hidden,
854
+ * disabled, shown, the consents, "<id>@<host>" each, unlisted, and the packs off): what it offers follows
855
+ * them, whatever it holds, and an instance whose consent changed starts again (the kit's net.js).
856
+ */
857
+ export const settingsLine = (settings) => `settings ${settings.hidden.join(",")} ${settings.disabled.join(",")} ${settings.shown.join(",")} ${consentPairs(settings).join(",")} ${(settings.unlisted ?? []).join(",")} ${(settings.packsOff ?? []).join(",")}`;