@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
@@ -0,0 +1,432 @@
1
+ import { existsSync } from "node:fs";
2
+ import fs from "node:fs/promises";
3
+ import path from "node:path";
4
+ import { fileURLToPath } from "node:url";
5
+ import { descendantsIn, outlineAndFile, parentIn, placeIn, readOutline, withOutlineLock, writeOutline, writtenAs } from "./outline.mjs";
6
+ import { DOCS, GROUP_LIMITS, isForeign, isTop, newGroupId, topIn, topOf } from "./outline-shape.mjs";
7
+ import { findPreviewServer } from "./preview-server.mjs";
8
+ import { idsOf, shownIcon } from "./workspace-columns.mjs";
9
+ import { nameStops, workspaceLabels, workspaceName } from "./workspace-name.mjs";
10
+ import { isWorkspace, readRegistry, workspaceId, workspaceKey } from "./workspace-registry.mjs";
11
+ import { defaultWorkspace, documentFiles, isSlugName, listDocumentSlugs } from "./workspace.mjs";
12
+
13
+ // The drafts of other workspaces in a workspace's sidebar (notes/plans/workspaces-links-plan-2026-11-08.md
14
+ // §2.2, §2.5, §7.2; docs/workbench.md "Drafts of other workspaces"): an entry of the outline written
15
+ // "~<ws id>/<slug>" (./outline-shape.mjs), the workspace's id its path's hash on the machine's registry
16
+ // (./workspace-registry.mjs), the draft its document <root>/<slug>/doc.html there. Only where the sidebar
17
+ // shows it is this workspace's to keep: the draft's folder never moves, and its own workspace's tree is
18
+ // never written (its server shows it as it was). Every registered workspace has a column of its own
19
+ // (./workspace-columns.mjs, ./outline.mjs), "whole" (all its documents) unless the user picked a document
20
+ // of it in 添加其他 Gallery 项目… (POST draft-add) while it had none shown: then it is `picked`, holding that
21
+ // document and those under it alone, and what an Agent makes or opens there later (gallery new, gallery
22
+ // open in another workspace than the default one: joinDefaultTree). The column the user removed is
23
+ // `hidden`; an Agent's gallery new or open there, or the user's pick, shows it again. A draft the user took
24
+ // out of a whole column (从文档树移除) is in its `left`, not filled in again until it is put back here.
25
+ // A draft whose workspace is not on the registry, two registered folders sharing its id (six hex digits
26
+ // of a hash: a clash is refused, never guessed), or whose folder is gone stays in the tree, shown grey
27
+ // (找不到底稿) until the user removes it. Reads other workspaces' files only; writes this one's outline.
28
+
29
+ /** A draft's entry in the outline. */
30
+ export const DRAFT_ENTRY = /^~(ws-[0-9a-f]{6})\/([a-z0-9]+(?:-[a-z0-9]+)*)$/;
31
+ export const draftEntry = (id, slug) => `~${id}/${slug}`;
32
+ /** The workspace's id and the slug a draft's entry names, or null for an entry that names none. */
33
+ export function draftOf(entry) {
34
+ const match = DRAFT_ENTRY.exec(String(entry ?? ""));
35
+ return match ? { ws: match[1], slug: match[2] } : null;
36
+ }
37
+
38
+ const oneLine = (value) => (typeof value === "string" ? value.replace(/\s+/g, " ").trim() : "");
39
+ const exists = (target) => fs.access(target).then(() => true, () => false);
40
+
41
+ /**
42
+ * The registered workspaces by their ids: a Map of id to the roots registered under it (two for one id:
43
+ * a clash of the hash's six digits, which names neither: workspaceOf). `registry`: readRegistry()'s.
44
+ */
45
+ export const registeredIds = (registry = readRegistry()) => idsOf(registry);
46
+
47
+ /**
48
+ * The workspace `id` names on the registry: { root }, or { refused: "unknown" (no registered workspace
49
+ * of that id: forgotten, or never registered) | "ambiguous" (two registered folders share it), roots }.
50
+ */
51
+ export function workspaceOf(id, ids = registeredIds()) {
52
+ const roots = ids.get(id) ?? [];
53
+ if (roots.length === 1) return { root: roots[0] };
54
+ return { refused: roots.length ? "ambiguous" : "unknown", roots };
55
+ }
56
+
57
+ /** The ids two or more registered folders share: [{ id, roots }] (gallery workspaces and the sidebar say so). */
58
+ export const clashingIds = (ids = registeredIds()) => [...ids].filter(([, roots]) => roots.length > 1).map(([id, roots]) => ({ id, roots }));
59
+
60
+ /** Whether a draft's doc.json says it is a document (not the 写作偏好 page of an old layout), and what it says. */
61
+ async function metadataAt(folder) {
62
+ const files = documentFiles(folder);
63
+ const [html, metadata] = await Promise.all([exists(files.html), fs.readFile(files.json, "utf8").then((text) => JSON.parse(text.replace(/^/, "")), () => null)]);
64
+ return { files, html, metadata: metadata && typeof metadata === "object" && !Array.isArray(metadata) ? metadata : null };
65
+ }
66
+
67
+ /**
68
+ * What the sidebar shows of draft `entry`: { entry, ws, slug, root (null: no workspace of that id),
69
+ * folder, path (its doc.html, or an old one's report.html), title, description, icon, missing: null, or
70
+ * why it is shown grey: "workspace" (none of that id on the registry, or its folder gone), "ambiguous"
71
+ * (two of that id), "draft" (its document is gone) }.
72
+ */
73
+ export async function draftFacts(entry, ids = registeredIds()) {
74
+ const { ws, slug } = draftOf(entry) ?? { ws: "", slug: entry };
75
+ const found = workspaceOf(ws, ids);
76
+ const none = { entry, ws, slug, root: null, folder: null, path: null, title: slug, description: "", icon: null };
77
+ if (!found.root) return { ...none, missing: found.refused === "ambiguous" ? "ambiguous" : "workspace" };
78
+ const folder = path.join(found.root, slug);
79
+ const { files, html, metadata } = await metadataAt(folder);
80
+ const missing = !isWorkspace(found.root) ? "workspace" : !html || metadata?.instructions === true ? "draft" : null;
81
+ // An untitled document says so (its title empty: the workbench names it 未命名文档); one with no doc.json to read, its slug.
82
+ return { entry, ws, slug, root: found.root, folder, path: files.html, title: typeof metadata?.title === "string" ? oneLine(metadata.title) : slug, description: oneLine(metadata?.description), icon: shownIcon(metadata?.icon), missing };
83
+ }
84
+
85
+ /**
86
+ * The names the sidebar calls the registered workspaces by: a Map of id to { name, above, upper, root,
87
+ * there }, for the ids `wanted`. `above` is what tells it apart from another of `among` (ids: those shown
88
+ * side by side, the sidebar's columns or the list of 添加其他 Gallery 项目…; `wanted` when none is given) that has
89
+ * its name (./workspace-name.mjs workspaceLabels), else null: never a workspace of the machine that is not
90
+ * shown. `upper`: the name of the folder above the one named (null at a drive's root), which the sidebar
91
+ * shows when a column of another kind has the name. `stops`: nameStops()'s (asked once by a server: it
92
+ * reads Windows' registry).
93
+ */
94
+ export function workspaceNames(wanted, { ids = registeredIds(), stops = nameStops(), among = wanted } = {}) {
95
+ const named = [...ids].filter(([id, roots]) => roots.length === 1 && (wanted.has(id) || among.has(id))).map(([id, [root]]) => ({ id, root, ...workspaceName(root, { stops }) }));
96
+ const compared = named.filter((entry) => among.has(entry.id));
97
+ const labels = new Map(workspaceLabels(compared).map((label, index) => [compared[index].id, label]));
98
+ const names = new Map();
99
+ for (const entry of named) {
100
+ if (wanted.has(entry.id)) names.set(entry.id, { name: entry.name, above: labels.get(entry.id)?.above ?? null, upper: entry.above, root: entry.root, there: isWorkspace(entry.root) });
101
+ }
102
+ return names;
103
+ }
104
+
105
+ /**
106
+ * What a path the user pasted or picked (添加其他 Gallery 项目…) names: a workspace's folder, a document's
107
+ * doc.html (an old one's report.html) or its folder; a file:// address of one too, and quotes around it are
108
+ * taken away. One of: { kind: "workspace", root } (a folder holding Gallery's gallery.json);
109
+ * { kind: "draft", folder, slug, root (the workspace it is in: the nearest folder up holding Gallery's
110
+ * gallery.json; null for none, `parent` then the folder that would become one) }; { kind: "folder", folder }
111
+ * (a folder that is no workspace yet but holds Gallery documents: the one that would become a workspace);
112
+ * { kind: "missing" } (nothing there, or not an absolute path); { kind: "plain" } (an HTML file, or a folder
113
+ * that is no Gallery draft, workspace or folder of documents); { kind: "nested", root } (a draft that is not
114
+ * right in its workspace: the trash's, the 写作偏好 page's); { kind: "name" } (a folder whose name is no slug).
115
+ */
116
+ export async function findDraft(written) {
117
+ let target = String(written ?? "").trim().replace(/^["']+|["']+$/g, "");
118
+ if (/^file:\/\//i.test(target)) {
119
+ try {
120
+ target = fileURLToPath(target);
121
+ } catch {
122
+ return { kind: "missing", path: target };
123
+ }
124
+ }
125
+ if (!target || !path.isAbsolute(target)) return { kind: "missing", path: target };
126
+ target = path.resolve(target);
127
+ const stat = await fs.stat(target).catch(() => null);
128
+ if (!stat) return { kind: "missing", path: target };
129
+ let folder;
130
+ if (stat.isDirectory()) folder = target;
131
+ else if (/^(doc|report)\.html$/i.test(path.basename(target))) folder = path.dirname(target);
132
+ else return { kind: "plain", path: target };
133
+ if (stat.isDirectory() && isWorkspace(folder)) return { kind: "workspace", path: target, root: folder };
134
+ const { files, html, metadata } = await metadataAt(folder);
135
+ if (stat.isDirectory() && !html && (await listDocumentSlugs(folder).catch(() => [])).some(isSlugName)) return { kind: "folder", path: target, folder };
136
+ if (!html || (!files.old && !metadata) || metadata?.instructions === true) return { kind: "plain", path: target };
137
+ let root = null;
138
+ for (let directory = path.dirname(folder); ; directory = path.dirname(directory)) {
139
+ if (isWorkspace(directory)) {
140
+ root = directory;
141
+ break;
142
+ }
143
+ if (path.dirname(directory) === directory) break;
144
+ }
145
+ const slug = path.basename(folder);
146
+ if (root && workspaceKey(path.dirname(folder)) !== workspaceKey(root)) return { kind: "nested", path: target, root };
147
+ if (!isSlugName(slug)) return { kind: "name", path: target };
148
+ return { kind: "draft", path: files.html, folder, slug, root, parent: path.dirname(folder) };
149
+ }
150
+
151
+ /**
152
+ * The column of workspace `id` in `outline` (changed in place): the one that has `workspace: id`; with none
153
+ * (a workspace the sidebar does not show as it was read: the outline of a workspace's own tree, or past 50
154
+ * columns), one made right after the column `after` (an id; none: last), picked (`picked`) or whole, or null
155
+ * where no column can be made (50 already: the entry goes to the own column's top).
156
+ */
157
+ function columnFor(outline, id, { after = null, picked = false } = {}) {
158
+ let group = outline.groups.find((each) => each.workspace === id);
159
+ if (group) return group;
160
+ if (outline.groups.length >= GROUP_LIMITS.groups) return null;
161
+ group = { id: outline.groups.some((each) => each.id === id) ? newGroupId(outline.groups) : id, workspace: id, ...(picked ? { picked: true } : {}) };
162
+ const at = outline.groups.findIndex((each) => each.id === after);
163
+ outline.groups = at < 0 ? [...outline.groups, group] : [...outline.groups.slice(0, at + 1), group, ...outline.groups.slice(at + 1)];
164
+ outline.children[topOf(group.id)] ??= [];
165
+ return group;
166
+ }
167
+
168
+ /** `outline`'s column `id` (changed in place: its object replaced) as `change(column)` gives it, at index `to` when given. */
169
+ function changeColumn(outline, id, change, to = null) {
170
+ const groups = outline.groups.filter((each) => each.id !== id);
171
+ const at = outline.groups.findIndex((each) => each.id === id);
172
+ const next = change(outline.groups[at]);
173
+ groups.splice(to === null ? at : Math.min(to, groups.length), 0, next);
174
+ outline.groups = groups;
175
+ return next;
176
+ }
177
+
178
+ /** `outline`'s column `id` moved right after column `after` (one of it; none, or itself: where it is). */
179
+ function moveAfter(outline, id, after) {
180
+ if (!after || after === id || !outline.groups.some((each) => each.id === after)) return;
181
+ const groups = outline.groups.filter((each) => each.id !== id);
182
+ groups.splice(groups.findIndex((each) => each.id === after) + 1, 0, outline.groups.find((each) => each.id === id));
183
+ outline.groups = groups;
184
+ }
185
+
186
+ const shownColumn = ({ hidden, ...column }) => column;
187
+
188
+ /**
189
+ * Draft `slug` of workspace `draftRoot` put in the sidebar of workspace `treeRoot` (its outline, under the
190
+ * outline's lock; `changed()` once it is written), with the drafts under it in its own workspace's tree
191
+ * (documents: a web link of that workspace is none, nor a draft of a third its tree shows, the drafts under
192
+ * one going under the draft above it), those the tree does not hold yet. Its workspace's column is shown
193
+ * again when the user had removed it (hidden). How, `pick` says:
194
+ * - false (an Agent's gallery new or open there: joinDefaultTree, POST draft-join): one the outline holds
195
+ * (the file, or a whole column as it is read) stays where it is; else (a picked column) under its own
196
+ * parent's entry when the tree holds that, else last in its workspace's column;
197
+ * - true (the user's pick in 添加其他 Gallery 项目…, `after`: the column whose menu it came from): one shown
198
+ * in the sidebar already stays where it is (revealed, `existing`); its workspace's column hidden, or one the
199
+ * sidebar showed not before (`fresh`: its workspace registered just now, its column made only as the outline
200
+ * is read, filled whole), it is made a picked one holding it and those under it alone, right after `after`;
201
+ * one shown picked or whole takes it (under its own parent's entry, else last: one the user had taken out of
202
+ * a whole one); with none, a picked column is made right after `after`.
203
+ * Either way, what is put in a whole column is in its `left` no more.
204
+ * Resolves to { entry, existing: whether the file held it, so that nothing was put in, parent, added: the
205
+ * entries put in, column: the id of the column it is in, under: the entry it is under, or null, shown: whether
206
+ * the column was shown again }.
207
+ */
208
+ export async function addDraft(treeRoot, draftRoot, slug, { changed = () => {}, pick = false, after = null, fresh = false } = {}) {
209
+ const id = workspaceId(draftRoot);
210
+ const entry = draftEntry(id, slug);
211
+ const own = await readOutline(draftRoot, { others: false }).catch(() => ({ children: {}, links: [] })); // its own tree, read alone
212
+ // No document of that workspace: its web links, and the drafts of others its tree shows (~<ws id>/<slug>).
213
+ const none = (key) => own.links.includes(key) || isForeign(key);
214
+ const ownParent = (child) => {
215
+ let up = parentIn(own.children, child);
216
+ while (up !== null && !isTop(up) && none(up)) up = parentIn(own.children, up);
217
+ return up === null || isTop(up) ? null : up;
218
+ };
219
+ return withOutlineLock(treeRoot, async () => {
220
+ const { outline, stored } = await outlineAndFile(treeRoot);
221
+ const holds = (key) => Object.values(outline.children).some((list) => list.includes(key));
222
+ const storedHolds = Object.values(stored?.children ?? {}).some((list) => list.includes(entry));
223
+ const where = () => {
224
+ const parent = parentIn(outline.children, entry);
225
+ const top = topIn(outline.children, entry);
226
+ return { parent, column: top === null || top === "" ? DOCS : top.slice(1), under: parent !== null && !isTop(parent) ? parent : null };
227
+ };
228
+ const columnOf = (key) => outline.groups.find((each) => topOf(each.id) === topIn(outline.children, key)) ?? null;
229
+ let shown = false;
230
+ let column = outline.groups.find((each) => each.workspace === id) ?? null;
231
+ const put = () => {
232
+ const added = [];
233
+ const top = column ? topOf(column.id) : topOf(DOCS);
234
+ const above = ownParent(slug);
235
+ placeIn(outline, entry, above !== null && holds(draftEntry(id, above)) ? draftEntry(id, above) : top);
236
+ added.push(entry);
237
+ for (const child of descendantsIn(own.children, slug)) {
238
+ const childEntry = draftEntry(id, child);
239
+ if (none(child) || holds(childEntry)) continue;
240
+ placeIn(outline, childEntry, draftEntry(id, ownParent(child) ?? slug));
241
+ added.push(childEntry);
242
+ }
243
+ // Put in again: taken out of a whole column no more.
244
+ if (column?.left) {
245
+ const back = new Set(added.map((each) => draftOf(each).slug));
246
+ column = changeColumn(outline, column.id, ({ left, ...rest }) => {
247
+ const still = left.filter((taken) => !back.has(taken));
248
+ return still.length ? { ...rest, left: still } : rest;
249
+ });
250
+ }
251
+ return added;
252
+ };
253
+ let added = [];
254
+ let existing = false;
255
+ if (!pick) {
256
+ if (column?.hidden) {
257
+ column = changeColumn(outline, column.id, shownColumn);
258
+ shown = true;
259
+ }
260
+ existing = storedHolds;
261
+ if (!holds(entry)) {
262
+ column ??= columnFor(outline, id);
263
+ added = put();
264
+ } else if (!storedHolds) added = [entry];
265
+ } else {
266
+ // A column the file holds not, of a workspace the sidebar showed not before: made as it was read, whole.
267
+ const madeNow = Boolean(column) && fresh && !(stored?.groups ?? []).some((each) => each.workspace === id);
268
+ const at = columnOf(entry);
269
+ const there = holds(entry) && !at?.hidden && !(madeNow && at?.id === column.id);
270
+ if (there) existing = true;
271
+ else if (column?.hidden || madeNow) {
272
+ // Made a picked column holding it and those under it alone, shown, right after `after`.
273
+ const top = topOf(column.id);
274
+ for (const key of descendantsIn(outline.children, top)) delete outline.children[key];
275
+ outline.children[top] = [];
276
+ shown = Boolean(column.hidden);
277
+ column = changeColumn(outline, column.id, ({ left: _left, ...each }) => ({ ...shownColumn(each), picked: true }));
278
+ moveAfter(outline, column.id, after);
279
+ added = put();
280
+ } else {
281
+ column ??= columnFor(outline, id, { after, picked: true });
282
+ added = put();
283
+ }
284
+ }
285
+ if (!writtenAs(outline, stored)) {
286
+ await writeOutline(treeRoot, outline);
287
+ changed();
288
+ }
289
+ return { entry, existing, added, shown, ...where() };
290
+ });
291
+ }
292
+
293
+ /**
294
+ * Workspace `otherRoot` shown whole in the sidebar of workspace `treeRoot` (添加其他 Gallery 项目… with a
295
+ * workspace: its outline, under the outline's lock; `changed()` once it is written): its column (made when
296
+ * there is none) shown, whole (all its documents, those the user had taken out of it too: those no column
297
+ * holds come as the outline is read), right after the column `after` (an id). Resolves to { column: its id,
298
+ * moved, shown, whole: whether each changed }.
299
+ */
300
+ export async function addWorkspace(treeRoot, otherRoot, { changed = () => {}, after = null } = {}) {
301
+ const id = workspaceId(otherRoot);
302
+ return withOutlineLock(treeRoot, async () => {
303
+ const { outline, stored } = await outlineAndFile(treeRoot);
304
+ let column = columnFor(outline, id, { after });
305
+ if (!column) return { column: null, moved: false, shown: false, whole: false };
306
+ const shown = Boolean(column.hidden);
307
+ const whole = Boolean(column.picked || column.left);
308
+ // Whole: all its documents, those the user took out of it before too (its `left` gone).
309
+ column = changeColumn(outline, column.id, ({ picked: _picked, left: _left, ...each }) => shownColumn(each));
310
+ const before = outline.groups.findIndex((each) => each.id === column.id);
311
+ moveAfter(outline, column.id, after);
312
+ const moved = outline.groups.findIndex((each) => each.id === column.id) !== before;
313
+ if (!writtenAs(outline, stored)) {
314
+ await writeOutline(treeRoot, outline);
315
+ changed();
316
+ }
317
+ return { column: column.id, moved, shown, whole };
318
+ });
319
+ }
320
+
321
+ /**
322
+ * The other registered workspaces (but `treeRoot`'s own), for 添加其他 Gallery 项目…'s list: [{ ws, root, name,
323
+ * above, documents: [{ entry, slug, title, icon, path, depth }] }], each workspace's documents in the order
324
+ * its own sidebar has them (depth: how deep under others there), those whose folder is no workspace now left
325
+ * out, a clash of ids too (refused, never guessed), the one used last first. Reads files only: nothing of
326
+ * another workspace is written (its 写作偏好 page is no draft).
327
+ */
328
+ export async function projectChoices(treeRoot, { ids = registeredIds(), stops = nameStops(), registry = readRegistry() } = {}) {
329
+ const seen = new Map(registry.workspaces.map(({ root, seen: at }) => [workspaceKey(root), Date.parse(at)]));
330
+ const wanted = new Set([...ids].filter(([, roots]) => roots.length === 1 && workspaceKey(roots[0]) !== workspaceKey(treeRoot)).map(([id]) => id));
331
+ const names = workspaceNames(wanted, { ids, stops });
332
+ const found = await Promise.all([...names].filter(([, { there }]) => there).map(async ([id, { name, above, root }]) => {
333
+ const tree = await readOutline(root, { others: false }).catch(() => null);
334
+ const documents = [];
335
+ const isDocument = (slug) => !(tree?.links ?? []).includes(slug) && !isForeign(slug) && isSlugName(slug);
336
+ const walk = (key, depth) => (tree?.children[key] ?? []).forEach((slug) => {
337
+ const document = isDocument(slug);
338
+ if (document) documents.push({ slug, depth });
339
+ walk(slug, document ? depth + 1 : depth);
340
+ });
341
+ for (const { id: column } of tree?.groups ?? []) walk(topOf(column), 0);
342
+ const listed = await Promise.all(documents.map(async ({ slug, depth }) => {
343
+ const { files, metadata } = await metadataAt(path.join(root, slug));
344
+ return { entry: draftEntry(id, slug), slug, title: oneLine(metadata?.title) || slug, icon: shownIcon(metadata?.icon), path: files.html, depth };
345
+ }));
346
+ return { ws: id, root, name, above, seen: seen.get(workspaceKey(root)) ?? 0, documents: listed };
347
+ }));
348
+ return found.sort((a, b) => b.seen - a.seen).map(({ seen: _seen, ...rest }) => rest);
349
+ }
350
+
351
+
352
+ /** The environment variable that keeps gallery new and gallery open from putting their draft in the default workspace's sidebar (the tests set it). */
353
+ export const NO_DEFAULT_TREE = "GALLERY_NO_DEFAULT_TREE";
354
+ const set = (value) => !["", "0", undefined].includes(value);
355
+
356
+ /**
357
+ * gallery new and gallery open in a workspace other than the default one (src/shared/workspace.mjs
358
+ * defaultWorkspace): draft `slug` of workspace `root` put in the default workspace's sidebar (addDraft,
359
+ * with the drafts under it), through the default workspace's server when one runs (POST
360
+ * /__gallery/workspace/draft-join: in its queue, its workbench told at once), else here under the
361
+ * outline's lock. Null where it is not done: NO_DEFAULT_TREE set, `root` the default workspace, no
362
+ * default workspace there yet (nothing is made for it), or `root` not on the registry under its id (a
363
+ * workspace in the system's temporary folder, or a clash of ids: an entry would name none). Else
364
+ * addDraft's answer with `home` (the default workspace) and `names`: { column: the name of the column
365
+ * it is in, under: the title of the draft it is under, or null }; or { failed: why } (nothing written).
366
+ */
367
+ export async function joinDefaultTree(root, slug, { env = process.env } = {}) {
368
+ if (set(env[NO_DEFAULT_TREE])) return null;
369
+ const home = defaultWorkspace({ env });
370
+ if (workspaceKey(home) === workspaceKey(root) || !isWorkspace(home)) return null;
371
+ const ids = registeredIds();
372
+ const found = workspaceOf(workspaceId(root), ids);
373
+ if (!found.root || workspaceKey(found.root) !== workspaceKey(root)) return null;
374
+ let done = null;
375
+ try {
376
+ const server = await findPreviewServer({ reportsDirectory: home });
377
+ if (server) done = await joinThrough(server, root, slug);
378
+ done ??= await addDraft(home, root, slug);
379
+ } catch (error) {
380
+ return { failed: error.message, home };
381
+ }
382
+ return { ...done, home, names: await placeNames(home, done, ids) };
383
+ }
384
+
385
+ // POST draft-join to the default workspace's server; null when no server of it takes it (gone, or an older Gallery's).
386
+ async function joinThrough(server, root, slug) {
387
+ const host = `127.0.0.1:${server.port}`;
388
+ try {
389
+ const response = await fetch(`http://${host}/__gallery/workspace/draft-join`, {
390
+ method: "POST",
391
+ headers: { "Content-Type": "application/json", Origin: `http://${host}`, "X-Gallery-Token": server.token },
392
+ body: JSON.stringify({ root, slug }),
393
+ signal: AbortSignal.timeout(30000),
394
+ });
395
+ const answer = await response.json().catch(() => null);
396
+ return answer?.ok === true && typeof answer.entry === "string" ? answer : null;
397
+ } catch {
398
+ return null;
399
+ }
400
+ }
401
+
402
+ // The names a line says of where a draft went: its column's (the user's title, else its workspace's
403
+ // name, else 默认文档, the default workspace's own column, or 链接) and the title of the draft or document it is under.
404
+ async function placeNames(home, { column, under }, ids) {
405
+ const { groups } = await readOutline(home);
406
+ const group = groups.find((each) => each.id === column);
407
+ let name = group?.title ?? null;
408
+ if (!name && group?.workspace) name = workspaceNames(new Set([group.workspace]), { ids }).get(group.workspace)?.name ?? null;
409
+ name ??= group?.role === "links" ? "链接" : group?.id === DOCS || !group ? "默认文档" : "未命名栏"; // its own column is the default workspace's
410
+ let above = null;
411
+ if (under) {
412
+ if (draftOf(under)) above = (await draftFacts(under, ids)).title;
413
+ else {
414
+ const metadata = await fs.readFile(documentFiles(path.join(home, under)).json, "utf8").then(JSON.parse, () => null);
415
+ above = oneLine(metadata?.title) || under;
416
+ }
417
+ }
418
+ return { column: name, under: above };
419
+ }
420
+
421
+ /** The line gallery new and gallery open print of joinDefaultTree's answer (null for none). */
422
+ export function joinedLine(joined) {
423
+ if (!joined) return null;
424
+ const where = `默认工作区(${joined.home})的侧边栏`;
425
+ if (joined.failed) return `${where}:没有加进去(${joined.failed})`;
426
+ if (joined.existing) return `${where}里已经有它(${joined.names.under ? `在「${joined.names.under}」下面` : `「${joined.names.column}」栏`})`;
427
+ const more = joined.added.length > 1 ? `,连同它下面的 ${joined.added.length - 1} 篇` : "";
428
+ return `${where}:已加进${joined.names.under ? `「${joined.names.under}」下面` : `「${joined.names.column}」栏`}${more}(拖动只改那里的显示位置,文件不动)`;
429
+ }
430
+
431
+ /** Whether a gallery.json at `folder` would be another program's or not readable (what draft-add refuses to make a workspace of). */
432
+ export const foreignMarker = (folder) => existsSync(path.join(folder, "gallery.json")) && !isWorkspace(folder);
@@ -0,0 +1,43 @@
1
+ ISC License
2
+
3
+ Copyright (c) 2026 Lucide Icons and Contributors
4
+
5
+ Permission to use, copy, modify, and/or distribute this software for any
6
+ purpose with or without fee is hereby granted, provided that the above
7
+ copyright notice and this permission notice appear in all copies.
8
+
9
+ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
10
+ WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
11
+ MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
12
+ ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
13
+ WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
14
+ ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
15
+ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
16
+
17
+ ---
18
+
19
+ The following Lucide icons are derived from the Feather project:
20
+
21
+ airplay, alert-circle, alert-octagon, alert-triangle, aperture, arrow-down-circle, arrow-down-left, arrow-down-right, arrow-down, arrow-left-circle, arrow-left, arrow-right-circle, arrow-right, arrow-up-circle, arrow-up-left, arrow-up-right, arrow-up, at-sign, calendar, cast, check, chevron-down, chevron-left, chevron-right, chevron-up, chevrons-down, chevrons-left, chevrons-right, chevrons-up, circle, clipboard, clock, code, columns, command, compass, corner-down-left, corner-down-right, corner-left-down, corner-left-up, corner-right-down, corner-right-up, corner-up-left, corner-up-right, crosshair, database, divide-circle, divide-square, dollar-sign, download, external-link, feather, frown, hash, headphones, help-circle, info, italic, key, layout, life-buoy, link-2, link, loader, lock, log-in, log-out, maximize, meh, minimize, minimize-2, minus-circle, minus-square, minus, monitor, moon, more-horizontal, more-vertical, move, music, navigation-2, navigation, octagon, pause-circle, percent, plus-circle, plus-square, plus, power, radio, rss, search, server, share, shopping-bag, sidebar, smartphone, smile, square, table-2, tablet, target, terminal, trash-2, trash, triangle, tv, type, upload, x-circle, x-octagon, x-square, x, zoom-in, zoom-out
22
+
23
+ The MIT License (MIT) (for the icons listed above)
24
+
25
+ Copyright (c) 2013-present Cole Bemis
26
+
27
+ Permission is hereby granted, free of charge, to any person obtaining a copy
28
+ of this software and associated documentation files (the "Software"), to deal
29
+ in the Software without restriction, including without limitation the rights
30
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
31
+ copies of the Software, and to permit persons to whom the Software is
32
+ furnished to do so, subject to the following conditions:
33
+
34
+ The above copyright notice and this permission notice shall be included in all
35
+ copies or substantial portions of the Software.
36
+
37
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
38
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
39
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
40
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
41
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
42
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
43
+ SOFTWARE.
@@ -1,6 +1,6 @@
1
1
  # Emoji and icon data
2
2
 
3
- The emoji data is taken as it is from notion-lite (`src/ui/emoji/data/`). Its scripts took it out of Notion's web bundle.
3
+ The emoji data is taken from notion-lite (`src/ui/emoji/data/`), without its flags (the Flags group). notion-lite's scripts took it out of Notion's web bundle.
4
4
 
5
5
  | File | What it holds |
6
6
  |---|---|
@@ -11,10 +11,12 @@ The emoji data is taken as it is from notion-lite (`src/ui/emoji/data/`). Its sc
11
11
  | `twemoji-svg.bin` | The Twemoji SVGs, end to end, gzip |
12
12
  | `names.json` | Each emoji's name, which a custom emoji's name may not take |
13
13
  | `icons.json` | The 图标 tab's icons: `{ sets, categories: [Chinese name], icons: [[Chinese name, MingCute name, Tabler name, MingCute SVG, Tabler SVG, category, search words]] }`, 443 pairs and Tabler's 40 numbers (their MingCute name and SVG `null`), in the tab's order (by category: the index into `categories`), each SVG drawn in `#COLOR` (the color it is shown in: `ICON_COLOR_VALUES` of `../icon-value.mjs`, the one table of the ten colors) |
14
- | `LICENSE-mingcute.txt`, `LICENSE-tabler.txt` | The two icon sets' licenses |
14
+ | `LICENSE-mingcute.txt`, `LICENSE-tabler.txt`, `LICENSE-lucide.txt` | The two icon sets' licenses, and Lucide's (the few line icons the workbench, the editor and the kit take from it: the sidebar's, the settings gear, the 写作偏好 book, a page with no icon) |
15
15
 
16
16
  Notion's sprite sheet is not taken. An emoji the pack lacks shows in the system's emoji font.
17
17
 
18
+ Since 2026-11 (the user's word) Notion's Flags group is taken out whole: its 269 emojis, and the three other ways `positions.json` wrote 🏳, 🏳‍🌈 and 🏴‍☠ (without the variation selector). None of them is in any file here (categories, positions, both keywords, the 807 names that named them), and the pack holds no picture of them. A one-off script took them out by codepoint (an emoji whose codepoints are a flag's, in every way written) and packed the pictures left again, end to end; `tests/unit/icons.mjs` holds that none is left and the pack's pieces tile it, so data taken from notion-lite again must have them taken out again. An emoji the pack lacks (a flag a document holds counts) shows in the system's emoji font; `/__gallery/edit/icon` draws it as an SVG holding its character.
19
+
18
20
  The emoji graphics are Twemoji, © Twitter, Inc and other contributors, licensed under CC-BY 4.0 (https://creativecommons.org/licenses/by/4.0/; https://github.com/twitter/twemoji).
19
21
 
20
22
  The icons are two open-source sets of filled icons, the 443 things both have one icon for (a reviewed one-to-one list of synonyms), and Tabler's 40 numbers (0–9 in a circle, a square, a rounded square and a hexagon), which MingCute has no series of, in 12 categories: