@heycys/gallery 0.1.2 → 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (292) hide show
  1. package/THIRD-PARTY-NOTICES.md +2 -2
  2. package/browser/editor/components/align.mjs +58 -0
  3. package/browser/editor/components/code/index.mjs +1 -1
  4. package/browser/editor/components/embed/page.mjs +1 -1
  5. package/browser/editor/components/file/page.mjs +4 -4
  6. package/browser/editor/components/heading/index.mjs +7 -6
  7. package/browser/editor/components/icons.mjs +3 -0
  8. package/browser/editor/components/image/index.mjs +2 -0
  9. package/browser/editor/components/image/page.mjs +172 -90
  10. package/browser/editor/components/installed/index.mjs +6 -2
  11. package/browser/editor/components/installed/page.mjs +80 -13
  12. package/browser/editor/components/media/icons.mjs +13 -8
  13. package/browser/editor/components/media/page.mjs +5 -3
  14. package/browser/editor/components/media/toolbar.mjs +12 -3
  15. package/browser/editor/components/paragraph/index.mjs +4 -3
  16. package/browser/editor/components/registry.mjs +17 -5
  17. package/browser/editor/components/table/index.mjs +4 -2
  18. package/browser/editor/page/after/index.mjs +288 -0
  19. package/browser/editor/page/align.mjs +91 -0
  20. package/browser/editor/page/beside.mjs +5 -6
  21. package/browser/editor/page/block-menu/index.mjs +6 -3
  22. package/browser/editor/page/blocks.mjs +3 -1
  23. package/browser/editor/page/board/hint.mjs +64 -27
  24. package/browser/editor/page/board/index.mjs +160 -71
  25. package/browser/editor/page/board/motion.mjs +177 -0
  26. package/browser/editor/page/board/settings.mjs +4 -3
  27. package/browser/editor/page/clipboard/index.mjs +10 -3
  28. package/browser/editor/page/clipboard/own/blocks.mjs +3 -4
  29. package/browser/editor/page/clipboard/own/describe.mjs +6 -2
  30. package/browser/editor/page/commit.mjs +2 -2
  31. package/browser/editor/page/core.mjs +3 -1
  32. package/browser/editor/page/custom-page.mjs +15 -11
  33. package/browser/editor/page/editor.mjs +31 -14
  34. package/browser/editor/page/history.mjs +19 -4
  35. package/browser/editor/page/insert/index.mjs +20 -22
  36. package/browser/editor/page/menu.mjs +15 -7
  37. package/browser/editor/page/page-objects.mjs +3 -7
  38. package/browser/editor/page/present-links.mjs +5 -4
  39. package/browser/editor/page/present-shell.mjs +63 -0
  40. package/browser/editor/page/selection/index.mjs +10 -2
  41. package/browser/editor/page/table/binding.mjs +87 -0
  42. package/browser/editor/page/table/icons.mjs +0 -2
  43. package/browser/editor/page/table/index.mjs +10 -14
  44. package/browser/editor/page/table/views.mjs +5 -52
  45. package/browser/editor/page/table/widths.mjs +82 -10
  46. package/browser/editor/page/typing/index.mjs +44 -12
  47. package/browser/editor/page/typing/leave.mjs +19 -5
  48. package/browser/shared/block-packs.mjs +23 -8
  49. package/browser/shared/component-catalog.mjs +15 -8
  50. package/browser/shared/component-source.mjs +3 -1
  51. package/browser/shared/components/heading.mjs +2 -1
  52. package/browser/shared/components/installed.mjs +1 -1
  53. package/browser/shared/components/page.mjs +2 -0
  54. package/browser/shared/components/paragraph.mjs +8 -1
  55. package/browser/shared/components/table.mjs +1 -0
  56. package/browser/shared/emoji/line-icons.mjs +37 -0
  57. package/browser/shared/http.mjs +9 -0
  58. package/browser/shared/i18n/en.mjs +40 -17
  59. package/browser/shared/outline.mjs +30 -2
  60. package/browser/shared/pack-manifest.mjs +12 -1
  61. package/browser/shared/pages.mjs +169 -57
  62. package/browser/shared/pinyin.mjs +92 -0
  63. package/browser/shared/present-step.mjs +17 -0
  64. package/browser/shared/sidebar-head.mjs +70 -0
  65. package/browser/shared/web-links.mjs +5 -0
  66. package/dist/chunk-2OHANJ6Q.mjs +2 -0
  67. package/dist/{chunk-QOUEFUCH.mjs → chunk-3MBRL2PM.mjs} +1 -1
  68. package/dist/{chunk-NWR2LT5B.mjs → chunk-4OKWZY5E.mjs} +1 -1
  69. package/dist/{chunk-RMECZA2K.mjs → chunk-5K44HLTZ.mjs} +1 -1
  70. package/dist/{chunk-NFMCP2HI.mjs → chunk-5XA2ZBAE.mjs} +2 -2
  71. package/dist/{chunk-OUUP3WKT.mjs → chunk-67N2QJYT.mjs} +1 -1
  72. package/dist/chunk-6KBYRA2C.mjs +2 -0
  73. package/dist/{chunk-SX4LJYT6.mjs → chunk-6N3PX4XX.mjs} +1 -1
  74. package/dist/{chunk-RFDZXFJF.mjs → chunk-7JDX4E65.mjs} +1 -1
  75. package/dist/chunk-7M2BQQGZ.mjs +2 -0
  76. package/dist/{chunk-ZUNVAXLH.mjs → chunk-7OG26PGF.mjs} +1 -1
  77. package/dist/{chunk-B4P2CM2J.mjs → chunk-AHN3NFKJ.mjs} +1 -1
  78. package/dist/chunk-ALZ6ZENZ.mjs +3 -0
  79. package/dist/{chunk-UGWYKHBL.mjs → chunk-AR5D57ZD.mjs} +2 -2
  80. package/dist/{chunk-W3BGBJQW.mjs → chunk-BFJGHSQN.mjs} +1 -1
  81. package/dist/{chunk-HLYV7RIH.mjs → chunk-CMA72MAG.mjs} +1 -1
  82. package/dist/{chunk-D4CKRD3V.mjs → chunk-DAZL73VK.mjs} +2 -2
  83. package/dist/{chunk-6VTU6KEO.mjs → chunk-DJISHPUL.mjs} +1 -1
  84. package/dist/{chunk-BPL64HGA.mjs → chunk-EAIFITAV.mjs} +1 -1
  85. package/dist/chunk-EP25HDAJ.mjs +2 -0
  86. package/dist/{chunk-6EZ7FNIK.mjs → chunk-F4ZA6JRZ.mjs} +1 -1
  87. package/dist/{chunk-3KJHLHUO.mjs → chunk-F6HVDZR4.mjs} +1 -1
  88. package/dist/{chunk-3NJACR4W.mjs → chunk-FDMAXMQA.mjs} +1 -1
  89. package/dist/chunk-FETSREUN.mjs +5 -0
  90. package/dist/{chunk-RKPWLGZ3.mjs → chunk-GHOYKMQ3.mjs} +1 -1
  91. package/dist/chunk-HDWTZ763.mjs +12 -0
  92. package/dist/{chunk-VTKNEYT3.mjs → chunk-HPOI4ZX7.mjs} +1 -1
  93. package/dist/{chunk-OW5NWPOJ.mjs → chunk-HXG7EOPJ.mjs} +1 -1
  94. package/dist/{chunk-V6RIYQZZ.mjs → chunk-ITOH5EGO.mjs} +1 -1
  95. package/dist/{chunk-ZWPMCK7P.mjs → chunk-IV64FFI4.mjs} +1 -1
  96. package/dist/chunk-J43Z6LSS.mjs +2 -0
  97. package/dist/chunk-J5PUIV3Y.mjs +4 -0
  98. package/dist/{chunk-KTKHRC6H.mjs → chunk-JA7G53PC.mjs} +1 -1
  99. package/dist/{chunk-NWFBE2YA.mjs → chunk-JLTZF4LA.mjs} +1 -1
  100. package/dist/{chunk-GY3FAUVM.mjs → chunk-JZT7I2OJ.mjs} +1 -1
  101. package/dist/{chunk-QKXMPUXC.mjs → chunk-K5XATEOO.mjs} +1 -1
  102. package/dist/chunk-L2SUIS5S.mjs +2 -0
  103. package/dist/{chunk-TEZAWDSQ.mjs → chunk-LM4XFQHZ.mjs} +1 -1
  104. package/dist/{chunk-5ZJA7CXT.mjs → chunk-MN7BZL4R.mjs} +1 -1
  105. package/dist/chunk-MTYYHM2G.mjs +15 -0
  106. package/dist/{chunk-HMYTM3GT.mjs → chunk-MXUBKDRO.mjs} +1 -1
  107. package/dist/{chunk-MHW7ZKOU.mjs → chunk-OEXWRJME.mjs} +1 -1
  108. package/dist/{chunk-CRJEG7MT.mjs → chunk-OFHXGWOX.mjs} +1 -1
  109. package/dist/chunk-ORID3AE7.mjs +166 -0
  110. package/dist/{chunk-32ZUEFZ7.mjs → chunk-PGDE24N5.mjs} +1 -1
  111. package/dist/{chunk-UNOYVIYR.mjs → chunk-POTA2FV4.mjs} +1 -1
  112. package/dist/{chunk-N7AZZLGT.mjs → chunk-QE5RG76S.mjs} +18 -17
  113. package/dist/{chunk-N76HWBA3.mjs → chunk-R2ZDLJYT.mjs} +1 -1
  114. package/dist/chunk-SWUTTZCN.mjs +2 -0
  115. package/dist/{chunk-POQSE4C2.mjs → chunk-TR7TWGHB.mjs} +1 -1
  116. package/dist/chunk-U5XL7D6A.mjs +3 -0
  117. package/dist/{chunk-PVER7LSC.mjs → chunk-U7NZI6N4.mjs} +2 -2
  118. package/dist/{chunk-Q47PLKIJ.mjs → chunk-UGWMMEJ5.mjs} +1 -1
  119. package/dist/chunk-UJQJKNGK.mjs +2 -0
  120. package/dist/chunk-UYVCQK3H.mjs +22 -0
  121. package/dist/{chunk-FJYN7RTH.mjs → chunk-VFX2KNHP.mjs} +1 -1
  122. package/dist/{chunk-UBBRTJ2R.mjs → chunk-VS7JIGJW.mjs} +1 -1
  123. package/dist/{chunk-NVRNLK25.mjs → chunk-W7665ZEC.mjs} +2 -2
  124. package/dist/{chunk-NG375ILQ.mjs → chunk-WQDQWCX5.mjs} +1 -1
  125. package/dist/chunk-YLPSMDIS.mjs +5 -0
  126. package/dist/{chunk-VXACTLO3.mjs → chunk-YNAWBAYN.mjs} +1 -1
  127. package/dist/{chunk-ZB4H7ZN4.mjs → chunk-YROX2O22.mjs} +1 -1
  128. package/dist/{chunk-YQGT4AB2.mjs → chunk-ZDLPUOAG.mjs} +1 -1
  129. package/dist/chunk-ZQS6H473.mjs +16 -0
  130. package/dist/{chunk-OJKMINIU.mjs → chunk-ZWWC4KLF.mjs} +15 -15
  131. package/dist/cli.mjs +1 -1
  132. package/dist/server.mjs +1 -1
  133. package/dist/worker.mjs +1 -1
  134. package/kit/board.css +5 -5
  135. package/kit/code.js +15 -15
  136. package/kit/report.css +120 -41
  137. package/kit/runtime.js +45 -7
  138. package/kit/tables.js +2 -0
  139. package/kit/ui.js +2 -0
  140. package/package.json +1 -1
  141. package/packs/gallery/chart-view/kit.js +3 -3
  142. package/packs/gallery/chart-view/writing.md +1 -1
  143. package/packs/gallery/countdown/component.json +1 -1
  144. package/packs/gallery/countdown/kit.js +89 -29
  145. package/packs/gallery/countdown/preview.svg +1 -1
  146. package/packs/gallery/countdown/style.css +88 -100
  147. package/packs/gallery/countdown/writing.md +2 -2
  148. package/packs/gallery/habit/component.json +3 -3
  149. package/packs/gallery/habit/kit.js +114 -75
  150. package/packs/gallery/habit/preview.svg +1 -1
  151. package/packs/gallery/habit/style.css +133 -205
  152. package/packs/gallery/habit/writing.md +2 -2
  153. package/packs/gallery/heatmap/component.json +2 -2
  154. package/packs/gallery/heatmap/kit.js +335 -173
  155. package/packs/gallery/heatmap/preview.svg +1 -1
  156. package/packs/gallery/heatmap/style.css +158 -170
  157. package/packs/gallery/heatmap/writing.md +2 -2
  158. package/packs/gallery/kanban/kit.js +3 -3
  159. package/packs/gallery/kanban/writing.md +1 -1
  160. package/packs/gallery/metric/kit.js +3 -3
  161. package/packs/gallery/metric/writing.md +1 -1
  162. package/packs/gallery/note/component.json +3 -3
  163. package/packs/gallery/note/kit.js +40 -13
  164. package/packs/gallery/note/preview.svg +1 -1
  165. package/packs/gallery/note/style.css +51 -30
  166. package/packs/gallery/note/writing.md +2 -2
  167. package/packs/gallery/recent/component.json +2 -2
  168. package/packs/gallery/recent/kit.js +141 -86
  169. package/packs/gallery/recent/preview.svg +1 -1
  170. package/packs/gallery/recent/style.css +53 -126
  171. package/packs/gallery/recent/writing.md +2 -2
  172. package/packs/gallery/static/component.json +2 -2
  173. package/packs/gallery/static/preview.svg +1 -1
  174. package/packs/gallery/static/style.css +99 -66
  175. package/packs/gallery/static/writing.md +2 -2
  176. package/packs/gallery/stats/component.json +3 -3
  177. package/packs/gallery/stats/kit.js +253 -72
  178. package/packs/gallery/stats/preview.svg +1 -1
  179. package/packs/gallery/stats/style.css +64 -142
  180. package/packs/gallery/stats/writing.md +2 -2
  181. package/packs/gallery/today/component.json +2 -2
  182. package/packs/gallery/today/kit.js +62 -27
  183. package/packs/gallery/today/preview.svg +1 -1
  184. package/packs/gallery/today/style.css +101 -72
  185. package/packs/gallery/today/writing.md +2 -2
  186. package/packs/gallery/todos/component.json +1 -1
  187. package/packs/gallery/todos/kit.js +218 -71
  188. package/packs/gallery/todos/preview.svg +1 -1
  189. package/packs/gallery/todos/style.css +170 -223
  190. package/packs/gallery/todos/writing.md +1 -1
  191. package/packs/gallery/weather/component.json +2 -2
  192. package/packs/gallery/weather/kit.js +165 -90
  193. package/packs/gallery/weather/preview.svg +1 -1
  194. package/packs/gallery/weather/style.css +100 -218
  195. package/packs/gallery/weather/writing.md +1 -1
  196. package/packs/gallery-soft/countdown/component.json +18 -0
  197. package/packs/gallery-soft/countdown/example.html +3 -0
  198. package/packs/gallery-soft/countdown/kit.js +206 -0
  199. package/packs/gallery-soft/countdown/preview.svg +1 -0
  200. package/packs/gallery-soft/countdown/style.css +211 -0
  201. package/packs/gallery-soft/countdown/template.html +3 -0
  202. package/packs/gallery-soft/countdown/writing.md +24 -0
  203. package/packs/gallery-soft/habit/component.json +14 -0
  204. package/packs/gallery-soft/habit/example.html +3 -0
  205. package/packs/gallery-soft/habit/kit.js +366 -0
  206. package/packs/gallery-soft/habit/preview.svg +1 -0
  207. package/packs/gallery-soft/habit/style.css +251 -0
  208. package/packs/gallery-soft/habit/template.html +3 -0
  209. package/packs/gallery-soft/habit/writing.md +23 -0
  210. package/packs/gallery-soft/heatmap/component.json +18 -0
  211. package/packs/gallery-soft/heatmap/example.html +3 -0
  212. package/packs/gallery-soft/heatmap/kit.js +498 -0
  213. package/packs/gallery-soft/heatmap/preview.svg +1 -0
  214. package/packs/gallery-soft/heatmap/style.css +181 -0
  215. package/packs/gallery-soft/heatmap/template.html +3 -0
  216. package/packs/gallery-soft/heatmap/writing.md +23 -0
  217. package/packs/gallery-soft/note/component.json +14 -0
  218. package/packs/gallery-soft/note/example.html +3 -0
  219. package/packs/gallery-soft/note/kit.js +162 -0
  220. package/packs/gallery-soft/note/preview.svg +1 -0
  221. package/packs/gallery-soft/note/style.css +148 -0
  222. package/packs/gallery-soft/note/template.html +3 -0
  223. package/packs/gallery-soft/note/writing.md +20 -0
  224. package/packs/gallery-soft/recent/component.json +13 -0
  225. package/packs/gallery-soft/recent/example.html +1 -0
  226. package/packs/gallery-soft/recent/kit.js +335 -0
  227. package/packs/gallery-soft/recent/preview.svg +1 -0
  228. package/packs/gallery-soft/recent/style.css +160 -0
  229. package/packs/gallery-soft/recent/template.html +1 -0
  230. package/packs/gallery-soft/recent/writing.md +17 -0
  231. package/packs/gallery-soft/static/component.json +13 -0
  232. package/packs/gallery-soft/static/example.html +12 -0
  233. package/packs/gallery-soft/static/preview.svg +1 -0
  234. package/packs/gallery-soft/static/style.css +186 -0
  235. package/packs/gallery-soft/static/template.html +1 -0
  236. package/packs/gallery-soft/static/writing.md +20 -0
  237. package/packs/gallery-soft/stats/component.json +13 -0
  238. package/packs/gallery-soft/stats/example.html +1 -0
  239. package/packs/gallery-soft/stats/kit.js +341 -0
  240. package/packs/gallery-soft/stats/preview.svg +1 -0
  241. package/packs/gallery-soft/stats/style.css +119 -0
  242. package/packs/gallery-soft/stats/template.html +1 -0
  243. package/packs/gallery-soft/stats/writing.md +13 -0
  244. package/packs/gallery-soft/today/component.json +12 -0
  245. package/packs/gallery-soft/today/example.html +1 -0
  246. package/packs/gallery-soft/today/kit.js +222 -0
  247. package/packs/gallery-soft/today/preview.svg +1 -0
  248. package/packs/gallery-soft/today/style.css +178 -0
  249. package/packs/gallery-soft/today/template.html +1 -0
  250. package/packs/gallery-soft/today/writing.md +16 -0
  251. package/packs/gallery-soft/todos/component.json +19 -0
  252. package/packs/gallery-soft/todos/example.html +3 -0
  253. package/packs/gallery-soft/todos/kit.js +527 -0
  254. package/packs/gallery-soft/todos/preview.svg +1 -0
  255. package/packs/gallery-soft/todos/style.css +212 -0
  256. package/packs/gallery-soft/todos/template.html +3 -0
  257. package/packs/gallery-soft/todos/writing.md +32 -0
  258. package/packs/gallery-soft/weather/component.json +19 -0
  259. package/packs/gallery-soft/weather/example.html +3 -0
  260. package/packs/gallery-soft/weather/kit.js +411 -0
  261. package/packs/gallery-soft/weather/preview.svg +1 -0
  262. package/packs/gallery-soft/weather/style.css +185 -0
  263. package/packs/gallery-soft/weather/template.html +3 -0
  264. package/packs/gallery-soft/weather/writing.md +28 -0
  265. package/release.json +9 -9
  266. package/skill/SKILL.md +12 -12
  267. package/skill/references/building-blocks.md +4 -4
  268. package/skill/references/pages-and-data.md +13 -9
  269. package/skill/references/writing-html.md +2 -0
  270. package/web/assets/index-BM_K-Auu.css +1 -0
  271. package/web/assets/index-DRslOBiv.js +15 -0
  272. package/web/index.html +2 -2
  273. package/dist/chunk-2NRBY6AJ.mjs +0 -2
  274. package/dist/chunk-35NQ4PLQ.mjs +0 -2
  275. package/dist/chunk-4AV456RQ.mjs +0 -2
  276. package/dist/chunk-5XYHDBJ5.mjs +0 -2
  277. package/dist/chunk-6A53MZYZ.mjs +0 -2
  278. package/dist/chunk-6EXH3ORZ.mjs +0 -166
  279. package/dist/chunk-BVEFGE4B.mjs +0 -2
  280. package/dist/chunk-D4EURAX4.mjs +0 -4
  281. package/dist/chunk-DQCE7TJY.mjs +0 -5
  282. package/dist/chunk-FWNRPMCJ.mjs +0 -12
  283. package/dist/chunk-FWW4CSAZ.mjs +0 -2
  284. package/dist/chunk-JVHHHGEA.mjs +0 -3
  285. package/dist/chunk-PZDLJJTJ.mjs +0 -3
  286. package/dist/chunk-SXHBYZST.mjs +0 -16
  287. package/dist/chunk-UFNYFFKO.mjs +0 -20
  288. package/dist/chunk-UKSHDZZ6.mjs +0 -2
  289. package/dist/chunk-VJPFVNNW.mjs +0 -15
  290. package/dist/chunk-VS3ZMVGX.mjs +0 -5
  291. package/web/assets/index-BK2e_07w.js +0 -13
  292. package/web/assets/index-CWFI83mF.css +0 -1
