@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,10 +1,10 @@
1
1
  import { OUTER, UNIT, blocksIn, boxKind, heldIn, newHost, newTail, placeBefore, unitElement, withLeads } from "../core.mjs";
2
2
  import { containerType } from "../convert.mjs";
3
3
  import { begin, done, made } from "../made.mjs";
4
- import { selectsBeside } from "../beside.mjs";
4
+ import { caretBeside } from "../beside.mjs";
5
5
  import { caretAt, nearestOnLine, placeCaret, selectAt } from "../caret.mjs";
6
6
  import { sectionOps } from "../page-objects.mjs";
7
- import { contentOf, endOf, hoverAt, innerBox, measure } from "../geometry.mjs";
7
+ import { endOf, hoverAt, innerBox, measure } from "../geometry.mjs";
8
8
  import { BOXED, HOLDS_ONE, accepts } from "../../components/registry.mjs";
9
9
  import { DIALOG } from "../../components/kit.mjs";
10
10
 
@@ -18,9 +18,9 @@ import { DIALOG } from "../../components/kit.mjs";
18
18
 
19
19
  /**
20
20
  * struct(parents, touched, mutate): the editor's undoable structural change (history.mjs). blocks():
21
- * the block tools (blocks.mjs).
21
+ * the block tools (blocks.mjs). after: the caret after a block (after/).
22
22
  */
