@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,7 +1,9 @@
1
1
  // The session between a report page and a workbench that shows it in an iframe of the same origin
2
2
  // (docs/workbench.md): the page's side is src/editor/page/session.mjs, the workbench's
3
3
  // src/workbench/app/session/. Every message is { protocol: PROTOCOL, v: VERSION, type, slug, ... },
4
- // posted to the other window for this origin only.
4
+ // posted to the other window for this origin only; or, for a draft of another workspace, between the
5
+ // page and a workbench of another origin each side's server vouched for (the page's ?shell=<origin>,
6
+ // GET /__gallery/workspace/shell; the workbench's POST elsewhere: src/workbench/elsewhere.mjs).
5
7
  //
6
8
  // report -> workbench ready once the editor started: { commands, title, icon, look, state, annotations, card }
7
9
  // state when the state, the title, the page's icon, the look it shows, how many 批注 it
@@ -31,9 +33,14 @@
31
33
  // workspace a page was made under this one (a page block's box, the page itself
32
34
  // staying as it is): the workbench reads the list of pages again and
33
35
  // shows this page's row open
36
+ // consent a block's card asks to be let online (its 允许访问: the kit's net.js):
37
+ // { block (its id), hosts (those of its needs waiting) }: the workbench
38
+ // opens its consent dialog, which writes what the reader says
34
39
  // annotations-removed
35
40
  // a 批注 deleted from its card: { items }: the workbench says so, as
36
41
  // it does for 全部删除, and its 撤销 puts them back
42
+ // bye the page goes (pagehide), to a workbench of another origin alone, which
43
+ // cannot see it go: its session ends there
37
44
  // workbench -> report command { id, name, ... }
38
45
 
39
46
  export const PROTOCOL = "gallery/session";