@@ -1,17 +1,22 @@
1
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.
2
+ // context.workspace.query("recent") (its manifest's needs hold "workspace"; and "stats", for how many
3
+ // there are in all): each its page icon, its title and when it was edited. A click opens the document
4
+ // (context.workspace.open: the workbench goes there). It reads again whenever the workspace says the list
5
+ // changed (the `data` signal, "recent": a document written, renamed, given another icon, made or gone), and
6
+ // says the times again each minute (the kit's clock). It holds no part and writes nothing: all it shows is
7
+ // drawn (the manifest's `runtime`). Where the workspace cannot be read (an exported file, where it has no
8
+ // server; a server that does not answer) it says so. The words are the page's language (the UI's where
9
+ // Gallery says it, else the page's lang).
10
+ //
11
+ // Its face (the pack's design B, in the kit's card tokens): a head of the chip (a clock), 最近编辑 and how
12
+ // many of them were edited today, its quiet meta (今天 3 篇); then rows like the sidebar's, grouped by
13
+ // when (今天, 昨天, 本周, 更早: `groupOf`), each its icon, its title and its time at its end, said by its
14
+ // group (`whenOf`: today's 12 分钟前, or the hour once an hour has gone, 08:05; yesterday's its hour; this
15
+ // week's its weekday, 周二; earlier ones the date, 11月7日); under them, faint, how many more there are (还有
16
+ // 20 篇). The card shows whole rows only, as many as the room under its head holds with their groups'
17
+ // titles (`fit`, measured again as the card changes size: its own ResizeObserver on the face). A card two
18
+ // cells high (`data-layout` "short", by context.size) lists the last three, no groups, their times as a
19
+ // person says them (昨天, 周二). No document yet: the cards' empty face.
15
20
  //