23
- export function createInsert({ struct, blocks }) {
23
+ export function createInsert({ struct, blocks, after }) {
24
24
  // An empty paragraph right before the block of a text block, the caret staying where it is.
25
25
  // Returns whether one could go there.
26
26
  function paragraphBefore(host) {
@@ -54,10 +54,10 @@ export function createInsert({ struct, blocks }) {
54
54
  // (geometry.mjs endOf). Under the last block of a box whose end is its own padding (endIsPadding: a
55
55
  // highlight block, a callout, a disclosure's content; the user's, 2026-11-06, as notion-lite's click-blank.js
56
56
  // makes a block only below the page and in a column) it is a gap like any other, below. Right of
57
- // the text area a boxed block (a code block, a callout, a file…: not text) or a row of columns
58
- // stands in, at its height (boxedBeside), that block selected, so Delete takes it and Enter puts a
59
- // paragraph after it; between a narrower block's right edge and its column's, as beside any block
60
- // of no text (below). Elsewhere beside text, the caret goes into the text block on that line (the nearest of those
57
+ // a boxed block (a code block, a callout, a file…: not text) or a row of columns, at its height
58
+ // (boxedBeside), the caret after it, at its bottom right (after/: Backspace deletes it, Enter or a
59
+ // key makes a paragraph after it; the user's, 2026-11-09: a click there selected it before).
60
+ // Elsewhere beside text, the caret goes into the text block on that line (the nearest of those
61
61
  // side by side), where the line is nearest the click (Notion's way); in the gap between two
62
62
  // blocks, or beside a block of no text, into the nearer of the blocks around it that is text, in the
63
63
  // innermost box at that height (boxBeside: the press may be on the page's margin, the block in a
@@ -82,7 +82,7 @@ export function createInsert({ struct, blocks }) {
82
82
  if (end) return newParagraph(end.box, end.after);
83
83
  const top = y + scrollY;
84
84
  const beside = boxedBeside(main, x, y, target);
85
- if (beside) return blocks().select(beside);
85
+ if (beside) return after.place(beside);
86
86
  const host = hoverAt(measure(main, { top, bottom: top }), x + scrollX, top, { reach: Infinity, skip: (unit) => !unit.text });
87
87
  if (host) return caretNear(host, x, y);
88
88
  for (let around = boxBeside(box, x, y); around; around = around === box ? null : around.parentElement.closest("[data-ge-box]")) {
@@ -157,26 +157,24 @@ export function createInsert({ struct, blocks }) {
157
157
  const texts = [unit, ...unit.querySelectorAll("[data-ge-block], [data-ge-new]")].filter((node) => node.isContentEditable && node.getClientRects().length > 0 && !node.closest("details:not([open]) > :not(summary)"));
158
158
  return (last ? texts.at(-1) : texts[0]) ?? null;
159
159
  }
160
- // A boxed block or a row of columns at height `y` with (x, y) right of the text area it stands in
161
- // (the content box of its box: the page's column, a column of 分栏, a section's, a quote's, a
162
- // highlight block's or a callout's, a disclosure's content) and right of the block itself (one
163
- // wider than that area), or null: in the page's margin, or in the padding of the box it stands in;
164
- // never between a narrower block's right edge and its area's (a table, a picture: the user's,
165
- // 2026-11-07, a click there selected it), nor in another text area (the blank box `target` the
166
- // press was on holds the block: a column further right is no place beside one in the column left
167
- // of it). The innermost, but never a block inside a row of columns the click is to the right of too
168
- // (the row is selected whole): past a column's edge is the gap to the next column, whose press is
169
- // the gap's (columns/: it drags, a click alone changes nothing), or past the row, which is selected.
160
+ // A boxed block or a row of columns at height `y` with (x, y) right of it: between its right edge
161
+ // and the text area's it stands in (a table, a picture narrower than its column: the user's,
162
+ // 2026-11-09, the caret after it where a click there once selected it, 2026-11-07, and later went to
163
+ // the nearest text), in the padding of the box it stands in (a highlight block's, a callout's) or in the
164
+ // page's margin; or null. Never in another text area (the blank box `target` the press was on holds the
165
+ // block: a column further right is no place beside one in the column left of it). The innermost,
166
+ // but never a block inside a row of columns the click is to the right of too (the caret goes after
167
+ // the row): past a column's edge is the gap to the next column, whose press is the gap's (columns/:
168
+ // it drags, a click alone changes nothing), or past the row.
170
169
  function boxedBeside(main, x, y, target) {
171
170
  let found = null;
172
171
  const right = (unit) => {
173
172
  const rect = unit.getBoundingClientRect();
174
173
  if (y < rect.top || y > rect.bottom || (target?.contains && !target.contains(unit))) return false;
175
- const box = unit.parentElement;
176
- return x > Math.max(rect.right, contentOf(box.getBoundingClientRect(), getComputedStyle(box)).right);
174
+ return x > rect.right;
177
175
  };
178
176
  for (const unit of main.querySelectorAll(`[data-ge-unit-kind]`)) {
179
- if (!selectsBeside(unit) || !unit.parentElement?.hasAttribute("data-ge-box") || unit.parentElement.closest("details:not([open])")) continue;
177
+ if (!caretBeside(unit) || !unit.parentElement?.hasAttribute("data-ge-box") || unit.parentElement.closest("details:not([open])")) continue;
180
178
  if (!right(unit)) continue;
181
179
  const row = unit.parentElement.closest('[data-ge-unit-kind="columns"]');
182
180
  if (row && main.contains(row) && right(row)) continue;
@@ -9,7 +9,7 @@ import { placeBox } from "../placement.mjs";
9
9
  import { tooltip } from "../tooltip.mjs";
10
10
  import { addStyle, copyAddress, element, fadeIn, mount, swallowNext } from "../ui.mjs";
11
11
  import { typedHref } from "./address.mjs";
12
- import { findPages, heldList, pageRows, placeIn, readPages, titleIn, trashed } from "./pages.mjs";
12
+ import { findPages, heldList, pageRows, placeIn, readPages, titleIn, trashed, webLinkIn } from "./pages.mjs";
13
13
  import { DIALOG_TRIGGER } from "../../components/dialog/index.mjs";
14
14
  import { DIALOG_ICON } from "../../components/icons.mjs";
15
15
  import { VIEWS, closeOffer, closeViews, hasViews, hrefOf, isPageChip, offerViews, openViews, pageChip, refetch, viewNodes, viewOf, viewsHold } from "./views.mjs";
@@ -668,12 +668,14 @@ async function listedPage(address) {
668
668
 
669
669
  /**
670
670
  * Whether a page alone in a tab may leave for a workbench's `hash`, which only the list reads: not for
671
- * one that names no document, said as the workbench says it, the page staying. With no answer it goes,
671
+ * one that names no document, said as the workbench says it, the page staying. A web link of the sidebar,
672
+ * or an entry of an extension's column with an address (#~<id>/<entry id>), is a place the workbench
673
+ * opens (in its content area), so it goes there. With no answer it goes,
672
674
  * for the workbench to say.
673
675
  */
674
676
  export async function leadsToPage(hash) {
675
677
  const list = await readPages(use.own());
676
- if (!list || placeIn(list, `#${hash}`)) return true;
678
+ if (!list || placeIn(list, `#${hash}`) || webLinkIn(list, hash)) return true;
677
679
  use.say(inTrash(list.trash, hash) ? t("这个页面已删除。") : t("没有找到这个页面。"));
678
680
  return false;
679
681
  }
@@ -1,15 +1,21 @@
1
1
  import { iconUrl } from "../../../shared/emoji/icon-value.mjs";
2
2
  import { escapeAttribute } from "../../../shared/escape.mjs";
3
3
  import { addressOn, decoded, hashAddress } from "../../../shared/page-address.mjs";
4
+ import { DOCS, isTop, topOf } from "../../../shared/outline-shape.mjs";
5
+ import { entryOfKey } from "../../../shared/extension-sidebar.mjs";
4
6
  import { inTrash, namedLinks, pageLink, pageLinks } from "../../../shared/page-links.mjs";
5
7
  import { PAGE_ICON } from "../../components/icons.mjs";
8
+ import { t } from "../../../shared/i18n/index.mjs";
6
9
 
7
10
  // The documents of the workspace, as a link's card, a page block's box and "@" look for them
8
11
  // (docs/editor.md, "Links"): one search for the three. The list is read once for each opening from
9
12
  // what the workbench reads itself (GET /__gallery/workspace/outline: no route of its own, nothing
10
- // pushed), in the sidebar's order, each document with the title of the one above it in the sidebar; 写作偏好
11
- // is no page to link to, and this page has the title it shows now, not the one last saved. A list that
12
- // cannot be read is no results, and the field goes on taking addresses.
13
+ // pushed), in the sidebar's order, column after column (栏: shared/outline-shape.mjs), each document with
14
+ // the title of the one above it in the sidebar; 写作偏好 is no page to link to, nor is a web link of the
15
+ // sidebar (kind "link": no file of its own to link to; the documents under one are pages all the same) or a
16
+ // draft of another workspace (kind "draft": its file is that workspace's, which no relative link reaches),
17
+ // and this page has the title it shows now, not the one last saved. A list that cannot be read is no
18
+ // results, and the field goes on taking addresses.
13
19
  //
14
20
  // What a copy writes is an address by a page's link, and a copy cannot wait for an answer: the
15
21
  // clipboard takes a write only in the click itself. So the page holds the list ready, the last one
@@ -31,8 +37,8 @@ let shown = () => null; // this page, as readPages takes it
31
37
 
32
38
  /**
33
39
  * The workspace's documents: { pages: [{ slug, title, icon, parent }] (`parent`: the title of the one
34
- * it is under, or null), links: their links (shared/page-links.mjs), trash: what the trash holds }, or
35
- * null when the list cannot be read. `own`: this page, { slug, title } as it shows it.
40
+ * it is under, or null), links: their links (shared/page-links.mjs), trash: what the trash holds but web links }, or
41
+ * null when the list cannot be read (`webs`: the links of the sidebar's web links, which are no pages). `own`: this page, { slug, title } as it shows it.
36
42
  */
37
43
  export async function readPages(own = null) {
38
44
  const listed = await fetch(OUTLINE).then((answer) => answer.json()).catch(() => null);
@@ -41,13 +47,18 @@ export async function readPages(own = null) {
41
47
  const pages = [];
42
48
  const walk = (parent) => {
43
49
  for (const slug of listed.outline?.children?.[parent] ?? []) {
44
- if (!listed.reports[slug] || listed.reports[slug].instructions) continue;
45
- pages.push({ slug, title: titleOf(slug) || slug, icon: listed.reports[slug].icon ?? null, parent: parent ? titleOf(parent) || parent : null });
50
+ const report = listed.reports[slug];
51
+ if (!report || report.instructions) continue;
52
+ // An untitled document is named 未命名文档, as the workbench names it (its link's words: its page id alone).
53
+ if (report.kind !== "link" && report.kind !== "draft") pages.push({ slug, title: titleOf(slug) || t("未命名文档"), icon: report.icon ?? null, parent: isTop(parent) ? null : titleOf(parent) || t("未命名文档") });
46
54
  walk(slug);
47
55
  }
48
56
  };
49
- walk("");
50
- held = { pages, links: pageLinks(pages.map(({ slug }) => ({ slug, title: titleOf(slug) }))), trash: listed.trash ?? [] };
57
+ for (const { id } of listed.outline?.groups ?? [{ id: DOCS }]) walk(topOf(id));
58
+ // The sidebar's web links, by their links as a workbench's hash holds them: no page to link to, but an address the workbench opens.
59
+ const web = Object.values(listed.reports).filter((report) => report.kind === "link").map(({ slug, title }) => ({ slug, title }));
60
+ // And the extensions' columns (their entries: an address #~<id>/<entry id> the workbench opens too).
61
+ held = { pages, links: pageLinks(pages.map(({ slug }) => ({ slug, title: titleOf(slug) }))), webs: pageLinks(web), extensions: listed.extensions ?? [], trash: (listed.trash ?? []).filter(({ kind }) => kind !== "link") };
51
62
  return held;
52
63
  }
53
64
 
@@ -118,6 +129,13 @@ export function placeIn(list, text) {
118
129
  return page ? { ...page, block: place.block } : null;
119
130
  }
120
131
 
132
+ /**
133
+ * Whether workbench hash `hash` (no #) names a web link of the sidebar, or an entry of an extension's
134
+ * column that has an address (#~<id>/<entry id>): the workbench opens it in its content area, though it
135
+ * is no page to link to.
136
+ */
137
+ export const webLinkIn = (list, hash) => Boolean(hashAddress(decoded(hash), list.webs) || entryOfKey(list.extensions, decoded(hash))?.url);
138
+
121
139
  /** The title of the page `text` is an address of, of `list` or of its trash, or null: what stands for a link to it where its address would be a folder's. */
122
140
  export function titleIn(list, text) {
123
141
  const binned = addressOn(text, pageLinks(list.trash), globalThis.location?.origin)?.slug;
@@ -1,13 +1,15 @@
1
1
  // What every popup of the editor is painted with, written once: Notion's neutral palette, its blue
2
2
  // and its two shadows, light and dark by light-dark() (the page's color-scheme decides). A sheet of
3
- // `:root` custom properties, put in every document the editor draws in (ui.mjs addStyleTo), so a
3
+ // `:root` custom properties and the one button look (BUTTONS), put in every document the editor draws in (ui.mjs addStyleTo), so a
4
4
  // menu, a card, a bar, a notice reads them wherever it stands and none declares a palette of its
5
5
  // own. Values are Notion's own as notion-lite carries them (view/theme/notion-vars.css), which this
6
6
  // editor follows; the page's content colors (--doc-*, the kit's tokens.css) are another matter.
7
7
  //
8
8
  // The blue is two tokens because notion-lite has two, for two jobs: --ge-accent (its
9
- // --c-bluBacAccPri: a primary button, a switch, a chosen icon) and --ge-focus (its --c-butBluFocRin
10
- // and --c-inpBluFocRin: the ring round a focused field).
9
+ // --c-bluBacAccPri: a switch, a chosen icon, a table's tools, the bars that mark a place) and
10
+ // --ge-focus (its --c-butBluFocRin and --c-inpBluFocRin: the ring round a focused field). A button is
11
+ // neither: the one button look is BUTTONS below, whose primary is a pale blue (--ge-btn-primary*), the
12
+ // workbench's, never the solid --ge-accent.
11
13
  //
12
14
  // Two shadows, because Notion has two surfaces: --ge-shadow, a card standing over the text (the
13
15
  // format bar, the formula and link cards, the conflicts, a notice), and --ge-shadow-pop, a menu
@@ -15,6 +17,38 @@
15
17
  // emoji-picker/support.mjs keeps notion-lite's --c-* variables only for the media menu and the image's
16
18
  // alignment bar.
17
19
 
20
+ /**
21
+ * The one look of a button the editor draws on a page (the Agent changes' bar, the conflict card and the lost
22
+ * texts' panel, the crop window, a list's number, the icon picker's upload, the media menu): rules in the
23
+ * palette's sheet, so that every document the editor draws in has them from the first paint and no style
24
+ * repeats them. `.ge-btn` is a text button (ui.mjs textButton): no line and no fill, a gray under the
25
+ * pointer and while the keys are on it, a deeper one pressed; `data-primary` the pale blue (add, confirm,
26
+ * save), with `data-danger` the pale red (a delete); `data-quiet` a small one for looking, not deciding
27
+ * (收起, 定位). `.disabled` and `aria-disabled` are how a button made of a div says it cannot be pressed.
28
+ * `.ge-icon-btn` is the look of an icon button standing alone (a 批注's marker and its delete): no fill under
29
+ * the pointer (the icon goes darker), a gray only while it is pressed. The tools of a bar (the format bar's,
30
+ * the link card's) and a menu's rows are gray under the pointer, as Notion's are. Text fields are not
31
+ * buttons: they keep their thin outline.
32
+ */
33
+ const OFF = ":disabled, .disabled, [aria-disabled=\"true\"]";
34
+ export const BUTTONS = `
35
+ .ge-btn { box-sizing: border-box; display: inline-flex; align-items: center; justify-content: center; height: 28px; margin: 0; padding: 0 10px; border: 0; border-radius: 6px; box-shadow: none; background: transparent; color: var(--ge-tx); font: inherit; font-weight: 500; line-height: 1; white-space: nowrap; cursor: pointer; user-select: none; transition: background 20ms ease-in; }
36
+ .ge-btn:is(:hover, :focus-visible):not(${OFF}) { outline: none; background: var(--ge-hover); }
37
+ .ge-btn:active:not(${OFF}) { background: var(--ge-press); }
38
+ .ge-btn[data-primary] { background: var(--ge-btn-primary); color: var(--ge-btn-primary-text); }
39
+ .ge-btn[data-primary]:is(:hover, :focus-visible):not(${OFF}) { background: var(--ge-btn-primary-hover); }
40
+ .ge-btn[data-primary]:active:not(${OFF}) { background: var(--ge-btn-primary-press); }
41
+ .ge-btn[data-primary][data-danger] { background: var(--ge-btn-danger); color: var(--ge-btn-danger-text); }
42
+ .ge-btn[data-primary][data-danger]:is(:hover, :focus-visible):not(${OFF}) { background: var(--ge-btn-danger-hover); }
43
+ .ge-btn[data-primary][data-danger]:active:not(${OFF}) { background: var(--ge-btn-danger-press); }
44
+ .ge-btn[data-quiet] { height: 24px; padding: 0 6px; color: var(--ge-tx2); font-weight: 400; }
45
+ .ge-btn[data-quiet]:is(:hover, :focus-visible):not(${OFF}) { color: var(--ge-tx); }
46
+ .ge-btn:is(${OFF}) { opacity: .45; cursor: default; }
47
+ .ge-icon-btn { border: 0; box-shadow: none; background: transparent; cursor: pointer; transition: background 20ms ease-in, color 20ms ease-in; }
48
+ .ge-icon-btn:hover:not(:disabled) { color: var(--ge-ico); }
49
+ .ge-icon-btn:active:not(:disabled) { background: var(--ge-press); }
50
+ `;
51
+
18
52
  export const TOKENS = `
19
53
  :root {
20
54
  --ge-tx: light-dark(#2c2c2b, #f0efed);
@@ -40,6 +74,17 @@ export const TOKENS = `
40
74
  --ge-focus: #2383e2;
41
75
  --ge-red: light-dark(#eb5757, #ff6b6b);
42
76
  --ge-quote: light-dark(rgb(28 19 1 / 16%), rgb(255 255 235 / 16%));
77
+ /* Buttons (BUTTONS below; the user's rule, restated 2026-11-09): a primary is a pale blue fill, always shown, its words the
78
+ deeper blue; a primary that cannot be taken back a pale red; every other button has no fill and no line, a gray under
79
+ the pointer (--ge-hover) and a deeper one pressed (--ge-press). The workbench's own values (--btnPriBg, --btnDanBg: tokens.css). */
80
+ --ge-btn-primary: light-dark(rgb(35 131 226 / 14%), rgb(67 155 255 / 24%));
81
+ --ge-btn-primary-hover: light-dark(rgb(35 131 226 / 22%), rgb(67 155 255 / 34%));
82
+ --ge-btn-primary-press: light-dark(rgb(35 131 226 / 30%), rgb(67 155 255 / 44%));
83
+ --ge-btn-primary-text: light-dark(#1a69bd, #7ab8ff);
84
+ --ge-btn-danger: light-dark(rgb(235 87 87 / 14%), rgb(255 104 92 / 24%));
85
+ --ge-btn-danger-hover: light-dark(rgb(235 87 87 / 22%), rgb(255 104 92 / 34%));
86
+ --ge-btn-danger-press: light-dark(rgb(235 87 87 / 30%), rgb(255 104 92 / 44%));
87
+ --ge-btn-danger-text: light-dark(#c4403c, #ff9a90);
43
88
  --ge-fill: light-dark(rgb(35 131 226 / 14%), rgb(35 131 226 / 28%));
44
89
  --ge-halo: rgb(35 131 226 / 14%);
45
90
  --ge-select: light-dark(rgb(35 131 226 / 28%), rgb(35 131 226 / 45%));
@@ -55,6 +100,11 @@ export const TOKENS = `
55
100
  --ge-toast-bg: light-dark(#0f0f0f, #2f2f2f);
56
101
  /* The quiet gray a heading is lit with for a moment when the outline goes to it (outline/), never a blue. */
57
102
  --ge-outline-flash: light-dark(rgb(33 27 23 / 7%), rgb(255 255 255 / 8%));
103
+ /* The lines a size is dragged by (resize/, columns/), grays like Notion's column resizer (its border.primaryTranslucent), never a
104
+ bright blue (the user, 2026-11-07): where a drag may start, the line being dragged, and that line where it snaps. */
105
+ --ge-guide: light-dark(rgb(55 53 47 / 16%), rgb(255 255 255 / 14%));
106
+ --ge-guide-hot: light-dark(rgb(55 53 47 / 36%), rgb(255 255 255 / 32%));
107
+ --ge-guide-snap: light-dark(rgb(55 53 47 / 62%), rgb(255 255 255 / 58%));
58
108
  /* 批注 (annotate/): a warm mark on the words an annotation is about, its 2px underline leading (a faint fill, so it is never
59
109
  taken for the report's own yellow background), a block anchor's bar; stronger for the one shown. */
60
110
  --ge-note: light-dark(rgb(255 212 0 / 6%), rgb(255 212 0 / 6%));
@@ -74,4 +124,5 @@ export const TOKENS = `
74
124
  --ge-diff-del-fill: light-dark(rgb(223 22 0 / 4.5%), rgb(255 104 92 / 10%));
75
125
  --ge-diff-del-text: light-dark(#cf5148, #ff8f85);
76
126
  }
127
+ ${BUTTONS}
77
128
  `;
@@ -1,5 +1,6 @@
1
1
  import { OLD_OUTLINE_OPEN_KEY, OLD_PREFERENCES_KEY, OUTLINE_OPEN_KEY, PREFERENCES_KEY } from "../../shared/preferences.mjs";
2
2
  import { LOOK_ATTRIBUTES } from "../../shared/document-look.mjs";
3
+ import { ADD, HANDLE } from "./handle-sizes.mjs";
3
4
 
4
5
  // The right side of the page while it is edited (docs/editor.md, "The outline and the right side"): the
5
6
  // outline (目录, outline/) docked at the window's right edge, the cards of 批注 (annotate/) between it and
@@ -52,9 +53,18 @@ import { LOOK_ATTRIBUTES } from "../../shared/document-look.mjs";
52
53
  // column stands where it will stay from the first paint, and by setMargin() after that.
53
54
  // When they move the column, the page hears a resize, so what stands over the text (the format bar, a
54
55
  // selection's strips, a card) is placed again.
56
+ //
57
+ // The edge room is also the page's gutters (the kit's --doc-page-gutter and --doc-wide-gutter, page.css),
58
+ // set by MARGIN_STYLE, which the edit service puts in the page's head: the column the kit lets show
59
+ // (data-doc-ready, the frame a workbench swaps the page in on) stands where the editor keeps it, its lines
60
+ // broken as they stay, before the editor has started, the outline off and no 批注 as much as with them.
61
+ // (Until 2026-11-09 the handle put them in once the page edited: in a workbench with its sidebar open, a
62
+ // page 795px wide came in with the kit's 20px gutters, its column 712 wide and 42 in, and moved to 667 and
63
+ // 64 a few frames later, its lines breaking anew: the user's report on 0.1.1.)
55
64
 
56
65
  /**
57
- * The numbers: the edge room (the least room either side of the column keeps), the least it gives up
66
+ * The numbers: the edge room (the least room either side of the column keeps, and the page's gutters:
67
+ * the bar's square left of the block handle's grip, the grip, its gap and room to breathe, 64), the least it gives up
58
68
  * to (the block handle's: its 38px, its 12px gap, 2px), the column, the least a full-width column
59
69
  * keeps, the outline in full (its default width, the least and the most it is dragged to), its
60
70
  * list's inset in its panel (`guide`: the column's right room ends there, at the list's edge, its
@@ -65,7 +75,7 @@ import { LOOK_ATTRIBUTES } from "../../shared/document-look.mjs";
65
75
  * clear; one focused comes 20px left, and no button shows then), a card's width, the least it gives up
66
76
  * to, and the room past it (clear of the outline's list: its guide and grip).
67
77
  */
68
- export const MARGIN = Object.freeze({ edge: 64, start: 52, column: 712, least: 560, full: 200, fullMin: 160, fullMax: 360, guide: 8, grip: 4, strip: 36, hysteresis: 16, lane: 60, card: 308, cardLeast: 240, cardEnd: 20 });
78
+ export const MARGIN = Object.freeze({ edge: ADD.width + HANDLE.width + HANDLE.gap + 12, start: 52, column: 712, least: 560, full: 200, fullMin: 160, fullMax: 360, guide: 8, grip: 4, strip: 36, hysteresis: 16, lane: 60, card: 308, cardLeast: 240, cardEnd: 20 });
69
79
 
70
80
  /**
71
81
  * The outline's width in full for the reader's choice `chosen` (px; 0 or none: the default), within
@@ -116,8 +126,13 @@ export function marginLayout({ width, outline = false, collapsed = false, notes
116
126
 
117
127
  const SLIDE = 200; // ms: the column's slide as the page comes to have 批注 or has none left
118
128
 
119
- /** The page's rules for the room: the column placed (and narrowed only when it must), screen only. */
129
+ /**
130
+ * The page's rules for the room: its gutters the edge room, and on screen the column placed (and
131
+ * narrowed only when it must).
132
+ */
120
133
  export const MARGIN_STYLE = `
134
+ /* The handle's room beside the page's blocks, the page's gutters from its first paint (a page the editor edits: this sheet is in the head the edit service serves); resize/ and the workbench's sidebar read --ge-edge-room. */
135
+ :root { --ge-edge-room: ${MARGIN.edge}px; --doc-page-gutter: var(--ge-edge-room); --doc-wide-gutter: var(--ge-edge-room); }
121
136
  @media screen {
122
137
  :root[data-ge-margin] {
123
138
  /* The least room either side of the column keeps (marginLayout's side: the edge room, less where the page is short of it, down to the handle's). */
@@ -28,15 +28,14 @@ const STYLE = `
28
28
  .nmedia-menu-tab.active::after { content: ""; position: absolute; left: 8px; right: 8px; bottom: 0; border-bottom: 2px solid var(--c-texPri); }
29
29
  .nmedia-menu-body { padding: 12px 12px 10px; }
30
30
  .nmedia-menu-inner { display: flex; justify-content: center; padding: 4px; }
31
- .nmedia-menu-upload { display: flex; align-items: center; justify-content: center; width: 100%; height: 32px; padding: 0 12px; border-radius: 6px; border: 1px solid var(--ca-borPriTra); font-size: 14px; font-weight: 500; line-height: 1.2; cursor: pointer; transition: background 20ms ease-in; }
32
- .nmedia-menu-upload:hover { background: var(--ca-bacIntTra); }
31
+ /* Its buttons are the editor's one button look (look.mjs BUTTONS): the pale blue primary, here what the tab does. */
32
+ .nmedia-menu-upload, .nmedia-menu-embed { width: 100%; font-size: 14px; }
33
33
  .nmedia-menu-link { flex-direction: column; align-items: stretch; gap: 8px; }
34
34
  .nmedia-menu-input { display: flex; align-items: center; gap: 4px; width: 100%; height: 28px; padding: 3px 6px; border-radius: 6px; background: var(--ca-bacSecTra); box-shadow: 0 0 0 1px var(--ca-borPriTra); box-sizing: border-box; }
35
35
  .nmedia-menu-input:focus-within { box-shadow: var(--c-inpBluFocRin); }
36
36
  .nmedia-menu-input input { flex: 1; min-width: 0; border: none; outline: none; background: transparent; padding: 0; font: inherit; font-size: 14px; line-height: 20px; color: var(--c-texPri); }
37
37
  .nmedia-menu-input input::placeholder { color: var(--c-texTer); }
38
- .nmedia-menu-embed { display: flex; align-items: center; justify-content: center; width: 100%; max-width: 300px; margin: 0 auto; height: 28px; padding: 0 8px; border-radius: 6px; background: var(--c-bluBacAccPri); color: #fff; font-size: 14px; font-weight: 500; cursor: pointer; box-sizing: border-box; }
39
- .nmedia-menu-embed:hover { filter: brightness(.94); }
38
+ .nmedia-menu-embed { max-width: 300px; margin: 0 auto; }
40
39
  .nmedia-menu-caption { margin: -6px 0 4px; padding: 4px 0; font-size: 12px; line-height: 1.4; color: var(--c-texSec); text-align: center; }
41
40
  .nmedia-menu.dragover .nmedia-menu-body { background: var(--ca-bluBacSecTra); }
42
41
  .nmedia-menu-choose { margin-top: 8px; }
@@ -76,10 +75,10 @@ export function openMediaMenu(anchor, { tabs, width, upload = {}, link = {}, onU
76
75
  `<div class="nmedia-menu-tab-wrap"><div role="tab" class="nmedia-menu-tab${key === current ? " active" : ""}" aria-selected="${key === current}" data-tab="${key}">${esc(label)}</div></div>`).join("")}</div>` : "")
77
76
  + `<div class="nmedia-menu-body">${current === "upload"
78
77
  ? (upload.primary
79
- ? `<div class="nmedia-menu-inner nmedia-menu-link"><div role="button" tabindex="0" class="nmedia-menu-embed nmedia-menu-choose" data-do="upload">${esc(upload.label ?? t("选择文件"))}</div>${upload.caption ? `<div class="nmedia-menu-caption">${esc(upload.caption)}</div>` : ""}</div>`
80
- : `<div class="nmedia-menu-inner"><div role="button" tabindex="0" class="nmedia-menu-upload" data-do="upload">${esc(upload.label ?? t("上传文件"))}</div></div>`)
78
+ ? `<div class="nmedia-menu-inner nmedia-menu-link"><div role="button" tabindex="0" class="ge-btn nmedia-menu-embed nmedia-menu-choose" data-primary data-do="upload">${esc(upload.label ?? t("选择文件"))}</div>${upload.caption ? `<div class="nmedia-menu-caption">${esc(upload.caption)}</div>` : ""}</div>`
79
+ : `<div class="nmedia-menu-inner"><div role="button" tabindex="0" class="ge-btn nmedia-menu-upload" data-primary data-do="upload">${esc(upload.label ?? t("上传文件"))}</div></div>`)
81
80
  : `<div class="nmedia-menu-inner nmedia-menu-link"><div class="nmedia-menu-input"><input type="url" placeholder="${esc(link.placeholder ?? t("粘贴链接…"))}" autocomplete="off"></div>`
82
- + `<div role="button" tabindex="0" class="nmedia-menu-embed" data-do="embed">${esc(link.button ?? t("嵌入链接"))}</div>`
81
+ + `<div role="button" tabindex="0" class="ge-btn nmedia-menu-embed" data-primary data-do="embed">${esc(link.button ?? t("嵌入链接"))}</div>`
83
82
  + (link.caption ? `<div class="nmedia-menu-caption">${esc(link.caption)}</div>` : "") + "</div>"}</div>`;
84
83
  const input = el.querySelector("input");
85
84
  if (input) {
@@ -37,6 +37,8 @@ const STYLE = `
37
37
  }
38
38
  /* A width given (data-sized: opts.width, placed by place()): that width, whatever the rows hold. */
39
39
  .ge-pop[data-sized] { min-width: 0; max-width: calc(100vw - 16px); }
40
+ /* A short list of one kind of word (a card's 大小 ›: 4 × 2): only as wide as its rows, no 180px floor. */
41
+ .ge-pop[data-compact] { min-width: 0; }
40
42
  @keyframes ge-pop-in { from { opacity: 0; transform: scale(.98); } }
41
43
  @media (prefers-reduced-motion: reduce) { .ge-pop { animation: none; } }
42
44
  .ge-pop-title { display: flex; align-items: center; gap: 8px; padding: 8px 12px; color: var(--ge-tx2); font-size: 12px; font-weight: 500; line-height: 14px; }
@@ -58,6 +60,7 @@ const STYLE = `
58
60
  words and the hint takes what is left, cut short with an ellipsis where it is too long (an English
59
61
  row's current choice once took the whole row, its label drawn 0px wide). */
60
62
  .ge-pop-label:has(+ .ge-pop-hint) { flex: 1 0 auto; max-width: 100%; }
63
+ .ge-pop-of { color: var(--ge-tx3); }
61
64
  .ge-pop-hint { flex: 0 1 auto; min-width: 0; overflow: hidden; text-overflow: ellipsis; color: var(--ge-tx3); font-size: 12px; white-space: nowrap; }
62
65
  /* A row of a page (its title, the page it is under as its hint): a long title is what an ellipsis
63
66
  cuts, and the page above keeps its words, up to a part of the row. */
@@ -83,8 +86,8 @@ const STYLE = `
83
86
  /* A note wraps at the card's width and never widens it (no width of its own: contain). */
84
87
  .ge-pop-note { contain: inline-size; padding: 0 12px 6px 40px; color: var(--ge-tx3); font-size: 12px; line-height: 1.5; }
85
88
  .ge-pop-empty { padding: 8px 12px; color: var(--ge-tx3); }
86
- /* What a row makes, shown beside it under the pointer (a component package's preview.svg). */
87
- .ge-pop-preview { display: block; width: 240px; max-height: 180px; border-radius: 4px; object-fit: contain; background: var(--ge-bg); }
89
+ /* What a row makes, shown beside it under the pointer (a component package's preview.svg), in the middle of the bubble: its description under it wraps wider than the picture. */
90
+ .ge-pop-preview { display: block; width: 240px; max-width: 100%; max-height: 180px; margin: 0 auto; border-radius: 4px; object-fit: contain; object-position: center; background: var(--ge-bg); }
88
91
  .ge-pop-search { position: sticky; top: 0; z-index: 1; padding: 8px 8px 6px; background: var(--ge-bg); }
89
92
  .ge-pop-search input { box-sizing: border-box; width: 100%; height: 28px; margin: 0; padding: 0 8px; border: 0; border-radius: 6px; outline: none; background: var(--ge-hover); color: var(--ge-tx); font: inherit; box-shadow: inset 0 0 0 1px var(--ge-line); }
90
93
  .ge-pop-search input:focus { box-shadow: inset 0 0 0 1px color-mix(in srgb, var(--ge-tx3) 60%, transparent); }
@@ -125,10 +128,12 @@ const opened = new Set(); // the menus open now, whichever part of the page open
125
128
  export const menuOpen = () => opened.size > 0;
126
129
 
127
130
  /**
128
- * items: rows { label, run, icon?, hint?, long?, current?, checked?, disabled?, note?, preview? } (long:
131
+ * items: rows { label, run, icon?, of?, hint?, long?, current?, checked?, disabled?, note?, preview? } (of: what
132
+ * the label is of, grey after it, a block's pack where two rows have one name; long:
129
133
  * a label of any length, a page's title, cut before its hint is; current: the choice
130
134
  * made, checked and not to be chosen again; checked: a switch that is on, checked and clicked to turn
131
- * it off; preview: { src, says }, a picture of what the row makes, where it has one, and a line on it,
135
+ * it off; selected: the choice of a dropdown (a field's list of options), checked as current is but
136
+ * still a row to click, which closes the card with nothing changed; preview: { src, says }, a picture of what the row makes, where it has one, and a line on it,
132
137
  * shown at the row's right while the pointer rests on it, notion-lite's row tooltip) (or { label, icon?, submenu:
133
138
  * () => items, width?, search? } opening a submenu, with a search field at its top when `search` is
134
139
  * given, as `opts.search` below, and `search.empty` the words shown when nothing is found; a row
@@ -140,10 +145,14 @@ export const menuOpen = () => opened.size > 0;
140
145
  * as its rows (FIT; SEARCHING with a search field). around: the rect of the block a handle
141
146
  * (the anchor) stands for; the menu keeps clear of that block: left of it beside the handle, else
142
147
  * below or above it (scrolling inside when only part of it fits), and over it only when the block
143
- * leaves no room at all. side: "right": beside the anchor, right of it (left of it when there is no
148
+ * leaves no room at all; a tall block (more than TALL high: a table, a formula, a highlight, an image)
149
+ * has it beside the handle, left of it or, with no room there,
150
+ * right of it over the block, centered on the handle, never over the handle. side: "right": beside the anchor, right of it (left of it when there is no
144
151
  * room), level with it (a section's bar). Without either the menu stands below the anchor (the
145
152
  * caret), or above it when there is no room below; align: "end", its right edge at the anchor's.
146
- * icons: false, rows of words alone (no column for icons: a code block's languages); height: the
153
+ * icons: false, rows of words alone (no column for icons: a code block's languages; a row that opens a
154
+ * submenu says it of its own as `icons: false`, and `compact: true` makes it only as wide as its rows, no
155
+ * 180px floor: a card's 大小 ›); height: the
147
156
  * card's greatest height, in px (its rows scroll inside it past that). stand(size): where the card
148
157
  * stands, its { left, top } for its { width, height }, in place of all of these rules (a pasted
149
158
  * address's 选择视图, by the format bar's rule: placement.mjs besideText). inside: an element the rows
@@ -221,7 +230,8 @@ export function createMenu() {
221
230
  if (row.split) row.setAttribute("data-split", "");
222
231
  if (item.long) row.setAttribute("data-long", "");
223
232
  if (options.icons !== false) words.append(element("span", { class: "ge-pop-icon", html: item.icon ?? "" }));
224
- words.append(element("span", { class: "ge-pop-label", text: item.label }));
233
+ // A row's pack where two rows have one name (我的待办 · 柔光风格): grey, after the name, in the label.
234
+ words.append(item.of ? element("span", { class: "ge-pop-label" }, item.label, element("span", { class: "ge-pop-of", text: ` · ${item.of}` })) : element("span", { class: "ge-pop-label", text: item.label }));
225
235
  if (item.hint) words.append(element("span", { class: "ge-pop-hint", text: item.hint }));
226
236
  if (row.split) row.append(words, element("span", { class: "ge-pop-more", html: `<span class="ge-pop-arrow">${ICONS.chevron}</span>` }));
227
237
  else if (item.submenu) row.append(element("span", { class: "ge-pop-arrow", html: ICONS.chevron }));
@@ -230,11 +240,12 @@ export function createMenu() {
230
240
  row.submenu = item.submenu;
231
241
  row.subWidth = item.width;
232
242
  row.subSearch = item.search;
243
+ row.subLook = { icons: item.icons, compact: item.compact };
233
244
  }
234
- if (item.current || item.checked) {
235
- row.append(element("span", { class: "ge-pop-check", html: ICONS.check, "aria-label": item.current ? t("当前") : t("已开启") }));
245
+ if (item.current || item.checked || item.selected) {
246
+ row.append(element("span", { class: "ge-pop-check", html: ICONS.check, "aria-label": item.checked ? t("已开启") : t("当前") }));
236
247
  row.setAttribute("data-current", "");
237
- if (item.checked) row.setAttribute("aria-checked", "true");
248
+ if (item.checked || item.selected) row.setAttribute("aria-checked", "true");
238
249
  }
239
250
  row.disabled = Boolean(item.disabled || item.current);
240
251
  row.run = item.run;
@@ -267,6 +278,7 @@ export function createMenu() {
267
278
  }
268
279
 
269
280
  const clamp = (value, low, high) => Math.max(low, Math.min(high, value));
281
+ const TALL = 34; // px: a block taller than this (a line of text is 26px) is a tall one: its menu may stand over it
270
282
 
271
283
  function place() {
272
284
  if (options.inside) return;
@@ -315,11 +327,16 @@ export function createMenu() {
315
327
  const below = innerHeight - margin - (block.bottom + gap);
316
328
  const above = block.top - gap - margin;
317
329
  const beside = anchor.left - gap - width;
318
- if (beside >= margin) {
319
- // Left of the block, centered on its handle.
330
+ // A block of more than a line (a table, a formula, a highlight, an image: taller than TALL) may
331
+ // have the menu over it: beside its handle, right of it where there is no room left of it,
332
+ // rather than below the block, away from the handle.
333
+ const middle = (anchor.top + anchor.bottom) / 2;
334
+ const onRight = block.bottom - block.top > TALL && anchor.right + gap + width <= innerWidth - margin;
335
+ if (beside >= margin || onRight) {
336
+ // Beside the handle (never over it), left first, centered on it.
320
337
  fit(room);
321
- left = beside;
322
- top = clamp((anchor.top + anchor.bottom) / 2 - height / 2, margin, innerHeight - margin - height);
338
+ left = beside >= margin ? beside : anchor.right + gap;
339
+ top = clamp(middle - height / 2, margin, innerHeight - margin - height);
323
340
  } else if (Math.max(below, above) >= Math.min(height, 180)) {
324
341
  // Below the block, else above it; in the larger of the two when it fits in neither.
325
342
  left = clamp(anchor.left, margin, innerWidth - width - margin);
@@ -360,6 +377,7 @@ export function createMenu() {
360
377
  const search = row.subSearch && { placeholder: row.subSearch.placeholder, filter: (text) => closing(row.subSearch.filter(text)) };
361
378
  sub.open(items, row.getBoundingClientRect(), {
362
379
  side: "right", gap: 0, height: Math.round(innerHeight * 0.7), highlight: keys, width: row.subWidth, label: row.textContent, search, empty: row.subSearch?.empty, focus: keys,
380
+ ...(row.subLook.icons === false ? { icons: false } : {}), ...(row.subLook.compact ? { compact: true } : {}),
363
381
  onClose: () => {
364
382
  row.removeAttribute("aria-expanded");
365
383
  if (subRow === row) {
@@ -439,6 +457,7 @@ export function createMenu() {
439
457
  opened.add(menu);
440
458
  node = element("div", { class: "ge-pop", role: "menu", "aria-label": opts.label ?? t("菜单") });
441
459
  if (options.width) node.setAttribute("data-sized", "");
460
+ if (options.compact) node.setAttribute("data-compact", "");
442
461
  if (opts.inside) {
443
462
  node.setAttribute("data-inside", "");
444
463
  opts.inside.append(node);
@@ -1,6 +1,6 @@
1
1
  import { Z } from "../../shared/layers.mjs";
2
2
  import { PANEL_STYLE, onPanels, panelGone, panelRoom, panelShown } from "./panel.mjs";
3
- import { addStyle, button, element, mount } from "./ui.mjs";
3
+ import { addStyle, element, mount, textButton } from "./ui.mjs";
4
4
  import { t } from "../../shared/i18n/index.mjs";
5
5
  import { preference } from "../../shared/preferences.mjs";
6
6
  import { routine } from "./quiet.mjs";
@@ -128,7 +128,7 @@ export function showPanel(title) {
128
128
  closePanel();
129
129
  addStyle(PANEL_STYLE);
130
130
  panel = mount(element("div", { class: "ge-panel", role: "region", "aria-label": title },
131
- element("div", { class: "ge-panel-head" }, element("span", { text: title }), button(t("关闭"), closePanel, { "data-quiet": "" }))));
131
+ element("div", { class: "ge-panel-head" }, element("span", { text: title }), textButton(t("关闭"), closePanel, { quiet: true }))));
132
132
  panelShown(panel);
133
133
  }
134
134
 
@@ -31,8 +31,15 @@ export function menuEntry(key) {
31
31
  /** The row of a key of a menu of blocks: its type's, or its variant's; null for neither. */
32
32
  export const menuRow = (key) => TYPE_INFO[key] ?? menuEntry(key).variant;
33
33
 
34
- /** The keys of every variant there is now. */
35
- export const variantKeys = () => Object.keys(TYPE_COMPONENT).flatMap((type) => Object.keys(pageOfType(type)?.menuVariants?.() ?? {}).map((name) => `${type}:${name}`));
34
+ // Every variant there is now: [key, row].
35
+ const variants = () => Object.keys(TYPE_COMPONENT).flatMap((type) => Object.entries(pageOfType(type)?.menuVariants?.() ?? {}).map(([name, row]) => [`${type}:${name}`, row]));
36
+
37
+ /**
38
+ * The keys of the variants the menus of blocks offer now ("/", 在下方新建, the handle's +, 转换成): every
39
+ * one, a view of a table (`readsTables`: a custom block whose needs hold "tables") too, which binds
40
+ * itself to the table above it as it is made (components/installed/page.mjs; page/table/binding.mjs).
41
+ */
42
+ export const variantKeys = () => variants().map(([key]) => key);
36
43
 
37
44
  /** The page objects, in the order they are made. */
38
45
  export const pageObjects = () => Object.values(pages);
@@ -3,8 +3,10 @@ import { Z } from "../../shared/layers.mjs";
3
3
  // The editor's bottom panels: the conflicts' (conflicts.mjs, left) and the lost texts' (notices.mjs,
4
4
  // right) are the same card, and the bar of the Agent's changes (changes/bar.mjs, in the middle) is its
5
5
  // buttons in a row: a small muted head with a red dot, items under it, the reader's words as
6
- // a quote, one filled primary button, the rest outlined or, looking only, quiet text. No notice covers
7
- // one: while one stands, the toast stands above it (notices.mjs, and the workbench's, told the room).
6
+ // a quote, one pale blue primary button, the rest with no line and no fill (gray under the pointer) or, looking
7
+ // only, quiet text: all of them the editor's one button look (look.mjs BUTTONS, ui.mjs textButton), none of
8
+ // their own here. No notice covers one: while one stands, the toast stands above it (notices.mjs, and the
9
+ // workbench's, told the room).
8
10
 
9
11
  const PANELS = ".ge-conflicts:not([hidden]), .ge-panel, .ge-changes:not([hidden])";
10
12
 
@@ -55,11 +57,4 @@ export const PANEL_STYLE = `
55
57
  :is(.ge-conflict, .ge-panel-item) p + .ge-version { margin-top: 6px; }
56
58
  :is(.ge-conflicts, .ge-panel) .ge-version { margin: 0; padding: 0 0 0 10px; border-left: 2px solid var(--ge-quote); overflow-wrap: anywhere; }
57
59
  :is(.ge-conflicts, .ge-panel) .ge-actions { display: flex; flex-wrap: wrap; align-items: center; gap: 6px; margin-top: 12px; }
58
- :is(.ge-conflicts, .ge-panel) button { height: 28px; padding: 0 10px; border: 1px solid var(--ge-edge); border-radius: 6px; background: transparent; color: inherit; font: inherit; font-weight: 500; white-space: nowrap; cursor: pointer; }
59
- :is(.ge-conflicts, .ge-panel) button:hover:not(:disabled) { background: var(--ge-hover); }
60
- :is(.ge-conflicts, .ge-panel) button[data-primary] { border-color: transparent; background: var(--ge-accent); color: #fff; }
61
- :is(.ge-conflicts, .ge-panel) button[data-primary]:hover:not(:disabled) { background: var(--ge-accent-hover); }
62
- :is(.ge-conflicts, .ge-panel) button[data-quiet] { height: 24px; padding: 0 6px; border-color: transparent; color: var(--ge-tx2); font-weight: 400; }
63
- :is(.ge-conflicts, .ge-panel) button[data-quiet]:hover:not(:disabled) { color: var(--ge-tx); background: transparent; }
64
- :is(.ge-conflicts, .ge-panel) button:disabled { opacity: .45; cursor: default; }
65
60
  `;