@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
@@ -14,6 +14,8 @@ import { BLOCK_TYPES, LEAVES_BY_ENTER, accepts } from "../../components/registry
14
14
  // too) moves out after the box, which goes if nothing is left in it (`leaveBox`).
15
15
  // - A block of a type that says `resettable` (a quote's paragraph, a list item) turns into a
16
16
  // paragraph where it stands, its container splitting around it (convert.mjs).
17
+ // - Backspace in an empty block of a type that says `emptyToText` (a heading, small text) turns it
18
+ // into an empty paragraph where it stands (`emptied`; the user's, 2026-11-09).
17
19
  // Enter in a title that goes into its content (a disclosure, a card, a code block) is another rule
18
20
  // (their components').
19
21
 
@@ -36,8 +38,10 @@ export function leaveBox(host) {
36
38
  * and touchedBy (a structural undo step), convertHost, typeOf and targetsOf (convert.mjs).
37
39
  */
38
40
  export function createLeaving({ struct, touchedBy, convertHost, typeOf, targetsOf }) {
39
- // A block of a type that resets, which can be body text where it stands.
40
- const resets = (host) => BLOCK_TYPES[typeOf(host)]?.resettable === true && targetsOf(host).includes("paragraph");
41
+ // A block of a type that says `field` (resettable, emptyToText), which can be body text where it stands.
42
+ const says = (host, field) => BLOCK_TYPES[typeOf(host)]?.[field] === true && targetsOf(host).includes("paragraph");
43
+ const resets = (host) => says(host, "resettable");
44
+ const toText = (host) => convertHost(host, "paragraph");
41
45
 
42
46
  // Enter on an empty text block. True when it left its container or became text.
43
47
  function enter(host) {
@@ -52,7 +56,7 @@ export function createLeaving({ struct, touchedBy, convertHost, typeOf, targetsO
52
56
  return true;
53
57
  }
54
58
  if (!resets(host)) return false;
55
- convertHost(host, "paragraph");
59
+ toText(host);
56
60
  return true;
57
61
  }
58
62
 
@@ -60,9 +64,19 @@ export function createLeaving({ struct, touchedBy, convertHost, typeOf, targetsO
60
64
  // quote's first paragraph), turns into body text before the container. True when it did.
61
65
  function backspace(host) {
62
66
  if (!resets(host) || host.parentElement?.firstElementChild !== host) return false;
63
- convertHost(host, "paragraph");
67
+ toText(host);
64
68
  return true;
65
69
  }
66
70
 
67
- return { enter, backspace };
71
+ // Backspace in an empty text block of a type that says `emptyToText` (a heading, small text): it turns
72
+ // into an empty paragraph where it stands, the caret in it, one undo step (the user's, 2026-11-09: as an
73
+ // emptied item or quote paragraph, and as every container left empty, goes back to body text). True
74
+ // when it did.
75
+ function emptied(host) {
76
+ if (!isEmpty(host) || !says(host, "emptyToText")) return false;
77
+ toText(host);
78
+ return true;
79
+ }
80
+
81
+ return { enter, backspace, emptied };
68
82
  }
@@ -55,6 +55,19 @@ export function button(label, action, { primary = false, ...props } = {}) {
55
55
  return node;
56
56
  }
57
57
 
58
+ /**
59
+ * A text button in the editor's one button look (look.mjs BUTTONS, `.ge-btn`): no line, no fill, a gray
60
+ * under the pointer. `primary` the pale blue one (add, confirm, save; `data-primary`), `danger` with it the
61
+ * pale red (a delete), `quiet` a small one for looking, not deciding (`data-quiet`). A press on it leaves
62
+ * the selection where it is (button()).
63
+ */
64
+ export function textButton(label, action, { primary = false, danger = false, quiet = false, class: own = "", ...props } = {}) {
65
+ const node = button(label, action, { primary, class: `ge-btn${own ? ` ${own}` : ""}`, ...props });
66
+ if (danger) node.dataset.danger = "";
67
+ if (quiet) node.dataset.quiet = "";
68
+ return node;
69
+ }
70
+
58
71
  // Editor UI lives in the top layer with an open modal dialog, otherwise it would be inert.
59
72
  export function layer() {
60
73
  return document.querySelector(DIALOG.open) ?? document.body;
@@ -0,0 +1,419 @@
1
+ import fs from "node:fs";
2
+ import path from "node:path";
3
+ import { componentSettings, problemIn, writeComponentSettings } from "./component-catalog.mjs";
4
+ import { refusal, said } from "./i18n/index.mjs";
5
+ import { DEFAULT_PACK, OWN_SCOPE, PACK_FILE, PACK_ID, readPackManifest } from "./pack-manifest.mjs";
6
+ import { packsDirectory } from "./paths.mjs";
7
+ import { filesIn, fingerprintOf, fingerprintOfFiles, isSystemFile, recordOf, shippedBlocks, shippedPackIds, versionAfter, writeRecord, writingOrder } from "./shipped-blocks.mjs";
8
+ import { DEVICE_NAMES, PACKAGE_MANIFEST, layoutOf, markerOf, packageFolders } from "./workspace.mjs";
9
+
10
+ // Block packs (自定义块包: notes/plans/block-packs-plan-2026-11-09.md; docs/render.md "Block packs"). A pack
11
+ // is a scope of the workspace's custom blocks, components/<id>/, with its pack.json (./pack-manifest.mjs)
12
+ // and a folder of each of its blocks, <id>/<name>/, the blocks' ids <id>/<name> as ever, so that nothing
13
+ // written of a block changes; a scope with no pack.json is a pack of its own, named by its scope, and
14
+ // local/ (OWN_SCOPE: gallery block new <name>'s, where an Agent's block goes when it names no pack) is the
15
+ // default pack (默认块包, pack-manifest.mjs DEFAULT_PACK), always listed, first. A pack is shared as its folder, or a zip of it (the folder itself, or what it
16
+ // holds, at the zip's top), and installed into a workspace by gallery block pack install (src/cli/component.mjs)
17
+ // or 设置 › 组件列表's 导入 (src/server/component-settings.mjs), which both read it (src/transfer/pack-source.mjs)
18
+ // and hand its files here, checked alike:
19
+ //
20
+ // installPack its files copied in, as gallery block add copies one of Gallery's own: each block's
21
+ // manifest last; .gallery/blocks.json records each block's version and fingerprint, and
22
+ // under `packs` the pack's version, the fingerprint of its own files (pack.json, and what
23
+ // else stands at its top) and its blocks. Installed again (a newer version), a block as it
24
+ // was installed is replaced, one changed since kept as it is (someone's work), a block
25
+ // the new version has not taken out where it is as installed; pack.json the same way.
26
+ // Refused, with why (said()'s, a \`code\`): a file that points out of the pack ("path"),
27
+ // one too large ("size"), a pack.json missing or that does not read ("manifest"), a block
28
+ // folder of no component.json naming it <id>/<name> ("block"), the id of one of Gallery's
29
+ // own packs ("official"), an id a scope of the workspace has that no install put there
30
+ // ("taken": another pack, or blocks someone wrote).
31
+ // removePack a pack installed taken out, its folder and records; never one of Gallery's own (its
32
+ // switch turns it off), nor a scope no install put there ("own": someone's work).
33
+ // workspacePacks the workspace's packs as 设置 › 组件列表 and gallery block pack list say them.
34
+ //
35
+ // Gallery's own packs (src/packs/<id>/: gallery, Gallery 风格; gallery-soft, 柔光风格) are installed the
36
+ // same way as a workspace's server starts and by gallery init (installOfficialPacks): once each, a pack
37
+ // switched off at first where OFF_AT_FIRST says so (gallery.json's components.packs), and again at each
38
+ // start with the same rule, so that a block as it was installed follows Gallery, a block Gallery's pack
39
+ // has come to hold is added, and one taken away by hand stays away (its record says it was there).
40
+ // A pack's switch (components.packs, { "<id>": { "enabled": false } }, none written on) keeps all its
41
+ // blocks out of every menu and library, as each one's master switch does (shared/components/installed.mjs
42
+ // inDocumentMenus); what is written of them shows as ever.
43
+
44
+ /** Gallery's own packs that a workspace has switched off when they are first installed. */
45
+ export const OFF_AT_FIRST = Object.freeze(["gallery-soft"]);
46
+
47
+ /**
48
+ * The ids of Gallery's own packs that are off though gallery.json names no switch for them: one off at first
49
+ * (OFF_AT_FIRST) that this workspace has not installed yet, which its first install will switch off. A
50
+ * start that installs none (NO_PACKS, a workspace made by hand) has the library offer Gallery's own blocks
51
+ * from the package, and a pack that is off when it comes in is not one of them. `switches` is the catalog
52
+ * settings' `packs` (true on, false off, by id).
53
+ */
54
+ export function offUntilInstalled(root, switches = {}) {
55
+ const installed = recordOf(root).packs;
56
+ return OFF_AT_FIRST.filter((id) => switches?.[id] === undefined && !isTable(installed?.[id]));
57
+ }
58
+
59
+ /** The environment variable that keeps a start (and gallery init) from installing Gallery's own packs: the tests' workspaces. */
60
+ export const NO_PACKS = "GALLERY_NO_PACKS";
61
+
62
+ /** Whether `env` says to install none of Gallery's own packs (NO_PACKS set, not to "", "0" or "false"). */
63
+ export const packsSkipped = (env = process.env) => !["", "0", "false", undefined].includes(env[NO_PACKS]);
64
+
65
+ const MOST_FILES = 2000;
66
+ const MOST_BYTES = 64 * 1024 * 1024;
67
+ const NAME = /^[a-z0-9][a-z0-9-]*$/;
68
+ const isTable = (value) => typeof value === "object" && value !== null && !Array.isArray(value);
69
+ const fail = (code, message) => {
70
+ throw refusal(message, { code });
71
+ };
72
+
73
+ /** The files of `folder`, [{ name (its path in it, with "/"), data }]: a link is none of them. */
74
+ export function folderFiles(folder) {
75
+ const files = [];
76
+ for (const entry of fs.readdirSync(folder, { recursive: true, withFileTypes: true })) {
77
+ if (!entry.isFile()) continue;
78
+ if (files.length >= MOST_FILES) fail("size", said("块包太大:最多 {0} 个文件、{1} MB", MOST_FILES, MOST_BYTES / 1024 / 1024));
79
+ const name = path.relative(folder, path.join(entry.parentPath, entry.name)).split(path.sep).join("/");
80
+ files.push({ name, data: fs.readFileSync(path.join(folder, ...name.split("/"))) });
81
+ }
82
+ return files;
83
+ }
84
+
85
+ /**
86
+ * A pack's files ([{ name, data }], as a folder or a zip gives them) read as one: { manifest, blocks: Map
87
+ * of each block's folder name to its files, own: the files at its top, pack.json among them }. A pack
88
+ * zipped with its folder (one folder at the top, pack.json in it) is read from that folder; what a
89
+ * system wrote (.DS_Store, __MACOSX/…) is passed over. Refused as installPack says; `refuse(manifest)`, run
90
+ * once its pack.json reads, before its blocks are looked at, refuses what it will.
91
+ */
92
+ export function readPack(given, { refuse = () => {} } = {}) {
93
+ const files = [];
94
+ let bytes = 0;
95
+ for (const { name: written, data } of given) {
96
+ const name = String(written).replace(/\\/g, "/");
97
+ if (name.endsWith("/")) continue; // a folder of a zip
98
+ const parts = name.split("/");
99
+ if (name.startsWith("/") || /^[A-Za-z]:/.test(name) || name.includes("\u0000") || parts.some((part) => part === "" || part === "." || part === "..")) fail("path", said("{0} 指向块包外面,不能装", String(written)));
100
+ if (parts[0] === "__MACOSX" || isSystemFile(parts.at(-1))) continue;
101
+ bytes += data.length;
102
+ files.push({ name, data });
103
+ }
104
+ if (files.length > MOST_FILES || bytes > MOST_BYTES) fail("size", said("块包太大:最多 {0} 个文件、{1} MB", MOST_FILES, MOST_BYTES / 1024 / 1024));
105
+ let inner = files;
106
+ if (!files.some(({ name }) => name === PACK_FILE)) {
107
+ const tops = new Set(files.map(({ name }) => name.split("/")[0]));
108
+ const [top] = tops;
109
+ if (tops.size !== 1 || !files.some(({ name }) => name === `${top}/${PACK_FILE}`)) fail("manifest", said("最上一层没有 pack.json:块包是一个文件夹,最上一层放 pack.json,每个块一个文件夹"));
110
+ inner = files.map(({ name, data }) => ({ name: name.slice(top.length + 1), data }));
111
+ }
112
+ const manifest = readPackManifest(inner.find(({ name }) => name === PACK_FILE).data.toString("utf8"));
113
+ refuse(manifest);
114
+ const blocks = new Map();
115
+ const own = [];
116
+ for (const file of inner) {
117
+ const [first, ...rest] = file.name.split("/");
118
+ if (rest.length === 0) {
119
+ own.push(file);
120
+ continue;
121
+ }
122
+ if (!blocks.has(first)) blocks.set(first, []);
123
+ blocks.get(first).push({ name: rest.join("/"), data: file.data });
124
+ }
125
+ for (const [name, list] of blocks) {
126
+ if (!NAME.test(name) || DEVICE_NAMES.has(name)) fail("block", said("{0} 不是块的文件夹名:只用小写字母、数字和连字符", name));
127
+ const file = list.find((each) => each.name === PACKAGE_MANIFEST);
128
+ if (!file) fail("block", said("{0}/ 里没有 component.json", name));
129
+ let id;
130
+ try {
131
+ id = JSON.parse(file.data.toString("utf8").replace(/^/, "")).id;
132
+ } catch {
133
+ fail("block", said("{0}/component.json 不是 JSON", name));
134
+ }
135
+ if (id !== `${manifest.id}/${name}`) fail("block", said("{0}/component.json 的 id 要写成 {1}", name, `${manifest.id}/${name}`));
136
+ }
137
+ return { manifest, blocks, own };
138
+ }
139
+
140
+ // A block's version, as its manifest says it, or null.
141
+ function versionIn(list) {
142
+ try {
143
+ const version = JSON.parse(list.find(({ name }) => name === PACKAGE_MANIFEST).data.toString("utf8").replace(/^/, "")).version;
144
+ return typeof version === "string" ? version : null;
145
+ } catch {
146
+ return null;
147
+ }
148
+ }
149
+
150
+ // The files right at the top of a pack's folder (pack.json and what else stands beside the blocks).
151
+ function topFiles(folder) {
152
+ try {
153
+ return fs.readdirSync(folder, { withFileTypes: true }).filter((entry) => entry.isFile() && !isSystemFile(entry.name)).map((entry) => entry.name).sort();
154
+ } catch {
155
+ return [];
156
+ }
157
+ }
158
+
159
+ // What the top of a pack's folder holds, as a fingerprint, or null for nothing there.
160
+ function ownFingerprint(folder) {
161
+ const names = topFiles(folder);
162
+ return names.length ? fingerprintOfFiles(names.map((name) => ({ name, data: fs.readFileSync(path.join(folder, name)) }))) : null;
163
+ }
164
+
165
+ // Whether a folder holds anything a system did not write there.
166
+ function holds(folder) {
167
+ try {
168
+ return fs.readdirSync(folder).some((name) => !isSystemFile(name));
169
+ } catch {
170
+ return false;
171
+ }
172
+ }
173
+
174
+ // `files` written into `folder`, the files of what was there that they have not taken out first
175
+ // (`replacing`), the manifest last: what makes a folder a block to a running server's watcher.
176
+ function writeFiles(folder, files, { replacing = false, last = PACKAGE_MANIFEST } = {}) {
177
+ const names = files.map(({ name }) => name);
178
+ if (replacing) for (const old of filesIn(folder)) if (!names.includes(old)) fs.rmSync(path.join(folder, ...old.split("/")), { force: true });
179
+ const byName = new Map(files.map((file) => [file.name, file.data]));
180
+ const order = last === PACKAGE_MANIFEST ? writingOrder(names) : [...names.filter((name) => name !== last), ...(names.includes(last) ? [last] : [])];
181
+ for (const name of order) {
182
+ const target = path.join(folder, ...name.split("/"));
183
+ fs.mkdirSync(path.dirname(target), { recursive: true });
184
+ fs.writeFileSync(target, byName.get(name));
185
+ }
186
+ }
187
+
188
+ /**
189
+ * The pack `given` holds ([{ name, data }]: src/transfer/pack-source.mjs reads a folder or a zip into
190
+ * them) installed into the workspace at `root` (above): { id, name, version, from (the version installed
191
+ * before, or null), did ("installed", "updated" or "same"), folder, added, updated, same, kept (blocks
192
+ * changed since they were installed, left as they are), removed (blocks the new version has not), skipped
193
+ * (blocks of Gallery's own taken away by hand, which stay away), ownKept (its pack.json changed since,
194
+ * left) }, each list of block ids. `official`: one of Gallery's own packs (installOfficialPacks), whose
195
+ * id is its own and whose scope may hold its blocks already, as gallery block add put them there.
196
+ */
197
+ export function installPack(root, given, { official = false, shippedIds = shippedPackIds() } = {}) {
198
+ const { manifest, blocks, own } = readPack(given, {
199
+ refuse: ({ id }) => {
200
+ if (!official && shippedIds.includes(id)) fail("official", said("{0} 是 Gallery 自带的块包用的 id:换一个 id 再装", id));
201
+ },
202
+ });
203
+ const { id } = manifest;
204
+ const folder = path.join(layoutOf(root).components, id);
205
+ const record = recordOf(root);
206
+ const packs = isTable(record.packs) ? record.packs : {};
207
+ const was = isTable(packs[id]) ? packs[id] : null;
208
+ if (!official && !was && holds(folder)) fail("taken", said("工作区里已经有 components/{0}:这个名字被别的块包或别人写的块用着,换一个 id,或先把那个文件夹挪走", id));
209
+ const done = { id, name: manifest.name, version: manifest.version, from: was?.version ?? null, folder, added: [], updated: [], same: [], kept: [], removed: [], skipped: [], ownKept: false };
210
+ const names = [...blocks.keys()].sort();
211
+ for (const name of names) {
212
+ const block = `${id}/${name}`;
213
+ const list = blocks.get(name);
214
+ const target = path.join(folder, name);
215
+ const next = fingerprintOfFiles(list);
216
+ const now = fingerprintOf(target);
217
+ const kept = isTable(record[block]) ? record[block] : null;
218
+ if (now === null) {
219
+ if (official && kept) {
220
+ done.skipped.push(block);
221
+ continue;
222
+ }
223
+ writeFiles(target, list);
224
+ done.added.push(block);
225
+ } else if (now === next) done.same.push(block);
226
+ else if (kept && now === kept.fingerprint) {
227
+ writeFiles(target, list, { replacing: true });
228
+ done.updated.push(block);
229
+ } else {
230
+ done.kept.push(block);
231
+ continue;
232
+ }
233
+ record[block] = { version: versionIn(list), fingerprint: next };
234
+ }
235
+ // The blocks of the pack as it was installed that this version has not: out, where they are as installed.
236
+ for (const block of Array.isArray(was?.blocks) ? was.blocks : []) {
237
+ const name = String(block).split("/")[1];
238
+ if (!name || blocks.has(name) || !NAME.test(name)) continue;
239
+ const target = path.join(folder, name);
240
+ const now = fingerprintOf(target);
241
+ if (now !== null && now !== record[block]?.fingerprint) {
242
+ done.kept.push(block);
243
+ continue;
244
+ }
245
+ if (now !== null) {
246
+ fs.rmSync(target, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 });
247
+ done.removed.push(block);
248
+ }
249
+ delete record[block];
250
+ }
251
+ // Its own files, pack.json last, the same way.
252
+ const ownNow = ownFingerprint(folder);
253
+ const ownNext = fingerprintOfFiles(own);
254
+ if (ownNow !== ownNext) {
255
+ if (ownNow === null || ownNow === was?.fingerprint) {
256
+ const names = own.map(({ name }) => name);
257
+ for (const old of topFiles(folder)) if (!names.includes(old)) fs.rmSync(path.join(folder, old), { force: true });
258
+ fs.mkdirSync(folder, { recursive: true });
259
+ writeFiles(folder, own, { last: PACK_FILE });
260
+ } else done.ownKept = true;
261
+ }
262
+ const changed = done.added.length + done.updated.length + done.removed.length > 0 || (ownNow !== ownNext && !done.ownKept);
263
+ done.did = !was ? "installed" : changed ? "updated" : "same";
264
+ record.packs = { ...packs, [id]: { version: manifest.version, fingerprint: done.ownKept ? was.fingerprint : ownNext, blocks: names.map((name) => `${id}/${name}`), ...(official ? { official: true } : {}) } };
265
+ writeRecord(root, record);
266
+ return done;
267
+ }
268
+
269
+ /**
270
+ * The pack `id` taken out of the workspace at `root`: its folder and what .gallery/blocks.json records of
271
+ * it ({ id, version, blocks }). What documents and pages hold of its blocks stays, shown as blocks that
272
+ * are not there. Refused: one of Gallery's own ("official": its switch in 设置 › 组件列表 turns it off), none
273
+ * there ("missing"), a scope no install put there ("own": blocks someone wrote, theirs to delete).
274
+ */
275
+ export function removePack(root, id, { shippedIds = shippedPackIds() } = {}) {
276
+ if (shippedIds.includes(id)) fail("official", said("{0} 是 Gallery 自带的块包,不能删除:在 设置 › 组件列表 里把它关掉", id));
277
+ const folder = path.join(layoutOf(root).components, id);
278
+ if (!PACK_ID.test(id) || !fs.existsSync(folder)) fail("missing", said("工作区里没有块包 {0}", id));
279
+ const record = recordOf(root);
280
+ const was = isTable(record.packs) && isTable(record.packs[id]) ? record.packs[id] : null;
281
+ if (!was) fail("own", said("components/{0} 不是装进来的块包,里面的块是有人在这个工作区写的:要删就自己删掉这个文件夹", id));
282
+ fs.rmSync(folder, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 });
283
+ for (const key of Object.keys(record)) if (key.startsWith(`${id}/`)) delete record[key];
284
+ const { [id]: _gone, ...rest } = record.packs;
285
+ writeRecord(root, { ...record, packs: rest });
286
+ return { id, version: was.version ?? null, blocks: Array.isArray(was.blocks) ? was.blocks : [] };
287
+ }
288
+
289
+ // Why, in both languages.
290
+ const both = (problem) => ({ zh: problemIn("zh", problem), en: problemIn("en", problem) });
291
+
292
+ /**
293
+ * The workspace's packs, as 设置 › 组件列表's cards and gallery block pack list say them: each scope of
294
+ * components/ that holds a block or a pack.json, [{ id, name: { zh, en } (its scope's for one with no
295
+ * pack.json), description, version, author, homepage, icon (null where it says none), kind ("official":
296
+ * one of Gallery's own; "installed": put there by an install; "own": a scope of blocks someone wrote
297
+ * here), problem ({ zh, en }: why its pack.json does not read, or null), blocks (how many), enabled (its
298
+ * switch, gallery.json's components.packs), changed (of what was installed, the blocks changed since, and
299
+ * pack.json where it was), newer (of one of Gallery's own that was changed since, Gallery's version of it
300
+ * when that comes after the one installed, which is not put over it; else null) }]: Gallery's own first,
301
+ * then those installed, then the workspace's own, each by id; and before them all the default pack (local/,
302
+ * OWN_SCOPE: kind "default", named and described by DEFAULT_PACK, its switch as any pack's), whether or
303
+ * not it holds a block yet: where an Agent's block goes when it names no pack.
304
+ */
305
+ export function workspacePacks(root, { settings = null, shippedIds = shippedPackIds(), directory = packsDirectory } = {}) {
306
+ const { components } = layoutOf(root);
307
+ const record = recordOf(root);
308
+ const installed = isTable(record.packs) ? record.packs : {};
309
+ const blocks = packageFolders(root);
310
+ const scopes = new Set([OWN_SCOPE, ...blocks.map(({ id }) => id.split("/")[0])]);
311
+ try {
312
+ for (const name of fs.readdirSync(components)) if (PACK_ID.test(name) && fs.existsSync(path.join(components, name, PACK_FILE))) scopes.add(name);
313
+ } catch {}
314
+ const switches = (settings ?? componentSettings(root)).packs ?? {};
315
+ const listed = [...scopes].map((id) => {
316
+ const folder = path.join(components, id);
317
+ let manifest = null;
318
+ let problem = null;
319
+ if (fs.existsSync(path.join(folder, PACK_FILE))) {
320
+ try {
321
+ manifest = readPackManifest(fs.readFileSync(path.join(folder, PACK_FILE), "utf8"));
322
+ if (manifest.id !== id) {
323
+ problem = said("pack.json 的 id 是 {0},它的文件夹却是 components/{1}", manifest.id, id);
324
+ manifest = null;
325
+ }
326
+ } catch (error) {
327
+ problem = error;
328
+ }
329
+ }
330
+ const was = isTable(installed[id]) ? installed[id] : null;
331
+ const ids = blocks.filter((block) => block.id.startsWith(`${id}/`));
332
+ const changed = was ? ids.filter((block) => isTable(record[block.id]) && fingerprintOf(block.folder) !== record[block.id].fingerprint).map((block) => block.id) : [];
333
+ if (was && ownFingerprint(folder) !== was.fingerprint) changed.push(`${id}/${PACK_FILE}`);
334
+ const official = shippedIds.includes(id);
335
+ // One of Gallery's own: what Gallery's pack.json says of it, where the workspace's has none (its blocks
336
+ // put there one by one, gallery block add's, before a start installed the pack).
337
+ let shipped = null;
338
+ if (official) {
339
+ try {
340
+ shipped = readPackManifest(fs.readFileSync(path.join(directory, id, PACK_FILE), "utf8"));
341
+ } catch {}
342
+ }
343
+ // Gallery's newer version, not put over a change: a changed block of it whose version Gallery's comes after, or a changed pack.json.
344
+ const versionAt = (block) => {
345
+ try {
346
+ return JSON.parse(fs.readFileSync(path.join(components, ...block.split("/"), PACKAGE_MANIFEST), "utf8")).version ?? null;
347
+ } catch {
348
+ return null;
349
+ }
350
+ };
351
+ const ownBlocks = official ? shippedBlocks(directory) : [];
352
+ const behind = official && shipped && changed.some((block) => (block.endsWith(`/${PACK_FILE}`) ? versionAfter(shipped.version, manifest?.version ?? null) : (ownBlocks.some((one) => one.id === block) && versionAfter(ownBlocks.find((one) => one.id === block).version, versionAt(block)))));
353
+ const newer = behind ? shipped.version : null;
354
+ const told = id === OWN_SCOPE ? DEFAULT_PACK : manifest ?? (problem ? null : shipped);
355
+ return {
356
+ id,
357
+ name: told?.name ?? { zh: id, en: id },
358
+ description: told?.description ?? null,
359
+ version: manifest?.version ?? null,
360
+ author: told?.author ?? null,
361
+ homepage: told?.homepage ?? null,
362
+ icon: told?.icon ?? null,
363
+ kind: id === OWN_SCOPE ? "default" : official ? "official" : was ? "installed" : "own",
364
+ problem: problem ? both(problem) : null,
365
+ blocks: ids.length,
366
+ enabled: switches[id] !== false,
367
+ changed,
368
+ newer,
369
+ };
370
+ });
371
+ const rank = ({ id, kind }) => (kind === "default" ? -1 : kind === "official" ? shippedIds.indexOf(id) : kind === "installed" ? 1000 : 2000);
372
+ return listed.sort((a, b) => rank(a) - rank(b) || (a.id < b.id ? -1 : 1));
373
+ }
374
+
375
+ // What installOfficialPacks tells the log of one pack, a line each.
376
+ function installedLines(root, made, first) {
377
+ const lines = [];
378
+ const where = path.resolve(root);
379
+ if (first) lines.push(`Gallery's pack ${made.id} ${made.version} installed in ${where} (${made.added.length + made.same.length + made.updated.length} blocks)${OFF_AT_FIRST.includes(made.id) ? ", switched off: 设置 › 组件列表 turns it on" : ""}`);
380
+ else {
381
+ if (made.added.length) lines.push(`Gallery's pack ${made.id} in ${where} has new blocks: ${made.added.join(", ")}`);
382
+ if (made.updated.length) lines.push(`Gallery's pack ${made.id} in ${where}, its blocks as they were installed, updated to this Gallery's: ${made.updated.join(", ")}`);
383
+ if (made.removed.length) lines.push(`Gallery's pack ${made.id} in ${where}: ${made.removed.join(", ")} no longer in it, taken out`);
384
+ }
385
+ return lines;
386
+ }
387
+
388
+ /**
389
+ * Gallery's own packs (in `directory`, the package's) installed into the workspace at `root`, as
390
+ * installPack installs any, whenever its server starts and by gallery init: one not installed yet is
391
+ * (one of OFF_AT_FIRST switched off first in gallery.json, where it says nothing of it: a gallery.json that
392
+ * cannot be written leaves that pack for the next start), one installed is brought up to Gallery's.
393
+ * `env`: whose NO_PACKS is read; `log`: told what was done, a line each. Never rejects: { did: "off"
394
+ * (NO_PACKS), "unread" (gallery.json does not read as Gallery's) or "done", packs: [installPack's answer
395
+ * with `first`, or { id, failed }] }.
396
+ */
397
+ export async function installOfficialPacks(root, { directory = packsDirectory, env = process.env, log = () => {} } = {}) {
398
+ if (packsSkipped(env)) return { did: "off", packs: [] };
399
+ let marker = { ours: false };
400
+ try {
401
+ marker = markerOf(fs.readFileSync(layoutOf(root).marker, "utf8"));
402
+ } catch {}
403
+ if (!marker.ours) return { did: "unread", packs: [] };
404
+ const ids = shippedPackIds(directory);
405
+ const packs = [];
406
+ for (const id of ids) {
407
+ try {
408
+ const first = !isTable(recordOf(root).packs?.[id]);
409
+ if (first && OFF_AT_FIRST.includes(id) && componentSettings(root).packs[id] === undefined) await writeComponentSettings(root, { pack: id, enabled: false });
410
+ const made = installPack(root, folderFiles(path.join(directory, id)), { official: true, shippedIds: ids });
411
+ packs.push({ ...made, first });
412
+ for (const line of installedLines(root, made, first)) log(line);
413
+ } catch (error) {
414
+ log(`Gallery's pack ${id} could not be installed in ${path.resolve(root)}: ${error?.message ?? error}`);
415
+ packs.push({ id, failed: error?.message ?? String(error) });
416
+ }
417
+ }
418
+ return { did: "done", packs };
419
+ }