@heycys/gallery 0.1.0 → 0.1.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (465) hide show
  1. package/THIRD-PARTY-NOTICES.md +51 -1
  2. package/browser/editor/components/callout/index.mjs +40 -15
  3. package/browser/editor/components/columns/page.mjs +45 -32
  4. package/browser/editor/components/details/index.mjs +2 -1
  5. package/browser/editor/components/dialog/index.mjs +2 -1
  6. package/browser/editor/components/dialog/page.mjs +0 -18
  7. package/browser/editor/components/divider/index.mjs +1 -1
  8. package/browser/editor/components/embed/index.mjs +2 -2
  9. package/browser/editor/components/figure/page.mjs +10 -1
  10. package/browser/editor/components/file/page.mjs +2 -2
  11. package/browser/editor/components/flowchart/add.mjs +7 -6
  12. package/browser/editor/components/flowchart/page.mjs +1 -1
  13. package/browser/editor/components/heading/index.mjs +2 -0
  14. package/browser/editor/components/heading/page.mjs +6 -0
  15. package/browser/editor/components/highlight/index.mjs +4 -20
  16. package/browser/editor/components/icons.mjs +13 -2
  17. package/browser/editor/components/image/crop.mjs +6 -9
  18. package/browser/editor/components/image/page.mjs +2 -2
  19. package/browser/editor/components/installed/index.mjs +82 -29
  20. package/browser/editor/components/installed/page.mjs +146 -34
  21. package/browser/editor/components/installed/served.mjs +6 -5
  22. package/browser/editor/components/instances.mjs +18 -0
  23. package/browser/editor/components/kit.mjs +3 -0
  24. package/browser/editor/components/list/page.mjs +3 -6
  25. package/browser/editor/components/media/page.mjs +44 -14
  26. package/browser/editor/components/pages.mjs +2 -2
  27. package/browser/editor/components/registry.mjs +68 -33
  28. package/browser/editor/components/section/index.mjs +2 -1
  29. package/browser/editor/components/set-apart.mjs +24 -0
  30. package/browser/editor/components/table/index.mjs +64 -5
  31. package/browser/editor/components/table/page.mjs +30 -19
  32. package/browser/editor/page/annotate/anchors.mjs +4 -3
  33. package/browser/editor/page/annotate/card.mjs +3 -6
  34. package/browser/editor/page/annotate/index.mjs +61 -34
  35. package/browser/editor/page/autosave.mjs +357 -38
  36. package/browser/editor/page/beside.mjs +5 -5
  37. package/browser/editor/page/block-menu/colors.mjs +3 -1
  38. package/browser/editor/page/block-menu/index.mjs +8 -6
  39. package/browser/editor/page/blocks.mjs +16 -7
  40. package/browser/editor/page/board/client.mjs +57 -0
  41. package/browser/editor/page/board/hint.mjs +145 -0
  42. package/browser/editor/page/board/history.mjs +119 -0
  43. package/browser/editor/page/board/index.mjs +970 -0
  44. package/browser/editor/page/board/settings.mjs +209 -0
  45. package/browser/editor/page/caret.mjs +5 -2
  46. package/browser/editor/page/changes/bar.mjs +94 -0
  47. package/browser/editor/page/changes/ghost.mjs +206 -0
  48. package/browser/editor/page/changes/gone-words.mjs +94 -0
  49. package/browser/editor/page/changes/index.mjs +447 -0
  50. package/browser/editor/page/changes/words.mjs +27 -0
  51. package/browser/editor/page/clipboard/import/colors.mjs +3 -3
  52. package/browser/editor/page/clipboard/import/html.mjs +29 -6
  53. package/browser/editor/page/clipboard/import/inline.mjs +32 -0
  54. package/browser/editor/page/clipboard/import/markdown.mjs +58 -13
  55. package/browser/editor/page/clipboard/import/read.mjs +6 -1
  56. package/browser/editor/page/clipboard/import/to-blocks.mjs +44 -12
  57. package/browser/editor/page/clipboard/import/yuque.mjs +622 -0
  58. package/browser/editor/page/clipboard/index.mjs +156 -26
  59. package/browser/editor/page/clipboard/own/blocks.mjs +25 -16
  60. package/browser/editor/page/clipboard/own/chart-keys.mjs +41 -28
  61. package/browser/editor/page/clipboard/own/describe.mjs +16 -7
  62. package/browser/editor/page/clipboard/own/export.mjs +6 -6
  63. package/browser/editor/page/clipboard/own/selection.mjs +3 -3
  64. package/browser/editor/page/clipboard/own/writers.mjs +0 -11
  65. package/browser/editor/page/columns/index.mjs +48 -46
  66. package/browser/editor/page/commit.mjs +98 -25
  67. package/browser/editor/page/conflicts.mjs +13 -33
  68. package/browser/editor/page/convert.mjs +8 -7
  69. package/browser/editor/page/core.mjs +81 -27
  70. package/browser/editor/page/custom-page.mjs +106 -0
  71. package/browser/editor/page/drag/index.mjs +40 -24
  72. package/browser/editor/page/drag/preview.mjs +9 -4
  73. package/browser/editor/page/editor.mjs +120 -28
  74. package/browser/editor/page/emoji-picker/emoji-tab.mjs +22 -13
  75. package/browser/editor/page/emoji-picker/grid.mjs +7 -5
  76. package/browser/editor/page/emoji-picker/icon-tab.mjs +4 -4
  77. package/browser/editor/page/emoji-picker/icons.mjs +0 -1
  78. package/browser/editor/page/emoji-picker/index.mjs +11 -9
  79. package/browser/editor/page/emoji-picker/styles.mjs +156 -2
  80. package/browser/editor/page/emoji-picker/support.mjs +6 -4
  81. package/browser/editor/page/emoji-picker/upload.mjs +14 -13
  82. package/browser/editor/page/fills.mjs +5 -3
  83. package/browser/editor/page/fold/index.mjs +348 -0
  84. package/browser/editor/page/fold/rule.mjs +125 -0
  85. package/browser/editor/page/folded.mjs +23 -0
  86. package/browser/editor/page/format-bar/bar.mjs +2 -1
  87. package/browser/editor/page/format-bar/index.mjs +1 -1
  88. package/browser/editor/page/geometry.mjs +8 -6
  89. package/browser/editor/page/handle/index.mjs +22 -14
  90. package/browser/editor/page/hints/index.mjs +1 -1
  91. package/browser/editor/page/history.mjs +24 -4
  92. package/browser/editor/page/insert/index.mjs +30 -17
  93. package/browser/editor/page/links/index.mjs +5 -3
  94. package/browser/editor/page/links/pages.mjs +27 -9
  95. package/browser/editor/page/long-runs.mjs +75 -0
  96. package/browser/editor/page/look.mjs +69 -6
  97. package/browser/editor/page/margin.mjs +63 -27
  98. package/browser/editor/page/media-menu/index.mjs +6 -7
  99. package/browser/editor/page/menu.mjs +86 -31
  100. package/browser/editor/page/merge.mjs +24 -0
  101. package/browser/editor/page/notices.mjs +3 -3
  102. package/browser/editor/page/offered.mjs +1 -1
  103. package/browser/editor/page/outline/folds.mjs +11 -10
  104. package/browser/editor/page/outline/index.mjs +131 -45
  105. package/browser/editor/page/outline/list.mjs +23 -11
  106. package/browser/editor/page/outline/read.mjs +1 -1
  107. package/browser/editor/page/outline/strip.mjs +7 -1
  108. package/browser/editor/page/page-objects.mjs +13 -2
  109. package/browser/editor/page/panel.mjs +9 -13
  110. package/browser/editor/page/present-links.mjs +11 -2
  111. package/browser/editor/page/resize/index.mjs +42 -29
  112. package/browser/editor/page/selection/delete.mjs +8 -6
  113. package/browser/editor/page/selection/index.mjs +10 -3
  114. package/browser/editor/page/served.mjs +14 -0
  115. package/browser/editor/page/session.mjs +101 -6
  116. package/browser/editor/page/slash-menu/index.mjs +3 -3
  117. package/browser/editor/page/table/cell-bar.mjs +4 -1
  118. package/browser/editor/page/table/cells.mjs +103 -47
  119. package/browser/editor/page/table/icons.mjs +3 -1
  120. package/browser/editor/page/table/index.mjs +40 -16
  121. package/browser/editor/page/table/pictures.mjs +299 -0
  122. package/browser/editor/page/table/views.mjs +150 -0
  123. package/browser/editor/page/table/widths.mjs +9 -4
  124. package/browser/editor/page/text-select/index.mjs +43 -14
  125. package/browser/editor/page/todo-writes.mjs +75 -0
  126. package/browser/editor/page/tooltip.mjs +1 -1
  127. package/browser/editor/page/type-grid.mjs +4 -3
  128. package/browser/editor/page/typing/code-edges.mjs +63 -17
  129. package/browser/editor/page/typing/index.mjs +65 -9
  130. package/browser/editor/page/typing/leave.mjs +1 -1
  131. package/browser/editor/page/ui.mjs +13 -0
  132. package/browser/shared/annotations.mjs +8 -10
  133. package/browser/shared/block-packs.mjs +404 -0
  134. package/browser/shared/board-places.mjs +224 -0
  135. package/browser/shared/card-size.mjs +59 -0
  136. package/browser/shared/code-folds.mjs +5 -1
  137. package/browser/shared/colors.mjs +17 -14
  138. package/browser/shared/component-catalog.mjs +345 -54
  139. package/browser/shared/component-source.mjs +37 -0
  140. package/browser/shared/components/callout.mjs +4 -2
  141. package/browser/shared/components/index.mjs +72 -9
  142. package/browser/shared/components/installed.mjs +110 -8
  143. package/browser/shared/components/page.mjs +22 -3
  144. package/browser/shared/components/state.mjs +5 -1
  145. package/browser/shared/components/table.mjs +1 -1
  146. package/browser/shared/components/text.mjs +2 -2
  147. package/browser/shared/document-look.mjs +183 -0
  148. package/browser/shared/drafts.mjs +432 -0
  149. package/browser/shared/emoji/data/LICENSE-lucide.txt +43 -0
  150. package/browser/shared/emoji/data/README.md +4 -2
  151. package/browser/shared/emoji/data/categories.json +1 -1
  152. package/browser/shared/emoji/data/keywords-en.json +1 -1
  153. package/browser/shared/emoji/data/keywords-zh.json +1 -1
  154. package/browser/shared/emoji/data/names.json +1 -1
  155. package/browser/shared/emoji/data/positions.json +1 -1
  156. package/browser/shared/emoji/data/twemoji-index.json +1 -1
  157. package/browser/shared/emoji/data/twemoji-svg.bin +0 -0
  158. package/browser/shared/emoji/data.mjs +10 -12
  159. package/browser/shared/emoji/emoji.mjs +8 -7
  160. package/browser/shared/emoji/icon-value.mjs +4 -3
  161. package/browser/shared/extension-sidebar.mjs +126 -0
  162. package/browser/shared/extensions.mjs +79 -0
  163. package/browser/shared/file-table.mjs +101 -0
  164. package/browser/shared/html-tree.mjs +11 -5
  165. package/browser/shared/i18n/en.mjs +374 -35
  166. package/browser/shared/json-layout.mjs +47 -0
  167. package/browser/shared/long-runs.mjs +39 -0
  168. package/browser/shared/net-cache.mjs +133 -0
  169. package/browser/shared/net-keys.mjs +32 -0
  170. package/browser/shared/net-policy.mjs +177 -0
  171. package/browser/shared/new-names.mjs +5 -2
  172. package/browser/shared/outline-shape.mjs +128 -0
  173. package/browser/shared/outline.mjs +458 -0
  174. package/browser/shared/pack-manifest.mjs +77 -0
  175. package/browser/shared/page-address.mjs +6 -3
  176. package/browser/shared/page-cards.mjs +308 -0
  177. package/browser/shared/page-links.mjs +69 -6
  178. package/browser/shared/pages.mjs +388 -0
  179. package/browser/shared/paths.mjs +6 -0
  180. package/browser/shared/preferences.mjs +10 -4
  181. package/browser/shared/preview-server.mjs +3 -7
  182. package/browser/shared/session.mjs +13 -5
  183. package/browser/shared/shipped-blocks.mjs +299 -0
  184. package/browser/shared/table-chart.mjs +33 -1
  185. package/browser/shared/todos.mjs +83 -0
  186. package/browser/shared/user-directory.mjs +24 -0
  187. package/browser/shared/versions.mjs +14 -0
  188. package/browser/shared/web-links.mjs +134 -0
  189. package/browser/shared/workspace-columns.mjs +120 -0
  190. package/browser/shared/workspace-look.mjs +91 -0
  191. package/browser/shared/workspace-name.mjs +154 -0
  192. package/browser/shared/workspace-query.mjs +125 -0
  193. package/browser/shared/workspace-registry.mjs +272 -0
  194. package/browser/shared/workspace.mjs +171 -20
  195. package/browser/shared/zoom.mjs +5 -5
  196. package/dist/chunk-2NRBY6AJ.mjs +2 -0
  197. package/dist/chunk-32ZUEFZ7.mjs +2 -0
  198. package/dist/chunk-35NQ4PLQ.mjs +2 -0
  199. package/dist/chunk-3KJHLHUO.mjs +2 -0
  200. package/dist/chunk-3NJACR4W.mjs +2 -0
  201. package/dist/chunk-4AV456RQ.mjs +2 -0
  202. package/dist/chunk-4OZWXZE5.mjs +5 -0
  203. package/dist/chunk-5XYHDBJ5.mjs +2 -0
  204. package/dist/chunk-5ZJA7CXT.mjs +2 -0
  205. package/dist/chunk-6A53MZYZ.mjs +2 -0
  206. package/dist/chunk-6EXH3ORZ.mjs +166 -0
  207. package/dist/chunk-6EZ7FNIK.mjs +3 -0
  208. package/dist/{chunk-UXUK4PMC.mjs → chunk-6QBHU4DF.mjs} +1 -1
  209. package/dist/{chunk-6U2SLSDN.mjs → chunk-6VTU6KEO.mjs} +1 -1
  210. package/dist/chunk-B4P2CM2J.mjs +3 -0
  211. package/dist/chunk-BPL64HGA.mjs +4 -0
  212. package/dist/chunk-BVEFGE4B.mjs +2 -0
  213. package/dist/chunk-BZ5RAF7L.mjs +2 -0
  214. package/dist/chunk-CRJEG7MT.mjs +2 -0
  215. package/dist/{chunk-B3VTYBYR.mjs → chunk-D4CKRD3V.mjs} +91 -91
  216. package/dist/chunk-D4EURAX4.mjs +4 -0
  217. package/dist/chunk-DQCE7TJY.mjs +5 -0
  218. package/dist/chunk-DR73Y2UJ.mjs +3 -0
  219. package/dist/{chunk-TMYZB6AV.mjs → chunk-EKNHM3P4.mjs} +1 -1
  220. package/dist/{chunk-DB4WKGYF.mjs → chunk-ERLAIBOA.mjs} +2 -2
  221. package/dist/chunk-EURLTOTZ.mjs +4 -0
  222. package/dist/chunk-FJYN7RTH.mjs +4 -0
  223. package/dist/chunk-FWNRPMCJ.mjs +12 -0
  224. package/dist/chunk-FWW4CSAZ.mjs +2 -0
  225. package/dist/{chunk-2B5E4CDJ.mjs → chunk-GPIWQ4X4.mjs} +1 -1
  226. package/dist/chunk-GY3FAUVM.mjs +2 -0
  227. package/dist/chunk-HLYV7RIH.mjs +2 -0
  228. package/dist/chunk-HMYTM3GT.mjs +15 -0
  229. package/dist/chunk-IA4PSIMD.mjs +2 -0
  230. package/dist/chunk-JEUK3ZO7.mjs +2 -0
  231. package/dist/chunk-JVHHHGEA.mjs +3 -0
  232. package/dist/chunk-KTKHRC6H.mjs +2 -0
  233. package/dist/chunk-L7UP52JO.mjs +2 -0
  234. package/dist/chunk-MHW7ZKOU.mjs +2 -0
  235. package/dist/chunk-N76HWBA3.mjs +10 -0
  236. package/dist/chunk-N7AZZLGT.mjs +548 -0
  237. package/dist/chunk-NAMN3RAF.mjs +2 -0
  238. package/dist/{chunk-YXAUQPVK.mjs → chunk-NFMCP2HI.mjs} +3 -3
  239. package/dist/chunk-NG375ILQ.mjs +2 -0
  240. package/dist/chunk-NVRNLK25.mjs +6 -0
  241. package/dist/chunk-NWFBE2YA.mjs +2 -0
  242. package/dist/chunk-NWR2LT5B.mjs +2 -0
  243. package/dist/chunk-OJKMINIU.mjs +20 -0
  244. package/dist/chunk-OUUP3WKT.mjs +2 -0
  245. package/dist/chunk-OW5NWPOJ.mjs +10 -0
  246. package/dist/chunk-PAREWQGB.mjs +4 -0
  247. package/dist/chunk-POQSE4C2.mjs +2 -0
  248. package/dist/chunk-PUOQ65NC.mjs +2 -0
  249. package/dist/{chunk-Z52HTUW7.mjs → chunk-PVER7LSC.mjs} +2 -2
  250. package/dist/chunk-PZDLJJTJ.mjs +3 -0
  251. package/dist/chunk-Q47PLKIJ.mjs +15 -0
  252. package/dist/chunk-Q4UEPUWF.mjs +2 -0
  253. package/dist/chunk-QKXMPUXC.mjs +2 -0
  254. package/dist/chunk-QOUEFUCH.mjs +16 -0
  255. package/dist/chunk-RFDZXFJF.mjs +13 -0
  256. package/dist/chunk-RKPWLGZ3.mjs +4 -0
  257. package/dist/chunk-RMECZA2K.mjs +2 -0
  258. package/dist/{chunk-EUX7IC5J.mjs → chunk-SQ6Y2ZMA.mjs} +2 -2
  259. package/dist/chunk-SX4LJYT6.mjs +8 -0
  260. package/dist/chunk-SXHBYZST.mjs +16 -0
  261. package/dist/chunk-TANZRINB.mjs +2 -0
  262. package/dist/chunk-TEZAWDSQ.mjs +2 -0
  263. package/dist/chunk-UBBRTJ2R.mjs +24 -0
  264. package/dist/chunk-UFNYFFKO.mjs +20 -0
  265. package/dist/chunk-UGWYKHBL.mjs +170 -0
  266. package/dist/chunk-UKSHDZZ6.mjs +2 -0
  267. package/dist/chunk-UMHUSOPJ.mjs +2 -0
  268. package/dist/chunk-UNOYVIYR.mjs +2 -0
  269. package/dist/chunk-V6RIYQZZ.mjs +4 -0
  270. package/dist/chunk-VJPFVNNW.mjs +15 -0
  271. package/dist/chunk-VS3ZMVGX.mjs +5 -0
  272. package/dist/chunk-VTKNEYT3.mjs +6 -0
  273. package/dist/chunk-VXACTLO3.mjs +3 -0
  274. package/dist/chunk-W3BGBJQW.mjs +2 -0
  275. package/dist/chunk-YI43RG4P.mjs +2 -0
  276. package/dist/chunk-YQGT4AB2.mjs +6 -0
  277. package/dist/chunk-ZB4H7ZN4.mjs +2 -0
  278. package/dist/{chunk-ACOPDCNB.mjs → chunk-ZHEHPMBK.mjs} +1 -1
  279. package/dist/chunk-ZTHICSSF.mjs +2 -0
  280. package/dist/chunk-ZUNVAXLH.mjs +2 -0
  281. package/dist/chunk-ZWPMCK7P.mjs +2 -0
  282. package/dist/cli.mjs +1 -1
  283. package/dist/server.mjs +1 -1
  284. package/dist/{chunk-EVJ3BX3M.mjs → update-fetch.mjs} +1 -1
  285. package/dist/worker.mjs +1 -1
  286. package/kit/board.css +95 -0
  287. package/kit/board.js +250 -0
  288. package/kit/charts.js +5 -71
  289. package/kit/code.js +14 -14
  290. package/kit/math.js +18 -2
  291. package/kit/report.css +500 -151
  292. package/kit/runtime.js +1720 -170
  293. package/kit/state.js +10 -1
  294. package/kit/tables.js +172 -37
  295. package/kit/ui.js +166 -27
  296. package/package.json +2 -1
  297. package/packs/gallery/card/component.json +14 -0
  298. package/packs/gallery/card/example.html +10 -0
  299. package/packs/gallery/card/preview.svg +1 -0
  300. package/packs/gallery/card/style.css +6 -0
  301. package/packs/gallery/card/template.html +6 -0
  302. package/packs/gallery/card/writing.md +14 -0
  303. package/packs/gallery/chart-card/component.json +15 -0
  304. package/packs/gallery/chart-card/example.html +14 -0
  305. package/packs/gallery/chart-card/kit.js +130 -0
  306. package/packs/gallery/chart-card/preview.svg +1 -0
  307. package/packs/gallery/chart-card/style.css +42 -0
  308. package/packs/gallery/chart-card/template.html +13 -0
  309. package/packs/gallery/chart-card/writing.md +20 -0
  310. package/packs/gallery/chart-view/component.json +20 -0
  311. package/packs/gallery/chart-view/example.html +13 -0
  312. package/packs/gallery/chart-view/kit.js +355 -0
  313. package/packs/gallery/chart-view/preview.svg +1 -0
  314. package/packs/gallery/chart-view/style.css +94 -0
  315. package/packs/gallery/chart-view/template.html +3 -0
  316. package/packs/gallery/chart-view/writing.md +22 -0
  317. package/packs/gallery/countdown/component.json +18 -0
  318. package/packs/gallery/countdown/example.html +3 -0
  319. package/packs/gallery/countdown/kit.js +156 -0
  320. package/packs/gallery/countdown/preview.svg +1 -0
  321. package/packs/gallery/countdown/style.css +130 -0
  322. package/packs/gallery/countdown/template.html +3 -0
  323. package/packs/gallery/countdown/writing.md +22 -0
  324. package/packs/gallery/habit/component.json +14 -0
  325. package/packs/gallery/habit/example.html +3 -0
  326. package/packs/gallery/habit/kit.js +295 -0
  327. package/packs/gallery/habit/preview.svg +1 -0
  328. package/packs/gallery/habit/style.css +246 -0
  329. package/packs/gallery/habit/template.html +3 -0
  330. package/packs/gallery/habit/writing.md +21 -0
  331. package/packs/gallery/heatmap/component.json +18 -0
  332. package/packs/gallery/heatmap/example.html +3 -0
  333. package/packs/gallery/heatmap/kit.js +351 -0
  334. package/packs/gallery/heatmap/preview.svg +1 -0
  335. package/packs/gallery/heatmap/style.css +201 -0
  336. package/packs/gallery/heatmap/template.html +3 -0
  337. package/packs/gallery/heatmap/writing.md +21 -0
  338. package/packs/gallery/kanban/component.json +18 -0
  339. package/packs/gallery/kanban/example.html +12 -0
  340. package/packs/gallery/kanban/kit.js +540 -0
  341. package/packs/gallery/kanban/preview.svg +1 -0
  342. package/packs/gallery/kanban/style.css +212 -0
  343. package/packs/gallery/kanban/template.html +3 -0
  344. package/packs/gallery/kanban/writing.md +20 -0
  345. package/packs/gallery/metric/component.json +22 -0
  346. package/packs/gallery/metric/example.html +15 -0
  347. package/packs/gallery/metric/kit.js +248 -0
  348. package/packs/gallery/metric/preview.svg +1 -0
  349. package/packs/gallery/metric/style.css +92 -0
  350. package/packs/gallery/metric/template.html +3 -0
  351. package/packs/gallery/metric/writing.md +23 -0
  352. package/packs/gallery/note/component.json +14 -0
  353. package/packs/gallery/note/example.html +3 -0
  354. package/packs/gallery/note/kit.js +102 -0
  355. package/packs/gallery/note/preview.svg +1 -0
  356. package/packs/gallery/note/style.css +76 -0
  357. package/packs/gallery/note/template.html +3 -0
  358. package/packs/gallery/note/writing.md +18 -0
  359. package/packs/gallery/pack.json +8 -0
  360. package/packs/gallery/recent/component.json +13 -0
  361. package/packs/gallery/recent/example.html +1 -0
  362. package/packs/gallery/recent/kit.js +238 -0
  363. package/packs/gallery/recent/preview.svg +1 -0
  364. package/packs/gallery/recent/style.css +158 -0
  365. package/packs/gallery/recent/template.html +1 -0
  366. package/packs/gallery/recent/writing.md +15 -0
  367. package/packs/gallery/static/component.json +13 -0
  368. package/packs/gallery/static/example.html +11 -0
  369. package/packs/gallery/static/preview.svg +1 -0
  370. package/packs/gallery/static/style.css +138 -0
  371. package/packs/gallery/static/template.html +1 -0
  372. package/packs/gallery/static/writing.md +18 -0
  373. package/packs/gallery/stats/component.json +13 -0
  374. package/packs/gallery/stats/example.html +1 -0
  375. package/packs/gallery/stats/kit.js +166 -0
  376. package/packs/gallery/stats/preview.svg +1 -0
  377. package/packs/gallery/stats/style.css +151 -0
  378. package/packs/gallery/stats/template.html +1 -0
  379. package/packs/gallery/stats/writing.md +11 -0
  380. package/packs/gallery/today/component.json +12 -0
  381. package/packs/gallery/today/example.html +1 -0
  382. package/packs/gallery/today/kit.js +185 -0
  383. package/packs/gallery/today/preview.svg +1 -0
  384. package/packs/gallery/today/style.css +120 -0
  385. package/packs/gallery/today/template.html +1 -0
  386. package/packs/gallery/today/writing.md +14 -0
  387. package/packs/gallery/todos/component.json +19 -0
  388. package/packs/gallery/todos/example.html +3 -0
  389. package/packs/gallery/todos/kit.js +342 -0
  390. package/packs/gallery/todos/preview.svg +1 -0
  391. package/packs/gallery/todos/style.css +267 -0
  392. package/packs/gallery/todos/template.html +3 -0
  393. package/packs/gallery/todos/writing.md +30 -0
  394. package/packs/gallery/weather/component.json +19 -0
  395. package/packs/gallery/weather/example.html +3 -0
  396. package/packs/gallery/weather/kit.js +312 -0
  397. package/packs/gallery/weather/preview.svg +1 -0
  398. package/packs/gallery/weather/style.css +258 -0
  399. package/packs/gallery/weather/template.html +3 -0
  400. package/packs/gallery/weather/writing.md +26 -0
  401. package/packs/gallery-soft/pack.json +8 -0
  402. package/release.json +13 -11
  403. package/sdk/doc-kit.d.ts +404 -7
  404. package/sdk/doc-state.d.ts +2 -0
  405. package/skill/SKILL.md +71 -26
  406. package/skill/references/block-script.md +140 -0
  407. package/skill/references/building-blocks.md +257 -0
  408. package/skill/references/example-report.html +1 -1
  409. package/skill/references/extensions.md +59 -0
  410. package/skill/references/pages-and-data.md +221 -0
  411. package/skill/references/writing-html.md +9 -7
  412. package/skill/sdk/doc-kit.d.ts +404 -7
  413. package/skill/sdk/doc-state.d.ts +2 -0
  414. package/web/assets/index-BK2e_07w.js +13 -0
  415. package/web/assets/index-CWFI83mF.css +1 -0
  416. package/web/index.html +2 -2
  417. package/browser/editor/components/callout/page.mjs +0 -13
  418. package/dist/chunk-2PBALTR3.mjs +0 -57
  419. package/dist/chunk-3LA3EMDE.mjs +0 -15
  420. package/dist/chunk-5FRMCDPY.mjs +0 -16
  421. package/dist/chunk-5LEK2CBS.mjs +0 -2
  422. package/dist/chunk-5OFN5AHC.mjs +0 -2
  423. package/dist/chunk-5SIYS5HN.mjs +0 -2
  424. package/dist/chunk-5TEK3RAD.mjs +0 -2
  425. package/dist/chunk-6CYG3Z4V.mjs +0 -2
  426. package/dist/chunk-7GHT2UCA.mjs +0 -15
  427. package/dist/chunk-7QQBR7PB.mjs +0 -2
  428. package/dist/chunk-ATCJYAR4.mjs +0 -2
  429. package/dist/chunk-C7HWOBIF.mjs +0 -2
  430. package/dist/chunk-E7VYDG2X.mjs +0 -2
  431. package/dist/chunk-EZY3WC6Z.mjs +0 -15
  432. package/dist/chunk-FQGQH4KM.mjs +0 -2
  433. package/dist/chunk-G7TOXONE.mjs +0 -6
  434. package/dist/chunk-GPF4YWWB.mjs +0 -9
  435. package/dist/chunk-GYQV7Y4J.mjs +0 -120
  436. package/dist/chunk-HMHK3EQ6.mjs +0 -2
  437. package/dist/chunk-HQQMJCQJ.mjs +0 -10
  438. package/dist/chunk-IERUOGC3.mjs +0 -6
  439. package/dist/chunk-ITNLYXXV.mjs +0 -3
  440. package/dist/chunk-L4DVONOG.mjs +0 -2
  441. package/dist/chunk-LAE5NQ4B.mjs +0 -2
  442. package/dist/chunk-LC7YNQFG.mjs +0 -2
  443. package/dist/chunk-LHTFLRB6.mjs +0 -4
  444. package/dist/chunk-NFIBI4IP.mjs +0 -26
  445. package/dist/chunk-NSKUTQ5J.mjs +0 -5
  446. package/dist/chunk-O52JMOCZ.mjs +0 -2
  447. package/dist/chunk-P2CAZPDP.mjs +0 -3
  448. package/dist/chunk-QMQUXTU4.mjs +0 -12
  449. package/dist/chunk-QVWVFC5K.mjs +0 -6
  450. package/dist/chunk-QYKCJ7FG.mjs +0 -8
  451. package/dist/chunk-QZY6Q64C.mjs +0 -2
  452. package/dist/chunk-TDQP3DKQ.mjs +0 -10
  453. package/dist/chunk-TX6JH7TR.mjs +0 -2
  454. package/dist/chunk-UNUEWH4S.mjs +0 -2
  455. package/dist/chunk-V4CPWKMZ.mjs +0 -2
  456. package/dist/chunk-VACRB2NE.mjs +0 -3
  457. package/dist/chunk-W63L7367.mjs +0 -7
  458. package/dist/chunk-W7CXPCRV.mjs +0 -6
  459. package/dist/chunk-XINNG4F2.mjs +0 -4
  460. package/dist/chunk-YL2DPWVS.mjs +0 -4
  461. package/dist/chunk-YZ5Z6H4W.mjs +0 -4
  462. package/dist/chunk-ZBIM6ARY.mjs +0 -216
  463. package/skill/references/building-components.md +0 -327
  464. package/web/assets/index-B6Ai3wsa.js +0 -13
  465. package/web/assets/index-SYPC3EZy.css +0 -1
