@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,177 @@
|
|
|
1
|
+
// How a board's cards move while they are edited (./index.mjs; docs/render.md "Its cards edited"), the user's
|
|
2
|
+
// word of 2026-11-09: as smooth as the widgets of an iPhone's home screen, nothing that jumps or stutters.
|
|
3
|
+
//
|
|
4
|
+
// - glide(): the cards a change of the layout moves (a draft while a card is dragged or resized, a drop, an
|
|
5
|
+
// undo, 大小 ›) glide from where they were seen to where the layout now puts them (FLIP: their box before
|
|
6
|
+
// and after, a transform from the one to the other run to none) on a spring's ease (spring: a little
|
|
7
|
+
// less than critically damped, its overshoot under 2%), GLIDE ms; a card whose size changed glides its
|
|
8
|
+
// width and height too. A card already gliding to where the layout still puts it is left to go on; one
|
|
9
|
+
// the change sends elsewhere starts again from where it is seen then, so a target that changes under a
|
|
10
|
+
// drag never makes a card jump (interruptible).
|
|
11
|
+
// - createSettle(): a held card's place (or a resized card's size), axis by axis: the pointer's, or within
|
|
12
|
+
// `snap` px of the cells (or the size) a drop gives, those; where that changes (the card comes within the
|
|
13
|
+
// snap or leaves it, or the cells it stands on move) it settles from where it was carried to the new
|
|
14
|
+
// place in SETTLE ms on the same spring, the pointer's own motion never delayed.
|
|
15
|
+
// - createEdgeScroll(): near the window's top or bottom edge a gesture scrolls the page, timed by the frames'
|
|
16
|
+
// clock (not by the pointer's events): within BAND px of the edge, faster as the pointer is nearer it (the
|
|
17
|
+
// square of how far into the band, past the edge the most), FASTEST px a second at the most (12 a frame
|
|
18
|
+
// at 60 frames a second), and growing from nothing over RAMP ms once the pointer comes into the band, so
|
|
19
|
+
// that a card picked up near the edge does not set the page running.
|
|
20
|
+
// - prefers-reduced-motion: no glide and no settling (the layout and the snap at once); the scroll as it is.
|
|
21
|
+
|
|
22
|
+
export const GLIDE = 280; // ms a card glides to where a layout puts it
|
|
23
|
+
export const SETTLE = 180; // ms a held (or resized) card settles on what it snaps to, or comes off it
|
|
24
|
+
export const BAND = 64; // px from the window's top or bottom edge within which a gesture scrolls the page
|
|
25
|
+
export const FASTEST = 720; // px a second the page scrolls at the most
|
|
26
|
+
export const RAMP = 320; // ms over which that speed grows from nothing once the pointer is in the band
|
|
27
|
+
|
|
28
|
+
export const reduced = () => typeof matchMedia === "function" && matchMedia("(prefers-reduced-motion: reduce)").matches;
|
|
29
|
+
|
|
30
|
+
// The step response of a spring (damping ZETA, settled within 0.2% at t = 1): 0 at 0, 1 at 1, still at both
|
|
31
|
+
// ends, a crest of under 2% past 1 at t ≈ 0.65.
|
|
32
|
+
const ZETA = 0.8;
|
|
33
|
+
const OMEGA = 6.4 / ZETA;
|
|
34
|
+
const DAMPED = OMEGA * Math.sqrt(1 - ZETA * ZETA);
|
|
35
|
+
export function spring(t) {
|
|
36
|
+
if (t <= 0) return 0;
|
|
37
|
+
if (t >= 1) return 1;
|
|
38
|
+
return 1 - Math.exp(-ZETA * OMEGA * t) * (Math.cos(DAMPED * t) + ((ZETA * OMEGA) / DAMPED) * Math.sin(DAMPED * t));
|
|
39
|
+
}
|
|
40
|
+
// The same as an easing a Web Animation takes (CSS linear() of 40 points), else a close cubic Bézier.
|
|
41
|
+
const EASE = (() => {
|
|
42
|
+
const points = Array.from({ length: 41 }, (_, index) => Math.round(spring(index / 40) * 10000) / 10000).join(", ");
|
|
43
|
+
const curve = `linear(${points})`;
|
|
44
|
+
return typeof CSS !== "undefined" && CSS.supports?.("transition-timing-function", curve) ? curve : "cubic-bezier(.2, .9, .25, 1)";
|
|
45
|
+
})();
|
|
46
|
+
|
|
47
|
+
const running = new WeakMap(); // a card -> its glide under way
|
|
48
|
+
// Where the kit's board script draws a card now: its cells as the CSS takes them (the board's row skip in).
|
|
49
|
+
const keyOf = (card) => ["x", "y", "w", "h"].map((name) => card.style.getPropertyValue(`--gallery-${name}`)).join();
|
|
50
|
+
|
|
51
|
+
/** Whether a card is gliding now. */
|
|
52
|
+
export const isGliding = (card) => running.has(card);
|
|
53
|
+
|
|
54
|
+
/** A card's glide stopped where it is (a gesture takes it up): it stands where the layout puts it. */
|
|
55
|
+
export function stopGlide(card) {
|
|
56
|
+
running.get(card)?.cancel();
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
/**
|
|
60
|
+
* `change()` run (it lays the board out at once: DocBoard.draft or .layout), and each of `cards` it moves
|
|
61
|
+
* glided from where it was seen to its new place. `still`: a card left out (the one a gesture holds, which
|
|
62
|
+
* follows the pointer); `lift`: a card kept over the others while it glides (data-ge-landing: one let go);
|
|
63
|
+
* `settled()`: run once every glide this started has ended (at once where none started). Gives what change() gave.
|
|
64
|
+
*/
|
|
65
|
+
export function glide(cards, change, { still = null, lift = null, duration = GLIDE, settled = null } = {}) {
|
|
66
|
+
if (reduced()) {
|
|
67
|
+
const result = change();
|
|
68
|
+
settled?.();
|
|
69
|
+
return result;
|
|
70
|
+
}
|
|
71
|
+
const started = [];
|
|
72
|
+
const before = cards.filter((card) => card !== still).map((card) => ({ card, key: keyOf(card), box: card.getBoundingClientRect() }));
|
|
73
|
+
const result = change();
|
|
74
|
+
for (const { card, key, box } of before) {
|
|
75
|
+
if (!card.isConnected) continue;
|
|
76
|
+
const going = running.get(card);
|
|
77
|
+
if (going && keyOf(card) === key) continue; // on its way to where it still goes
|
|
78
|
+
going?.cancel();
|
|
79
|
+
const now = card.getBoundingClientRect();
|
|
80
|
+
const dx = box.left - now.left;
|
|
81
|
+
const dy = box.top - now.top;
|
|
82
|
+
const sized = Math.abs(box.width - now.width) > 0.5 || Math.abs(box.height - now.height) > 0.5;
|
|
83
|
+
if (Math.abs(dx) < 0.5 && Math.abs(dy) < 0.5 && !sized) continue;
|
|
84
|
+
const from = { transform: `translate(${dx}px, ${dy}px)` };
|
|
85
|
+
const to = { transform: "translate(0px, 0px)" };
|
|
86
|
+
if (sized) {
|
|
87
|
+
Object.assign(from, { width: `${box.width}px`, height: `${box.height}px` });
|
|
88
|
+
Object.assign(to, { width: `${now.width}px`, height: `${now.height}px` });
|
|
89
|
+
}
|
|
90
|
+
const animation = card.animate([from, to], { duration, easing: EASE });
|
|
91
|
+
running.set(card, animation);
|
|
92
|
+
if (card === lift) card.setAttribute("data-ge-landing", "");
|
|
93
|
+
const end = () => {
|
|
94
|
+
if (running.get(card) !== animation) return;
|
|
95
|
+
running.delete(card);
|
|
96
|
+
card.removeAttribute("data-ge-landing");
|
|
97
|
+
};
|
|
98
|
+
animation.addEventListener("finish", end);
|
|
99
|
+
animation.addEventListener("cancel", end);
|
|
100
|
+
started.push(animation.finished.catch(() => {}));
|
|
101
|
+
}
|
|
102
|
+
if (settled) {
|
|
103
|
+
if (started.length) Promise.all(started).then(settled);
|
|
104
|
+
else settled();
|
|
105
|
+
}
|
|
106
|
+
return result;
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
/**
|
|
110
|
+
* A held card's place, or a resized card's size, axis by axis (`name`: "x", "y", "w", "h"): at(name, raw,
|
|
111
|
+
* target, time) gives what is drawn for the pointer's `raw` and the `target` a drop gives (the cells' place
|
|
112
|
+
* or size, px): the target within `snap` px of it, else raw; a change of which (or of the target while on
|
|
113
|
+
* it) settles from where the card was carried, in `duration` ms. gliding(): whether any axis still settles.
|
|
114
|
+
*/
|
|
115
|
+
export function createSettle(snap, duration = SETTLE) {
|
|
116
|
+
const axes = new Map();
|
|
117
|
+
return {
|
|
118
|
+
at(name, raw, target, time) {
|
|
119
|
+
const on = Math.abs(raw - target) <= snap;
|
|
120
|
+
const want = on ? target : raw;
|
|
121
|
+
const axis = axes.get(name);
|
|
122
|
+
if (!axis) {
|
|
123
|
+
axes.set(name, { raw, target, on, shown: want, glide: null });
|
|
124
|
+
return want;
|
|
125
|
+
}
|
|
126
|
+
// Where it would be had it gone with the pointer since the last time: what a settling starts from.
|
|
127
|
+
const carried = axis.shown + (raw - axis.raw);
|
|
128
|
+
if (on !== axis.on || (on && target !== axis.target)) axis.glide = reduced() ? null : { offset: carried - want, start: time };
|
|
129
|
+
Object.assign(axis, { raw, target, on });
|
|
130
|
+
let shown = want;
|
|
131
|
+
if (axis.glide) {
|
|
132
|
+
const progress = (time - axis.glide.start) / duration;
|
|
133
|
+
if (progress >= 1) axis.glide = null;
|
|
134
|
+
else shown = want + axis.glide.offset * (1 - spring(progress));
|
|
135
|
+
}
|
|
136
|
+
axis.shown = shown;
|
|
137
|
+
return shown;
|
|
138
|
+
},
|
|
139
|
+
gliding: () => [...axes.values()].some((axis) => axis.glide !== null),
|
|
140
|
+
};
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
/**
|
|
144
|
+
* The page scrolled near the window's edge while a gesture lasts: frame(y, time) once a frame (the pointer's
|
|
145
|
+
* y in the window, the frame's time), whether the page moved; stop() as the gesture ends.
|
|
146
|
+
*/
|
|
147
|
+
export function createEdgeScroll({ band = BAND, fastest = FASTEST, ramp = RAMP } = {}) {
|
|
148
|
+
let since = null; // when the pointer came into the band
|
|
149
|
+
let last = null; // the last frame's time
|
|
150
|
+
let carry = 0; // px asked and not yet scrolled (a frame's share is seldom whole)
|
|
151
|
+
return {
|
|
152
|
+
frame(y, time) {
|
|
153
|
+
const step = last === null ? 0 : Math.min(34, Math.max(0, time - last)); // a stalled frame scrolls no more than two
|
|
154
|
+
last = time;
|
|
155
|
+
const into = y < band ? -(band - y) / band : y > innerHeight - band ? (y - (innerHeight - band)) / band : 0;
|
|
156
|
+
if (into === 0) {
|
|
157
|
+
since = null;
|
|
158
|
+
carry = 0;
|
|
159
|
+
return false;
|
|
160
|
+
}
|
|
161
|
+
since ??= time;
|
|
162
|
+
const depth = Math.min(1, Math.abs(into));
|
|
163
|
+
carry += Math.sign(into) * fastest * depth * depth * Math.min(1, (time - since) / ramp) * (step / 1000);
|
|
164
|
+
const whole = Math.trunc(carry);
|
|
165
|
+
if (!whole) return false;
|
|
166
|
+
carry -= whole;
|
|
167
|
+
const was = scrollY;
|
|
168
|
+
scrollBy(0, whole);
|
|
169
|
+
return scrollY !== was;
|
|
170
|
+
},
|
|
171
|
+
stop() {
|
|
172
|
+
since = null;
|
|
173
|
+
last = null;
|
|
174
|
+
carry = 0;
|
|
175
|
+
},
|
|
176
|
+
};
|
|
177
|
+
}
|
|
@@ -0,0 +1,210 @@
|
|
|
1
|
+
import { Z } from "../../../shared/layers.mjs";
|
|
2
|
+
import { language, t } from "../../../shared/i18n/index.mjs";
|
|
3
|
+
import { createMenu } from "../menu.mjs";
|
|
4
|
+
import { placeBox } from "../placement.mjs";
|
|
5
|
+
import { addStyle, button, element, mount } from "../ui.mjs";
|
|
6
|
+
|
|
7
|
+
// A card's 设置… (docs/render.md "A custom page"): a small form of the fields its block's manifest
|
|
8
|
+
// lists (`settings`: text, number, select, date, switch, document), Notion's popup look (the editor's
|
|
9
|
+
// palette, look.mjs), standing under the card's grip (its right edge at the grip's). What it shows is what the card's settings part holds,
|
|
10
|
+
// each field its manifest's default where it holds none; 保存 (or Enter in a field) hands the values
|
|
11
|
+
// that changed to `save`, 取消, Escape or a press outside it nothing. Its buttons are the editor's flat
|
|
12
|
+
// ones (CLAUDE.md 界面): no line round either, 取消 with no fill until the pointer is on it (grey), 保存 on
|
|
13
|
+
// a pale blue fill of its own. A document is chosen from the
|
|
14
|
+
// workspace's documents by title (the workbench's outline: GET /__gallery/workspace/outline, its web
|
|
15
|
+
// links no documents), the slug what is kept. A choice from a list (select, document) is a field that
|
|
16
|
+
// opens the editor's own menu card under it (menu.mjs: rows, the chosen one checked, ↑/↓ Enter Escape from
|
|
17
|
+
// the field), a choice of the caller's (type "choice", `choices`: [[value, words]], what a document block adds
|
|
18
|
+
// to its fields: the table a view reads) too, not a native <select>: the page cannot style that one's popup, which a browser draws in
|
|
19
|
+
// the system's colours (a white list with pale words in a dark page, the user's picture of 2026-11-09).
|
|
20
|
+
// While the form stands, the page is not shown again under it (the board's idle).
|
|
21
|
+
|
|
22
|
+
const STYLE = `
|
|
23
|
+
.ge-board-form { position: fixed; left: 0; top: 0; z-index: ${Z.menu}; box-sizing: border-box; width: 300px; max-height: calc(100vh - 24px); overflow-y: auto; padding: 12px 12px 10px;
|
|
24
|
+
border-radius: 10px; background: var(--ge-bg); color: var(--ge-tx); box-shadow: var(--ge-shadow-pop);
|
|
25
|
+
font: 14px/1.4 ui-sans-serif, -apple-system, BlinkMacSystemFont, "Segoe UI Variable Display", "Segoe UI", Helvetica, "PingFang SC", "Microsoft YaHei", Arial, sans-serif; }
|
|
26
|
+
.ge-board-form-title { display: flex; align-items: baseline; gap: 8px; margin: 0 0 10px; font-size: 14px; font-weight: 600; }
|
|
27
|
+
.ge-board-form-title small { min-width: 0; overflow: hidden; color: var(--ge-tx3); font-size: 12px; font-weight: 400; text-overflow: ellipsis; white-space: nowrap; }
|
|
28
|
+
.ge-board-field { display: block; margin: 0 0 10px; }
|
|
29
|
+
.ge-board-field > span { display: block; margin: 0 0 4px; color: var(--ge-tx2); font-size: 12px; }
|
|
30
|
+
.ge-board-field :is(input, .ge-board-pick) { box-sizing: border-box; width: 100%; height: 28px; margin: 0; padding: 0 8px; border: 0; border-radius: 6px; outline: none;
|
|
31
|
+
background: var(--ge-field); color: var(--ge-tx); font: inherit; box-shadow: inset 0 0 0 1px var(--ge-edge); }
|
|
32
|
+
.ge-board-field :is(input, .ge-board-pick):focus, .ge-board-pick[aria-expanded="true"] { box-shadow: inset 0 0 0 1px var(--ge-focus), 0 0 0 2px var(--ge-halo); }
|
|
33
|
+
.ge-board-pick { display: flex; align-items: center; gap: 6px; text-align: left; cursor: pointer; }
|
|
34
|
+
.ge-board-pick-text { flex: 1; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
|
|
35
|
+
.ge-board-pick svg { flex: none; display: block; width: 16px; height: 16px; fill: none; stroke: var(--ge-tx3); stroke-width: 1.5; stroke-linecap: round; stroke-linejoin: round; }
|
|
36
|
+
.ge-board-switch { display: flex; align-items: center; justify-content: space-between; gap: 12px; margin: 0 0 10px; }
|
|
37
|
+
.ge-board-switch > span { color: var(--ge-tx); font-size: 14px; }
|
|
38
|
+
.ge-board-switch button { position: relative; flex: none; width: 30px; height: 18px; padding: 0; border: 0; border-radius: 9px; background: var(--ge-line-strong); cursor: pointer; transition: background .12s; }
|
|
39
|
+
.ge-board-switch button::after { content: ""; position: absolute; top: 2px; left: 2px; width: 14px; height: 14px; border-radius: 50%; background: #fff; box-shadow: 0 1px 2px rgb(15 15 15 / 20%); transition: transform .12s; }
|
|
40
|
+
.ge-board-switch button[aria-checked="true"] { background: var(--ge-accent); }
|
|
41
|
+
.ge-board-switch button[aria-checked="true"]::after { transform: translateX(12px); }
|
|
42
|
+
.ge-board-switch button:focus-visible { outline: 2px solid var(--ge-halo); }
|
|
43
|
+
.ge-board-form-foot { display: flex; justify-content: flex-end; gap: 8px; margin-top: 4px; }
|
|
44
|
+
.ge-board-form-foot button { height: 28px; padding: 0 12px; border: 0; border-radius: 6px; background: transparent; color: var(--ge-tx); font: inherit; cursor: pointer; }
|
|
45
|
+
.ge-board-form-foot button:hover { background: var(--ge-hover); }
|
|
46
|
+
.ge-board-form-foot button[data-primary] { background: var(--ge-btn-primary); color: var(--ge-btn-primary-text); }
|
|
47
|
+
.ge-board-form-foot button[data-primary]:hover { background: var(--ge-btn-primary-hover); }
|
|
48
|
+
.ge-board-form-foot button:focus-visible { outline: 2px solid var(--ge-halo); }
|
|
49
|
+
@media (prefers-reduced-motion: reduce) { .ge-board-switch :is(button, button::after) { transition: none; } }
|
|
50
|
+
`;
|
|
51
|
+
|
|
52
|
+
const CHEVRON = '<svg viewBox="0 0 16 16" aria-hidden="true"><path d="m4 6 4 4 4-4"/></svg>';
|
|
53
|
+
const said = (words) => (typeof words === "string" ? words : words?.[language] ?? words?.zh ?? words?.en ?? "");
|
|
54
|
+
let shown = null; // the form standing now: { node, close }
|
|
55
|
+
|
|
56
|
+
/** Whether the form stands now. */
|
|
57
|
+
export const formOpen = () => shown !== null;
|
|
58
|
+
|
|
59
|
+
/** The workspace's documents, by title: [{ slug, title }] (none where the outline cannot be read). */
|
|
60
|
+
async function documents() {
|
|
61
|
+
try {
|
|
62
|
+
const answer = await (await fetch("/__gallery/workspace/outline")).json();
|
|
63
|
+
return Object.values(answer.reports ?? {}).filter((report) => !report.instructions && report.kind !== "link").map(({ slug, title }) => ({ slug, title: title || slug }))
|
|
64
|
+
.sort((a, b) => a.title.localeCompare(b.title, "zh-CN"));
|
|
65
|
+
} catch {
|
|
66
|
+
return [];
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
/**
|
|
71
|
+
* The form for a card: `fields`, its manifest's settings; `values`, what its settings part holds;
|
|
72
|
+
* `name`, its block's name; `anchor`, the rect it stands by; `save(changed)`, the values that changed
|
|
73
|
+
* by key. Closes another that stands.
|
|
74
|
+
*/
|
|
75
|
+
export async function openSettings({ fields, values, name, anchor, save }) {
|
|
76
|
+
addStyle(STYLE);
|
|
77
|
+
shown?.close();
|
|
78
|
+
const kinds = new Map();
|
|
79
|
+
const pick = createMenu(); // the list of the field being chosen from (one at a time)
|
|
80
|
+
let picking = null; // the field it stands under
|
|
81
|
+
const node = element("form", { class: "ge-board-form", role: "dialog", "aria-label": t("卡片设置"), novalidate: "" });
|
|
82
|
+
node.append(element("div", { class: "ge-board-form-title" }, element("span", { text: t("设置") }), element("small", { text: said(name) })));
|
|
83
|
+
const listed = fields.some((field) => field.type === "document") ? await documents() : [];
|
|
84
|
+
const now = (field) => (Object.hasOwn(values ?? {}, field.key) ? values[field.key] : field.default);
|
|
85
|
+
for (const field of fields) {
|
|
86
|
+
const label = said(field.label) || field.key;
|
|
87
|
+
const value = now(field);
|
|
88
|
+
if (field.type === "switch") {
|
|
89
|
+
const toggle = element("button", { type: "button", role: "switch", "aria-checked": String(value === true), "aria-label": label, "data-key": field.key });
|
|
90
|
+
toggle.addEventListener("click", () => toggle.setAttribute("aria-checked", String(toggle.getAttribute("aria-checked") !== "true")));
|
|
91
|
+
node.append(element("div", { class: "ge-board-switch" }, element("span", { text: label }), toggle));
|
|
92
|
+
kinds.set(field.key, { field, read: () => toggle.getAttribute("aria-checked") === "true" });
|
|
93
|
+
continue;
|
|
94
|
+
}
|
|
95
|
+
let control;
|
|
96
|
+
const choice = field.type === "select" || field.type === "document" || field.type === "choice"; // chosen from a list
|
|
97
|
+
if (choice) {
|
|
98
|
+
const options = field.type === "select" ? field.options.map((option) => [String(option), String(option)]) : field.type === "choice" ? field.choices : [["", t("(未选择)")], ...listed.map(({ slug, title }) => [slug, title])];
|
|
99
|
+
if (field.type === "document" && value && !listed.some(({ slug }) => slug === value)) options.push([String(value), String(value)]);
|
|
100
|
+
const text = element("span", { class: "ge-board-pick-text" });
|
|
101
|
+
control = element("button", { type: "button", class: "ge-board-pick", "data-key": field.key, "aria-haspopup": "menu", "aria-expanded": "false" }, text, element("span", { html: CHEVRON }));
|
|
102
|
+
// What the field holds is its `value` (the key of an option), shown as the option's words.
|
|
103
|
+
const show = (key) => {
|
|
104
|
+
control.value = key;
|
|
105
|
+
text.textContent = options.find(([option]) => option === key)?.[1] ?? key;
|
|
106
|
+
};
|
|
107
|
+
show(value === undefined || value === null ? (field.type === "select" ? String(field.options[0]) : "") : String(value));
|
|
108
|
+
const open = () => {
|
|
109
|
+
const wide = control.getBoundingClientRect();
|
|
110
|
+
picking = control;
|
|
111
|
+
control.setAttribute("aria-expanded", "true");
|
|
112
|
+
pick.open(options.map(([key, words]) => ({ label: words, selected: key === control.value, run: () => show(key) })), wide, {
|
|
113
|
+
label, width: Math.round(wide.width), icons: false, height: 280,
|
|
114
|
+
onClose: () => { if (picking === control) picking = null; control.setAttribute("aria-expanded", "false"); },
|
|
115
|
+
});
|
|
116
|
+
// The chosen row highlighted where there is one (the first otherwise: the menu's own).
|
|
117
|
+
const chosen = options.findIndex(([key]) => key === control.value);
|
|
118
|
+
for (let step = 0; step < Math.max(0, chosen); step++) pick.move(1);
|
|
119
|
+
};
|
|
120
|
+
control.addEventListener("click", () => { if (picking === control) pick.close(); else open(); });
|
|
121
|
+
control.addEventListener("keydown", (event) => {
|
|
122
|
+
if (event.isComposing || event.keyCode === 229) return;
|
|
123
|
+
if (picking !== control) {
|
|
124
|
+
if (event.key === "ArrowDown" || event.key === "ArrowUp") {
|
|
125
|
+
event.preventDefault();
|
|
126
|
+
open();
|
|
127
|
+
}
|
|
128
|
+
return;
|
|
129
|
+
}
|
|
130
|
+
if (pick.arrow(event)) event.preventDefault();
|
|
131
|
+
else if (event.key === "Enter" || event.key === " ") {
|
|
132
|
+
event.preventDefault();
|
|
133
|
+
pick.choose();
|
|
134
|
+
} else if (event.key === "Escape") {
|
|
135
|
+
event.preventDefault();
|
|
136
|
+
event.stopPropagation(); // the list closes; the form stays
|
|
137
|
+
pick.close();
|
|
138
|
+
} else if (event.key === "Tab") pick.close();
|
|
139
|
+
});
|
|
140
|
+
} else {
|
|
141
|
+
control = element("input", { type: field.type === "number" ? "number" : field.type === "date" ? "date" : "text", "data-key": field.key, autocomplete: "off" });
|
|
142
|
+
control.value = value === undefined || value === null ? "" : String(value);
|
|
143
|
+
}
|
|
144
|
+
// A field to choose from is no <label> (a click on its words would open its list): its words name it by aria-labelledby.
|
|
145
|
+
const words = element("span", { text: label });
|
|
146
|
+
if (choice) {
|
|
147
|
+
words.id = `ge-board-label-${field.key}`;
|
|
148
|
+
control.setAttribute("aria-labelledby", words.id);
|
|
149
|
+
}
|
|
150
|
+
node.append(element(choice ? "div" : "label", { class: "ge-board-field" }, words, control));
|
|
151
|
+
kinds.set(field.key, {
|
|
152
|
+
field,
|
|
153
|
+
read: () => {
|
|
154
|
+
if (field.type === "number") return control.value.trim() === "" ? null : Number(control.value);
|
|
155
|
+
if (field.type === "select") return field.options.find((option) => String(option) === control.value) ?? field.options[0];
|
|
156
|
+
return control.value;
|
|
157
|
+
},
|
|
158
|
+
});
|
|
159
|
+
}
|
|
160
|
+
const close = () => {
|
|
161
|
+
if (shown?.node !== node) return;
|
|
162
|
+
shown = null;
|
|
163
|
+
pick.close();
|
|
164
|
+
node.remove();
|
|
165
|
+
removeEventListener("pointerdown", outside, true);
|
|
166
|
+
};
|
|
167
|
+
// What a field showed as it opened, as it reads it back (a field the part holds nothing of shows its default, or nothing).
|
|
168
|
+
const shownAt = (field) => now(field) ?? (field.type === "switch" ? false : field.type === "select" ? field.options[0] : field.type === "number" ? null : "");
|
|
169
|
+
// Only what the reader changed goes: a field left as it showed stays as the part holds it (its default unwritten).
|
|
170
|
+
const done = () => {
|
|
171
|
+
const changed = {};
|
|
172
|
+
for (const [key, { field, read }] of kinds) {
|
|
173
|
+
const value = read();
|
|
174
|
+
if (field.type === "number" && value !== null && !Number.isFinite(value)) continue;
|
|
175
|
+
if (JSON.stringify(value) !== JSON.stringify(shownAt(field))) changed[key] = value;
|
|
176
|
+
}
|
|
177
|
+
close();
|
|
178
|
+
if (Object.keys(changed).length) save(changed);
|
|
179
|
+
};
|
|
180
|
+
const outside = (event) => {
|
|
181
|
+
if (!node.contains(event.target) && !pick.contains(event.target)) close();
|
|
182
|
+
};
|
|
183
|
+
node.addEventListener("submit", (event) => {
|
|
184
|
+
event.preventDefault();
|
|
185
|
+
done();
|
|
186
|
+
});
|
|
187
|
+
node.addEventListener("keydown", (event) => {
|
|
188
|
+
if (event.isComposing || event.keyCode === 229) return;
|
|
189
|
+
if (event.key === "Escape") {
|
|
190
|
+
event.preventDefault();
|
|
191
|
+
event.stopPropagation();
|
|
192
|
+
close();
|
|
193
|
+
} else if (event.key === "Enter" && event.target.localName === "input") {
|
|
194
|
+
event.preventDefault();
|
|
195
|
+
done();
|
|
196
|
+
}
|
|
197
|
+
});
|
|
198
|
+
node.append(element("div", { class: "ge-board-form-foot" }, button(t("取消"), close), element("button", { type: "submit", "data-primary": "", text: t("保存") })));
|
|
199
|
+
mount(node);
|
|
200
|
+
const { left, top } = placeBox(anchor, { width: node.offsetWidth, height: node.offsetHeight }, { placement: "bottom", align: "end", gap: 6 });
|
|
201
|
+
node.style.left = `${Math.round(left)}px`;
|
|
202
|
+
node.style.top = `${Math.round(top)}px`;
|
|
203
|
+
shown = { node, close };
|
|
204
|
+
addEventListener("pointerdown", outside, true);
|
|
205
|
+
node.querySelector("input, .ge-board-pick, button[role=switch]")?.focus({ preventScroll: true });
|
|
206
|
+
return node;
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
/** The form taken away, whatever it holds. */
|
|
210
|
+
export const closeSettings = () => shown?.close();
|
|
@@ -105,7 +105,7 @@ export function caretAtOffset(host, offset) {
|
|
|
105
105
|
rest -= node.length;
|
|
106
106
|
last = node;
|
|
107
107
|
}
|
|
108
|
-
|
|
108
|
+
caretAt(host, last ? "end" : "start"); // past its text, or in a block with none (emptied)
|
|
109
109
|
}
|
|
110
110
|
|
|
111
111
|
/** The selection when it is non-empty and inside a single block: { host, range }, or null. */
|
|
@@ -1,13 +1,14 @@
|
|
|
1
1
|
import { t } from "../../../shared/i18n/index.mjs";
|
|
2
2
|
import { Z } from "../../../shared/layers.mjs";
|
|
3
3
|
import { PANEL_STYLE, onPanels, panelGone, panelShown } from "../panel.mjs";
|
|
4
|
-
import { addStyle,
|
|
4
|
+
import { addStyle, element, fadeIn, fadeOut, mount, textButton } from "../ui.mjs";
|
|
5
5
|
|
|
6
6
|
// The bar of the Agent's changes (docs/editor.md "Agent's changes"), Cursor's review bar: the third of
|
|
7
7
|
// the editor's bottom panels (panel.mjs), in the middle of the window's bottom, so that a notice
|
|
8
8
|
// stands above it as above the others. It says how many blocks the Agent added and changed (+) and
|
|
9
9
|
// changed and deleted (−), the numbers in the conflict card's green and red, and offers 撤回 and 确认
|
|
10
|
-
// (the primary one
|
|
10
|
+
// (the primary one: the pale blue), in the editor's one button look (look.mjs BUTTONS: no line, no fill
|
|
11
|
+
// until the pointer is on it). Reverted, it says so and offers
|
|
11
12
|
// 撤销 for UNDO_SHOWN. A conflict card at the left or the lost texts at the right reaching under it
|
|
12
13
|
// lift it 8px above them.
|
|
13
14
|
|
|
@@ -21,15 +22,6 @@ const STYLE = `
|
|
|
21
22
|
.ge-changes-count { display: inline-flex; gap: 6px; margin-right: 4px; font-variant-numeric: tabular-nums; font-weight: 500; }
|
|
22
23
|
.ge-changes-plus { color: var(--ge-diff-add-text); }
|
|
23
24
|
.ge-changes-minus { color: var(--ge-diff-del-text); }
|
|
24
|
-
/* Its buttons as the editor's floating bars' (the format bar's 转换为): no border, 6px corners, a gray under the
|
|
25
|
-
pointer, darker pressed; 确认 the primary blue (the workbench dialog's, the media menu's 嵌入链接). */
|
|
26
|
-
.ge-changes button { height: 28px; padding: 0 10px; border: 0; border-radius: 6px; background: transparent; color: inherit; font: inherit; font-weight: 500; white-space: nowrap; cursor: pointer; transition: background 20ms ease-in; }
|
|
27
|
-
.ge-changes button:hover:not(:disabled) { background: var(--ge-hover); }
|
|
28
|
-
.ge-changes button:active:not(:disabled) { background: var(--ge-press); }
|
|
29
|
-
.ge-changes button[data-primary] { background: var(--ge-accent); color: #fff; }
|
|
30
|
-
.ge-changes button[data-primary]:hover:not(:disabled) { background: var(--ge-accent-hover); }
|
|
31
|
-
.ge-changes button[data-primary]:active:not(:disabled) { background: var(--ge-accent-press); }
|
|
32
|
-
.ge-changes button:disabled { opacity: .45; cursor: default; }
|
|
33
25
|
@media print { .ge-changes { display: none; } }
|
|
34
26
|
`;
|
|
35
27
|
|
|
@@ -80,15 +72,15 @@ export function createBar({ revert, accept }) {
|
|
|
80
72
|
element("span", { class: "ge-changes-count", title: t("Agent 新增 {0} 块、改动 {1} 块、删除 {2} 块", added, changed, removed) },
|
|
81
73
|
...(plus ? [element("span", { class: "ge-changes-plus", text: `+${plus}` })] : []),
|
|
82
74
|
...(minus ? [element("span", { class: "ge-changes-minus", text: `−${minus}` })] : [])),
|
|
83
|
-
|
|
84
|
-
|
|
75
|
+
textButton(t("撤回"), revert, { title: t("撤回 Agent 的这些修改,你自己的修改会保留"), "data-action": "revert" }),
|
|
76
|
+
textButton(t("确认"), accept, { primary: true, title: t("保留这些修改,不再标出"), "data-action": "accept" }),
|
|
85
77
|
);
|
|
86
78
|
},
|
|
87
79
|
// Reverted `left` ms ago at most: 撤销 offered until UNDO_SHOWN is over.
|
|
88
80
|
reverted(left, undo) {
|
|
89
81
|
show(
|
|
90
82
|
element("span", { class: "ge-changes-what", text: t("已撤回 Agent 的修改") }),
|
|
91
|
-
|
|
83
|
+
textButton(t("撤销"), undo, { "data-action": "undo" }),
|
|
92
84
|
);
|
|
93
85
|
timer = setTimeout(() => this.hide(), Math.max(0, left));
|
|
94
86
|
},
|
|
@@ -361,7 +361,7 @@ export function createChanges({ slug, token, commits, autosave, flush, say, sess
|
|
|
361
361
|
answer = await postAnswer(ROUTE, token, { slug, action: "revert", stamp });
|
|
362
362
|
if (!answer.ok || answer.none) return false;
|
|
363
363
|
session?.set(undoKey, JSON.stringify({ undo: answer.undo, at: Date.now() }));
|
|
364
|
-
return true;
|
|
364
|
+
return answer.version || true; // the version it wrote: the page shown again on another asks what that put back
|
|
365
365
|
});
|
|
366
366
|
if (shown) return; // the page goes: the one shown again offers 撤销
|
|
367
367
|
busy = false;
|
|
@@ -381,7 +381,7 @@ export function createChanges({ slug, token, commits, autosave, flush, say, sess
|
|
|
381
381
|
let answer = null;
|
|
382
382
|
const shown = await autosave().showOwn(async () => {
|
|
383
383
|
answer = await postAnswer(ROUTE, token, { slug, action: "undo", undo: id });
|
|
384
|
-
return
|
|
384
|
+
return answer.ok ? answer.version || true : false;
|
|
385
385
|
});
|
|
386
386
|
if (shown) return;
|
|
387
387
|
busy = false;
|
|
@@ -332,7 +332,11 @@ function equationOf(el) {
|
|
|
332
332
|
return el.getAttribute(ATTR.equation) || el.getAttribute(ATTR.inlineEquation) || annotation || /^\$\$([\s\S]+?)\$\$\s*$/.exec(text)?.[1].trim() || /^\$([\s\S]+?)\$$/.exec(text)?.[1].trim();
|
|
333
333
|
}
|
|
334
334
|
|
|
335
|
-
|
|
335
|
+
// Besides Notion's: a picture in a table's cell (`pictures`) is a token of its own, PICTURE annotated
|
|
336
|
+
// ["img", its address, its alt, "", its width] (inline.mjs's pieces, the width of an <img width>), which
|
|
337
|
+
// a cell of the page shows (to-blocks.mjs richHtml).
|
|
338
|
+
const PICTURE = String.fromCodePoint(0xfffc);
|
|
339
|
+
function richTextOf(node, { stripText = false, stripSurroundingWhitespace = false, ignoreCodeBlock = false, preserveLineBreaks = false, pictures = false } = {}) {
|
|
336
340
|
const doc = node.ownerDocument;
|
|
337
341
|
if (!stripText) {
|
|
338
342
|
// Paragraphs, headings and items as lines with their bullets (the structure kept in one text).
|
|
@@ -354,17 +358,18 @@ function richTextOf(node, { stripText = false, stripSurroundingWhitespace = fals
|
|
|
354
358
|
all.push(n);
|
|
355
359
|
for (const child of n.childNodes) walk(child);
|
|
356
360
|
})(node);
|
|
357
|
-
const
|
|
361
|
+
const picture = (n) => pictures && tagOf(n) === "img" && Boolean(n.getAttribute("src"));
|
|
362
|
+
const nodes = all.filter((n) => (n.nodeType !== 3 ? (preserveLineBreaks && tagOf(n) === "br") || picture(n) : !(stripText && BLANK_LINES.test(n.data))));
|
|
358
363
|
const tokens = [];
|
|
359
364
|
const seenEquations = new Set();
|
|
360
365
|
nodes.forEach((n, i) => {
|
|
361
|
-
let text = n.nodeType === 3 ? n.data : "\n";
|
|
366
|
+
let text = n.nodeType === 3 ? n.data : picture(n) ? PICTURE : "\n";
|
|
362
367
|
if (stripText) text = text.replace(/\[ \] /g, "").replace(/\[x\] /g, "").replace(/^[-*•]\s?/g, "").replace(/(\s)+/g, "$1");
|
|
363
368
|
if (i === 0 && stripSurroundingWhitespace && !node.hasAttribute?.("confluenceTabSpaces")) text = text.trimStart();
|
|
364
369
|
text = clean(text);
|
|
365
370
|
if (i === nodes.length - 1 && stripSurroundingWhitespace) text = text.trimEnd();
|
|
366
371
|
const up = ancestors(n).filter((a) => a.nodeType === 1);
|
|
367
|
-
const annotations = [];
|
|
372
|
+
const annotations = picture(n) ? [["img", n.getAttribute("src"), n.getAttribute("alt") ?? "", "", n.getAttribute("width") ?? ""]] : [];
|
|
368
373
|
if (!stripText && up.some((a) => HEADINGS.includes(tagOf(a)))) annotations.push(["b"]);
|
|
369
374
|
if (up.some((a) => tagOf(a) === "strong")) annotations.push(["b"]);
|
|
370
375
|
if (up.some((a) => tagOf(a) === "em")) annotations.push(["i"]);
|
|
@@ -526,7 +531,8 @@ const int = (value, fallback) => {
|
|
|
526
531
|
};
|
|
527
532
|
|
|
528
533
|
// 760354 table: row and column spans spread into empty cells; a first row all th a header row, every
|
|
529
|
-
// row starting with a th a header column (both: the side with more th's).
|
|
534
|
+
// row starting with a th a header column (both: the side with more th's). Its cells' pictures kept
|
|
535
|
+
// (richTextOf `pictures`, besides Notion's).
|
|
530
536
|
function tableBlock(node) {
|
|
531
537
|
const rows = [...node.querySelectorAll("tr")].filter((row) => row.closest("table") === node);
|
|
532
538
|
let headerRow = false;
|
|
@@ -550,7 +556,7 @@ function tableBlock(node) {
|
|
|
550
556
|
while (taken[r][c]) c++;
|
|
551
557
|
const rowSpan = int(cell.getAttribute("rowspan"), 1);
|
|
552
558
|
const colSpan = int(cell.getAttribute("colspan"), 1);
|
|
553
|
-
grid[r][c] = richTextOf(cell, { stripSurroundingWhitespace: true, preserveLineBreaks: true });
|
|
559
|
+
grid[r][c] = richTextOf(cell, { stripSurroundingWhitespace: true, preserveLineBreaks: true, pictures: true });
|
|
554
560
|
taken[r][c] = true;
|
|
555
561
|
for (let dr = 0; dr < rowSpan && r + dr < rows.length; dr++) {
|
|
556
562
|
for (let dc = 0; dc < colSpan; dc++) {
|
|
@@ -716,6 +722,23 @@ function blockOf(node) {
|
|
|
716
722
|
|
|
717
723
|
const blocksOf = (nodes) => nodes.flatMap(blockOf);
|
|
718
724
|
|
|
725
|
+
/**
|
|
726
|
+
* Besides Notion's (another program's cells pasted into a table's: page/clipboard/ cellsOf): the
|
|
727
|
+
* HTML's table, when it holds one and no words outside it, as rows of rich text, its cells' as
|
|
728
|
+
* tableBlock reads them (spans spread into empty cells, pictures kept); a table of one column stays
|
|
729
|
+
* one (normalizing makes Notion's paragraphs of it). Null for anything else.
|
|
730
|
+
*/
|
|
731
|
+
export function tableRows(root, options = {}) {
|
|
732
|
+
const tables = [...root.querySelectorAll("table")].filter((table) => !table.parentElement?.closest("table"));
|
|
733
|
+
const outside = (n) => (n.nodeType === 3 ? n.data.trim() !== "" : n.nodeType === 1 && tagOf(n) !== "table" && !REMOVED.has(tagOf(n)) && [...n.childNodes].some(outside));
|
|
734
|
+
if (tables.length !== 1 || [...root.childNodes].some(outside)) return null;
|
|
735
|
+
tables[0].classList.add("simple-table"); // kept a table (firstPass)
|
|
736
|
+
normalizeHTML(root, { ...options, inline: false });
|
|
737
|
+
const table = root.querySelector("table");
|
|
738
|
+
const block = table ? tableBlock(table) : null;
|
|
739
|
+
return block ? block.children.map((row) => block.props.table_block_column_order.map((column) => row.props.cells[column] ?? [])) : null;
|
|
740
|
+
}
|
|
741
|
+
|
|
719
742
|
// ---------- entry points ----------
|
|
720
743
|
|
|
721
744
|
/** 760354 U: the HTML's blocks. */
|
|
@@ -27,8 +27,14 @@
|
|
|
27
27
|
// and a bare a@b.c (GFM's); $$…$$ amid words a display formula (annotated display too, which
|
|
28
28
|
// markdown.mjs makes a block of its own in a paragraph).
|
|
29
29
|
// Besides Notion's annotations, these three: sup (superscript), sub (subscript) and display.
|
|
30
|
+
//
|
|
31
|
+
// Yuque's Markdown (its toolbar's 复制为 Markdown, read as a whole document with `yuque`: yuque.mjs)
|
|
32
|
+
// reads two more: a formula as Yuque writes one, $ … $ with a space inside each $ (Pandoc's rule
|
|
33
|
+
// refuses those), and the colors of a <font style="color: …; background-color: …"> (or a <span> so
|
|
34
|
+
// styled) as the page's nearest (colors.mjs: Yuque's colors are meant, as Word's are).
|
|
30
35
|
|
|
31
36
|
import { addressOf } from "../../links/address.mjs";
|
|
37
|
+
import { backgroundColor, textColor } from "./colors.mjs";
|
|
32
38
|
|
|
33
39
|
const WORD = /[\p{L}\p{N}]/u;
|
|
34
40
|
const TRAILING = /[.,:;!?'")\]}>,。:;!?、)】」』]+$/u;
|
|
@@ -100,6 +106,20 @@ const attribute = (tag, name) => {
|
|
|
100
106
|
};
|
|
101
107
|
const decodeEntities = (text) => text.replace(/&(#\d{1,7}|#[xX][0-9a-fA-F]{1,6}|[A-Za-z][A-Za-z0-9]{1,31});/g, (all, name) => entity(name) ?? all);
|
|
102
108
|
|
|
109
|
+
// Yuque's Markdown: $ … $ with a space inside each $ a formula (its words trimmed), and a <font> or
|
|
110
|
+
// <span> whose style colors its words those colors, the nearest of the page's (none: its words alone).
|
|
111
|
+
const styleValue = (style, name) => new RegExp(`(?:^|;)\\s*${name}\\s*:\\s*([^;]+)`, "i").exec(style ?? "")?.[1].trim() ?? "";
|
|
112
|
+
const YUQUE_RULES = [
|
|
113
|
+
[/^\$ +([^$\n]*?[^\s$]) +\$(?!\d)/, (m) => ["⁍", ["e", m[1]], false]],
|
|
114
|
+
[/^<(font|span)\s([^<>]*)>([\s\S]*?)<\/\1\s*>/i, (m) => {
|
|
115
|
+
const style = attribute(`<${m[1]} ${m[2]}>`, "style");
|
|
116
|
+
const text = textColor(styleValue(style, "color"), { nearest: true });
|
|
117
|
+
const background = backgroundColor(styleValue(style, "background(?:-color)?"), { nearest: true });
|
|
118
|
+
const colors = [text, background].filter(Boolean).map((name) => ["h", name]);
|
|
119
|
+
return [m[3], colors.length ? colors : null, true];
|
|
120
|
+
}],
|
|
121
|
+
];
|
|
122
|
+
|
|
103
123
|
/** A picture's piece: U+FFFC annotated ["img", its address, its alt, its title]. */
|
|
104
124
|
const picture = (src, alt, title) => ["\u{FFFC}", ["img", src.replace(/^<|>$/g, ""), alt ?? "", title ?? ""], false];
|
|
105
125
|
const unquoted = (text) => (text ? text.slice(1, -1) : "");
|
|
@@ -123,6 +143,7 @@ function documentRules(doc) {
|
|
|
123
143
|
}
|
|
124
144
|
};
|
|
125
145
|
const rules = [
|
|
146
|
+
...(doc.yuque ? YUQUE_RULES : []),
|
|
126
147
|
RULES[0], RULES[1],
|
|
127
148
|
// $$ … $$ amid words: a display formula (markdown.mjs makes it a block of its own in a paragraph).
|
|
128
149
|
[/^\$\$(.+?)\$\$/, (m) => ["⁍", [["e", m[1].trim()], ["display"]], false]],
|
|
@@ -185,6 +206,17 @@ export const parseInlineMath = (text) => parseInline(text, MATH_RULES);
|
|
|
185
206
|
*/
|
|
186
207
|
export const parseInlineMarkdown = (text, doc = null) => parseInline(text, doc ? (doc.rules ??= documentRules(doc)) : RULES); // a document's made once
|
|
187
208
|
|
|
209
|
+
// A table cell's pictures, a linked one's too (its link left: the cell's picture is what it shows),
|
|
210
|
+
// ahead of Notion's rules (a paste's Markdown table: 单元格里的图片, which a cell holds).
|
|
211
|
+
const CELL_RULES = [
|
|
212
|
+
[new RegExp(String.raw`^\[!\[([^\]]*)\]${LINK_TARGET}\]${LINK_TARGET}`), (m) => picture(m[2], m[1], unquoted(m[3]))],
|
|
213
|
+
[new RegExp(String.raw`^!\[([^\]]*)\]${LINK_TARGET}`), (m) => picture(m[2], m[1], unquoted(m[3]))],
|
|
214
|
+
...RULES,
|
|
215
|
+
];
|
|
216
|
+
|
|
217
|
+
/** A pasted Markdown table's cell as rich text: Notion's rules, and its pictures  (inline.mjs's picture pieces). */
|
|
218
|
+
export const parseCellMarkdown = (text) => parseInline(text, CELL_RULES);
|
|
219
|
+
|
|
188
220
|
/** HTML entities in text as their characters (& —), one it does not know as written. */
|
|
189
221
|
export { decodeEntities };
|
|
190
222
|
|