@heycys/gallery 0.1.0 → 0.1.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/THIRD-PARTY-NOTICES.md +51 -1
- package/browser/editor/components/callout/index.mjs +40 -15
- package/browser/editor/components/columns/page.mjs +45 -32
- package/browser/editor/components/details/index.mjs +2 -1
- package/browser/editor/components/dialog/index.mjs +2 -1
- package/browser/editor/components/dialog/page.mjs +0 -18
- package/browser/editor/components/divider/index.mjs +1 -1
- package/browser/editor/components/embed/index.mjs +2 -2
- package/browser/editor/components/figure/page.mjs +10 -1
- package/browser/editor/components/file/page.mjs +2 -2
- 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 +2 -0
- package/browser/editor/components/heading/page.mjs +6 -0
- package/browser/editor/components/highlight/index.mjs +4 -20
- package/browser/editor/components/icons.mjs +13 -2
- package/browser/editor/components/image/crop.mjs +6 -9
- package/browser/editor/components/image/page.mjs +2 -2
- package/browser/editor/components/installed/index.mjs +82 -29
- package/browser/editor/components/installed/page.mjs +146 -34
- package/browser/editor/components/installed/served.mjs +6 -5
- package/browser/editor/components/instances.mjs +18 -0
- package/browser/editor/components/kit.mjs +3 -0
- package/browser/editor/components/list/page.mjs +3 -6
- package/browser/editor/components/media/page.mjs +44 -14
- package/browser/editor/components/pages.mjs +2 -2
- package/browser/editor/components/registry.mjs +68 -33
- package/browser/editor/components/section/index.mjs +2 -1
- package/browser/editor/components/set-apart.mjs +24 -0
- package/browser/editor/components/table/index.mjs +64 -5
- package/browser/editor/components/table/page.mjs +30 -19
- package/browser/editor/page/annotate/anchors.mjs +4 -3
- package/browser/editor/page/annotate/card.mjs +3 -6
- package/browser/editor/page/annotate/index.mjs +61 -34
- package/browser/editor/page/autosave.mjs +357 -38
- package/browser/editor/page/beside.mjs +5 -5
- package/browser/editor/page/block-menu/colors.mjs +3 -1
- package/browser/editor/page/block-menu/index.mjs +8 -6
- package/browser/editor/page/blocks.mjs +16 -7
- package/browser/editor/page/board/client.mjs +57 -0
- package/browser/editor/page/board/hint.mjs +145 -0
- package/browser/editor/page/board/history.mjs +119 -0
- package/browser/editor/page/board/index.mjs +970 -0
- package/browser/editor/page/board/settings.mjs +209 -0
- package/browser/editor/page/caret.mjs +5 -2
- package/browser/editor/page/changes/bar.mjs +94 -0
- package/browser/editor/page/changes/ghost.mjs +206 -0
- package/browser/editor/page/changes/gone-words.mjs +94 -0
- package/browser/editor/page/changes/index.mjs +447 -0
- package/browser/editor/page/changes/words.mjs +27 -0
- package/browser/editor/page/clipboard/import/colors.mjs +3 -3
- 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 +156 -26
- package/browser/editor/page/clipboard/own/blocks.mjs +25 -16
- package/browser/editor/page/clipboard/own/chart-keys.mjs +41 -28
- package/browser/editor/page/clipboard/own/describe.mjs +16 -7
- package/browser/editor/page/clipboard/own/export.mjs +6 -6
- package/browser/editor/page/clipboard/own/selection.mjs +3 -3
- package/browser/editor/page/clipboard/own/writers.mjs +0 -11
- package/browser/editor/page/columns/index.mjs +48 -46
- package/browser/editor/page/commit.mjs +98 -25
- package/browser/editor/page/conflicts.mjs +13 -33
- package/browser/editor/page/convert.mjs +8 -7
- package/browser/editor/page/core.mjs +81 -27
- package/browser/editor/page/custom-page.mjs +106 -0
- package/browser/editor/page/drag/index.mjs +40 -24
- package/browser/editor/page/drag/preview.mjs +9 -4
- package/browser/editor/page/editor.mjs +120 -28
- package/browser/editor/page/emoji-picker/emoji-tab.mjs +22 -13
- package/browser/editor/page/emoji-picker/grid.mjs +7 -5
- package/browser/editor/page/emoji-picker/icon-tab.mjs +4 -4
- package/browser/editor/page/emoji-picker/icons.mjs +0 -1
- package/browser/editor/page/emoji-picker/index.mjs +11 -9
- package/browser/editor/page/emoji-picker/styles.mjs +156 -2
- package/browser/editor/page/emoji-picker/support.mjs +6 -4
- package/browser/editor/page/emoji-picker/upload.mjs +14 -13
- package/browser/editor/page/fills.mjs +5 -3
- package/browser/editor/page/fold/index.mjs +348 -0
- package/browser/editor/page/fold/rule.mjs +125 -0
- package/browser/editor/page/folded.mjs +23 -0
- package/browser/editor/page/format-bar/bar.mjs +2 -1
- package/browser/editor/page/format-bar/index.mjs +1 -1
- package/browser/editor/page/geometry.mjs +8 -6
- package/browser/editor/page/handle/index.mjs +22 -14
- package/browser/editor/page/hints/index.mjs +1 -1
- package/browser/editor/page/history.mjs +24 -4
- package/browser/editor/page/insert/index.mjs +30 -17
- package/browser/editor/page/links/index.mjs +5 -3
- package/browser/editor/page/links/pages.mjs +27 -9
- package/browser/editor/page/long-runs.mjs +75 -0
- package/browser/editor/page/look.mjs +69 -6
- package/browser/editor/page/margin.mjs +63 -27
- package/browser/editor/page/media-menu/index.mjs +6 -7
- package/browser/editor/page/menu.mjs +86 -31
- package/browser/editor/page/merge.mjs +24 -0
- package/browser/editor/page/notices.mjs +3 -3
- package/browser/editor/page/offered.mjs +1 -1
- package/browser/editor/page/outline/folds.mjs +11 -10
- package/browser/editor/page/outline/index.mjs +131 -45
- package/browser/editor/page/outline/list.mjs +23 -11
- package/browser/editor/page/outline/read.mjs +1 -1
- package/browser/editor/page/outline/strip.mjs +7 -1
- package/browser/editor/page/page-objects.mjs +13 -2
- package/browser/editor/page/panel.mjs +9 -13
- package/browser/editor/page/present-links.mjs +11 -2
- package/browser/editor/page/resize/index.mjs +42 -29
- package/browser/editor/page/selection/delete.mjs +8 -6
- package/browser/editor/page/selection/index.mjs +10 -3
- package/browser/editor/page/served.mjs +14 -0
- package/browser/editor/page/session.mjs +101 -6
- package/browser/editor/page/slash-menu/index.mjs +3 -3
- package/browser/editor/page/table/cell-bar.mjs +4 -1
- package/browser/editor/page/table/cells.mjs +103 -47
- package/browser/editor/page/table/icons.mjs +3 -1
- package/browser/editor/page/table/index.mjs +40 -16
- package/browser/editor/page/table/pictures.mjs +299 -0
- package/browser/editor/page/table/views.mjs +150 -0
- package/browser/editor/page/table/widths.mjs +9 -4
- package/browser/editor/page/text-select/index.mjs +43 -14
- package/browser/editor/page/todo-writes.mjs +75 -0
- package/browser/editor/page/tooltip.mjs +1 -1
- package/browser/editor/page/type-grid.mjs +4 -3
- package/browser/editor/page/typing/code-edges.mjs +63 -17
- package/browser/editor/page/typing/index.mjs +65 -9
- package/browser/editor/page/typing/leave.mjs +1 -1
- package/browser/editor/page/ui.mjs +13 -0
- package/browser/shared/annotations.mjs +8 -10
- package/browser/shared/block-packs.mjs +404 -0
- package/browser/shared/board-places.mjs +224 -0
- package/browser/shared/card-size.mjs +59 -0
- package/browser/shared/code-folds.mjs +5 -1
- package/browser/shared/colors.mjs +17 -14
- package/browser/shared/component-catalog.mjs +345 -54
- package/browser/shared/component-source.mjs +37 -0
- package/browser/shared/components/callout.mjs +4 -2
- package/browser/shared/components/index.mjs +72 -9
- package/browser/shared/components/installed.mjs +110 -8
- package/browser/shared/components/page.mjs +22 -3
- package/browser/shared/components/state.mjs +5 -1
- package/browser/shared/components/table.mjs +1 -1
- package/browser/shared/components/text.mjs +2 -2
- package/browser/shared/document-look.mjs +183 -0
- package/browser/shared/drafts.mjs +432 -0
- package/browser/shared/emoji/data/LICENSE-lucide.txt +43 -0
- package/browser/shared/emoji/data/README.md +4 -2
- package/browser/shared/emoji/data/categories.json +1 -1
- package/browser/shared/emoji/data/keywords-en.json +1 -1
- package/browser/shared/emoji/data/keywords-zh.json +1 -1
- package/browser/shared/emoji/data/names.json +1 -1
- package/browser/shared/emoji/data/positions.json +1 -1
- package/browser/shared/emoji/data/twemoji-index.json +1 -1
- package/browser/shared/emoji/data/twemoji-svg.bin +0 -0
- package/browser/shared/emoji/data.mjs +10 -12
- package/browser/shared/emoji/emoji.mjs +8 -7
- package/browser/shared/emoji/icon-value.mjs +4 -3
- 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/html-tree.mjs +11 -5
- package/browser/shared/i18n/en.mjs +374 -35
- package/browser/shared/json-layout.mjs +47 -0
- package/browser/shared/long-runs.mjs +39 -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/new-names.mjs +5 -2
- package/browser/shared/outline-shape.mjs +128 -0
- package/browser/shared/outline.mjs +458 -0
- package/browser/shared/pack-manifest.mjs +77 -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 +388 -0
- package/browser/shared/paths.mjs +6 -0
- package/browser/shared/preferences.mjs +10 -4
- package/browser/shared/preview-server.mjs +3 -7
- package/browser/shared/session.mjs +13 -5
- package/browser/shared/shipped-blocks.mjs +299 -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 +134 -0
- package/browser/shared/workspace-columns.mjs +120 -0
- package/browser/shared/workspace-look.mjs +91 -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/browser/shared/zoom.mjs +5 -5
- package/dist/chunk-2NRBY6AJ.mjs +2 -0
- package/dist/chunk-32ZUEFZ7.mjs +2 -0
- package/dist/chunk-35NQ4PLQ.mjs +2 -0
- package/dist/chunk-3KJHLHUO.mjs +2 -0
- package/dist/chunk-3NJACR4W.mjs +2 -0
- package/dist/chunk-4AV456RQ.mjs +2 -0
- package/dist/chunk-4OZWXZE5.mjs +5 -0
- package/dist/chunk-5XYHDBJ5.mjs +2 -0
- package/dist/chunk-5ZJA7CXT.mjs +2 -0
- package/dist/chunk-6A53MZYZ.mjs +2 -0
- package/dist/chunk-6EXH3ORZ.mjs +166 -0
- package/dist/chunk-6EZ7FNIK.mjs +3 -0
- package/dist/{chunk-UXUK4PMC.mjs → chunk-6QBHU4DF.mjs} +1 -1
- package/dist/{chunk-6U2SLSDN.mjs → chunk-6VTU6KEO.mjs} +1 -1
- package/dist/chunk-B4P2CM2J.mjs +3 -0
- package/dist/chunk-BPL64HGA.mjs +4 -0
- package/dist/chunk-BVEFGE4B.mjs +2 -0
- package/dist/chunk-BZ5RAF7L.mjs +2 -0
- package/dist/chunk-CRJEG7MT.mjs +2 -0
- package/dist/{chunk-B3VTYBYR.mjs → chunk-D4CKRD3V.mjs} +91 -91
- package/dist/chunk-D4EURAX4.mjs +4 -0
- package/dist/chunk-DQCE7TJY.mjs +5 -0
- package/dist/chunk-DR73Y2UJ.mjs +3 -0
- package/dist/{chunk-TMYZB6AV.mjs → chunk-EKNHM3P4.mjs} +1 -1
- package/dist/{chunk-DB4WKGYF.mjs → chunk-ERLAIBOA.mjs} +2 -2
- package/dist/chunk-EURLTOTZ.mjs +4 -0
- package/dist/chunk-FJYN7RTH.mjs +4 -0
- package/dist/chunk-FWNRPMCJ.mjs +12 -0
- package/dist/chunk-FWW4CSAZ.mjs +2 -0
- package/dist/{chunk-2B5E4CDJ.mjs → chunk-GPIWQ4X4.mjs} +1 -1
- package/dist/chunk-GY3FAUVM.mjs +2 -0
- package/dist/chunk-HLYV7RIH.mjs +2 -0
- package/dist/chunk-HMYTM3GT.mjs +15 -0
- package/dist/chunk-IA4PSIMD.mjs +2 -0
- package/dist/chunk-JEUK3ZO7.mjs +2 -0
- package/dist/chunk-JVHHHGEA.mjs +3 -0
- package/dist/chunk-KTKHRC6H.mjs +2 -0
- package/dist/chunk-L7UP52JO.mjs +2 -0
- package/dist/chunk-MHW7ZKOU.mjs +2 -0
- package/dist/chunk-N76HWBA3.mjs +10 -0
- package/dist/chunk-N7AZZLGT.mjs +548 -0
- package/dist/chunk-NAMN3RAF.mjs +2 -0
- package/dist/{chunk-YXAUQPVK.mjs → chunk-NFMCP2HI.mjs} +3 -3
- package/dist/chunk-NG375ILQ.mjs +2 -0
- package/dist/chunk-NVRNLK25.mjs +6 -0
- package/dist/chunk-NWFBE2YA.mjs +2 -0
- package/dist/chunk-NWR2LT5B.mjs +2 -0
- package/dist/chunk-OJKMINIU.mjs +20 -0
- package/dist/chunk-OUUP3WKT.mjs +2 -0
- package/dist/chunk-OW5NWPOJ.mjs +10 -0
- package/dist/chunk-PAREWQGB.mjs +4 -0
- package/dist/chunk-POQSE4C2.mjs +2 -0
- package/dist/chunk-PUOQ65NC.mjs +2 -0
- package/dist/{chunk-Z52HTUW7.mjs → chunk-PVER7LSC.mjs} +2 -2
- package/dist/chunk-PZDLJJTJ.mjs +3 -0
- package/dist/chunk-Q47PLKIJ.mjs +15 -0
- package/dist/chunk-Q4UEPUWF.mjs +2 -0
- package/dist/chunk-QKXMPUXC.mjs +2 -0
- package/dist/chunk-QOUEFUCH.mjs +16 -0
- package/dist/chunk-RFDZXFJF.mjs +13 -0
- package/dist/chunk-RKPWLGZ3.mjs +4 -0
- package/dist/chunk-RMECZA2K.mjs +2 -0
- package/dist/{chunk-EUX7IC5J.mjs → chunk-SQ6Y2ZMA.mjs} +2 -2
- package/dist/chunk-SX4LJYT6.mjs +8 -0
- package/dist/chunk-SXHBYZST.mjs +16 -0
- package/dist/chunk-TANZRINB.mjs +2 -0
- package/dist/chunk-TEZAWDSQ.mjs +2 -0
- package/dist/chunk-UBBRTJ2R.mjs +24 -0
- package/dist/chunk-UFNYFFKO.mjs +20 -0
- package/dist/chunk-UGWYKHBL.mjs +170 -0
- package/dist/chunk-UKSHDZZ6.mjs +2 -0
- package/dist/chunk-UMHUSOPJ.mjs +2 -0
- package/dist/chunk-UNOYVIYR.mjs +2 -0
- package/dist/chunk-V6RIYQZZ.mjs +4 -0
- package/dist/chunk-VJPFVNNW.mjs +15 -0
- package/dist/chunk-VS3ZMVGX.mjs +5 -0
- package/dist/chunk-VTKNEYT3.mjs +6 -0
- package/dist/chunk-VXACTLO3.mjs +3 -0
- package/dist/chunk-W3BGBJQW.mjs +2 -0
- package/dist/chunk-YI43RG4P.mjs +2 -0
- package/dist/chunk-YQGT4AB2.mjs +6 -0
- package/dist/chunk-ZB4H7ZN4.mjs +2 -0
- package/dist/{chunk-ACOPDCNB.mjs → chunk-ZHEHPMBK.mjs} +1 -1
- package/dist/chunk-ZTHICSSF.mjs +2 -0
- package/dist/chunk-ZUNVAXLH.mjs +2 -0
- package/dist/chunk-ZWPMCK7P.mjs +2 -0
- package/dist/cli.mjs +1 -1
- package/dist/server.mjs +1 -1
- package/dist/{chunk-EVJ3BX3M.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 +14 -14
- package/kit/math.js +18 -2
- package/kit/report.css +500 -151
- package/kit/runtime.js +1720 -170
- package/kit/state.js +10 -1
- package/kit/tables.js +172 -37
- package/kit/ui.js +166 -27
- 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 +156 -0
- package/packs/gallery/countdown/preview.svg +1 -0
- package/packs/gallery/countdown/style.css +130 -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 +295 -0
- package/packs/gallery/habit/preview.svg +1 -0
- package/packs/gallery/habit/style.css +246 -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 +351 -0
- package/packs/gallery/heatmap/preview.svg +1 -0
- package/packs/gallery/heatmap/style.css +201 -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 +102 -0
- package/packs/gallery/note/preview.svg +1 -0
- package/packs/gallery/note/style.css +76 -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 +238 -0
- package/packs/gallery/recent/preview.svg +1 -0
- package/packs/gallery/recent/style.css +158 -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 +138 -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 +166 -0
- package/packs/gallery/stats/preview.svg +1 -0
- package/packs/gallery/stats/style.css +151 -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 +185 -0
- package/packs/gallery/today/preview.svg +1 -0
- package/packs/gallery/today/style.css +120 -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 +342 -0
- package/packs/gallery/todos/preview.svg +1 -0
- package/packs/gallery/todos/style.css +267 -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 +312 -0
- package/packs/gallery/weather/preview.svg +1 -0
- package/packs/gallery/weather/style.css +258 -0
- package/packs/gallery/weather/template.html +3 -0
- package/packs/gallery/weather/writing.md +26 -0
- package/packs/gallery-soft/pack.json +8 -0
- package/release.json +13 -11
- package/sdk/doc-kit.d.ts +404 -7
- package/sdk/doc-state.d.ts +2 -0
- package/skill/SKILL.md +71 -26
- package/skill/references/block-script.md +140 -0
- package/skill/references/building-blocks.md +257 -0
- package/skill/references/example-report.html +1 -1
- package/skill/references/extensions.md +59 -0
- package/skill/references/pages-and-data.md +221 -0
- package/skill/references/writing-html.md +9 -7
- package/skill/sdk/doc-kit.d.ts +404 -7
- package/skill/sdk/doc-state.d.ts +2 -0
- package/web/assets/index-BK2e_07w.js +13 -0
- package/web/assets/index-CWFI83mF.css +1 -0
- package/web/index.html +2 -2
- package/browser/editor/components/callout/page.mjs +0 -13
- package/dist/chunk-2PBALTR3.mjs +0 -57
- package/dist/chunk-3LA3EMDE.mjs +0 -15
- package/dist/chunk-5FRMCDPY.mjs +0 -16
- package/dist/chunk-5LEK2CBS.mjs +0 -2
- package/dist/chunk-5OFN5AHC.mjs +0 -2
- package/dist/chunk-5SIYS5HN.mjs +0 -2
- package/dist/chunk-5TEK3RAD.mjs +0 -2
- package/dist/chunk-6CYG3Z4V.mjs +0 -2
- package/dist/chunk-7GHT2UCA.mjs +0 -15
- package/dist/chunk-7QQBR7PB.mjs +0 -2
- package/dist/chunk-ATCJYAR4.mjs +0 -2
- package/dist/chunk-C7HWOBIF.mjs +0 -2
- package/dist/chunk-E7VYDG2X.mjs +0 -2
- package/dist/chunk-EZY3WC6Z.mjs +0 -15
- package/dist/chunk-FQGQH4KM.mjs +0 -2
- package/dist/chunk-G7TOXONE.mjs +0 -6
- package/dist/chunk-GPF4YWWB.mjs +0 -9
- package/dist/chunk-GYQV7Y4J.mjs +0 -120
- package/dist/chunk-HMHK3EQ6.mjs +0 -2
- package/dist/chunk-HQQMJCQJ.mjs +0 -10
- package/dist/chunk-IERUOGC3.mjs +0 -6
- package/dist/chunk-ITNLYXXV.mjs +0 -3
- package/dist/chunk-L4DVONOG.mjs +0 -2
- package/dist/chunk-LAE5NQ4B.mjs +0 -2
- package/dist/chunk-LC7YNQFG.mjs +0 -2
- package/dist/chunk-LHTFLRB6.mjs +0 -4
- package/dist/chunk-NFIBI4IP.mjs +0 -26
- package/dist/chunk-NSKUTQ5J.mjs +0 -5
- package/dist/chunk-O52JMOCZ.mjs +0 -2
- package/dist/chunk-P2CAZPDP.mjs +0 -3
- package/dist/chunk-QMQUXTU4.mjs +0 -12
- package/dist/chunk-QVWVFC5K.mjs +0 -6
- package/dist/chunk-QYKCJ7FG.mjs +0 -8
- package/dist/chunk-QZY6Q64C.mjs +0 -2
- package/dist/chunk-TDQP3DKQ.mjs +0 -10
- package/dist/chunk-TX6JH7TR.mjs +0 -2
- package/dist/chunk-UNUEWH4S.mjs +0 -2
- package/dist/chunk-V4CPWKMZ.mjs +0 -2
- package/dist/chunk-VACRB2NE.mjs +0 -3
- package/dist/chunk-W63L7367.mjs +0 -7
- package/dist/chunk-W7CXPCRV.mjs +0 -6
- package/dist/chunk-XINNG4F2.mjs +0 -4
- package/dist/chunk-YL2DPWVS.mjs +0 -4
- package/dist/chunk-YZ5Z6H4W.mjs +0 -4
- package/dist/chunk-ZBIM6ARY.mjs +0 -216
- package/skill/references/building-components.md +0 -327
- package/web/assets/index-B6Ai3wsa.js +0 -13
- package/web/assets/index-SYPC3EZy.css +0 -1
|
@@ -1,14 +1,19 @@
|
|
|
1
1
|
import { OLD_OUTLINE_OPEN_KEY, OLD_PREFERENCES_KEY, OUTLINE_OPEN_KEY, PREFERENCES_KEY } from "../../shared/preferences.mjs";
|
|
2
|
+
import { LOOK_ATTRIBUTES } from "../../shared/document-look.mjs";
|
|
3
|
+
import { ADD, HANDLE } from "./handle-sizes.mjs";
|
|
2
4
|
|
|
3
5
|
// The right side of the page while it is edited (docs/editor.md, "The outline and the right side"): the
|
|
4
6
|
// outline (目录, outline/) docked at the window's right edge, the cards of 批注 (annotate/) between it and
|
|
5
7
|
// the column, and where the body column goes beside them. The outline is a panel at the window's right
|
|
6
8
|
// edge, in full (its list, 200px unless the reader dragged its guide wider or narrower: `outlineWidth`;
|
|
7
|
-
// the
|
|
8
|
-
//
|
|
9
|
+
// the list 8px in, its guide a little further in, close to its top level's titles: outline/list.mjs
|
|
10
|
+
// LIST) or as its strip (36px: a short line a heading, its card shown while the pointer is
|
|
11
|
+
// on it), as the room allows; or as its strip wherever the reader collapsed it (a click on its guide:
|
|
12
|
+
// `collapsed`, the preference outlineCollapsed, until a click on the guide in the strip's card takes it
|
|
13
|
+
// back, which gives the list only where the room allows it).
|
|
9
14
|
//
|
|
10
15
|
// One rule places the column: in the middle of what the outline leaves of the page, as far from the
|
|
11
|
-
// window's left edge as from the outline (its
|
|
16
|
+
// window's left edge as from the outline (its list's edge, or its strip). With the outline the rooms at the
|
|
12
17
|
// column's two sides are the same, and they stay the same as the guide is dragged (each gives or takes
|
|
13
18
|
// half of what the list takes or gives) and as the window is resized; without it the column is
|
|
14
19
|
// centered in the page as ever. Each room is the edge room at least (64: the block handle at the left,
|
|
@@ -48,18 +53,29 @@ import { OLD_OUTLINE_OPEN_KEY, OLD_PREFERENCES_KEY, OUTLINE_OPEN_KEY, PREFERENCE
|
|
|
48
53
|
// column stands where it will stay from the first paint, and by setMargin() after that.
|
|
49
54
|
// When they move the column, the page hears a resize, so what stands over the text (the format bar, a
|
|
50
55
|
// selection's strips, a card) is placed again.
|
|
56
|
+
//
|
|
57
|
+
// The edge room is also the page's gutters (the kit's --doc-page-gutter and --doc-wide-gutter, page.css),
|
|
58
|
+
// set by MARGIN_STYLE, which the edit service puts in the page's head: the column the kit lets show
|
|
59
|
+
// (data-doc-ready, the frame a workbench swaps the page in on) stands where the editor keeps it, its lines
|
|
60
|
+
// broken as they stay, before the editor has started, the outline off and no 批注 as much as with them.
|
|
61
|
+
// (Until 2026-11-09 the handle put them in once the page edited: in a workbench with its sidebar open, a
|
|
62
|
+
// page 795px wide came in with the kit's 20px gutters, its column 712 wide and 42 in, and moved to 667 and
|
|
63
|
+
// 64 a few frames later, its lines breaking anew: the user's report on 0.1.1.)
|
|
51
64
|
|
|
52
65
|
/**
|
|
53
|
-
* The numbers: the edge room (the least room either side of the column keeps
|
|
66
|
+
* The numbers: the edge room (the least room either side of the column keeps, and the page's gutters:
|
|
67
|
+
* the bar's square left of the block handle's grip, the grip, its gap and room to breathe, 64), the least it gives up
|
|
54
68
|
* to (the block handle's: its 38px, its 12px gap, 2px), the column, the least a full-width column
|
|
55
69
|
* keeps, the outline in full (its default width, the least and the most it is dragged to), its
|
|
56
|
-
*
|
|
57
|
-
*
|
|
70
|
+
* list's inset in its panel (`guide`: the column's right room ends there, at the list's edge, its
|
|
71
|
+
* guide's hairline LIST.guide further in, outline/list.mjs; the guide stood there
|
|
72
|
+
* until 2026-11-07, the numbers kept so the forms switch at the same widths), how far left of the guide's
|
|
73
|
+
* hairline its grip reaches (and how far short of the list what stands in the column's right room stays), its strip, the hysteresis; how far right of the column a card of 批注 stands (the button beside
|
|
58
74
|
* a block, past a section's strip, ends 52px out, and a card under the pointer comes 5px left: 3px
|
|
59
75
|
* clear; one focused comes 20px left, and no button shows then), a card's width, the least it gives up
|
|
60
|
-
* to, and the room past it (clear of the outline's guide and grip).
|
|
76
|
+
* to, and the room past it (clear of the outline's list: its guide and grip).
|
|
61
77
|
*/
|
|
62
|
-
export const MARGIN = Object.freeze({ edge:
|
|
78
|
+
export const MARGIN = Object.freeze({ edge: ADD.width + HANDLE.width + HANDLE.gap + 12, start: 52, column: 712, least: 560, full: 200, fullMin: 160, fullMax: 360, guide: 8, grip: 4, strip: 36, hysteresis: 16, lane: 60, card: 308, cardLeast: 240, cardEnd: 20 });
|
|
63
79
|
|
|
64
80
|
/**
|
|
65
81
|
* The outline's width in full for the reader's choice `chosen` (px; 0 or none: the default), within
|
|
@@ -71,19 +87,20 @@ export function outlineWidth(chosen, { full = 200, fullMin = 160, fullMax = 360
|
|
|
71
87
|
|
|
72
88
|
/**
|
|
73
89
|
* Where the right side's parts go on a page `width` px wide (its window less its scrollbar): `outline`,
|
|
74
|
-
* whether the outline is on, `
|
|
75
|
-
*
|
|
76
|
-
* (a form it laid out is kept for
|
|
90
|
+
* whether the outline is on, `collapsed`, whether the reader collapsed it to its strip, `notes`,
|
|
91
|
+
* whether the page has 批注, `full`, its width in full (outlineWidth), `wide`, a report read full
|
|
92
|
+
* width, `was`, the layout given last for the same request (a form it laid out is kept for
|
|
93
|
+
* `hysteresis` px under the width it needs).
|
|
77
94
|
* Returns { dock: the outline's width at the window's right edge (0, its strip's or its list's),
|
|
78
95
|
* outline: its form, "full" | "strip" | null, room: what the outline takes of the page's width beside
|
|
79
|
-
* the column's rooms (the list's less its
|
|
96
|
+
* the column's rooms (the list's less its inset, the strip's, 0), side: the least room either
|
|
80
97
|
* side of the column keeps, left: the room at the column's left on this page, right: the room right of
|
|
81
98
|
* it to the window's edge (its own and the outline's), column: its width, cards: the width of a card
|
|
82
99
|
* of 批注 standing right of it (0: they fold into markers), cardRoom: what the page's rule keeps right of
|
|
83
100
|
* the column for them (0: none), floor: the least room at its left }. Written with no outside name, so
|
|
84
101
|
* the page's head can carry it as it is (EARLY_MARGIN).
|
|
85
102
|
*/
|
|
86
|
-
export function marginLayout({ width, outline = false, notes = false, wide = false, was = null, edge = 64, start = 52, column = 712, least = 560, full = 200, guide = 8, strip = 36, hysteresis = 16, lane = 60, card = 308, cardLeast = 240, cardEnd = 20 }) {
|
|
103
|
+
export function marginLayout({ width, outline = false, collapsed = false, notes = false, wide = false, was = null, edge = 64, start = 52, column = 712, least = 560, full = 200, guide = 8, strip = 36, hysteresis = 16, lane = 60, card = 308, cardLeast = 240, cardEnd = 20 }) {
|
|
87
104
|
const body = wide ? least : column;
|
|
88
105
|
// The column in the middle of what the outline leaves, its rooms `side` at least (narrower only below
|
|
89
106
|
// that), and left of there as far as a card's room asks, down to `start`, the card giving what is short.
|
|
@@ -99,17 +116,23 @@ export function marginLayout({ width, outline = false, notes = false, wide = fal
|
|
|
99
116
|
if (!outline) return placed(null, 0, 0, edge);
|
|
100
117
|
// In full while the list, as wide as the reader gave it, leaves the column the handle's room at both
|
|
101
118
|
// sides (its rooms the edge room, less down to the handle's where the page is short); a form kept
|
|
102
|
-
// under the width it needs (the hysteresis) narrows the column by what is short. Else
|
|
103
|
-
|
|
119
|
+
// under the width it needs (the hysteresis) narrows the column by what is short. Else, or collapsed by
|
|
120
|
+
// the reader, its strip.
|
|
121
|
+
const spare = width + guide - body; // the page beside the column, the list's room counted from its edge (its inset `guide`)
|
|
104
122
|
const kept = was?.outline === "full" ? hysteresis : 0;
|
|
105
|
-
if (spare + kept >= 2 * start + full) return placed("full", full, full - guide, Math.max(start, Math.min(edge, (spare - full) / 2)));
|
|
123
|
+
if (!collapsed && spare + kept >= 2 * start + full) return placed("full", full, full - guide, Math.max(start, Math.min(edge, (spare - full) / 2)));
|
|
106
124
|
return placed("strip", strip, strip, edge);
|
|
107
125
|
}
|
|
108
126
|
|
|
109
127
|
const SLIDE = 200; // ms: the column's slide as the page comes to have 批注 or has none left
|
|
110
128
|
|
|
111
|
-
/**
|
|
129
|
+
/**
|
|
130
|
+
* The page's rules for the room: its gutters the edge room, and on screen the column placed (and
|
|
131
|
+
* narrowed only when it must).
|
|
132
|
+
*/
|
|
112
133
|
export const MARGIN_STYLE = `
|
|
134
|
+
/* The handle's room beside the page's blocks, the page's gutters from its first paint (a page the editor edits: this sheet is in the head the edit service serves); resize/ and the workbench's sidebar read --ge-edge-room. */
|
|
135
|
+
:root { --ge-edge-room: ${MARGIN.edge}px; --doc-page-gutter: var(--ge-edge-room); --doc-wide-gutter: var(--ge-edge-room); }
|
|
113
136
|
@media screen {
|
|
114
137
|
:root[data-ge-margin] {
|
|
115
138
|
/* The least room either side of the column keeps (marginLayout's side: the edge room, less where the page is short of it, down to the handle's). */
|
|
@@ -143,8 +166,9 @@ const roomCss = ({ room, side, cardRoom = 0, floor = side }) => `:root[data-ge-m
|
|
|
143
166
|
|
|
144
167
|
// The head's script (EARLY_MARGIN): the outline's room before the page shows, when the report has it
|
|
145
168
|
// on (`keys.open`: the reports that have it on, shared/preferences.mjs outlineOpen; `slug`: this page's), as
|
|
146
|
-
// wide as the reader's preferences say (`keys.preferences`: outlineWidth,
|
|
147
|
-
// and the cards' room, when it has 批注 (`notes`, the
|
|
169
|
+
// wide as the reader's preferences say and in the form they chose (`keys.preferences`: outlineWidth,
|
|
170
|
+
// outlineCollapsed, the same for every report), and the cards' room, when it has 批注 (`notes`, the
|
|
171
|
+
// edit service's word).
|
|
148
172
|
// Never on a page opened on its own in a frame (?solo, the 写作偏好 dialog), which has none.
|
|
149
173
|
// In the head the page has no content yet, so no scrollbar: its width is read again at
|
|
150
174
|
// DOMContentLoaded, when the content is in and the kit has not shown it yet (a frame later), unless the
|
|
@@ -157,13 +181,17 @@ function earlyMargin(layout, widthOf, numbers, keys, slug, notes, room, early, c
|
|
|
157
181
|
const outline = Array.isArray(open) && open.includes(slug);
|
|
158
182
|
if (!outline && !notes) return;
|
|
159
183
|
const prefs = JSON.parse(read(keys.preferences, keys.oldPreferences) || "{}") || {};
|
|
160
|
-
const asked = { outline, notes, outlineWidth: Number(prefs.outlineWidth) || 0 };
|
|
184
|
+
const asked = { outline, notes, outlineWidth: Number(prefs.outlineWidth) || 0, collapsed: prefs.outlineCollapsed === true };
|
|
161
185
|
const root = document.documentElement;
|
|
162
186
|
const sheet = document.createElement("style");
|
|
163
187
|
sheet.setAttribute("data-doc-dev", "");
|
|
164
188
|
sheet.setAttribute(room, "");
|
|
165
189
|
const lay = () => {
|
|
166
|
-
|
|
190
|
+
// The column the kit's stylesheet gives (a document's look, its 正文宽度 alone, makes it another
|
|
191
|
+
// than 712px: src/shared/document-look.mjs), read as the editor reads it (numbers() below); the kit's
|
|
192
|
+
// stylesheet stands before this script in the head, so it is in.
|
|
193
|
+
const column = parseFloat(getComputedStyle(root).getPropertyValue("--doc-content-max-width")) || numbers.column;
|
|
194
|
+
const given = layout({ ...numbers, column, width: root.clientWidth, outline, collapsed: asked.collapsed, notes, full: widthOf(asked.outlineWidth, numbers), wide: root.getAttribute("data-doc-width") === "full" });
|
|
167
195
|
sheet.textContent = css(given);
|
|
168
196
|
sheet.setAttribute(early, JSON.stringify({ given, asked }));
|
|
169
197
|
};
|
|
@@ -186,7 +214,7 @@ export const earlyMarginScript = (slug, { notes = false } = {}) => {
|
|
|
186
214
|
|
|
187
215
|
// ---------- on the page ----------
|
|
188
216
|
|
|
189
|
-
const asked = { outline: false, notes: false, outlineWidth: 0 }; // what the outline and 批注 ask for
|
|
217
|
+
const asked = { outline: false, notes: false, outlineWidth: 0, collapsed: false }; // what the outline and 批注 ask for
|
|
190
218
|
const listeners = new Set();
|
|
191
219
|
let now = null; // the layout given last
|
|
192
220
|
let request = null; // what it was given for: { outline, wide } (the outline's width keeps the form laid out)
|
|
@@ -311,14 +339,16 @@ function start() {
|
|
|
311
339
|
addEventListener("resize", resized);
|
|
312
340
|
// The page's width changes without the window's too: its scrollbar comes or goes.
|
|
313
341
|
new ResizeObserver(resized).observe(document.documentElement);
|
|
314
|
-
// A report read full width, or no longer
|
|
315
|
-
|
|
342
|
+
// A report read full width, or no longer; the document's look changed (its column's width with its
|
|
343
|
+
// 正文宽度, never its 字体大小: the kit's ui.js puts it on the root, src/shared/document-look.mjs).
|
|
344
|
+
new MutationObserver(() => apply()).observe(document.documentElement, { attributes: true, attributeFilter: ["data-doc-width", ...Object.values(LOOK_ATTRIBUTES)] });
|
|
316
345
|
}
|
|
317
346
|
|
|
318
347
|
/**
|
|
319
348
|
* Ask for room: { outline } (whether it shows), { outlineWidth } (its width in full as the reader
|
|
320
|
-
* chose it, px; 0: the default), {
|
|
321
|
-
* changes it). The layout is given at once and
|
|
349
|
+
* chose it, px; 0: the default), { collapsed } (the reader collapsed it to its strip), { notes }
|
|
350
|
+
* (whether the page has 批注: the column slides when that changes it). The layout is given at once and
|
|
351
|
+
* again whenever the page's width changes it.
|
|
322
352
|
*/
|
|
323
353
|
export function setMargin(part) {
|
|
324
354
|
start();
|
|
@@ -331,7 +361,13 @@ export function setMargin(part) {
|
|
|
331
361
|
/** The layout given last ({ dock, outline, room, side, left, right, column, cards, cardRoom, floor }; see marginLayout). */
|
|
332
362
|
export const margin = () => now ?? layoutFor(isWide(), null);
|
|
333
363
|
|
|
334
|
-
/**
|
|
364
|
+
/**
|
|
365
|
+
* Whether the page's room gives the outline its list in full now, the reader's collapse aside: what a
|
|
366
|
+
* click on the guide in the strip's card would bring (the whole width needed, as for any strip going up).
|
|
367
|
+
*/
|
|
368
|
+
export const listFits = () => marginLayout({ ...MARGIN, width: pageWidth(), ...numbers(), ...asked, outline: true, collapsed: false, full: outlineWidth(asked.outlineWidth, MARGIN), wide: isWide(), was: null }).outline === "full";
|
|
369
|
+
|
|
370
|
+
/** How far right of the column what stands in its right room may reach, by `layout` (marginLayout): MARGIN.grip short of the outline's list (its guide and grip further in), or of its strip, or of the window's edge. */
|
|
335
371
|
export const rightRoom = ({ right, room } = margin()) => right - room - MARGIN.grip;
|
|
336
372
|
|
|
337
373
|
/** Call `listener(layout)` whenever the layout changes (the outline's form or width, the column's least rooms, the cards' width). */
|
|
@@ -28,15 +28,14 @@ const STYLE = `
|
|
|
28
28
|
.nmedia-menu-tab.active::after { content: ""; position: absolute; left: 8px; right: 8px; bottom: 0; border-bottom: 2px solid var(--c-texPri); }
|
|
29
29
|
.nmedia-menu-body { padding: 12px 12px 10px; }
|
|
30
30
|
.nmedia-menu-inner { display: flex; justify-content: center; padding: 4px; }
|
|
31
|
-
|
|
32
|
-
.nmedia-menu-upload
|
|
31
|
+
/* Its buttons are the editor's one button look (look.mjs BUTTONS): the pale blue primary, here what the tab does. */
|
|
32
|
+
.nmedia-menu-upload, .nmedia-menu-embed { width: 100%; font-size: 14px; }
|
|
33
33
|
.nmedia-menu-link { flex-direction: column; align-items: stretch; gap: 8px; }
|
|
34
34
|
.nmedia-menu-input { display: flex; align-items: center; gap: 4px; width: 100%; height: 28px; padding: 3px 6px; border-radius: 6px; background: var(--ca-bacSecTra); box-shadow: 0 0 0 1px var(--ca-borPriTra); box-sizing: border-box; }
|
|
35
35
|
.nmedia-menu-input:focus-within { box-shadow: var(--c-inpBluFocRin); }
|
|
36
36
|
.nmedia-menu-input input { flex: 1; min-width: 0; border: none; outline: none; background: transparent; padding: 0; font: inherit; font-size: 14px; line-height: 20px; color: var(--c-texPri); }
|
|
37
37
|
.nmedia-menu-input input::placeholder { color: var(--c-texTer); }
|
|
38
|
-
.nmedia-menu-embed {
|
|
39
|
-
.nmedia-menu-embed:hover { filter: brightness(.94); }
|
|
38
|
+
.nmedia-menu-embed { max-width: 300px; margin: 0 auto; }
|
|
40
39
|
.nmedia-menu-caption { margin: -6px 0 4px; padding: 4px 0; font-size: 12px; line-height: 1.4; color: var(--c-texSec); text-align: center; }
|
|
41
40
|
.nmedia-menu.dragover .nmedia-menu-body { background: var(--ca-bluBacSecTra); }
|
|
42
41
|
.nmedia-menu-choose { margin-top: 8px; }
|
|
@@ -76,10 +75,10 @@ export function openMediaMenu(anchor, { tabs, width, upload = {}, link = {}, onU
|
|
|
76
75
|
`<div class="nmedia-menu-tab-wrap"><div role="tab" class="nmedia-menu-tab${key === current ? " active" : ""}" aria-selected="${key === current}" data-tab="${key}">${esc(label)}</div></div>`).join("")}</div>` : "")
|
|
77
76
|
+ `<div class="nmedia-menu-body">${current === "upload"
|
|
78
77
|
? (upload.primary
|
|
79
|
-
? `<div class="nmedia-menu-inner nmedia-menu-link"><div role="button" tabindex="0" class="nmedia-menu-embed nmedia-menu-choose" data-do="upload">${esc(upload.label ?? t("选择文件"))}</div>${upload.caption ? `<div class="nmedia-menu-caption">${esc(upload.caption)}</div>` : ""}</div>`
|
|
80
|
-
: `<div class="nmedia-menu-inner"><div role="button" tabindex="0" class="nmedia-menu-upload" data-do="upload">${esc(upload.label ?? t("上传文件"))}</div></div>`)
|
|
78
|
+
? `<div class="nmedia-menu-inner nmedia-menu-link"><div role="button" tabindex="0" class="ge-btn nmedia-menu-embed nmedia-menu-choose" data-primary data-do="upload">${esc(upload.label ?? t("选择文件"))}</div>${upload.caption ? `<div class="nmedia-menu-caption">${esc(upload.caption)}</div>` : ""}</div>`
|
|
79
|
+
: `<div class="nmedia-menu-inner"><div role="button" tabindex="0" class="ge-btn nmedia-menu-upload" data-primary data-do="upload">${esc(upload.label ?? t("上传文件"))}</div></div>`)
|
|
81
80
|
: `<div class="nmedia-menu-inner nmedia-menu-link"><div class="nmedia-menu-input"><input type="url" placeholder="${esc(link.placeholder ?? t("粘贴链接…"))}" autocomplete="off"></div>`
|
|
82
|
-
+ `<div role="button" tabindex="0" class="nmedia-menu-embed" data-do="embed">${esc(link.button ?? t("嵌入链接"))}</div>`
|
|
81
|
+
+ `<div role="button" tabindex="0" class="ge-btn nmedia-menu-embed" data-primary data-do="embed">${esc(link.button ?? t("嵌入链接"))}</div>`
|
|
83
82
|
+ (link.caption ? `<div class="nmedia-menu-caption">${esc(link.caption)}</div>` : "") + "</div>"}</div>`;
|
|
84
83
|
const input = el.querySelector("input");
|
|
85
84
|
if (input) {
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { Z } from "../../shared/layers.mjs";
|
|
2
2
|
import { addStyle, element, mount } from "./ui.mjs";
|
|
3
3
|
import { hideTooltip, tooltip } from "./tooltip.mjs";
|
|
4
|
-
import { svg } from "../components/icons.mjs";
|
|
4
|
+
import { SECTION_ICON, svg } from "../components/icons.mjs";
|
|
5
5
|
import { t } from "../../shared/i18n/index.mjs";
|
|
6
6
|
|
|
7
7
|
// The editor's menu card, used by the "/" menu (slash-menu/: block types, filtered as the reader
|
|
@@ -12,16 +12,33 @@ import { t } from "../../shared/i18n/index.mjs";
|
|
|
12
12
|
// the page with a block selected). A press on a row never moves the caret. Colors follow the
|
|
13
13
|
// report's light or dark theme (light-dark()). A row may open a submenu (Notion's 颜色 ›): a second
|
|
14
14
|
// card right of it, opened by resting on the row, a click, Enter or →, and closed by ←, by resting
|
|
15
|
-
// on another row, or with the menu; while it is open from the keys they move in it.
|
|
15
|
+
// on another row, or with the menu; while it is open from the keys they move in it. A row that both
|
|
16
|
+
// runs and opens a submenu (a split row: a table's 一键优化 ›) is two parts side by side, each with
|
|
17
|
+
// its own grey under the pointer: its words, which a click or Enter runs, and its › at its right,
|
|
18
|
+
// which opens the submenu (resting on it, a click, or →); resting on its words opens nothing.
|
|
19
|
+
//
|
|
20
|
+
// A card is as wide as its rows (Notion's menus: 180px at least), up to FIT.most, past which a row's
|
|
21
|
+
// words are cut by an ellipsis, so a short submenu (一键优化 ›: 自动调整列宽, 识别数字列; 对齐 ›) is no
|
|
22
|
+
// wider than its words; it once took 265px whatever it held. A card whose rows change as it is used
|
|
23
|
+
// keeps the one width its caller gives (`width`: the block menu's grid, the "/" menu, a code block's
|
|
24
|
+
// languages), or SEARCHING when it has a search field and gives none, so it never jumps as rows come
|
|
25
|
+
// and go.
|
|
26
|
+
|
|
27
|
+
const FIT = { least: 180, most: 320 }; // a card with no width given: as wide as its rows, between these
|
|
28
|
+
const SEARCHING = 240; // a card with a search field and no width given: its rows filtered as typed
|
|
16
29
|
|
|
17
30
|
const STYLE = `
|
|
18
31
|
.ge-pop {
|
|
19
|
-
position: fixed; left: 0; top: 0; z-index: ${Z.menu}; width:
|
|
32
|
+
position: fixed; left: 0; top: 0; z-index: ${Z.menu}; width: max-content; min-width: ${FIT.least}px; max-width: min(${FIT.most}px, calc(100vw - 16px)); max-height: calc(100vh - 24px);
|
|
20
33
|
overflow-x: hidden; overflow-y: auto; padding: 4px 0; border-radius: 10px; background: var(--ge-bg); color: var(--ge-tx);
|
|
21
34
|
box-shadow: var(--ge-shadow-pop);
|
|
22
35
|
font: 14px/1.2 ui-sans-serif, -apple-system, BlinkMacSystemFont, "Segoe UI Variable Display", "Segoe UI", Helvetica, "PingFang SC", "Microsoft YaHei", Arial, sans-serif;
|
|
23
36
|
user-select: none; scrollbar-width: thin; scrollbar-color: var(--ge-line-strong) transparent; animation: ge-pop-in .12s ease-out;
|
|
24
37
|
}
|
|
38
|
+
/* A width given (data-sized: opts.width, placed by place()): that width, whatever the rows hold. */
|
|
39
|
+
.ge-pop[data-sized] { min-width: 0; max-width: calc(100vw - 16px); }
|
|
40
|
+
/* A short list of one kind of word (a card's 大小 ›: 4 × 2): only as wide as its rows, no 180px floor. */
|
|
41
|
+
.ge-pop[data-compact] { min-width: 0; }
|
|
25
42
|
@keyframes ge-pop-in { from { opacity: 0; transform: scale(.98); } }
|
|
26
43
|
@media (prefers-reduced-motion: reduce) { .ge-pop { animation: none; } }
|
|
27
44
|
.ge-pop-title { display: flex; align-items: center; gap: 8px; padding: 8px 12px; color: var(--ge-tx2); font-size: 12px; font-weight: 500; line-height: 14px; }
|
|
@@ -43,6 +60,7 @@ const STYLE = `
|
|
|
43
60
|
words and the hint takes what is left, cut short with an ellipsis where it is too long (an English
|
|
44
61
|
row's current choice once took the whole row, its label drawn 0px wide). */
|
|
45
62
|
.ge-pop-label:has(+ .ge-pop-hint) { flex: 1 0 auto; max-width: 100%; }
|
|
63
|
+
.ge-pop-of { color: var(--ge-tx3); }
|
|
46
64
|
.ge-pop-hint { flex: 0 1 auto; min-width: 0; overflow: hidden; text-overflow: ellipsis; color: var(--ge-tx3); font-size: 12px; white-space: nowrap; }
|
|
47
65
|
/* A row of a page (its title, the page it is under as its hint): a long title is what an ellipsis
|
|
48
66
|
cuts, and the page above keeps its words, up to a part of the row. */
|
|
@@ -52,9 +70,21 @@ const STYLE = `
|
|
|
52
70
|
.ge-pop-arrow { color: var(--ge-tx3); }
|
|
53
71
|
.ge-pop-arrow svg { display: block; width: 16px; height: 16px; fill: none; stroke: currentColor; stroke-width: 1.5; stroke-linecap: round; stroke-linejoin: round; }
|
|
54
72
|
.ge-pop-row[aria-expanded="true"] { background: var(--ge-hover); }
|
|
73
|
+
/* A split row (run and submenu both): its words (.ge-pop-main) and its › (.ge-pop-more, 32px wide:
|
|
74
|
+
the › where another submenu row has its own) side by side, 2px apart, each grey on its own: the words
|
|
75
|
+
when the row is highlighted and the pointer is not on the ›, the › under the pointer and while its
|
|
76
|
+
submenu is open. The row itself takes no grey. */
|
|
77
|
+
.ge-pop-row[data-split] { gap: 2px; padding: 0; }
|
|
78
|
+
.ge-pop-row[data-split][data-active], .ge-pop-row[data-split][aria-expanded="true"] { background: transparent; }
|
|
79
|
+
.ge-pop-main { flex: 1; min-width: 0; display: flex; align-items: center; gap: 8px; align-self: stretch; padding: 0 8px; border-radius: 6px; }
|
|
80
|
+
.ge-pop-more { flex: none; display: flex; align-items: center; justify-content: center; width: 32px; align-self: stretch; border-radius: 6px; }
|
|
81
|
+
.ge-pop-row[data-split][data-active]:not([data-more]) > .ge-pop-main,
|
|
82
|
+
.ge-pop-row[data-split][data-more] > .ge-pop-more,
|
|
83
|
+
.ge-pop-row[data-split][aria-expanded="true"] > .ge-pop-more { background: var(--ge-hover); }
|
|
55
84
|
.ge-pop-check svg { display: block; width: 16px; height: 16px; fill: none; stroke: currentColor; stroke-width: 1.7; stroke-linecap: round; stroke-linejoin: round; }
|
|
56
85
|
.ge-pop-sep { height: 1px; margin: 3px 12px 4px; background: var(--ge-line); }
|
|
57
|
-
|
|
86
|
+
/* A note wraps at the card's width and never widens it (no width of its own: contain). */
|
|
87
|
+
.ge-pop-note { contain: inline-size; padding: 0 12px 6px 40px; color: var(--ge-tx3); font-size: 12px; line-height: 1.5; }
|
|
58
88
|
.ge-pop-empty { padding: 8px 12px; color: var(--ge-tx3); }
|
|
59
89
|
/* What a row makes, shown beside it under the pointer (a component package's preview.svg). */
|
|
60
90
|
.ge-pop-preview { display: block; width: 240px; max-height: 180px; border-radius: 4px; object-fit: contain; background: var(--ge-bg); }
|
|
@@ -63,7 +93,7 @@ const STYLE = `
|
|
|
63
93
|
.ge-pop-search input:focus { box-shadow: inset 0 0 0 1px color-mix(in srgb, var(--ge-tx3) 60%, transparent); }
|
|
64
94
|
.ge-pop-search input::placeholder { color: var(--ge-tx3); }
|
|
65
95
|
/* Rows in a card that is there already (inside: a link card's pages): under what stands in it, as wide as it, no card of their own. */
|
|
66
|
-
.ge-pop[data-inside] { position: static; flex: 0 0 100%; width: auto; max-width: none; padding: 4px 0 0; border-radius: 0; background: none; box-shadow: none; animation: none; }
|
|
96
|
+
.ge-pop[data-inside] { position: static; flex: 0 0 100%; width: auto; min-width: 0; max-width: none; padding: 4px 0 0; border-radius: 0; background: none; box-shadow: none; animation: none; }
|
|
67
97
|
.ge-pop[data-inside] .ge-pop-row { width: 100%; margin-inline: 0; }
|
|
68
98
|
`;
|
|
69
99
|
|
|
@@ -78,8 +108,7 @@ export const ICONS = {
|
|
|
78
108
|
outer: svg('<rect x="3.25" y="3.25" width="13.5" height="13.5" rx="2.5" stroke-dasharray="2.2 2.2"/><rect x="6.5" y="6.5" width="7" height="7" rx="1.25"/>'),
|
|
79
109
|
section: svg(`${SECTION_LINES}<path d="M14.5 12v5M12 14.5h5"/>`),
|
|
80
110
|
dissolve: svg(`${SECTION_LINES}<path d="m12.75 12.75 3.5 3.5M16.25 12.75l-3.5 3.5"/>`), // section's plus, turned 45°
|
|
81
|
-
//
|
|
82
|
-
group: svg('<path d="M6 3.75h-.75a2 2 0 0 0-2 2v8.5a2 2 0 0 0 2 2H6M14 3.75h.75a2 2 0 0 1 2 2v8.5a2 2 0 0 1-2 2H14"/><path d="M7.25 7.75h5.5M7.25 12.25h5.5"/>'),
|
|
111
|
+
group: SECTION_ICON, // blocks gathered into a new section: their lines between brackets (components/icons.mjs)
|
|
83
112
|
center: svg('<rect x="5.25" y="4.25" width="9.5" height="11.5" rx="1.75"/><path d="M2.75 4v12M17.25 4v12"/>'),
|
|
84
113
|
full: svg('<rect x="3.25" y="4.25" width="13.5" height="11.5" rx="1.75"/><path d="m6.5 10h7M6.5 10l1.75-1.75M6.5 10l1.75 1.75M13.5 10l-1.75-1.75M13.5 10l-1.75 1.75"/>'),
|
|
85
114
|
reset: svg('<path d="M4.75 6.75A6 6 0 1 1 4 10.5"/><path d="M4.5 3.5v3.5H8"/>'),
|
|
@@ -99,23 +128,29 @@ const opened = new Set(); // the menus open now, whichever part of the page open
|
|
|
99
128
|
export const menuOpen = () => opened.size > 0;
|
|
100
129
|
|
|
101
130
|
/**
|
|
102
|
-
* items: rows { label, run, icon?, hint?, long?, current?, checked?, disabled?, note?, preview? } (
|
|
131
|
+
* items: rows { label, run, icon?, of?, hint?, long?, current?, checked?, disabled?, note?, preview? } (of: what
|
|
132
|
+
* the label is of, grey after it, a block's pack where two rows have one name; long:
|
|
103
133
|
* a label of any length, a page's title, cut before its hint is; current: the choice
|
|
104
134
|
* made, checked and not to be chosen again; checked: a switch that is on, checked and clicked to turn
|
|
105
|
-
* it off;
|
|
135
|
+
* it off; selected: the choice of a dropdown (a field's list of options), checked as current is but
|
|
136
|
+
* still a row to click, which closes the card with nothing changed; preview: { src, says }, a picture of what the row makes, where it has one, and a line on it,
|
|
106
137
|
* shown at the row's right while the pointer rests on it, notion-lite's row tooltip) (or { label, icon?, submenu:
|
|
107
138
|
* () => items, width?, search? } opening a submenu, with a search field at its top when `search` is
|
|
108
|
-
* given, as `opts.search` below, and `search.empty` the words shown when nothing is found
|
|
139
|
+
* given, as `opts.search` below, and `search.empty` the words shown when nothing is found; a row
|
|
140
|
+
* with both `run` and `submenu` is a split row: its words run, its › opens the submenu), titles
|
|
109
141
|
* { title, icon? }, separators { separator: true } and grids { node, cells, columns } (type-grid.mjs: the
|
|
110
142
|
* node shown as it is, its cells, buttons that act on their own click, highlighted as rows are).
|
|
111
|
-
* opts: { label, empty, highlight, onClose, around, side, width } — width: the card's, in px,
|
|
112
|
-
*
|
|
143
|
+
* opts: { label, empty, highlight, onClose, around, side, width } — width: the card's, in px, whatever
|
|
144
|
+
* its rows hold (the block menu: as wide as its grid of types), where without it the card is as wide
|
|
145
|
+
* as its rows (FIT; SEARCHING with a search field). around: the rect of the block a handle
|
|
113
146
|
* (the anchor) stands for; the menu keeps clear of that block: left of it beside the handle, else
|
|
114
147
|
* below or above it (scrolling inside when only part of it fits), and over it only when the block
|
|
115
148
|
* leaves no room at all. side: "right": beside the anchor, right of it (left of it when there is no
|
|
116
149
|
* room), level with it (a section's bar). Without either the menu stands below the anchor (the
|
|
117
150
|
* caret), or above it when there is no room below; align: "end", its right edge at the anchor's.
|
|
118
|
-
* icons: false, rows of words alone (no column for icons: a code block's languages
|
|
151
|
+
* icons: false, rows of words alone (no column for icons: a code block's languages; a row that opens a
|
|
152
|
+
* submenu says it of its own as `icons: false`, and `compact: true` makes it only as wide as its rows, no
|
|
153
|
+
* 180px floor: a card's 大小 ›); height: the
|
|
119
154
|
* card's greatest height, in px (its rows scroll inside it past that). stand(size): where the card
|
|
120
155
|
* stands, its { left, top } for its { width, height }, in place of all of these rules (a pasted
|
|
121
156
|
* address's 选择视图, by the format bar's rule: placement.mjs besideText). inside: an element the rows
|
|
@@ -139,25 +174,32 @@ export function createMenu() {
|
|
|
139
174
|
let subKeys = false; // opened from the keys: they move in it
|
|
140
175
|
let subTimer = 0;
|
|
141
176
|
let pointedRow = null;
|
|
177
|
+
let pointedMore = false; // the pointer on a split row's › (not on its words)
|
|
142
178
|
|
|
143
179
|
// The pointer over a row highlights it. In a menu that starts with nothing highlighted (the block
|
|
144
180
|
// menu), leaving the row takes the highlight off again, as :hover would; a row the keys moved to
|
|
145
|
-
// stays, and so does the "/" menu's, the row Enter runs.
|
|
146
|
-
|
|
181
|
+
// stays, and so does the "/" menu's, the row Enter runs. On a split row, `more`: the pointer is on
|
|
182
|
+
// its › (data-more on the row, which greys the › instead of the words), the part that opens.
|
|
183
|
+
const point = (row, more = false) => {
|
|
147
184
|
highlight(rows.indexOf(row), false);
|
|
148
185
|
pointed = true;
|
|
149
|
-
if (row
|
|
186
|
+
if (row.split) row.toggleAttribute("data-more", more);
|
|
187
|
+
if (row === pointedRow && more === pointedMore) return;
|
|
150
188
|
pointedRow = row;
|
|
189
|
+
pointedMore = more;
|
|
151
190
|
clearTimeout(subTimer);
|
|
152
191
|
// Notion's: a submenu opens 80ms after the pointer rests on its row (200ms while another is
|
|
153
|
-
// open), and goes 250ms after the pointer rests elsewhere.
|
|
154
|
-
|
|
155
|
-
|
|
192
|
+
// open), and goes 250ms after the pointer rests elsewhere (a split row's words being elsewhere).
|
|
193
|
+
const opens = Boolean(row.submenu) && (!row.split || more);
|
|
194
|
+
if (opens && row !== subRow) subTimer = setTimeout(() => openSub(row), subRow ? 200 : 80);
|
|
195
|
+
else if (!opens && subRow) subTimer = setTimeout(closeSub, 250);
|
|
156
196
|
};
|
|
157
197
|
const leave = (row) => {
|
|
158
198
|
if (pointed && rows[active] === row && options.highlight === false) highlight(-1);
|
|
199
|
+
row.removeAttribute("data-more");
|
|
159
200
|
if (pointedRow !== row) return;
|
|
160
201
|
pointedRow = null;
|
|
202
|
+
pointedMore = false;
|
|
161
203
|
clearTimeout(subTimer); // passing over a row opens nothing
|
|
162
204
|
if (subRow === row && !subKeys) subTimer = setTimeout(closeSub, 250); // unless the pointer goes into it
|
|
163
205
|
};
|
|
@@ -180,28 +222,36 @@ export function createMenu() {
|
|
|
180
222
|
children.push(item.node);
|
|
181
223
|
} else {
|
|
182
224
|
const row = element("button", { type: "button", class: "ge-pop-row", role: "menuitem" });
|
|
225
|
+
// A split row's words go in a part of their own, its › in another (CSS above).
|
|
226
|
+
row.split = Boolean(item.run && item.submenu);
|
|
227
|
+
const words = row.split ? element("span", { class: "ge-pop-main" }) : row;
|
|
228
|
+
if (row.split) row.setAttribute("data-split", "");
|
|
183
229
|
if (item.long) row.setAttribute("data-long", "");
|
|
184
|
-
if (options.icons !== false)
|
|
185
|
-
row
|
|
186
|
-
|
|
230
|
+
if (options.icons !== false) words.append(element("span", { class: "ge-pop-icon", html: item.icon ?? "" }));
|
|
231
|
+
// A row's pack where two rows have one name (我的待办 · 柔光风格): grey, after the name, in the label.
|
|
232
|
+
words.append(item.of ? element("span", { class: "ge-pop-label" }, item.label, element("span", { class: "ge-pop-of", text: ` · ${item.of}` })) : element("span", { class: "ge-pop-label", text: item.label }));
|
|
233
|
+
if (item.hint) words.append(element("span", { class: "ge-pop-hint", text: item.hint }));
|
|
234
|
+
if (row.split) row.append(words, element("span", { class: "ge-pop-more", html: `<span class="ge-pop-arrow">${ICONS.chevron}</span>` }));
|
|
235
|
+
else if (item.submenu) row.append(element("span", { class: "ge-pop-arrow", html: ICONS.chevron }));
|
|
187
236
|
if (item.submenu) {
|
|
188
|
-
row.append(element("span", { class: "ge-pop-arrow", html: ICONS.chevron }));
|
|
189
237
|
row.setAttribute("aria-haspopup", "menu");
|
|
190
238
|
row.submenu = item.submenu;
|
|
191
239
|
row.subWidth = item.width;
|
|
192
240
|
row.subSearch = item.search;
|
|
241
|
+
row.subLook = { icons: item.icons, compact: item.compact };
|
|
193
242
|
}
|
|
194
|
-
if (item.current || item.checked) {
|
|
195
|
-
row.append(element("span", { class: "ge-pop-check", html: ICONS.check, "aria-label": item.
|
|
243
|
+
if (item.current || item.checked || item.selected) {
|
|
244
|
+
row.append(element("span", { class: "ge-pop-check", html: ICONS.check, "aria-label": item.checked ? t("已开启") : t("当前") }));
|
|
196
245
|
row.setAttribute("data-current", "");
|
|
197
|
-
if (item.checked) row.setAttribute("aria-checked", "true");
|
|
246
|
+
if (item.checked || item.selected) row.setAttribute("aria-checked", "true");
|
|
198
247
|
}
|
|
199
248
|
row.disabled = Boolean(item.disabled || item.current);
|
|
200
249
|
row.run = item.run;
|
|
201
250
|
row.addEventListener("mousedown", (event) => event.preventDefault());
|
|
202
|
-
|
|
251
|
+
const onMore = (event) => row.split && Boolean(event.target.closest?.(".ge-pop-more"));
|
|
252
|
+
row.addEventListener("pointermove", (event) => point(row, onMore(event)));
|
|
203
253
|
row.addEventListener("pointerleave", () => leave(row));
|
|
204
|
-
row.addEventListener("click", () => run(row));
|
|
254
|
+
row.addEventListener("click", (event) => run(row, onMore(event)));
|
|
205
255
|
rows.push(row);
|
|
206
256
|
children.push(row);
|
|
207
257
|
if (item.note) children.push(element("div", { class: "ge-pop-note", text: item.note }));
|
|
@@ -319,6 +369,7 @@ export function createMenu() {
|
|
|
319
369
|
const search = row.subSearch && { placeholder: row.subSearch.placeholder, filter: (text) => closing(row.subSearch.filter(text)) };
|
|
320
370
|
sub.open(items, row.getBoundingClientRect(), {
|
|
321
371
|
side: "right", gap: 0, height: Math.round(innerHeight * 0.7), highlight: keys, width: row.subWidth, label: row.textContent, search, empty: row.subSearch?.empty, focus: keys,
|
|
372
|
+
...(row.subLook.icons === false ? { icons: false } : {}), ...(row.subLook.compact ? { compact: true } : {}),
|
|
322
373
|
onClose: () => {
|
|
323
374
|
row.removeAttribute("aria-expanded");
|
|
324
375
|
if (subRow === row) {
|
|
@@ -335,9 +386,11 @@ export function createMenu() {
|
|
|
335
386
|
sub?.close();
|
|
336
387
|
}
|
|
337
388
|
|
|
338
|
-
|
|
389
|
+
// A row's work: its submenu opened (a split row's only from its ›: `more`), a grid's cell's own
|
|
390
|
+
// click, or the menu closed and its action run (Enter and a click on a split row's words).
|
|
391
|
+
function run(row, more = false) {
|
|
339
392
|
if (!row || row.disabled) return false;
|
|
340
|
-
if (row.submenu) {
|
|
393
|
+
if (row.submenu && (!row.split || more)) {
|
|
341
394
|
openSub(row, true);
|
|
342
395
|
return true;
|
|
343
396
|
}
|
|
@@ -391,10 +444,12 @@ export function createMenu() {
|
|
|
391
444
|
const menu = {
|
|
392
445
|
open(items, rect, opts = {}) {
|
|
393
446
|
close();
|
|
394
|
-
options = opts;
|
|
447
|
+
options = opts.search && !opts.width ? { ...opts, width: SEARCHING } : opts;
|
|
395
448
|
anchor = rect;
|
|
396
449
|
opened.add(menu);
|
|
397
450
|
node = element("div", { class: "ge-pop", role: "menu", "aria-label": opts.label ?? t("菜单") });
|
|
451
|
+
if (options.width) node.setAttribute("data-sized", "");
|
|
452
|
+
if (options.compact) node.setAttribute("data-compact", "");
|
|
398
453
|
if (opts.inside) {
|
|
399
454
|
node.setAttribute("data-inside", "");
|
|
400
455
|
opts.inside.append(node);
|
|
@@ -30,6 +30,30 @@ export function commonRun(xs, ys) {
|
|
|
30
30
|
return [...head, ...middle, ...tail];
|
|
31
31
|
}
|
|
32
32
|
|
|
33
|
+
// A word diff of two texts, the reader's version against the file's (the conflict card's), or an
|
|
34
|
+
// Agent's baseline against the page (changes/): runs of { tag, text }, tag null
|
|
35
|
+
// for words both have, "del" for the reader's alone and "ins" for the file's alone (an ins before
|
|
36
|
+
// the del it stands beside). Words are runs of letters and digits, spaces, single other characters
|
|
37
|
+
// (each Chinese character on its own); at most 1500 words of each (commonRun above finds what is shared).
|
|
38
|
+
export function wordDiff(mine, theirs) {
|
|
39
|
+
const tokens = (text) => (text.match(/[A-Za-z0-9]+|\s+|[^A-Za-z0-9\s]/gu) ?? []).slice(0, 1500);
|
|
40
|
+
const a = tokens(mine);
|
|
41
|
+
const b = tokens(theirs);
|
|
42
|
+
const runs = [];
|
|
43
|
+
const add = (tag, text) => {
|
|
44
|
+
if (runs.at(-1)?.tag === tag) runs.at(-1).text += text;
|
|
45
|
+
else runs.push({ tag, text });
|
|
46
|
+
};
|
|
47
|
+
let [i, j] = [0, 0];
|
|
48
|
+
for (const [x, y] of [...commonRun(a, b), [a.length, b.length]]) {
|
|
49
|
+
while (j < y) add("ins", b[j++]);
|
|
50
|
+
while (i < x) add("del", a[i++]);
|
|
51
|
+
if (x < a.length) add(null, a[i++]);
|
|
52
|
+
j++;
|
|
53
|
+
}
|
|
54
|
+
return runs;
|
|
55
|
+
}
|
|
56
|
+
|
|
33
57
|
// ---------- merging a block both sides changed ----------
|
|
34
58
|
|
|
35
59
|
// Tokens of a block's inline HTML: a tag, an entity, a word, a run of spaces, or any other single
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { Z } from "../../shared/layers.mjs";
|
|
2
2
|
import { PANEL_STYLE, onPanels, panelGone, panelRoom, panelShown } from "./panel.mjs";
|
|
3
|
-
import { addStyle,
|
|
3
|
+
import { addStyle, element, mount, textButton } from "./ui.mjs";
|
|
4
4
|
import { t } from "../../shared/i18n/index.mjs";
|
|
5
5
|
import { preference } from "../../shared/preferences.mjs";
|
|
6
6
|
import { routine } from "./quiet.mjs";
|
|
@@ -24,7 +24,7 @@ import { routine } from "./quiet.mjs";
|
|
|
24
24
|
// so that the box has the whole window to be as wide as.
|
|
25
25
|
|
|
26
26
|
const STYLE = `
|
|
27
|
-
.ge-toast { position: fixed; left: 0; right: 0; bottom: 24px; z-index: ${Z.toast}; display: flex; align-items: center; gap: 10px; box-sizing: border-box; width: fit-content; max-width: min(640px, calc(100vw - 32px)); margin: 0 auto; padding: 8px 14px; border-radius: 8px; background: var(--ge-toast-bg); color: #f0efed; box-shadow: var(--ge-shadow); font: 14px/1.45 var(--doc-font, system-ui, sans-serif); opacity: 0; transform: translateY(10px); pointer-events: none; transition: opacity .18s, transform .18s; }
|
|
27
|
+
.ge-toast { position: fixed; left: 0; right: 0; bottom: 24px; z-index: ${Z.toast}; display: flex; align-items: center; gap: 10px; box-sizing: border-box; width: fit-content; max-width: min(640px, calc(100vw - 32px)); margin: 0 auto; padding: 8px 14px; border-radius: 8px; background: var(--ge-toast-bg); color: #f0efed; box-shadow: var(--ge-shadow); font: 14px/1.45 var(--doc-sans-font, var(--doc-font, system-ui, sans-serif)); opacity: 0; transform: translateY(10px); pointer-events: none; transition: opacity .18s, transform .18s; }
|
|
28
28
|
.ge-toast[data-show] { opacity: 1; transform: none; }
|
|
29
29
|
.ge-toast[data-tone="error"]::before { content: ""; flex: none; width: 6px; height: 6px; border-radius: 50%; background: #ff6b6b; }
|
|
30
30
|
`;
|
|
@@ -128,7 +128,7 @@ export function showPanel(title) {
|
|
|
128
128
|
closePanel();
|
|
129
129
|
addStyle(PANEL_STYLE);
|
|
130
130
|
panel = mount(element("div", { class: "ge-panel", role: "region", "aria-label": title },
|
|
131
|
-
element("div", { class: "ge-panel-head" }, element("span", { text: title }),
|
|
131
|
+
element("div", { class: "ge-panel-head" }, element("span", { text: title }), textButton(t("关闭"), closePanel, { quiet: true }))));
|
|
132
132
|
panelShown(panel);
|
|
133
133
|
}
|
|
134
134
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { TYPE_COMPONENT, blocksHidden } from "../components/registry.mjs";
|
|
2
2
|
|
|
3
|
-
// What the menus that make a block offer of the reader's 设置 ›
|
|
3
|
+
// What the menus that make a block offer of the reader's 设置 › 组件列表 (docs/workbench.md): the one place
|
|
4
4
|
// that hears what is hidden, gallery.json's as the page's map holds it (`hidden`), then as its event
|
|
5
5
|
// stream says it (`doc-settings-changed`), which costs the page nothing. A block type goes with its
|
|
6
6
|
// component. "/", 在下方新建 (both slash-menu/ typeItems) and the handle's grid (block-menu/) read it; no
|
|
@@ -1,23 +1,24 @@
|
|
|
1
1
|
// What is folded in the outline, kept for each report (localStorage, so the page the workbench shows
|
|
2
2
|
// again after an Agent's write, which is a new page, folds what the reader folded): a node's key (a
|
|
3
|
-
// heading's block id, a tab's area and tab), the reports folded last kept and the oldest let go.
|
|
3
|
+
// heading's block id, a tab's area and tab), the reports folded last kept and the oldest let go. The
|
|
4
|
+
// headings folded on the page (fold/) are kept the same way under a key of their own (`key`).
|
|
4
5
|
|
|
5
6
|
import { KEYS } from "../../../shared/renamed-storage.mjs";
|
|
6
7
|
|
|
7
8
|
export const FOLDS_KEY = KEYS.outlineFolds;
|
|
8
9
|
const KEEP = 100; // reports
|
|
9
10
|
|
|
10
|
-
function read(storage) {
|
|
11
|
+
function read(storage, key) {
|
|
11
12
|
try {
|
|
12
|
-
const value = JSON.parse(storage.get(
|
|
13
|
+
const value = JSON.parse(storage.get(key) ?? "null");
|
|
13
14
|
if (value && typeof value === "object" && value.folds && typeof value.folds === "object") return value;
|
|
14
15
|
} catch {}
|
|
15
16
|
return { folds: {} };
|
|
16
17
|
}
|
|
17
18
|
|
|
18
|
-
/** The keys folded in report `slug` (`storage`: { get, set }, page/storage.mjs)
|
|
19
|
-
export function foldsOf(storage, slug) {
|
|
20
|
-
const keys = read(storage).folds[slug];
|
|
19
|
+
/** The keys folded in report `slug` (`storage`: { get, set }, page/storage.mjs), kept under `key`. */
|
|
20
|
+
export function foldsOf(storage, slug, key = FOLDS_KEY) {
|
|
21
|
+
const keys = read(storage, key).folds[slug];
|
|
21
22
|
return new Set(Array.isArray(keys) ? keys.filter((key) => typeof key === "string") : []);
|
|
22
23
|
}
|
|
23
24
|
|
|
@@ -25,14 +26,14 @@ export function foldsOf(storage, slug) {
|
|
|
25
26
|
* Keep `folded` for report `slug`: only the keys the page still has (`present`), the report the one
|
|
26
27
|
* folded last; none folded forgets the report. At most KEEP reports, the oldest going first.
|
|
27
28
|
*/
|
|
28
|
-
export function keepFolds(storage, slug, folded, present = null) {
|
|
29
|
-
const value = read(storage);
|
|
30
|
-
const keys = [...folded].filter((
|
|
29
|
+
export function keepFolds(storage, slug, folded, present = null, key = FOLDS_KEY) {
|
|
30
|
+
const value = read(storage, key);
|
|
31
|
+
const keys = [...folded].filter((each) => !present || present.has(each));
|
|
31
32
|
delete value.folds[slug]; // put back last: the report folded last
|
|
32
33
|
if (keys.length) value.folds[slug] = keys;
|
|
33
34
|
const slugs = Object.keys(value.folds);
|
|
34
35
|
for (const old of slugs.slice(0, Math.max(0, slugs.length - KEEP))) delete value.folds[old];
|
|
35
|
-
storage.set(
|
|
36
|
+
storage.set(key, JSON.stringify(value));
|
|
36
37
|
}
|
|
37
38
|
|
|
38
39
|
/**
|