@heycys/gallery 0.1.1 → 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (473) hide show
  1. package/THIRD-PARTY-NOTICES.md +2 -2
  2. package/browser/editor/components/align.mjs +58 -0
  3. package/browser/editor/components/code/index.mjs +1 -1
  4. package/browser/editor/components/columns/page.mjs +4 -4
  5. package/browser/editor/components/embed/index.mjs +2 -2
  6. package/browser/editor/components/embed/page.mjs +1 -1
  7. package/browser/editor/components/file/page.mjs +4 -4
  8. package/browser/editor/components/flowchart/add.mjs +7 -6
  9. package/browser/editor/components/flowchart/page.mjs +1 -1
  10. package/browser/editor/components/heading/index.mjs +7 -6
  11. package/browser/editor/components/icons.mjs +11 -0
  12. package/browser/editor/components/image/crop.mjs +6 -9
  13. package/browser/editor/components/image/index.mjs +2 -0
  14. package/browser/editor/components/image/page.mjs +172 -90
  15. package/browser/editor/components/installed/index.mjs +15 -4
  16. package/browser/editor/components/installed/page.mjs +103 -25
  17. package/browser/editor/components/installed/served.mjs +6 -5
  18. package/browser/editor/components/instances.mjs +18 -0
  19. package/browser/editor/components/list/page.mjs +3 -6
  20. package/browser/editor/components/media/icons.mjs +13 -8
  21. package/browser/editor/components/media/page.mjs +5 -3
  22. package/browser/editor/components/media/toolbar.mjs +12 -3
  23. package/browser/editor/components/paragraph/index.mjs +4 -3
  24. package/browser/editor/components/registry.mjs +30 -9
  25. package/browser/editor/components/table/index.mjs +61 -2
  26. package/browser/editor/components/table/page.mjs +1 -1
  27. package/browser/editor/page/after/index.mjs +288 -0
  28. package/browser/editor/page/align.mjs +91 -0
  29. package/browser/editor/page/annotate/card.mjs +3 -6
  30. package/browser/editor/page/autosave.mjs +310 -37
  31. package/browser/editor/page/beside.mjs +5 -6
  32. package/browser/editor/page/block-menu/index.mjs +6 -3
  33. package/browser/editor/page/blocks.mjs +3 -1
  34. package/browser/editor/page/board/client.mjs +57 -0
  35. package/browser/editor/page/board/hint.mjs +182 -0
  36. package/browser/editor/page/board/history.mjs +119 -0
  37. package/browser/editor/page/board/index.mjs +1059 -0
  38. package/browser/editor/page/board/motion.mjs +177 -0
  39. package/browser/editor/page/board/settings.mjs +210 -0
  40. package/browser/editor/page/caret.mjs +1 -1
  41. package/browser/editor/page/changes/bar.mjs +6 -14
  42. package/browser/editor/page/changes/index.mjs +2 -2
  43. package/browser/editor/page/clipboard/import/html.mjs +29 -6
  44. package/browser/editor/page/clipboard/import/inline.mjs +32 -0
  45. package/browser/editor/page/clipboard/import/markdown.mjs +58 -13
  46. package/browser/editor/page/clipboard/import/read.mjs +6 -1
  47. package/browser/editor/page/clipboard/import/to-blocks.mjs +44 -12
  48. package/browser/editor/page/clipboard/import/yuque.mjs +622 -0
  49. package/browser/editor/page/clipboard/index.mjs +133 -15
  50. package/browser/editor/page/clipboard/own/blocks.mjs +13 -14
  51. package/browser/editor/page/clipboard/own/chart-keys.mjs +41 -28
  52. package/browser/editor/page/clipboard/own/describe.mjs +6 -2
  53. package/browser/editor/page/clipboard/own/selection.mjs +1 -1
  54. package/browser/editor/page/columns/index.mjs +48 -46
  55. package/browser/editor/page/commit.mjs +80 -22
  56. package/browser/editor/page/conflicts.mjs +7 -7
  57. package/browser/editor/page/core.mjs +34 -16
  58. package/browser/editor/page/custom-page.mjs +110 -0
  59. package/browser/editor/page/editor.mjs +71 -17
  60. package/browser/editor/page/emoji-picker/styles.mjs +7 -12
  61. package/browser/editor/page/emoji-picker/upload.mjs +2 -2
  62. package/browser/editor/page/handle/index.mjs +5 -8
  63. package/browser/editor/page/history.mjs +41 -6
  64. package/browser/editor/page/insert/index.mjs +20 -22
  65. package/browser/editor/page/links/index.mjs +5 -3
  66. package/browser/editor/page/links/pages.mjs +27 -9
  67. package/browser/editor/page/look.mjs +54 -3
  68. package/browser/editor/page/margin.mjs +18 -3
  69. package/browser/editor/page/media-menu/index.mjs +6 -7
  70. package/browser/editor/page/menu.mjs +33 -14
  71. package/browser/editor/page/notices.mjs +2 -2
  72. package/browser/editor/page/page-objects.mjs +9 -2
  73. package/browser/editor/page/panel.mjs +4 -9
  74. package/browser/editor/page/present-links.mjs +15 -5
  75. package/browser/editor/page/present-shell.mjs +63 -0
  76. package/browser/editor/page/resize/index.mjs +42 -29
  77. package/browser/editor/page/selection/index.mjs +10 -2
  78. package/browser/editor/page/served.mjs +14 -0
  79. package/browser/editor/page/session.mjs +48 -4
  80. package/browser/editor/page/slash-menu/index.mjs +3 -3
  81. package/browser/editor/page/table/binding.mjs +87 -0
  82. package/browser/editor/page/table/cells.mjs +102 -46
  83. package/browser/editor/page/table/index.mjs +24 -9
  84. package/browser/editor/page/table/pictures.mjs +299 -0
  85. package/browser/editor/page/table/views.mjs +103 -0
  86. package/browser/editor/page/table/widths.mjs +82 -10
  87. package/browser/editor/page/text-select/index.mjs +26 -12
  88. package/browser/editor/page/todo-writes.mjs +75 -0
  89. package/browser/editor/page/typing/index.mjs +97 -15
  90. package/browser/editor/page/typing/leave.mjs +19 -5
  91. package/browser/editor/page/ui.mjs +13 -0
  92. package/browser/shared/block-packs.mjs +419 -0
  93. package/browser/shared/board-places.mjs +224 -0
  94. package/browser/shared/card-size.mjs +59 -0
  95. package/browser/shared/colors.mjs +3 -2
  96. package/browser/shared/component-catalog.mjs +330 -46
  97. package/browser/shared/component-source.mjs +39 -0
  98. package/browser/shared/components/heading.mjs +2 -1
  99. package/browser/shared/components/index.mjs +12 -3
  100. package/browser/shared/components/installed.mjs +35 -3
  101. package/browser/shared/components/page.mjs +20 -8
  102. package/browser/shared/components/paragraph.mjs +8 -1
  103. package/browser/shared/components/state.mjs +5 -1
  104. package/browser/shared/components/table.mjs +1 -0
  105. package/browser/shared/document-look.mjs +10 -5
  106. package/browser/shared/drafts.mjs +432 -0
  107. package/browser/shared/emoji/line-icons.mjs +37 -0
  108. package/browser/shared/extension-sidebar.mjs +126 -0
  109. package/browser/shared/extensions.mjs +79 -0
  110. package/browser/shared/file-table.mjs +101 -0
  111. package/browser/shared/http.mjs +9 -0
  112. package/browser/shared/i18n/en.mjs +330 -27
  113. package/browser/shared/json-layout.mjs +47 -0
  114. package/browser/shared/net-cache.mjs +133 -0
  115. package/browser/shared/net-keys.mjs +32 -0
  116. package/browser/shared/net-policy.mjs +177 -0
  117. package/browser/shared/outline-shape.mjs +128 -0
  118. package/browser/shared/outline.mjs +359 -67
  119. package/browser/shared/pack-manifest.mjs +88 -0
  120. package/browser/shared/page-address.mjs +6 -3
  121. package/browser/shared/page-cards.mjs +308 -0
  122. package/browser/shared/page-links.mjs +69 -6
  123. package/browser/shared/pages.mjs +500 -0
  124. package/browser/shared/paths.mjs +6 -0
  125. package/browser/shared/pinyin.mjs +92 -0
  126. package/browser/shared/present-step.mjs +17 -0
  127. package/browser/shared/preview-server.mjs +3 -7
  128. package/browser/shared/session.mjs +8 -1
  129. package/browser/shared/shipped-blocks.mjs +299 -0
  130. package/browser/shared/sidebar-head.mjs +70 -0
  131. package/browser/shared/table-chart.mjs +33 -1
  132. package/browser/shared/todos.mjs +83 -0
  133. package/browser/shared/user-directory.mjs +24 -0
  134. package/browser/shared/versions.mjs +14 -0
  135. package/browser/shared/web-links.mjs +139 -0
  136. package/browser/shared/workspace-columns.mjs +120 -0
  137. package/browser/shared/workspace-name.mjs +154 -0
  138. package/browser/shared/workspace-query.mjs +125 -0
  139. package/browser/shared/workspace-registry.mjs +272 -0
  140. package/browser/shared/workspace.mjs +171 -20
  141. package/dist/chunk-2OHANJ6Q.mjs +2 -0
  142. package/dist/chunk-3MBRL2PM.mjs +16 -0
  143. package/dist/chunk-4OKWZY5E.mjs +2 -0
  144. package/dist/chunk-4OZWXZE5.mjs +5 -0
  145. package/dist/chunk-5K44HLTZ.mjs +2 -0
  146. package/dist/{chunk-5ZKJ3H4P.mjs → chunk-5XA2ZBAE.mjs} +3 -3
  147. package/dist/{chunk-4FS7Z7WR.mjs → chunk-67N2QJYT.mjs} +1 -1
  148. package/dist/chunk-6KBYRA2C.mjs +2 -0
  149. package/dist/chunk-6N3PX4XX.mjs +8 -0
  150. package/dist/{chunk-V5JTW2LH.mjs → chunk-6QBHU4DF.mjs} +1 -1
  151. package/dist/chunk-7JDX4E65.mjs +13 -0
  152. package/dist/chunk-7M2BQQGZ.mjs +2 -0
  153. package/dist/chunk-7OG26PGF.mjs +2 -0
  154. package/dist/chunk-AHN3NFKJ.mjs +3 -0
  155. package/dist/chunk-ALZ6ZENZ.mjs +3 -0
  156. package/dist/chunk-AR5D57ZD.mjs +170 -0
  157. package/dist/{chunk-W3BGBJQW.mjs → chunk-BFJGHSQN.mjs} +1 -1
  158. package/dist/{chunk-LS4F7JUM.mjs → chunk-BZ5RAF7L.mjs} +1 -1
  159. package/dist/chunk-CMA72MAG.mjs +2 -0
  160. package/dist/{chunk-LCTHTZIL.mjs → chunk-DAZL73VK.mjs} +91 -91
  161. package/dist/{chunk-Y6RLRPG3.mjs → chunk-DJISHPUL.mjs} +1 -1
  162. package/dist/chunk-DR73Y2UJ.mjs +3 -0
  163. package/dist/{chunk-FDLXYYG4.mjs → chunk-EAIFITAV.mjs} +1 -1
  164. package/dist/{chunk-TMYZB6AV.mjs → chunk-EKNHM3P4.mjs} +1 -1
  165. package/dist/chunk-EP25HDAJ.mjs +2 -0
  166. package/dist/{chunk-GB5SOYQJ.mjs → chunk-ERLAIBOA.mjs} +2 -2
  167. package/dist/chunk-EURLTOTZ.mjs +4 -0
  168. package/dist/chunk-F4ZA6JRZ.mjs +3 -0
  169. package/dist/chunk-F6HVDZR4.mjs +2 -0
  170. package/dist/chunk-FDMAXMQA.mjs +2 -0
  171. package/dist/chunk-FETSREUN.mjs +5 -0
  172. package/dist/chunk-GHOYKMQ3.mjs +4 -0
  173. package/dist/{chunk-2B5E4CDJ.mjs → chunk-GPIWQ4X4.mjs} +1 -1
  174. package/dist/chunk-HDWTZ763.mjs +12 -0
  175. package/dist/chunk-HPOI4ZX7.mjs +6 -0
  176. package/dist/{chunk-BGGDRNYQ.mjs → chunk-HXG7EOPJ.mjs} +1 -1
  177. package/dist/chunk-IA4PSIMD.mjs +2 -0
  178. package/dist/{chunk-E7LWZRXY.mjs → chunk-ITOH5EGO.mjs} +1 -1
  179. package/dist/chunk-IV64FFI4.mjs +2 -0
  180. package/dist/chunk-J43Z6LSS.mjs +2 -0
  181. package/dist/chunk-J5PUIV3Y.mjs +4 -0
  182. package/dist/chunk-JA7G53PC.mjs +2 -0
  183. package/dist/chunk-JEUK3ZO7.mjs +2 -0
  184. package/dist/chunk-JLTZF4LA.mjs +2 -0
  185. package/dist/chunk-JZT7I2OJ.mjs +2 -0
  186. package/dist/chunk-K5XATEOO.mjs +2 -0
  187. package/dist/chunk-L2SUIS5S.mjs +2 -0
  188. package/dist/chunk-L7UP52JO.mjs +2 -0
  189. package/dist/chunk-LM4XFQHZ.mjs +2 -0
  190. package/dist/chunk-MN7BZL4R.mjs +2 -0
  191. package/dist/chunk-MTYYHM2G.mjs +15 -0
  192. package/dist/chunk-MXUBKDRO.mjs +15 -0
  193. package/dist/chunk-NAMN3RAF.mjs +2 -0
  194. package/dist/{chunk-SYGN7GLU.mjs → chunk-OEXWRJME.mjs} +1 -1
  195. package/dist/chunk-OFHXGWOX.mjs +2 -0
  196. package/dist/chunk-ORID3AE7.mjs +166 -0
  197. package/dist/chunk-PAREWQGB.mjs +4 -0
  198. package/dist/chunk-PGDE24N5.mjs +2 -0
  199. package/dist/chunk-POTA2FV4.mjs +2 -0
  200. package/dist/chunk-PUOQ65NC.mjs +2 -0
  201. package/dist/chunk-Q4UEPUWF.mjs +2 -0
  202. package/dist/chunk-QE5RG76S.mjs +549 -0
  203. package/dist/chunk-R2ZDLJYT.mjs +10 -0
  204. package/dist/{chunk-7DTINW6U.mjs → chunk-SQ6Y2ZMA.mjs} +2 -2
  205. package/dist/chunk-SWUTTZCN.mjs +2 -0
  206. package/dist/chunk-TANZRINB.mjs +2 -0
  207. package/dist/chunk-TR7TWGHB.mjs +2 -0
  208. package/dist/chunk-U5XL7D6A.mjs +3 -0
  209. package/dist/{chunk-XNROSH2T.mjs → chunk-U7NZI6N4.mjs} +2 -2
  210. package/dist/chunk-UGWMMEJ5.mjs +15 -0
  211. package/dist/chunk-UJQJKNGK.mjs +2 -0
  212. package/dist/chunk-UYVCQK3H.mjs +22 -0
  213. package/dist/chunk-VFX2KNHP.mjs +4 -0
  214. package/dist/chunk-VS7JIGJW.mjs +24 -0
  215. package/dist/chunk-W7665ZEC.mjs +6 -0
  216. package/dist/chunk-WQDQWCX5.mjs +2 -0
  217. package/dist/chunk-YI43RG4P.mjs +2 -0
  218. package/dist/chunk-YLPSMDIS.mjs +5 -0
  219. package/dist/chunk-YNAWBAYN.mjs +3 -0
  220. package/dist/chunk-YROX2O22.mjs +2 -0
  221. package/dist/chunk-ZDLPUOAG.mjs +6 -0
  222. package/dist/{chunk-IVDLMMBD.mjs → chunk-ZHEHPMBK.mjs} +1 -1
  223. package/dist/chunk-ZQS6H473.mjs +16 -0
  224. package/dist/chunk-ZTHICSSF.mjs +2 -0
  225. package/dist/chunk-ZWWC4KLF.mjs +20 -0
  226. package/dist/cli.mjs +1 -1
  227. package/dist/server.mjs +1 -1
  228. package/dist/{chunk-U6KNPJPR.mjs → update-fetch.mjs} +1 -1
  229. package/dist/worker.mjs +1 -1
  230. package/kit/board.css +95 -0
  231. package/kit/board.js +250 -0
  232. package/kit/charts.js +5 -71
  233. package/kit/code.js +17 -17
  234. package/kit/report.css +335 -18
  235. package/kit/runtime.js +1638 -125
  236. package/kit/state.js +10 -1
  237. package/kit/tables.js +130 -43
  238. package/kit/ui.js +79 -35
  239. package/package.json +2 -1
  240. package/packs/gallery/card/component.json +14 -0
  241. package/packs/gallery/card/example.html +10 -0
  242. package/packs/gallery/card/preview.svg +1 -0
  243. package/packs/gallery/card/style.css +6 -0
  244. package/packs/gallery/card/template.html +6 -0
  245. package/packs/gallery/card/writing.md +14 -0
  246. package/packs/gallery/chart-card/component.json +15 -0
  247. package/packs/gallery/chart-card/example.html +14 -0
  248. package/packs/gallery/chart-card/kit.js +130 -0
  249. package/packs/gallery/chart-card/preview.svg +1 -0
  250. package/packs/gallery/chart-card/style.css +42 -0
  251. package/packs/gallery/chart-card/template.html +13 -0
  252. package/packs/gallery/chart-card/writing.md +20 -0
  253. package/packs/gallery/chart-view/component.json +20 -0
  254. package/packs/gallery/chart-view/example.html +13 -0
  255. package/packs/gallery/chart-view/kit.js +355 -0
  256. package/packs/gallery/chart-view/preview.svg +1 -0
  257. package/packs/gallery/chart-view/style.css +94 -0
  258. package/packs/gallery/chart-view/template.html +3 -0
  259. package/packs/gallery/chart-view/writing.md +22 -0
  260. package/packs/gallery/countdown/component.json +18 -0
  261. package/packs/gallery/countdown/example.html +3 -0
  262. package/packs/gallery/countdown/kit.js +216 -0
  263. package/packs/gallery/countdown/preview.svg +1 -0
  264. package/packs/gallery/countdown/style.css +118 -0
  265. package/packs/gallery/countdown/template.html +3 -0
  266. package/packs/gallery/countdown/writing.md +22 -0
  267. package/packs/gallery/habit/component.json +14 -0
  268. package/packs/gallery/habit/example.html +3 -0
  269. package/packs/gallery/habit/kit.js +334 -0
  270. package/packs/gallery/habit/preview.svg +1 -0
  271. package/packs/gallery/habit/style.css +174 -0
  272. package/packs/gallery/habit/template.html +3 -0
  273. package/packs/gallery/habit/writing.md +21 -0
  274. package/packs/gallery/heatmap/component.json +18 -0
  275. package/packs/gallery/heatmap/example.html +3 -0
  276. package/packs/gallery/heatmap/kit.js +513 -0
  277. package/packs/gallery/heatmap/preview.svg +1 -0
  278. package/packs/gallery/heatmap/style.css +189 -0
  279. package/packs/gallery/heatmap/template.html +3 -0
  280. package/packs/gallery/heatmap/writing.md +21 -0
  281. package/packs/gallery/kanban/component.json +18 -0
  282. package/packs/gallery/kanban/example.html +12 -0
  283. package/packs/gallery/kanban/kit.js +540 -0
  284. package/packs/gallery/kanban/preview.svg +1 -0
  285. package/packs/gallery/kanban/style.css +212 -0
  286. package/packs/gallery/kanban/template.html +3 -0
  287. package/packs/gallery/kanban/writing.md +20 -0
  288. package/packs/gallery/metric/component.json +22 -0
  289. package/packs/gallery/metric/example.html +15 -0
  290. package/packs/gallery/metric/kit.js +248 -0
  291. package/packs/gallery/metric/preview.svg +1 -0
  292. package/packs/gallery/metric/style.css +92 -0
  293. package/packs/gallery/metric/template.html +3 -0
  294. package/packs/gallery/metric/writing.md +23 -0
  295. package/packs/gallery/note/component.json +14 -0
  296. package/packs/gallery/note/example.html +3 -0
  297. package/packs/gallery/note/kit.js +129 -0
  298. package/packs/gallery/note/preview.svg +1 -0
  299. package/packs/gallery/note/style.css +97 -0
  300. package/packs/gallery/note/template.html +3 -0
  301. package/packs/gallery/note/writing.md +18 -0
  302. package/packs/gallery/pack.json +8 -0
  303. package/packs/gallery/recent/component.json +13 -0
  304. package/packs/gallery/recent/example.html +1 -0
  305. package/packs/gallery/recent/kit.js +293 -0
  306. package/packs/gallery/recent/preview.svg +1 -0
  307. package/packs/gallery/recent/style.css +85 -0
  308. package/packs/gallery/recent/template.html +1 -0
  309. package/packs/gallery/recent/writing.md +15 -0
  310. package/packs/gallery/static/component.json +13 -0
  311. package/packs/gallery/static/example.html +11 -0
  312. package/packs/gallery/static/preview.svg +1 -0
  313. package/packs/gallery/static/style.css +171 -0
  314. package/packs/gallery/static/template.html +1 -0
  315. package/packs/gallery/static/writing.md +18 -0
  316. package/packs/gallery/stats/component.json +13 -0
  317. package/packs/gallery/stats/example.html +1 -0
  318. package/packs/gallery/stats/kit.js +347 -0
  319. package/packs/gallery/stats/preview.svg +1 -0
  320. package/packs/gallery/stats/style.css +73 -0
  321. package/packs/gallery/stats/template.html +1 -0
  322. package/packs/gallery/stats/writing.md +11 -0
  323. package/packs/gallery/today/component.json +12 -0
  324. package/packs/gallery/today/example.html +1 -0
  325. package/packs/gallery/today/kit.js +220 -0
  326. package/packs/gallery/today/preview.svg +1 -0
  327. package/packs/gallery/today/style.css +149 -0
  328. package/packs/gallery/today/template.html +1 -0
  329. package/packs/gallery/today/writing.md +14 -0
  330. package/packs/gallery/todos/component.json +19 -0
  331. package/packs/gallery/todos/example.html +3 -0
  332. package/packs/gallery/todos/kit.js +489 -0
  333. package/packs/gallery/todos/preview.svg +1 -0
  334. package/packs/gallery/todos/style.css +214 -0
  335. package/packs/gallery/todos/template.html +3 -0
  336. package/packs/gallery/todos/writing.md +30 -0
  337. package/packs/gallery/weather/component.json +19 -0
  338. package/packs/gallery/weather/example.html +3 -0
  339. package/packs/gallery/weather/kit.js +387 -0
  340. package/packs/gallery/weather/preview.svg +1 -0
  341. package/packs/gallery/weather/style.css +140 -0
  342. package/packs/gallery/weather/template.html +3 -0
  343. package/packs/gallery/weather/writing.md +26 -0
  344. package/packs/gallery-soft/countdown/component.json +18 -0
  345. package/packs/gallery-soft/countdown/example.html +3 -0
  346. package/packs/gallery-soft/countdown/kit.js +206 -0
  347. package/packs/gallery-soft/countdown/preview.svg +1 -0
  348. package/packs/gallery-soft/countdown/style.css +211 -0
  349. package/packs/gallery-soft/countdown/template.html +3 -0
  350. package/packs/gallery-soft/countdown/writing.md +24 -0
  351. package/packs/gallery-soft/habit/component.json +14 -0
  352. package/packs/gallery-soft/habit/example.html +3 -0
  353. package/packs/gallery-soft/habit/kit.js +366 -0
  354. package/packs/gallery-soft/habit/preview.svg +1 -0
  355. package/packs/gallery-soft/habit/style.css +251 -0
  356. package/packs/gallery-soft/habit/template.html +3 -0
  357. package/packs/gallery-soft/habit/writing.md +23 -0
  358. package/packs/gallery-soft/heatmap/component.json +18 -0
  359. package/packs/gallery-soft/heatmap/example.html +3 -0
  360. package/packs/gallery-soft/heatmap/kit.js +498 -0
  361. package/packs/gallery-soft/heatmap/preview.svg +1 -0
  362. package/packs/gallery-soft/heatmap/style.css +181 -0
  363. package/packs/gallery-soft/heatmap/template.html +3 -0
  364. package/packs/gallery-soft/heatmap/writing.md +23 -0
  365. package/packs/gallery-soft/note/component.json +14 -0
  366. package/packs/gallery-soft/note/example.html +3 -0
  367. package/packs/gallery-soft/note/kit.js +162 -0
  368. package/packs/gallery-soft/note/preview.svg +1 -0
  369. package/packs/gallery-soft/note/style.css +148 -0
  370. package/packs/gallery-soft/note/template.html +3 -0
  371. package/packs/gallery-soft/note/writing.md +20 -0
  372. package/packs/gallery-soft/pack.json +8 -0
  373. package/packs/gallery-soft/recent/component.json +13 -0
  374. package/packs/gallery-soft/recent/example.html +1 -0
  375. package/packs/gallery-soft/recent/kit.js +335 -0
  376. package/packs/gallery-soft/recent/preview.svg +1 -0
  377. package/packs/gallery-soft/recent/style.css +160 -0
  378. package/packs/gallery-soft/recent/template.html +1 -0
  379. package/packs/gallery-soft/recent/writing.md +17 -0
  380. package/packs/gallery-soft/static/component.json +13 -0
  381. package/packs/gallery-soft/static/example.html +12 -0
  382. package/packs/gallery-soft/static/preview.svg +1 -0
  383. package/packs/gallery-soft/static/style.css +186 -0
  384. package/packs/gallery-soft/static/template.html +1 -0
  385. package/packs/gallery-soft/static/writing.md +20 -0
  386. package/packs/gallery-soft/stats/component.json +13 -0
  387. package/packs/gallery-soft/stats/example.html +1 -0
  388. package/packs/gallery-soft/stats/kit.js +341 -0
  389. package/packs/gallery-soft/stats/preview.svg +1 -0
  390. package/packs/gallery-soft/stats/style.css +119 -0
  391. package/packs/gallery-soft/stats/template.html +1 -0
  392. package/packs/gallery-soft/stats/writing.md +13 -0
  393. package/packs/gallery-soft/today/component.json +12 -0
  394. package/packs/gallery-soft/today/example.html +1 -0
  395. package/packs/gallery-soft/today/kit.js +222 -0
  396. package/packs/gallery-soft/today/preview.svg +1 -0
  397. package/packs/gallery-soft/today/style.css +178 -0
  398. package/packs/gallery-soft/today/template.html +1 -0
  399. package/packs/gallery-soft/today/writing.md +16 -0
  400. package/packs/gallery-soft/todos/component.json +19 -0
  401. package/packs/gallery-soft/todos/example.html +3 -0
  402. package/packs/gallery-soft/todos/kit.js +527 -0
  403. package/packs/gallery-soft/todos/preview.svg +1 -0
  404. package/packs/gallery-soft/todos/style.css +212 -0
  405. package/packs/gallery-soft/todos/template.html +3 -0
  406. package/packs/gallery-soft/todos/writing.md +32 -0
  407. package/packs/gallery-soft/weather/component.json +19 -0
  408. package/packs/gallery-soft/weather/example.html +3 -0
  409. package/packs/gallery-soft/weather/kit.js +411 -0
  410. package/packs/gallery-soft/weather/preview.svg +1 -0
  411. package/packs/gallery-soft/weather/style.css +185 -0
  412. package/packs/gallery-soft/weather/template.html +3 -0
  413. package/packs/gallery-soft/weather/writing.md +28 -0
  414. package/release.json +12 -10
  415. package/sdk/doc-kit.d.ts +396 -5
  416. package/sdk/doc-state.d.ts +2 -0
  417. package/skill/SKILL.md +56 -23
  418. package/skill/references/block-script.md +140 -0
  419. package/skill/references/building-blocks.md +257 -0
  420. package/skill/references/extensions.md +59 -0
  421. package/skill/references/pages-and-data.md +225 -0
  422. package/skill/references/writing-html.md +8 -4
  423. package/skill/sdk/doc-kit.d.ts +396 -5
  424. package/skill/sdk/doc-state.d.ts +2 -0
  425. package/web/assets/index-BM_K-Auu.css +1 -0
  426. package/web/assets/index-DRslOBiv.js +15 -0
  427. package/web/index.html +2 -2
  428. package/dist/chunk-3HIRPVLU.mjs +0 -2
  429. package/dist/chunk-5MHMDLZD.mjs +0 -4
  430. package/dist/chunk-64K7IPLO.mjs +0 -255
  431. package/dist/chunk-6QXGZM36.mjs +0 -8
  432. package/dist/chunk-6RGJOMJP.mjs +0 -16
  433. package/dist/chunk-AJ73XJF3.mjs +0 -2
  434. package/dist/chunk-AUZGSZJH.mjs +0 -13
  435. package/dist/chunk-BFE45AKL.mjs +0 -2
  436. package/dist/chunk-BXO2ZY5P.mjs +0 -2
  437. package/dist/chunk-CEH4MRCC.mjs +0 -2
  438. package/dist/chunk-CY2FNNAB.mjs +0 -16
  439. package/dist/chunk-DFUDV4LX.mjs +0 -2
  440. package/dist/chunk-DKXG4XDG.mjs +0 -2
  441. package/dist/chunk-EZQ34M3F.mjs +0 -124
  442. package/dist/chunk-EZY3WC6Z.mjs +0 -15
  443. package/dist/chunk-FUKQNOQS.mjs +0 -9
  444. package/dist/chunk-JPOSLGOC.mjs +0 -6
  445. package/dist/chunk-JVHHHGEA.mjs +0 -3
  446. package/dist/chunk-L3QKH4OK.mjs +0 -26
  447. package/dist/chunk-LAE5NQ4B.mjs +0 -2
  448. package/dist/chunk-LEF6DRCK.mjs +0 -59
  449. package/dist/chunk-NO5NJCHO.mjs +0 -2
  450. package/dist/chunk-NQPVAU63.mjs +0 -2
  451. package/dist/chunk-NSKUTQ5J.mjs +0 -5
  452. package/dist/chunk-O35FIXRB.mjs +0 -2
  453. package/dist/chunk-P2CAZPDP.mjs +0 -3
  454. package/dist/chunk-PL6GHLGD.mjs +0 -15
  455. package/dist/chunk-QJIR2BLP.mjs +0 -6
  456. package/dist/chunk-QUPLVPB2.mjs +0 -7
  457. package/dist/chunk-R7BNENLY.mjs +0 -4
  458. package/dist/chunk-S6O4UHLC.mjs +0 -2
  459. package/dist/chunk-SGJWQKEI.mjs +0 -2
  460. package/dist/chunk-TX6JH7TR.mjs +0 -2
  461. package/dist/chunk-TYK6VNAB.mjs +0 -10
  462. package/dist/chunk-UALRNVSE.mjs +0 -4
  463. package/dist/chunk-V3HXVQEM.mjs +0 -2
  464. package/dist/chunk-V5VXUJKG.mjs +0 -2
  465. package/dist/chunk-VBXMADMP.mjs +0 -2
  466. package/dist/chunk-VNV55RUA.mjs +0 -2
  467. package/dist/chunk-VPD2PS35.mjs +0 -2
  468. package/dist/chunk-W4VKN3GF.mjs +0 -7
  469. package/dist/chunk-W5BXXPDJ.mjs +0 -3
  470. package/dist/chunk-XUNHRCOG.mjs +0 -6
  471. package/skill/references/building-components.md +0 -367
  472. package/web/assets/index-Bh74DfsV.css +0 -1
  473. package/web/assets/index-UW0RyFFt.js +0 -13
