@heycys/gallery 0.1.1 → 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 +1 -1
- package/browser/editor/components/columns/page.mjs +4 -4
- package/browser/editor/components/embed/index.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/icons.mjs +8 -0
- package/browser/editor/components/image/crop.mjs +6 -9
- package/browser/editor/components/installed/index.mjs +11 -4
- package/browser/editor/components/installed/page.mjs +27 -16
- 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/registry.mjs +13 -4
- package/browser/editor/components/table/index.mjs +59 -2
- package/browser/editor/components/table/page.mjs +1 -1
- package/browser/editor/page/annotate/card.mjs +3 -6
- package/browser/editor/page/autosave.mjs +310 -37
- 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 +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 +124 -13
- package/browser/editor/page/clipboard/own/blocks.mjs +11 -11
- package/browser/editor/page/clipboard/own/chart-keys.mjs +41 -28
- 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 +31 -15
- package/browser/editor/page/custom-page.mjs +106 -0
- package/browser/editor/page/editor.mjs +51 -14
- 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 +24 -4
- 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 +18 -7
- package/browser/editor/page/notices.mjs +2 -2
- package/browser/editor/page/page-objects.mjs +13 -2
- package/browser/editor/page/panel.mjs +4 -9
- package/browser/editor/page/present-links.mjs +11 -2
- package/browser/editor/page/resize/index.mjs +42 -29
- 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/cells.mjs +102 -46
- package/browser/editor/page/table/icons.mjs +2 -0
- package/browser/editor/page/table/index.mjs +29 -10
- package/browser/editor/page/table/pictures.mjs +299 -0
- package/browser/editor/page/table/views.mjs +150 -0
- 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 +53 -3
- package/browser/editor/page/ui.mjs +13 -0
- 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/colors.mjs +3 -2
- package/browser/shared/component-catalog.mjs +323 -46
- package/browser/shared/component-source.mjs +37 -0
- package/browser/shared/components/index.mjs +12 -3
- package/browser/shared/components/installed.mjs +35 -3
- package/browser/shared/components/page.mjs +18 -8
- package/browser/shared/components/state.mjs +5 -1
- package/browser/shared/document-look.mjs +10 -5
- package/browser/shared/drafts.mjs +432 -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/i18n/en.mjs +307 -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 +331 -67
- 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/preview-server.mjs +3 -7
- package/browser/shared/session.mjs +8 -1
- 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-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-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-V5JTW2LH.mjs → chunk-6QBHU4DF.mjs} +1 -1
- package/dist/{chunk-Y6RLRPG3.mjs → chunk-6VTU6KEO.mjs} +1 -1
- package/dist/chunk-B4P2CM2J.mjs +3 -0
- package/dist/{chunk-FDLXYYG4.mjs → chunk-BPL64HGA.mjs} +1 -1
- package/dist/chunk-BVEFGE4B.mjs +2 -0
- package/dist/{chunk-LS4F7JUM.mjs → chunk-BZ5RAF7L.mjs} +1 -1
- package/dist/chunk-CRJEG7MT.mjs +2 -0
- package/dist/{chunk-LCTHTZIL.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-GB5SOYQJ.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-KTKHRC6H.mjs +2 -0
- package/dist/chunk-L7UP52JO.mjs +2 -0
- package/dist/{chunk-SYGN7GLU.mjs → chunk-MHW7ZKOU.mjs} +1 -1
- package/dist/chunk-N76HWBA3.mjs +10 -0
- package/dist/chunk-N7AZZLGT.mjs +548 -0
- package/dist/chunk-NAMN3RAF.mjs +2 -0
- package/dist/{chunk-5ZKJ3H4P.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-4FS7Z7WR.mjs → chunk-OUUP3WKT.mjs} +1 -1
- package/dist/{chunk-BGGDRNYQ.mjs → chunk-OW5NWPOJ.mjs} +1 -1
- package/dist/chunk-PAREWQGB.mjs +4 -0
- package/dist/chunk-POQSE4C2.mjs +2 -0
- package/dist/chunk-PUOQ65NC.mjs +2 -0
- package/dist/{chunk-XNROSH2T.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-7DTINW6U.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-UNOYVIYR.mjs +2 -0
- package/dist/{chunk-E7LWZRXY.mjs → chunk-V6RIYQZZ.mjs} +1 -1
- 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-YI43RG4P.mjs +2 -0
- package/dist/chunk-YQGT4AB2.mjs +6 -0
- package/dist/chunk-ZB4H7ZN4.mjs +2 -0
- package/dist/{chunk-IVDLMMBD.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-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 +14 -14
- package/kit/report.css +255 -17
- package/kit/runtime.js +1600 -125
- package/kit/state.js +10 -1
- package/kit/tables.js +128 -43
- package/kit/ui.js +77 -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 +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 +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 +221 -0
- package/skill/references/writing-html.md +6 -4
- package/skill/sdk/doc-kit.d.ts +396 -5
- 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/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-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
|
@@ -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) {
|
|
@@ -37,6 +37,8 @@ const STYLE = `
|
|
|
37
37
|
}
|
|
38
38
|
/* A width given (data-sized: opts.width, placed by place()): that width, whatever the rows hold. */
|
|
39
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; }
|
|
40
42
|
@keyframes ge-pop-in { from { opacity: 0; transform: scale(.98); } }
|
|
41
43
|
@media (prefers-reduced-motion: reduce) { .ge-pop { animation: none; } }
|
|
42
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; }
|
|
@@ -58,6 +60,7 @@ const STYLE = `
|
|
|
58
60
|
words and the hint takes what is left, cut short with an ellipsis where it is too long (an English
|
|
59
61
|
row's current choice once took the whole row, its label drawn 0px wide). */
|
|
60
62
|
.ge-pop-label:has(+ .ge-pop-hint) { flex: 1 0 auto; max-width: 100%; }
|
|
63
|
+
.ge-pop-of { color: var(--ge-tx3); }
|
|
61
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; }
|
|
62
65
|
/* A row of a page (its title, the page it is under as its hint): a long title is what an ellipsis
|
|
63
66
|
cuts, and the page above keeps its words, up to a part of the row. */
|
|
@@ -125,10 +128,12 @@ const opened = new Set(); // the menus open now, whichever part of the page open
|
|
|
125
128
|
export const menuOpen = () => opened.size > 0;
|
|
126
129
|
|
|
127
130
|
/**
|
|
128
|
-
* 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:
|
|
129
133
|
* a label of any length, a page's title, cut before its hint is; current: the choice
|
|
130
134
|
* made, checked and not to be chosen again; checked: a switch that is on, checked and clicked to turn
|
|
131
|
-
* 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,
|
|
132
137
|
* shown at the row's right while the pointer rests on it, notion-lite's row tooltip) (or { label, icon?, submenu:
|
|
133
138
|
* () => items, width?, search? } opening a submenu, with a search field at its top when `search` is
|
|
134
139
|
* given, as `opts.search` below, and `search.empty` the words shown when nothing is found; a row
|
|
@@ -143,7 +148,9 @@ export const menuOpen = () => opened.size > 0;
|
|
|
143
148
|
* leaves no room at all. side: "right": beside the anchor, right of it (left of it when there is no
|
|
144
149
|
* room), level with it (a section's bar). Without either the menu stands below the anchor (the
|
|
145
150
|
* caret), or above it when there is no room below; align: "end", its right edge at the anchor's.
|
|
146
|
-
* 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
|
|
147
154
|
* card's greatest height, in px (its rows scroll inside it past that). stand(size): where the card
|
|
148
155
|
* stands, its { left, top } for its { width, height }, in place of all of these rules (a pasted
|
|
149
156
|
* address's 选择视图, by the format bar's rule: placement.mjs besideText). inside: an element the rows
|
|
@@ -221,7 +228,8 @@ export function createMenu() {
|
|
|
221
228
|
if (row.split) row.setAttribute("data-split", "");
|
|
222
229
|
if (item.long) row.setAttribute("data-long", "");
|
|
223
230
|
if (options.icons !== false) words.append(element("span", { class: "ge-pop-icon", html: item.icon ?? "" }));
|
|
224
|
-
|
|
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 }));
|
|
225
233
|
if (item.hint) words.append(element("span", { class: "ge-pop-hint", text: item.hint }));
|
|
226
234
|
if (row.split) row.append(words, element("span", { class: "ge-pop-more", html: `<span class="ge-pop-arrow">${ICONS.chevron}</span>` }));
|
|
227
235
|
else if (item.submenu) row.append(element("span", { class: "ge-pop-arrow", html: ICONS.chevron }));
|
|
@@ -230,11 +238,12 @@ export function createMenu() {
|
|
|
230
238
|
row.submenu = item.submenu;
|
|
231
239
|
row.subWidth = item.width;
|
|
232
240
|
row.subSearch = item.search;
|
|
241
|
+
row.subLook = { icons: item.icons, compact: item.compact };
|
|
233
242
|
}
|
|
234
|
-
if (item.current || item.checked) {
|
|
235
|
-
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("当前") }));
|
|
236
245
|
row.setAttribute("data-current", "");
|
|
237
|
-
if (item.checked) row.setAttribute("aria-checked", "true");
|
|
246
|
+
if (item.checked || item.selected) row.setAttribute("aria-checked", "true");
|
|
238
247
|
}
|
|
239
248
|
row.disabled = Boolean(item.disabled || item.current);
|
|
240
249
|
row.run = item.run;
|
|
@@ -360,6 +369,7 @@ export function createMenu() {
|
|
|
360
369
|
const search = row.subSearch && { placeholder: row.subSearch.placeholder, filter: (text) => closing(row.subSearch.filter(text)) };
|
|
361
370
|
sub.open(items, row.getBoundingClientRect(), {
|
|
362
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 } : {}),
|
|
363
373
|
onClose: () => {
|
|
364
374
|
row.removeAttribute("aria-expanded");
|
|
365
375
|
if (subRow === row) {
|
|
@@ -439,6 +449,7 @@ export function createMenu() {
|
|
|
439
449
|
opened.add(menu);
|
|
440
450
|
node = element("div", { class: "ge-pop", role: "menu", "aria-label": opts.label ?? t("菜单") });
|
|
441
451
|
if (options.width) node.setAttribute("data-sized", "");
|
|
452
|
+
if (options.compact) node.setAttribute("data-compact", "");
|
|
442
453
|
if (opts.inside) {
|
|
443
454
|
node.setAttribute("data-inside", "");
|
|
444
455
|
opts.inside.append(node);
|
|
@@ -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";
|
|
@@ -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
|
|
|
@@ -31,8 +31,19 @@ export function menuEntry(key) {
|
|
|
31
31
|
/** The row of a key of a menu of blocks: its type's, or its variant's; null for neither. */
|
|
32
32
|
export const menuRow = (key) => TYPE_INFO[key] ?? menuEntry(key).variant;
|
|
33
33
|
|
|
34
|
-
|
|
35
|
-
|
|
34
|
+
// Every variant there is now: [key, row].
|
|
35
|
+
const variants = () => Object.keys(TYPE_COMPONENT).flatMap((type) => Object.entries(pageOfType(type)?.menuVariants?.() ?? {}).map(([name, row]) => [`${type}:${name}`, row]));
|
|
36
|
+
|
|
37
|
+
/**
|
|
38
|
+
* The keys of the variants the menus of blocks offer now ("/", 在下方新建, the handle's +, 转换成): every
|
|
39
|
+
* one but a view of a table (`readsTables`: a custom block whose needs hold "tables"), which a table's
|
|
40
|
+
* 视图 › alone offers, as it puts one in bound to that table (viewKeys): one put in anywhere else would
|
|
41
|
+
* only say it has no table to read.
|
|
42
|
+
*/
|
|
43
|
+
export const variantKeys = () => variants().filter(([, row]) => !row.readsTables).map(([key]) => key);
|
|
44
|
+
|
|
45
|
+
/** The keys of the variants that are views of a table, for a table's 视图 › (table/views.mjs). */
|
|
46
|
+
export const viewKeys = () => variants().filter(([, row]) => row.readsTables).map(([key]) => key);
|
|
36
47
|
|
|
37
48
|
/** The page objects, in the order they are made. */
|
|
38
49
|
export const pageObjects = () => Object.values(pages);
|
|
@@ -3,8 +3,10 @@ import { Z } from "../../shared/layers.mjs";
|
|
|
3
3
|
// The editor's bottom panels: the conflicts' (conflicts.mjs, left) and the lost texts' (notices.mjs,
|
|
4
4
|
// right) are the same card, and the bar of the Agent's changes (changes/bar.mjs, in the middle) is its
|
|
5
5
|
// buttons in a row: a small muted head with a red dot, items under it, the reader's words as
|
|
6
|
-
// a quote, one
|
|
7
|
-
//
|
|
6
|
+
// a quote, one pale blue primary button, the rest with no line and no fill (gray under the pointer) or, looking
|
|
7
|
+
// only, quiet text: all of them the editor's one button look (look.mjs BUTTONS, ui.mjs textButton), none of
|
|
8
|
+
// their own here. No notice covers one: while one stands, the toast stands above it (notices.mjs, and the
|
|
9
|
+
// workbench's, told the room).
|
|
8
10
|
|
|
9
11
|
const PANELS = ".ge-conflicts:not([hidden]), .ge-panel, .ge-changes:not([hidden])";
|
|
10
12
|
|
|
@@ -55,11 +57,4 @@ export const PANEL_STYLE = `
|
|
|
55
57
|
:is(.ge-conflict, .ge-panel-item) p + .ge-version { margin-top: 6px; }
|
|
56
58
|
:is(.ge-conflicts, .ge-panel) .ge-version { margin: 0; padding: 0 0 0 10px; border-left: 2px solid var(--ge-quote); overflow-wrap: anywhere; }
|
|
57
59
|
:is(.ge-conflicts, .ge-panel) .ge-actions { display: flex; flex-wrap: wrap; align-items: center; gap: 6px; margin-top: 12px; }
|
|
58
|
-
:is(.ge-conflicts, .ge-panel) button { height: 28px; padding: 0 10px; border: 1px solid var(--ge-edge); border-radius: 6px; background: transparent; color: inherit; font: inherit; font-weight: 500; white-space: nowrap; cursor: pointer; }
|
|
59
|
-
:is(.ge-conflicts, .ge-panel) button:hover:not(:disabled) { background: var(--ge-hover); }
|
|
60
|
-
:is(.ge-conflicts, .ge-panel) button[data-primary] { border-color: transparent; background: var(--ge-accent); color: #fff; }
|
|
61
|
-
:is(.ge-conflicts, .ge-panel) button[data-primary]:hover:not(:disabled) { background: var(--ge-accent-hover); }
|
|
62
|
-
:is(.ge-conflicts, .ge-panel) button[data-quiet] { height: 24px; padding: 0 6px; border-color: transparent; color: var(--ge-tx2); font-weight: 400; }
|
|
63
|
-
:is(.ge-conflicts, .ge-panel) button[data-quiet]:hover:not(:disabled) { color: var(--ge-tx); background: transparent; }
|
|
64
|
-
:is(.ge-conflicts, .ge-panel) button:disabled { opacity: .45; cursor: default; }
|
|
65
60
|
`;
|
|
@@ -1,6 +1,7 @@
|
|
|
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 { entryOfKey } from "../../shared/extension-sidebar.mjs";
|
|
4
5
|
import { PROTOCOL, VERSION } from "../../shared/session.mjs";
|
|
5
6
|
|
|
6
7
|
// The links of a page shown in 演示视图 (?present: src/server/routes.mjs), which has no editor and whose
|
|
@@ -13,7 +14,9 @@ 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.
|
|
17
20
|
|
|
18
21
|
const own = pageAddress(location.href)?.slug ?? null;
|
|
19
22
|
const openTab = (address) => window.open(address, "_blank", "noopener");
|
|
@@ -34,7 +37,13 @@ async function follow(address) {
|
|
|
34
37
|
if (!mayBePage(address)) return void openTab(address);
|
|
35
38
|
const listed = await read("outline");
|
|
36
39
|
const place = addressOn(address, listed?.reports ? pageLinks(linkedPages(listed.reports)) : null, location.origin);
|
|
37
|
-
|
|
40
|
+
const web = place && listed?.reports?.[place.slug]?.kind === "link" ? listed.reports[place.slug] : null;
|
|
41
|
+
const entry = !place && !elsewhere(address, location.origin) ? entryOfKey(listed?.extensions, workbenchHash(address) ?? "") : null;
|
|
42
|
+
if (web) {
|
|
43
|
+
if (/^https?:/.test(web.url ?? "")) openTab(web.url);
|
|
44
|
+
else sayGone(web.slug, listed);
|
|
45
|
+
} else if (place) go(place);
|
|
46
|
+
else if (entry?.url) openTab(entry.url);
|
|
38
47
|
else if (isPageAddress(address) && !elsewhere(address, location.origin)) sayGone(pageAddress(address)?.slug ?? workbenchHash(address), listed ?? undefined);
|
|
39
48
|
else openTab(address);
|
|
40
49
|
}
|
|
@@ -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
|
}
|
|
@@ -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);
|