@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.
- package/THIRD-PARTY-NOTICES.md +2 -2
- package/browser/editor/components/align.mjs +58 -0
- package/browser/editor/components/code/index.mjs +1 -1
- package/browser/editor/components/columns/page.mjs +4 -4
- package/browser/editor/components/embed/index.mjs +2 -2
- package/browser/editor/components/embed/page.mjs +1 -1
- package/browser/editor/components/file/page.mjs +4 -4
- package/browser/editor/components/flowchart/add.mjs +7 -6
- package/browser/editor/components/flowchart/page.mjs +1 -1
- package/browser/editor/components/heading/index.mjs +7 -6
- package/browser/editor/components/icons.mjs +11 -0
- package/browser/editor/components/image/crop.mjs +6 -9
- package/browser/editor/components/image/index.mjs +2 -0
- package/browser/editor/components/image/page.mjs +172 -90
- package/browser/editor/components/installed/index.mjs +15 -4
- package/browser/editor/components/installed/page.mjs +103 -25
- package/browser/editor/components/installed/served.mjs +6 -5
- package/browser/editor/components/instances.mjs +18 -0
- package/browser/editor/components/list/page.mjs +3 -6
- package/browser/editor/components/media/icons.mjs +13 -8
- package/browser/editor/components/media/page.mjs +5 -3
- package/browser/editor/components/media/toolbar.mjs +12 -3
- package/browser/editor/components/paragraph/index.mjs +4 -3
- package/browser/editor/components/registry.mjs +30 -9
- package/browser/editor/components/table/index.mjs +61 -2
- package/browser/editor/components/table/page.mjs +1 -1
- package/browser/editor/page/after/index.mjs +288 -0
- package/browser/editor/page/align.mjs +91 -0
- package/browser/editor/page/annotate/card.mjs +3 -6
- package/browser/editor/page/autosave.mjs +310 -37
- package/browser/editor/page/beside.mjs +5 -6
- package/browser/editor/page/block-menu/index.mjs +6 -3
- package/browser/editor/page/blocks.mjs +3 -1
- package/browser/editor/page/board/client.mjs +57 -0
- package/browser/editor/page/board/hint.mjs +182 -0
- package/browser/editor/page/board/history.mjs +119 -0
- package/browser/editor/page/board/index.mjs +1059 -0
- package/browser/editor/page/board/motion.mjs +177 -0
- package/browser/editor/page/board/settings.mjs +210 -0
- package/browser/editor/page/caret.mjs +1 -1
- package/browser/editor/page/changes/bar.mjs +6 -14
- package/browser/editor/page/changes/index.mjs +2 -2
- package/browser/editor/page/clipboard/import/html.mjs +29 -6
- package/browser/editor/page/clipboard/import/inline.mjs +32 -0
- package/browser/editor/page/clipboard/import/markdown.mjs +58 -13
- package/browser/editor/page/clipboard/import/read.mjs +6 -1
- package/browser/editor/page/clipboard/import/to-blocks.mjs +44 -12
- package/browser/editor/page/clipboard/import/yuque.mjs +622 -0
- package/browser/editor/page/clipboard/index.mjs +133 -15
- package/browser/editor/page/clipboard/own/blocks.mjs +13 -14
- package/browser/editor/page/clipboard/own/chart-keys.mjs +41 -28
- package/browser/editor/page/clipboard/own/describe.mjs +6 -2
- package/browser/editor/page/clipboard/own/selection.mjs +1 -1
- package/browser/editor/page/columns/index.mjs +48 -46
- package/browser/editor/page/commit.mjs +80 -22
- package/browser/editor/page/conflicts.mjs +7 -7
- package/browser/editor/page/core.mjs +34 -16
- package/browser/editor/page/custom-page.mjs +110 -0
- package/browser/editor/page/editor.mjs +71 -17
- package/browser/editor/page/emoji-picker/styles.mjs +7 -12
- package/browser/editor/page/emoji-picker/upload.mjs +2 -2
- package/browser/editor/page/handle/index.mjs +5 -8
- package/browser/editor/page/history.mjs +41 -6
- package/browser/editor/page/insert/index.mjs +20 -22
- package/browser/editor/page/links/index.mjs +5 -3
- package/browser/editor/page/links/pages.mjs +27 -9
- package/browser/editor/page/look.mjs +54 -3
- package/browser/editor/page/margin.mjs +18 -3
- package/browser/editor/page/media-menu/index.mjs +6 -7
- package/browser/editor/page/menu.mjs +33 -14
- package/browser/editor/page/notices.mjs +2 -2
- package/browser/editor/page/page-objects.mjs +9 -2
- package/browser/editor/page/panel.mjs +4 -9
- package/browser/editor/page/present-links.mjs +15 -5
- package/browser/editor/page/present-shell.mjs +63 -0
- package/browser/editor/page/resize/index.mjs +42 -29
- package/browser/editor/page/selection/index.mjs +10 -2
- package/browser/editor/page/served.mjs +14 -0
- package/browser/editor/page/session.mjs +48 -4
- package/browser/editor/page/slash-menu/index.mjs +3 -3
- package/browser/editor/page/table/binding.mjs +87 -0
- package/browser/editor/page/table/cells.mjs +102 -46
- package/browser/editor/page/table/index.mjs +24 -9
- package/browser/editor/page/table/pictures.mjs +299 -0
- package/browser/editor/page/table/views.mjs +103 -0
- package/browser/editor/page/table/widths.mjs +82 -10
- package/browser/editor/page/text-select/index.mjs +26 -12
- package/browser/editor/page/todo-writes.mjs +75 -0
- package/browser/editor/page/typing/index.mjs +97 -15
- package/browser/editor/page/typing/leave.mjs +19 -5
- package/browser/editor/page/ui.mjs +13 -0
- package/browser/shared/block-packs.mjs +419 -0
- package/browser/shared/board-places.mjs +224 -0
- package/browser/shared/card-size.mjs +59 -0
- package/browser/shared/colors.mjs +3 -2
- package/browser/shared/component-catalog.mjs +330 -46
- package/browser/shared/component-source.mjs +39 -0
- package/browser/shared/components/heading.mjs +2 -1
- package/browser/shared/components/index.mjs +12 -3
- package/browser/shared/components/installed.mjs +35 -3
- package/browser/shared/components/page.mjs +20 -8
- package/browser/shared/components/paragraph.mjs +8 -1
- package/browser/shared/components/state.mjs +5 -1
- package/browser/shared/components/table.mjs +1 -0
- package/browser/shared/document-look.mjs +10 -5
- package/browser/shared/drafts.mjs +432 -0
- package/browser/shared/emoji/line-icons.mjs +37 -0
- package/browser/shared/extension-sidebar.mjs +126 -0
- package/browser/shared/extensions.mjs +79 -0
- package/browser/shared/file-table.mjs +101 -0
- package/browser/shared/http.mjs +9 -0
- package/browser/shared/i18n/en.mjs +330 -27
- package/browser/shared/json-layout.mjs +47 -0
- package/browser/shared/net-cache.mjs +133 -0
- package/browser/shared/net-keys.mjs +32 -0
- package/browser/shared/net-policy.mjs +177 -0
- package/browser/shared/outline-shape.mjs +128 -0
- package/browser/shared/outline.mjs +359 -67
- package/browser/shared/pack-manifest.mjs +88 -0
- package/browser/shared/page-address.mjs +6 -3
- package/browser/shared/page-cards.mjs +308 -0
- package/browser/shared/page-links.mjs +69 -6
- package/browser/shared/pages.mjs +500 -0
- package/browser/shared/paths.mjs +6 -0
- package/browser/shared/pinyin.mjs +92 -0
- package/browser/shared/present-step.mjs +17 -0
- package/browser/shared/preview-server.mjs +3 -7
- package/browser/shared/session.mjs +8 -1
- package/browser/shared/shipped-blocks.mjs +299 -0
- package/browser/shared/sidebar-head.mjs +70 -0
- package/browser/shared/table-chart.mjs +33 -1
- package/browser/shared/todos.mjs +83 -0
- package/browser/shared/user-directory.mjs +24 -0
- package/browser/shared/versions.mjs +14 -0
- package/browser/shared/web-links.mjs +139 -0
- package/browser/shared/workspace-columns.mjs +120 -0
- package/browser/shared/workspace-name.mjs +154 -0
- package/browser/shared/workspace-query.mjs +125 -0
- package/browser/shared/workspace-registry.mjs +272 -0
- package/browser/shared/workspace.mjs +171 -20
- package/dist/chunk-2OHANJ6Q.mjs +2 -0
- package/dist/chunk-3MBRL2PM.mjs +16 -0
- package/dist/chunk-4OKWZY5E.mjs +2 -0
- package/dist/chunk-4OZWXZE5.mjs +5 -0
- package/dist/chunk-5K44HLTZ.mjs +2 -0
- package/dist/{chunk-5ZKJ3H4P.mjs → chunk-5XA2ZBAE.mjs} +3 -3
- package/dist/{chunk-4FS7Z7WR.mjs → chunk-67N2QJYT.mjs} +1 -1
- package/dist/chunk-6KBYRA2C.mjs +2 -0
- package/dist/chunk-6N3PX4XX.mjs +8 -0
- package/dist/{chunk-V5JTW2LH.mjs → chunk-6QBHU4DF.mjs} +1 -1
- package/dist/chunk-7JDX4E65.mjs +13 -0
- package/dist/chunk-7M2BQQGZ.mjs +2 -0
- package/dist/chunk-7OG26PGF.mjs +2 -0
- package/dist/chunk-AHN3NFKJ.mjs +3 -0
- package/dist/chunk-ALZ6ZENZ.mjs +3 -0
- package/dist/chunk-AR5D57ZD.mjs +170 -0
- package/dist/{chunk-W3BGBJQW.mjs → chunk-BFJGHSQN.mjs} +1 -1
- package/dist/{chunk-LS4F7JUM.mjs → chunk-BZ5RAF7L.mjs} +1 -1
- package/dist/chunk-CMA72MAG.mjs +2 -0
- package/dist/{chunk-LCTHTZIL.mjs → chunk-DAZL73VK.mjs} +91 -91
- package/dist/{chunk-Y6RLRPG3.mjs → chunk-DJISHPUL.mjs} +1 -1
- package/dist/chunk-DR73Y2UJ.mjs +3 -0
- package/dist/{chunk-FDLXYYG4.mjs → chunk-EAIFITAV.mjs} +1 -1
- package/dist/{chunk-TMYZB6AV.mjs → chunk-EKNHM3P4.mjs} +1 -1
- package/dist/chunk-EP25HDAJ.mjs +2 -0
- package/dist/{chunk-GB5SOYQJ.mjs → chunk-ERLAIBOA.mjs} +2 -2
- package/dist/chunk-EURLTOTZ.mjs +4 -0
- package/dist/chunk-F4ZA6JRZ.mjs +3 -0
- package/dist/chunk-F6HVDZR4.mjs +2 -0
- package/dist/chunk-FDMAXMQA.mjs +2 -0
- package/dist/chunk-FETSREUN.mjs +5 -0
- package/dist/chunk-GHOYKMQ3.mjs +4 -0
- package/dist/{chunk-2B5E4CDJ.mjs → chunk-GPIWQ4X4.mjs} +1 -1
- package/dist/chunk-HDWTZ763.mjs +12 -0
- package/dist/chunk-HPOI4ZX7.mjs +6 -0
- package/dist/{chunk-BGGDRNYQ.mjs → chunk-HXG7EOPJ.mjs} +1 -1
- package/dist/chunk-IA4PSIMD.mjs +2 -0
- package/dist/{chunk-E7LWZRXY.mjs → chunk-ITOH5EGO.mjs} +1 -1
- package/dist/chunk-IV64FFI4.mjs +2 -0
- package/dist/chunk-J43Z6LSS.mjs +2 -0
- package/dist/chunk-J5PUIV3Y.mjs +4 -0
- package/dist/chunk-JA7G53PC.mjs +2 -0
- package/dist/chunk-JEUK3ZO7.mjs +2 -0
- package/dist/chunk-JLTZF4LA.mjs +2 -0
- package/dist/chunk-JZT7I2OJ.mjs +2 -0
- package/dist/chunk-K5XATEOO.mjs +2 -0
- package/dist/chunk-L2SUIS5S.mjs +2 -0
- package/dist/chunk-L7UP52JO.mjs +2 -0
- package/dist/chunk-LM4XFQHZ.mjs +2 -0
- package/dist/chunk-MN7BZL4R.mjs +2 -0
- package/dist/chunk-MTYYHM2G.mjs +15 -0
- package/dist/chunk-MXUBKDRO.mjs +15 -0
- package/dist/chunk-NAMN3RAF.mjs +2 -0
- package/dist/{chunk-SYGN7GLU.mjs → chunk-OEXWRJME.mjs} +1 -1
- package/dist/chunk-OFHXGWOX.mjs +2 -0
- package/dist/chunk-ORID3AE7.mjs +166 -0
- package/dist/chunk-PAREWQGB.mjs +4 -0
- package/dist/chunk-PGDE24N5.mjs +2 -0
- package/dist/chunk-POTA2FV4.mjs +2 -0
- package/dist/chunk-PUOQ65NC.mjs +2 -0
- package/dist/chunk-Q4UEPUWF.mjs +2 -0
- package/dist/chunk-QE5RG76S.mjs +549 -0
- package/dist/chunk-R2ZDLJYT.mjs +10 -0
- package/dist/{chunk-7DTINW6U.mjs → chunk-SQ6Y2ZMA.mjs} +2 -2
- package/dist/chunk-SWUTTZCN.mjs +2 -0
- package/dist/chunk-TANZRINB.mjs +2 -0
- package/dist/chunk-TR7TWGHB.mjs +2 -0
- package/dist/chunk-U5XL7D6A.mjs +3 -0
- package/dist/{chunk-XNROSH2T.mjs → chunk-U7NZI6N4.mjs} +2 -2
- package/dist/chunk-UGWMMEJ5.mjs +15 -0
- package/dist/chunk-UJQJKNGK.mjs +2 -0
- package/dist/chunk-UYVCQK3H.mjs +22 -0
- package/dist/chunk-VFX2KNHP.mjs +4 -0
- package/dist/chunk-VS7JIGJW.mjs +24 -0
- package/dist/chunk-W7665ZEC.mjs +6 -0
- package/dist/chunk-WQDQWCX5.mjs +2 -0
- package/dist/chunk-YI43RG4P.mjs +2 -0
- package/dist/chunk-YLPSMDIS.mjs +5 -0
- package/dist/chunk-YNAWBAYN.mjs +3 -0
- package/dist/chunk-YROX2O22.mjs +2 -0
- package/dist/chunk-ZDLPUOAG.mjs +6 -0
- package/dist/{chunk-IVDLMMBD.mjs → chunk-ZHEHPMBK.mjs} +1 -1
- package/dist/chunk-ZQS6H473.mjs +16 -0
- package/dist/chunk-ZTHICSSF.mjs +2 -0
- package/dist/chunk-ZWWC4KLF.mjs +20 -0
- package/dist/cli.mjs +1 -1
- package/dist/server.mjs +1 -1
- package/dist/{chunk-U6KNPJPR.mjs → update-fetch.mjs} +1 -1
- package/dist/worker.mjs +1 -1
- package/kit/board.css +95 -0
- package/kit/board.js +250 -0
- package/kit/charts.js +5 -71
- package/kit/code.js +17 -17
- package/kit/report.css +335 -18
- package/kit/runtime.js +1638 -125
- package/kit/state.js +10 -1
- package/kit/tables.js +130 -43
- package/kit/ui.js +79 -35
- package/package.json +2 -1
- package/packs/gallery/card/component.json +14 -0
- package/packs/gallery/card/example.html +10 -0
- package/packs/gallery/card/preview.svg +1 -0
- package/packs/gallery/card/style.css +6 -0
- package/packs/gallery/card/template.html +6 -0
- package/packs/gallery/card/writing.md +14 -0
- package/packs/gallery/chart-card/component.json +15 -0
- package/packs/gallery/chart-card/example.html +14 -0
- package/packs/gallery/chart-card/kit.js +130 -0
- package/packs/gallery/chart-card/preview.svg +1 -0
- package/packs/gallery/chart-card/style.css +42 -0
- package/packs/gallery/chart-card/template.html +13 -0
- package/packs/gallery/chart-card/writing.md +20 -0
- package/packs/gallery/chart-view/component.json +20 -0
- package/packs/gallery/chart-view/example.html +13 -0
- package/packs/gallery/chart-view/kit.js +355 -0
- package/packs/gallery/chart-view/preview.svg +1 -0
- package/packs/gallery/chart-view/style.css +94 -0
- package/packs/gallery/chart-view/template.html +3 -0
- package/packs/gallery/chart-view/writing.md +22 -0
- package/packs/gallery/countdown/component.json +18 -0
- package/packs/gallery/countdown/example.html +3 -0
- package/packs/gallery/countdown/kit.js +216 -0
- package/packs/gallery/countdown/preview.svg +1 -0
- package/packs/gallery/countdown/style.css +118 -0
- package/packs/gallery/countdown/template.html +3 -0
- package/packs/gallery/countdown/writing.md +22 -0
- package/packs/gallery/habit/component.json +14 -0
- package/packs/gallery/habit/example.html +3 -0
- package/packs/gallery/habit/kit.js +334 -0
- package/packs/gallery/habit/preview.svg +1 -0
- package/packs/gallery/habit/style.css +174 -0
- package/packs/gallery/habit/template.html +3 -0
- package/packs/gallery/habit/writing.md +21 -0
- package/packs/gallery/heatmap/component.json +18 -0
- package/packs/gallery/heatmap/example.html +3 -0
- package/packs/gallery/heatmap/kit.js +513 -0
- package/packs/gallery/heatmap/preview.svg +1 -0
- package/packs/gallery/heatmap/style.css +189 -0
- package/packs/gallery/heatmap/template.html +3 -0
- package/packs/gallery/heatmap/writing.md +21 -0
- package/packs/gallery/kanban/component.json +18 -0
- package/packs/gallery/kanban/example.html +12 -0
- package/packs/gallery/kanban/kit.js +540 -0
- package/packs/gallery/kanban/preview.svg +1 -0
- package/packs/gallery/kanban/style.css +212 -0
- package/packs/gallery/kanban/template.html +3 -0
- package/packs/gallery/kanban/writing.md +20 -0
- package/packs/gallery/metric/component.json +22 -0
- package/packs/gallery/metric/example.html +15 -0
- package/packs/gallery/metric/kit.js +248 -0
- package/packs/gallery/metric/preview.svg +1 -0
- package/packs/gallery/metric/style.css +92 -0
- package/packs/gallery/metric/template.html +3 -0
- package/packs/gallery/metric/writing.md +23 -0
- package/packs/gallery/note/component.json +14 -0
- package/packs/gallery/note/example.html +3 -0
- package/packs/gallery/note/kit.js +129 -0
- package/packs/gallery/note/preview.svg +1 -0
- package/packs/gallery/note/style.css +97 -0
- package/packs/gallery/note/template.html +3 -0
- package/packs/gallery/note/writing.md +18 -0
- package/packs/gallery/pack.json +8 -0
- package/packs/gallery/recent/component.json +13 -0
- package/packs/gallery/recent/example.html +1 -0
- package/packs/gallery/recent/kit.js +293 -0
- package/packs/gallery/recent/preview.svg +1 -0
- package/packs/gallery/recent/style.css +85 -0
- package/packs/gallery/recent/template.html +1 -0
- package/packs/gallery/recent/writing.md +15 -0
- package/packs/gallery/static/component.json +13 -0
- package/packs/gallery/static/example.html +11 -0
- package/packs/gallery/static/preview.svg +1 -0
- package/packs/gallery/static/style.css +171 -0
- package/packs/gallery/static/template.html +1 -0
- package/packs/gallery/static/writing.md +18 -0
- package/packs/gallery/stats/component.json +13 -0
- package/packs/gallery/stats/example.html +1 -0
- package/packs/gallery/stats/kit.js +347 -0
- package/packs/gallery/stats/preview.svg +1 -0
- package/packs/gallery/stats/style.css +73 -0
- package/packs/gallery/stats/template.html +1 -0
- package/packs/gallery/stats/writing.md +11 -0
- package/packs/gallery/today/component.json +12 -0
- package/packs/gallery/today/example.html +1 -0
- package/packs/gallery/today/kit.js +220 -0
- package/packs/gallery/today/preview.svg +1 -0
- package/packs/gallery/today/style.css +149 -0
- package/packs/gallery/today/template.html +1 -0
- package/packs/gallery/today/writing.md +14 -0
- package/packs/gallery/todos/component.json +19 -0
- package/packs/gallery/todos/example.html +3 -0
- package/packs/gallery/todos/kit.js +489 -0
- package/packs/gallery/todos/preview.svg +1 -0
- package/packs/gallery/todos/style.css +214 -0
- package/packs/gallery/todos/template.html +3 -0
- package/packs/gallery/todos/writing.md +30 -0
- package/packs/gallery/weather/component.json +19 -0
- package/packs/gallery/weather/example.html +3 -0
- package/packs/gallery/weather/kit.js +387 -0
- package/packs/gallery/weather/preview.svg +1 -0
- package/packs/gallery/weather/style.css +140 -0
- package/packs/gallery/weather/template.html +3 -0
- package/packs/gallery/weather/writing.md +26 -0
- package/packs/gallery-soft/countdown/component.json +18 -0
- package/packs/gallery-soft/countdown/example.html +3 -0
- package/packs/gallery-soft/countdown/kit.js +206 -0
- package/packs/gallery-soft/countdown/preview.svg +1 -0
- package/packs/gallery-soft/countdown/style.css +211 -0
- package/packs/gallery-soft/countdown/template.html +3 -0
- package/packs/gallery-soft/countdown/writing.md +24 -0
- package/packs/gallery-soft/habit/component.json +14 -0
- package/packs/gallery-soft/habit/example.html +3 -0
- package/packs/gallery-soft/habit/kit.js +366 -0
- package/packs/gallery-soft/habit/preview.svg +1 -0
- package/packs/gallery-soft/habit/style.css +251 -0
- package/packs/gallery-soft/habit/template.html +3 -0
- package/packs/gallery-soft/habit/writing.md +23 -0
- package/packs/gallery-soft/heatmap/component.json +18 -0
- package/packs/gallery-soft/heatmap/example.html +3 -0
- package/packs/gallery-soft/heatmap/kit.js +498 -0
- package/packs/gallery-soft/heatmap/preview.svg +1 -0
- package/packs/gallery-soft/heatmap/style.css +181 -0
- package/packs/gallery-soft/heatmap/template.html +3 -0
- package/packs/gallery-soft/heatmap/writing.md +23 -0
- package/packs/gallery-soft/note/component.json +14 -0
- package/packs/gallery-soft/note/example.html +3 -0
- package/packs/gallery-soft/note/kit.js +162 -0
- package/packs/gallery-soft/note/preview.svg +1 -0
- package/packs/gallery-soft/note/style.css +148 -0
- package/packs/gallery-soft/note/template.html +3 -0
- package/packs/gallery-soft/note/writing.md +20 -0
- package/packs/gallery-soft/pack.json +8 -0
- package/packs/gallery-soft/recent/component.json +13 -0
- package/packs/gallery-soft/recent/example.html +1 -0
- package/packs/gallery-soft/recent/kit.js +335 -0
- package/packs/gallery-soft/recent/preview.svg +1 -0
- package/packs/gallery-soft/recent/style.css +160 -0
- package/packs/gallery-soft/recent/template.html +1 -0
- package/packs/gallery-soft/recent/writing.md +17 -0
- package/packs/gallery-soft/static/component.json +13 -0
- package/packs/gallery-soft/static/example.html +12 -0
- package/packs/gallery-soft/static/preview.svg +1 -0
- package/packs/gallery-soft/static/style.css +186 -0
- package/packs/gallery-soft/static/template.html +1 -0
- package/packs/gallery-soft/static/writing.md +20 -0
- package/packs/gallery-soft/stats/component.json +13 -0
- package/packs/gallery-soft/stats/example.html +1 -0
- package/packs/gallery-soft/stats/kit.js +341 -0
- package/packs/gallery-soft/stats/preview.svg +1 -0
- package/packs/gallery-soft/stats/style.css +119 -0
- package/packs/gallery-soft/stats/template.html +1 -0
- package/packs/gallery-soft/stats/writing.md +13 -0
- package/packs/gallery-soft/today/component.json +12 -0
- package/packs/gallery-soft/today/example.html +1 -0
- package/packs/gallery-soft/today/kit.js +222 -0
- package/packs/gallery-soft/today/preview.svg +1 -0
- package/packs/gallery-soft/today/style.css +178 -0
- package/packs/gallery-soft/today/template.html +1 -0
- package/packs/gallery-soft/today/writing.md +16 -0
- package/packs/gallery-soft/todos/component.json +19 -0
- package/packs/gallery-soft/todos/example.html +3 -0
- package/packs/gallery-soft/todos/kit.js +527 -0
- package/packs/gallery-soft/todos/preview.svg +1 -0
- package/packs/gallery-soft/todos/style.css +212 -0
- package/packs/gallery-soft/todos/template.html +3 -0
- package/packs/gallery-soft/todos/writing.md +32 -0
- package/packs/gallery-soft/weather/component.json +19 -0
- package/packs/gallery-soft/weather/example.html +3 -0
- package/packs/gallery-soft/weather/kit.js +411 -0
- package/packs/gallery-soft/weather/preview.svg +1 -0
- package/packs/gallery-soft/weather/style.css +185 -0
- package/packs/gallery-soft/weather/template.html +3 -0
- package/packs/gallery-soft/weather/writing.md +28 -0
- package/release.json +12 -10
- package/sdk/doc-kit.d.ts +396 -5
- package/sdk/doc-state.d.ts +2 -0
- package/skill/SKILL.md +56 -23
- package/skill/references/block-script.md +140 -0
- package/skill/references/building-blocks.md +257 -0
- package/skill/references/extensions.md +59 -0
- package/skill/references/pages-and-data.md +225 -0
- package/skill/references/writing-html.md +8 -4
- package/skill/sdk/doc-kit.d.ts +396 -5
- package/skill/sdk/doc-state.d.ts +2 -0
- package/web/assets/index-BM_K-Auu.css +1 -0
- package/web/assets/index-DRslOBiv.js +15 -0
- package/web/index.html +2 -2
- package/dist/chunk-3HIRPVLU.mjs +0 -2
- package/dist/chunk-5MHMDLZD.mjs +0 -4
- package/dist/chunk-64K7IPLO.mjs +0 -255
- package/dist/chunk-6QXGZM36.mjs +0 -8
- package/dist/chunk-6RGJOMJP.mjs +0 -16
- package/dist/chunk-AJ73XJF3.mjs +0 -2
- package/dist/chunk-AUZGSZJH.mjs +0 -13
- package/dist/chunk-BFE45AKL.mjs +0 -2
- package/dist/chunk-BXO2ZY5P.mjs +0 -2
- package/dist/chunk-CEH4MRCC.mjs +0 -2
- package/dist/chunk-CY2FNNAB.mjs +0 -16
- package/dist/chunk-DFUDV4LX.mjs +0 -2
- package/dist/chunk-DKXG4XDG.mjs +0 -2
- package/dist/chunk-EZQ34M3F.mjs +0 -124
- package/dist/chunk-EZY3WC6Z.mjs +0 -15
- package/dist/chunk-FUKQNOQS.mjs +0 -9
- package/dist/chunk-JPOSLGOC.mjs +0 -6
- package/dist/chunk-JVHHHGEA.mjs +0 -3
- package/dist/chunk-L3QKH4OK.mjs +0 -26
- package/dist/chunk-LAE5NQ4B.mjs +0 -2
- package/dist/chunk-LEF6DRCK.mjs +0 -59
- package/dist/chunk-NO5NJCHO.mjs +0 -2
- package/dist/chunk-NQPVAU63.mjs +0 -2
- package/dist/chunk-NSKUTQ5J.mjs +0 -5
- package/dist/chunk-O35FIXRB.mjs +0 -2
- package/dist/chunk-P2CAZPDP.mjs +0 -3
- package/dist/chunk-PL6GHLGD.mjs +0 -15
- package/dist/chunk-QJIR2BLP.mjs +0 -6
- package/dist/chunk-QUPLVPB2.mjs +0 -7
- package/dist/chunk-R7BNENLY.mjs +0 -4
- package/dist/chunk-S6O4UHLC.mjs +0 -2
- package/dist/chunk-SGJWQKEI.mjs +0 -2
- package/dist/chunk-TX6JH7TR.mjs +0 -2
- package/dist/chunk-TYK6VNAB.mjs +0 -10
- package/dist/chunk-UALRNVSE.mjs +0 -4
- package/dist/chunk-V3HXVQEM.mjs +0 -2
- package/dist/chunk-V5VXUJKG.mjs +0 -2
- package/dist/chunk-VBXMADMP.mjs +0 -2
- package/dist/chunk-VNV55RUA.mjs +0 -2
- package/dist/chunk-VPD2PS35.mjs +0 -2
- package/dist/chunk-W4VKN3GF.mjs +0 -7
- package/dist/chunk-W5BXXPDJ.mjs +0 -3
- package/dist/chunk-XUNHRCOG.mjs +0 -6
- package/skill/references/building-components.md +0 -367
- package/web/assets/index-Bh74DfsV.css +0 -1
- package/web/assets/index-UW0RyFFt.js +0 -13
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
import { startBoard } from "./board/index.mjs";
|
|
2
|
+
import { relayTo } from "./notices.mjs";
|
|
3
|
+
import { connectWorkbench } from "./session.mjs";
|
|
4
|
+
|
|
5
|
+
// A custom page inside a workbench (src/server/routes.mjs serves it at /pages/<slug> with this module;
|
|
6
|
+
// docs/workbench.md "Custom pages"): no document editor, the session, by which the workbench shows it
|
|
7
|
+
// as it shows a document's page, and its boards' editing (./board/: the cards moved, resized, added,
|
|
8
|
+
// taken out, their settings and their blocks' writes, through the page service, by the page map the
|
|
9
|
+
// server writes in its head), which shows the page again only once nothing of it waits. Its session's
|
|
10
|
+
// slug is "@<slug>", the page's address in the workbench (#@<slug>), which no document's slug can be.
|
|
11
|
+
// It answers the session's own commands (theme, keys, scroll-top: src/editor/page/session.mjs),
|
|
12
|
+
// prepare-close (once the board's ops sent are answered: each is written at once, nothing else waits),
|
|
13
|
+
// add-card where it has a board (the top bar's 添加自定义块: the library of the page's first board, under the
|
|
14
|
+
// button's place that the workbench sends; a page with none, a blank one or one an Agent wrote with no
|
|
15
|
+
// board, offers no 添加自定义块) and, on a page with the default cards (its page map's `defaults`: its
|
|
16
|
+
// page.json's defaultCards, the default home page's), restore-defaults (恢复默认卡片, its menu's: the board's,
|
|
17
|
+
// one step of its undo; its answer { ok, added, skipped } the workbench says) and undo-restore ({ cards }:
|
|
18
|
+
// that step undone while it is the board's last, the workbench's 撤销),
|
|
19
|
+
// and sends ready, reload (its live script heard that page.html or page.json changed, or a block it
|
|
20
|
+
// holds: the workbench loads it again in a hidden frame and swaps it in once drawn), open (a link to a
|
|
21
|
+
// document or another page, or a block's context.workspace.open: doc-open-request) and key. Opened on its own (not in a frame of the workbench), it has no
|
|
22
|
+
// session: its board edits all the same, and the live script reloads it.
|
|
23
|
+
|
|
24
|
+
const slug = decodeURIComponent(location.pathname.split("/")[2] ?? "");
|
|
25
|
+
const IDLE = { editing: false, pending: false, saving: false, offline: false, conflicts: 0, unfit: 0, changed: false };
|
|
26
|
+
// Nothing stands over a custom page as a modal.
|
|
27
|
+
const NO_MODALS = { open: () => [], listen() {}, closeTop: () => false };
|
|
28
|
+
|
|
29
|
+
// The page map (routes.mjs: its slug, its token, the version it was served at, its blocks): the boards edit.
|
|
30
|
+
let map = null;
|
|
31
|
+
try {
|
|
32
|
+
map = JSON.parse(document.querySelector("script[data-ge-page]")?.textContent ?? "null");
|
|
33
|
+
} catch {}
|
|
34
|
+
const hasBoard = Boolean(document.querySelector(".gallery-board"));
|
|
35
|
+
|
|
36
|
+
let board = null;
|
|
37
|
+
const session = connectWorkbench({
|
|
38
|
+
slug: `@${slug}`,
|
|
39
|
+
snapshot: () => ({ title: document.title, icon: null, state: IDLE }),
|
|
40
|
+
commands: {
|
|
41
|
+
"prepare-close": async () => {
|
|
42
|
+
await board?.idle();
|
|
43
|
+
return { ok: true };
|
|
44
|
+
},
|
|
45
|
+
// 添加自定义块 of the workbench's top bar: the library opens in the page, at `anchor` (the button's place in
|
|
46
|
+
// this frame's coordinates; none: in the middle of the window), the first board's.
|
|
47
|
+
...(hasBoard ? { "add-card": async ({ anchor } = {}) => (board ? board.addCard({ anchor }) : { ok: false, reason: "board" }) } : {}),
|
|
48
|
+
...(map?.defaults ? {
|
|
49
|
+
"restore-defaults": async () => (board ? board.restoreDefaults() : { ok: false, reason: "board" }),
|
|
50
|
+
"undo-restore": async ({ cards }) => (board ? board.undoRestore(cards) : { ok: false, reason: "board" }),
|
|
51
|
+
} : {}),
|
|
52
|
+
},
|
|
53
|
+
modals: NO_MODALS,
|
|
54
|
+
});
|
|
55
|
+
|
|
56
|
+
board = map?.token ? startBoard({ map, reload: () => (session ? session.reload() : location.reload()), hosted: Boolean(session) }) : null;
|
|
57
|
+
// The live script (routes.mjs) shows the page again through the workbench, which swaps a new page in
|
|
58
|
+
// once drawn: no reload seen; once the board's own writes, a drag, a form or a field typed in are done.
|
|
59
|
+
if (board) window.__galleryEditReload = () => board.swap();
|
|
60
|
+
|
|
61
|
+
if (session) {
|
|
62
|
+
// Its notices (a card someone else changed) are the workbench's toasts, as a document's page's are.
|
|
63
|
+
relayTo(session.notice, session.noticeRoom);
|
|
64
|
+
if (!board) window.__galleryEditReload = () => session.reload();
|
|
65
|
+
|
|
66
|
+
// A block's context.workspace.open (the kit's runtime/workspace.js: 我的待办's item, 最近编辑's
|
|
67
|
+
// document): a document, at its block where it names one, or a custom page, opened in the workbench.
|
|
68
|
+
addEventListener("doc-open-request", (event) => {
|
|
69
|
+
const { slug = null, block = null, page = null } = event.detail ?? {};
|
|
70
|
+
event.preventDefault();
|
|
71
|
+
session.open(page ? { hash: `@${page}` } : { target: slug, block });
|
|
72
|
+
});
|
|
73
|
+
|
|
74
|
+
// A link to a document or a page of the workbench goes there in the workbench, never in this frame:
|
|
75
|
+
// a workbench's address (#<link>, #@<slug>, /#…), a document's page (/generated/<slug>.html) or its
|
|
76
|
+
// file (../<slug>/doc.html), a custom page's served path (/pages/<slug>, the page alone that gallery
|
|
77
|
+
// page open gives, or written relative to this one: "reading" from /pages/home). Another site's
|
|
78
|
+
// opens in a tab of its own.
|
|
79
|
+
addEventListener("click", (event) => {
|
|
80
|
+
if (event.defaultPrevented || event.button !== 0 || event.metaKey || event.ctrlKey || event.shiftKey || event.altKey) return;
|
|
81
|
+
const link = event.target instanceof Element ? event.target.closest("a[href]") : null;
|
|
82
|
+
if (!link || link.hasAttribute("download")) return;
|
|
83
|
+
const raw = link.getAttribute("href") ?? "";
|
|
84
|
+
// A place in this page (an element of that id) is the browser's to go to.
|
|
85
|
+
if (raw.startsWith("#") && raw.length > 1 && document.getElementById(decodeURIComponent(raw.slice(1)))) return;
|
|
86
|
+
let url;
|
|
87
|
+
try {
|
|
88
|
+
url = new URL(raw, location.href);
|
|
89
|
+
} catch {
|
|
90
|
+
return;
|
|
91
|
+
}
|
|
92
|
+
if (url.origin !== location.origin) {
|
|
93
|
+
event.preventDefault();
|
|
94
|
+
window.open(url.href, "_blank", "noopener");
|
|
95
|
+
return;
|
|
96
|
+
}
|
|
97
|
+
const custom = /^\/pages\/([a-z0-9-]+)\/?$/.exec(url.pathname)?.[1];
|
|
98
|
+
const page = /^\/generated\/([a-z0-9-]+)\.html$/.exec(url.pathname)?.[1] ?? /^\/([a-z0-9-]+)\/(?:doc|report)\.html$/.exec(url.pathname)?.[1];
|
|
99
|
+
if (custom) {
|
|
100
|
+
event.preventDefault();
|
|
101
|
+
session.open({ hash: `@${custom}` });
|
|
102
|
+
} else if (page) {
|
|
103
|
+
event.preventDefault();
|
|
104
|
+
session.open({ target: page, block: url.hash.slice(1) || null });
|
|
105
|
+
} else if ((url.pathname === "/" || raw.startsWith("#")) && url.hash.length > 1) {
|
|
106
|
+
event.preventDefault();
|
|
107
|
+
session.open({ hash: decodeURIComponent(url.hash.slice(1)) });
|
|
108
|
+
}
|
|
109
|
+
});
|
|
110
|
+
}
|
|
@@ -15,14 +15,17 @@ import { createCommits, kindOf } from "./commit.mjs";
|
|
|
15
15
|
import { createConflicts, packageChanged, unfit } from "./conflicts.mjs";
|
|
16
16
|
import { checkLeft, createAutosave, keepWith, lostKey, pendingKey, readLost, recover, reloadView, setReloader, takeView, viewNow } from "./autosave.mjs";
|
|
17
17
|
import { SOLO, connectWorkbench } from "./session.mjs";
|
|
18
|
+
import { OUTLINE_OPEN_KEY, onOutlineOpen, outlineOpen, setOutlineOpen } from "../../shared/preferences.mjs";
|
|
18
19
|
import { lookOfElement } from "../../shared/document-look.mjs";
|
|
19
20
|
import { belowTargets, convertBlock, convertGroup, groupParents, groupTargets, noTextToCarry, targetsOf, touchedBy, turnInto, turnParents, turnUnit, typeOf } from "./convert.mjs";
|
|
20
21
|
import { joinCode, rangeAt, rangeOffsets } from "./marks.mjs";
|
|
21
|
-
import { addStyle,
|
|
22
|
+
import { addStyle, copyAddress, element, layer, textButton } from "./ui.mjs";
|
|
22
23
|
import { createClipboard } from "./clipboard/index.mjs";
|
|
24
|
+
import { serveFiles } from "./served.mjs";
|
|
23
25
|
import { createFormatting } from "./format-bar/index.mjs";
|
|
24
26
|
import { connectHints, hideHint, readOnlyReason, scheduleHint, trackPointer } from "./hints/index.mjs";
|
|
25
27
|
import { createInsert } from "./insert/index.mjs";
|
|
28
|
+
import { createAfter } from "./after/index.mjs";
|
|
26
29
|
import { connectLinks, dismissLink, drawPasted, followLink, leadsToPage, linkBoxNode, linkHolds, linkNodes, linkOf, linkPending, openLink, pageLinkOf } from "./links/index.mjs";
|
|
27
30
|
import { bookmarkItems, connectViews, linkTitle, offerViews } from "./links/views.mjs";
|
|
28
31
|
import { connectChipFills } from "./chip-fills.mjs";
|
|
@@ -35,6 +38,7 @@ import { createResize } from "./resize/index.mjs";
|
|
|
35
38
|
import { connectPages, fieldOpen, keptByComponent, menuRow, modalOps, pageAt, pageIcon, pageObjects, pageOf, pageOfHost, pageOfType, pageOfUnit, panelOpen, typedAsIs } from "./page-objects.mjs";
|
|
36
39
|
import { preloading } from "./type-grid.mjs";
|
|
37
40
|
import { createColumnGaps } from "./columns/index.mjs";
|
|
41
|
+
import { viewFrames } from "./table/binding.mjs";
|
|
38
42
|
import { createTableEditing } from "./table/index.mjs";
|
|
39
43
|
import { createAtMenu } from "./at-menu/index.mjs";
|
|
40
44
|
import { createSlashMenu } from "./slash-menu/index.mjs";
|
|
@@ -58,6 +62,7 @@ import { goBackTo, placeIn, unmoved } from "../../shared/reading-place.mjs";
|
|
|
58
62
|
import { heldList, holdPages } from "./links/pages.mjs";
|
|
59
63
|
import { hideBlocks } from "./offered.mjs";
|
|
60
64
|
import { local, storageOf } from "./storage.mjs";
|
|
65
|
+
import { createTodoWrites } from "./todo-writes.mjs";
|
|
61
66
|
import { language, t } from "../../shared/i18n/index.mjs";
|
|
62
67
|
|
|
63
68
|
// In-place editing for the live preview (`npm run dev:local` only; never exported).
|
|
@@ -70,6 +75,7 @@ import { language, t } from "../../shared/i18n/index.mjs";
|
|
|
70
75
|
//
|
|
71
76
|
// typing/ Enter, Backspace/Delete at block edges, auto spacing, placeholders
|
|
72
77
|
// insert/ new blocks: below a block (its menu), a click below the last block, a paragraph before or after
|
|
78
|
+
// after/ the caret after a block of no text (a click right of it): Backspace deletes it, Enter or a key a paragraph after it
|
|
73
79
|
// format-bar/ the bar over selected text and its keys (marks.mjs does the marks)
|
|
74
80
|
// links/ the link box (Ctrl+K), following links; hints/: why something is read-only
|
|
75
81
|
// formula/ the formula box: selected text made an inline formula (Ctrl+Shift+E)
|
|
@@ -259,7 +265,9 @@ function showLanded(node) {
|
|
|
259
265
|
modalOps().show(node);
|
|
260
266
|
}
|
|
261
267
|
|
|
262
|
-
|
|
268
|
+
// The caret after a block of no text, where a click right of one puts it (insert/ clickBlank).
|
|
269
|
+
const after = createAfter({ struct, blocks: () => blocks, keepText: (node) => blocks.keepText(node), removeBlocks: (units) => blocks.remove(units), say, undo: () => undo(), redo: () => redo() });
|
|
270
|
+
const insert = createInsert({ struct, blocks: () => blocks, after });
|
|
263
271
|
const { newParagraph } = insert;
|
|
264
272
|
|
|
265
273
|
// What a component does on the page beyond what every block does is its own page module
|
|
@@ -268,7 +276,12 @@ const { newParagraph } = insert;
|
|
|
268
276
|
|
|
269
277
|
// The icon picker's images go into the report's folder (editor/media-store.mjs), where the server serves them.
|
|
270
278
|
const assetUrl = (file) => mediaUrl("asset", MAP.slug, file);
|
|
279
|
+
serveFiles(assetUrl); // a table cell's pictures (单元格里的图片) show where the server serves them
|
|
271
280
|
connectPicker({ slug: MAP.slug, token: MAP.token, notify: say });
|
|
281
|
+
// A block of the page checking a to-do of a document (context.workspace.setTodo: ./todo-writes.mjs): written
|
|
282
|
+
// by the workspace's service, this one's too as any write it did not make, which the page merges; no step of
|
|
283
|
+
// its undo (only a custom page keeps one: board/).
|
|
284
|
+
createTodoWrites({ token: MAP.token }).listen();
|
|
272
285
|
// Whether a block tool may act: the page edits, no reload is on its way and no field of a component is being edited.
|
|
273
286
|
const active = () => editing && !autosave?.state.reloading && !fieldOpen();
|
|
274
287
|
// A picture or file sent to the report's folder (kind: "image", "file" or "embed"): the server's answer.
|
|
@@ -319,6 +332,8 @@ const typing = createTyping({
|
|
|
319
332
|
adding: () => slash?.adding ?? null,
|
|
320
333
|
leave: createLeaving({ struct, touchedBy, convertHost, typeOf, targetsOf }),
|
|
321
334
|
showHidden: (node) => blocks?.folds.showAround(node), // a folded heading's section opened before a join takes in its words (fold/)
|
|
335
|
+
look: lookStep, // a block's alignment and indent taken off by Backspace (align.mjs)
|
|
336
|
+
afterAbove: (host) => after.back(host), // Backspace right after a block of no text: the caret after it (after/)
|
|
322
337
|
});
|
|
323
338
|
// Selecting text across blocks: its listeners go before the editor's own keys and clipboard.
|
|
324
339
|
const crossText = createTextSelection({
|
|
@@ -372,6 +387,7 @@ const clipboard = createClipboard({
|
|
|
372
387
|
pageLink: pageLinkOf,
|
|
373
388
|
titleBold: () => formatting?.armed ?? false, // a node's empty title: what is pasted there bold, as typed
|
|
374
389
|
showCaret,
|
|
390
|
+
pictures: () => tables?.pictures ?? null, // a table cell's (table/pictures.mjs)
|
|
375
391
|
});
|
|
376
392
|
|
|
377
393
|
// ---------- editing ----------
|
|
@@ -440,17 +456,19 @@ function enter() {
|
|
|
440
456
|
conflicts.add(entries.map((entry) => ({ ...entry, key: `r:${entry.key}`, revert: entry.key, kind: entry.written ? "reverted-source" : entry.unit === undefined ? "reverted" : "reverted-unit" })));
|
|
441
457
|
say(t("AI 的写入把你之前保存的 {0} 处修改改回去了:在左下方选择保留哪一边。", entries.length), "error");
|
|
442
458
|
},
|
|
459
|
+
listed: () => showLost(), // a block the page before this one made, which someone else's write took out
|
|
443
460
|
});
|
|
444
461
|
conflicts = createConflicts({ act: decide, nodeOf: conflictNode, restorable, copyBlock: (node) => clipboard.copyBlocks([node]), say });
|
|
445
462
|
editing = true;
|
|
446
463
|
document.documentElement.setAttribute("data-ge-editing", "");
|
|
464
|
+
typing.untitled(); // an empty title says 未命名文档 from the start
|
|
447
465
|
blocks?.folds.start(); // what was folded, folded again in this task: no frame shows it open (fold/)
|
|
448
466
|
refresh();
|
|
449
467
|
for (const page of pageObjects()) page.entered?.();
|
|
450
468
|
}
|
|
451
469
|
|
|
452
470
|
// What the page says when what a component wrote went by a manifest that changed: given up, the page shown again.
|
|
453
|
-
const outdatedNotice = () => t("
|
|
471
|
+
const outdatedNotice = () => t("自定义块刚刚变了,这次改动没有保存,页面已按新的块重新显示。");
|
|
454
472
|
|
|
455
473
|
// What 仍然调整 wrote over someone else's change of what a component writes, by page unit: the step that
|
|
456
474
|
// gives theirs back (installed/ overwrite), and when its write went in, all of it (commit.mjs `forced`).
|
|
@@ -465,9 +483,10 @@ const keepsOverwrite = (asked) => !asked && [...overwrites.values()].some(({ lan
|
|
|
465
483
|
|
|
466
484
|
// A commit was taken in (commit.mjs): a block merged with someone else's words shows the merge;
|
|
467
485
|
// what the file refused is flagged and held back, the rest goes on.
|
|
468
|
-
function committed({ conflicts: held, merged, outdated, forced = [] }, receipt) {
|
|
486
|
+
function committed({ conflicts: held, merged, outdated, forced = [], rekeyed = [] }, receipt) {
|
|
469
487
|
agentChanges?.committed(receipt);
|
|
470
488
|
for (const host of merged) history.merged(host);
|
|
489
|
+
history.rekeyed(rekeyed); // the keys of tables the file gave otherwise, in the steps that recorded them
|
|
471
490
|
for (const unit of forced) {
|
|
472
491
|
const written = overwrites.get(unit);
|
|
473
492
|
if (!written || written.landed > 0) continue;
|
|
@@ -485,7 +504,7 @@ function committed({ conflicts: held, merged, outdated, forced = [] }, receipt)
|
|
|
485
504
|
conflicts.add(held);
|
|
486
505
|
const conflicted = held.filter((entry) => !unfit(entry) && !packageChanged(entry)).length;
|
|
487
506
|
const packaged = held.filter(packageChanged).length;
|
|
488
|
-
say(conflicted > 0 ? t("{0} 处修改和文件的最新版本冲突,没有保存:在左下方选择怎么处理。", conflicted) : packaged > 0 ? t("
|
|
507
|
+
say(conflicted > 0 ? t("{0} 处修改和文件的最新版本冲突,没有保存:在左下方选择怎么处理。", conflicted) : packaged > 0 ? t("自定义块刚刚变了,{0} 处修改没有保存:在左下方选择怎么处理。", packaged) : t("{0} 处内容文档存不下,没有保存:在左下方选择怎么处理。", held.length), "error");
|
|
489
508
|
}
|
|
490
509
|
else if (outdated || merged.length > 0 || receipt.texts?.some((entry) => entry.status === "merged")) {
|
|
491
510
|
const count = receipt.texts.filter((entry) => entry.status === "merged").length;
|
|
@@ -612,6 +631,7 @@ function markChanged(now = false) {
|
|
|
612
631
|
conflicts?.reflag();
|
|
613
632
|
}
|
|
614
633
|
if (messageKind() === "error") settle(); // the reader is dealing with it
|
|
634
|
+
typing.untitled(); // a title emptied (or filled) by any change says 未命名文档 (or nothing) at once
|
|
615
635
|
lastChange = Date.now();
|
|
616
636
|
discrete ||= now;
|
|
617
637
|
const counting = checkPending;
|
|
@@ -661,7 +681,7 @@ function convertHost(host, type, typed = null, after = null) {
|
|
|
661
681
|
if (!focus && !typed) return null;
|
|
662
682
|
const more = focus && after ? after(focus) : [];
|
|
663
683
|
return { touched: [focus ?? host], focus: focus ?? host, created: [...created, ...more] };
|
|
664
|
-
});
|
|
684
|
+
}, { attributes: viewFrames(type) });
|
|
665
685
|
if (result) afterConvert(result.focus, type, result.focus !== host ? t("已转换为{0}", menuRow(type).label) : null);
|
|
666
686
|
}
|
|
667
687
|
|
|
@@ -691,6 +711,8 @@ function afterConvert(focus, type, said) {
|
|
|
691
711
|
* heading) and the new block turns into the type; below any other block, an empty paragraph of its
|
|
692
712
|
* box does (the first box out that takes one). One undo step.
|
|
693
713
|
*/
|
|
714
|
+
// A view of a table (a custom block that reads tables) is bound to the table above it as it is made
|
|
715
|
+
// (installed/page.mjs create), the tables' keys recorded in the same step (viewFrames).
|
|
694
716
|
function insertBelow(target, type, typed = null) {
|
|
695
717
|
const splits = isHost(target) && can(target, "split");
|
|
696
718
|
let after = target;
|
|
@@ -712,7 +734,7 @@ function insertBelow(target, type, typed = null) {
|
|
|
712
734
|
const turned = type === "paragraph" && fresh.localName === "p" ? { focus: null, created: [] } : convertBlock(fresh, type, { fresh: true });
|
|
713
735
|
const focus = turned.focus ?? fresh;
|
|
714
736
|
return { touched: splits ? [target, focus] : [focus], focus, created: turned.created };
|
|
715
|
-
});
|
|
737
|
+
}, { attributes: viewFrames(type) });
|
|
716
738
|
if (result) afterConvert(result.focus, type, t("已插入{0}", menuRow(type).label));
|
|
717
739
|
}
|
|
718
740
|
|
|
@@ -765,7 +787,7 @@ function convertUnit(unit, type, { loaded = false } = {}) {
|
|
|
765
787
|
const turned = turnUnit(unit, type);
|
|
766
788
|
emptied = Boolean(turned.emptied);
|
|
767
789
|
return turned.focus ? { touched: [turned.focus], focus: turned.focus, created: turned.created, select: emptied ? null : unit } : null;
|
|
768
|
-
});
|
|
790
|
+
}, { attributes: viewFrames(type) });
|
|
769
791
|
if (!result) return;
|
|
770
792
|
if (!made || !onCreated(type, result.focus)) {
|
|
771
793
|
if (emptied && isHost(result.focus)) caretAt(result.focus, "start");
|
|
@@ -806,6 +828,7 @@ function convertAll(group, type, { select = true } = {}) {
|
|
|
806
828
|
function onKeydown(event) {
|
|
807
829
|
compositionOver(event);
|
|
808
830
|
if (!editing) return;
|
|
831
|
+
if (after.key(event)) return; // the caret after a block: its keys are its own (after/)
|
|
809
832
|
// A 批注's card is a field of its own: its keys are its own, but for Ctrl+S, which saves it and the report.
|
|
810
833
|
if (annotate?.holds(event.target)) {
|
|
811
834
|
const mod = event.ctrlKey || event.metaKey;
|
|
@@ -911,7 +934,8 @@ function onKeydown(event) {
|
|
|
911
934
|
moveHostBlock(host, event.key === "ArrowUp" ? -1 : 1);
|
|
912
935
|
} else if (event.key.startsWith("Arrow") && !mod && !event.altKey && !event.shiftKey && !renamed) {
|
|
913
936
|
// ←/→ stop on both sides of inline code's edges (typing/code-edges.mjs); a tab's caret stays in its name.
|
|
914
|
-
|
|
937
|
+
// ← or ↑ at the start of the text right after a block of no text: the caret after that block (after/).
|
|
938
|
+
if ((textFilters(host) && codeArrow(host, event.key)) || after.up(host, event.key) || arrow(host, event.key)) event.preventDefault();
|
|
915
939
|
}
|
|
916
940
|
}
|
|
917
941
|
|
|
@@ -1160,7 +1184,8 @@ async function newSubpage(title) {
|
|
|
1160
1184
|
}
|
|
1161
1185
|
|
|
1162
1186
|
// The report's title as the reader sees it now (while editing, the title block's text).
|
|
1163
|
-
const
|
|
1187
|
+
const titleNode = () => document.querySelector('[data-ge-kind="title"]') ?? document.querySelector("h1.doc-title, .doc-header h1");
|
|
1188
|
+
const currentTitle = () => titleNode()?.textContent.replace(/\s+/g, " ").trim() ?? "";
|
|
1164
1189
|
|
|
1165
1190
|
// This page, as the list of pages takes it (links/pages.mjs).
|
|
1166
1191
|
const thisPage = () => ({ slug: MAP.slug, title: currentTitle() });
|
|
@@ -1225,6 +1250,15 @@ const COMMANDS = {
|
|
|
1225
1250
|
if (!editing || !annotate) return { ok: false, reason: "editing" };
|
|
1226
1251
|
return annotate.action(message);
|
|
1227
1252
|
},
|
|
1253
|
+
// The outline (目录) switched by the workbench's 更多: a draft of another workspace is shown from that workspace's own origin,
|
|
1254
|
+
// whose storage the workbench cannot write (the switch is kept per origin: shared/preferences.mjs outlineOpen), so it asks and
|
|
1255
|
+
// this page keeps it, shown as another tab's change is (the storage event the outline listens for). Answers the switch as kept.
|
|
1256
|
+
async outline({ open }) {
|
|
1257
|
+
if (typeof open !== "boolean") return { ok: false, reason: "open" };
|
|
1258
|
+
setOutlineOpen(MAP.slug, open);
|
|
1259
|
+
dispatchEvent(new StorageEvent("storage", { key: OUTLINE_OPEN_KEY }));
|
|
1260
|
+
return { ok: true, outline: outlineOpen(MAP.slug) };
|
|
1261
|
+
},
|
|
1228
1262
|
// Rename the report: its title, selected for typing (saving it updates <title> and report.json).
|
|
1229
1263
|
async "edit-title"() {
|
|
1230
1264
|
const title = document.querySelector('[data-ge-kind="title"]');
|
|
@@ -1454,8 +1488,21 @@ function handOff() {
|
|
|
1454
1488
|
function connect() {
|
|
1455
1489
|
// The look the page shows (字体与布局: its <html>'s, src/shared/document-look.mjs), which the workbench's
|
|
1456
1490
|
// 更多 marks as chosen; told again when it changes (the kit's ui.js, doc-look-change).
|
|
1457
|
-
|
|
1491
|
+
// `title`: null for a page with no title at all (the workbench names it by its doc.json); "" an untitled one (未命名文档).
|
|
1492
|
+
workbench = connectWorkbench({ slug: MAP.slug, snapshot: () => ({ title: titleNode() ? currentTitle() : null, icon: pageIcon(), look: lookOfElement(document.documentElement), state: sessionState(), annotations: annotate?.count(), outline: outlineOpen(MAP.slug) }), commands: COMMANDS, modals: modalOps() });
|
|
1458
1493
|
addEventListener("doc-look-change", () => workbench?.update());
|
|
1494
|
+
onOutlineOpen(() => workbench?.update()); // the switch changed in another tab of this origin: the workbench's 目录 follows it (a draft's)
|
|
1495
|
+
// A block's context.workspace.open (the kit's runtime/workspace.js): a document, or a block of one, goes
|
|
1496
|
+
// where a link to it goes (goTo: in the workbench, its address; on its own, the page once saved); a custom
|
|
1497
|
+
// page, the workbench's #@<slug>, or /pages/<slug> once saved.
|
|
1498
|
+
addEventListener("doc-open-request", (event) => {
|
|
1499
|
+
const { slug = null, block = null, page = null } = event.detail ?? {};
|
|
1500
|
+
event.preventDefault();
|
|
1501
|
+
if (page) {
|
|
1502
|
+
if (window.parent !== window && !SOLO) workbench?.open({ hash: `@${page}` });
|
|
1503
|
+
else COMMANDS["prepare-close"]().then(() => location.assign(`/pages/${page}`));
|
|
1504
|
+
} else goTo({ slug, block }, `/generated/${slug}.html${block ? `#${encodeURIComponent(block)}` : ""}`);
|
|
1505
|
+
});
|
|
1459
1506
|
relayTo(workbench ? workbench.notice : null, workbench ? workbench.noticeRoom : null); // the workbench shows the page's notices, above the page's bottom panels
|
|
1460
1507
|
handOff();
|
|
1461
1508
|
// A page on its own in a frame (?solo: the 写作偏好 dialog's, which no session asks to save) is saved
|
|
@@ -1514,6 +1561,10 @@ async function start() {
|
|
|
1514
1561
|
TAB = newTab();
|
|
1515
1562
|
session.set(keys.tab, TAB);
|
|
1516
1563
|
}
|
|
1564
|
+
// What earlier pages of the document committed, made and wrote (this tab's, and those of tabs no longer
|
|
1565
|
+
// open), asked of at once where this page opened on another version of the file than they last knew
|
|
1566
|
+
// (its cards and list said through the workbench).
|
|
1567
|
+
autosave?.opened(open);
|
|
1517
1568
|
const prefix = pendingKey(MAP.slug, "");
|
|
1518
1569
|
const left = local.keys().filter((key) => key.startsWith(prefix) && key !== pendingKey(MAP.slug, TAB) && !open.has(key.slice(prefix.length)));
|
|
1519
1570
|
if (left.length === 0) return;
|
|
@@ -1573,7 +1624,7 @@ function showLost() {
|
|
|
1573
1624
|
if (block) {
|
|
1574
1625
|
panelItem(
|
|
1575
1626
|
element("p", { text: t("文件里的这一块已被修改:复制你的版本,再粘贴到页面上。") }),
|
|
1576
|
-
element("div", { class: "ge-actions" },
|
|
1627
|
+
element("div", { class: "ge-actions" }, textButton(t("复制这一块"), () => { if (!clipboard.copyBlocks([block])) say(t("没能完成,请再试一次。"), "error"); })),
|
|
1577
1628
|
);
|
|
1578
1629
|
continue;
|
|
1579
1630
|
}
|
|
@@ -1581,10 +1632,10 @@ function showLost() {
|
|
|
1581
1632
|
panelItem(
|
|
1582
1633
|
element("p", { text: LOST[item.why] ?? LOST.refused }),
|
|
1583
1634
|
element("div", { class: "ge-version", text }),
|
|
1584
|
-
element("div", { class: "ge-actions" },
|
|
1635
|
+
element("div", { class: "ge-actions" }, textButton(t("复制文字"), () => navigator.clipboard?.writeText(text).then(() => say(t("已复制。"))))),
|
|
1585
1636
|
);
|
|
1586
1637
|
}
|
|
1587
|
-
panelItem(element("div", { class: "ge-actions" },
|
|
1638
|
+
panelItem(element("div", { class: "ge-actions" }, textButton(t("都处理好了,不再保留"), () => {
|
|
1588
1639
|
local.remove(lostKey(MAP.slug));
|
|
1589
1640
|
closePanel();
|
|
1590
1641
|
}, { primary: true })));
|
|
@@ -1617,10 +1668,13 @@ function boot() {
|
|
|
1617
1668
|
copyLink: SOLO ? null : copyBlockLink, // what ?solo shows (写作偏好) only its dialog opens: no address leads there
|
|
1618
1669
|
linkAhead: () => holdPages(thisPage),
|
|
1619
1670
|
});
|
|
1620
|
-
resize = createResize({ units, active, look: lookStep, say, owns: (node) => tables?.owns(node) ?? false });
|
|
1621
|
-
gaps = createColumnGaps({ active, struct, look: lookStep, say });
|
|
1671
|
+
resize = createResize({ units, active, look: lookStep, say, settle, owns: (node) => tables?.owns(node) ?? false });
|
|
1672
|
+
gaps = createColumnGaps({ active, struct, look: lookStep, say, settle });
|
|
1622
1673
|
for (const page of pageObjects()) page.install?.(); // the round "+" at a flowchart node's right, renaming Sheet tabs
|
|
1623
|
-
tables = createTableEditing({
|
|
1674
|
+
tables = createTableEditing({
|
|
1675
|
+
active, struct, look: lookStep, selectBlock: (unit) => blocks.select(unit), resizeTable: (event, unit, axis) => resize.startTable(event, unit, axis), say, settle, cellsOf: (data) => clipboard.cellsOf(data), upload: uploadTo, typedKey,
|
|
1676
|
+
recordStep,
|
|
1677
|
+
});
|
|
1624
1678
|
selectAll = createSelectAll({ blocks, say, cells: { table: () => tables.selectedTable, clear: () => tables.clear() } });
|
|
1625
1679
|
createFrame(() => editing);
|
|
1626
1680
|
createFlags(() => editing);
|
|
@@ -64,14 +64,14 @@ export const PICKER_CSS = `
|
|
|
64
64
|
.nmm-cell.focus-visible { background: var(--ge-press); }
|
|
65
65
|
.nmm-cell img { display: block; }
|
|
66
66
|
.nmm-cell img.notion-custom-emoji { object-fit: contain; color: transparent; }
|
|
67
|
-
/* 添加表情符号: the custom group's first cell, a round plus (26, 3 around,
|
|
68
|
-
|
|
69
|
-
.nmm-cell.nmm-add-cell { width: 26px; height: 26px; margin: 3px; box-sizing: border-box; border-radius: 50%;
|
|
67
|
+
/* 添加表情符号: the custom group's first cell, a round plus (26, 3 around, the plus --ge-ico3, no line round
|
|
68
|
+
it: gray under the pointer as a cell); with no result, a button (28 high, 13px / 500, no line either) */
|
|
69
|
+
.nmm-cell.nmm-add-cell { width: 26px; height: 26px; margin: 3px; box-sizing: border-box; border-radius: 50%; --nmm-icon: var(--ge-ico3); }
|
|
70
70
|
.nmm-cell.nmm-add-cell.focused { --nmm-icon: var(--ge-ico); }
|
|
71
71
|
.nmm-empty { padding: 8px 12px; }
|
|
72
72
|
.nmm-empty-caption { display: flex; align-items: center; height: 20px; padding: 0 4px; font-size: 12px; font-weight: 500; color: var(--ge-tx3); }
|
|
73
73
|
.nmm-empty.with-add { display: flex; flex-direction: column; align-items: flex-start; gap: 6px; }
|
|
74
|
-
.nmm-cell.nmm-add-button { justify-content: flex-start; gap: 6px; width: max-content; height: 28px; padding: 0 10px 0 8px; box-sizing: border-box; border-radius: 6px;
|
|
74
|
+
.nmm-cell.nmm-add-button { justify-content: flex-start; gap: 6px; width: max-content; height: 28px; padding: 0 10px 0 8px; box-sizing: border-box; border-radius: 6px; font-size: 13px; font-weight: 500; line-height: 1; color: var(--ge-tx); white-space: nowrap; --nmm-icon: var(--ge-ico2); }
|
|
75
75
|
|
|
76
76
|
/* The category bar: a --ge-line above it, 6 12 8; buttons 28 x 28, icons 18 in --ge-ico3; the group scrolled
|
|
77
77
|
to on --ge-hover, its icon --ge-ico; a group with no emoji faded to .35 and not to be clicked (自定义 and
|
|
@@ -106,8 +106,8 @@ export const PICKER_CSS = `
|
|
|
106
106
|
|
|
107
107
|
/* The 上传 tab and the 添加表情符号 popup (upload.mjs): the zone an image goes in on --ge-field, a 1px
|
|
108
108
|
--ge-edge inside it, rounded 8, deeper while a file is dragged over it (--ge-hover, --ge-ico3), never blue;
|
|
109
|
-
保存
|
|
110
|
-
|
|
109
|
+
保存 the pale blue primary and 取消 / 返回 the plain text button (look.mjs BUTTONS: .ge-btn, dimmed while it cannot be
|
|
110
|
+
clicked); the checkbox checked --ge-tx2 with a white tick; an error --ge-red */
|
|
111
111
|
.nmm-upload { display: flex; flex-direction: column; padding: 0 16px; font-size: 14px; color: var(--ge-tx); }
|
|
112
112
|
.nmm-upload-title { margin-top: 14px; font-size: 14px; font-weight: 600; }
|
|
113
113
|
.nmm-upload-description { margin-top: 2px; font-size: 12px; color: var(--ge-tx2); }
|
|
@@ -142,12 +142,7 @@ export const PICKER_CSS = `
|
|
|
142
142
|
.nmm-upload-name-error { margin-top: 10px; font-size: 12px; color: var(--ge-red); }
|
|
143
143
|
.nmm-upload-name-error[hidden], .nmm-upload [hidden] { display: none; }
|
|
144
144
|
.nmm-upload-footer { display: flex; align-items: center; justify-content: space-between; gap: 8px; margin: 16px 0 12px; }
|
|
145
|
-
.nmm-upload-secondary, .nmm-upload-save {
|
|
146
|
-
.nmm-upload-secondary { color: var(--ge-tx2); }
|
|
147
|
-
.nmm-upload-secondary:hover { background: var(--ge-hover); color: var(--ge-tx); }
|
|
148
|
-
.nmm-upload-save { color: var(--ge-tx); font-weight: 500; }
|
|
149
|
-
.nmm-upload-save:not(.disabled):hover { background: var(--ge-hover); }
|
|
150
|
-
.nmm-upload-save.disabled { color: var(--ge-tx3); cursor: default; }
|
|
145
|
+
.nmm-upload-secondary, .nmm-upload-save { font-size: 14px; }
|
|
151
146
|
.nmm-custom-emoji-popup { min-width: 280px; border-radius: 10px; background: var(--ge-bg); box-shadow: var(--ge-shadow-pop); }
|
|
152
147
|
|
|
153
148
|
/* A button reached by Tab: a gray fill, not the browser's dark or blue ring; the checkbox a gray ring */
|
|
@@ -76,8 +76,8 @@ export function createUploadForm({ showTitle = false, largeEmoji = false, allowU
|
|
|
76
76
|
`<label class="nmm-upload-name" hidden><div class="nmm-upload-name-label">${T.nameLabel}</div>` +
|
|
77
77
|
`<div class="nmm-upload-input"><input type="text" placeholder="${T.namePlaceholder}" autocomplete="off" spellcheck="false"></div>` +
|
|
78
78
|
`<div class="nmm-upload-name-error" hidden></div></label>` +
|
|
79
|
-
`<div class="nmm-upload-footer"><div role="button" tabindex="0" class="nmm-upload-secondary" data-act="secondary"></div>` +
|
|
80
|
-
`<div role="button" tabindex="0" class="nmm-upload-save" data-act="save">${T.save}</div></div>` +
|
|
79
|
+
`<div class="nmm-upload-footer"><div role="button" tabindex="0" class="ge-btn nmm-upload-secondary" data-act="secondary"></div>` +
|
|
80
|
+
`<div role="button" tabindex="0" class="ge-btn nmm-upload-save" data-primary data-act="save">${T.save}</div></div>` +
|
|
81
81
|
`<input type="file" accept="${ACCEPT}" hidden>`;
|
|
82
82
|
|
|
83
83
|
const zone = el.querySelector('.nmm-upload-zone'), wrap = el.querySelector('.nmm-upload-zone-wrap');
|
|
@@ -44,13 +44,12 @@ import { t } from "../../../shared/i18n/index.mjs";
|
|
|
44
44
|
// (lineAt, blocks.mjs). The handle and the bar are drawn in the editor's own layer (overlay-layer.mjs:
|
|
45
45
|
// the one of the block they stand beside), never inside a block, each belonging to the block it stands
|
|
46
46
|
// beside (overlays.mjs). A press ends when the pointer comes up, is cancelled, or the handle loses the
|
|
47
|
-
// pointer capture (then a drag under way is cancelled, never dropped).
|
|
47
|
+
// pointer capture (then a drag under way is cancelled, never dropped). On a page the editor edits, its
|
|
48
48
|
// side gutters (the kit's --doc-page-gutter, --doc-wide-gutter) are at least the room the
|
|
49
|
-
// handle takes left of a block, and a little (
|
|
50
|
-
//
|
|
51
|
-
// the right. A wide window, whose column
|
|
52
|
-
|
|
53
|
-
const EDGE = ADD.width + HANDLE.width + HANDLE.gap + 12; // the page's gutter while editing: the bar's square, the grip, its gap, and room to breathe (64)
|
|
49
|
+
// handle takes left of a block, and a little (margin.mjs MARGIN.edge, from the page's first paint: the
|
|
50
|
+
// head's MARGIN_STYLE): on a narrow window the handle stands in the margin, never over the text, as
|
|
51
|
+
// Feishu's and Notion's do; the section bar has the same room on the right. A wide window, whose column
|
|
52
|
+
// leaves more than that, does not change.
|
|
54
53
|
|
|
55
54
|
const STYLE = `
|
|
56
55
|
.ge-handle { position: absolute; left: 0; top: 0; z-index: ${IN_LAYER.handle}; display: flex; align-items: center; height: ${HANDLE.height}px; touch-action: none; }
|
|
@@ -84,8 +83,6 @@ const STYLE = `
|
|
|
84
83
|
.ge-section-bar::before { content: ""; position: absolute; top: 0; bottom: 0; left: 6px; width: 4px; border-radius: 2px; background: light-dark(rgb(55 53 47 / 14%), rgb(255 255 255 / 14%)); transition: background .08s ease-in; }
|
|
85
84
|
.ge-section-bar:hover::before { background: light-dark(rgb(55 53 47 / 28%), rgb(255 255 255 / 26%)); }
|
|
86
85
|
.ge-section-bar[data-active]::before { background: color-mix(in srgb, var(--doc-accent, #2678d8) 60%, transparent); }
|
|
87
|
-
/* Room for the handle beside the page's blocks: the page's gutters while editing (resize/ reads --ge-edge-room). */
|
|
88
|
-
:root[data-ge-editing] { --ge-edge-room: ${EDGE}px; --doc-page-gutter: var(--ge-edge-room); --doc-wide-gutter: var(--ge-edge-room); }
|
|
89
86
|
`;
|
|
90
87
|
|
|
91
88
|
// Notion's grip in size (its dragHandle icon at its icons' 20px): 2.5px dots 5px apart across and 6px down (notion-lite's were 5px down, the grip 2px shorter than Notion's: the user, 2026-10-26).
|
|
@@ -69,7 +69,7 @@ export function createHistory({ changed, beforeUndo, blocks, afterText, refuse =
|
|
|
69
69
|
typing.time = at;
|
|
70
70
|
} else {
|
|
71
71
|
closeTyping();
|
|
72
|
-
typing = { type: "text", element: host, before, after, time: at };
|
|
72
|
+
typing = { type: "text", element: host, before, after, time: at, began: at };
|
|
73
73
|
}
|
|
74
74
|
changed(now);
|
|
75
75
|
}
|
|
@@ -83,8 +83,14 @@ export function createHistory({ changed, beforeUndo, blocks, afterText, refuse =
|
|
|
83
83
|
changed(true);
|
|
84
84
|
}
|
|
85
85
|
|
|
86
|
+
// A run of typing closed: a step of its own, unless it went into the block the last step made for
|
|
87
|
+
// what was typed (struct's `typedInto`: a paragraph after a block, after/), begun within a second of it:
|
|
88
|
+
// then it is part of that step, which undo takes away whole, redo putting the words back with it.
|
|
86
89
|
function closeTyping() {
|
|
87
|
-
|
|
90
|
+
const last = undoStack.at(-1);
|
|
91
|
+
if (typingChanged() && last?.typedInto === typing.element && typing.began - last.madeAt < 1000) last.htmlAfter.set(typing.element, typing.after);
|
|
92
|
+
else if (typingChanged()) push(typing);
|
|
93
|
+
if (typing && last?.typedInto) last.typedInto = null;
|
|
88
94
|
typing = null;
|
|
89
95
|
}
|
|
90
96
|
|
|
@@ -148,6 +154,31 @@ export function createHistory({ changed, beforeUndo, blocks, afterText, refuse =
|
|
|
148
154
|
for (const stack of [undoStack, redoStack]) if (stack.includes(step)) stack.splice(stack.indexOf(step), 1);
|
|
149
155
|
}
|
|
150
156
|
|
|
157
|
+
// An attribute the file gave another value than the page had (`changes`: [element, name, from, to],
|
|
158
|
+
// `to` null for none; a key of a table a commit gave a pair anew: page/commit.mjs apply), the page's
|
|
159
|
+
// element set so: the steps that recorded `from` of it record `to` instead, so that an undo or a redo
|
|
160
|
+
// puts back what the file has, never the value it changed (a view made from "/" redone with the key its view
|
|
161
|
+
// no longer carries).
|
|
162
|
+
function rekeyed(changes) {
|
|
163
|
+
if (changes.length === 0) return;
|
|
164
|
+
for (const step of [...undoStack, ...redoStack]) {
|
|
165
|
+
for (const recorded of [step.attributesBefore, step.attributesAfter]) {
|
|
166
|
+
for (const [element, name, from, to] of changes) {
|
|
167
|
+
const values = recorded?.get(element);
|
|
168
|
+
if (values?.some(([each, value]) => each === name && value === from)) recorded.set(element, values.map(([each, value]) => [each, each === name && value === from ? to : value]));
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
// A view's table chosen in its 设置 is a step of look (installed/page.mjs readTable): its attributes by element.
|
|
172
|
+
if (step.type === "look") {
|
|
173
|
+
for (const recorded of [step.before, step.after]) {
|
|
174
|
+
step.elements.forEach((each, index) => {
|
|
175
|
+
for (const [element, name, from, to] of changes) if (each === element && recorded[index]?.attributes?.[name] === from) recorded[index].attributes[name] = to;
|
|
176
|
+
});
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
|
|
151
182
|
// What a step puts into a block (`from`: what the step left there, `to`: what it puts back): as
|
|
152
183
|
// recorded, unless someone else's words were merged into the block since the step; then the step's
|
|
153
184
|
// change three ways against what the block holds now (null: the two touch the same place).
|
|
@@ -174,8 +205,10 @@ export function createHistory({ changed, beforeUndo, blocks, afterText, refuse =
|
|
|
174
205
|
// after undo and redo (a deleted Sheet tab switches the Sheet shown). A step that names no text block
|
|
175
206
|
// it came from keeps where the caret stood, which undo puts back, as notion-lite's selectionBefore.
|
|
176
207
|
// `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
|
-
|
|
208
|
+
// spans and widths, which its operations change: components/table/page.mjs). `caret`: where the caret
|
|
209
|
+
// stood in the first text block it touched is kept too, which undo puts back (notion-lite's Enter in the
|
|
210
|
+
// page's title, enter.js: "撤销后光标回到回车前的位置"; typing/ enterBody).
|
|
211
|
+
function struct(parents, touched, mutate, { attributes = [], caret = false, typedInto = null } = {}) {
|
|
179
212
|
closeTyping();
|
|
180
213
|
// What the change may leave untidy is tidied after it by the components that know (rows of
|
|
181
214
|
// columns with a column emptied, lists set side by side: tidy), so what they name is recorded
|
|
@@ -189,7 +222,7 @@ export function createHistory({ changed, beforeUndo, blocks, afterText, refuse =
|
|
|
189
222
|
}
|
|
190
223
|
// A text block among the parents (a list item whose lists change) keeps its text through undo too.
|
|
191
224
|
touched = [...new Set([...touched, ...parents.filter(isHost)])];
|
|
192
|
-
const place = touched[0] ? null : caretPlace(parents[0]);
|
|
225
|
+
const place = touched[0] && !caret ? null : caretPlace(parents[0]);
|
|
193
226
|
const before = parents.map(contentOf);
|
|
194
227
|
const htmlBefore = new Map(touched.map((node) => [node, ownHTML(node)]));
|
|
195
228
|
const classesBefore = new Map(touched.map((node) => [node, new Set(node.classList)]));
|
|
@@ -219,7 +252,7 @@ export function createHistory({ changed, beforeUndo, blocks, afterText, refuse =
|
|
|
219
252
|
.filter(({ added, removed }) => added.length > 0 || removed.length > 0),
|
|
220
253
|
attributesBefore,
|
|
221
254
|
attributesAfter: attributesOf(),
|
|
222
|
-
focusBefore: touched[0] ?? place?.host,
|
|
255
|
+
focusBefore: (caret ? place?.host : null) ?? touched[0] ?? place?.host,
|
|
223
256
|
caretBefore: place?.offsets ?? null,
|
|
224
257
|
focusAfter: result.focus,
|
|
225
258
|
select: result.select ?? null,
|
|
@@ -227,6 +260,7 @@ export function createHistory({ changed, beforeUndo, blocks, afterText, refuse =
|
|
|
227
260
|
selectAfter: result.selectAfter ?? null, // what redo selects instead
|
|
228
261
|
caret: result.caret ?? null, // where redo puts the caret when it selects nothing (tidyEmptied)
|
|
229
262
|
settle: result.settle ?? null,
|
|
263
|
+
typedInto, madeAt: Date.now(), // the block made for what is typed, whose first run of typing is part of this step (closeTyping)
|
|
230
264
|
});
|
|
231
265
|
result.touched.forEach((node) => lastKnown.set(node, ownHTML(node)));
|
|
232
266
|
note("history", "change");
|
|
@@ -381,6 +415,7 @@ export function createHistory({ changed, beforeUndo, blocks, afterText, refuse =
|
|
|
381
415
|
sourceStep,
|
|
382
416
|
fold,
|
|
383
417
|
drop,
|
|
418
|
+
rekeyed,
|
|
384
419
|
closeTyping,
|
|
385
420
|
struct,
|
|
386
421
|
finish,
|