@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,14 @@
1
+ {
2
+ "id": "gallery/note",
3
+ "apiVersion": 1,
4
+ "version": "1.2.0",
5
+ "name": { "zh": "便签", "en": "Note" },
6
+ "description": { "zh": "几行随手记,在卡片上直接写,存在页面里", "en": "A few lines jotted down, typed on the card and kept in the page" },
7
+ "words": "bianqian note memo sticky 便签 笔记 随手记 记事",
8
+ "parts": {
9
+ "note": { "at": ":scope > script", "edit": "data" }
10
+ },
11
+ "runtime": { "generated": [":scope > .gallery-note-head", ":scope > .gallery-note-field"] },
12
+ "places": ["page"],
13
+ "card": { "sizes": [[4, 2], [2, 2], [4, 4]], "resize": true }
14
+ }
@@ -0,0 +1,3 @@
1
+ <div data-doc-component="gallery/note">
2
+ <script type="application/json">{"text":"周五前把季度报告发给王经理\n买牛奶、鸡蛋\n下周二下午三点 牙医"}</script>
3
+ </div>
@@ -0,0 +1,102 @@
1
+ // gallery/note (便签): a few lines of free text, kept in the instance's data part, a script of JSON,
2
+ // { "text": "…" }, and typed on the card itself, in a <textarea> the block draws over the whole card.
3
+ // The field is the kit's (DocKit.input): what the reader typed goes to the file once they are done with
4
+ // it, as they leave the field or press Ctrl+Enter (⌘Enter on a Mac; Enter alone is a new line), never
5
+ // while an input method composes, and never a value it holds already; Esc puts back what the file holds.
6
+ // Each of those is one context.editJSON, one undo step, the JSON written back on one line as it was. It
7
+ // draws from the part on every `source` (an Agent's write, an undo), the words the reader is typing kept
8
+ // where they are. Where nothing takes its writes (an export, a page that has not come to edit yet:
9
+ // context.canEdit() false) the field is read-only, and shows the same words. An empty note says 写点什么.
10
+ // Above the field its head, as the cards' heads are (the kit's card tokens): the chip, a note's picture,
11
+ // and its name, 便签, and its quiet meta, how many characters the field holds (its blanks not counted,
12
+ // said again as the reader types); nothing of it is written.
13
+
14
+ const WORDS = {
15
+ zh: { empty: "写点什么", label: "便签", count: (/** @type {number} */ count) => `${count} 字` },
16
+ en: { empty: "Write something", label: "Note", count: (/** @type {number} */ count) => `${count} ${count === 1 ? "character" : "characters"}` },
17
+ };
18
+
19
+ /** The language the page speaks: the UI's where Gallery says it (data-ge-language), else its lang's. */
20
+ function languageOf(/** @type {HTMLElement} */ root) {
21
+ const ui = root.getAttribute("data-ge-language");
22
+ return (ui !== null ? ui === "en" : /^en(?:-|$)/i.test(root.lang)) ? "en" : "zh";
23
+ }
24
+
25
+ /**
26
+ * The words a note's data holds (context.readJSON's): its `text`, "" where it has none yet; throws
27
+ * saying why for data that is no note, which the block does not draw over.
28
+ * @param {any} data
29
+ * @returns {string}
30
+ */
31
+ function textOf(data) {
32
+ if (data === null || typeof data !== "object" || Array.isArray(data)) throw new Error("its data is no object: a note holds { \"text\": \"…\" }");
33
+ if (data.text === undefined) return "";
34
+ if (typeof data.text !== "string") throw new Error("its text is no string");
35
+ return data.text;
36
+ }
37
+
38
+ /**
39
+ * The note made to hold `text`, one write (context.editJSON): what a reader's words, once they are done
40
+ * with the field, call, and the example too. Whether it was taken.
41
+ * @param {DocComponentContext} context
42
+ * @param {string} text
43
+ */
44
+ function writeNote(context, text) {
45
+ return context.editJSON("note", (data) => {
46
+ textOf(data);
47
+ data.text = text;
48
+ });
49
+ }
50
+
51
+ DocKit.component({
52
+ id: "gallery/note",
53
+ on: ["source", "editable"],
54
+ mount(host, context) {
55
+ const words = WORDS[languageOf(document.documentElement)];
56
+ const head = document.createElement("div");
57
+ head.className = "gallery-note-head";
58
+ head.setAttribute("aria-hidden", "true");
59
+ const chip = document.createElement("span");
60
+ chip.className = "gallery-note-chip";
61
+ chip.innerHTML = '<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.9" stroke-linecap="round" stroke-linejoin="round"><path d="M13 20l7-7M13 20v-6a1 1 0 0 1 1-1h6V6a2 2 0 0 0-2-2H6a2 2 0 0 0-2 2v12a2 2 0 0 0 2 2h7"/></svg>';
62
+ const title = document.createElement("span");
63
+ title.className = "gallery-note-title";
64
+ title.textContent = words.label;
65
+ // Its quiet meta at the head's end: how many characters the field holds (its blanks not counted), as the reader types too.
66
+ const meta = document.createElement("span");
67
+ meta.className = "gallery-note-meta";
68
+ head.append(chip, title, meta);
69
+ const field = document.createElement("textarea");
70
+ field.className = "gallery-note-field";
71
+ field.placeholder = words.empty;
72
+ field.spellcheck = false;
73
+ field.setAttribute("aria-label", words.label);
74
+ host.append(head, field);
75
+ const typed = DocKit.input(field, { signal: context.signal, commit: (value) => writeNote(context, value) });
76
+ const recount = () => {
77
+ const count = [...field.value.replace(/s+/g, "")].length;
78
+ const said = count > 0 ? words.count(count) : "";
79
+ if (meta.textContent !== said) meta.textContent = said;
80
+ };
81
+ field.addEventListener("input", recount);
82
+ context.signal?.addEventListener("abort", () => field.removeEventListener("input", recount), { once: true });
83
+ const draw = () => {
84
+ const data = context.readJSON("note");
85
+ if (data === undefined) return; // no JSON: the instance has failed, and Gallery shows what it holds
86
+ let text;
87
+ try {
88
+ text = textOf(data);
89
+ } catch (error) {
90
+ return context.fail(error);
91
+ }
92
+ field.readOnly = !context.canEdit();
93
+ typed.set(text);
94
+ recount();
95
+ };
96
+ draw();
97
+ return { update: draw };
98
+ },
99
+ example(host, context) {
100
+ writeNote(context, `${textOf(context.readJSON("note"))}\n再加一行`);
101
+ },
102
+ });
@@ -0,0 +1 @@
1
+ <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 240 120"><rect width="240" height="120" rx="8" fill="#f3f3f1"/><rect x="16.5" y="12.5" width="207" height="95" rx="12" fill="#ffffff" stroke="#e7e6e3"/><rect x="30" y="24" width="14" height="14" rx="4.5" fill="#ebf2fa"/><g transform="translate(32 26) scale(.4167)" fill="none" stroke="#2e7cd1" stroke-width="2.4" stroke-linecap="round" stroke-linejoin="round"><path d="M13 20l7-7M13 20v-6a1 1 0 0 1 1-1h6V6a2 2 0 0 0-2-2H6a2 2 0 0 0-2 2v12a2 2 0 0 0 2 2h7"/></g><rect x="50" y="28" width="24" height="6" rx="3" fill="#3b3a37"/><rect x="30" y="50" width="150" height="6" rx="3" fill="#7b7a76"/><rect x="30" y="62" width="118" height="6" rx="3" fill="#7b7a76"/><rect x="30" y="74" width="168" height="6" rx="3" fill="#7b7a76"/><rect x="30" y="86" width="92" height="6" rx="3" fill="#7b7a76"/><rect x="125" y="84" width="1.5" height="10" fill="#3b3a37"/></svg>
@@ -0,0 +1,76 @@
1
+ /* Every selector starts at the instance and goes down a step at a time (>), so that nothing here
2
+ reaches the rest of the page. In the kit's card tokens: its head (the chip and 便签, how many characters
3
+ it holds its quiet meta at the end), its end clear of the card's grip, and under it the field the script draws, the rest of the note's face: no border, no
4
+ fill and no ring of its own, its words in the page's font, its placeholder (写点什么) muted. On a custom
5
+ page it fills the card the board frames; where no card is around it (a document, as gallery block
6
+ check shows it) the instance frames itself, a few lines high. Light and dark. */
7
+ [data-doc-component="gallery/note"] {
8
+ display: flex;
9
+ flex-direction: column;
10
+ gap: var(--gallery-face-gap);
11
+ box-sizing: border-box;
12
+ padding: 14px 16px;
13
+ border: 1px solid var(--doc-border);
14
+ border-radius: var(--gallery-card-radius);
15
+ > .gallery-note-head {
16
+ display: flex;
17
+ align-items: center;
18
+ gap: 8px;
19
+ flex: none;
20
+ min-width: 0;
21
+ padding-inline-end: var(--gallery-grip-room, 0px);
22
+ }
23
+ > .gallery-note-head > .gallery-note-chip {
24
+ flex: none;
25
+ display: inline-flex;
26
+ align-items: center;
27
+ justify-content: center;
28
+ width: var(--gallery-chip-size);
29
+ height: var(--gallery-chip-size);
30
+ border-radius: var(--gallery-chip-radius);
31
+ background: var(--gallery-accent-soft);
32
+ color: var(--gallery-accent);
33
+ }
34
+ > .gallery-note-head > .gallery-note-chip > svg { width: var(--gallery-chip-icon); height: var(--gallery-chip-icon); }
35
+ > .gallery-note-head > .gallery-note-title {
36
+ flex: 1 1 auto;
37
+ min-width: 0;
38
+ overflow: hidden;
39
+ white-space: nowrap;
40
+ text-overflow: ellipsis;
41
+ font-size: var(--gallery-title-size);
42
+ line-height: var(--gallery-title-line);
43
+ font-weight: 600;
44
+ color: var(--gallery-text-strong);
45
+ }
46
+ > .gallery-note-head > .gallery-note-meta { flex: none; font-size: var(--gallery-meta-size); color: var(--doc-muted); white-space: nowrap; font-variant-numeric: tabular-nums; margin-inline-end: calc(-1 * var(--gallery-grip-room, 0px)); opacity: calc(1 - var(--gallery-grip-shown, 0)); transition: opacity .12s ease-out; }
47
+ > .gallery-note-field {
48
+ display: block;
49
+ flex: 1 1 auto;
50
+ box-sizing: border-box;
51
+ width: 100%;
52
+ min-height: 7.5em;
53
+ margin: 0;
54
+ padding: 0;
55
+ border: 0;
56
+ outline: 0;
57
+ resize: none;
58
+ background: transparent;
59
+ font: inherit;
60
+ font-size: 14px;
61
+ line-height: 1.65;
62
+ color: var(--gallery-text);
63
+ overflow-wrap: break-word;
64
+ scrollbar-width: thin;
65
+ }
66
+ > .gallery-note-field::placeholder { color: var(--doc-muted); opacity: .7; }
67
+ > .gallery-note-field:read-only { cursor: default; }
68
+ }
69
+ /* On a custom page the board draws the frame: the note is as high as what the card holds inside it. */
70
+ .gallery-card > [data-doc-component="gallery/note"] {
71
+ height: 100%;
72
+ padding: 0;
73
+ border: 0;
74
+ border-radius: 0;
75
+ > .gallery-note-field { min-height: 0; }
76
+ }
@@ -0,0 +1,3 @@
1
+ <div data-doc-component="gallery/note">
2
+ <script type="application/json">{"text":""}</script>
3
+ </div>
@@ -0,0 +1,18 @@
1
+ # 便签 (gallery/note)
2
+
3
+ A card for a custom page (its places are `page`): a few lines the user types on the card itself, kept in the page. Use it where the user wants to jot something down beside the rest of a page (a reminder, a list for today).
4
+
5
+ ## How to write it
6
+
7
+ Put it on a custom page as a card of its board, `<section class="gallery-card" data-card-id="…" data-x data-y data-w data-h>`, holding one instance, after `gallery block add note`, the instance as template.html has it: its data part, a `<script type="application/json">` holding `{"text":"…"}` (on one line and compact, as the block writes it back), the note's words, lines apart with `\n`; `{"text":""}` for an empty one, which shows 写点什么.
8
+
9
+ - Leave the words of a note that is there alone: they are the user's. To start one with words of yours (a list the user asked for), write them in `text`, as example.html does.
10
+ - Sizes: 4 × 2 (the default), 2 × 2 and 4 × 4. Words that do not fit scroll inside the card.
11
+
12
+ ## What the user does
13
+
14
+ They click the card and type. What they typed is written to the page once they leave the card, or press Ctrl+Enter (⌘Enter on a Mac); Enter alone starts a new line, and Esc puts back what was there. Each write is one step of the page's undo. Nothing is written while a Chinese input method is composing.
15
+
16
+ ## How it looks
17
+
18
+ Its head (a chip and 便签, how many characters it holds at its end) at the top, the words filling the rest of the card, in the page's font, with no frame of their own (the board draws the card's), 写点什么 muted where there are none; in the kit's card tokens (as every Gallery card: a head of a tinted chip and a title, its end clear of the card's grip), light and dark. Where nothing can be written (an export) it shows the same words, read-only. The script runs with the rights of the page's own scripts, as any block's does.
@@ -0,0 +1,8 @@
1
+ {
2
+ "id": "gallery",
3
+ "name": { "zh": "Gallery 风格", "en": "Gallery style" },
4
+ "description": { "zh": "Gallery 自己的样子:克制、清楚的首页卡片,以及文档里用的看板、指标、图表、卡片和图表卡。", "en": "Gallery's own look: quiet, clear cards for the home page, and the board, metric, chart, card and chart card for documents." },
5
+ "version": "1.0.0",
6
+ "author": "Gallery",
7
+ "icon": "🗂️"
8
+ }
@@ -0,0 +1,13 @@
1
+ {
2
+ "id": "gallery/recent",
3
+ "apiVersion": 1,
4
+ "version": "1.3.0",
5
+ "name": { "zh": "最近编辑", "en": "Recently edited" },
6
+ "description": { "zh": "最近改过的文档,点一篇就打开它", "en": "The documents edited last: click one to open it" },
7
+ "words": "zuijinbianji zuijin bianji recent recently edited documents 最近 最近编辑 文档 改过",
8
+ "parts": {},
9
+ "runtime": { "generated": [":scope > .gallery-recent-face"] },
10
+ "places": ["page"],
11
+ "card": { "sizes": [[4, 5], [4, 2], [4, 4], [4, 6]], "resize": true },
12
+ "needs": ["workspace"]
13
+ }
@@ -0,0 +1 @@
1
+ <div data-doc-component="gallery/recent"></div>
@@ -0,0 +1,238 @@
1
+ // gallery/recent (最近编辑): the workspace's documents edited last, the last first, read through
2
+ // context.workspace.query("recent") (its manifest's needs hold "workspace"): each its page icon, its title
3
+ // and when it was edited, said as a person says it (刚刚, 5 分钟前, 昨天, 11月2日), which moves on by itself
4
+ // (the kit's clock, each minute). A click opens the document (context.workspace.open: the workbench goes
5
+ // there). It reads again whenever the workspace says the list changed (the `data` signal, "recent": a
6
+ // document written, renamed, given another icon, made or gone). It holds no part and writes nothing: all
7
+ // it shows is drawn (the manifest's `runtime`). Where the workspace cannot be read (an exported file,
8
+ // where it has no server; a server that does not answer) it says so in a line. The words are the page's
9
+ // language (the UI's where Gallery says it, else the page's lang). Its head is the cards' (the kit's card
10
+ // tokens): the chip, a clock, before its title, how many of those listed were edited today its quiet meta
11
+ // at the end (今天 3 篇, said again with the times). The list shows whole rows only: as many as fit what the
12
+ // card has under its head (`fit`, its height a whole number of rows; the rest of the room under it), a
13
+ // muted line under them saying how many more are below (还有 3 篇), counted again as the list scrolls or the
14
+ // card changes size (its own ResizeObserver on the face) and gone at its end.
15
+ //
16
+ // A document's icon is drawn as Gallery's sidebar draws it, from the server that shows the page (its icon
17
+ // route, /__gallery/edit/icon, one picture of any icon's value): an emoji or a picture of its folder as a
18
+ // picture, one of Gallery's glyphs as a mask in the muted color, which follows the theme; a document with
19
+ // none a page drawn in its line.
20
+
21
+ const WORDS = {
22
+ zh: {
23
+ title: "最近编辑",
24
+ empty: "还没有文档",
25
+ offline: "在 Gallery 里打开时,这里列出最近改过的文档",
26
+ failed: "读不到工作区的文档",
27
+ more: (/** @type {number} */ count) => `还有 ${count} 篇`,
28
+ today: (/** @type {number} */ count) => `今天 ${count} 篇`,
29
+ open: (/** @type {string} */ title) => `打开「${title}」`,
30
+ now: "刚刚",
31
+ minutes: (/** @type {number} */ count) => `${count} 分钟前`,
32
+ hours: (/** @type {number} */ count) => `${count} 小时前`,
33
+ yesterday: "昨天",
34
+ days: (/** @type {number} */ count) => `${count} 天前`,
35
+ date: (/** @type {Date} */ date, /** @type {boolean} */ thisYear) => (thisYear ? `${date.getMonth() + 1}月${date.getDate()}日` : `${date.getFullYear()}年${date.getMonth() + 1}月${date.getDate()}日`),
36
+ },
37
+ en: {
38
+ title: "Recently edited",
39
+ empty: "No documents yet",
40
+ offline: "Opened in Gallery, this lists the documents edited last",
41
+ failed: "The workspace's documents could not be read",
42
+ more: (/** @type {number} */ count) => `${count} more`,
43
+ today: (/** @type {number} */ count) => `${count} today`,
44
+ open: (/** @type {string} */ title) => `Open “${title}”`,
45
+ now: "just now",
46
+ minutes: (/** @type {number} */ count) => `${count} min ago`,
47
+ hours: (/** @type {number} */ count) => `${count} h ago`,
48
+ yesterday: "yesterday",
49
+ days: (/** @type {number} */ count) => `${count} days ago`,
50
+ date: (/** @type {Date} */ date, /** @type {boolean} */ thisYear) => `${["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"][date.getMonth()]} ${date.getDate()}${thisYear ? "" : `, ${date.getFullYear()}`}`,
51
+ },
52
+ };
53
+
54
+ /** The language the page speaks: the UI's where Gallery says it (data-ge-language), else its lang's. */
55
+ function languageOf(/** @type {HTMLElement} */ root) {
56
+ const ui = root.getAttribute("data-ge-language");
57
+ return (ui !== null ? ui === "en" : /^en(?:-|$)/i.test(root.lang)) ? "en" : "zh";
58
+ }
59
+
60
+ /**
61
+ * When `edited` (an ISO time) was, from `now` (the reader's clock), as a person says it: within a minute
62
+ * 刚刚, then minutes, then hours (the same day, or within 6 hours of it), 昨天 for the day before, days
63
+ * within the week, else the date (the year said when it is another).
64
+ * @param {string} edited
65
+ * @param {Date} now
66
+ * @param {"zh" | "en"} language
67
+ */
68
+ function whenOf(edited, now, language) {
69
+ const words = WORDS[language];
70
+ const then = new Date(edited);
71
+ const minutes = Math.floor((now.getTime() - then.getTime()) / 60_000);
72
+ if (!Number.isFinite(minutes)) return "";
73
+ if (minutes < 1) return words.now;
74
+ if (minutes < 60) return words.minutes(minutes);
75
+ const day = (/** @type {Date} */ date) => Date.UTC(date.getFullYear(), date.getMonth(), date.getDate()) / 86_400_000;
76
+ const days = day(now) - day(then);
77
+ if (days === 0 || minutes < 360) return words.hours(Math.floor(minutes / 60));
78
+ if (days === 1) return words.yesterday;
79
+ if (days < 7) return words.days(days);
80
+ return words.date(then, then.getFullYear() === now.getFullYear());
81
+ }
82
+
83
+ /** What a document's icon is, as Gallery writes its value: a glyph (/icons/…), a picture of its folder (assets/…), an emoji, or none. @param {string | null} value */
84
+ function iconKindOf(value) {
85
+ if (typeof value !== "string" || !value) return null;
86
+ if (value.startsWith("/icons/")) return "glyph";
87
+ if (value.startsWith("assets/")) return "image";
88
+ return "emoji";
89
+ }
90
+
91
+ /**
92
+ * An element of the face, of `kind` (its class).
93
+ * @template {keyof HTMLElementTagNameMap} K
94
+ * @param {K} tag
95
+ * @param {string} kind
96
+ * @param {string} [text]
97
+ */
98
+ function made(tag, kind, text) {
99
+ const node = document.createElement(tag);
100
+ node.className = `gallery-recent-${kind}`;
101
+ if (text !== undefined) node.textContent = text;
102
+ return node;
103
+ }
104
+
105
+ // A document's icon: its picture from the server's icon route, a glyph masked, or none (the page CSS draws).
106
+ function iconFor(/** @type {string} */ slug, /** @type {string | null} */ value) {
107
+ const kind = iconKindOf(value);
108
+ const icon = made("span", "icon");
109
+ if (!kind || value === null) return icon;
110
+ const address = `/__gallery/edit/icon?value=${encodeURIComponent(value)}&slug=${encodeURIComponent(slug)}`;
111
+ if (kind === "glyph") {
112
+ icon.classList.add("gallery-recent-glyph");
113
+ icon.style.setProperty("--gallery-recent-icon", `url("${address}")`);
114
+ return icon;
115
+ }
116
+ const picture = document.createElement("img");
117
+ picture.alt = "";
118
+ picture.src = address;
119
+ picture.decoding = "async";
120
+ icon.classList.add("gallery-recent-picture");
121
+ icon.append(picture);
122
+ return icon;
123
+ }
124
+
125
+ DocKit.component({
126
+ id: "gallery/recent",
127
+ on: ["data", "clock"],
128
+ mount(host, context) {
129
+ const language = languageOf(document.documentElement);
130
+ const words = WORDS[language];
131
+ const face = made("div", "face");
132
+ const list = made("ul", "list");
133
+ const line = made("p", "line");
134
+ const head = made("div", "head");
135
+ const chip = made("span", "chip");
136
+ chip.setAttribute("aria-hidden", "true");
137
+ chip.innerHTML = '<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.9" stroke-linecap="round" stroke-linejoin="round"><path d="M3 12a9 9 0 1 0 18 0 9 9 0 0 0-18 0"/><path d="M12 7v5l3 3"/></svg>';
138
+ // Its quiet meta at the head's end: how many of the documents listed were edited today.
139
+ const meta = made("span", "meta");
140
+ head.append(chip, made("span", "title", words.title), meta);
141
+ const more = made("p", "more");
142
+ more.hidden = true;
143
+ face.append(head, list, line, more);
144
+ host.append(face);
145
+ // How many rows are below what the list shows (one cut off counted), said under it, or nothing.
146
+ const recount = () => {
147
+ const bottom = list.scrollTop + list.clientHeight;
148
+ let below = 0;
149
+ for (const row of /** @type {HTMLCollectionOf<HTMLElement>} */ (list.children)) if (row.offsetTop + row.offsetHeight > bottom + 1) below++;
150
+ const said = below > 0 ? words.more(below) : "";
151
+ if (more.textContent !== said) more.textContent = said;
152
+ more.hidden = below === 0;
153
+ };
154
+ // The list as high as the whole rows that fit the room under the head (with the line of more under it
155
+ // where they are not all shown), so that no row is cut at the card's bottom; the rest of the room under it.
156
+ const fit = () => {
157
+ list.style.maxHeight = "";
158
+ const rows = /** @type {HTMLCollectionOf<HTMLElement>} */ (list.children);
159
+ if (rows.length === 0 || list.clientHeight === 0) return void recount();
160
+ const pitch = rows[0].getBoundingClientRect().height;
161
+ more.hidden = true;
162
+ if (list.scrollHeight <= list.clientHeight + 1 || !(pitch > 0)) return void recount();
163
+ more.textContent = words.more(rows.length);
164
+ more.hidden = false;
165
+ const shown = Math.max(1, Math.floor((list.clientHeight + 0.5) / pitch));
166
+ list.style.maxHeight = `${shown * pitch}px`;
167
+ recount();
168
+ };
169
+ list.addEventListener("scroll", recount, { passive: true });
170
+ const watch = typeof ResizeObserver === "function" ? new ResizeObserver(() => fit()) : null;
171
+ watch?.observe(face);
172
+ context.signal?.addEventListener("abort", () => {
173
+ list.removeEventListener("scroll", recount);
174
+ watch?.disconnect();
175
+ }, { once: true });
176
+ const workspace = context.workspace;
177
+ if (!workspace) return void context.fail(new Error("its manifest's needs hold \"workspace\": context.workspace is not there"));
178
+ /** @type {Array<{ node: HTMLElement, edited: string }>} */
179
+ let times = [];
180
+ const say = (/** @type {string | null} */ words) => {
181
+ line.hidden = words === null;
182
+ line.textContent = words ?? "";
183
+ };
184
+ // Each time said again, only where its words are others; the head's count of today's too.
185
+ const retime = () => {
186
+ const now = new Date();
187
+ let today = 0;
188
+ for (const { node, edited } of times) {
189
+ const said = whenOf(edited, now, language);
190
+ if (node.textContent !== said) node.textContent = said;
191
+ const then = new Date(edited);
192
+ if (then.getFullYear() === now.getFullYear() && then.getMonth() === now.getMonth() && then.getDate() === now.getDate()) today++;
193
+ }
194
+ const counted = today > 0 ? words.today(today) : "";
195
+ if (meta.textContent !== counted) meta.textContent = counted;
196
+ };
197
+ const draw = (/** @type {Array<{ slug: string, title: string, icon: string | null, edited: string }>} */ documents) => {
198
+ times = [];
199
+ list.replaceChildren(...documents.map((entry) => {
200
+ const item = made("li", "item");
201
+ const button = made("button", "document");
202
+ button.type = "button";
203
+ button.title = words.open(entry.title);
204
+ const when = made("time", "when");
205
+ when.dateTime = entry.edited;
206
+ times.push({ node: when, edited: entry.edited });
207
+ button.append(iconFor(entry.slug, entry.icon), made("span", "name", entry.title), when);
208
+ button.addEventListener("click", () => workspace.open({ slug: entry.slug }));
209
+ item.append(button);
210
+ return item;
211
+ }));
212
+ retime();
213
+ say(documents.length === 0 ? words.empty : null);
214
+ fit();
215
+ };
216
+ let asking = 0; // the last read asked: an older answer that comes after it is dropped
217
+ const read = () => {
218
+ const ticket = ++asking;
219
+ workspace.query("recent", { limit: 20 }).then(({ data }) => {
220
+ if (ticket === asking && !context.signal.aborted) draw(data);
221
+ }, (/** @type {any} */ error) => {
222
+ if (ticket !== asking || context.signal.aborted) return;
223
+ times = [];
224
+ meta.textContent = "";
225
+ list.replaceChildren();
226
+ say(error?.code === "offline" ? words.offline : words.failed);
227
+ fit();
228
+ });
229
+ };
230
+ read();
231
+ return {
232
+ update(reason, detail) {
233
+ if (reason === "data" && detail === "recent") read();
234
+ else if (reason === "clock") retime();
235
+ },
236
+ };
237
+ },
238
+ });
@@ -0,0 +1 @@
1
+ <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 240 120"><rect width="240" height="120" rx="8" fill="#f3f3f1"/><rect x="16.5" y="12.5" width="207" height="95" rx="12" fill="#ffffff" stroke="#e7e6e3"/><rect x="30" y="24" width="14" height="14" rx="4.5" fill="#ebf2fa"/><g transform="translate(32 26) scale(.4167)" fill="none" stroke="#2e7cd1" stroke-width="2.4" stroke-linecap="round" stroke-linejoin="round"><path d="M3 12a9 9 0 1 0 18 0 9 9 0 0 0-18 0"/><path d="M12 7v5l3 3"/></g><rect x="50" y="28" width="44" height="6" rx="3" fill="#3b3a37"/><path d="M32.6 50h4.4l3 3v7.4a1 1 0 0 1-1 1h-6.4a1 1 0 0 1-1-1v-9.4a1 1 0 0 1 1-1z" fill="none" stroke="#8f8d88" stroke-width="1.1" stroke-linejoin="round"/><rect x="47" y="53.5" width="70" height="6" rx="3" fill="#3b3a37"/><rect x="180" y="54" width="30" height="5" rx="2.5" fill="#c4c2bd"/><path d="M32.6 68h4.4l3 3v7.4a1 1 0 0 1-1 1h-6.4a1 1 0 0 1-1-1v-9.4a1 1 0 0 1 1-1z" fill="none" stroke="#8f8d88" stroke-width="1.1" stroke-linejoin="round"/><rect x="47" y="71.5" width="56" height="6" rx="3" fill="#3b3a37"/><rect x="194" y="72" width="16" height="5" rx="2.5" fill="#c4c2bd"/><path d="M32.6 86h4.4l3 3v7.4a1 1 0 0 1-1 1h-6.4a1 1 0 0 1-1-1v-9.4a1 1 0 0 1 1-1z" fill="none" stroke="#8f8d88" stroke-width="1.1" stroke-linejoin="round"/><rect x="47" y="89.5" width="84" height="6" rx="3" fill="#3b3a37"/><rect x="186" y="90" width="24" height="5" rx="2.5" fill="#c4c2bd"/></svg>