@heycys/gallery 0.1.0 → 0.1.2

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 (465) hide show
  1. package/THIRD-PARTY-NOTICES.md +51 -1
  2. package/browser/editor/components/callout/index.mjs +40 -15
  3. package/browser/editor/components/columns/page.mjs +45 -32
  4. package/browser/editor/components/details/index.mjs +2 -1
  5. package/browser/editor/components/dialog/index.mjs +2 -1
  6. package/browser/editor/components/dialog/page.mjs +0 -18
  7. package/browser/editor/components/divider/index.mjs +1 -1
  8. package/browser/editor/components/embed/index.mjs +2 -2
  9. package/browser/editor/components/figure/page.mjs +10 -1
  10. package/browser/editor/components/file/page.mjs +2 -2
  11. package/browser/editor/components/flowchart/add.mjs +7 -6
  12. package/browser/editor/components/flowchart/page.mjs +1 -1
  13. package/browser/editor/components/heading/index.mjs +2 -0
  14. package/browser/editor/components/heading/page.mjs +6 -0
  15. package/browser/editor/components/highlight/index.mjs +4 -20
  16. package/browser/editor/components/icons.mjs +13 -2
  17. package/browser/editor/components/image/crop.mjs +6 -9
  18. package/browser/editor/components/image/page.mjs +2 -2
  19. package/browser/editor/components/installed/index.mjs +82 -29
  20. package/browser/editor/components/installed/page.mjs +146 -34
  21. package/browser/editor/components/installed/served.mjs +6 -5
  22. package/browser/editor/components/instances.mjs +18 -0
  23. package/browser/editor/components/kit.mjs +3 -0
  24. package/browser/editor/components/list/page.mjs +3 -6
  25. package/browser/editor/components/media/page.mjs +44 -14
  26. package/browser/editor/components/pages.mjs +2 -2
  27. package/browser/editor/components/registry.mjs +68 -33
  28. package/browser/editor/components/section/index.mjs +2 -1
  29. package/browser/editor/components/set-apart.mjs +24 -0
  30. package/browser/editor/components/table/index.mjs +64 -5
  31. package/browser/editor/components/table/page.mjs +30 -19
  32. package/browser/editor/page/annotate/anchors.mjs +4 -3
  33. package/browser/editor/page/annotate/card.mjs +3 -6
  34. package/browser/editor/page/annotate/index.mjs +61 -34
  35. package/browser/editor/page/autosave.mjs +357 -38
  36. package/browser/editor/page/beside.mjs +5 -5
  37. package/browser/editor/page/block-menu/colors.mjs +3 -1
  38. package/browser/editor/page/block-menu/index.mjs +8 -6
  39. package/browser/editor/page/blocks.mjs +16 -7
  40. package/browser/editor/page/board/client.mjs +57 -0
  41. package/browser/editor/page/board/hint.mjs +145 -0
  42. package/browser/editor/page/board/history.mjs +119 -0
  43. package/browser/editor/page/board/index.mjs +970 -0
  44. package/browser/editor/page/board/settings.mjs +209 -0
  45. package/browser/editor/page/caret.mjs +5 -2
  46. package/browser/editor/page/changes/bar.mjs +94 -0
  47. package/browser/editor/page/changes/ghost.mjs +206 -0
  48. package/browser/editor/page/changes/gone-words.mjs +94 -0
  49. package/browser/editor/page/changes/index.mjs +447 -0
  50. package/browser/editor/page/changes/words.mjs +27 -0
  51. package/browser/editor/page/clipboard/import/colors.mjs +3 -3
  52. package/browser/editor/page/clipboard/import/html.mjs +29 -6
  53. package/browser/editor/page/clipboard/import/inline.mjs +32 -0
  54. package/browser/editor/page/clipboard/import/markdown.mjs +58 -13
  55. package/browser/editor/page/clipboard/import/read.mjs +6 -1
  56. package/browser/editor/page/clipboard/import/to-blocks.mjs +44 -12
  57. package/browser/editor/page/clipboard/import/yuque.mjs +622 -0
  58. package/browser/editor/page/clipboard/index.mjs +156 -26
  59. package/browser/editor/page/clipboard/own/blocks.mjs +25 -16
  60. package/browser/editor/page/clipboard/own/chart-keys.mjs +41 -28
  61. package/browser/editor/page/clipboard/own/describe.mjs +16 -7
  62. package/browser/editor/page/clipboard/own/export.mjs +6 -6
  63. package/browser/editor/page/clipboard/own/selection.mjs +3 -3
  64. package/browser/editor/page/clipboard/own/writers.mjs +0 -11
  65. package/browser/editor/page/columns/index.mjs +48 -46
  66. package/browser/editor/page/commit.mjs +98 -25
  67. package/browser/editor/page/conflicts.mjs +13 -33
  68. package/browser/editor/page/convert.mjs +8 -7
  69. package/browser/editor/page/core.mjs +81 -27
  70. package/browser/editor/page/custom-page.mjs +106 -0
  71. package/browser/editor/page/drag/index.mjs +40 -24
  72. package/browser/editor/page/drag/preview.mjs +9 -4
  73. package/browser/editor/page/editor.mjs +120 -28
  74. package/browser/editor/page/emoji-picker/emoji-tab.mjs +22 -13
  75. package/browser/editor/page/emoji-picker/grid.mjs +7 -5
  76. package/browser/editor/page/emoji-picker/icon-tab.mjs +4 -4
  77. package/browser/editor/page/emoji-picker/icons.mjs +0 -1
  78. package/browser/editor/page/emoji-picker/index.mjs +11 -9
  79. package/browser/editor/page/emoji-picker/styles.mjs +156 -2
  80. package/browser/editor/page/emoji-picker/support.mjs +6 -4
  81. package/browser/editor/page/emoji-picker/upload.mjs +14 -13
  82. package/browser/editor/page/fills.mjs +5 -3
  83. package/browser/editor/page/fold/index.mjs +348 -0
  84. package/browser/editor/page/fold/rule.mjs +125 -0
  85. package/browser/editor/page/folded.mjs +23 -0
  86. package/browser/editor/page/format-bar/bar.mjs +2 -1
  87. package/browser/editor/page/format-bar/index.mjs +1 -1
  88. package/browser/editor/page/geometry.mjs +8 -6
  89. package/browser/editor/page/handle/index.mjs +22 -14
  90. package/browser/editor/page/hints/index.mjs +1 -1
  91. package/browser/editor/page/history.mjs +24 -4
  92. package/browser/editor/page/insert/index.mjs +30 -17
  93. package/browser/editor/page/links/index.mjs +5 -3
  94. package/browser/editor/page/links/pages.mjs +27 -9
  95. package/browser/editor/page/long-runs.mjs +75 -0
  96. package/browser/editor/page/look.mjs +69 -6
  97. package/browser/editor/page/margin.mjs +63 -27
  98. package/browser/editor/page/media-menu/index.mjs +6 -7
  99. package/browser/editor/page/menu.mjs +86 -31
  100. package/browser/editor/page/merge.mjs +24 -0
  101. package/browser/editor/page/notices.mjs +3 -3
  102. package/browser/editor/page/offered.mjs +1 -1
  103. package/browser/editor/page/outline/folds.mjs +11 -10
  104. package/browser/editor/page/outline/index.mjs +131 -45
  105. package/browser/editor/page/outline/list.mjs +23 -11
  106. package/browser/editor/page/outline/read.mjs +1 -1
  107. package/browser/editor/page/outline/strip.mjs +7 -1
  108. package/browser/editor/page/page-objects.mjs +13 -2
  109. package/browser/editor/page/panel.mjs +9 -13
  110. package/browser/editor/page/present-links.mjs +11 -2
  111. package/browser/editor/page/resize/index.mjs +42 -29
  112. package/browser/editor/page/selection/delete.mjs +8 -6
  113. package/browser/editor/page/selection/index.mjs +10 -3
  114. package/browser/editor/page/served.mjs +14 -0
  115. package/browser/editor/page/session.mjs +101 -6
  116. package/browser/editor/page/slash-menu/index.mjs +3 -3
  117. package/browser/editor/page/table/cell-bar.mjs +4 -1
  118. package/browser/editor/page/table/cells.mjs +103 -47
  119. package/browser/editor/page/table/icons.mjs +3 -1
  120. package/browser/editor/page/table/index.mjs +40 -16
  121. package/browser/editor/page/table/pictures.mjs +299 -0
  122. package/browser/editor/page/table/views.mjs +150 -0
  123. package/browser/editor/page/table/widths.mjs +9 -4
  124. package/browser/editor/page/text-select/index.mjs +43 -14
  125. package/browser/editor/page/todo-writes.mjs +75 -0
  126. package/browser/editor/page/tooltip.mjs +1 -1
  127. package/browser/editor/page/type-grid.mjs +4 -3
  128. package/browser/editor/page/typing/code-edges.mjs +63 -17
  129. package/browser/editor/page/typing/index.mjs +65 -9
  130. package/browser/editor/page/typing/leave.mjs +1 -1
  131. package/browser/editor/page/ui.mjs +13 -0
  132. package/browser/shared/annotations.mjs +8 -10
  133. package/browser/shared/block-packs.mjs +404 -0
  134. package/browser/shared/board-places.mjs +224 -0
  135. package/browser/shared/card-size.mjs +59 -0
  136. package/browser/shared/code-folds.mjs +5 -1
  137. package/browser/shared/colors.mjs +17 -14
  138. package/browser/shared/component-catalog.mjs +345 -54
  139. package/browser/shared/component-source.mjs +37 -0
  140. package/browser/shared/components/callout.mjs +4 -2
  141. package/browser/shared/components/index.mjs +72 -9
  142. package/browser/shared/components/installed.mjs +110 -8
  143. package/browser/shared/components/page.mjs +22 -3
  144. package/browser/shared/components/state.mjs +5 -1
  145. package/browser/shared/components/table.mjs +1 -1
  146. package/browser/shared/components/text.mjs +2 -2
  147. package/browser/shared/document-look.mjs +183 -0
  148. package/browser/shared/drafts.mjs +432 -0
  149. package/browser/shared/emoji/data/LICENSE-lucide.txt +43 -0
  150. package/browser/shared/emoji/data/README.md +4 -2
  151. package/browser/shared/emoji/data/categories.json +1 -1
  152. package/browser/shared/emoji/data/keywords-en.json +1 -1
  153. package/browser/shared/emoji/data/keywords-zh.json +1 -1
  154. package/browser/shared/emoji/data/names.json +1 -1
  155. package/browser/shared/emoji/data/positions.json +1 -1
  156. package/browser/shared/emoji/data/twemoji-index.json +1 -1
  157. package/browser/shared/emoji/data/twemoji-svg.bin +0 -0
  158. package/browser/shared/emoji/data.mjs +10 -12
  159. package/browser/shared/emoji/emoji.mjs +8 -7
  160. package/browser/shared/emoji/icon-value.mjs +4 -3
  161. package/browser/shared/extension-sidebar.mjs +126 -0
  162. package/browser/shared/extensions.mjs +79 -0
  163. package/browser/shared/file-table.mjs +101 -0
  164. package/browser/shared/html-tree.mjs +11 -5
  165. package/browser/shared/i18n/en.mjs +374 -35
  166. package/browser/shared/json-layout.mjs +47 -0
  167. package/browser/shared/long-runs.mjs +39 -0
  168. package/browser/shared/net-cache.mjs +133 -0
  169. package/browser/shared/net-keys.mjs +32 -0
  170. package/browser/shared/net-policy.mjs +177 -0
  171. package/browser/shared/new-names.mjs +5 -2
  172. package/browser/shared/outline-shape.mjs +128 -0
  173. package/browser/shared/outline.mjs +458 -0
  174. package/browser/shared/pack-manifest.mjs +77 -0
  175. package/browser/shared/page-address.mjs +6 -3
  176. package/browser/shared/page-cards.mjs +308 -0
  177. package/browser/shared/page-links.mjs +69 -6
  178. package/browser/shared/pages.mjs +388 -0
  179. package/browser/shared/paths.mjs +6 -0
  180. package/browser/shared/preferences.mjs +10 -4
  181. package/browser/shared/preview-server.mjs +3 -7
  182. package/browser/shared/session.mjs +13 -5
  183. package/browser/shared/shipped-blocks.mjs +299 -0
  184. package/browser/shared/table-chart.mjs +33 -1
  185. package/browser/shared/todos.mjs +83 -0
  186. package/browser/shared/user-directory.mjs +24 -0
  187. package/browser/shared/versions.mjs +14 -0
  188. package/browser/shared/web-links.mjs +134 -0
  189. package/browser/shared/workspace-columns.mjs +120 -0
  190. package/browser/shared/workspace-look.mjs +91 -0
  191. package/browser/shared/workspace-name.mjs +154 -0
  192. package/browser/shared/workspace-query.mjs +125 -0
  193. package/browser/shared/workspace-registry.mjs +272 -0
  194. package/browser/shared/workspace.mjs +171 -20
  195. package/browser/shared/zoom.mjs +5 -5
  196. package/dist/chunk-2NRBY6AJ.mjs +2 -0
  197. package/dist/chunk-32ZUEFZ7.mjs +2 -0
  198. package/dist/chunk-35NQ4PLQ.mjs +2 -0
  199. package/dist/chunk-3KJHLHUO.mjs +2 -0
  200. package/dist/chunk-3NJACR4W.mjs +2 -0
  201. package/dist/chunk-4AV456RQ.mjs +2 -0
  202. package/dist/chunk-4OZWXZE5.mjs +5 -0
  203. package/dist/chunk-5XYHDBJ5.mjs +2 -0
  204. package/dist/chunk-5ZJA7CXT.mjs +2 -0
  205. package/dist/chunk-6A53MZYZ.mjs +2 -0
  206. package/dist/chunk-6EXH3ORZ.mjs +166 -0
  207. package/dist/chunk-6EZ7FNIK.mjs +3 -0
  208. package/dist/{chunk-UXUK4PMC.mjs → chunk-6QBHU4DF.mjs} +1 -1
  209. package/dist/{chunk-6U2SLSDN.mjs → chunk-6VTU6KEO.mjs} +1 -1
  210. package/dist/chunk-B4P2CM2J.mjs +3 -0
  211. package/dist/chunk-BPL64HGA.mjs +4 -0
  212. package/dist/chunk-BVEFGE4B.mjs +2 -0
  213. package/dist/chunk-BZ5RAF7L.mjs +2 -0
  214. package/dist/chunk-CRJEG7MT.mjs +2 -0
  215. package/dist/{chunk-B3VTYBYR.mjs → chunk-D4CKRD3V.mjs} +91 -91
  216. package/dist/chunk-D4EURAX4.mjs +4 -0
  217. package/dist/chunk-DQCE7TJY.mjs +5 -0
  218. package/dist/chunk-DR73Y2UJ.mjs +3 -0
  219. package/dist/{chunk-TMYZB6AV.mjs → chunk-EKNHM3P4.mjs} +1 -1
  220. package/dist/{chunk-DB4WKGYF.mjs → chunk-ERLAIBOA.mjs} +2 -2
  221. package/dist/chunk-EURLTOTZ.mjs +4 -0
  222. package/dist/chunk-FJYN7RTH.mjs +4 -0
  223. package/dist/chunk-FWNRPMCJ.mjs +12 -0
  224. package/dist/chunk-FWW4CSAZ.mjs +2 -0
  225. package/dist/{chunk-2B5E4CDJ.mjs → chunk-GPIWQ4X4.mjs} +1 -1
  226. package/dist/chunk-GY3FAUVM.mjs +2 -0
  227. package/dist/chunk-HLYV7RIH.mjs +2 -0
  228. package/dist/chunk-HMYTM3GT.mjs +15 -0
  229. package/dist/chunk-IA4PSIMD.mjs +2 -0
  230. package/dist/chunk-JEUK3ZO7.mjs +2 -0
  231. package/dist/chunk-JVHHHGEA.mjs +3 -0
  232. package/dist/chunk-KTKHRC6H.mjs +2 -0
  233. package/dist/chunk-L7UP52JO.mjs +2 -0
  234. package/dist/chunk-MHW7ZKOU.mjs +2 -0
  235. package/dist/chunk-N76HWBA3.mjs +10 -0
  236. package/dist/chunk-N7AZZLGT.mjs +548 -0
  237. package/dist/chunk-NAMN3RAF.mjs +2 -0
  238. package/dist/{chunk-YXAUQPVK.mjs → chunk-NFMCP2HI.mjs} +3 -3
  239. package/dist/chunk-NG375ILQ.mjs +2 -0
  240. package/dist/chunk-NVRNLK25.mjs +6 -0
  241. package/dist/chunk-NWFBE2YA.mjs +2 -0
  242. package/dist/chunk-NWR2LT5B.mjs +2 -0
  243. package/dist/chunk-OJKMINIU.mjs +20 -0
  244. package/dist/chunk-OUUP3WKT.mjs +2 -0
  245. package/dist/chunk-OW5NWPOJ.mjs +10 -0
  246. package/dist/chunk-PAREWQGB.mjs +4 -0
  247. package/dist/chunk-POQSE4C2.mjs +2 -0
  248. package/dist/chunk-PUOQ65NC.mjs +2 -0
  249. package/dist/{chunk-Z52HTUW7.mjs → chunk-PVER7LSC.mjs} +2 -2
  250. package/dist/chunk-PZDLJJTJ.mjs +3 -0
  251. package/dist/chunk-Q47PLKIJ.mjs +15 -0
  252. package/dist/chunk-Q4UEPUWF.mjs +2 -0
  253. package/dist/chunk-QKXMPUXC.mjs +2 -0
  254. package/dist/chunk-QOUEFUCH.mjs +16 -0
  255. package/dist/chunk-RFDZXFJF.mjs +13 -0
  256. package/dist/chunk-RKPWLGZ3.mjs +4 -0
  257. package/dist/chunk-RMECZA2K.mjs +2 -0
  258. package/dist/{chunk-EUX7IC5J.mjs → chunk-SQ6Y2ZMA.mjs} +2 -2
  259. package/dist/chunk-SX4LJYT6.mjs +8 -0
  260. package/dist/chunk-SXHBYZST.mjs +16 -0
  261. package/dist/chunk-TANZRINB.mjs +2 -0
  262. package/dist/chunk-TEZAWDSQ.mjs +2 -0
  263. package/dist/chunk-UBBRTJ2R.mjs +24 -0
  264. package/dist/chunk-UFNYFFKO.mjs +20 -0
  265. package/dist/chunk-UGWYKHBL.mjs +170 -0
  266. package/dist/chunk-UKSHDZZ6.mjs +2 -0
  267. package/dist/chunk-UMHUSOPJ.mjs +2 -0
  268. package/dist/chunk-UNOYVIYR.mjs +2 -0
  269. package/dist/chunk-V6RIYQZZ.mjs +4 -0
  270. package/dist/chunk-VJPFVNNW.mjs +15 -0
  271. package/dist/chunk-VS3ZMVGX.mjs +5 -0
  272. package/dist/chunk-VTKNEYT3.mjs +6 -0
  273. package/dist/chunk-VXACTLO3.mjs +3 -0
  274. package/dist/chunk-W3BGBJQW.mjs +2 -0
  275. package/dist/chunk-YI43RG4P.mjs +2 -0
  276. package/dist/chunk-YQGT4AB2.mjs +6 -0
  277. package/dist/chunk-ZB4H7ZN4.mjs +2 -0
  278. package/dist/{chunk-ACOPDCNB.mjs → chunk-ZHEHPMBK.mjs} +1 -1
  279. package/dist/chunk-ZTHICSSF.mjs +2 -0
  280. package/dist/chunk-ZUNVAXLH.mjs +2 -0
  281. package/dist/chunk-ZWPMCK7P.mjs +2 -0
  282. package/dist/cli.mjs +1 -1
  283. package/dist/server.mjs +1 -1
  284. package/dist/{chunk-EVJ3BX3M.mjs → update-fetch.mjs} +1 -1
  285. package/dist/worker.mjs +1 -1
  286. package/kit/board.css +95 -0
  287. package/kit/board.js +250 -0
  288. package/kit/charts.js +5 -71
  289. package/kit/code.js +14 -14
  290. package/kit/math.js +18 -2
  291. package/kit/report.css +500 -151
  292. package/kit/runtime.js +1720 -170
  293. package/kit/state.js +10 -1
  294. package/kit/tables.js +172 -37
  295. package/kit/ui.js +166 -27
  296. package/package.json +2 -1
  297. package/packs/gallery/card/component.json +14 -0
  298. package/packs/gallery/card/example.html +10 -0
  299. package/packs/gallery/card/preview.svg +1 -0
  300. package/packs/gallery/card/style.css +6 -0
  301. package/packs/gallery/card/template.html +6 -0
  302. package/packs/gallery/card/writing.md +14 -0
  303. package/packs/gallery/chart-card/component.json +15 -0
  304. package/packs/gallery/chart-card/example.html +14 -0
  305. package/packs/gallery/chart-card/kit.js +130 -0
  306. package/packs/gallery/chart-card/preview.svg +1 -0
  307. package/packs/gallery/chart-card/style.css +42 -0
  308. package/packs/gallery/chart-card/template.html +13 -0
  309. package/packs/gallery/chart-card/writing.md +20 -0
  310. package/packs/gallery/chart-view/component.json +20 -0
  311. package/packs/gallery/chart-view/example.html +13 -0
  312. package/packs/gallery/chart-view/kit.js +355 -0
  313. package/packs/gallery/chart-view/preview.svg +1 -0
  314. package/packs/gallery/chart-view/style.css +94 -0
  315. package/packs/gallery/chart-view/template.html +3 -0
  316. package/packs/gallery/chart-view/writing.md +22 -0
  317. package/packs/gallery/countdown/component.json +18 -0
  318. package/packs/gallery/countdown/example.html +3 -0
  319. package/packs/gallery/countdown/kit.js +156 -0
  320. package/packs/gallery/countdown/preview.svg +1 -0
  321. package/packs/gallery/countdown/style.css +130 -0
  322. package/packs/gallery/countdown/template.html +3 -0
  323. package/packs/gallery/countdown/writing.md +22 -0
  324. package/packs/gallery/habit/component.json +14 -0
  325. package/packs/gallery/habit/example.html +3 -0
  326. package/packs/gallery/habit/kit.js +295 -0
  327. package/packs/gallery/habit/preview.svg +1 -0
  328. package/packs/gallery/habit/style.css +246 -0
  329. package/packs/gallery/habit/template.html +3 -0
  330. package/packs/gallery/habit/writing.md +21 -0
  331. package/packs/gallery/heatmap/component.json +18 -0
  332. package/packs/gallery/heatmap/example.html +3 -0
  333. package/packs/gallery/heatmap/kit.js +351 -0
  334. package/packs/gallery/heatmap/preview.svg +1 -0
  335. package/packs/gallery/heatmap/style.css +201 -0
  336. package/packs/gallery/heatmap/template.html +3 -0
  337. package/packs/gallery/heatmap/writing.md +21 -0
  338. package/packs/gallery/kanban/component.json +18 -0
  339. package/packs/gallery/kanban/example.html +12 -0
  340. package/packs/gallery/kanban/kit.js +540 -0
  341. package/packs/gallery/kanban/preview.svg +1 -0
  342. package/packs/gallery/kanban/style.css +212 -0
  343. package/packs/gallery/kanban/template.html +3 -0
  344. package/packs/gallery/kanban/writing.md +20 -0
  345. package/packs/gallery/metric/component.json +22 -0
  346. package/packs/gallery/metric/example.html +15 -0
  347. package/packs/gallery/metric/kit.js +248 -0
  348. package/packs/gallery/metric/preview.svg +1 -0
  349. package/packs/gallery/metric/style.css +92 -0
  350. package/packs/gallery/metric/template.html +3 -0
  351. package/packs/gallery/metric/writing.md +23 -0
  352. package/packs/gallery/note/component.json +14 -0
  353. package/packs/gallery/note/example.html +3 -0
  354. package/packs/gallery/note/kit.js +102 -0
  355. package/packs/gallery/note/preview.svg +1 -0
  356. package/packs/gallery/note/style.css +76 -0
  357. package/packs/gallery/note/template.html +3 -0
  358. package/packs/gallery/note/writing.md +18 -0
  359. package/packs/gallery/pack.json +8 -0
  360. package/packs/gallery/recent/component.json +13 -0
  361. package/packs/gallery/recent/example.html +1 -0
  362. package/packs/gallery/recent/kit.js +238 -0
  363. package/packs/gallery/recent/preview.svg +1 -0
  364. package/packs/gallery/recent/style.css +158 -0
  365. package/packs/gallery/recent/template.html +1 -0
  366. package/packs/gallery/recent/writing.md +15 -0
  367. package/packs/gallery/static/component.json +13 -0
  368. package/packs/gallery/static/example.html +11 -0
  369. package/packs/gallery/static/preview.svg +1 -0
  370. package/packs/gallery/static/style.css +138 -0
  371. package/packs/gallery/static/template.html +1 -0
  372. package/packs/gallery/static/writing.md +18 -0
  373. package/packs/gallery/stats/component.json +13 -0
  374. package/packs/gallery/stats/example.html +1 -0
  375. package/packs/gallery/stats/kit.js +166 -0
  376. package/packs/gallery/stats/preview.svg +1 -0
  377. package/packs/gallery/stats/style.css +151 -0
  378. package/packs/gallery/stats/template.html +1 -0
  379. package/packs/gallery/stats/writing.md +11 -0
  380. package/packs/gallery/today/component.json +12 -0
  381. package/packs/gallery/today/example.html +1 -0
  382. package/packs/gallery/today/kit.js +185 -0
  383. package/packs/gallery/today/preview.svg +1 -0
  384. package/packs/gallery/today/style.css +120 -0
  385. package/packs/gallery/today/template.html +1 -0
  386. package/packs/gallery/today/writing.md +14 -0
  387. package/packs/gallery/todos/component.json +19 -0
  388. package/packs/gallery/todos/example.html +3 -0
  389. package/packs/gallery/todos/kit.js +342 -0
  390. package/packs/gallery/todos/preview.svg +1 -0
  391. package/packs/gallery/todos/style.css +267 -0
  392. package/packs/gallery/todos/template.html +3 -0
  393. package/packs/gallery/todos/writing.md +30 -0
  394. package/packs/gallery/weather/component.json +19 -0
  395. package/packs/gallery/weather/example.html +3 -0
  396. package/packs/gallery/weather/kit.js +312 -0
  397. package/packs/gallery/weather/preview.svg +1 -0
  398. package/packs/gallery/weather/style.css +258 -0
  399. package/packs/gallery/weather/template.html +3 -0
  400. package/packs/gallery/weather/writing.md +26 -0
  401. package/packs/gallery-soft/pack.json +8 -0
  402. package/release.json +13 -11
  403. package/sdk/doc-kit.d.ts +404 -7
  404. package/sdk/doc-state.d.ts +2 -0
  405. package/skill/SKILL.md +71 -26
  406. package/skill/references/block-script.md +140 -0
  407. package/skill/references/building-blocks.md +257 -0
  408. package/skill/references/example-report.html +1 -1
  409. package/skill/references/extensions.md +59 -0
  410. package/skill/references/pages-and-data.md +221 -0
  411. package/skill/references/writing-html.md +9 -7
  412. package/skill/sdk/doc-kit.d.ts +404 -7
  413. package/skill/sdk/doc-state.d.ts +2 -0
  414. package/web/assets/index-BK2e_07w.js +13 -0
  415. package/web/assets/index-CWFI83mF.css +1 -0
  416. package/web/index.html +2 -2
  417. package/browser/editor/components/callout/page.mjs +0 -13
  418. package/dist/chunk-2PBALTR3.mjs +0 -57
  419. package/dist/chunk-3LA3EMDE.mjs +0 -15
  420. package/dist/chunk-5FRMCDPY.mjs +0 -16
  421. package/dist/chunk-5LEK2CBS.mjs +0 -2
  422. package/dist/chunk-5OFN5AHC.mjs +0 -2
  423. package/dist/chunk-5SIYS5HN.mjs +0 -2
  424. package/dist/chunk-5TEK3RAD.mjs +0 -2
  425. package/dist/chunk-6CYG3Z4V.mjs +0 -2
  426. package/dist/chunk-7GHT2UCA.mjs +0 -15
  427. package/dist/chunk-7QQBR7PB.mjs +0 -2
  428. package/dist/chunk-ATCJYAR4.mjs +0 -2
  429. package/dist/chunk-C7HWOBIF.mjs +0 -2
  430. package/dist/chunk-E7VYDG2X.mjs +0 -2
  431. package/dist/chunk-EZY3WC6Z.mjs +0 -15
  432. package/dist/chunk-FQGQH4KM.mjs +0 -2
  433. package/dist/chunk-G7TOXONE.mjs +0 -6
  434. package/dist/chunk-GPF4YWWB.mjs +0 -9
  435. package/dist/chunk-GYQV7Y4J.mjs +0 -120
  436. package/dist/chunk-HMHK3EQ6.mjs +0 -2
  437. package/dist/chunk-HQQMJCQJ.mjs +0 -10
  438. package/dist/chunk-IERUOGC3.mjs +0 -6
  439. package/dist/chunk-ITNLYXXV.mjs +0 -3
  440. package/dist/chunk-L4DVONOG.mjs +0 -2
  441. package/dist/chunk-LAE5NQ4B.mjs +0 -2
  442. package/dist/chunk-LC7YNQFG.mjs +0 -2
  443. package/dist/chunk-LHTFLRB6.mjs +0 -4
  444. package/dist/chunk-NFIBI4IP.mjs +0 -26
  445. package/dist/chunk-NSKUTQ5J.mjs +0 -5
  446. package/dist/chunk-O52JMOCZ.mjs +0 -2
  447. package/dist/chunk-P2CAZPDP.mjs +0 -3
  448. package/dist/chunk-QMQUXTU4.mjs +0 -12
  449. package/dist/chunk-QVWVFC5K.mjs +0 -6
  450. package/dist/chunk-QYKCJ7FG.mjs +0 -8
  451. package/dist/chunk-QZY6Q64C.mjs +0 -2
  452. package/dist/chunk-TDQP3DKQ.mjs +0 -10
  453. package/dist/chunk-TX6JH7TR.mjs +0 -2
  454. package/dist/chunk-UNUEWH4S.mjs +0 -2
  455. package/dist/chunk-V4CPWKMZ.mjs +0 -2
  456. package/dist/chunk-VACRB2NE.mjs +0 -3
  457. package/dist/chunk-W63L7367.mjs +0 -7
  458. package/dist/chunk-W7CXPCRV.mjs +0 -6
  459. package/dist/chunk-XINNG4F2.mjs +0 -4
  460. package/dist/chunk-YL2DPWVS.mjs +0 -4
  461. package/dist/chunk-YZ5Z6H4W.mjs +0 -4
  462. package/dist/chunk-ZBIM6ARY.mjs +0 -216
  463. package/skill/references/building-components.md +0 -327
  464. package/web/assets/index-B6Ai3wsa.js +0 -13
  465. package/web/assets/index-SYPC3EZy.css +0 -1
@@ -6,9 +6,11 @@
6
6
  // (page icons in its tree); the server reads the pack itself for an export (src/render/emoji.mjs).
7
7
  //
8
8
  // What differs from notion-lite: the data is fetched (the page editor's modules are served as
9
- // they are, unbundled); no sprite sheet (an emoji the pack lacks shows in the system's emoji font);
10
- // the custom emojis are the workspace's library (custom.mjs); settings and the frequently used ones
11
- // are Gallery's own (localStorage).
9
+ // they are, unbundled); no sprite sheet; the custom emojis are the workspace's library (custom.mjs);
10
+ // settings and the frequently used ones are Gallery's own (localStorage). The Twemoji pack is shown on
11
+ // every system (since 2026-11, the user's word: Notion and notion-lite show the system's emoji font on
12
+ // Apple's, Gallery does not), the system's font only where the browser cannot unpack the pack or the
13
+ // pack lacks the emoji. The data holds no flag (Notion's Flags group taken out: data/README.md).
12
14
 
13
15
  import { KEYS } from "../renamed-storage.mjs";
14
16
 
@@ -20,10 +22,6 @@ const FRECENCY_KEY = KEYS.emojiFrecency;
20
22
  export const SKIN_TONE_HANDS = ["✋", "✋🏻", "✋🏼", "✋🏽", "✋🏾", "✋🏿"];