@@ -0,0 +1,299 @@
1
+ import { createHash } from "node:crypto";
2
+ import fs from "node:fs";
3
+ import path from "node:path";
4
+ import { beforeCatalogRead } from "./component-catalog.mjs";
5
+ import { packsDirectory } from "./paths.mjs";
6
+ import { PACKAGE_MANIFEST, layoutOf } from "./workspace.mjs";
7
+
8
+ // Gallery's own custom blocks (自带块): the blocks of Gallery's own block packs (./block-packs.mjs), a
9
+ // folder each in the package (src/packs/<pack>/<name>/ in the source checkout, packs/<pack>/<name>/ in
10
+ // the release), each a block of the scope <pack> as any workspace's is, its manifest's id <pack>/<name>:
11
+ // the pack gallery's (Gallery 风格) and gallery-soft's (柔光风格). A workspace's first start installs each
12
+ // pack as any shared pack is installed (./block-packs.mjs installOfficialPacks); gallery block add <name>
13
+ // (gallery's, or <pack>/<name>) copies one unchanged into a workspace, components/<pack>/<name>/, and records its
14
+ // version and a fingerprint of what it copied in .gallery/blocks.json; adding it again updates a copy
15
+ // that is as it was put there, and never one whose fingerprint has changed since, which is someone's
16
+ // work (gallery block new <id> --recipe <name> starts a block of one's own from a shipped one instead).
17
+ // The scopes of Gallery's packs are kept for these: gallery block new refuses them. A custom page's
18
+ // service (phase 2) adds one the same way when a card asks for it.
19
+ //
20
+ // A workspace's copies follow Gallery (the user, 2026-11-09: a home page made with 1.0.0's cards kept
21
+ // their plain look after 1.1.0 brought the cards' design): a copy that is as it was added and behind
22
+ // Gallery's is updated in place, as gallery block add would update it, without the command
23
+ // (followShipped): as a server starts (src/server/index.mjs, production.mjs), whenever its catalog
24
+ // reads the workspace's blocks (readCatalog, by followOnRead's hook) and when the page service reads
25
+ // them (its library, an add), once a process for each block and version, told once in the server's
26
+ // log. A copy changed since it was added is someone's work and stays as it is: the log says so once,
27
+ // and 设置 › 组件列表 and gallery block list say that Gallery has a newer one and how to take it.
28
+
29
+ /** The scope of Gallery's own blocks that a bare name names (gallery block add card): the pack gallery's. */
30
+ export const SHIPPED_SCOPE = "gallery";
31
+
32
+ // What a system writes into a folder it shows, which nobody wrote: macOS's Finder (.DS_Store, and ._
33
+ // files beside each on a disk of another format), Windows' Explorer (Thumbs.db, desktop.ini). No
34
+ // fingerprint counts them, no add takes them out, and a recipe copies none.
35
+ const SYSTEM_FILE = /^(?:\.DS_Store|\._.*|Thumbs\.db|ehthumbs\.db|desktop\.ini)$/i;
36
+
37
+ /** Whether a file called `name` (its last part) is one a system wrote into a folder it showed. */
38
+ export const isSystemFile = (name) => SYSTEM_FILE.test(name);
39
+
40
+ /** The files of a folder, by their paths in it with "/", sorted, what a system wrote there left out. */
41
+ export function filesIn(folder) {
42
+ return fs.readdirSync(folder, { recursive: true, withFileTypes: true }).filter((entry) => entry.isFile() && !SYSTEM_FILE.test(entry.name))
43
+ .map((entry) => path.relative(folder, path.join(entry.parentPath, entry.name)).split(path.sep).join("/")).sort();
44
+ }
45
+
46
+ /**
47
+ * The names of a block's files in the order they are written: its manifest last, what makes a folder a
48
+ * block to whoever watches (a running server's watcher, the catalog), so that a block that appears is
49
+ * whole, and one a write stopped partway through is a folder with no manifest, which loads as nothing.
50
+ */
51
+ export const writingOrder = (names) => [...names.filter((name) => name !== PACKAGE_MANIFEST), ...(names.includes(PACKAGE_MANIFEST) ? [PACKAGE_MANIFEST] : [])];
52
+
53
+ /** What a folder holds, as a hash of each file's path and bytes (what a system wrote there aside), or null when there is no such folder. */
54
+ export function fingerprintOf(folder) {
55
+ if (!fs.existsSync(folder)) return null;
56
+ return fingerprintOfFiles(filesIn(folder).map((name) => ({ name, data: fs.readFileSync(path.join(folder, name)) })));
57
+ }
58
+
59
+ /** What fingerprintOf says of a folder that holds `files` alone ([{ name, data }], each by its path in it with "/"). */
60
+ export function fingerprintOfFiles(files) {
61
+ const hash = createHash("sha256");
62
+ const named = files.filter(({ name }) => !SYSTEM_FILE.test(name.split("/").at(-1))).sort((a, b) => (a.name < b.name ? -1 : a.name > b.name ? 1 : 0));
63
+ for (const { name, data } of named) hash.update(`${name}\u0000`).update(data).update("\n");
64
+ return hash.digest("hex").slice(0, 16);
65
+ }
66
+
67
+ // The folders right in `directory`, by name, or none where it is not there.
68
+ const foldersOf = (directory) => {
69
+ try {
70
+ return fs.readdirSync(directory, { withFileTypes: true }).filter((entry) => entry.isDirectory()).map((entry) => entry.name).sort();
71
+ } catch {
72
+ return [];
73
+ }
74
+ };
75
+
76
+ /** The ids of Gallery's own packs in `directory` (the package's): each folder of it, by name. */
77
+ export const shippedPackIds = (directory = packsDirectory) => foldersOf(directory);
78
+
79
+ /**
80
+ * Gallery's own blocks in `directory` (the package's packs): [{ name, id, pack, folder, version, title:
81
+ * { zh, en }, description: { zh, en }, places }], by pack and name; a folder whose manifest does not read
82
+ * as its pack's block of its name is none.
83
+ */
84
+ export function shippedBlocks(directory = packsDirectory) {
85
+ return foldersOf(directory).flatMap((pack) => foldersOf(path.join(directory, pack)).flatMap((name) => {
86
+ const folder = path.join(directory, pack, name);
87
+ try {
88
+ const manifest = JSON.parse(fs.readFileSync(path.join(folder, PACKAGE_MANIFEST), "utf8"));
89
+ if (manifest.id !== `${pack}/${name}`) return [];
90
+ return [{ name, id: manifest.id, pack, folder, version: manifest.version, title: manifest.name, description: manifest.description, places: manifest.places ?? ["document"] }];
91
+ } catch {
92
+ return [];
93
+ }
94
+ }));
95
+ }
96
+
97
+ /** The shipped block `written` names (card, gallery/card, gallery-soft/todos: a bare name is the pack gallery's), or null. */
98
+ export function shippedBlock(written, directory = packsDirectory) {
99
+ const id = written.includes("/") ? written : `${SHIPPED_SCOPE}/${written}`;
100
+ return shippedBlocks(directory).find((block) => block.id === id) ?? null;
101
+ }
102
+
103
+ /** Whether `id` is of a scope of Gallery's own packs (gallery/…, gallery-soft/…). */
104
+ export const isShippedId = (id, directory = packsDirectory) => shippedPackIds(directory).includes(String(id).split("/")[0]);
105
+
106
+ /**
107
+ * .gallery/blocks.json: { "<id>": { version, fingerprint } } of each block added or installed (one of
108
+ * Gallery's own, or of a pack), and `packs`, { "<pack id>": { version, fingerprint, blocks, official? } } of
109
+ * each pack installed (./block-packs.mjs); {} for none or a file that does not read.
110
+ */
111
+ export function recordOf(root) {
112
+ try {
113
+ const record = JSON.parse(fs.readFileSync(layoutOf(root).blocks, "utf8"));
114
+ return record && typeof record === "object" && !Array.isArray(record) ? record : {};
115
+ } catch {
116
+ return {};
117
+ }
118
+ }
119
+
120
+ /** .gallery/blocks.json as `record` says. */
121
+ export function writeRecord(root, record) {
122
+ const file = layoutOf(root).blocks;
123
+ fs.mkdirSync(path.dirname(file), { recursive: true });
124
+ fs.writeFileSync(file, `${JSON.stringify(record, null, 2)}\n`);
125
+ }
126
+
127
+ /** Where a block of the workspace at `root` is. */
128
+ const folderIn = (root, id) => path.join(layoutOf(root).components, ...id.split("/"));
129
+
130
+ /**
131
+ * What the workspace at `root` holds of the shipped `block`: { added (a folder of its id is there),
132
+ * version (what its manifest says, or null), changed (its files are not what was added: changed since,
133
+ * or put there by some other hand), behind (it is as added, and Gallery's is another now) }.
134
+ */
135
+ export function shippedState(root, block) {
136
+ const folder = folderIn(root, block.id);
137
+ const now = fingerprintOf(folder);
138
+ if (now === null) return { added: false, version: null, changed: false, behind: false };
139
+ let version = null;
140
+ try {
141
+ version = JSON.parse(fs.readFileSync(path.join(folder, PACKAGE_MANIFEST), "utf8")).version ?? null;
142
+ } catch {}
143
+ const kept = recordOf(root)[block.id];
144
+ const shipped = fingerprintOf(block.folder);
145
+ const changed = now !== shipped && now !== kept?.fingerprint;
146
+ return { added: true, version, changed, behind: !changed && now !== shipped };
147
+ }
148
+
149
+ /**
150
+ * Copies the shipped `block` into the workspace at `root`, unchanged: { did: "added", "updated" (from a
151
+ * copy as it was added, `from` its version) or "same" (nothing to do), folder }. A copy whose files
152
+ * changed since it was added (or that no add put there) is left as it is: an error with code "changed".
153
+ * The manifest is written last, what makes a folder a block to a running server's watcher, so that a
154
+ * block that appears is whole; files of the old copy that the new one has not go first.
155
+ */
156
+ export function addShipped(root, block) {
157
+ const folder = folderIn(root, block.id);
158
+ const state = shippedState(root, block);
159
+ if (state.changed) throw Object.assign(new Error(`${block.id} was changed after it was added`), { code: "changed", folder });
160
+ const shipped = fingerprintOf(block.folder);
161
+ const record = recordOf(root);
162
+ if (state.added && !state.behind) {
163
+ if (record[block.id]?.fingerprint !== shipped) writeRecord(root, { ...record, [block.id]: { version: block.version, fingerprint: shipped } });
164
+ return { did: "same", folder };
165
+ }
166
+ const files = filesIn(block.folder);
167
+ if (state.added) for (const old of filesIn(folder)) if (!files.includes(old)) fs.rmSync(path.join(folder, old));
168
+ for (const file of writingOrder(files)) {
169
+ fs.mkdirSync(path.dirname(path.join(folder, file)), { recursive: true });
170
+ fs.copyFileSync(path.join(block.folder, file), path.join(folder, file));
171
+ }
172
+ writeRecord(root, { ...record, [block.id]: { version: block.version, fingerprint: shipped } });
173
+ return { did: state.added ? "updated" : "added", from: state.version, folder };
174
+ }
175
+
176
+ // A version's numbers (1.10.0: [1, 10, 0]), or null for one that is not three of them.
177
+ const numbersOf = (version) => (/^\d+\.\d+\.\d+$/.test(String(version ?? "")) ? version.split(".").map(Number) : null);
178
+
179
+ /** Whether version `a` comes after `b` (both x.y.z); `b` none or not of that form: whether they differ. */
180
+ export function versionAfter(a, b) {
181
+ const [x, y] = [numbersOf(a), numbersOf(b)];
182
+ if (!x || !y) return a !== b;
183
+ const at = x.findIndex((number, index) => number !== y[index]);
184
+ return at !== -1 && x[at] > y[at];
185
+ }
186
+
187
+ /**
188
+ * The version of the shipped `block` that the workspace at `root` does not take because its copy was
189
+ * changed since it was added (or no add put it there), when Gallery's comes after the copy's; else null.
190
+ */
191
+ export function shippedNewer(root, block) {
192
+ const state = shippedState(root, block);
193
+ return state.changed && versionAfter(block.version, state.version) ? block.version : null;
194
+ }
195
+
196
+ const looked = new Map(); // a workspace's root and a shipped block's folder -> the version of it looked at
197
+ let told = () => {}; // where followShipped tells what it did when it is not given a log: the server's (followOnRead)
198
+
199
+ // What followShipped did, as lines of the log.
200
+ function followedLines(root, { updated, kept, failed }) {
201
+ const lines = [];
202
+ if (updated.length) lines.push(`Gallery's own blocks in ${root}, as they were added, updated to this Gallery's: ${updated.map(({ id, from, to }) => `${id} ${from ?? "?"} -> ${to}`).join(", ")}`);
203
+ for (const { id, version, shipped } of kept) lines.push(`${id} in ${root} was changed after it was added, so it stays at ${version ?? "its version"}: Gallery's is ${shipped} (设置 › 组件列表 says how to take it)`);
204
+ for (const { id, to, why } of failed) lines.push(`${id} in ${root} could not be updated to Gallery's ${to}: ${why}`);
205
+ return lines;
206
+ }
207
+
208
+ /**
209
+ * Bring the workspace at `root`'s copies of Gallery's own blocks (of `ids`, by default each one) up to
210
+ * Gallery's (in `directory`): one that is as it was added and behind is updated as addShipped updates
211
+ * it (the manifest written last); one changed since it was added is kept as it is. Each block and
212
+ * version is looked at once a process, a later call for it doing nothing, so that what reads the blocks
213
+ * again and again (a server's catalog, its page service) pays once. `log`: told once of what was done,
214
+ * a line each (by default the one followOnRead set: none in a command). Never throws: { updated: [{ id,
215
+ * from, to }], kept: [{ id, version, shipped }] (changed, Gallery's newer), failed: [{ id, to, why }] }.
216
+ */
217
+ export function followShipped(root, { ids = null, directory = packsDirectory, log = null } = {}) {
218
+ const done = { updated: [], kept: [], failed: [] };
219
+ const key = path.resolve(root);
220
+ for (const block of shippedBlocks(directory)) {
221
+ if (ids && !ids.includes(block.id)) continue;
222
+ const at = `${key}\u0000${path.resolve(block.folder)}`;
223
+ if (looked.get(at) === block.version) continue;
224
+ looked.set(at, block.version);
225
+ try {
226
+ const state = shippedState(root, block);
227
+ if (state.changed && versionAfter(block.version, state.version)) done.kept.push({ id: block.id, version: state.version, shipped: block.version });
228
+ if (!state.behind) continue;
229
+ if (addShipped(root, block).did === "updated") done.updated.push({ id: block.id, from: state.version, to: block.version });
230
+ } catch (error) {
231
+ done.failed.push({ id: block.id, to: block.version, why: error?.message ?? String(error) });
232
+ }
233
+ }
234
+ for (const line of followedLines(key, done)) (log ?? told)(line);
235
+ return done;
236
+ }
237
+
238
+ const following = new Set(); // the workspaces whose server runs in this process (followOnRead), by their resolved root
239
+ const keyOf = (root) => (process.platform === "win32" ? path.resolve(root).toLowerCase() : path.resolve(root));
240
+
241
+ /**
242
+ * From now on in this process, the catalog brings the copies of Gallery's own blocks of the workspace at
243
+ * `root` up to Gallery's before it reads them (followShipped, its ids those of the scopes of Gallery's
244
+ * packs it finds), and what is done of it is told to `log` (a line): a server's, set as it starts for
245
+ * its own workspace (another's blocks are its own server's to follow, and a test's process reads the
246
+ * repository's reports/ too, which nothing of it is to write).
247
+ */
248
+ export function followOnRead(root, log) {
249
+ following.add(keyOf(root));
250
+ told = log;
251
+ beforeCatalogRead((read, ids) => {
252
+ if (following.has(keyOf(read))) followShipped(read, { ids });
253
+ }, shippedPackIds());
254
+ }
255
+
256
+ // The words of a shipped block's files that name it, and what a recipe's copy names instead: its id,
257
+ // and the id with "-" for "/" (a class, a chart type).
258
+ const namesOf = (id) => [id, id.replace("/", "-")];
259
+ const escaped = (words) => words.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
260
+
261
+ /**
262
+ * The shipped block whose preview.svg the file `bytes` is, byte for byte, as Gallery ships it or as a
263
+ * recipe of it for the block `id` has it (every word that named it naming `id`), or null: a block made
264
+ * by --recipe keeps its recipe's picture until someone draws its own, which gallery block check notes.
265
+ */
266
+ export function shippedPreviewOf(bytes, id, directory = packsDirectory) {
267
+ for (const block of shippedBlocks(directory)) {
268
+ if (block.id === id) continue; // a shipped block's own picture is its own
269
+ let shipped;
270
+ try {
271
+ shipped = fs.readFileSync(path.join(block.folder, "preview.svg"));
272
+ } catch {
273
+ continue;
274
+ }
275
+ if (shipped.equals(bytes) || Buffer.from(recipeFiles(block, id)["preview.svg"] ?? "").equals(bytes)) return block;
276
+ }
277
+ return null;
278
+ }
279
+
280
+ /**
281
+ * The files of a new block `id` made from the shipped `block` (gallery block new <id> --recipe <name>),
282
+ * by name, the manifest last: each as Gallery ships it, every word that names the shipped block naming
283
+ * the new one, all in one pass, so that a new name holding an old one (local/gallery-card, made of
284
+ * gallery/card) is not renamed again; its version 0.1.0.
285
+ */
286
+ export function recipeFiles(block, id) {
287
+ const [from, to] = [namesOf(block.id), namesOf(id)];
288
+ const names = new RegExp(from.map(escaped).join("|"), "g");
289
+ const files = {};
290
+ for (const file of filesIn(block.folder)) {
291
+ const bytes = fs.readFileSync(path.join(block.folder, file));
292
+ if (/\.(?:json|html|md|css|js|svg)$/.test(file)) {
293
+ let text = bytes.toString("utf8").replace(names, (name) => to[from.indexOf(name)]);
294
+ if (file === PACKAGE_MANIFEST) text = text.replace(/"version":\s*"[^"]*"/, '"version": "0.1.0"');
295
+ files[file] = text;
296
+ } else files[file] = bytes;
297
+ }
298
+ return Object.fromEntries(writingOrder(Object.keys(files)).map((name) => [name, files[name]]));
299
+ }
@@ -0,0 +1,70 @@
1
+ // The sidebar's head rows (docs/workbench.md "The sidebar", **Head**; the user's word of 2026-11-09):
2
+ // 新建, 搜索 and each custom page, one list the reader orders by dragging its rows (no row goes into
3
+ // another, none into the tree, no document among them), kept for the workspace in the outline file
4
+ // (.gallery/outline.json's `head`, which ./outline.mjs keeps as it writes the tree, so that every browser
5
+ // shows the order the reader gave). A row's key: "new" (新建), "search" (搜索), or "@<slug>" for a custom
6
+ // page (its address in the workbench, which no slug holds). Pure: the server's (shared/pages.mjs listPages,
7
+ // the workbench service's head) and the workbench's (its sidebar) alike.
8
+
9
+ /** The key of the head's 新建 row. */
10
+ export const HEAD_NEW = "new";
11
+ /** The key of the head's 搜索 row. */
12
+ export const HEAD_SEARCH = "search";
13
+ /** The key of custom page `slug`'s row: @<slug>. */
14
+ export const pageHeadKey = (slug) => `@${slug}`;
15
+ /** The custom page a head key names, or null (new, search). */
16
+ export const headPage = (key) => (typeof key === "string" && key.startsWith("@") ? key.slice(1) : null);
17
+ /** How many keys a stored head keeps at most (those of pages gone stay, so that one restored goes back to its place). */
18
+ export const MOST_HEAD = 200;
19
+
20
+ const KEY = /^(?:new|search|@[a-z0-9]+(?:-[a-z0-9]+)*)$/;
21
+
22
+ /**
23
+ * `value` as a head to store: an array of keys (new, search, @<slug>), each once, MOST_HEAD at most; null
24
+ * for anything else (not an array, a key that is none, one twice, too many).
25
+ */
26
+ export function storedHead(value) {
27
+ if (!Array.isArray(value) || value.length > MOST_HEAD) return null;
28
+ if (!value.every((key) => typeof key === "string" && KEY.test(key))) return null;
29
+ return new Set(value).size === value.length ? [...value] : null;
30
+ }
31
+
32
+ /**
33
+ * The head's rows in their order: the keys `stored` (a head as the outline file keeps it, or null) gives,
34
+ * those of pages that are not there passed over, then what it does not name: 新建 first and 搜索 after it
35
+ * where it names neither (as before any drag), and each page of `pages` (their slugs, in the order a page
36
+ * goes by when the reader gave it none: shared/pages.mjs inPageOrder) after the last row it names, in that
37
+ * order. Always holds new and search once each, and each page of `pages` once.
38
+ */
39
+ export function headOrder(stored, pages = []) {
40
+ const there = new Set(pages);
41
+ const named = (storedHead(stored) ?? []).filter((key) => key === HEAD_NEW || key === HEAD_SEARCH || there.has(headPage(key)));
42
+ if (!named.includes(HEAD_SEARCH)) named.unshift(HEAD_SEARCH);
43
+ if (!named.includes(HEAD_NEW)) named.splice(named.indexOf(HEAD_SEARCH), 0, HEAD_NEW);
44
+ for (const slug of pages) if (!named.includes(pageHeadKey(slug))) named.push(pageHeadKey(slug));
45
+ return named;
46
+ }
47
+
48
+ /**
49
+ * The head with the row `key` moved before the row `before` (null: last), the others as they were: what a
50
+ * drop on the head makes. Unchanged where `key` is not in it or is `before`.
51
+ */
52
+ export function movedInHead(head, key, before) {
53
+ if (!head.includes(key) || key === before) return [...head];
54
+ const rest = head.filter((one) => one !== key);
55
+ const at = before === null ? rest.length : rest.indexOf(before);
56
+ rest.splice(at < 0 ? rest.length : at, 0, key);
57
+ return rest;
58
+ }
59
+
60
+ /**
61
+ * The stored head `stored` (or null, when none is kept yet: `shown`, the head as the sidebar shows it now,
62
+ * stands for it) with page `slug`'s row put right after the row of `after` (a page's slug), else last: a
63
+ * new page's place. Keys of pages gone are kept where they stand.
64
+ */
65
+ export function headWithPage(stored, shown, slug, after = null) {
66
+ const head = (storedHead(stored) ?? storedHead(shown) ?? [HEAD_NEW, HEAD_SEARCH]).filter((key) => key !== pageHeadKey(slug));
67
+ const at = after ? head.indexOf(pageHeadKey(after)) : -1;
68
+ head.splice(at < 0 ? head.length : at + 1, 0, pageHeadKey(slug));
69
+ return head.slice(-MOST_HEAD);
70
+ }
@@ -13,11 +13,21 @@ import { isMissingValue, numberReading } from "./number-reading.mjs";
13
13
  // copy or delete either block (a copied pair takes a key of its own:
14
14
  // src/editor/page/clipboard/own/chart-keys.mjs, and the commit makes sure of it against the file:
15
15
  // src/editor/source/chart-keys.mjs).
16
+ //
17
+ // A view of a table (plan 阶段 4: a task board, a count, a chart card of a custom block's) is the same
18
+ // link: an instance of a custom block whose manifest's needs hold "tables" names the table by that key
19
+ // (VIEW_FROM), reads its rows as a chart does (the kit's runtime/table-reading.js, context.table()) and
20
+ // changes them only by asking the page editor (an intent: docs/editor.md, "Table views"). A key is one
21
+ // table's, which any number of charts and views read: TABLE_READERS are the attributes that read one.
16
22
 
17
23
  /** On a chart's host: the key of the table it draws. */
18
24
  export const CHART_DATA = "data-doc-chart-data";
19
25
  /** On a table's frame (.doc-table-wrap): the key a chart reads it by. */
20
26
  export const CHART_SOURCE = "data-doc-chart-source";
27
+ /** On an instance of a custom block whose needs hold "tables": the key of the table it is a view of (context.table()). */
28
+ export const VIEW_FROM = "data-doc-from";
29
+ /** The attributes that name a table by its key, a chart's host's and a view's. */
30
+ export const TABLE_READERS = [CHART_DATA, VIEW_FROM];
21
31
  /** A key: a letter, then letters, digits, "_" or "-", 32 at most. */