@@ -1,7 +1,8 @@
1
1
  import { t } from "../../shared/i18n/index.mjs";
2
2
  import { addressOn, elsewhere, fromFile, isPageAddress, mayBePage, pageAddress, workbenchHash } from "../../shared/page-address.mjs";
3
3
  import { inTrash, linkedPages, pageLinks } from "../../shared/page-links.mjs";
4
- import { PROTOCOL, VERSION } from "../../shared/session.mjs";
4
+ import { entryOfKey } from "../../shared/extension-sidebar.mjs";
5
+ import { SHELL, tell } from "./present-shell.mjs";
5
6
 
6
7
  // The links of a page shown in 演示视图 (?present: src/server/routes.mjs), which has no editor and whose
7
8
  // frame the presentation holds (src/workbench/app/features/present/). A link to a document or a block
@@ -13,7 +14,10 @@ import { PROTOCOL, VERSION } from "../../shared/session.mjs";
13
14
  // it is, with a word through it (the workbench's notice), and on another port what the list does not
14
15
  // hold (addressOn) is another program's, a web address like any. What the kit or the browser does with
15
16
  // a click stays theirs: an anchor, a link to save, a link of a target of its own, any click with a key
16
- // held.
17
+ // held. A workbench's address that names a web link of the sidebar, or an entry of an extension's column
18
+ // (#~<id>/<entry id>, one with an address), is a web address to the presentation: its page goes to a new
19
+ // tab; an entry the list does not hold, or one with no address, is said gone as a document is. (In a draft's presentation, a frame
20
+ // of its workspace's own server, the word goes to the workbench of another origin and a link keeps it around the page: present-shell.mjs.)
17
21
 