16
21
  // A document's icon is drawn as Gallery's sidebar draws it, from the server that shows the page (its icon
17
22
  // route, /__gallery/edit/icon, one picture of any icon's value): an emoji or a picture of its folder as a
@@ -21,35 +26,40 @@
21
26
  const WORDS = {
22
27
  zh: {
23
28
  title: "最近编辑",
24
- empty: "还没有文档",
25
- offline: "在 Gallery 里打开时,这里列出最近改过的文档",
26
- failed: "读不到工作区的文档",
29
+ empty: ["还没有文档", "新建一篇,或者让 Agent 写一篇"],
30
+ offline: ["在 Gallery 里打开时显示", "这里会列出最近改过的文档"],
31
+ failed: ["读不到工作区的文档", "过一会儿会再读"],
27
32
  more: (/** @type {number} */ count) => `还有 ${count} 篇`,
28
33
  today: (/** @type {number} */ count) => `今天 ${count} 篇`,
29
34
  open: (/** @type {string} */ title) => `打开「${title}」`,
35
+ groups: { today: "今天", yesterday: "昨天", week: "本周", earlier: "更早" },
30
36
  now: "刚刚",
31
37
  minutes: (/** @type {number} */ count) => `${count} 分钟前`,
32
- hours: (/** @type {number} */ count) => `${count} 小时前`,
33
38
  yesterday: "昨天",
34
- days: (/** @type {number} */ count) => `${count} 天前`,
39
+ weekdays: ["周日", "周一", "周二", "周三", "周四", "周五", "周六"],
35
40
  date: (/** @type {Date} */ date, /** @type {boolean} */ thisYear) => (thisYear ? `${date.getMonth() + 1}月${date.getDate()}日` : `${date.getFullYear()}年${date.getMonth() + 1}月${date.getDate()}日`),
36
41
  },
37
42
  en: {
38
43
  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",
44
+ empty: ["No documents yet", "Make one, or ask your Agent to write one"],
45
+ offline: ["Shown when opened in Gallery", "The documents edited last show here"],
46
+ failed: ["The workspace's documents could not be read", "It reads them again in a while"],
42
47
  more: (/** @type {number} */ count) => `${count} more`,
43
48
  today: (/** @type {number} */ count) => `${count} today`,
44
49
  open: (/** @type {string} */ title) => `Open “${title}”`,
50
+ groups: { today: "Today", yesterday: "Yesterday", week: "This week", earlier: "Earlier" },
45
51
  now: "just now",
46
52
  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`,
53
+ yesterday: "Yesterday",
54
+ weekdays: ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"],
50
55
  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
56
  },
52
57
  };
58
+ /** The documents it asks for: as many as the tallest card shows, and more. */
59
+ const LIMIT = 50;
60
+ /** A group's title and a row, in px (style.css). */
61
+ const GROUP_HEIGHT = 26;
62
+ const ROW_HEIGHT = 30;
53
63
 
54
64
  /** The language the page speaks: the UI's where Gallery says it (data-ge-language), else its lang's. */
55
65
  function languageOf(/** @type {HTMLElement} */ root) {
@@ -57,26 +67,43 @@ function languageOf(/** @type {HTMLElement} */ root) {
57
67
  return (ui !== null ? ui === "en" : /^en(?:-|$)/i.test(root.lang)) ? "en" : "zh";
58
68
  }
59
69
 
70
+ /** A local day, as a number of days. @param {Date} date */
71
+ const dayNumber = (date) => Date.UTC(date.getFullYear(), date.getMonth(), date.getDate()) / 86_400_000;
72
+
73
+ /**
74
+ * Which group a document edited at `edited` (an ISO time) is in, from `now` (the reader's clock): "today",
75
+ * "yesterday", "week" (earlier this week, from its Monday) or "earlier".
76
+ * @param {string} edited
77
+ * @param {Date} now
78
+ */
79
+ function groupOf(edited, now) {
80
+ const then = new Date(edited);
81
+ const days = dayNumber(now) - dayNumber(then);
82
+ if (days <= 0) return "today";
83
+ if (days === 1) return "yesterday";
84
+ return days <= (now.getDay() + 6) % 7 ? "week" : "earlier";
85
+ }
86
+
60
87
  /**
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).
88
+ * When `edited` (an ISO time) was, from `now` (the reader's clock), in `language`: within the hour 刚刚
89
+ * and N 分钟前, then today's hour (08:05); yesterday's hour where its group says yesterday (`grouped`),
90
+ * else 昨天; a day earlier this week its weekday (周二); else its date, the year said when it is another.
64
91
  * @param {string} edited
65
92
  * @param {Date} now
66
93
  * @param {"zh" | "en"} language
94
+ * @param {boolean} [grouped]
67
95
  */
68
- function whenOf(edited, now, language) {
96
+ function whenOf(edited, now, language, grouped = true) {
69
97
  const words = WORDS[language];
70
98
  const then = new Date(edited);
71
99
  const minutes = Math.floor((now.getTime() - then.getTime()) / 60_000);
72
100
  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);
101
+ const two = (/** @type {number} */ value) => String(value).padStart(2, "0");
102
+ const hour = `${two(then.getHours())}:${two(then.getMinutes())}`;
103
+ const group = groupOf(edited, now);
104
+ if (group === "today") return minutes < 1 ? words.now : minutes < 60 ? words.minutes(minutes) : hour;
105
+ if (group === "yesterday") return grouped ? hour : words.yesterday;
106
+ if (group === "week") return words.weekdays[then.getDay()];
80
107
  return words.date(then, then.getFullYear() === now.getFullYear());
81
108
  }
82
109
 
@@ -124,79 +151,94 @@ function iconFor(/** @type {string} */ slug, /** @type {string | null} */ value)
124
151
 
125
152
  DocKit.component({
126
153
  id: "gallery/recent",
127
- on: ["data", "clock"],
154
+ on: ["data", "clock", "layout"],
128
155
  mount(host, context) {
129
156
  const language = languageOf(document.documentElement);
130
157
  const words = WORDS[language];
131
158
  const face = made("div", "face");
132
159
  const list = made("ul", "list");
133
- const line = made("p", "line");
134
160
  const head = made("div", "head");
135
161
  const chip = made("span", "chip");
136
162
  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.
163
+ chip.innerHTML = '<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.9" stroke-linecap="round" stroke-linejoin="round"><circle cx="12" cy="12" r="8.5"/><path d="M12 7.5V12l3 1.8"/></svg>';
164
+ // Its quiet meta after the title: how many of the documents were edited today.
139
165
  const meta = made("span", "meta");
140
166
  head.append(chip, made("span", "title", words.title), meta);
141
167
  const more = made("p", "more");
142
168
  more.hidden = true;
143
- face.append(head, list, line, more);
169
+ // No document, or no workspace: the cards' empty face.
170
+ const empty = made("div", "empty");
171
+ const emptyPicture = made("span", "empty-picture");
172
+ emptyPicture.setAttribute("aria-hidden", "true");
173
+ emptyPicture.innerHTML = '<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.7" stroke-linecap="round" stroke-linejoin="round"><path d="M7 3.5h6.5L18 8v11a1.5 1.5 0 0 1-1.5 1.5h-9.5A1.5 1.5 0 0 1 5.5 19V5A1.5 1.5 0 0 1 7 3.5z"/><path d="M13.5 3.5V8H18"/></svg>';
174
+ const line = made("p", "line");
175
+ const hint = made("p", "hint");
176
+ empty.append(emptyPicture, line, hint);
177
+ empty.hidden = true;
178
+ face.append(head, list, more, empty);
144
179
  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
180
  const workspace = context.workspace;
177
181
  if (!workspace) return void context.fail(new Error("its manifest's needs hold \"workspace\": context.workspace is not there"));
182
+ /** @type {Array<{ slug: string, title: string, icon: string | null, edited: string }> | null} */
183
+ let documents = null;
184
+ let total = 0;
178
185
  /** @type {Array<{ node: HTMLElement, edited: string }>} */
179
186
  let times = [];
180
- const say = (/** @type {string | null} */ words) => {
181
- line.hidden = words === null;
182
- line.textContent = words ?? "";
187
+ let shown = -1;
188
+ const short = () => Boolean(context.size && context.size.h <= 2);
189
+ const say = (/** @type {string[] | null} */ said) => {
190
+ empty.hidden = said === null;
191
+ list.hidden = said !== null;
192
+ if (said === null) return;
193
+ line.textContent = said[0];
194
+ hint.textContent = said[1] ?? "";
183
195
  };
184
196
  // Each time said again, only where its words are others; the head's count of today's too.
185
197
  const retime = () => {
186
198
  const now = new Date();
187
- let today = 0;
188
199
  for (const { node, edited } of times) {
189
- const said = whenOf(edited, now, language);
200
+ const said = whenOf(edited, now, language, !short());
190
201
  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
202
  }
203
+ const today = (documents ?? []).filter(({ edited }) => groupOf(edited, now) === "today").length;
194
204
  const counted = today > 0 ? words.today(today) : "";
195
205
  if (meta.textContent !== counted) meta.textContent = counted;
196
206
  };
197
- const draw = (/** @type {Array<{ slug: string, title: string, icon: string | null, edited: string }>} */ documents) => {
207
+ // The rows the room under the head holds, whole, with their groups' titles (none on a short card), and
208
+ // a line of how many more there are: drawn again only when that is another number.
209
+ const fit = (/** @type {boolean} */ again = false) => {
210
+ if (!documents) return;
211
+ const layout = short() ? "short" : "full";
212
+ face.dataset.layout = layout;
213
+ const now = new Date();
214
+ // The room: the face's height under the head and the line of more (none measured where nothing lays it out: every row).
215
+ const room = face.clientHeight > 0 ? face.clientHeight - head.offsetHeight - (layout === "short" ? 4 : 6) - (layout === "short" ? 0 : 24) : Infinity;
216
+ let count = 0;
217
+ if (layout === "short") count = Math.min(3, documents.length);
218
+ else {
219
+ let used = 0;
220
+ let group = "";
221
+ for (const entry of documents) {
222
+ const next = groupOf(entry.edited, now);
223
+ const cost = (next !== group ? GROUP_HEIGHT : 0) + ROW_HEIGHT;
224
+ if (used + cost > room) break;
225
+ used += cost;
226
+ group = next;
227
+ count++;
228
+ }
229
+ }
230
+ const key = `${layout}:${count}`;
231
+ if (!again && String(shown) === key) return;
232
+ shown = /** @type {any} */ (key);
198
233
  times = [];
199
- list.replaceChildren(...documents.map((entry) => {
234
+ let group = "";
235
+ list.replaceChildren(...documents.slice(0, count).flatMap((entry) => {
236
+ const rows = [];
237
+ const next = groupOf(entry.edited, now);
238
+ if (layout === "full" && next !== group) {
239
+ rows.push(made("li", "group", words.groups[/** @type {keyof typeof words.groups} */ (next)]));
240
+ group = next;
241
+ }
200
242
  const item = made("li", "item");
201
243
  const button = made("button", "document");
202
244
  button.type = "button";
@@ -207,24 +249,36 @@ DocKit.component({
207
249
  button.append(iconFor(entry.slug, entry.icon), made("span", "name", entry.title), when);
208
250
  button.addEventListener("click", () => workspace.open({ slug: entry.slug }));
209
251
  item.append(button);
210
- return item;
252
+ rows.push(item);
253
+ return rows;
211
254
  }));
255
+ const below = Math.max(0, total - count);
256
+ more.hidden = below === 0 || layout === "short";
257
+ more.textContent = below > 0 ? words.more(below) : "";
212
258
  retime();
213
- say(documents.length === 0 ? words.empty : null);
214
- fit();
215
259
  };
260
+ const watch = typeof ResizeObserver === "function" ? new ResizeObserver(() => fit()) : null;
261
+ watch?.observe(face);
262
+ context.signal?.addEventListener("abort", () => watch?.disconnect(), { once: true });
216
263
  let asking = 0; // the last read asked: an older answer that comes after it is dropped
217
264
  const read = () => {
218
265
  const ticket = ++asking;
219
- workspace.query("recent", { limit: 20 }).then(({ data }) => {
220
- if (ticket === asking && !context.signal.aborted) draw(data);
266
+ const counted = workspace.query("stats").then(({ data }) => data?.documents ?? null, () => null);
267
+ workspace.query("recent", { limit: LIMIT }).then(async ({ data }) => {
268
+ const all = await counted;
269
+ if (ticket !== asking || context.signal.aborted) return;
270
+ documents = data;
271
+ total = typeof all === "number" ? Math.max(all, data.length) : data.length;
272
+ say(data.length === 0 ? words.empty : null);
273
+ fit(true);
221
274
  }, (/** @type {any} */ error) => {
222
275
  if (ticket !== asking || context.signal.aborted) return;
276
+ documents = null;
223
277
  times = [];
224
278
  meta.textContent = "";
225
279
  list.replaceChildren();
280
+ more.hidden = true;
226
281
  say(error?.code === "offline" ? words.offline : words.failed);
227
- fit();
228
282
  });
229
283
  };
230
284
  read();
@@ -232,6 +286,7 @@ DocKit.component({
232
286
  update(reason, detail) {
233
287
  if (reason === "data" && detail === "recent") read();
234
288
  else if (reason === "clock") retime();
289
+ else if (reason === "layout") fit();
235
290
  },
236
291
  };
237
292
  },
@@ -1 +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>
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="60.5" y="6.5" width="119" height="107" rx="8" fill="#ffffff" stroke="#e6e6e3"/><rect x="70" y="14" width="10" height="10" rx="3" fill="#efefed"/><rect x="84" y="16.5" width="30" height="5" rx="2.5" fill="#37352f"/><rect x="118" y="16.5" width="16" height="5" rx="2.5" fill="#d4d3cf"/><rect x="70" y="32" width="12" height="4" rx="2" fill="#a6a5a1"/><rect x="70" y="41" width="7" height="7" rx="2" fill="#f6c264"/><rect x="81" y="42" width="52" height="5" rx="2.5" fill="#37352f"/><rect x="158" y="42.5" width="12" height="4" rx="2" fill="#d4d3cf"/><rect x="70" y="54" width="7" height="7" rx="2" fill="#e8a3a3"/><rect x="81" y="55" width="44" height="5" rx="2.5" fill="#37352f"/><rect x="158" y="55.5" width="12" height="4" rx="2" fill="#d4d3cf"/><rect x="70" y="67" width="7" height="7" rx="2" fill="#9fc3ef"/><rect x="81" y="68" width="38" height="5" rx="2.5" fill="#37352f"/><rect x="158" y="68.5" width="12" height="4" rx="2" fill="#d4d3cf"/><rect x="70" y="88" width="7" height="7" rx="2" fill="#b8d79a"/><rect x="81" y="89" width="48" height="5" rx="2.5" fill="#37352f"/><rect x="158" y="89.5" width="12" height="4" rx="2" fill="#d4d3cf"/><rect x="70" y="101" width="7" height="7" rx="2" fill="#c9b3ec"/><rect x="81" y="102" width="36" height="5" rx="2.5" fill="#37352f"/><rect x="158" y="102.5" width="12" height="4" rx="2" fill="#d4d3cf"/><rect x="70" y="79" width="12" height="4" rx="2" fill="#a6a5a1"/></svg>
@@ -1,158 +1,85 @@
1
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. The face fills its card on a custom page (the board draws the frame), in
3
- the kit's card tokens: its head (the chip and 最近编辑, how many were edited today its quiet meta at the
4
- end, clear of the card's grip), then the
5
- documents, as many whole rows as fit (the script sets the list's height; they scroll inside it), a row each as the sidebar draws one (its icon, its title, and
6
- when it was edited at its end, muted), a hover fill a press away from opening it; where more are below
7
- what it shows, a muted line under the list says how many (the script's); none, the cards' empty face (a
8
- page in a soft disc over a muted line). Light and dark. */
2
+ reaches the rest of the page. The pack's design B, in the kit's card tokens: the head (the chip, a
3
+ clock, 最近编辑 and how many were edited today, faint), its end clear of the card's grip; rows like the
4
+ sidebar's (30px, out to the face's edges by 6px so that a row's hover fill has room), each its icon, its
5
+ title and its time at its end, faint; the groups' titles (今天, 昨天, 本周, 更早) small, faint and 600; and
6
+ under them how many more there are, faint. A short card (data-layout "short") lists three, no groups.
7
+ No document: the cards' empty face in the middle. A document's icon as the sidebar draws it (a picture,
8
+ a glyph masked in the faint color, or a page drawn here). Light and dark. */
9
9
  [data-doc-component="gallery/recent"] {
10
- height: 16em;
11
- > .gallery-recent-face {
12
- display: flex;
13
- flex-direction: column;
14
- gap: var(--gallery-face-gap);
15
- box-sizing: border-box;
16
- height: 100%;
17
- min-height: 0;
18
- color: var(--gallery-text);
19
- font-size: 14px;
20
- line-height: 1.45;
21
- }
10
+ font-family: var(--gallery-font);
11
+ font-size: 13px;
12
+ line-height: 1.5;
13
+ color: var(--gallery-text);
14
+ > .gallery-recent-face { display: flex; flex-direction: column; box-sizing: border-box; min-height: 0; }
22
15
  > .gallery-recent-face > .gallery-recent-head {
23
16
  display: flex;
24
17
  align-items: center;
25
18
  gap: 8px;
26
19
  flex: none;
20
+ height: 20px;
27
21
  min-width: 0;
28
22
  padding-inline-end: var(--gallery-grip-room, 0px);
29
23
  }
30
24
  > .gallery-recent-face > .gallery-recent-head > .gallery-recent-chip {
31
25
  flex: none;
32
- display: inline-flex;
33
- align-items: center;
34
- justify-content: center;
26
+ display: grid;
27
+ place-items: center;
35
28
  width: var(--gallery-chip-size);
36
29
  height: var(--gallery-chip-size);
37
30
  border-radius: var(--gallery-chip-radius);
38
- background: var(--gallery-accent-soft);
39
- color: var(--gallery-accent);
40
- }
41
- > .gallery-recent-face > .gallery-recent-head > .gallery-recent-chip > svg { width: var(--gallery-chip-icon); height: var(--gallery-chip-icon); }
42
- > .gallery-recent-face > .gallery-recent-head > .gallery-recent-title {
43
- flex: 1 1 auto;
44
- min-width: 0;
45
- overflow: hidden;
46
- white-space: nowrap;
47
- text-overflow: ellipsis;
48
- font-size: var(--gallery-title-size);
49
- line-height: var(--gallery-title-line);
50
- font-weight: 600;
51
- color: var(--gallery-text-strong);
52
- }
53
- > .gallery-recent-face > .gallery-recent-head > .gallery-recent-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; }
54
- > .gallery-recent-face > .gallery-recent-list {
55
- flex: 1 1 auto;
56
- min-height: 0;
57
- margin: -2px -6px 0;
58
- padding: 0;
59
- list-style: none;
60
- position: relative;
61
- overflow-y: auto;
62
- overscroll-behavior: contain;
63
- scrollbar-width: thin;
31
+ background: var(--gallery-fill);
32
+ color: var(--gallery-muted);
64
33
  }
34
+ > .gallery-recent-face > .gallery-recent-head > .gallery-recent-chip > svg { display: block; width: var(--gallery-chip-icon); height: var(--gallery-chip-icon); }
35
+ > .gallery-recent-face > .gallery-recent-head > .gallery-recent-title { min-width: 0; overflow: hidden; white-space: nowrap; text-overflow: ellipsis; font-size: var(--gallery-title-size); line-height: var(--gallery-title-line); font-weight: 600; color: var(--gallery-text); }
36
+ > .gallery-recent-face > .gallery-recent-head > .gallery-recent-meta { flex: none; font-size: var(--gallery-meta-size); color: var(--gallery-faint); white-space: nowrap; }
37
+ > .gallery-recent-face > .gallery-recent-list { flex: 1 1 auto; min-height: 0; margin: 6px -6px 0; padding: 0; overflow: hidden; list-style: none; }
38
+ > .gallery-recent-face[data-layout="short"] > .gallery-recent-list { margin-top: 4px; }
39
+ > .gallery-recent-face > .gallery-recent-list[hidden] { display: none; }
40
+ > .gallery-recent-face > .gallery-recent-list > .gallery-recent-group { padding: 8px 6px 2px; font-size: 11.5px; line-height: 16px; font-weight: 600; color: var(--gallery-faint); }
65
41
  > .gallery-recent-face > .gallery-recent-list > .gallery-recent-item > .gallery-recent-document {
66
42
  display: flex;
67
43
  align-items: center;
68
- gap: 10px;
44
+ gap: 8px;
69
45
  box-sizing: border-box;
70
46
  width: 100%;
71
- margin: 0;
72
- padding: 6px;
47
+ height: 30px;
48
+ padding: 0 6px;
73
49
  border: 0;
74
50
  border-radius: 6px;
75
- background: transparent;
51
+ background: none;
76
52
  font: inherit;
77
53
  color: inherit;
78
54
  text-align: start;
79
55
  cursor: pointer;
80
56
  }
81
- > .gallery-recent-face > .gallery-recent-list > .gallery-recent-item > .gallery-recent-document:hover { background: var(--doc-hover); }
82
- > .gallery-recent-face > .gallery-recent-list > .gallery-recent-item > .gallery-recent-document > .gallery-recent-icon {
83
- flex: none;
84
- display: inline-flex;
85
- align-items: center;
86
- justify-content: center;
87
- width: 18px;
88
- height: 18px;
89
- color: var(--doc-muted);
90
- }
91
- /* A document with no icon: a page, drawn as the sidebar's (a folded corner), in the muted color. */
92
- > .gallery-recent-face > .gallery-recent-list > .gallery-recent-item > .gallery-recent-document > .gallery-recent-icon:empty:not(.gallery-recent-glyph)::before {
93
- content: "";
94
- display: block;
95
- width: 13px;
96
- height: 16px;
97
- background: currentColor;
98
- -webkit-mask: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 13 16'%3E%3Cpath d='M2 .75h6.2l4.05 4.05V14A1.25 1.25 0 0 1 11 15.25H2A1.25 1.25 0 0 1 .75 14V2A1.25 1.25 0 0 1 2 .75z M8 1v3.5a.75.75 0 0 0 .75.75H12' fill='none' stroke='black' stroke-width='1.4' stroke-linejoin='round'/%3E%3C/svg%3E") center / contain no-repeat;
99
- mask: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 13 16'%3E%3Cpath d='M2 .75h6.2l4.05 4.05V14A1.25 1.25 0 0 1 11 15.25H2A1.25 1.25 0 0 1 .75 14V2A1.25 1.25 0 0 1 2 .75z M8 1v3.5a.75.75 0 0 0 .75.75H12' fill='none' stroke='black' stroke-width='1.4' stroke-linejoin='round'/%3E%3C/svg%3E") center / contain no-repeat;
100
- }
101
- > .gallery-recent-face > .gallery-recent-list > .gallery-recent-item > .gallery-recent-document > .gallery-recent-glyph {
102
- background: currentColor;
103
- -webkit-mask: var(--gallery-recent-icon) center / 16px no-repeat;
104
- mask: var(--gallery-recent-icon) center / 16px no-repeat;
105
- }
106
- > .gallery-recent-face > .gallery-recent-list > .gallery-recent-item > .gallery-recent-document > .gallery-recent-picture > img { display: block; width: 16px; height: 16px; object-fit: contain; border-radius: 3px; }
107
- > .gallery-recent-face > .gallery-recent-list > .gallery-recent-item > .gallery-recent-document > .gallery-recent-name {
108
- flex: 1 1 auto;
109
- min-width: 0;
110
- overflow: hidden;
111
- white-space: nowrap;
112
- text-overflow: ellipsis;
113
- }
114
- > .gallery-recent-face > .gallery-recent-list > .gallery-recent-item > .gallery-recent-document > .gallery-recent-when { flex: none; font-size: var(--gallery-meta-size); color: var(--doc-muted); white-space: nowrap; font-variant-numeric: tabular-nums; }
115
- /* What it says where it lists nothing: in the middle of what the card has left, muted, a quiet
116
- picture of a page over it. */
117
- > .gallery-recent-face > .gallery-recent-line {
118
- flex: 1 1 auto;
119
- display: flex;
120
- flex-direction: column;
121
- align-items: center;
122
- justify-content: center;
123
- gap: 8px;
124
- margin: 0;
125
- padding: 8px 12px;
126
- font-size: 13px;
127
- color: var(--doc-muted);
128
- text-align: center;
129
- }
130
- > .gallery-recent-face > .gallery-recent-line::before {
57
+ > .gallery-recent-face > .gallery-recent-list > .gallery-recent-item > .gallery-recent-document:hover { background: var(--gallery-hover); }
58
+ > .gallery-recent-face > .gallery-recent-list > .gallery-recent-item > .gallery-recent-document:focus-visible { outline: 2px solid var(--gallery-accent-wash); outline-offset: -2px; }
59
+ > .gallery-recent-face > .gallery-recent-list > .gallery-recent-item > .gallery-recent-document > .gallery-recent-icon { flex: none; display: grid; place-items: center; width: 18px; height: 18px; }
60
+ > .gallery-recent-face > .gallery-recent-list > .gallery-recent-item > .gallery-recent-document > .gallery-recent-picture > img { display: block; width: 15px; height: 15px; object-fit: contain; }
61
+ > .gallery-recent-face > .gallery-recent-list > .gallery-recent-item > .gallery-recent-document > .gallery-recent-glyph::before { content: ""; width: 15px; height: 15px; background: var(--gallery-faint); -webkit-mask: var(--gallery-recent-icon) center / contain no-repeat; mask: var(--gallery-recent-icon) center / contain no-repeat; }
62
+ > .gallery-recent-face > .gallery-recent-list > .gallery-recent-item > .gallery-recent-document > .gallery-recent-icon:empty::before {
131
63
  content: "";
132
- flex: none;
133
- width: 44px;
134
- height: 44px;
135
- margin-bottom: 2px;
136
- background: currentColor;
137
- -webkit-mask: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 44 44'%3E%3Ccircle cx='22' cy='22' r='22' fill-opacity='.14'/%3E%3Cg transform='translate(11 11) scale(.9167)' fill='none' stroke='black' stroke-width='1.8' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M14 3v4a1 1 0 0 0 1 1h4'/%3E%3Cpath d='M17 21H7a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h7l5 5v11a2 2 0 0 1-2 2z'/%3E%3C/g%3E%3C/svg%3E") center / contain no-repeat;
138
- mask: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 44 44'%3E%3Ccircle cx='22' cy='22' r='22' fill-opacity='.14'/%3E%3Cg transform='translate(11 11) scale(.9167)' fill='none' stroke='black' stroke-width='1.8' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M14 3v4a1 1 0 0 0 1 1h4'/%3E%3Cpath d='M17 21H7a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h7l5 5v11a2 2 0 0 1-2 2z'/%3E%3C/g%3E%3C/svg%3E") center / contain no-repeat;
139
- }
140
- > .gallery-recent-face > .gallery-recent-line[hidden] { display: none; }
141
- /* How many more are below what the list shows. */
142
- > .gallery-recent-face > .gallery-recent-more {
143
- flex: none;
144
- margin: -2px 0 0;
145
- font-size: var(--gallery-meta-size);
146
- line-height: 16px;
147
- color: var(--doc-muted);
64
+ width: 15px;
65
+ height: 15px;
66
+ background: var(--gallery-faint);
67
+ -webkit-mask: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='black' stroke-width='1.7' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M7 3.5h6.5L18 8v11a1.5 1.5 0 0 1-1.5 1.5h-9.5A1.5 1.5 0 0 1 5.5 19V5A1.5 1.5 0 0 1 7 3.5z'/%3E%3Cpath d='M13.5 3.5V8H18'/%3E%3C/svg%3E") center / contain no-repeat;
68
+ mask: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='black' stroke-width='1.7' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M7 3.5h6.5L18 8v11a1.5 1.5 0 0 1-1.5 1.5h-9.5A1.5 1.5 0 0 1 5.5 19V5A1.5 1.5 0 0 1 7 3.5z'/%3E%3Cpath d='M13.5 3.5V8H18'/%3E%3C/svg%3E") center / contain no-repeat;
148
69
  }
70
+ > .gallery-recent-face > .gallery-recent-list > .gallery-recent-item > .gallery-recent-document > .gallery-recent-name { flex: 1; min-width: 0; overflow: hidden; white-space: nowrap; text-overflow: ellipsis; font-size: 13px; color: var(--gallery-text); }
71
+ > .gallery-recent-face > .gallery-recent-list > .gallery-recent-item > .gallery-recent-document > .gallery-recent-when { flex: none; font-size: 12px; color: var(--gallery-faint); white-space: nowrap; font-variant-numeric: tabular-nums; }
72
+ > .gallery-recent-face > .gallery-recent-more { flex: none; margin: 0; padding-top: 6px; font-size: 12px; line-height: 18px; color: var(--gallery-faint); }
149
73
  > .gallery-recent-face > .gallery-recent-more[hidden] { display: none; }
74
+ /* No document, or no workspace: the cards' empty face in the middle. */
75
+ > .gallery-recent-face > .gallery-recent-empty { flex: 1; display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 4px; min-height: 0; text-align: center; }
76
+ > .gallery-recent-face > .gallery-recent-empty[hidden] { display: none; }
77
+ > .gallery-recent-face > .gallery-recent-empty > p { margin: 0; }
78
+ > .gallery-recent-face > .gallery-recent-empty > .gallery-recent-empty-picture { display: grid; place-items: center; width: 28px; height: 28px; margin-bottom: 6px; border-radius: 8px; background: var(--gallery-fill); color: var(--gallery-faint); }
79
+ > .gallery-recent-face > .gallery-recent-empty > .gallery-recent-empty-picture > svg { width: 16px; height: 16px; }
80
+ > .gallery-recent-face > .gallery-recent-empty > .gallery-recent-line { font-size: 13.5px; line-height: 20px; font-weight: 600; color: var(--gallery-text); }
81
+ > .gallery-recent-face > .gallery-recent-empty > .gallery-recent-hint { font-size: 12px; line-height: 18px; color: var(--gallery-faint); }
150
82
  }
151
- /* On a custom page the face is the card's: as high as what the card holds inside its padding, and a
152
- container of that height, so that a low card (two rows of cells) says it lists nothing in its words
153
- alone, the picture over them left out (it would not fit under the head). */
154
- .gallery-card > [data-doc-component="gallery/recent"] { height: 100%; container-type: size; }
155
- @container (max-height: 150px) {
156
- [data-doc-component="gallery/recent"] > .gallery-recent-face > .gallery-recent-line { padding-block: 0; }
157
- [data-doc-component="gallery/recent"] > .gallery-recent-face > .gallery-recent-line::before { display: none; }
158
- }
83
+ /* On a custom page the face fills the card the board frames. */
84
+ .gallery-card > [data-doc-component="gallery/recent"] { height: 100%; }
85
+ .gallery-card > [data-doc-component="gallery/recent"] > .gallery-recent-face { height: 100%; }
@@ -4,7 +4,7 @@ A card for a custom page (its places are `page`, its needs `workspace`): the doc
4
4
 
5
5
  ## How to write it
6
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 recent`: the instance is empty, `<div data-doc-component="gallery/recent"></div>`, everything on it drawn by its script. It has no settings and holds no data: there is nothing to fill in and nothing it writes. Sizes: 4 × 5 (the default), 4 × 2, 4 × 4 and 4 × 6; the list scrolls inside the card.
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 recent`: the instance is empty, `<div data-doc-component="gallery/recent"></div>`, everything on it drawn by its script. It has no settings and holds no data: there is nothing to fill in and nothing it writes. Sizes: 4 × 4 (the default), 4 × 2 (the last three, no groups) and 4 × 6 are the ones its menu lists; it is 4 wide and any height from 2 to 8 cells. As many whole rows as the card holds, and how many more there are under them.
8
8
 
9
9
  ## What the user does
10
10
 
@@ -12,4 +12,4 @@ Clicks a document: it opens. The list follows by itself: a document written, ren
12
12
 
13
13
  ## How it looks
14
14
 
15
- 最近编辑 beside a clock's chip on the top line, how many were edited today at its end (今天 3 篇), then a row a document as the sidebar draws one, its time muted at its end, as many whole rows as the card holds, a muted line under them saying how many more are below (还有 3 篇); 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. With no document it says 还没有文档. In an exported file, which has no workspace to read, it says the list shows when the page is opened in Gallery. The script runs with the rights of the page's own scripts, as any block's does.
15
+ In Gallery 风格's look (the kit's card tokens, light and dark): a head of a small gray chip and a title, its end clear of the card's grip; one hero; the rest small and gray; the accent on the data and on today alone. Its head is a clock's chip, 最近编辑 and how many were edited today; then rows like the sidebar's, grouped as 今天, 昨天, 本周 and 更早, each the document's icon, its title and its time at its end (12 分钟前, then the hour; yesterday's hour; this week's weekday, 周二; earlier ones the date). A row under the pointer takes the hover's gray. No document yet: it says so in the middle.
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "id": "gallery/static",
3
3
  "apiVersion": 1,
4
- "version": "1.2.0",
4
+ "version": "2.0.0",
5
5
  "name": { "zh": "静态卡片", "en": "Static card" },
6
6
  "description": { "zh": "放一段任意的 HTML,只展示,不能在页面上改", "en": "Any HTML, shown as it is: nothing on it changes in the page" },
7
7
  "words": "jingtaikapian jingtai kapian static html card 静态 卡片 展示 内容",
@@ -9,5 +9,5 @@
9
9
  "content": { "at": ":scope > div", "edit": "none" }
10
10
  },
11
11
  "places": ["page"],
12
- "card": { "sizes": [[4, 2], [2, 1], [2, 2], [4, 1], [4, 3], [4, 4], [6, 2], [6, 4], [8, 4], [12, 2], [12, 4]], "min": { "w": 1, "h": 1 }, "max": { "w": 12, "h": 24 }, "resize": true }
12
+ "card": { "sizes": [[4, 4], [4, 2], [8, 2], [2, 2], [4, 1], [2, 1]], "min": { "w": 1, "h": 1 }, "max": { "w": 12, "h": 24 }, "resize": true }
13
13
  }