22
32
  export const CHART_KEY = /^[A-Za-z][\w-]{0,31}$/;
23
33
 
@@ -38,6 +48,28 @@ const FORMULA = /\\\(([\s\S]*?)\\\)|\\\[([\s\S]*?)\\\]|\$\$([\s\S]*?)\$\$/g;
38
48
  */
39
49
  export const cellWords = (text) => text.replace(FORMULA, (_, inline, display, dollars) => inline ?? display ?? dollars).replaceAll(ZWSP, "").replace(/\s+/g, " ").trim();
40
50
 
51
+ // A formula KaTeX drew on a page: its TeX is its annotation (its drawing's text is its glyphs, twice over).
52
+ const TEX = 'annotation[encoding="application/x-tex"]';
53
+
54
+ /**
55
+ * A cell's text on a page as the file writes it, as near as the page tells: a formula KaTeX drew as its
56
+ * TeX, the editor's chip of an empty one as nothing (the file's \(\)). Its words are then cellWords'.
57
+ * For the kit, which reads a table on a page (runtime/table-reading.js: a chart's, a view's and a package's rows).
58
+ * @param {Node} node
59
+ * @returns {string}
60
+ */
61
+ export function cellText(node) {
62
+ if (node.nodeType === 3) return /** @type {Text} */ (node).data;
63
+ if (node.nodeType !== 1) return "";
64
+ const element = /** @type {Element} */ (node);
65
+ if (element.hasAttribute("data-ge-empty")) return "";
66
+ const tex = element.classList.contains("katex") ? element.querySelector(TEX) : null;
67
+ if (tex) return tex.textContent ?? "";
68
+ let text = "";
69
+ for (const child of element.childNodes) text += cellText(child);
70
+ return text;
71
+ }
72
+
41
73
  // A header's data-sort-type that says its column holds no numbers: its values are its words.