21
23
  export const SKIN_TONE_VARIATIONS = SKIN_TONE_HANDS.length - 1;
22
24
 
23
- // Notion shows Twemoji on Windows, Linux and Android, and the system's own emoji font on Apple's.
24
- const agent = globalThis.navigator?.userAgent ?? "";
25
- export const emojiStyle = /Android|Windows|Linux/i.test(agent) ? "twitter" : "raw";
26
-
27
25
  const state = { positions: null, categories: null, keywords: {}, unique: {}, loaded: false, failed: false, svgIndex: null, svgPack: null };
28
26
  let loading = null;
29
27
 
@@ -52,8 +50,8 @@ export function loadEmojiData() {
52
50
  json("categories.json"),
53
51
  json("keywords-en.json"),
54
52
  json("keywords-zh.json"),
55
- emojiStyle === "raw" ? null : json("twemoji-index.json"),
56
- emojiStyle === "raw" ? null : loadSvgPack(),
53
+ json("twemoji-index.json"),
54
+ loadSvgPack(),
57
55
  ]).then(([positions, categories, en, zh, svgIndex, svgPack]) => {
58
56
  state.svgIndex = svgPack ? svgIndex : null;
59
57
  state.svgPack = svgPack;
@@ -189,8 +187,8 @@ export function recordEmojiUse(emoji) {
189
187
  frecency = map;
190
188
  writeStorage(FRECENCY_KEY, JSON.stringify(map));
191
189
  }
192
- /** The recently used: by count, then by the last use, two rows of them. */
193
- export function recentEmojis(perRow) {
194
- return Object.keys(frecency).sort((a, b) => (frecency[b].f !== frecency[a].f ? frecency[b].f - frecency[a].f : frecency[b].u - frecency[a].u)).slice(0, 2 * perRow);
190
+ /** The recently used: by count, then by the last use, two rows of them; `keep`: those still known (a flag used before, taken out since, no longer shows). */
191
+ export function recentEmojis(perRow, keep = () => true) {
192
+ return Object.keys(frecency).filter(keep).sort((a, b) => (frecency[b].f !== frecency[a].f ? frecency[b].f - frecency[a].f : frecency[b].u - frecency[a].u)).slice(0, 2 * perRow);
195
193
  }
196
194
  export const frecencyBoost = (emoji) => (frecency[emoji] ? 100 * frecency[emoji].f : 0);
@@ -1,10 +1,11 @@
1
1
  import { escapeMarkup } from "../escape.mjs";
2
- import { emojiDataFailed, emojiDataLoaded, emojiInfo, emojiStyle, emojiSvgUrl, hasEmojiSvg, svgUrlOf } from "./data.mjs";
2
+ import { emojiDataFailed, emojiDataLoaded, emojiInfo, emojiSvgUrl, hasEmojiSvg, svgUrlOf } from "./data.mjs";
3
3
 
4
- // Showing an emoji (notion-lite's ui/emoji/emoji.js): on Windows and Linux an <img> of its Twemoji
5
- // vector image (data.mjs), elsewhere, before the data is in or where the pack lacks it, the
6
- // system's emoji font. `lazy`: the image's address is made once it scrolls near (the picker draws
7
- // over a thousand of them), its codepoints kept in data-svg until then (lazySrc).
4
+ // Showing an emoji (notion-lite's ui/emoji/emoji.js): on every system an <img> of its Twemoji vector
5
+ // image (data.mjs); the system's emoji font only where the data failed or the pack lacks it (a
6
+ // placeholder of its size while the data comes). `lazy`: the image's address is made once it
7
+ // scrolls near (the picker draws over a thousand of them), its codepoints kept in data-svg until
8
+ // then (lazySrc).
8
9
 
9
10
  const BLANK_GIF = "data:image/gif;base64,R0lGODlhAQABAIAAAP///wAAACH5BAEAAAAALAAAAAABAAEAAAICRAEAOw==";
10
11
  const px = (size) => (typeof size === "number" ? `${size}px` : size);
@@ -29,8 +30,8 @@ function rawEmojiHTML(emoji, { size } = {}) {
29
30
  */
30
31
  export function emojiHTML(emoji, { size, lazy = false } = {}) {
31
32
  const side = size ? px(size) : "100%";
32
- if (emojiStyle !== "raw" && !emojiDataLoaded() && !emojiDataFailed()) return `<span class="ge-emoji-pending" style="display:inline-block;width:${side};height:${side}"></span>`;
33
- const info = emojiStyle === "raw" ? null : emojiInfo(emoji);
33
+ if (!emojiDataLoaded() && !emojiDataFailed()) return `<span class="ge-emoji-pending" style="display:inline-block;width:${side};height:${side}"></span>`;
34
+ const info = emojiInfo(emoji);
34
35
  if (!info || !hasEmojiSvg(info)) return rawEmojiHTML(emoji, { size });
35
36
  if (lazy) return `<img class="ge-emoji" alt="${esc(emoji)}" src="${BLANK_GIF}" data-svg="${info.codepoints}" draggable="false" style="width:${side};height:${side}">`;
36
37
  return `<img class="ge-emoji" alt="${esc(emoji)}" src="${emojiSvgUrl(info)}" draggable="false" style="width:${side};height:${side}">`;
@@ -73,11 +73,12 @@ export const iconUrl = (value, slug = null, { tab = false } = {}) => `/__gallery
73
73
  const [TAB_LIGHT, TAB_DARK] = ICON_COLOR_VALUES.gray;
74
74
  /**
75
75
  * The browser tab's image of a page with no icon (the workbench's and the preview page's): the page
76
- * the workbench's tree shows for one (its "page" icon, components/icons.ts), in the tab glyphs' gray,
77
- * light or dark as the system is. An image, never none: a tab given no image, or one that does not
76
+ * the workbench's tree shows for one (its "page" icon, components/icons.ts: Lucide's file-text,
77
+ * FinHarness's 文档), its box cropped to `1 1 22 22` so it fills the tab as an emoji does, in the tab
78
+ * glyphs' gray, light or dark as the system is. An image, never none: a tab given no image, or one that does not
78
79
  * load, keeps the one it showed (Chrome), so a page with no icon opened after one with one showed that one's.
79
80
  */
80
- export const DEFAULT_TAB_ICON = `data:image/svg+xml,${encodeURIComponent(`<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 20" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><style>svg{color:${TAB_LIGHT}}@media (prefers-color-scheme:dark){svg{color:${TAB_DARK}}}</style><path d="M5.75 2.75h5.5l3.5 3.5v9.5a1.5 1.5 0 0 1-1.5 1.5h-7.5a1.5 1.5 0 0 1-1.5-1.5V4.25a1.5 1.5 0 0 1 1.5-1.5z"/><path d="M11 2.75v3c0 .41.34.75.75.75h3"/><path d="M7.25 10h5.5M7.25 13h3.5"/></svg>`)}`;
81
+ export const DEFAULT_TAB_ICON = `data:image/svg+xml,${encodeURIComponent(`<svg xmlns="http://www.w3.org/2000/svg" viewBox="1 1 22 22" fill="none" stroke="currentColor" stroke-width="1.75" stroke-linecap="round" stroke-linejoin="round"><style>svg{color:${TAB_LIGHT}}@media (prefers-color-scheme:dark){svg{color:${TAB_DARK}}}</style><path d="M6 22a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h8a2.4 2.4 0 0 1 1.704.706l3.588 3.588A2.4 2.4 0 0 1 20 8v12a2 2 0 0 1-2 2z"/><path d="M14 2v5a1 1 0 0 0 1 1h5"/><path d="M10 9H8"/><path d="M16 13H8"/><path d="M16 17H8"/></svg>`)}`;
81
82
 
82
83
  /** The value of an icon's element as the file (or a page) has it, or null. */
83
84
  export function iconValueOf(html) {
@@ -0,0 +1,126 @@
1
+ import { said } from "./i18n/index.mjs";
2
+ import { isExtensionId } from "./outline-shape.mjs";
3
+ import { linkAddress, linkIcon } from "./web-links.mjs";
4
+
5
+ // The sidebar column an extension provides (docs/workbench.md "Extension columns", references/extensions.md
6
+ // for the Agent that writes one): <workspace>/extensions/<id>/sidebar.json,
7
+ // { "title": "语雀", "icon": "📗", "entries": [
8
+ // { "id": "team", "title": "团队知识库", "url": "https://www.yuque.com/team",
9
+ // "children": [ { "id": "weekly", "title": "周报", "url": "https://www.yuque.com/team/weekly" } ] },
10
+ // { "id": "panel", "title": "发布面板", "url": "http://127.0.0.1:4318/" } ] }
11
+ // `title` is the column's name (100 characters at most), `icon` an emoji or an icon of the 图标 tab (no
12
+ // picture is ever loaded from the web). An entry has an `id` (1 to 128 of A-Z a-z 0-9 . _ : -, once in
13
+ // the file: the extension keeps it, for it is what an address and an open entry go by), a `title` (200
14
+ // at most), an `url` (http or https, 2048 at most: none, and the entry only holds its `children`, which
15
+ // a click opens and closes), an `icon` and `children` (8 levels, 2000 entries in all, 1 MB the file).
16
+ // Pure and the same wherever it is read (the server answers the workbench with it, gallery extension
17
+ // check prints it); reading the file is ./extensions.mjs's (Node's). What makes the file unusable is a
18
+ // refusal (`error`, said() of a reason: the column then shows one row, 条目读不出来:<reason>); what is
19
+ // only left out of it (an icon that is none) is a note, said by gallery extension check and shown nowhere.
20
+
21
+ /** The extension's file in its folder. */
22
+ export const SIDEBAR_FILE = "sidebar.json";
23
+ export const SIDEBAR_LIMITS = { bytes: 1_048_576, levels: 8, entries: 2000, id: 128, title: 200, column: 100 };
24
+ export const entryIdPattern = /^[A-Za-z0-9._:-]{1,128}$/;
25
+
26
+ /** An entry's key in the workbench's address (`#~<extension id>/<entry id>`), and as its row says it. */
27
+ export const extensionKey = (extension, entry) => `~${extension}/${entry}`;
28
+ /** The extension and the entry a key names: { extension, entry }, or null for what is none. */
29
+ export function parseExtensionKey(value) {
30
+ if (typeof value !== "string" || !value.startsWith("~")) return null;
31
+ const at = value.indexOf("/");
32
+ if (at < 0) return null;
33
+ const extension = value.slice(1, at);
34
+ const entry = value.slice(at + 1);
35
+ return isExtensionId(extension) && entryIdPattern.test(entry) ? { extension, entry } : null;
36
+ }
37
+
38
+ const tidy = (value) => (typeof value === "string" ? value.replace(/\s+/g, " ").trim() : "");
39
+ const refused = (message) => ({ error: message });
40
+
41
+ /**
42
+ * What the text of a sidebar.json says: { sidebar: { title, icon?, entries, count }, notes } with each
43
+ * entry { id, title, icon?, url?, children? } (the address as the URL spells it, a title's white space
44
+ * run together), or { error } (said(): why the file is no sidebar), the first reason found. `notes`: said()
45
+ * of what was left out (an icon that is no emoji nor icon of the 图标 tab).
46
+ */
47
+ export function readSidebarText(text) {
48
+ const source = String(text);
49
+ if (source.length > SIDEBAR_LIMITS.bytes) return refused(said("文件超过 1MB"));
50
+ let value;
51
+ try {
52
+ value = JSON.parse(source.replace(/^/, ""));
53
+ } catch (error) {
54
+ return refused(said("不是 JSON:{0}", error.message));
55
+ }
56
+ if (!value || typeof value !== "object" || Array.isArray(value)) return refused(said("最外层要是一个对象,有 title 和 entries"));
57
+ const title = tidy(value.title);
58
+ if (!title || title.length > SIDEBAR_LIMITS.column) return refused(said("title 要有,是栏的名字(100 个字以内)"));
59
+ if (!Array.isArray(value.entries)) return refused(said("entries 要是一个列表"));
60
+ const notes = [];
61
+ let icon;
62
+ if (value.icon !== undefined && value.icon !== null && value.icon !== "") {
63
+ if (linkIcon(value.icon)) icon = value.icon;
64
+ else notes.push(said("icon 不是表情,也不是图标页签里的图标,没有显示"));
65
+ }
66
+ const ids = new Set();
67
+ let count = 0;
68
+ const walk = (list, path, level) => {
69
+ if (level > SIDEBAR_LIMITS.levels && list.length) return { error: said("条目超过 {0} 层({1})", SIDEBAR_LIMITS.levels, path) };
70
+ const made = [];
71
+ for (const [index, raw] of list.entries()) {
72
+ const where = `${path}[${index}]`;
73
+ if (++count > SIDEBAR_LIMITS.entries) return { error: said("条目超过 {0} 个", SIDEBAR_LIMITS.entries) };
74
+ if (!raw || typeof raw !== "object" || Array.isArray(raw)) return { error: said("{0} 要是一个对象", where) };
75
+ if (typeof raw.id !== "string" || !entryIdPattern.test(raw.id)) return { error: said("{0} 的 id 不对(1 到 128 个字符,只能用字母、数字和 . _ : -)", where) };
76
+ if (ids.has(raw.id)) return { error: said("{0} 的 id「{1}」重复了(同一个文件里 id 不能重)", where, raw.id) };
77
+ ids.add(raw.id);
78
+ const name = tidy(raw.title);
79
+ if (!name || name.length > SIDEBAR_LIMITS.title) return { error: said("{0} 要有 title(名称,200 个字以内)", where) };
80
+ const entry = { id: raw.id, title: name };
81
+ if (raw.url !== undefined && raw.url !== null && raw.url !== "") {
82
+ const address = linkAddress(raw.url);
83
+ if (address.refused === "scheme") return { error: said("{0} 的 url 只能是 http 或 https 的网址", where) };
84
+ if (address.refused === "long") return { error: said("{0} 的 url 太长了(最多 2048 个字符)", where) };
85
+ if (address.refused) return { error: said("{0} 的 url 不是一个网址", where) };
86
+ entry.url = address.url;
87
+ }
88
+ if (raw.icon !== undefined && raw.icon !== null && raw.icon !== "") {
89
+ if (linkIcon(raw.icon)) entry.icon = raw.icon;
90
+ else notes.push(said("{0} 的 icon 不是表情,也不是图标页签里的图标,没有显示", where));
91
+ }
92
+ if (raw.children !== undefined && raw.children !== null) {
93
+ if (!Array.isArray(raw.children)) return { error: said("{0} 的 children 要是一个列表", where) };
94
+ const inner = walk(raw.children, `${where}.children`, level + 1);
95
+ if (inner.error) return inner;
96
+ if (inner.entries.length) entry.children = inner.entries;
97
+ }
98
+ made.push(entry);
99
+ }
100
+ return { entries: made };
101
+ };
102
+ const walked = walk(value.entries, "entries", 1);
103
+ if (walked.error) return refused(walked.error);
104
+ return { sidebar: { title, ...(icon ? { icon } : {}), entries: walked.entries, count }, notes };
105
+ }
106
+
107
+ /** The entry `id` of `entries` (a tree: children under each), or null. */
108
+ export function entryIn(entries, id) {
109
+ for (const entry of entries ?? []) {
110
+ if (entry.id === id) return entry;
111
+ const inside = entryIn(entry.children, id);
112
+ if (inside) return inside;
113
+ }
114
+ return null;
115
+ }
116
+
117
+ /**
118
+ * The entry key `key` (`~<extension id>/<entry id>`, a workbench's hash, decoded) names among `extensions`
119
+ * (the columns as GET outline lists them: [{ id, entries }]), or null: what a link to an entry's address
120
+ * opens (one with an `url`) wherever a page reads it (the workbench, a page alone in a tab, 演示视图).
121
+ */
122
+ export function entryOfKey(extensions, key) {
123
+ const named = parseExtensionKey(key);
124
+ const extension = named && (extensions ?? []).find(({ id }) => id === named.extension);
125
+ return extension ? entryIn(extension.entries, named.entry) : null;
126
+ }
@@ -0,0 +1,79 @@
1
+ import fs from "node:fs/promises";
2
+ import path from "node:path";
3
+ import { SIDEBAR_FILE, SIDEBAR_LIMITS, readSidebarText } from "./extension-sidebar.mjs";
4
+ import { said } from "./i18n/index.mjs";
5
+ import { isExtensionId } from "./outline-shape.mjs";
6
+ import { DOCUMENT_FOLDERS, layoutOf } from "./workspace.mjs";
7
+
8
+ // The extensions of a workspace (docs/workbench.md "Extension columns"): each a folder
9
+ // <workspace>/extensions/<id>/ whose sidebar.json (./extension-sidebar.mjs) gives a column of the sidebar
10
+ // its entries; what else the folder holds (the extension's own server, its code) is none of Gallery's.
11
+ // Read from disk each time it is asked (the workbench's list, the outline's columns, gallery extension):
12
+ // the extension writes the file, the watcher tells the workbench (src/server/routes.mjs changeOf), no
13
+ // state is kept here. Node's built-ins only.
14
+
15
+ /**
16
+ * The folders of extensions/ that may be an extension, sorted: no dot name, a name that is an id
17
+ * (isExtensionId), not assets or materials (a document called extensions, made before they came, keeps those
18
+ * in its folder), and no link, which leads out of the workspace. [{ id, folder }].
19
+ */
20
+ export async function extensionFolders(root) {
21
+ const { extensions } = layoutOf(root);
22
+ const entries = await fs.readdir(extensions, { withFileTypes: true }).catch(() => []);
23
+ return entries
24
+ .filter((entry) => entry.isDirectory() && isExtensionId(entry.name) && !DOCUMENT_FOLDERS.includes(entry.name))
25
+ .map((entry) => ({ id: entry.name, folder: path.join(extensions, entry.name) }))
26
+ .sort((a, b) => (a.id < b.id ? -1 : 1));
27
+ }
28
+
29
+ /** The ids of the extensions that have a sidebar.json (the columns the sidebar has), sorted. */
30
+ export async function extensionColumnIds(root) {
31
+ const found = await Promise.all((await extensionFolders(root)).map(async ({ id, folder }) => ((await fs.stat(path.join(folder, SIDEBAR_FILE)).then(() => true, () => false)) ? id : null)));
32
+ return found.filter(Boolean);
33
+ }
34
+
35
+ /**
36
+ * Extension `id` as the sidebar shows it: { id, file (the sidebar.json's path), title (the column's name; the
37
+ * id when the file does not say one), icon?, entries (a tree of { id, title, icon?, url?, children? }), count
38
+ * (the entries in all), notes (said(): what was left out) } or, when the file is not usable, `error`
39
+ * (said(): why) with no entries; `missing` for a folder with no sidebar.json: an extension with nothing to show.
40
+ */
41
+ export async function readExtension(root, id) {
42
+ const file = path.join(layoutOf(root).extensions, id, SIDEBAR_FILE);
43
+ const empty = { id, file, title: id, entries: [], count: 0, notes: [] };
44
+ let stat;
45
+ try {
46
+ stat = await fs.stat(file);
47
+ } catch (error) {
48
+ return error.code === "ENOENT" ? { ...empty, missing: true, error: said("没有 sidebar.json") } : { ...empty, error: said("读不出这个文件:{0}", error.code ?? "error") };
49
+ }
50
+ if (!stat.isFile()) return { ...empty, error: said("sidebar.json 不是一个文件") };
51
+ if (stat.size > SIDEBAR_LIMITS.bytes) return { ...empty, error: said("文件超过 1MB") };
52
+ let text;
53
+ try {
54
+ text = await fs.readFile(file, "utf8");
55
+ } catch (error) {
56
+ return { ...empty, error: said("读不出这个文件:{0}", error.code ?? "error") };
57
+ }
58
+ const read = readSidebarText(text);
59
+ if (read.error) {
60
+ // What can still be said of a file that does not read: its name, when it has one.
61
+ let title = id;
62
+ try {
63
+ const named = JSON.parse(text.replace(/^/, ""))?.title;
64
+ if (typeof named === "string" && named.trim() && named.trim().length <= SIDEBAR_LIMITS.column) title = named.replace(/\s+/g, " ").trim();
65
+ } catch {}
66
+ return { ...empty, title, error: read.error };
67
+ }
68
+ return { ...empty, ...read.sidebar, notes: read.notes };
69
+ }
70
+
71
+ /**
72
+ * The extensions of workspace `root`, by id: those with a sidebar.json (the sidebar's columns), or with `all`
73
+ * every folder that may be one (gallery extension list). Each as readExtension says it.
74
+ */
75
+ export async function listExtensions(root, { all = false } = {}) {
76
+ const folders = await extensionFolders(root);
77
+ const read = await Promise.all(folders.map(({ id }) => readExtension(root, id)));
78
+ return all ? read : read.filter((extension) => !extension.missing);
79
+ }
@@ -0,0 +1,101 @@
1
+ import { parse } from "parse5";
2
+ import { BODY } from "./components/index.mjs";
3
+ import { attr, elementsOf, walk } from "./html-tree.mjs";
4
+ import { decoded, pageAddress } from "./page-address.mjs";
5
+ import { CHART_SOURCE, cellWords, tableRows } from "./table-chart.mjs";
6
+
7
+ // A table of a document's file read as the kit reads it on a page (render/kit/runtime/table-reading.js:
8
+ // a chart drawn from a table, a view's context.table(), a package's context.rows): its header's words and
9
+ // data-sort-type, its rows of data in the file's order, each cell's words and sort value
10
+ // (shared/table-chart.mjs), whether a cell spans others; and, by a key (data-doc-chart-source on its
11
+ // frame), its rows as a block reads them, { values, links }. The checks read a chart's table so
12
+ // (render/chart-declarations.mjs), and the workspace's facts a table another document names
13
+ // (workspace.query("table"): src/workbench/index.mjs, the plan's 5.2). Of parse5's tree; no DOM.
14
+
15
+ const textOf = (node) => (node.nodeName === "#text" ? node.value : (node.childNodes ?? []).map(textOf).join(""));
16
+ const cellsOf = (row) => elementsOf(row).filter((cell) => cell.tagName === "td" || cell.tagName === "th");
17
+ const spans = (cell) => ["rowspan", "colspan"].some((name) => {
18
+ const value = Number.parseInt(attr(cell, name) ?? "1", 10);
19
+ return Number.isFinite(value) && value !== 1;
20
+ });
21
+
22
+ // Its groups, its header row (its head's first row, else a first row of its body all header cells; null
23
+ // for neither) and its body's rows after that, never a <tfoot>'s.
24
+ function tableParts(table) {
25
+ const groups = elementsOf(table);
26
+ const rowsOf = (group) => elementsOf(group).filter((row) => row.tagName === "tr");
27
+ const head = groups.find((group) => group.tagName === "thead");
28
+ let header = head ? rowsOf(head)[0] ?? null : null;
29
+ let rows = groups.filter((group) => group.tagName === "tbody").flatMap(rowsOf);
30
+ if (!header && rows.length > 0 && cellsOf(rows[0]).length > 0 && cellsOf(rows[0]).every((cell) => cell.tagName === "th")) [header, ...rows] = rows;
31
+ return { groups, rowsOf, header, rows };
32
+ }
33
+
34
+ /**
35
+ * What a table of the file holds for a chart (tableRows' `table`), as the kit reads it in the page
36
+ * (charts/from-table.js tableCells): its header row's words (its head's first row, else a first row
37
+ * of header cells alone; null for neither) and its header cells' data-sort-type, its rows of data,
38
+ * each cell's words and sort value (data-sort-value, or null), the first words of its <tfoot>'s rows
39
+ * (`foot`, which no chart reads: the readings say they were left out), and whether a cell of them
40
+ * spans rows or columns (a cell's words cellWords', a formula's its TeX).
41
+ */
42
+ export function tableCells(table) {
43
+ const { groups, rowsOf, header, rows } = tableParts(table);
44
+ const words = (cell) => cellWords(textOf(cell));
45
+ return {
46
+ names: header ? cellsOf(header).map(words) : null,
47
+ types: header ? cellsOf(header).map((cell) => attr(cell, "data-sort-type") ?? null) : null,
48
+ rows: rows.map((row) => cellsOf(row).map((cell) => ({ words: words(cell), sort: attr(cell, "data-sort-value")?.trim() ?? null }))),
49
+ foot: groups.filter((group) => group.tagName === "tfoot").flatMap(rowsOf).map((row) => (cellsOf(row)[0] ? words(cellsOf(row)[0]) : "")),
50
+ merged: [header, ...rows].some((row) => row && cellsOf(row).some(spans)),
51
+ };
52
+ }
53
+
54
+ // The links a row's cells hold to documents of the workspace, as a file writes them (shared/page-address.mjs):
55
+ // another's ../<slug>/doc.html, with #<block id> for a block, and #<block id> for one of this document (`own`).
56
+ function linksOf(row, own) {
57
+ const links = [];
58
+ walk(row, (node) => {
59
+ if (node.tagName !== "a") return;
60
+ const href = (attr(node, "href") ?? "").trim();
61
+ if (!href) return;
62
+ const place = href.startsWith("#") && href.length > 1 ? (own ? { slug: own, block: decoded(href.slice(1)) } : null) : pageAddress(href);
63
+ if (place) links.push({ slug: place.slug, title: cellWords(textOf(node)), block: place.block ?? null });
64
+ });
65
+ return links;
66
+ }
67
+
68
+ /**
69
+ * The table of a document's `text` (its page's HTML, as its pages see it) that `key` names, the first
70
+ * frame carrying it as data-doc-chart-source (the one the kit and gallery check read; none a <template>
71
+ * holds, nor the own region of an instance), its rows as a block reads them: { columns, rows: [{ values,
72
+ * links, words }] }, `values` by the header's words (cellValue: a number, its words or null; of two names
73
+ * alike the later column's), `links` those its cells hold to documents (`own`: the document's slug, which
74
+ * a link within it names), `words` each column's words as written (what a filter matches); or { error }:
75
+ * "missing" (no table carries it) or "merged" (a cell spans others: a value has one cell).
76
+ */
77
+ export function keyedTable(text, key, own = null) {
78
+ let table = null;
79
+ walk(parse(String(text)), (node) => {
80
+ if (table !== null || attr(node, CHART_SOURCE) !== key) return;
81
+ table = node.tagName === "table" ? node : elementsOf(node).find((child) => child.tagName === "table") ?? false;
82
+ }, { ...BODY, inTemplates: false });
83
+ if (!table) return { error: "missing" };
84
+ const cells = tableCells(table);
85
+ const read = tableRows(cells);
86
+ if (read.error) return { error: "merged" };
87
+ const { header, rows } = tableParts(table);
88
+ const dataRows = header ? rows : rows.slice(1);
89
+ const dataCells = cells.names ? cells.rows : cells.rows.slice(1);
90
+ const names = read.data.columns;
91
+ return {
92
+ columns: [...names],
93
+ rows: read.data.map((values, at) => {
94
+ const words = {};
95
+ names.forEach((name, column) => {
96
+ words[name] = dataCells[at][column]?.words ?? "";
97
+ });
98
+ return { values: { ...values }, links: linksOf(dataRows[at], own), words };
99
+ }),
100
+ };
101
+ }
@@ -41,13 +41,19 @@ export const elementsOf = (node) => (node.childNodes ?? []).filter((child) => ch
41
41
  * Every element under `root`, in document order, handed to `visit`. What a template holds is part of
42
42
  * the page's markup (`inTemplates`, the default) or left out, as a browser's querySelectorAll does
43
43
  * (what is inert there). A template in an <svg> or <math> holds no content: its children are the page's.
44
- * `stop(element)`: what it says yes to is handed to `visit`, and what that holds is not.
44
+ * `stop(element)`: what it says yes to is handed to `visit`, and what that holds is not, but for
45
+ * the elements `through(element)` gives of it, whose insides the walk goes on in (themselves not handed
46
+ * to `visit`): an instance of a component package and its slots (components/index.mjs BODY).
45
47
  */
46
- export function walk(root, visit, { inTemplates = true, stop = null } = {}) {
48
+ export function walk(root, visit, { inTemplates = true, stop = null, through = null } = {}) {
49
+ const options = { inTemplates, stop, through };
47
50
  for (const child of elementsOf(root)) {
48
51
  visit(child);
49
- if (stop?.(child)) continue;
50
- if (!(child.tagName === "template" && child.content)) walk(child, visit, { inTemplates, stop });
51
- else if (inTemplates) walk(child.content, visit, { inTemplates, stop });
52
+ if (stop?.(child)) {
53
+ for (const inner of through?.(child) ?? []) walk(inner, visit, options);
54
+ continue;
55
+ }
56
+ if (!(child.tagName === "template" && child.content)) walk(child, visit, options);
57
+ else if (inTemplates) walk(child.content, visit, options);
52
58
  }
53
59
  }