@@ -39,7 +39,7 @@ export function readOnlyReason(target) {
39
39
  if (editable(target) || target.closest("a[href]")) return null; // a link there is one to click on
40
40
  const locked = target.closest("[data-ge-lock]");
41
41
  if (locked) return lockText(locked.getAttribute("data-ge-lock"));
42
- const hint = READ_ONLY_HINTS.find(({ at }) => target.closest(at));
42
+ const hint = READ_ONLY_HINTS.find(({ at }) => (typeof at === "function" ? at(target) : target.closest(at)));
43
43
  if (hint) return hint.says;
44
44
  const ownText = [...target.childNodes].some((node) => node.nodeType === 3 && node.data.trim());
45
45
  return ownText ? t("这里暂不能在页面上修改。") : null;
@@ -148,6 +148,23 @@ export function createHistory({ changed, beforeUndo, blocks, afterText, refuse =
148
148
  for (const stack of [undoStack, redoStack]) if (stack.includes(step)) stack.splice(stack.indexOf(step), 1);
149
149
  }
150
150
 
151
+ // An attribute the file gave another value than the page had (`changes`: [element, name, from, to],
152
+ // `to` null for none; a key of a table a commit gave a pair anew: page/commit.mjs apply), the page's
153
+ // element set so: the steps that recorded `from` of it record `to` instead, so that an undo or a redo
154
+ // puts back what the file has, never the value it changed (a table's 视图 › redone with the key its view
155
+ // no longer carries).
156
+ function rekeyed(changes) {
157
+ if (changes.length === 0) return;
158
+ for (const step of [...undoStack, ...redoStack]) {
159
+ for (const recorded of [step.attributesBefore, step.attributesAfter]) {
160
+ for (const [element, name, from, to] of changes) {
161
+ const values = recorded?.get(element);
162
+ if (values?.some(([each, value]) => each === name && value === from)) recorded.set(element, values.map(([each, value]) => [each, each === name && value === from ? to : value]));
163
+ }
164
+ }
165
+ }
166
+ }
167
+
151
168
  // What a step puts into a block (`from`: what the step left there, `to`: what it puts back): as
152
169
  // recorded, unless someone else's words were merged into the block since the step; then the step's
153
170
  // change three ways against what the block holds now (null: the two touch the same place).
@@ -174,8 +191,10 @@ export function createHistory({ changed, beforeUndo, blocks, afterText, refuse =
174
191
  // after undo and redo (a deleted Sheet tab switches the Sheet shown). A step that names no text block
175
192
  // it came from keeps where the caret stood, which undo puts back, as notion-lite's selectionBefore.
176
193
  // `attributes`: [element, [names]] whose attributes the step records too (a table's cells: their
177
- // spans and widths, which its operations change: components/table/page.mjs).
178
- function struct(parents, touched, mutate, { attributes = [] } = {}) {
194
+ // spans and widths, which its operations change: components/table/page.mjs). `caret`: where the caret
195
+ // stood in the first text block it touched is kept too, which undo puts back (notion-lite's Enter in the
196
+ // page's title, enter.js: "撤销后光标回到回车前的位置"; typing/ enterBody).
197
+ function struct(parents, touched, mutate, { attributes = [], caret = false } = {}) {
179
198
  closeTyping();
180
199
  // What the change may leave untidy is tidied after it by the components that know (rows of
181
200
  // columns with a column emptied, lists set side by side: tidy), so what they name is recorded
@@ -189,7 +208,7 @@ export function createHistory({ changed, beforeUndo, blocks, afterText, refuse =
189
208
  }
190
209
  // A text block among the parents (a list item whose lists change) keeps its text through undo too.
191
210
  touched = [...new Set([...touched, ...parents.filter(isHost)])];
192
- const place = touched[0] ? null : caretPlace(parents[0]);
211
+ const place = touched[0] && !caret ? null : caretPlace(parents[0]);
193
212
  const before = parents.map(contentOf);
194
213
  const htmlBefore = new Map(touched.map((node) => [node, ownHTML(node)]));
195
214
  const classesBefore = new Map(touched.map((node) => [node, new Set(node.classList)]));
@@ -219,7 +238,7 @@ export function createHistory({ changed, beforeUndo, blocks, afterText, refuse =
219
238
  .filter(({ added, removed }) => added.length > 0 || removed.length > 0),
220
239
  attributesBefore,
221
240
  attributesAfter: attributesOf(),
222
- focusBefore: touched[0] ?? place?.host,
241
+ focusBefore: (caret ? place?.host : null) ?? touched[0] ?? place?.host,
223
242
  caretBefore: place?.offsets ?? null,
224
243
  focusAfter: result.focus,
225
244
  select: result.select ?? null,
@@ -381,6 +400,7 @@ export function createHistory({ changed, beforeUndo, blocks, afterText, refuse =
381
400
  sourceStep,
382
401
  fold,
383
402
  drop,
403
+ rekeyed,
384
404
  closeTyping,
385
405
  struct,
386
406
  finish,
@@ -4,13 +4,13 @@ import { begin, done, made } from "../made.mjs";
4
4
  import { selectsBeside } from "../beside.mjs";
5
5
  import { caretAt, nearestOnLine, placeCaret, selectAt } from "../caret.mjs";
6
6
  import { sectionOps } from "../page-objects.mjs";
7
- import { endOf, hoverAt, innerBox, measure } from "../geometry.mjs";
7
+ import { contentOf, 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
 
11
11
  // Where new blocks come from (docs/editor.md, "New blocks and conversions" and "Selecting
12
- // blocks"): a click on the empty space below the last block of a box (a new paragraph there, or the
13
- // caret into the empty one already at its end), Enter at the very start of a block (a paragraph
12
+ // blocks"): a click on the empty space below the last block of a box (not one whose end is its
13
+ // padding; a new paragraph there, or the caret into the empty one already at its end), Enter at the very start of a block (a paragraph
14
14
  // before it), the handle's "+" (an empty block beside the block: addNear), and the block menu's new section after a block (components/section/page.mjs). A
15
15
  // paragraph made here is written once it has text. "在下方新建一块" in a block's menu, like the "/"
16
16
  // menu's blocks in a block with text, is the editor's insertBelow; blocks also come from conversions
@@ -49,16 +49,20 @@ export function createInsert({ struct, blocks }) {
49
49
  }
50
50
 
51
51
  // A click on empty space (selection/marquee.mjs), below the last block of the box clicked (the
52
- // page, a Sheet panel, a section, a highlight block, a disclosure's content; below the report, the
53
- // page): a new paragraph at its end, or the caret into the empty paragraph already there
54
- // (geometry.mjs endOf). To the right of a boxed block (a code block, a callout, a file…: not text)
55
- // or of a row of columns, that block selected, so Delete takes it and Enter puts a paragraph after
56
- // it. Elsewhere beside text, the caret goes into the text block on that line (the nearest of those
52
+ // page, a Sheet panel, a section, a column, a detail card's content, a flowchart's node; below the
53
+ // report, the page): a new paragraph at its end, or the caret into the empty paragraph already there
54
+ // (geometry.mjs endOf). Under the last block of a box whose end is its own padding (endIsPadding: a
55
+ // highlight block, a callout, a disclosure's content; the user's, 2026-11-06, as notion-lite's click-blank.js
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
61
  // side by side), where the line is nearest the click (Notion's way); in the gap between two
58
62
  // blocks, or beside a block of no text, into the nearer of the blocks around it that is text, in the
59
63
  // innermost box at that height (boxBeside: the press may be on the page's margin, the block in a
60
64
  // Sheet's panel or a section), else in the boxes around that one, at the place nearest the click on
61
- // its nearest line (always somewhere: a click there never does nothing). The page stays where it
65
+ // its nearest line (somewhere in the box clicked or around it, when any is text). The page stays where it
62
66
  // is, that text out of sight too (caretNear; notion-lite's click-blank.js scrolls no page either).
63
67
  function clickBlank(x, y, target) {
64
68
  // In an open detail card, its content is the page: never a block behind it (marquee.mjs topOf).
@@ -77,7 +81,7 @@ export function createInsert({ struct, blocks }) {
77
81
  if (end?.focus) return caretAt(end.focus, "end");
78
82
  if (end) return newParagraph(end.box, end.after);
79
83
  const top = y + scrollY;
80
- const beside = boxedBeside(main, x, y);
84
+ const beside = boxedBeside(main, x, y, target);
81
85
  if (beside) return blocks().select(beside);
82
86
  const host = hoverAt(measure(main, { top, bottom: top }), x + scrollX, top, { reach: Infinity, skip: (unit) => !unit.text });
83
87
  if (host) return caretNear(host, x, y);
@@ -144,8 +148,8 @@ export function createInsert({ struct, blocks }) {
144
148
  return Math.max(rect.top - y, y - rect.bottom, 0);
145
149
  };
146
150
  // A block that is no text of its own (its category: a card, a container of its own or a whole
147
- // block; a code block, a callout, a formula block, a divider), as opposed to text blocks and the
148
- // boxes text flows in (a list, a quote, a section, columns).
151
+ // block, a highlight block, a callout; a code block, a formula block, a divider), as opposed to text
152
+ // blocks and the boxes text flows in (a list, a quote, a section, columns).
149
153
  const boxed = (unit) => BOXED.has(unit.getAttribute("data-ge-unit-kind"));
150
154
  // The text block of `unit` at its bottom (`last`) or its top: itself, or the last (first) of those it holds; none in a boxed block.
151
155
  function textEdge(unit, last) {
@@ -153,14 +157,23 @@ export function createInsert({ struct, blocks }) {
153
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)"));
154
158
  return (last ? texts.at(-1) : texts[0]) ?? null;
155
159
  }
156
- // A boxed block or a row of columns at height `y` with (x, y) to its right (in the page's margin,
157
- // or beside a narrower block), or null: the innermost, but never a block inside a row of columns
158
- // the click is to the right of too (the row is selected whole).
159
- function boxedBeside(main, x, y) {
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.
170
+ function boxedBeside(main, x, y, target) {
160
171
  let found = null;
161
172
  const right = (unit) => {
162
173
  const rect = unit.getBoundingClientRect();
163
- return y >= rect.top && y <= rect.bottom && x > rect.right;
174
+ 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);
164
177
  };
165
178
  for (const unit of main.querySelectorAll(`[data-ge-unit-kind]`)) {
166
179
  if (!selectsBeside(unit) || !unit.parentElement?.hasAttribute("data-ge-box") || unit.parentElement.closest("details:not([open])")) 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;
@@ -0,0 +1,75 @@
1
+ import { holdsLongRun } from "../../shared/long-runs.mjs";
2
+ import { textFilters } from "../components/registry.mjs";
3
+ import { addStyle } from "./ui.mjs";
4
+
5
+ // A long run in the text the page editor edits (src/shared/long-runs.mjs: a path, a URL, a long
6
+ // identifier, more than 20 characters with no place to break inside it) breaks where its line ends,
7
+ // as the kit breaks it in the page a reader sees (runtime/spacing.js, a span that breaks anywhere,
8
+ // .doc-long-run). No span goes into text the editor keeps equal to the file, so a text block whose
9
+ // own text holds such a run breaks anywhere as a whole (data-ge-long-run: word-break: break-all),
10
+ // and an ordinary word in that block may then be parted at a line's end too, which no other block's
11
+ // is (the compromise docs/editor.md names). The rule's weight is none: a block's own (a table's
12
+ // header keep-all, a short field normal, a code block's lines) wins; what the block holds that is a
13
+ // block or an atom of its own ([contenteditable="false"]: a nested list, a formula) breaks as it would
14
+ // without it, and an item of that list is judged by its own text. Never a block of plain text (a code
15
+ // block's lines, a tab's name: textFilters false), which keeps its own rule; a text part of an
16
+ // instance of a component package is judged as any text block (its component's own word-break, where
17
+ // it says one, wins), though the kit holds no run in an instance's own region.
18
+ //
19
+ // Judged as editing starts, for every text block, and again for the blocks whose text changed, as it
20
+ // changes, whatever changed it (typing, a paste, undo, a rebuild from the file, a block made or made
21
+ // editable): the page's mutations are watched (childList, characterData, contenteditable), and only
22
+ // the blocks they stand in are judged, each by its own text (a regular expression over a block's
23
+ // words: no scan of the page per keystroke). The marker is no text of the file's: a data-ge-* attribute
24
+ // on the block itself (core.mjs), set or taken off only where it changes.
25
+
26
+ const MARK = "data-ge-long-run";
27
+ const HOST = '[contenteditable="true"]';
28
+
29
+ const STYLE = `
30
+ /* A text block holding a long run breaks anywhere (long-runs.mjs), of no weight: a block's own rule wins. */
31
+ :where([data-ge-editing] [data-ge-long-run]) { word-break: break-all; }
32
+ /* What it holds of its own (a nested list, a formula) breaks as the page's text does. */
33
+ :where([data-ge-editing] [data-ge-long-run] [contenteditable="false"]) { word-break: normal; }
34
+ `;
35
+
36
+ // The text of `host` its own: not a block or an atom it holds (contenteditable="false"), a line break a space.
37
+ function ownText(host) {
38
+ const walker = host.ownerDocument.createTreeWalker(host, 5, { // NodeFilter.SHOW_ELEMENT | SHOW_TEXT
39
+ acceptNode: (node) => (node.nodeType === 1 && node !== host && node.hasAttribute("contenteditable") ? 2 : 1), // FILTER_REJECT, FILTER_ACCEPT
40
+ });
41
+ let text = "";
42
+ for (let node = walker.nextNode(); node; node = walker.nextNode()) {
43
+ if (node.nodeType === 3) text += node.data;
44
+ else if (node.localName === "br") text += " ";
45
+ }
46
+ return text;
47
+ }
48
+
49
+ /** Marks `element` as a text block holding a long run, or takes the mark off: whether it holds one. */
50
+ export function judgeLongRuns(element) {
51
+ const long = element.isConnected && element.matches(HOST) && textFilters(element) && holdsLongRun(ownText(element));
52
+ if (long !== element.hasAttribute(MARK)) element.toggleAttribute(MARK, long);
53
+ return long;
54
+ }
55
+
56
+ /** Judges every text block under `root` now, and each again as its text changes. */
57
+ export function followLongRuns(root) {
58
+ addStyle(STYLE);
59
+ for (const host of root.querySelectorAll(`${HOST}, [${MARK}]`)) judgeLongRuns(host);
60
+ new MutationObserver((records) => {
61
+ const judged = new Set();
62
+ for (const record of records) {
63
+ if (record.type === "attributes") judged.add(record.target); // made editable, or no longer
64
+ const at = record.target.nodeType === 1 ? record.target : record.target.parentElement;
65
+ const host = at?.closest(HOST);
66
+ if (host) judged.add(host);
67
+ for (const node of record.addedNodes) {
68
+ if (node.nodeType !== 1) continue;
69
+ if (node.matches(HOST)) judged.add(node);
70
+ for (const inner of node.querySelectorAll(HOST)) judged.add(inner);
71
+ }
72
+ }
73
+ judged.forEach(judgeLongRuns);
74
+ }).observe(root, { subtree: true, childList: true, characterData: true, attributes: true, attributeFilter: ["contenteditable"] });
75
+ }
@@ -1,25 +1,61 @@
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
14
- // (Notion's large outer shadow). The emoji picker (emoji-picker/support.mjs) carries notion-lite's
15
- // own --c-* variables, taken over as they are.
16
+ // (Notion's large outer shadow). The icon picker reads this palette too (emoji-picker/styles.mjs);
17
+ // emoji-picker/support.mjs keeps notion-lite's --c-* variables only for the media menu and the image's
18
+ // alignment bar.
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
+ `;
16
51
 
17
52
  export const TOKENS = `
18
53
  :root {
19
54
  --ge-tx: light-dark(#2c2c2b, #f0efed);
20
55
  --ge-tx2: light-dark(#7d7a75, #ada9a3);
21
56
  --ge-tx3: light-dark(#a19e99, #7d7a75);
22
- --ge-ico: light-dark(#383836, #e6e5e3);
57
+ /* The workbench's --icoPri (FinHarness-Demo's --ink-2). */
58
+ --ge-ico: light-dark(#5c5a55, #a9a69e);
23
59
  --ge-ico2: light-dark(#8e8b86, #ada9a3);
24
60
  /* The quietest icon gray (notion-lite's --c-icoTer): the block handle's dots, its bar and its +. */
25
61
  --ge-ico3: light-dark(#ada9a3, #7d7a75);
@@ -38,6 +74,17 @@ export const TOKENS = `
38
74
  --ge-focus: #2383e2;
39
75
  --ge-red: light-dark(#eb5757, #ff6b6b);
40
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);
41
88
  --ge-fill: light-dark(rgb(35 131 226 / 14%), rgb(35 131 226 / 28%));
42
89
  --ge-halo: rgb(35 131 226 / 14%);
43
90
  --ge-select: light-dark(rgb(35 131 226 / 28%), rgb(35 131 226 / 45%));
@@ -53,6 +100,11 @@ export const TOKENS = `
53
100
  --ge-toast-bg: light-dark(#0f0f0f, #2f2f2f);
54
101
  /* The quiet gray a heading is lit with for a moment when the outline goes to it (outline/), never a blue. */
55
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%));
56
108
  /* 批注 (annotate/): a warm mark on the words an annotation is about, its 2px underline leading (a faint fill, so it is never
57
109
  taken for the report's own yellow background), a block anchor's bar; stronger for the one shown. */
58
110
  --ge-note: light-dark(rgb(255 212 0 / 6%), rgb(255 212 0 / 6%));
@@ -61,5 +113,16 @@ export const TOKENS = `
61
113
  --ge-note-hot-line: light-dark(rgb(222 160 0 / 90%), rgb(255 204 64 / 80%));
62
114
  /* A card of 批注 in the margin under the pointer (notion-lite's --c-hovMarDisBac): a shade of the page. */
63
115
  --ge-note-shade: light-dark(#f9f9f8, #202020);
116
+ /* The Agent's changes (changes/, 设置 › 显示变更): Notion's green and red backgrounds, the conflict card's two versions (conflicts.mjs);
117
+ words added get a 批注's look (a faint fill under a 2px underline) in green, blocks a fainter fill; words
118
+ taken out stand in red struck through on the red, deleted blocks' ghost on a fainter red. */
119
+ --ge-diff-add: light-dark(rgb(0 100 45 / 9%), rgb(108 255 172 / 15.7%));
120
+ --ge-diff-add-line: light-dark(rgb(68 131 97 / 60%), rgb(111 197 150 / 55%));
121
+ --ge-diff-add-fill: light-dark(rgb(0 100 45 / 5.5%), rgb(108 255 172 / 9%));
122
+ --ge-diff-add-text: light-dark(#448361, #6fc596);
123
+ --ge-diff-del: light-dark(rgb(223 22 0 / 9.4%), rgb(255 104 92 / 24%));
124
+ --ge-diff-del-fill: light-dark(rgb(223 22 0 / 4.5%), rgb(255 104 92 / 10%));
125
+ --ge-diff-del-text: light-dark(#cf5148, #ff8f85);
64
126
  }
127
+ ${BUTTONS}
65
128
  `;