18
22
  const own = pageAddress(location.href)?.slug ?? null;
19
23
  const openTab = (address) => window.open(address, "_blank", "noopener");
@@ -21,20 +25,26 @@ const read = (route) => fetch(`/__gallery/workspace/${route}`).then((answer) =>
21
25
 
22
26
  function go({ slug, block }) {
23
27
  const fragment = block ? `#${encodeURIComponent(block)}` : "";
24
- if (slug !== own) location.assign(`/generated/${slug}.html?present${fragment}`);
28
+ if (slug !== own) location.assign(`/generated/${slug}.html?present${SHELL ? `&shell=${encodeURIComponent(SHELL)}` : ""}${fragment}`); // a draft's presentation keeps the workbench around it (present-shell.mjs)
25
29
  else if (block) dispatchEvent(new CustomEvent("doc-jump-request", { detail: { hash: fragment } })); // the kit's jump, a step of the history as a link #<block id> is
26
30
  }
27
31
 
28
32
  function sayGone(name, { trash = [] } = {}) {
29
33
  const text = inTrash(trash, name) ? t("这个页面已删除。") : t("没有找到这个页面。");
30
- window.parent.postMessage({ protocol: PROTOCOL, v: VERSION, type: "notice", slug: own, text }, location.origin);
34
+ tell("notice", { text });
31
35
  }
32
36
 
33
37
  async function follow(address) {
34
38
  if (!mayBePage(address)) return void openTab(address);
35
39
  const listed = await read("outline");
36
40
  const place = addressOn(address, listed?.reports ? pageLinks(linkedPages(listed.reports)) : null, location.origin);
37
- if (place) go(place);
41
+ const web = place && listed?.reports?.[place.slug]?.kind === "link" ? listed.reports[place.slug] : null;
42
+ const entry = !place && !elsewhere(address, location.origin) ? entryOfKey(listed?.extensions, workbenchHash(address) ?? "") : null;
43
+ if (web) {
44
+ if (/^https?:/.test(web.url ?? "")) openTab(web.url);
45
+ else sayGone(web.slug, listed);
46
+ } else if (place) go(place);
47
+ else if (entry?.url) openTab(entry.url);
38
48
  else if (isPageAddress(address) && !elsewhere(address, location.origin)) sayGone(pageAddress(address)?.slug ?? workbenchHash(address), listed ?? undefined);
39
49
  else openTab(address);
40
50
  }
@@ -0,0 +1,63 @@
1
+ import { pageAddress } from "../../shared/page-address.mjs";
2
+ import { KEEPS_KEYS, stepSection } from "../../shared/present-step.mjs";
3
+ import { PROTOCOL, PROTOCOLS, VERSION } from "../../shared/session.mjs";
4
+
5
+ // What a page shown in 演示视图 (?present: src/server/routes.mjs, no editor) says to the presentation around it and
6
+ // hears from it. The presentation of a document of this workspace is a frame of the same origin, which it reaches into (its
7
+ // scroll, its keys, its theme); that of a draft of another workspace (docs/workbench.md "Drafts of other workspaces") is a frame
8
+ // of that workspace's server, named by the page's address (?shell=<the workbench's origin>) as the editor's page names it
9
+ // (session.mjs): this page then asks its own server whether that is a Gallery server of this computer (GET
10
+ // /__gallery/workspace/shell) and talks to it alone once it is, holding what it says until then; one that is not hears nothing.
11
+ // It tells where the page is scrolled (`present-view`: { x, y }, with `ready` once the page can be spoken to) and the keys pressed
12
+ // in it that are the presentation's (`present-key`: { key, ctrlKey, metaKey, altKey, kept (a control holds the key), prevented }),
13
+ // and does what it is asked: `theme` (the workbench's, light or dark), `go-section` (上一节 / 下一节) and `scroll` ({ left, top }: the wheel). Every message is the session
14
+ // protocol's envelope (src/shared/session.mjs).
15
+
16
+ /** The origin of a workbench of another origin showing this page (?shell=<origin>), or null: this one's. */
17
+ export const SHELL = (() => {
18
+ const named = new URLSearchParams(location.search).get("shell");
19
+ return named && named !== location.origin ? named : null;
20
+ })();
21
+
22
+ const vouched = (origin) => fetch(`/__gallery/workspace/shell?origin=${encodeURIComponent(origin)}`, { cache: "no-store" })
23
+ .then((answer) => answer.json()).then((answer) => answer?.shell === true, () => false);
24
+
25
+ let parentOrigin = SHELL ? null : location.origin;
26
+ let held = SHELL ? [] : null;
27
+
28
+ /** Tell the presentation around the page (`window.parent`) something; held until its origin is vouched for, dropped when it is not. */
29
+ export function tell(type, fields = {}) {
30
+ if (window.parent === window) return;
31
+ if (held) return void held.push([type, fields]);
32
+ if (!parentOrigin) return;
33
+ window.parent.postMessage({ protocol: PROTOCOL, v: VERSION, type, slug: pageAddress(location.href)?.slug ?? "", ...fields }, parentOrigin);
34
+ }
35
+
36
+ function bridge() {
37
+ let frame = 0;
38
+ const view = (ready = false) => tell("present-view", { x: scrollX, y: scrollY, ...(ready ? { ready: true } : {}) });
39
+ addEventListener("scroll", () => { frame ||= requestAnimationFrame(() => { frame = 0; view(); }); }, { passive: true });
40
+ addEventListener("keydown", (event) => {
41
+ if (event.isComposing) return;
42
+ tell("present-key", { key: event.key, ctrlKey: event.ctrlKey, metaKey: event.metaKey, altKey: event.altKey, kept: Boolean(event.target?.closest?.(KEEPS_KEYS)), prevented: event.defaultPrevented });
43
+ });
44
+ addEventListener("message", (event) => {
45
+ const message = event.data;
46
+ if (event.source !== window.parent || event.origin !== parentOrigin || !PROTOCOLS.includes(message?.protocol) || message.v !== VERSION || message.type !== "command") return;
47
+ if (message.name === "theme") dispatchEvent(new CustomEvent("doc-theme-request", { detail: { theme: message.theme === "dark" ? "dark" : "light" } })); // the kit's ui.js
48
+ else if (message.name === "go-section") stepSection(window, message.direction > 0 ? 1 : -1);
49
+ else if (message.name === "scroll") scrollBy({ left: Number(message.left) || 0, top: Number(message.top) || 0 }); // the wheel over the presentation's ink
50
+ });
51
+ view(true);
52
+ }
53
+
54
+ if (SHELL && window.parent !== window) {
55
+ vouched(SHELL).then((ok) => {
56
+ const waiting = held;
57
+ held = null;
58
+ if (!ok) return;
59
+ parentOrigin = SHELL;
60
+ for (const [type, fields] of waiting) tell(type, fields);
61
+ bridge();
62
+ });
63
+ }
@@ -11,8 +11,9 @@ import { t } from "../../../shared/i18n/index.mjs";
11
11
 
12
12
  // Resizing chart cards and tables in the preview ("Sizes" in the kit's styles/sizes.css). With the pointer on the
13
13
  // right edge of a card or table, or on its bottom edge (a chart's plot height, a table's scroll
14
- // height), the cursor changes; dragging shows a blue line where the edge goes and the size that
15
- // makes, and letting go applies it as one undo step (Esc cancels). Widths are shares of the width
14
+ // height), the cursor changes; dragging shows a gray line where the edge goes (darker where it
15
+ // snaps) and the bottom notice says the size that makes while the drag lasts (no label beside the
16
+ // line: the user, 2026-11-07), and letting go applies it as one undo step (Esc cancels). Widths are shares of the width
16
17
  // the block stands in: the reading width, or its column's. A card's width snaps to the middle and
17
18
  // to the end; a centered card grows on both sides. A table's
18
19
  // width moves its own right end by as much as the pointer moves, also when the table is wider than
@@ -23,17 +24,19 @@ import { t } from "../../../shared/i18n/index.mjs";
23
24
  // height of its frame: shorter than its code, the code scrolls inside it, and the edge snaps to the
24
25
  // height that shows all of it (no height of its own). Letting go where the drag started changes
25
26
  // nothing. Anything that ends the press another way (the capture lost, the window losing the
26
- // focus, the page hidden) cancels it; the lines and the label belong to the drag (overlays.mjs). A
27
- // code block's bottom edge has no label: the line alone (where it snaps, the status line says after).
27
+ // focus, the page hidden) cancels it; the lines belong to the drag (overlays.mjs), and the notice it
28
+ // put up goes with it. Snapping takes the edge within SNAP (6px) of a place, little enough that a
29
+ // size near one can still be had (14px before 2026-11-07, which the user found too strong).
28
30
 
29
31
  const STYLE = `
30
32
  ${gestureLock("data-ge-resize=\"x\"", { cursor: "ew-resize" })}
31
33
  ${gestureLock("data-ge-resize=\"y\"", { cursor: "ns-resize" })}
32
- .ge-resize-line { position: fixed; left: 0; top: 0; z-index: ${Z.guide}; border-radius: 2px; background: rgb(151 197 241); pointer-events: none; }
33
- .ge-resize-label { position: fixed; left: 0; top: 0; z-index: ${Z.label}; padding: 2px 7px; border-radius: 5px; background: var(--doc-accent, #2678d8); color: #fff; font: 12px/18px var(--doc-sans-font, var(--doc-font, system-ui, sans-serif)); white-space: nowrap; pointer-events: none; }
34
+ .ge-resize-line { position: fixed; left: 0; top: 0; z-index: ${Z.guide}; border-radius: 1px; background: var(--ge-guide-hot); pointer-events: none; }
35
+ .ge-resize-line[data-snap] { background: var(--ge-guide-snap); }
34
36
  `;
35
37
  const GRAB = { inside: 3, outside: 8 }; // how near an edge the pointer takes it, inside and outside the block (px)
36
- const SNAP = 14; // px
38
+ const SNAP = 6; // px
39
+ const LIVE = 60000; // ms: the notice saying the size dragged to stays while the drag lasts (it is taken off when it ends)
37
40
  const MIN_WIDTH = 160; // px: the least a card's edge is dragged to (a table's is its columns' floors)
38
41
  // The sizes (name and range) are each component's description's (registry SIZES): the same ones the
39
42
  // server checks a size by.
@@ -45,11 +48,12 @@ const heightRange = (kind) => range(kind, heightOf(kind));
45
48
 
46
49
  /**
47
50
  * units: Map(id -> { kind }) from the edit map. active(): whether resizing may start.
48
- * look(element, { sizes }, select): the editor's undoable change of sizes. say(text): the status line.
51
+ * look(element, { sizes }, select): the editor's undoable change of sizes. say(text, kind, hold): the
52
+ * bottom notice; settle(): the notice taken off.
49
53
  * owns(node): whether a table's right and bottom edges are the table tools' (table/widths.mjs: a
50
54
  * click arms one, a drag then is this tool's, `startTable`).
51
55
  */
52
- export function createResize({ units, active, look, say, owns = () => false }) {
56
+ export function createResize({ units, active, look, say, settle = () => {}, owns = () => false }) {
53
57
  addStyle(STYLE);
54
58
  let hover = null; // { node, axis } under the pointer
55
59
  let drag = null;
@@ -134,12 +138,12 @@ export function createResize({ units, active, look, say, owns = () => false }) {
134
138
  const snaps = [{ x: table.press, label: t("原宽度"), keep: true }, { x: table.press + (box.width - table.width), label: t("铺满正文") }];
135
139
  const snap = snaps.find((candidate) => Math.abs(candidate.x - edge) <= SNAP);
136
140
  if (snap) edge = snap.x;
137
- if (snap?.keep) return { edge, label: snap.label, value: drag.before };
141
+ if (snap?.keep) return { edge, label: snap.label, value: drag.before, snapped: true };
138
142
  // Rounded up, so the frame is never narrower than where it was let go (at the floors, say).
139
143
  const share = Math.ceil(Math.max(range("table", SPAN).min, width(edge) / box.width) * 1000) / 1000;
140
144
  const label = snap?.label ?? (share > 1 ? t("超宽表 · 表宽 {0}px,横向滚动", Math.round(width(edge)))
141
145
  : edge <= narrowest + 0.5 ? t("最窄 · {0}%", Math.round(share * 100)) : `${Math.round(share * 100)}%`);
142
- return { edge, label, value: Math.abs(share - 1) < 0.005 ? "1" : String(Math.min(share, range("table", SPAN).max)) };
146
+ return { edge, label, value: Math.abs(share - 1) < 0.005 ? "1" : String(Math.min(share, range("table", SPAN).max)), snapped: Boolean(snap) };
143
147
  }
144
148
 
145
149
  // Where the edge may go and where it snaps: back where it started (no change), the middle (a
@@ -158,13 +162,13 @@ export function createResize({ units, active, look, say, owns = () => false }) {
158
162
  let edge = Math.min(Math.max(x, near), far);
159
163
  const snap = snaps.find((candidate) => Math.abs(candidate.x - edge) <= SNAP);
160
164
  if (snap) edge = snap.x;
161
- if (snap?.keep) return { edge, label: snap.label, value: drag.before };
165
+ if (snap?.keep) return { edge, label: snap.label, value: drag.before, snapped: true };
162
166
  const share = Math.round(Math.max(range(kind, SPAN).min, shareAt(edge)) * 1000) / 1000;
163
167
  const whole = Math.abs(share - 1) < 0.005;
164
168
  const label = snap?.label ?? `${Math.round(share * 100)}%${centered ? t(" · 居中") : ""}`;
165
169
  // A card at the whole width is the default.
166
170
  const value = whole ? (kind === "figure" && !centered ? null : "1") : String(Math.min(share, range(kind, SPAN).max));
167
- return { edge, label, value };
171
+ return { edge, label, value, snapped: Boolean(snap) };
168
172
  }
169
173
 
170
174
  // ---------- heights ----------
@@ -184,8 +188,8 @@ export function createResize({ units, active, look, say, owns = () => false }) {
184
188
  const header = rect.height - code.getBoundingClientRect().height;
185
189
  const whole = rect.height + (code.scrollHeight - code.clientHeight); // all its lines, no scrolling
186
190
  const height = Math.min(Math.max(y - rect.top, Math.min(whole, header + heightRange(kind).min)), whole);
187
- if (before !== null && Math.abs(rect.top + height - rect.bottom) <= SNAP / 2) return { edge: rect.bottom, label: t("原高度"), value: before };
188
- if (whole - height <= SNAP) return { edge: rect.top + whole, label: t("显示全部代码"), value: null };
191
+ if (before !== null && Math.abs(rect.top + height - rect.bottom) <= SNAP / 2) return { edge: rect.bottom, label: t("原高度"), value: before, snapped: true };
192
+ if (whole - height <= SNAP) return { edge: rect.top + whole, label: t("显示全部代码"), value: null, snapped: true };
189
193
  const frame = Math.round(height - header);
190
194
  return { edge: rect.top + header + frame, label: t("高 {0}px · 其余滚动查看", frame), value: `${frame}px` };
191
195
  }
@@ -194,19 +198,20 @@ export function createResize({ units, active, look, say, owns = () => false }) {
194
198
  const drawn = drawnHeight(svg);
195
199
  const scale = svg.getBoundingClientRect().height / drawn || 1;
196
200
  const floor = 160; // the least a chart is drawn at (a softer floor than the one a size is checked by)
197
- if (Math.abs(rect.bottom - y) <= SNAP) return { edge: rect.bottom, label: t("原高度"), value: before };
201
+ if (Math.abs(rect.bottom - y) <= SNAP) return { edge: rect.bottom, label: t("原高度"), value: before, snapped: true };
198
202
  // Level with a card beside it (in another column of its row): the bottoms meet.
199
203
  const beside = drag.beside.find((bottom) => Math.abs(bottom - y) <= SNAP);
200
204
  const height = Math.round(Math.min(Math.max(drawn + ((beside ?? y) - rect.bottom) / scale, floor), heightRange(kind).max));
201
205
  const edge = rect.bottom + (height - drawn) * scale;
202
- return { edge, label: beside !== undefined && Math.abs(edge - beside) < 1.5 ? t("与旁边对齐 · 图表高 {0}px", height) : t("图表高 {0}px", height), value: `${height}px` };
206
+ const level = beside !== undefined && Math.abs(edge - beside) < 1.5;
207
+ return { edge, label: level ? t("与旁边对齐 · 图表高 {0}px", height) : t("图表高 {0}px", height), value: `${height}px`, snapped: level };
203
208
  }
204
209
  const all = node.scrollHeight + (node.offsetHeight - node.clientHeight);
205
210
  let height = Math.min(Math.max(y - rect.top, heightRange(kind).min), all);
206
- if (Math.abs(rect.top + height - rect.bottom) <= SNAP / 2) return { edge: rect.bottom, label: t("原高度"), value: drag.before };
211
+ if (Math.abs(rect.top + height - rect.bottom) <= SNAP / 2) return { edge: rect.bottom, label: t("原高度"), value: drag.before, snapped: true };
207
212
  if (height >= all - 2) {
208
213
  const fits = all <= scrollHeight(node); // the default scroll area shows them all
209
- return { edge: rect.top + all, label: t("显示全部行"), value: fits ? null : "none" };
214
+ return { edge: rect.top + all, label: t("显示全部行"), value: fits ? null : "none", snapped: true };
210
215
  }
211
216
  height = Math.round(height);
212
217
  return { edge: rect.top + height, label: t("高 {0}px", height), value: `${height}px` };
@@ -231,6 +236,7 @@ export function createResize({ units, active, look, say, owns = () => false }) {
231
236
  const rect = node.getBoundingClientRect();
232
237
  drag = {
233
238
  node, axis, kind, name, before, rect,
239
+ press: { x: event.clientX, y: event.clientY },
234
240
  box: contentBox(node.parentElement),
235
241
  // A card's height snaps level with the cards beside it: the bottoms of those in the other columns of its row.
236
242
  beside: axis === "y" && kind === "figure" ? besideBottoms(node) : [],
@@ -243,19 +249,22 @@ export function createResize({ units, active, look, say, owns = () => false }) {
243
249
  press: event.clientX,
244
250
  atEnd: node.scrollLeft + node.clientWidth >= node.scrollWidth - 2,
245
251
  } : null,
246
- label: kind === "code" ? null : element("div", { class: "ge-resize-label" }),
247
252
  result: null,
253
+ told: null, // what the notice says now
248
254
  };
249
255
  const session = drag;
250
256
  session.lines = (session.centered ? [0, 1] : [0]).map(() => element("div", { class: "ge-resize-line" }));
251
- for (const part of [session.label, ...session.lines].filter(Boolean)) mount(own(part, "resize", { owner: node, alive: () => drag === session }));
257
+ for (const part of session.lines) mount(own(part, "resize", { owner: node, alive: () => drag === session }));
252
258
  note("resize", `start ${axis}`);
253
259
  document.documentElement.setPointerCapture?.(event.pointerId);
254
260
  update(event.clientX, event.clientY);
255
261
  }
256
262
 
263
+ // What is being resized, in the notice's words: 卡片 and 宽度, 表格 and 高度, 代码块 and 高度.
264
+ const what = (kind, axis) => [kind === "figure" ? t("卡片") : kind === "code" ? t("代码块") : t("表格"), axis === "x" ? t("宽度") : t("高度")];
265
+
257
266
  function update(x, y) {
258
- const { axis, rect, box, lines, label } = drag;
267
+ const { axis, kind, rect, box, lines } = drag;
259
268
  drag.result = axis === "x" ? widthAt(x) : heightAt(y);
260
269
  const { edge } = drag.result;
261
270
  if (axis === "x") {
@@ -264,24 +273,28 @@ export function createResize({ units, active, look, say, owns = () => false }) {
264
273
  width: "2px", height: `${Math.round(rect.height)}px`,
265
274
  transform: `translate(${Math.round((index ? mirror : edge) - 1)}px, ${Math.round(rect.top)}px)`,
266
275
  }));
267
- if (label) label.style.transform = `translate(${Math.round(Math.min(edge + 10, innerWidth - label.offsetWidth - 8))}px, ${Math.round(Math.max(8, y - 30))}px)`;
268
276
  } else {
269
277
  Object.assign(lines[0].style, { width: `${Math.round(rect.width)}px`, height: "2px", transform: `translate(${Math.round(rect.left)}px, ${Math.round(edge - 1)}px)` });
270
- if (label) label.style.transform = `translate(${Math.round(Math.min(x + 12, innerWidth - label.offsetWidth - 8))}px, ${Math.round(Math.min(edge + 8, innerHeight - 28))}px)`;
271
278
  }
272
- if (label) label.textContent = drag.result.label;
279
+ lines.forEach((line) => line.toggleAttribute("data-snap", Boolean(drag.result.snapped)));
280
+ // The size in the bottom notice once the pointer has moved (a press alone says nothing), said again
281
+ // only when it changes (a workbench is told each time).
282
+ if (!drag.told && Math.hypot(x - drag.press.x, y - drag.press.y) < 2) return;
283
+ const told = t("{0}{1}:{2}", ...what(kind, axis), drag.result.label);
284
+ if (told !== drag.told) say(told, "note", LIVE);
285
+ drag.told = told;
273
286
  }
274
287
 
275
288
  function finish(commit) {
276
289
  if (!drag) return;
277
- const { node, axis, kind, name, before, lines, label, result, table } = drag;
290
+ const { node, axis, kind, name, lines, result, table, told } = drag;
278
291
  note("resize", commit ? "released" : "cancelled");
279
292
  drag = null;
280
293
  lines.forEach((line) => line.remove());
281
- label?.remove();
294
+ if (told) settle(); // the size dragged to: what is said next (or nothing) replaces it
282
295
  setHover(null);
283
296
  if (commit && result && look(node, { sizes: { [name]: result.value } }, null)) {
284
- say(t("已调整{0}{1}:{2} · Ctrl+Z 撤销", kind === "figure" ? t("卡片") : kind === "code" ? t("代码块") : t("表格"), axis === "x" ? t("宽度") : t("高度"), result.label));
297
+ say(t("已调整{0}{1}:{2} · Ctrl+Z 撤销", ...what(kind, axis), result.label));
285
298
  // Scrolled to its end, a table stays so: its new end shows at the frame's edge, ready for the
286
299
  // next drag (after tables.js has laid it out again, on the next frame).
287
300
  if (table?.atEnd) requestAnimationFrame(() => requestAnimationFrame(() => { node.scrollLeft = node.scrollWidth; }));
@@ -322,6 +335,6 @@ export function createResize({ units, active, look, say, owns = () => false }) {
322
335
  setHover(null);
323
336
  },
324
337
  /** The editor's UI nodes to keep in the top layer when a modal dialog opens. */
325
- get nodes() { return drag ? [...drag.lines, drag.label].filter(Boolean) : []; },
338
+ get nodes() { return drag ? [...drag.lines] : []; },
326
339
  };
327
340
  }
@@ -5,6 +5,7 @@ import { createFills } from "../fills.mjs";
5
5
  import { FOLDED } from "../folded.mjs";
6
6
  import { describe, note, report } from "../overlays.mjs";
7
7
  import { t } from "../../../shared/i18n/index.mjs";
8
+ import { UNFILLED_ALONE } from "../../components/registry.mjs";
8
9
 
9
10
  // Selected blocks (docs/editor.md, "Selecting blocks"): a set of blocks, none inside another, in
10
11
  // document order. A box selection drawn from empty space gives blocks of one container
@@ -109,10 +110,17 @@ export function createSelection({ info, active, say, closeMenu, schedule }) {
109
110
  // The fills made to match the selection now: those of blocks no longer selected (or no longer on
110
111
  // the page) go at once; each selected block shown gets its fill where it is, reaching past it as
111
112
  // reachOf says, never into a neighbour's (roomOf). One that cannot be drawn takes all the fills
112
- // down (said once): better none than one in the wrong place.
113
+ // down (said once): better none than one in the wrong place. A kind whose own tools show it selected
114
+ // (UNFILLED_ALONE: the image with its picture, its corner grips and toolbar) draws no fill selected alone (the user, 2026-11-09: no pale
115
+ // blue over a picture clicked); among other blocks it is filled as they are.
116
+ const toolsShowIt = () => {
117
+ if (picked.length !== 1 || marked.length !== 0) return false;
118
+ const holds = UNFILLED_ALONE[picked[0].getAttribute?.("data-ge-unit-kind")];
119
+ return holds !== undefined && picked[0].querySelector?.(holds) !== null;
120
+ };
113
121
  function render() {
114
122
  try {
115
- halos.paint(hidden || !active() ? [] : [...picked, ...marked].filter(alive));
123
+ halos.paint(hidden || !active() || toolsShowIt() ? [] : [...picked, ...marked].filter(alive));
116
124
  } catch (error) {
117
125
  unpaint();
118
126
  report("selection fills", error);
@@ -0,0 +1,14 @@
1
+ // Where the page shows a file of the report's folder (assets/<file>): the server's asset route,
2
+ // which editor.mjs gives (serveFiles) once it knows the report. A picture in a table cell's text is
3
+ // shown there (components/table/ cellPicture). No imports: a component's index.mjs reads it while
4
+ // the registry is still being made.
5
+
6
+ let fileUrl = (path) => path;
7
+
8
+ /** Where the page shows a file of the report's folder from now on: `urlOf(path)`. */
9
+ export const serveFiles = (urlOf) => {
10
+ fileUrl = urlOf;
11
+ };
12
+
13
+ /** Where the page shows `path`, a file of the report's folder (assets/<file>). */
14
+ export const servedFile = (path) => fileUrl(path);
@@ -5,7 +5,15 @@ import { lookOf, lookOfElement } from "../../shared/document-look.mjs";
5
5
  // tells the workbench its state, never the report's content. Nothing happens when the page is not
6
6
  // embedded. The protocol is src/shared/session.mjs; how a workbench uses it, docs/workbench.md.
7
7
  //
8
- // A message counts only from the parent window, of this origin and protocol. A command names the
8
+ // A workbench of another workspace shows a draft of this one from its own origin (docs/workbench.md
9
+ // "Drafts of other workspaces"), naming that origin in the frame's address (?shell=<origin>): the page
10
+ // then asks its own server whether that is a Gallery server of this computer (GET
11
+ // /__gallery/workspace/shell: on the registry, running, its token and process as it announces them),
12
+ // and talks to it alone once it is, holding what it says until then; one that is not hears nothing and
13
+ // is heard by nothing, so that no other page of this computer drives a document by framing it. Going,
14
+ // such a page says `bye` (the workbench of another origin cannot see it go).
15
+ //
16
+ // A message counts only from the parent window, of this origin (or the shell's, vouched for) and protocol. A command names the
9
17
  // report it is meant for: one for another report (the iframe went to another page meanwhile) is
10
18
  // refused. Every command gets exactly one reply, once it is done. Besides the editor's commands the
11
19
  // session itself answers five: `theme` (show the report light or dark, or as the reader chose, without
@@ -14,10 +22,20 @@ import { lookOf, lookOfElement } from "../../shared/document-look.mjs";
14
22
  // `scroll-top` (back to the top when scrolled down) and `close-card` (the detail card on top closes as a
15
23
  // press on its backdrop closes it: the workbench asks on a press on its own bars, or Esc there, while
16
24
  // the page says a card is open, `card` in what it sends). A card stands in the middle of the
17
- // workbench's window, not of the frame (centreCards, below).
25
+ // workbench's window, not of the frame (centreCards, below). A block's 允许访问 (doc-net-consent, the kit's)
26
+ // is sent as `consent`.
18
27
 
19
28
  /** A page opened in a frame on its own (?solo), not as the workbench's report: no session, its own notices. */
20
29
  export const SOLO = new URLSearchParams(location.search).has("solo");
30
+ /** The origin of a workbench of another workspace showing this page (?shell=<origin>), or null: this one's. */
31
+ const SHELL = (() => {
32
+ const named = new URLSearchParams(location.search).get("shell");
33
+ return named && named !== location.origin ? named : null;
34
+ })();
35
+
36
+ // Whether this page's server vouches for the workbench at `origin` (GET /__gallery/workspace/shell).
37
+ const vouched = (origin) => fetch(`/__gallery/workspace/shell?origin=${encodeURIComponent(origin)}`, { cache: "no-store" })
38
+ .then((answer) => answer.json()).then((answer) => answer?.shell === true, () => false);
21
39
 
22
40
  /**
23
41
  * slug: the report's; snapshot(): { title, state } (state: STATE_FLAGS of src/shared/session.mjs);
@@ -38,11 +56,28 @@ export const SOLO = new URLSearchParams(location.search).has("solo");
38
56
  export function connectWorkbench({ slug, snapshot, commands, modals }) {
39
57
  if (window.parent === window || SOLO) return null;
40
58
  centreCards(modals);
59
+ // The workbench's origin: this one's, or the shell's once this page's server vouched for it (null till
60
+ // then: what the page says is held, and is dropped when it does not).
61
+ let parentOrigin = SHELL ? null : location.origin;
62
+ let held = SHELL ? [] : null;
63
+ if (SHELL) {
64
+ vouched(SHELL).then((ok) => {
65
+ const waiting = held;
66
+ held = null;
67
+ if (!ok) return;
68
+ parentOrigin = SHELL;
69
+ for (const [type, fields, protocols] of waiting) send(type, fields, protocols);
70
+ // A workbench of another origin sees no pagehide of this page: it is told.
71
+ addEventListener("pagehide", () => send("bye", {}), { once: true });
72
+ });
73
+ }
41
74
  // The id the workbench speaks (src/shared/session.mjs, OLD_PROTOCOL): null until its first command,
42
75
  // and meanwhile every message goes under both, so that a workbench of either version hears it.
43
76
  let spoken = null;
44
77
  const send = (type, fields, protocols = spoken ? [spoken] : [PROTOCOL, OLD_PROTOCOL]) => {
45
- for (const protocol of protocols) window.parent.postMessage({ protocol, v: VERSION, type, slug, ...fields }, location.origin);
78
+ if (held) return void held.push([type, fields, protocols]);
79
+ if (!parentOrigin) return;
80
+ for (const protocol of protocols) window.parent.postMessage({ protocol, v: VERSION, type, slug, ...fields }, parentOrigin);
46
81
  };
47
82
  let last = null;
48
83
  const update = () => {
@@ -64,6 +99,15 @@ export function connectWorkbench({ slug, snapshot, commands, modals }) {
64
99
  event.preventDefault();
65
100
  send("key", { key });
66
101
  });
102
+ // A block's card asks the reader to let it online (its 允许访问 button: the kit's net.js): the workbench
103
+ // opens its consent dialog, the one 设置 › 组件列表 opens, and writes what the reader says; the page
104
+ // hears it on its event stream, and the kit starts the instance again.
105
+ addEventListener("doc-net-consent", (event) => {
106
+ const { block, hosts } = event.detail ?? {};
107
+ if (typeof block !== "string") return;
108
+ event.preventDefault();
109
+ send("consent", { block, hosts: Array.isArray(hosts) ? hosts : [] });
110
+ });
67
111
  const own = {
68
112
  async theme({ theme = null }) {
69
113
  if (theme !== null && theme !== "light" && theme !== "dark") return { ok: false, reason: "theme" };
@@ -97,7 +141,7 @@ export function connectWorkbench({ slug, snapshot, commands, modals }) {
97
141
 
98
142
  addEventListener("message", async (event) => {
99
143
  const message = event.data;
100
- if (event.source !== window.parent || event.origin !== location.origin) return;
144
+ if (event.source !== window.parent || !parentOrigin || event.origin !== parentOrigin) return;
101
145
  if (!PROTOCOLS.includes(message?.protocol) || message.v !== VERSION || message.type !== "command") return;
102
146
  spoken = message.protocol;
103
147
  const run = Object.hasOwn(all, message.name) ? all[message.name] : null;
@@ -42,12 +42,12 @@ const INLINE = {
42
42
  };
43
43
 
44
44
  // Groups of the unfiltered menu: 基本区块, 高级区块 (media, code, tabs and formula blocks: what
45
- // holds more than text; the types' own `menu`, registry.mjs MENU_GROUPS), 组件 (what the variants
46
- // are now: the workspace's), and what is no block under 内联.
45
+ // holds more than text; the types' own `menu`, registry.mjs MENU_GROUPS), 自定义块 (what the variants
46
+ // are now: the workspace's custom blocks, plan §4.1's name for the group 组件 was), and what is no block under 内联.
47
47
  const SECTIONS = [
48
48
  { title: t("基本区块"), types: () => MENU_GROUPS.basic },
49
49
  { title: t("高级区块"), types: () => MENU_GROUPS.advanced },
50
- { title: t("组件@group"), types: variantKeys },
50
+ { title: t("自定义块"), types: variantKeys },
51
51
  ];
52
52
 
53
53
  const infoOf = (key) => INLINE[key] ?? menuRow(key);
@@ -0,0 +1,87 @@
1
+ import { TABLE } from "../../components/kit.mjs";
2
+ import { CHART_SOURCE, TABLE_READERS, VIEW_FROM, nextChartKey } from "../../../shared/table-chart.mjs";
3
+ import { t } from "../../../shared/i18n/index.mjs";
4
+ import { menuRow } from "../page-objects.mjs";
5
+
6
+ // Which table a view reads (docs/editor.md, "Table views"). A view of a table (an instance of a custom
7
+ // block whose needs hold "tables") names its table by a key: VIEW_FROM on the instance, CHART_SOURCE on
8
+ // the table's frame, never by an id or the blocks' order. A view made on the page ("/", 在下方新建, 转换成)
9
+ // is bound to the nearest table above it as it is made, in the same undo step; the table it reads is the
10
+ // reader's to change after that, in the block's 设置 (installed/page.mjs), which lists the document's tables.
11
+ // A table with no key gets one in the same step (the first of t1, t2 … the page does not hold), and so
12
+ // does the second of two an Agent wrote with one key: a view by that key would read the first.
13
+
14
+ const FRAME_WITH_TABLE = (frame) => frame.querySelector("table") !== null && !frame.closest("[data-doc-dev]");
15
+
16
+ /** The tables of the page, in the document's order: their frames (.doc-table-wrap). */
17
+ export const tableFrames = () => [...document.querySelectorAll(TABLE.frame)].filter(FRAME_WITH_TABLE);
18
+
19
+ /** The frame a key names, as the kit reads it (runtime/table-reading.js frameOf) and the checks do: the first that carries it. */
20
+ export const frameOf = (key) => tableFrames().find((frame) => frame.getAttribute(CHART_SOURCE) === key) ?? null;
21
+
22
+ /** The nearest table above `node`, in the document's order, that does not hold it; null where there is none. */
23
+ export function tableAbove(node) {
24
+ let found = null;
25
+ for (const frame of tableFrames()) {
26
+ if (frame.contains(node)) continue;
27
+ if (frame.compareDocumentPosition(node) & Node.DOCUMENT_POSITION_FOLLOWING) found = frame;
28
+ }
29
+ return found;
30
+ }
31
+
32
+ // Every key a chart or a view names, or a frame carries.
33
+ const takenKeys = () => new Set([...document.querySelectorAll([CHART_SOURCE, ...TABLE_READERS].map((name) => `[${name}]`).join(", "))]
34
+ .flatMap((node) => [CHART_SOURCE, ...TABLE_READERS].map((name) => node.getAttribute(name)).filter((value) => value !== null)));
35
+
36
+ /** The key `frame` is read by: its own where it names this frame, else a new one (not yet written). */
37
+ export function keyOf(frame) {
38
+ const own = frame.getAttribute(CHART_SOURCE);
39
+ return own !== null && frameOf(own) === frame ? own : nextChartKey(takenKeys());
40
+ }
41
+
42
+ /**
43
+ * `instance` made a view of `frame` (or of none: null takes its key off): its VIEW_FROM set, and the key
44
+ * on the frame where it carried none that names it. Records nothing: the caller's undo step does
45
+ * (`viewFrames`, struct's `attributes`). Returns whether anything changed.
46
+ */
47
+ export function bindView(instance, frame) {
48
+ if (!frame) {
49
+ if (!instance.hasAttribute(VIEW_FROM)) return false;
50
+ instance.removeAttribute(VIEW_FROM);
51
+ return true;
52
+ }
53
+ const key = keyOf(frame);
54
+ let changed = false;
55
+ if (instance.getAttribute(VIEW_FROM) !== key) {
56
+ instance.setAttribute(VIEW_FROM, key);
57
+ changed = true;
58
+ }
59
+ if (frame.getAttribute(CHART_SOURCE) !== key) {
60
+ frame.setAttribute(CHART_SOURCE, key);
61
+ changed = true;
62
+ }
63
+ return changed;
64
+ }
65
+
66
+ /** A view that was made bound to the table above it. */
67
+ export function bindAbove(instance) {
68
+ return bindView(instance, tableAbove(instance));
69
+ }
70
+
71
+ /**
72
+ * What the undo step that makes a block of the menu's key records of the tables' keys (struct's
73
+ * `attributes`): every table's frame when the block reads tables, as the table it is bound to is only
74
+ * known as the block is made; nothing for any other block.
75
+ */
76
+ export const viewFrames = (key) => (menuRow(key)?.readsTables ? tableFrames().map((frame) => [frame, [CHART_SOURCE]]) : []);
77
+
78
+ // A table named for a reader: its place among the document's tables and the words of its first row.
79
+ function labelOf(frame, place) {
80
+ const first = frame.querySelector("tr");
81
+ const words = first ? [...first.cells].map((cell) => cell.textContent.replace(/\s+/g, " ").trim()).filter(Boolean).slice(0, 4).join("、") : "";
82
+ const shown = words.length > 28 ? `${words.slice(0, 27)}…` : words;
83
+ return shown ? t("表格 {0} · {1}", place, shown) : t("表格 {0}", place);
84
+ }
85
+
86
+ /** The document's tables for a list to choose from: [{ frame, label }], the label naming the table by its place and its first row. */
87
+ export const tableChoices = () => tableFrames().map((frame, at) => ({ frame, label: labelOf(frame, at + 1) }));