42
74
  const WORD_TYPES = new Set(["text", "date"]);
43
75
 
@@ -66,7 +98,7 @@ export function cellValue(cell, type = null) {
66
98
  * row of header cells alone; null when it has neither), its header cells' data-sort-type (null where
67
99
  * none), its rows of data in the file's order (never a <tfoot>'s), each cell { words, sort } (its
68
100
  * words, cellWords', and its data-sort-value, or null), and whether a cell of the header or the rows
69
- * spans rows or columns (charts/from-table.js tableCells reads it from the page,
101
+ * spans rows or columns (runtime/table-reading.js readTable reads it from the page,
70
102
  * chart-declarations.mjs tableCells from the file).
71
103
  *
72
104
  * `data` is what d3.csvParse gives: an object for each row of data, in their order, its values by
@@ -0,0 +1,83 @@
1
+ import { parse } from "parse5";
2
+ import { TODO } from "./components/list.mjs";
3
+ import { sha256 } from "./files.mjs";
4
+ import { attr, BLOCK_LEVEL, elementsOf, hasClass } from "./html-tree.mjs";
5
+
6
+ // A document's to-dos as its pages show them (the items of its to-do lists, ul.doc-todo): what the
7
+ // workspace's facts list (src/workbench/index.mjs, workspace.query("todos")) and what a check of one
8
+ // from another page finds it by (src/editor/todos.mjs, workspace.setTodo: the plan's 5.1), the one
9
+ // reading for both, so that a ref the facts gave names the item the write looks for. Pure but for the
10
+ // parser and the hash: no DOM.
11
+
12
+ const SKIPPED = new Set(["script", "style", "template", "noscript", "svg", "math"]);
13
+ const HEADING = /^h([1-6])$/;
14
+ const tidy = (text) => text.replace(/[\s​]+/g, " ").trim();
15
+
16
+ // The words an element holds, as a reader reads them: its text, a line break a space, nothing of a script,
17
+ // a style or a drawing; `stop(child)`: a child left out with what it holds.
18
+ function wordsOf(node, stop = () => false) {
19
+ let text = "";
20
+ const visit = (current) => {
21
+ for (const child of current.childNodes ?? []) {
22
+ if (child.nodeName === "#text") text += child.value;
23
+ else if (child.tagName === "br") text += " ";
24
+ else if (child.tagName && !SKIPPED.has(child.tagName) && !stop(child)) visit(child);
25
+ }
26
+ };
27
+ visit(node);
28
+ return tidy(text);
29
+ }
30
+
31
+ // A to-do's own words: what the item holds before its lists and the blocks it holds (a paragraph, a
32
+ // picture), or, where it holds no words of its own (an item written <li><p>…</p></li>), its first block's.
33
+ function itemWords(item) {
34
+ const own = wordsOf(item, (child) => BLOCK_LEVEL.has(child.tagName));
35
+ if (own) return own;
36
+ const first = elementsOf(item).find((child) => BLOCK_LEVEL.has(child.tagName) && child.tagName !== "ul" && child.tagName !== "ol");
37
+ return first ? wordsOf(first, (child) => child.tagName === "ul" || child.tagName === "ol") : "";
38
+ }
39
+
40
+ /**
41
+ * The to-dos of a document's `text` (its page's HTML, as its pages see it), in their order: [{ text,
42
+ * done, block, path, nth }], `path` the headings above it (their words, the outermost first: an h2 under
43
+ * an h1 of the body, the document's title never one), `nth` which of the to-dos of the same words under
44
+ * the same path it is (0 the first). With `at`, each says where its <li> starts in `text` too (`at`, the
45
+ * offset of its start tag), which the editor's units name it by (source/units.mjs elStart).
46
+ */
47
+ export function todosOf(text, { at = false } = {}) {
48
+ const root = parse(String(text), { sourceCodeLocationInfo: at });
49
+ const headings = []; // [{ level, words }]
50
+ const todos = [];
51
+ const seen = new Map();
52
+ const visit = (node) => {
53
+ for (const child of elementsOf(node)) {
54
+ if (SKIPPED.has(child.tagName)) continue;
55
+ const heading = HEADING.exec(child.tagName);
56
+ if (heading && !hasClass(child, "doc-title")) {
57
+ const level = Number(heading[1]);
58
+ while (headings.length && headings.at(-1).level >= level) headings.pop();
59
+ const words = wordsOf(child);
60
+ if (words) headings.push({ level, words });
61
+ continue;
62
+ }
63
+ if (child.tagName === "li" && child.parentNode?.tagName === "ul" && hasClass(child.parentNode, TODO)) {
64
+ const path = headings.map(({ words }) => words);
65
+ const words = itemWords(child);
66
+ const key = JSON.stringify([words, path]);
67
+ const nth = seen.get(key) ?? 0;
68
+ seen.set(key, nth + 1);
69
+ todos.push({ text: words, done: attr(child, "data-checked") !== undefined, block: attr(child, "data-block-id") ?? null, path, nth, ...(at ? { at: child.sourceCodeLocation?.startOffset ?? -1 } : {}) });
70
+ }
71
+ visit(child);
72
+ }
73
+ };
74
+ visit(root);
75
+ return todos;
76
+ }
77
+
78
+ /**
79
+ * The version of a document's file the facts read its to-dos from (the hash of its text, as a to-do's
80
+ * ref carries it: workspace.query("todos")), which a check of one finds it by its place in (`nth`) while
81
+ * the file is still that one.
82
+ */
83
+ export const fileVersion = (source) => sha256(source).slice(0, 16);
@@ -0,0 +1,24 @@
1
+ import os from "node:os";
2
+ import path from "node:path";
3
+
4
+ // The user's own folders for Gallery, outside every workspace: "cache", what may be thrown away (the
5
+ // update check's answer, src/cli/updates.mjs), and "data", what Gallery keeps of the machine (the
6
+ // registry of the workspaces used on it, ./workspace-registry.mjs). One function, so that every system
7
+ // finds them alike. Node's built-ins only: gallery --version reads it, and stays as fast as Node's start.
8
+
9
+ /**
10
+ * The folder of `kind` ("cache" or "data"): GALLERY_CACHE_DIR or GALLERY_DATA_DIR when set (the tests
11
+ * name folders of their own); else on Windows %LOCALAPPDATA%\gallery for both; on macOS
12
+ * ~/Library/Caches/gallery and ~/Library/Application Support/gallery; elsewhere $XDG_CACHE_HOME/gallery
13
+ * (~/.cache/gallery) and $XDG_STATE_HOME/gallery (~/.local/state/gallery). Only a path: nothing is made.
14
+ */
15
+ export function userDirectory(kind, { env = process.env, platform = process.platform, home = os.homedir() } = {}) {
16
+ const cache = kind === "cache";
17
+ const own = cache ? env.GALLERY_CACHE_DIR : env.GALLERY_DATA_DIR;
18
+ if (own) return path.resolve(own);
19
+ if (platform === "win32") return path.join(env.LOCALAPPDATA || path.join(home, "AppData", "Local"), "gallery");
20
+ if (platform === "darwin") return path.join(home, "Library", cache ? "Caches" : "Application Support", "gallery");
21
+ return cache
22
+ ? path.join(env.XDG_CACHE_HOME || path.join(home, ".cache"), "gallery")
23
+ : path.join(env.XDG_STATE_HOME || path.join(home, ".local", "state"), "gallery");
24
+ }
@@ -0,0 +1,14 @@
1
+ // Gallery's versions compared, with nothing imported: the preview server's choice of a server to use
2
+ // or replace (./preview-server.mjs) and gallery --version's notes (src/cli/updates.mjs, which loads
3
+ // nothing it can do without) read it.
4
+
5
+ /** -1, 0 or 1 as version `a` is older than, the same as or newer than `b` (numbers by dots: 0.1.0 < 0.1.10 < 0.2.0). */
6
+ export function compareVersions(a, b) {
7
+ const parts = (version) => String(version ?? "0").split(/[.+-]/).slice(0, 3).map((part) => Number.parseInt(part, 10) || 0);
8
+ const [x, y] = [parts(a), parts(b)];
9
+ for (let index = 0; index < 3; index++) if ((x[index] ?? 0) !== (y[index] ?? 0)) return (x[index] ?? 0) < (y[index] ?? 0) ? -1 : 1;
10
+ return 0;
11
+ }
12
+
13
+ /** A released version as npm writes one, numbers alone (0.1.2): what a registry's answer must be to be believed. */
14
+ export const RELEASED = /^\d{1,6}\.\d{1,6}\.\d{1,6}$/;