@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
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
import { t } from "../../shared/i18n/index.mjs";
|
|
2
2
|
import { addressOn, elsewhere, fromFile, isPageAddress, mayBePage, pageAddress, workbenchHash } from "../../shared/page-address.mjs";
|
|
3
3
|
import { inTrash, linkedPages, pageLinks } from "../../shared/page-links.mjs";
|
|
4
|
-
import {
|
|
4
|
+
import { entryOfKey } from "../../shared/extension-sidebar.mjs";
|
|
5
|
+
import { SHELL, tell } from "./present-shell.mjs";
|
|
5
6
|
|
|
6
7
|
// The links of a page shown in 演示视图 (?present: src/server/routes.mjs), which has no editor and whose
|
|
7
8
|
// frame the presentation holds (src/workbench/app/features/present/). A link to a document or a block
|
|
@@ -13,7 +14,10 @@ import { PROTOCOL, VERSION } from "../../shared/session.mjs";
|
|
|
13
14
|
// it is, with a word through it (the workbench's notice), and on another port what the list does not
|
|
14
15
|
// hold (addressOn) is another program's, a web address like any. What the kit or the browser does with
|
|
15
16
|
// a click stays theirs: an anchor, a link to save, a link of a target of its own, any click with a key
|
|
16
|
-
// held.
|
|
17
|
+
// held. A workbench's address that names a web link of the sidebar, or an entry of an extension's column
|
|
18
|
+
// (#~<id>/<entry id>, one with an address), is a web address to the presentation: its page goes to a new
|
|
19
|
+
// tab; an entry the list does not hold, or one with no address, is said gone as a document is. (In a draft's presentation, a frame
|
|
20
|
+
// of its workspace's own server, the word goes to the workbench of another origin and a link keeps it around the page: present-shell.mjs.)
|
|
17
21
|
|
|
18
22
|
const own = pageAddress(location.href)?.slug ?? null;
|
|
19
23
|
const openTab = (address) => window.open(address, "_blank", "noopener");
|
|
@@ -21,20 +25,26 @@ const read = (route) => fetch(`/__gallery/workspace/${route}`).then((answer) =>
|
|
|
21
25
|
|
|
22
26
|
function go({ slug, block }) {
|
|
23
27
|
const fragment = block ? `#${encodeURIComponent(block)}` : "";
|
|
24
|
-
if (slug !== own) location.assign(`/generated/${slug}.html?present${fragment}`);
|
|
28
|
+
if (slug !== own) location.assign(`/generated/${slug}.html?present${SHELL ? `&shell=${encodeURIComponent(SHELL)}` : ""}${fragment}`); // a draft's presentation keeps the workbench around it (present-shell.mjs)
|
|
25
29
|
else if (block) dispatchEvent(new CustomEvent("doc-jump-request", { detail: { hash: fragment } })); // the kit's jump, a step of the history as a link #<block id> is
|
|
26
30
|
}
|
|
27
31
|
|
|
28
32
|
function sayGone(name, { trash = [] } = {}) {
|
|
29
33
|
const text = inTrash(trash, name) ? t("这个页面已删除。") : t("没有找到这个页面。");
|
|
30
|
-
|
|
34
|
+
tell("notice", { text });
|
|
31
35
|
}
|
|
32
36
|
|
|
33
37
|
async function follow(address) {
|
|
34
38
|
if (!mayBePage(address)) return void openTab(address);
|
|
35
39
|
const listed = await read("outline");
|
|
36
40
|
const place = addressOn(address, listed?.reports ? pageLinks(linkedPages(listed.reports)) : null, location.origin);
|
|
37
|
-
|
|
41
|
+
const web = place && listed?.reports?.[place.slug]?.kind === "link" ? listed.reports[place.slug] : null;
|
|
42
|
+
const entry = !place && !elsewhere(address, location.origin) ? entryOfKey(listed?.extensions, workbenchHash(address) ?? "") : null;
|
|
43
|
+
if (web) {
|
|
44
|
+
if (/^https?:/.test(web.url ?? "")) openTab(web.url);
|
|
45
|
+
else sayGone(web.slug, listed);
|
|
46
|
+
} else if (place) go(place);
|
|
47
|
+
else if (entry?.url) openTab(entry.url);
|
|
38
48
|
else if (isPageAddress(address) && !elsewhere(address, location.origin)) sayGone(pageAddress(address)?.slug ?? workbenchHash(address), listed ?? undefined);
|
|
39
49
|
else openTab(address);
|
|
40
50
|
}
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
import { pageAddress } from "../../shared/page-address.mjs";
|
|
2
|
+
import { KEEPS_KEYS, stepSection } from "../../shared/present-step.mjs";
|
|
3
|
+
import { PROTOCOL, PROTOCOLS, VERSION } from "../../shared/session.mjs";
|
|
4
|
+
|
|
5
|
+
// What a page shown in 演示视图 (?present: src/server/routes.mjs, no editor) says to the presentation around it and
|
|
6
|
+
// hears from it. The presentation of a document of this workspace is a frame of the same origin, which it reaches into (its
|
|
7
|
+
// scroll, its keys, its theme); that of a draft of another workspace (docs/workbench.md "Drafts of other workspaces") is a frame
|
|
8
|
+
// of that workspace's server, named by the page's address (?shell=<the workbench's origin>) as the editor's page names it
|
|
9
|
+
// (session.mjs): this page then asks its own server whether that is a Gallery server of this computer (GET
|
|
10
|
+
// /__gallery/workspace/shell) and talks to it alone once it is, holding what it says until then; one that is not hears nothing.
|
|
11
|
+
// It tells where the page is scrolled (`present-view`: { x, y }, with `ready` once the page can be spoken to) and the keys pressed
|
|
12
|
+
// in it that are the presentation's (`present-key`: { key, ctrlKey, metaKey, altKey, kept (a control holds the key), prevented }),
|
|
13
|
+
// and does what it is asked: `theme` (the workbench's, light or dark), `go-section` (上一节 / 下一节) and `scroll` ({ left, top }: the wheel). Every message is the session
|
|
14
|
+
// protocol's envelope (src/shared/session.mjs).
|
|
15
|
+
|
|
16
|
+
/** The origin of a workbench of another origin showing this page (?shell=<origin>), or null: this one's. */
|
|
17
|
+
export const SHELL = (() => {
|
|
18
|
+
const named = new URLSearchParams(location.search).get("shell");
|
|
19
|
+
return named && named !== location.origin ? named : null;
|
|
20
|
+
})();
|
|
21
|
+
|
|
22
|
+
const vouched = (origin) => fetch(`/__gallery/workspace/shell?origin=${encodeURIComponent(origin)}`, { cache: "no-store" })
|
|
23
|
+
.then((answer) => answer.json()).then((answer) => answer?.shell === true, () => false);
|
|
24
|
+
|
|
25
|
+
let parentOrigin = SHELL ? null : location.origin;
|
|
26
|
+
let held = SHELL ? [] : null;
|
|
27
|
+
|
|
28
|
+
/** Tell the presentation around the page (`window.parent`) something; held until its origin is vouched for, dropped when it is not. */
|
|
29
|
+
export function tell(type, fields = {}) {
|
|
30
|
+
if (window.parent === window) return;
|
|
31
|
+
if (held) return void held.push([type, fields]);
|
|
32
|
+
if (!parentOrigin) return;
|
|
33
|
+
window.parent.postMessage({ protocol: PROTOCOL, v: VERSION, type, slug: pageAddress(location.href)?.slug ?? "", ...fields }, parentOrigin);
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
function bridge() {
|
|
37
|
+
let frame = 0;
|
|
38
|
+
const view = (ready = false) => tell("present-view", { x: scrollX, y: scrollY, ...(ready ? { ready: true } : {}) });
|
|
39
|
+
addEventListener("scroll", () => { frame ||= requestAnimationFrame(() => { frame = 0; view(); }); }, { passive: true });
|
|
40
|
+
addEventListener("keydown", (event) => {
|
|
41
|
+
if (event.isComposing) return;
|
|
42
|
+
tell("present-key", { key: event.key, ctrlKey: event.ctrlKey, metaKey: event.metaKey, altKey: event.altKey, kept: Boolean(event.target?.closest?.(KEEPS_KEYS)), prevented: event.defaultPrevented });
|
|
43
|
+
});
|
|
44
|
+
addEventListener("message", (event) => {
|
|
45
|
+
const message = event.data;
|
|
46
|
+
if (event.source !== window.parent || event.origin !== parentOrigin || !PROTOCOLS.includes(message?.protocol) || message.v !== VERSION || message.type !== "command") return;
|
|
47
|
+
if (message.name === "theme") dispatchEvent(new CustomEvent("doc-theme-request", { detail: { theme: message.theme === "dark" ? "dark" : "light" } })); // the kit's ui.js
|
|
48
|
+
else if (message.name === "go-section") stepSection(window, message.direction > 0 ? 1 : -1);
|
|
49
|
+
else if (message.name === "scroll") scrollBy({ left: Number(message.left) || 0, top: Number(message.top) || 0 }); // the wheel over the presentation's ink
|
|
50
|
+
});
|
|
51
|
+
view(true);
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
if (SHELL && window.parent !== window) {
|
|
55
|
+
vouched(SHELL).then((ok) => {
|
|
56
|
+
const waiting = held;
|
|
57
|
+
held = null;
|
|
58
|
+
if (!ok) return;
|
|
59
|
+
parentOrigin = SHELL;
|
|
60
|
+
for (const [type, fields] of waiting) tell(type, fields);
|
|
61
|
+
bridge();
|
|
62
|
+
});
|
|
63
|
+
}
|
|
@@ -11,8 +11,9 @@ import { t } from "../../../shared/i18n/index.mjs";
|
|
|
11
11
|
|
|
12
12
|
// Resizing chart cards and tables in the preview ("Sizes" in the kit's styles/sizes.css). With the pointer on the
|
|
13
13
|
// right edge of a card or table, or on its bottom edge (a chart's plot height, a table's scroll
|
|
14
|
-
// height), the cursor changes; dragging shows a
|
|
15
|
-
//
|
|
14
|
+
// height), the cursor changes; dragging shows a gray line where the edge goes (darker where it
|
|
15
|
+
// snaps) and the bottom notice says the size that makes while the drag lasts (no label beside the
|
|
16
|
+
// line: the user, 2026-11-07), and letting go applies it as one undo step (Esc cancels). Widths are shares of the width
|
|
16
17
|
// the block stands in: the reading width, or its column's. A card's width snaps to the middle and
|
|
17
18
|
// to the end; a centered card grows on both sides. A table's
|
|
18
19
|
// width moves its own right end by as much as the pointer moves, also when the table is wider than
|
|
@@ -23,17 +24,19 @@ import { t } from "../../../shared/i18n/index.mjs";
|
|
|
23
24
|
// height of its frame: shorter than its code, the code scrolls inside it, and the edge snaps to the
|
|
24
25
|
// height that shows all of it (no height of its own). Letting go where the drag started changes
|
|
25
26
|
// nothing. Anything that ends the press another way (the capture lost, the window losing the
|
|
26
|
-
// focus, the page hidden) cancels it; the lines
|
|
27
|
-
//
|
|
27
|
+
// focus, the page hidden) cancels it; the lines belong to the drag (overlays.mjs), and the notice it
|
|
28
|
+
// put up goes with it. Snapping takes the edge within SNAP (6px) of a place, little enough that a
|
|
29
|
+
// size near one can still be had (14px before 2026-11-07, which the user found too strong).
|
|
28
30
|
|
|
29
31
|
const STYLE = `
|
|
30
32
|
${gestureLock("data-ge-resize=\"x\"", { cursor: "ew-resize" })}
|
|
31
33
|
${gestureLock("data-ge-resize=\"y\"", { cursor: "ns-resize" })}
|
|
32
|
-
.ge-resize-line { position: fixed; left: 0; top: 0; z-index: ${Z.guide}; border-radius:
|
|
33
|
-
.ge-resize-
|
|
34
|
+
.ge-resize-line { position: fixed; left: 0; top: 0; z-index: ${Z.guide}; border-radius: 1px; background: var(--ge-guide-hot); pointer-events: none; }
|
|
35
|
+
.ge-resize-line[data-snap] { background: var(--ge-guide-snap); }
|
|
34
36
|
`;
|
|
35
37
|
const GRAB = { inside: 3, outside: 8 }; // how near an edge the pointer takes it, inside and outside the block (px)
|
|
36
|
-
const SNAP =
|
|
38
|
+
const SNAP = 6; // px
|
|
39
|
+
const LIVE = 60000; // ms: the notice saying the size dragged to stays while the drag lasts (it is taken off when it ends)
|
|
37
40
|
const MIN_WIDTH = 160; // px: the least a card's edge is dragged to (a table's is its columns' floors)
|
|
38
41
|
// The sizes (name and range) are each component's description's (registry SIZES): the same ones the
|
|
39
42
|
// server checks a size by.
|
|
@@ -45,11 +48,12 @@ const heightRange = (kind) => range(kind, heightOf(kind));
|
|
|
45
48
|
|
|
46
49
|
/**
|
|
47
50
|
* units: Map(id -> { kind }) from the edit map. active(): whether resizing may start.
|
|
48
|
-
* look(element, { sizes }, select): the editor's undoable change of sizes. say(text): the
|
|
51
|
+
* look(element, { sizes }, select): the editor's undoable change of sizes. say(text, kind, hold): the
|
|
52
|
+
* bottom notice; settle(): the notice taken off.
|
|
49
53
|
* owns(node): whether a table's right and bottom edges are the table tools' (table/widths.mjs: a
|
|
50
54
|
* click arms one, a drag then is this tool's, `startTable`).
|
|
51
55
|
*/
|
|
52
|
-
export function createResize({ units, active, look, say, owns = () => false }) {
|
|
56
|
+
export function createResize({ units, active, look, say, settle = () => {}, owns = () => false }) {
|
|
53
57
|
addStyle(STYLE);
|
|
54
58
|
let hover = null; // { node, axis } under the pointer
|
|
55
59
|
let drag = null;
|
|
@@ -134,12 +138,12 @@ export function createResize({ units, active, look, say, owns = () => false }) {
|
|
|
134
138
|
const snaps = [{ x: table.press, label: t("原宽度"), keep: true }, { x: table.press + (box.width - table.width), label: t("铺满正文") }];
|
|
135
139
|
const snap = snaps.find((candidate) => Math.abs(candidate.x - edge) <= SNAP);
|
|
136
140
|
if (snap) edge = snap.x;
|
|
137
|
-
if (snap?.keep) return { edge, label: snap.label, value: drag.before };
|
|
141
|
+
if (snap?.keep) return { edge, label: snap.label, value: drag.before, snapped: true };
|
|
138
142
|
// Rounded up, so the frame is never narrower than where it was let go (at the floors, say).
|
|
139
143
|
const share = Math.ceil(Math.max(range("table", SPAN).min, width(edge) / box.width) * 1000) / 1000;
|
|
140
144
|
const label = snap?.label ?? (share > 1 ? t("超宽表 · 表宽 {0}px,横向滚动", Math.round(width(edge)))
|
|
141
145
|
: edge <= narrowest + 0.5 ? t("最窄 · {0}%", Math.round(share * 100)) : `${Math.round(share * 100)}%`);
|
|
142
|
-
return { edge, label, value: Math.abs(share - 1) < 0.005 ? "1" : String(Math.min(share, range("table", SPAN).max)) };
|
|
146
|
+
return { edge, label, value: Math.abs(share - 1) < 0.005 ? "1" : String(Math.min(share, range("table", SPAN).max)), snapped: Boolean(snap) };
|
|
143
147
|
}
|
|
144
148
|
|
|
145
149
|
// Where the edge may go and where it snaps: back where it started (no change), the middle (a
|
|
@@ -158,13 +162,13 @@ export function createResize({ units, active, look, say, owns = () => false }) {
|
|
|
158
162
|
let edge = Math.min(Math.max(x, near), far);
|
|
159
163
|
const snap = snaps.find((candidate) => Math.abs(candidate.x - edge) <= SNAP);
|
|
160
164
|
if (snap) edge = snap.x;
|
|
161
|
-
if (snap?.keep) return { edge, label: snap.label, value: drag.before };
|
|
165
|
+
if (snap?.keep) return { edge, label: snap.label, value: drag.before, snapped: true };
|
|
162
166
|
const share = Math.round(Math.max(range(kind, SPAN).min, shareAt(edge)) * 1000) / 1000;
|
|
163
167
|
const whole = Math.abs(share - 1) < 0.005;
|
|
164
168
|
const label = snap?.label ?? `${Math.round(share * 100)}%${centered ? t(" · 居中") : ""}`;
|
|
165
169
|
// A card at the whole width is the default.
|
|
166
170
|
const value = whole ? (kind === "figure" && !centered ? null : "1") : String(Math.min(share, range(kind, SPAN).max));
|
|
167
|
-
return { edge, label, value };
|
|
171
|
+
return { edge, label, value, snapped: Boolean(snap) };
|
|
168
172
|
}
|
|
169
173
|
|
|
170
174
|
// ---------- heights ----------
|
|
@@ -184,8 +188,8 @@ export function createResize({ units, active, look, say, owns = () => false }) {
|
|
|
184
188
|
const header = rect.height - code.getBoundingClientRect().height;
|
|
185
189
|
const whole = rect.height + (code.scrollHeight - code.clientHeight); // all its lines, no scrolling
|
|
186
190
|
const height = Math.min(Math.max(y - rect.top, Math.min(whole, header + heightRange(kind).min)), whole);
|
|
187
|
-
if (before !== null && Math.abs(rect.top + height - rect.bottom) <= SNAP / 2) return { edge: rect.bottom, label: t("原高度"), value: before };
|
|
188
|
-
if (whole - height <= SNAP) return { edge: rect.top + whole, label: t("显示全部代码"), value: null };
|
|
191
|
+
if (before !== null && Math.abs(rect.top + height - rect.bottom) <= SNAP / 2) return { edge: rect.bottom, label: t("原高度"), value: before, snapped: true };
|
|
192
|
+
if (whole - height <= SNAP) return { edge: rect.top + whole, label: t("显示全部代码"), value: null, snapped: true };
|
|
189
193
|
const frame = Math.round(height - header);
|
|
190
194
|
return { edge: rect.top + header + frame, label: t("高 {0}px · 其余滚动查看", frame), value: `${frame}px` };
|
|
191
195
|
}
|
|
@@ -194,19 +198,20 @@ export function createResize({ units, active, look, say, owns = () => false }) {
|
|
|
194
198
|
const drawn = drawnHeight(svg);
|
|
195
199
|
const scale = svg.getBoundingClientRect().height / drawn || 1;
|
|
196
200
|
const floor = 160; // the least a chart is drawn at (a softer floor than the one a size is checked by)
|
|
197
|
-
if (Math.abs(rect.bottom - y) <= SNAP) return { edge: rect.bottom, label: t("原高度"), value: before };
|
|
201
|
+
if (Math.abs(rect.bottom - y) <= SNAP) return { edge: rect.bottom, label: t("原高度"), value: before, snapped: true };
|
|
198
202
|
// Level with a card beside it (in another column of its row): the bottoms meet.
|
|
199
203
|
const beside = drag.beside.find((bottom) => Math.abs(bottom - y) <= SNAP);
|
|
200
204
|
const height = Math.round(Math.min(Math.max(drawn + ((beside ?? y) - rect.bottom) / scale, floor), heightRange(kind).max));
|
|
201
205
|
const edge = rect.bottom + (height - drawn) * scale;
|
|
202
|
-
|
|
206
|
+
const level = beside !== undefined && Math.abs(edge - beside) < 1.5;
|
|
207
|
+
return { edge, label: level ? t("与旁边对齐 · 图表高 {0}px", height) : t("图表高 {0}px", height), value: `${height}px`, snapped: level };
|
|
203
208
|
}
|
|
204
209
|
const all = node.scrollHeight + (node.offsetHeight - node.clientHeight);
|
|
205
210
|
let height = Math.min(Math.max(y - rect.top, heightRange(kind).min), all);
|
|
206
|
-
if (Math.abs(rect.top + height - rect.bottom) <= SNAP / 2) return { edge: rect.bottom, label: t("原高度"), value: drag.before };
|
|
211
|
+
if (Math.abs(rect.top + height - rect.bottom) <= SNAP / 2) return { edge: rect.bottom, label: t("原高度"), value: drag.before, snapped: true };
|
|
207
212
|
if (height >= all - 2) {
|
|
208
213
|
const fits = all <= scrollHeight(node); // the default scroll area shows them all
|
|
209
|
-
return { edge: rect.top + all, label: t("显示全部行"), value: fits ? null : "none" };
|
|
214
|
+
return { edge: rect.top + all, label: t("显示全部行"), value: fits ? null : "none", snapped: true };
|
|
210
215
|
}
|
|
211
216
|
height = Math.round(height);
|
|
212
217
|
return { edge: rect.top + height, label: t("高 {0}px", height), value: `${height}px` };
|
|
@@ -231,6 +236,7 @@ export function createResize({ units, active, look, say, owns = () => false }) {
|
|
|
231
236
|
const rect = node.getBoundingClientRect();
|
|
232
237
|
drag = {
|
|
233
238
|
node, axis, kind, name, before, rect,
|
|
239
|
+
press: { x: event.clientX, y: event.clientY },
|
|
234
240
|
box: contentBox(node.parentElement),
|
|
235
241
|
// A card's height snaps level with the cards beside it: the bottoms of those in the other columns of its row.
|
|
236
242
|
beside: axis === "y" && kind === "figure" ? besideBottoms(node) : [],
|
|
@@ -243,19 +249,22 @@ export function createResize({ units, active, look, say, owns = () => false }) {
|
|
|
243
249
|
press: event.clientX,
|
|
244
250
|
atEnd: node.scrollLeft + node.clientWidth >= node.scrollWidth - 2,
|
|
245
251
|
} : null,
|
|
246
|
-
label: kind === "code" ? null : element("div", { class: "ge-resize-label" }),
|
|
247
252
|
result: null,
|
|
253
|
+
told: null, // what the notice says now
|
|
248
254
|
};
|
|
249
255
|
const session = drag;
|
|
250
256
|
session.lines = (session.centered ? [0, 1] : [0]).map(() => element("div", { class: "ge-resize-line" }));
|
|
251
|
-
for (const part of
|
|
257
|
+
for (const part of session.lines) mount(own(part, "resize", { owner: node, alive: () => drag === session }));
|
|
252
258
|
note("resize", `start ${axis}`);
|
|
253
259
|
document.documentElement.setPointerCapture?.(event.pointerId);
|
|
254
260
|
update(event.clientX, event.clientY);
|
|
255
261
|
}
|
|
256
262
|
|
|
263
|
+
// What is being resized, in the notice's words: 卡片 and 宽度, 表格 and 高度, 代码块 and 高度.
|
|
264
|
+
const what = (kind, axis) => [kind === "figure" ? t("卡片") : kind === "code" ? t("代码块") : t("表格"), axis === "x" ? t("宽度") : t("高度")];
|
|
265
|
+
|
|
257
266
|
function update(x, y) {
|
|
258
|
-
const { axis, rect, box, lines
|
|
267
|
+
const { axis, kind, rect, box, lines } = drag;
|
|
259
268
|
drag.result = axis === "x" ? widthAt(x) : heightAt(y);
|
|
260
269
|
const { edge } = drag.result;
|
|
261
270
|
if (axis === "x") {
|
|
@@ -264,24 +273,28 @@ export function createResize({ units, active, look, say, owns = () => false }) {
|
|
|
264
273
|
width: "2px", height: `${Math.round(rect.height)}px`,
|
|
265
274
|
transform: `translate(${Math.round((index ? mirror : edge) - 1)}px, ${Math.round(rect.top)}px)`,
|
|
266
275
|
}));
|
|
267
|
-
if (label) label.style.transform = `translate(${Math.round(Math.min(edge + 10, innerWidth - label.offsetWidth - 8))}px, ${Math.round(Math.max(8, y - 30))}px)`;
|
|
268
276
|
} else {
|
|
269
277
|
Object.assign(lines[0].style, { width: `${Math.round(rect.width)}px`, height: "2px", transform: `translate(${Math.round(rect.left)}px, ${Math.round(edge - 1)}px)` });
|
|
270
|
-
if (label) label.style.transform = `translate(${Math.round(Math.min(x + 12, innerWidth - label.offsetWidth - 8))}px, ${Math.round(Math.min(edge + 8, innerHeight - 28))}px)`;
|
|
271
278
|
}
|
|
272
|
-
|
|
279
|
+
lines.forEach((line) => line.toggleAttribute("data-snap", Boolean(drag.result.snapped)));
|
|
280
|
+
// The size in the bottom notice once the pointer has moved (a press alone says nothing), said again
|
|
281
|
+
// only when it changes (a workbench is told each time).
|
|
282
|
+
if (!drag.told && Math.hypot(x - drag.press.x, y - drag.press.y) < 2) return;
|
|
283
|
+
const told = t("{0}{1}:{2}", ...what(kind, axis), drag.result.label);
|
|
284
|
+
if (told !== drag.told) say(told, "note", LIVE);
|
|
285
|
+
drag.told = told;
|
|
273
286
|
}
|
|
274
287
|
|
|
275
288
|
function finish(commit) {
|
|
276
289
|
if (!drag) return;
|
|
277
|
-
const { node, axis, kind, name,
|
|
290
|
+
const { node, axis, kind, name, lines, result, table, told } = drag;
|
|
278
291
|
note("resize", commit ? "released" : "cancelled");
|
|
279
292
|
drag = null;
|
|
280
293
|
lines.forEach((line) => line.remove());
|
|
281
|
-
|
|
294
|
+
if (told) settle(); // the size dragged to: what is said next (or nothing) replaces it
|
|
282
295
|
setHover(null);
|
|
283
296
|
if (commit && result && look(node, { sizes: { [name]: result.value } }, null)) {
|
|
284
|
-
say(t("已调整{0}{1}:{2} · Ctrl+Z 撤销",
|
|
297
|
+
say(t("已调整{0}{1}:{2} · Ctrl+Z 撤销", ...what(kind, axis), result.label));
|
|
285
298
|
// Scrolled to its end, a table stays so: its new end shows at the frame's edge, ready for the
|
|
286
299
|
// next drag (after tables.js has laid it out again, on the next frame).
|
|
287
300
|
if (table?.atEnd) requestAnimationFrame(() => requestAnimationFrame(() => { node.scrollLeft = node.scrollWidth; }));
|
|
@@ -322,6 +335,6 @@ export function createResize({ units, active, look, say, owns = () => false }) {
|
|
|
322
335
|
setHover(null);
|
|
323
336
|
},
|
|
324
337
|
/** The editor's UI nodes to keep in the top layer when a modal dialog opens. */
|
|
325
|
-
get nodes() { return drag ? [...drag.lines
|
|
338
|
+
get nodes() { return drag ? [...drag.lines] : []; },
|
|
326
339
|
};
|
|
327
340
|
}
|
|
@@ -5,6 +5,7 @@ import { createFills } from "../fills.mjs";
|
|
|
5
5
|
import { FOLDED } from "../folded.mjs";
|
|
6
6
|
import { describe, note, report } from "../overlays.mjs";
|
|
7
7
|
import { t } from "../../../shared/i18n/index.mjs";
|
|
8
|
+
import { UNFILLED_ALONE } from "../../components/registry.mjs";
|
|
8
9
|
|
|
9
10
|
// Selected blocks (docs/editor.md, "Selecting blocks"): a set of blocks, none inside another, in
|
|
10
11
|
// document order. A box selection drawn from empty space gives blocks of one container
|
|
@@ -109,10 +110,17 @@ export function createSelection({ info, active, say, closeMenu, schedule }) {
|
|
|
109
110
|
// The fills made to match the selection now: those of blocks no longer selected (or no longer on
|
|
110
111
|
// the page) go at once; each selected block shown gets its fill where it is, reaching past it as
|
|
111
112
|
// reachOf says, never into a neighbour's (roomOf). One that cannot be drawn takes all the fills
|
|
112
|
-
// down (said once): better none than one in the wrong place.
|
|
113
|
+
// down (said once): better none than one in the wrong place. A kind whose own tools show it selected
|
|
114
|
+
// (UNFILLED_ALONE: the image with its picture, its corner grips and toolbar) draws no fill selected alone (the user, 2026-11-09: no pale
|
|
115
|
+
// blue over a picture clicked); among other blocks it is filled as they are.
|
|
116
|
+
const toolsShowIt = () => {
|
|
117
|
+
if (picked.length !== 1 || marked.length !== 0) return false;
|
|
118
|
+
const holds = UNFILLED_ALONE[picked[0].getAttribute?.("data-ge-unit-kind")];
|
|
119
|
+
return holds !== undefined && picked[0].querySelector?.(holds) !== null;
|
|
120
|
+
};
|
|
113
121
|
function render() {
|
|
114
122
|
try {
|
|
115
|
-
halos.paint(hidden || !active() ? [] : [...picked, ...marked].filter(alive));
|
|
123
|
+
halos.paint(hidden || !active() || toolsShowIt() ? [] : [...picked, ...marked].filter(alive));
|
|
116
124
|
} catch (error) {
|
|
117
125
|
unpaint();
|
|
118
126
|
report("selection fills", error);
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
// Where the page shows a file of the report's folder (assets/<file>): the server's asset route,
|
|
2
|
+
// which editor.mjs gives (serveFiles) once it knows the report. A picture in a table cell's text is
|
|
3
|
+
// shown there (components/table/ cellPicture). No imports: a component's index.mjs reads it while
|
|
4
|
+
// the registry is still being made.
|
|
5
|
+
|
|
6
|
+
let fileUrl = (path) => path;
|
|
7
|
+
|
|
8
|
+
/** Where the page shows a file of the report's folder from now on: `urlOf(path)`. */
|
|
9
|
+
export const serveFiles = (urlOf) => {
|
|
10
|
+
fileUrl = urlOf;
|
|
11
|
+
};
|
|
12
|
+
|
|
13
|
+
/** Where the page shows `path`, a file of the report's folder (assets/<file>). */
|
|
14
|
+
export const servedFile = (path) => fileUrl(path);
|
|
@@ -5,7 +5,15 @@ import { lookOf, lookOfElement } from "../../shared/document-look.mjs";
|
|
|
5
5
|
// tells the workbench its state, never the report's content. Nothing happens when the page is not
|
|
6
6
|
// embedded. The protocol is src/shared/session.mjs; how a workbench uses it, docs/workbench.md.
|
|
7
7
|
//
|
|
8
|
-
// A
|
|
8
|
+
// A workbench of another workspace shows a draft of this one from its own origin (docs/workbench.md
|
|
9
|
+
// "Drafts of other workspaces"), naming that origin in the frame's address (?shell=<origin>): the page
|
|
10
|
+
// then asks its own server whether that is a Gallery server of this computer (GET
|
|
11
|
+
// /__gallery/workspace/shell: on the registry, running, its token and process as it announces them),
|
|
12
|
+
// and talks to it alone once it is, holding what it says until then; one that is not hears nothing and
|
|
13
|
+
// is heard by nothing, so that no other page of this computer drives a document by framing it. Going,
|
|
14
|
+
// such a page says `bye` (the workbench of another origin cannot see it go).
|
|
15
|
+
//
|
|
16
|
+
// A message counts only from the parent window, of this origin (or the shell's, vouched for) and protocol. A command names the
|
|
9
17
|
// report it is meant for: one for another report (the iframe went to another page meanwhile) is
|
|
10
18
|
// refused. Every command gets exactly one reply, once it is done. Besides the editor's commands the
|
|
11
19
|
// session itself answers five: `theme` (show the report light or dark, or as the reader chose, without
|
|
@@ -14,10 +22,20 @@ import { lookOf, lookOfElement } from "../../shared/document-look.mjs";
|
|
|
14
22
|
// `scroll-top` (back to the top when scrolled down) and `close-card` (the detail card on top closes as a
|
|
15
23
|
// press on its backdrop closes it: the workbench asks on a press on its own bars, or Esc there, while
|
|
16
24
|
// the page says a card is open, `card` in what it sends). A card stands in the middle of the
|
|
17
|
-
// workbench's window, not of the frame (centreCards, below).
|
|
25
|
+
// workbench's window, not of the frame (centreCards, below). A block's 允许访问 (doc-net-consent, the kit's)
|
|
26
|
+
// is sent as `consent`.
|
|
18
27
|
|
|
19
28
|
/** A page opened in a frame on its own (?solo), not as the workbench's report: no session, its own notices. */
|
|
20
29
|
export const SOLO = new URLSearchParams(location.search).has("solo");
|
|
30
|
+
/** The origin of a workbench of another workspace showing this page (?shell=<origin>), or null: this one's. */
|
|
31
|
+
const SHELL = (() => {
|
|
32
|
+
const named = new URLSearchParams(location.search).get("shell");
|
|
33
|
+
return named && named !== location.origin ? named : null;
|
|
34
|
+
})();
|
|
35
|
+
|
|
36
|
+
// Whether this page's server vouches for the workbench at `origin` (GET /__gallery/workspace/shell).
|
|
37
|
+
const vouched = (origin) => fetch(`/__gallery/workspace/shell?origin=${encodeURIComponent(origin)}`, { cache: "no-store" })
|
|
38
|
+
.then((answer) => answer.json()).then((answer) => answer?.shell === true, () => false);
|
|
21
39
|
|
|
22
40
|
/**
|
|
23
41
|
* slug: the report's; snapshot(): { title, state } (state: STATE_FLAGS of src/shared/session.mjs);
|
|
@@ -38,11 +56,28 @@ export const SOLO = new URLSearchParams(location.search).has("solo");
|
|
|
38
56
|
export function connectWorkbench({ slug, snapshot, commands, modals }) {
|
|
39
57
|
if (window.parent === window || SOLO) return null;
|
|
40
58
|
centreCards(modals);
|
|
59
|
+
// The workbench's origin: this one's, or the shell's once this page's server vouched for it (null till
|
|
60
|
+
// then: what the page says is held, and is dropped when it does not).
|
|
61
|
+
let parentOrigin = SHELL ? null : location.origin;
|
|
62
|
+
let held = SHELL ? [] : null;
|
|
63
|
+
if (SHELL) {
|
|
64
|
+
vouched(SHELL).then((ok) => {
|
|
65
|
+
const waiting = held;
|
|
66
|
+
held = null;
|
|
67
|
+
if (!ok) return;
|
|
68
|
+
parentOrigin = SHELL;
|
|
69
|
+
for (const [type, fields, protocols] of waiting) send(type, fields, protocols);
|
|
70
|
+
// A workbench of another origin sees no pagehide of this page: it is told.
|
|
71
|
+
addEventListener("pagehide", () => send("bye", {}), { once: true });
|
|
72
|
+
});
|
|
73
|
+
}
|
|
41
74
|
// The id the workbench speaks (src/shared/session.mjs, OLD_PROTOCOL): null until its first command,
|
|
42
75
|
// and meanwhile every message goes under both, so that a workbench of either version hears it.
|
|
43
76
|
let spoken = null;
|
|
44
77
|
const send = (type, fields, protocols = spoken ? [spoken] : [PROTOCOL, OLD_PROTOCOL]) => {
|
|
45
|
-
|
|
78
|
+
if (held) return void held.push([type, fields, protocols]);
|
|
79
|
+
if (!parentOrigin) return;
|
|
80
|
+
for (const protocol of protocols) window.parent.postMessage({ protocol, v: VERSION, type, slug, ...fields }, parentOrigin);
|
|
46
81
|
};
|
|
47
82
|
let last = null;
|
|
48
83
|
const update = () => {
|
|
@@ -64,6 +99,15 @@ export function connectWorkbench({ slug, snapshot, commands, modals }) {
|
|
|
64
99
|
event.preventDefault();
|
|
65
100
|
send("key", { key });
|
|
66
101
|
});
|
|
102
|
+
// A block's card asks the reader to let it online (its 允许访问 button: the kit's net.js): the workbench
|
|
103
|
+
// opens its consent dialog, the one 设置 › 组件列表 opens, and writes what the reader says; the page
|
|
104
|
+
// hears it on its event stream, and the kit starts the instance again.
|
|
105
|
+
addEventListener("doc-net-consent", (event) => {
|
|
106
|
+
const { block, hosts } = event.detail ?? {};
|
|
107
|
+
if (typeof block !== "string") return;
|
|
108
|
+
event.preventDefault();
|
|
109
|
+
send("consent", { block, hosts: Array.isArray(hosts) ? hosts : [] });
|
|
110
|
+
});
|
|
67
111
|
const own = {
|
|
68
112
|
async theme({ theme = null }) {
|
|
69
113
|
if (theme !== null && theme !== "light" && theme !== "dark") return { ok: false, reason: "theme" };
|
|
@@ -97,7 +141,7 @@ export function connectWorkbench({ slug, snapshot, commands, modals }) {
|
|
|
97
141
|
|
|
98
142
|
addEventListener("message", async (event) => {
|
|
99
143
|
const message = event.data;
|
|
100
|
-
if (event.source !== window.parent || event.origin !==
|
|
144
|
+
if (event.source !== window.parent || !parentOrigin || event.origin !== parentOrigin) return;
|
|
101
145
|
if (!PROTOCOLS.includes(message?.protocol) || message.v !== VERSION || message.type !== "command") return;
|
|
102
146
|
spoken = message.protocol;
|
|
103
147
|
const run = Object.hasOwn(all, message.name) ? all[message.name] : null;
|
|
@@ -42,12 +42,12 @@ const INLINE = {
|
|
|
42
42
|
};
|
|
43
43
|
|
|
44
44
|
// Groups of the unfiltered menu: 基本区块, 高级区块 (media, code, tabs and formula blocks: what
|
|
45
|
-
// holds more than text; the types' own `menu`, registry.mjs MENU_GROUPS),
|
|
46
|
-
// are now: the workspace's), and what is no block under 内联.
|
|
45
|
+
// holds more than text; the types' own `menu`, registry.mjs MENU_GROUPS), 自定义块 (what the variants
|
|
46
|
+
// are now: the workspace's custom blocks, plan §4.1's name for the group 组件 was), and what is no block under 内联.
|
|
47
47
|
const SECTIONS = [
|
|
48
48
|
{ title: t("基本区块"), types: () => MENU_GROUPS.basic },
|
|
49
49
|
{ title: t("高级区块"), types: () => MENU_GROUPS.advanced },
|
|
50
|
-
{ title: t("
|
|
50
|
+
{ title: t("自定义块"), types: variantKeys },
|
|
51
51
|
];
|
|
52
52
|
|
|
53
53
|
const infoOf = (key) => INLINE[key] ?? menuRow(key);
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
import { TABLE } from "../../components/kit.mjs";
|
|
2
|
+
import { CHART_SOURCE, TABLE_READERS, VIEW_FROM, nextChartKey } from "../../../shared/table-chart.mjs";
|
|
3
|
+
import { t } from "../../../shared/i18n/index.mjs";
|
|
4
|
+
import { menuRow } from "../page-objects.mjs";
|
|
5
|
+
|
|
6
|
+
// Which table a view reads (docs/editor.md, "Table views"). A view of a table (an instance of a custom
|
|
7
|
+
// block whose needs hold "tables") names its table by a key: VIEW_FROM on the instance, CHART_SOURCE on
|
|
8
|
+
// the table's frame, never by an id or the blocks' order. A view made on the page ("/", 在下方新建, 转换成)
|
|
9
|
+
// is bound to the nearest table above it as it is made, in the same undo step; the table it reads is the
|
|
10
|
+
// reader's to change after that, in the block's 设置 (installed/page.mjs), which lists the document's tables.
|
|
11
|
+
// A table with no key gets one in the same step (the first of t1, t2 … the page does not hold), and so
|
|
12
|
+
// does the second of two an Agent wrote with one key: a view by that key would read the first.
|
|
13
|
+
|
|
14
|
+
const FRAME_WITH_TABLE = (frame) => frame.querySelector("table") !== null && !frame.closest("[data-doc-dev]");
|
|
15
|
+
|
|
16
|
+
/** The tables of the page, in the document's order: their frames (.doc-table-wrap). */
|
|
17
|
+
export const tableFrames = () => [...document.querySelectorAll(TABLE.frame)].filter(FRAME_WITH_TABLE);
|
|
18
|
+
|
|
19
|
+
/** The frame a key names, as the kit reads it (runtime/table-reading.js frameOf) and the checks do: the first that carries it. */
|
|
20
|
+
export const frameOf = (key) => tableFrames().find((frame) => frame.getAttribute(CHART_SOURCE) === key) ?? null;
|
|
21
|
+
|
|
22
|
+
/** The nearest table above `node`, in the document's order, that does not hold it; null where there is none. */
|
|
23
|
+
export function tableAbove(node) {
|
|
24
|
+
let found = null;
|
|
25
|
+
for (const frame of tableFrames()) {
|
|
26
|
+
if (frame.contains(node)) continue;
|
|
27
|
+
if (frame.compareDocumentPosition(node) & Node.DOCUMENT_POSITION_FOLLOWING) found = frame;
|
|
28
|
+
}
|
|
29
|
+
return found;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
// Every key a chart or a view names, or a frame carries.
|
|
33
|
+
const takenKeys = () => new Set([...document.querySelectorAll([CHART_SOURCE, ...TABLE_READERS].map((name) => `[${name}]`).join(", "))]
|
|
34
|
+
.flatMap((node) => [CHART_SOURCE, ...TABLE_READERS].map((name) => node.getAttribute(name)).filter((value) => value !== null)));
|
|
35
|
+
|
|
36
|
+
/** The key `frame` is read by: its own where it names this frame, else a new one (not yet written). */
|
|
37
|
+
export function keyOf(frame) {
|
|
38
|
+
const own = frame.getAttribute(CHART_SOURCE);
|
|
39
|
+
return own !== null && frameOf(own) === frame ? own : nextChartKey(takenKeys());
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
/**
|
|
43
|
+
* `instance` made a view of `frame` (or of none: null takes its key off): its VIEW_FROM set, and the key
|
|
44
|
+
* on the frame where it carried none that names it. Records nothing: the caller's undo step does
|
|
45
|
+
* (`viewFrames`, struct's `attributes`). Returns whether anything changed.
|
|
46
|
+
*/
|
|
47
|
+
export function bindView(instance, frame) {
|
|
48
|
+
if (!frame) {
|
|
49
|
+
if (!instance.hasAttribute(VIEW_FROM)) return false;
|
|
50
|
+
instance.removeAttribute(VIEW_FROM);
|
|
51
|
+
return true;
|
|
52
|
+
}
|
|
53
|
+
const key = keyOf(frame);
|
|
54
|
+
let changed = false;
|
|
55
|
+
if (instance.getAttribute(VIEW_FROM) !== key) {
|
|
56
|
+
instance.setAttribute(VIEW_FROM, key);
|
|
57
|
+
changed = true;
|
|
58
|
+
}
|
|
59
|
+
if (frame.getAttribute(CHART_SOURCE) !== key) {
|
|
60
|
+
frame.setAttribute(CHART_SOURCE, key);
|
|
61
|
+
changed = true;
|
|
62
|
+
}
|
|
63
|
+
return changed;
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
/** A view that was made bound to the table above it. */
|
|
67
|
+
export function bindAbove(instance) {
|
|
68
|
+
return bindView(instance, tableAbove(instance));
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
/**
|
|
72
|
+
* What the undo step that makes a block of the menu's key records of the tables' keys (struct's
|
|
73
|
+
* `attributes`): every table's frame when the block reads tables, as the table it is bound to is only
|
|
74
|
+
* known as the block is made; nothing for any other block.
|
|
75
|
+
*/
|
|
76
|
+
export const viewFrames = (key) => (menuRow(key)?.readsTables ? tableFrames().map((frame) => [frame, [CHART_SOURCE]]) : []);
|
|
77
|
+
|
|
78
|
+
// A table named for a reader: its place among the document's tables and the words of its first row.
|
|
79
|
+
function labelOf(frame, place) {
|
|
80
|
+
const first = frame.querySelector("tr");
|
|
81
|
+
const words = first ? [...first.cells].map((cell) => cell.textContent.replace(/\s+/g, " ").trim()).filter(Boolean).slice(0, 4).join("、") : "";
|
|
82
|
+
const shown = words.length > 28 ? `${words.slice(0, 27)}…` : words;
|
|
83
|
+
return shown ? t("表格 {0} · {1}", place, shown) : t("表格 {0}", place);
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
/** The document's tables for a list to choose from: [{ frame, label }], the label naming the table by its place and its first row. */
|
|
87
|
+
export const tableChoices = () => tableFrames().map((frame, at) => ({ frame, label: labelOf(frame, at + 1) }));
|