@heycys/gallery 0.1.1 → 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/THIRD-PARTY-NOTICES.md +2 -2
- package/browser/editor/components/align.mjs +58 -0
- package/browser/editor/components/code/index.mjs +1 -1
- package/browser/editor/components/columns/page.mjs +4 -4
- package/browser/editor/components/embed/index.mjs +2 -2
- package/browser/editor/components/embed/page.mjs +1 -1
- package/browser/editor/components/file/page.mjs +4 -4
- package/browser/editor/components/flowchart/add.mjs +7 -6
- package/browser/editor/components/flowchart/page.mjs +1 -1
- package/browser/editor/components/heading/index.mjs +7 -6
- package/browser/editor/components/icons.mjs +11 -0
- package/browser/editor/components/image/crop.mjs +6 -9
- package/browser/editor/components/image/index.mjs +2 -0
- package/browser/editor/components/image/page.mjs +172 -90
- package/browser/editor/components/installed/index.mjs +15 -4
- package/browser/editor/components/installed/page.mjs +103 -25
- package/browser/editor/components/installed/served.mjs +6 -5
- package/browser/editor/components/instances.mjs +18 -0
- package/browser/editor/components/list/page.mjs +3 -6
- package/browser/editor/components/media/icons.mjs +13 -8
- package/browser/editor/components/media/page.mjs +5 -3
- package/browser/editor/components/media/toolbar.mjs +12 -3
- package/browser/editor/components/paragraph/index.mjs +4 -3
- package/browser/editor/components/registry.mjs +30 -9
- package/browser/editor/components/table/index.mjs +61 -2
- package/browser/editor/components/table/page.mjs +1 -1
- package/browser/editor/page/after/index.mjs +288 -0
- package/browser/editor/page/align.mjs +91 -0
- package/browser/editor/page/annotate/card.mjs +3 -6
- package/browser/editor/page/autosave.mjs +310 -37
- package/browser/editor/page/beside.mjs +5 -6
- package/browser/editor/page/block-menu/index.mjs +6 -3
- package/browser/editor/page/blocks.mjs +3 -1
- package/browser/editor/page/board/client.mjs +57 -0
- package/browser/editor/page/board/hint.mjs +182 -0
- package/browser/editor/page/board/history.mjs +119 -0
- package/browser/editor/page/board/index.mjs +1059 -0
- package/browser/editor/page/board/motion.mjs +177 -0
- package/browser/editor/page/board/settings.mjs +210 -0
- package/browser/editor/page/caret.mjs +1 -1
- package/browser/editor/page/changes/bar.mjs +6 -14
- package/browser/editor/page/changes/index.mjs +2 -2
- package/browser/editor/page/clipboard/import/html.mjs +29 -6
- package/browser/editor/page/clipboard/import/inline.mjs +32 -0
- package/browser/editor/page/clipboard/import/markdown.mjs +58 -13
- package/browser/editor/page/clipboard/import/read.mjs +6 -1
- package/browser/editor/page/clipboard/import/to-blocks.mjs +44 -12
- package/browser/editor/page/clipboard/import/yuque.mjs +622 -0
- package/browser/editor/page/clipboard/index.mjs +133 -15
- package/browser/editor/page/clipboard/own/blocks.mjs +13 -14
- package/browser/editor/page/clipboard/own/chart-keys.mjs +41 -28
- package/browser/editor/page/clipboard/own/describe.mjs +6 -2
- package/browser/editor/page/clipboard/own/selection.mjs +1 -1
- package/browser/editor/page/columns/index.mjs +48 -46
- package/browser/editor/page/commit.mjs +80 -22
- package/browser/editor/page/conflicts.mjs +7 -7
- package/browser/editor/page/core.mjs +34 -16
- package/browser/editor/page/custom-page.mjs +110 -0
- package/browser/editor/page/editor.mjs +71 -17
- package/browser/editor/page/emoji-picker/styles.mjs +7 -12
- package/browser/editor/page/emoji-picker/upload.mjs +2 -2
- package/browser/editor/page/handle/index.mjs +5 -8
- package/browser/editor/page/history.mjs +41 -6
- package/browser/editor/page/insert/index.mjs +20 -22
- package/browser/editor/page/links/index.mjs +5 -3
- package/browser/editor/page/links/pages.mjs +27 -9
- package/browser/editor/page/look.mjs +54 -3
- package/browser/editor/page/margin.mjs +18 -3
- package/browser/editor/page/media-menu/index.mjs +6 -7
- package/browser/editor/page/menu.mjs +33 -14
- package/browser/editor/page/notices.mjs +2 -2
- package/browser/editor/page/page-objects.mjs +9 -2
- package/browser/editor/page/panel.mjs +4 -9
- package/browser/editor/page/present-links.mjs +15 -5
- package/browser/editor/page/present-shell.mjs +63 -0
- package/browser/editor/page/resize/index.mjs +42 -29
- package/browser/editor/page/selection/index.mjs +10 -2
- package/browser/editor/page/served.mjs +14 -0
- package/browser/editor/page/session.mjs +48 -4
- package/browser/editor/page/slash-menu/index.mjs +3 -3
- package/browser/editor/page/table/binding.mjs +87 -0
- package/browser/editor/page/table/cells.mjs +102 -46
- package/browser/editor/page/table/index.mjs +24 -9
- package/browser/editor/page/table/pictures.mjs +299 -0
- package/browser/editor/page/table/views.mjs +103 -0
- package/browser/editor/page/table/widths.mjs +82 -10
- package/browser/editor/page/text-select/index.mjs +26 -12
- package/browser/editor/page/todo-writes.mjs +75 -0
- package/browser/editor/page/typing/index.mjs +97 -15
- package/browser/editor/page/typing/leave.mjs +19 -5
- package/browser/editor/page/ui.mjs +13 -0
- package/browser/shared/block-packs.mjs +419 -0
- package/browser/shared/board-places.mjs +224 -0
- package/browser/shared/card-size.mjs +59 -0
- package/browser/shared/colors.mjs +3 -2
- package/browser/shared/component-catalog.mjs +330 -46
- package/browser/shared/component-source.mjs +39 -0
- package/browser/shared/components/heading.mjs +2 -1
- package/browser/shared/components/index.mjs +12 -3
- package/browser/shared/components/installed.mjs +35 -3
- package/browser/shared/components/page.mjs +20 -8
- package/browser/shared/components/paragraph.mjs +8 -1
- package/browser/shared/components/state.mjs +5 -1
- package/browser/shared/components/table.mjs +1 -0
- package/browser/shared/document-look.mjs +10 -5
- package/browser/shared/drafts.mjs +432 -0
- package/browser/shared/emoji/line-icons.mjs +37 -0
- package/browser/shared/extension-sidebar.mjs +126 -0
- package/browser/shared/extensions.mjs +79 -0
- package/browser/shared/file-table.mjs +101 -0
- package/browser/shared/http.mjs +9 -0
- package/browser/shared/i18n/en.mjs +330 -27
- package/browser/shared/json-layout.mjs +47 -0
- package/browser/shared/net-cache.mjs +133 -0
- package/browser/shared/net-keys.mjs +32 -0
- package/browser/shared/net-policy.mjs +177 -0
- package/browser/shared/outline-shape.mjs +128 -0
- package/browser/shared/outline.mjs +359 -67
- package/browser/shared/pack-manifest.mjs +88 -0
- package/browser/shared/page-address.mjs +6 -3
- package/browser/shared/page-cards.mjs +308 -0
- package/browser/shared/page-links.mjs +69 -6
- package/browser/shared/pages.mjs +500 -0
- package/browser/shared/paths.mjs +6 -0
- package/browser/shared/pinyin.mjs +92 -0
- package/browser/shared/present-step.mjs +17 -0
- package/browser/shared/preview-server.mjs +3 -7
- package/browser/shared/session.mjs +8 -1
- package/browser/shared/shipped-blocks.mjs +299 -0
- package/browser/shared/sidebar-head.mjs +70 -0
- package/browser/shared/table-chart.mjs +33 -1
- package/browser/shared/todos.mjs +83 -0
- package/browser/shared/user-directory.mjs +24 -0
- package/browser/shared/versions.mjs +14 -0
- package/browser/shared/web-links.mjs +139 -0
- package/browser/shared/workspace-columns.mjs +120 -0
- package/browser/shared/workspace-name.mjs +154 -0
- package/browser/shared/workspace-query.mjs +125 -0
- package/browser/shared/workspace-registry.mjs +272 -0
- package/browser/shared/workspace.mjs +171 -20
- package/dist/chunk-2OHANJ6Q.mjs +2 -0
- package/dist/chunk-3MBRL2PM.mjs +16 -0
- package/dist/chunk-4OKWZY5E.mjs +2 -0
- package/dist/chunk-4OZWXZE5.mjs +5 -0
- package/dist/chunk-5K44HLTZ.mjs +2 -0
- package/dist/{chunk-5ZKJ3H4P.mjs → chunk-5XA2ZBAE.mjs} +3 -3
- package/dist/{chunk-4FS7Z7WR.mjs → chunk-67N2QJYT.mjs} +1 -1
- package/dist/chunk-6KBYRA2C.mjs +2 -0
- package/dist/chunk-6N3PX4XX.mjs +8 -0
- package/dist/{chunk-V5JTW2LH.mjs → chunk-6QBHU4DF.mjs} +1 -1
- package/dist/chunk-7JDX4E65.mjs +13 -0
- package/dist/chunk-7M2BQQGZ.mjs +2 -0
- package/dist/chunk-7OG26PGF.mjs +2 -0
- package/dist/chunk-AHN3NFKJ.mjs +3 -0
- package/dist/chunk-ALZ6ZENZ.mjs +3 -0
- package/dist/chunk-AR5D57ZD.mjs +170 -0
- package/dist/{chunk-W3BGBJQW.mjs → chunk-BFJGHSQN.mjs} +1 -1
- package/dist/{chunk-LS4F7JUM.mjs → chunk-BZ5RAF7L.mjs} +1 -1
- package/dist/chunk-CMA72MAG.mjs +2 -0
- package/dist/{chunk-LCTHTZIL.mjs → chunk-DAZL73VK.mjs} +91 -91
- package/dist/{chunk-Y6RLRPG3.mjs → chunk-DJISHPUL.mjs} +1 -1
- package/dist/chunk-DR73Y2UJ.mjs +3 -0
- package/dist/{chunk-FDLXYYG4.mjs → chunk-EAIFITAV.mjs} +1 -1
- package/dist/{chunk-TMYZB6AV.mjs → chunk-EKNHM3P4.mjs} +1 -1
- package/dist/chunk-EP25HDAJ.mjs +2 -0
- package/dist/{chunk-GB5SOYQJ.mjs → chunk-ERLAIBOA.mjs} +2 -2
- package/dist/chunk-EURLTOTZ.mjs +4 -0
- package/dist/chunk-F4ZA6JRZ.mjs +3 -0
- package/dist/chunk-F6HVDZR4.mjs +2 -0
- package/dist/chunk-FDMAXMQA.mjs +2 -0
- package/dist/chunk-FETSREUN.mjs +5 -0
- package/dist/chunk-GHOYKMQ3.mjs +4 -0
- package/dist/{chunk-2B5E4CDJ.mjs → chunk-GPIWQ4X4.mjs} +1 -1
- package/dist/chunk-HDWTZ763.mjs +12 -0
- package/dist/chunk-HPOI4ZX7.mjs +6 -0
- package/dist/{chunk-BGGDRNYQ.mjs → chunk-HXG7EOPJ.mjs} +1 -1
- package/dist/chunk-IA4PSIMD.mjs +2 -0
- package/dist/{chunk-E7LWZRXY.mjs → chunk-ITOH5EGO.mjs} +1 -1
- package/dist/chunk-IV64FFI4.mjs +2 -0
- package/dist/chunk-J43Z6LSS.mjs +2 -0
- package/dist/chunk-J5PUIV3Y.mjs +4 -0
- package/dist/chunk-JA7G53PC.mjs +2 -0
- package/dist/chunk-JEUK3ZO7.mjs +2 -0
- package/dist/chunk-JLTZF4LA.mjs +2 -0
- package/dist/chunk-JZT7I2OJ.mjs +2 -0
- package/dist/chunk-K5XATEOO.mjs +2 -0
- package/dist/chunk-L2SUIS5S.mjs +2 -0
- package/dist/chunk-L7UP52JO.mjs +2 -0
- package/dist/chunk-LM4XFQHZ.mjs +2 -0
- package/dist/chunk-MN7BZL4R.mjs +2 -0
- package/dist/chunk-MTYYHM2G.mjs +15 -0
- package/dist/chunk-MXUBKDRO.mjs +15 -0
- package/dist/chunk-NAMN3RAF.mjs +2 -0
- package/dist/{chunk-SYGN7GLU.mjs → chunk-OEXWRJME.mjs} +1 -1
- package/dist/chunk-OFHXGWOX.mjs +2 -0
- package/dist/chunk-ORID3AE7.mjs +166 -0
- package/dist/chunk-PAREWQGB.mjs +4 -0
- package/dist/chunk-PGDE24N5.mjs +2 -0
- package/dist/chunk-POTA2FV4.mjs +2 -0
- package/dist/chunk-PUOQ65NC.mjs +2 -0
- package/dist/chunk-Q4UEPUWF.mjs +2 -0
- package/dist/chunk-QE5RG76S.mjs +549 -0
- package/dist/chunk-R2ZDLJYT.mjs +10 -0
- package/dist/{chunk-7DTINW6U.mjs → chunk-SQ6Y2ZMA.mjs} +2 -2
- package/dist/chunk-SWUTTZCN.mjs +2 -0
- package/dist/chunk-TANZRINB.mjs +2 -0
- package/dist/chunk-TR7TWGHB.mjs +2 -0
- package/dist/chunk-U5XL7D6A.mjs +3 -0
- package/dist/{chunk-XNROSH2T.mjs → chunk-U7NZI6N4.mjs} +2 -2
- package/dist/chunk-UGWMMEJ5.mjs +15 -0
- package/dist/chunk-UJQJKNGK.mjs +2 -0
- package/dist/chunk-UYVCQK3H.mjs +22 -0
- package/dist/chunk-VFX2KNHP.mjs +4 -0
- package/dist/chunk-VS7JIGJW.mjs +24 -0
- package/dist/chunk-W7665ZEC.mjs +6 -0
- package/dist/chunk-WQDQWCX5.mjs +2 -0
- package/dist/chunk-YI43RG4P.mjs +2 -0
- package/dist/chunk-YLPSMDIS.mjs +5 -0
- package/dist/chunk-YNAWBAYN.mjs +3 -0
- package/dist/chunk-YROX2O22.mjs +2 -0
- package/dist/chunk-ZDLPUOAG.mjs +6 -0
- package/dist/{chunk-IVDLMMBD.mjs → chunk-ZHEHPMBK.mjs} +1 -1
- package/dist/chunk-ZQS6H473.mjs +16 -0
- package/dist/chunk-ZTHICSSF.mjs +2 -0
- package/dist/chunk-ZWWC4KLF.mjs +20 -0
- package/dist/cli.mjs +1 -1
- package/dist/server.mjs +1 -1
- package/dist/{chunk-U6KNPJPR.mjs → update-fetch.mjs} +1 -1
- package/dist/worker.mjs +1 -1
- package/kit/board.css +95 -0
- package/kit/board.js +250 -0
- package/kit/charts.js +5 -71
- package/kit/code.js +17 -17
- package/kit/report.css +335 -18
- package/kit/runtime.js +1638 -125
- package/kit/state.js +10 -1
- package/kit/tables.js +130 -43
- package/kit/ui.js +79 -35
- package/package.json +2 -1
- package/packs/gallery/card/component.json +14 -0
- package/packs/gallery/card/example.html +10 -0
- package/packs/gallery/card/preview.svg +1 -0
- package/packs/gallery/card/style.css +6 -0
- package/packs/gallery/card/template.html +6 -0
- package/packs/gallery/card/writing.md +14 -0
- package/packs/gallery/chart-card/component.json +15 -0
- package/packs/gallery/chart-card/example.html +14 -0
- package/packs/gallery/chart-card/kit.js +130 -0
- package/packs/gallery/chart-card/preview.svg +1 -0
- package/packs/gallery/chart-card/style.css +42 -0
- package/packs/gallery/chart-card/template.html +13 -0
- package/packs/gallery/chart-card/writing.md +20 -0
- package/packs/gallery/chart-view/component.json +20 -0
- package/packs/gallery/chart-view/example.html +13 -0
- package/packs/gallery/chart-view/kit.js +355 -0
- package/packs/gallery/chart-view/preview.svg +1 -0
- package/packs/gallery/chart-view/style.css +94 -0
- package/packs/gallery/chart-view/template.html +3 -0
- package/packs/gallery/chart-view/writing.md +22 -0
- package/packs/gallery/countdown/component.json +18 -0
- package/packs/gallery/countdown/example.html +3 -0
- package/packs/gallery/countdown/kit.js +216 -0
- package/packs/gallery/countdown/preview.svg +1 -0
- package/packs/gallery/countdown/style.css +118 -0
- package/packs/gallery/countdown/template.html +3 -0
- package/packs/gallery/countdown/writing.md +22 -0
- package/packs/gallery/habit/component.json +14 -0
- package/packs/gallery/habit/example.html +3 -0
- package/packs/gallery/habit/kit.js +334 -0
- package/packs/gallery/habit/preview.svg +1 -0
- package/packs/gallery/habit/style.css +174 -0
- package/packs/gallery/habit/template.html +3 -0
- package/packs/gallery/habit/writing.md +21 -0
- package/packs/gallery/heatmap/component.json +18 -0
- package/packs/gallery/heatmap/example.html +3 -0
- package/packs/gallery/heatmap/kit.js +513 -0
- package/packs/gallery/heatmap/preview.svg +1 -0
- package/packs/gallery/heatmap/style.css +189 -0
- package/packs/gallery/heatmap/template.html +3 -0
- package/packs/gallery/heatmap/writing.md +21 -0
- package/packs/gallery/kanban/component.json +18 -0
- package/packs/gallery/kanban/example.html +12 -0
- package/packs/gallery/kanban/kit.js +540 -0
- package/packs/gallery/kanban/preview.svg +1 -0
- package/packs/gallery/kanban/style.css +212 -0
- package/packs/gallery/kanban/template.html +3 -0
- package/packs/gallery/kanban/writing.md +20 -0
- package/packs/gallery/metric/component.json +22 -0
- package/packs/gallery/metric/example.html +15 -0
- package/packs/gallery/metric/kit.js +248 -0
- package/packs/gallery/metric/preview.svg +1 -0
- package/packs/gallery/metric/style.css +92 -0
- package/packs/gallery/metric/template.html +3 -0
- package/packs/gallery/metric/writing.md +23 -0
- package/packs/gallery/note/component.json +14 -0
- package/packs/gallery/note/example.html +3 -0
- package/packs/gallery/note/kit.js +129 -0
- package/packs/gallery/note/preview.svg +1 -0
- package/packs/gallery/note/style.css +97 -0
- package/packs/gallery/note/template.html +3 -0
- package/packs/gallery/note/writing.md +18 -0
- package/packs/gallery/pack.json +8 -0
- package/packs/gallery/recent/component.json +13 -0
- package/packs/gallery/recent/example.html +1 -0
- package/packs/gallery/recent/kit.js +293 -0
- package/packs/gallery/recent/preview.svg +1 -0
- package/packs/gallery/recent/style.css +85 -0
- package/packs/gallery/recent/template.html +1 -0
- package/packs/gallery/recent/writing.md +15 -0
- package/packs/gallery/static/component.json +13 -0
- package/packs/gallery/static/example.html +11 -0
- package/packs/gallery/static/preview.svg +1 -0
- package/packs/gallery/static/style.css +171 -0
- package/packs/gallery/static/template.html +1 -0
- package/packs/gallery/static/writing.md +18 -0
- package/packs/gallery/stats/component.json +13 -0
- package/packs/gallery/stats/example.html +1 -0
- package/packs/gallery/stats/kit.js +347 -0
- package/packs/gallery/stats/preview.svg +1 -0
- package/packs/gallery/stats/style.css +73 -0
- package/packs/gallery/stats/template.html +1 -0
- package/packs/gallery/stats/writing.md +11 -0
- package/packs/gallery/today/component.json +12 -0
- package/packs/gallery/today/example.html +1 -0
- package/packs/gallery/today/kit.js +220 -0
- package/packs/gallery/today/preview.svg +1 -0
- package/packs/gallery/today/style.css +149 -0
- package/packs/gallery/today/template.html +1 -0
- package/packs/gallery/today/writing.md +14 -0
- package/packs/gallery/todos/component.json +19 -0
- package/packs/gallery/todos/example.html +3 -0
- package/packs/gallery/todos/kit.js +489 -0
- package/packs/gallery/todos/preview.svg +1 -0
- package/packs/gallery/todos/style.css +214 -0
- package/packs/gallery/todos/template.html +3 -0
- package/packs/gallery/todos/writing.md +30 -0
- package/packs/gallery/weather/component.json +19 -0
- package/packs/gallery/weather/example.html +3 -0
- package/packs/gallery/weather/kit.js +387 -0
- package/packs/gallery/weather/preview.svg +1 -0
- package/packs/gallery/weather/style.css +140 -0
- package/packs/gallery/weather/template.html +3 -0
- package/packs/gallery/weather/writing.md +26 -0
- package/packs/gallery-soft/countdown/component.json +18 -0
- package/packs/gallery-soft/countdown/example.html +3 -0
- package/packs/gallery-soft/countdown/kit.js +206 -0
- package/packs/gallery-soft/countdown/preview.svg +1 -0
- package/packs/gallery-soft/countdown/style.css +211 -0
- package/packs/gallery-soft/countdown/template.html +3 -0
- package/packs/gallery-soft/countdown/writing.md +24 -0
- package/packs/gallery-soft/habit/component.json +14 -0
- package/packs/gallery-soft/habit/example.html +3 -0
- package/packs/gallery-soft/habit/kit.js +366 -0
- package/packs/gallery-soft/habit/preview.svg +1 -0
- package/packs/gallery-soft/habit/style.css +251 -0
- package/packs/gallery-soft/habit/template.html +3 -0
- package/packs/gallery-soft/habit/writing.md +23 -0
- package/packs/gallery-soft/heatmap/component.json +18 -0
- package/packs/gallery-soft/heatmap/example.html +3 -0
- package/packs/gallery-soft/heatmap/kit.js +498 -0
- package/packs/gallery-soft/heatmap/preview.svg +1 -0
- package/packs/gallery-soft/heatmap/style.css +181 -0
- package/packs/gallery-soft/heatmap/template.html +3 -0
- package/packs/gallery-soft/heatmap/writing.md +23 -0
- package/packs/gallery-soft/note/component.json +14 -0
- package/packs/gallery-soft/note/example.html +3 -0
- package/packs/gallery-soft/note/kit.js +162 -0
- package/packs/gallery-soft/note/preview.svg +1 -0
- package/packs/gallery-soft/note/style.css +148 -0
- package/packs/gallery-soft/note/template.html +3 -0
- package/packs/gallery-soft/note/writing.md +20 -0
- package/packs/gallery-soft/pack.json +8 -0
- package/packs/gallery-soft/recent/component.json +13 -0
- package/packs/gallery-soft/recent/example.html +1 -0
- package/packs/gallery-soft/recent/kit.js +335 -0
- package/packs/gallery-soft/recent/preview.svg +1 -0
- package/packs/gallery-soft/recent/style.css +160 -0
- package/packs/gallery-soft/recent/template.html +1 -0
- package/packs/gallery-soft/recent/writing.md +17 -0
- package/packs/gallery-soft/static/component.json +13 -0
- package/packs/gallery-soft/static/example.html +12 -0
- package/packs/gallery-soft/static/preview.svg +1 -0
- package/packs/gallery-soft/static/style.css +186 -0
- package/packs/gallery-soft/static/template.html +1 -0
- package/packs/gallery-soft/static/writing.md +20 -0
- package/packs/gallery-soft/stats/component.json +13 -0
- package/packs/gallery-soft/stats/example.html +1 -0
- package/packs/gallery-soft/stats/kit.js +341 -0
- package/packs/gallery-soft/stats/preview.svg +1 -0
- package/packs/gallery-soft/stats/style.css +119 -0
- package/packs/gallery-soft/stats/template.html +1 -0
- package/packs/gallery-soft/stats/writing.md +13 -0
- package/packs/gallery-soft/today/component.json +12 -0
- package/packs/gallery-soft/today/example.html +1 -0
- package/packs/gallery-soft/today/kit.js +222 -0
- package/packs/gallery-soft/today/preview.svg +1 -0
- package/packs/gallery-soft/today/style.css +178 -0
- package/packs/gallery-soft/today/template.html +1 -0
- package/packs/gallery-soft/today/writing.md +16 -0
- package/packs/gallery-soft/todos/component.json +19 -0
- package/packs/gallery-soft/todos/example.html +3 -0
- package/packs/gallery-soft/todos/kit.js +527 -0
- package/packs/gallery-soft/todos/preview.svg +1 -0
- package/packs/gallery-soft/todos/style.css +212 -0
- package/packs/gallery-soft/todos/template.html +3 -0
- package/packs/gallery-soft/todos/writing.md +32 -0
- package/packs/gallery-soft/weather/component.json +19 -0
- package/packs/gallery-soft/weather/example.html +3 -0
- package/packs/gallery-soft/weather/kit.js +411 -0
- package/packs/gallery-soft/weather/preview.svg +1 -0
- package/packs/gallery-soft/weather/style.css +185 -0
- package/packs/gallery-soft/weather/template.html +3 -0
- package/packs/gallery-soft/weather/writing.md +28 -0
- package/release.json +12 -10
- package/sdk/doc-kit.d.ts +396 -5
- package/sdk/doc-state.d.ts +2 -0
- package/skill/SKILL.md +56 -23
- package/skill/references/block-script.md +140 -0
- package/skill/references/building-blocks.md +257 -0
- package/skill/references/extensions.md +59 -0
- package/skill/references/pages-and-data.md +225 -0
- package/skill/references/writing-html.md +8 -4
- package/skill/sdk/doc-kit.d.ts +396 -5
- package/skill/sdk/doc-state.d.ts +2 -0
- package/web/assets/index-BM_K-Auu.css +1 -0
- package/web/assets/index-DRslOBiv.js +15 -0
- package/web/index.html +2 -2
- package/dist/chunk-3HIRPVLU.mjs +0 -2
- package/dist/chunk-5MHMDLZD.mjs +0 -4
- package/dist/chunk-64K7IPLO.mjs +0 -255
- package/dist/chunk-6QXGZM36.mjs +0 -8
- package/dist/chunk-6RGJOMJP.mjs +0 -16
- package/dist/chunk-AJ73XJF3.mjs +0 -2
- package/dist/chunk-AUZGSZJH.mjs +0 -13
- package/dist/chunk-BFE45AKL.mjs +0 -2
- package/dist/chunk-BXO2ZY5P.mjs +0 -2
- package/dist/chunk-CEH4MRCC.mjs +0 -2
- package/dist/chunk-CY2FNNAB.mjs +0 -16
- package/dist/chunk-DFUDV4LX.mjs +0 -2
- package/dist/chunk-DKXG4XDG.mjs +0 -2
- package/dist/chunk-EZQ34M3F.mjs +0 -124
- package/dist/chunk-EZY3WC6Z.mjs +0 -15
- package/dist/chunk-FUKQNOQS.mjs +0 -9
- package/dist/chunk-JPOSLGOC.mjs +0 -6
- package/dist/chunk-JVHHHGEA.mjs +0 -3
- package/dist/chunk-L3QKH4OK.mjs +0 -26
- package/dist/chunk-LAE5NQ4B.mjs +0 -2
- package/dist/chunk-LEF6DRCK.mjs +0 -59
- package/dist/chunk-NO5NJCHO.mjs +0 -2
- package/dist/chunk-NQPVAU63.mjs +0 -2
- package/dist/chunk-NSKUTQ5J.mjs +0 -5
- package/dist/chunk-O35FIXRB.mjs +0 -2
- package/dist/chunk-P2CAZPDP.mjs +0 -3
- package/dist/chunk-PL6GHLGD.mjs +0 -15
- package/dist/chunk-QJIR2BLP.mjs +0 -6
- package/dist/chunk-QUPLVPB2.mjs +0 -7
- package/dist/chunk-R7BNENLY.mjs +0 -4
- package/dist/chunk-S6O4UHLC.mjs +0 -2
- package/dist/chunk-SGJWQKEI.mjs +0 -2
- package/dist/chunk-TX6JH7TR.mjs +0 -2
- package/dist/chunk-TYK6VNAB.mjs +0 -10
- package/dist/chunk-UALRNVSE.mjs +0 -4
- package/dist/chunk-V3HXVQEM.mjs +0 -2
- package/dist/chunk-V5VXUJKG.mjs +0 -2
- package/dist/chunk-VBXMADMP.mjs +0 -2
- package/dist/chunk-VNV55RUA.mjs +0 -2
- package/dist/chunk-VPD2PS35.mjs +0 -2
- package/dist/chunk-W4VKN3GF.mjs +0 -7
- package/dist/chunk-W5BXXPDJ.mjs +0 -3
- package/dist/chunk-XUNHRCOG.mjs +0 -6
- package/skill/references/building-components.md +0 -367
- package/web/assets/index-Bh74DfsV.css +0 -1
- package/web/assets/index-UW0RyFFt.js +0 -13
|
@@ -1,7 +1,9 @@
|
|
|
1
1
|
// The session between a report page and a workbench that shows it in an iframe of the same origin
|
|
2
2
|
// (docs/workbench.md): the page's side is src/editor/page/session.mjs, the workbench's
|
|
3
3
|
// src/workbench/app/session/. Every message is { protocol: PROTOCOL, v: VERSION, type, slug, ... },
|
|
4
|
-
// posted to the other window for this origin only
|
|
4
|
+
// posted to the other window for this origin only; or, for a draft of another workspace, between the
|
|
5
|
+
// page and a workbench of another origin each side's server vouched for (the page's ?shell=<origin>,
|
|
6
|
+
// GET /__gallery/workspace/shell; the workbench's POST elsewhere: src/workbench/elsewhere.mjs).
|
|
5
7
|
//
|
|
6
8
|
// report -> workbench ready once the editor started: { commands, title, icon, look, state, annotations, card }
|
|
7
9
|
// state when the state, the title, the page's icon, the look it shows, how many 批注 it
|
|
@@ -31,9 +33,14 @@
|
|
|
31
33
|
// workspace a page was made under this one (a page block's box, the page itself
|
|
32
34
|
// staying as it is): the workbench reads the list of pages again and
|
|
33
35
|
// shows this page's row open
|
|
36
|
+
// consent a block's card asks to be let online (its 允许访问: the kit's net.js):
|
|
37
|
+
// { block (its id), hosts (those of its needs waiting) }: the workbench
|
|
38
|
+
// opens its consent dialog, which writes what the reader says
|
|
34
39
|
// annotations-removed
|
|
35
40
|
// a 批注 deleted from its card: { items }: the workbench says so, as
|
|
36
41
|
// it does for 全部删除, and its 撤销 puts them back
|
|
42
|
+
// bye the page goes (pagehide), to a workbench of another origin alone, which
|
|
43
|
+
// cannot see it go: its session ends there
|
|
37
44
|
// workbench -> report command { id, name, ... }
|
|
38
45
|
|
|
39
46
|
export const PROTOCOL = "gallery/session";
|
|
@@ -0,0 +1,299 @@
|
|
|
1
|
+
import { createHash } from "node:crypto";
|
|
2
|
+
import fs from "node:fs";
|
|
3
|
+
import path from "node:path";
|
|
4
|
+
import { beforeCatalogRead } from "./component-catalog.mjs";
|
|
5
|
+
import { packsDirectory } from "./paths.mjs";
|
|
6
|
+
import { PACKAGE_MANIFEST, layoutOf } from "./workspace.mjs";
|
|
7
|
+
|
|
8
|
+
// Gallery's own custom blocks (自带块): the blocks of Gallery's own block packs (./block-packs.mjs), a
|
|
9
|
+
// folder each in the package (src/packs/<pack>/<name>/ in the source checkout, packs/<pack>/<name>/ in
|
|
10
|
+
// the release), each a block of the scope <pack> as any workspace's is, its manifest's id <pack>/<name>:
|
|
11
|
+
// the pack gallery's (Gallery 风格) and gallery-soft's (柔光风格). A workspace's first start installs each
|
|
12
|
+
// pack as any shared pack is installed (./block-packs.mjs installOfficialPacks); gallery block add <name>
|
|
13
|
+
// (gallery's, or <pack>/<name>) copies one unchanged into a workspace, components/<pack>/<name>/, and records its
|
|
14
|
+
// version and a fingerprint of what it copied in .gallery/blocks.json; adding it again updates a copy
|
|
15
|
+
// that is as it was put there, and never one whose fingerprint has changed since, which is someone's
|
|
16
|
+
// work (gallery block new <id> --recipe <name> starts a block of one's own from a shipped one instead).
|
|
17
|
+
// The scopes of Gallery's packs are kept for these: gallery block new refuses them. A custom page's
|
|
18
|
+
// service (phase 2) adds one the same way when a card asks for it.
|
|
19
|
+
//
|
|
20
|
+
// A workspace's copies follow Gallery (the user, 2026-11-09: a home page made with 1.0.0's cards kept
|
|
21
|
+
// their plain look after 1.1.0 brought the cards' design): a copy that is as it was added and behind
|
|
22
|
+
// Gallery's is updated in place, as gallery block add would update it, without the command
|
|
23
|
+
// (followShipped): as a server starts (src/server/index.mjs, production.mjs), whenever its catalog
|
|
24
|
+
// reads the workspace's blocks (readCatalog, by followOnRead's hook) and when the page service reads
|
|
25
|
+
// them (its library, an add), once a process for each block and version, told once in the server's
|
|
26
|
+
// log. A copy changed since it was added is someone's work and stays as it is: the log says so once,
|
|
27
|
+
// and 设置 › 组件列表 and gallery block list say that Gallery has a newer one and how to take it.
|
|
28
|
+
|
|
29
|
+
/** The scope of Gallery's own blocks that a bare name names (gallery block add card): the pack gallery's. */
|
|
30
|
+
export const SHIPPED_SCOPE = "gallery";
|
|
31
|
+
|
|
32
|
+
// What a system writes into a folder it shows, which nobody wrote: macOS's Finder (.DS_Store, and ._
|
|
33
|
+
// files beside each on a disk of another format), Windows' Explorer (Thumbs.db, desktop.ini). No
|
|
34
|
+
// fingerprint counts them, no add takes them out, and a recipe copies none.
|
|
35
|
+
const SYSTEM_FILE = /^(?:\.DS_Store|\._.*|Thumbs\.db|ehthumbs\.db|desktop\.ini)$/i;
|
|
36
|
+
|
|
37
|
+
/** Whether a file called `name` (its last part) is one a system wrote into a folder it showed. */
|
|
38
|
+
export const isSystemFile = (name) => SYSTEM_FILE.test(name);
|
|
39
|
+
|
|
40
|
+
/** The files of a folder, by their paths in it with "/", sorted, what a system wrote there left out. */
|
|
41
|
+
export function filesIn(folder) {
|
|
42
|
+
return fs.readdirSync(folder, { recursive: true, withFileTypes: true }).filter((entry) => entry.isFile() && !SYSTEM_FILE.test(entry.name))
|
|
43
|
+
.map((entry) => path.relative(folder, path.join(entry.parentPath, entry.name)).split(path.sep).join("/")).sort();
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
/**
|
|
47
|
+
* The names of a block's files in the order they are written: its manifest last, what makes a folder a
|
|
48
|
+
* block to whoever watches (a running server's watcher, the catalog), so that a block that appears is
|
|
49
|
+
* whole, and one a write stopped partway through is a folder with no manifest, which loads as nothing.
|
|
50
|
+
*/
|
|
51
|
+
export const writingOrder = (names) => [...names.filter((name) => name !== PACKAGE_MANIFEST), ...(names.includes(PACKAGE_MANIFEST) ? [PACKAGE_MANIFEST] : [])];
|
|
52
|
+
|
|
53
|
+
/** What a folder holds, as a hash of each file's path and bytes (what a system wrote there aside), or null when there is no such folder. */
|
|
54
|
+
export function fingerprintOf(folder) {
|
|
55
|
+
if (!fs.existsSync(folder)) return null;
|
|
56
|
+
return fingerprintOfFiles(filesIn(folder).map((name) => ({ name, data: fs.readFileSync(path.join(folder, name)) })));
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
/** What fingerprintOf says of a folder that holds `files` alone ([{ name, data }], each by its path in it with "/"). */
|
|
60
|
+
export function fingerprintOfFiles(files) {
|
|
61
|
+
const hash = createHash("sha256");
|
|
62
|
+
const named = files.filter(({ name }) => !SYSTEM_FILE.test(name.split("/").at(-1))).sort((a, b) => (a.name < b.name ? -1 : a.name > b.name ? 1 : 0));
|
|
63
|
+
for (const { name, data } of named) hash.update(`${name}\u0000`).update(data).update("\n");
|
|
64
|
+
return hash.digest("hex").slice(0, 16);
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
// The folders right in `directory`, by name, or none where it is not there.
|
|
68
|
+
const foldersOf = (directory) => {
|
|
69
|
+
try {
|
|
70
|
+
return fs.readdirSync(directory, { withFileTypes: true }).filter((entry) => entry.isDirectory()).map((entry) => entry.name).sort();
|
|
71
|
+
} catch {
|
|
72
|
+
return [];
|
|
73
|
+
}
|
|
74
|
+
};
|
|
75
|
+
|
|
76
|
+
/** The ids of Gallery's own packs in `directory` (the package's): each folder of it, by name. */
|
|
77
|
+
export const shippedPackIds = (directory = packsDirectory) => foldersOf(directory);
|
|
78
|
+
|
|
79
|
+
/**
|
|
80
|
+
* Gallery's own blocks in `directory` (the package's packs): [{ name, id, pack, folder, version, title:
|
|
81
|
+
* { zh, en }, description: { zh, en }, places }], by pack and name; a folder whose manifest does not read
|
|
82
|
+
* as its pack's block of its name is none.
|
|
83
|
+
*/
|
|
84
|
+
export function shippedBlocks(directory = packsDirectory) {
|
|
85
|
+
return foldersOf(directory).flatMap((pack) => foldersOf(path.join(directory, pack)).flatMap((name) => {
|
|
86
|
+
const folder = path.join(directory, pack, name);
|
|
87
|
+
try {
|
|
88
|
+
const manifest = JSON.parse(fs.readFileSync(path.join(folder, PACKAGE_MANIFEST), "utf8"));
|
|
89
|
+
if (manifest.id !== `${pack}/${name}`) return [];
|
|
90
|
+
return [{ name, id: manifest.id, pack, folder, version: manifest.version, title: manifest.name, description: manifest.description, places: manifest.places ?? ["document"] }];
|
|
91
|
+
} catch {
|
|
92
|
+
return [];
|
|
93
|
+
}
|
|
94
|
+
}));
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
/** The shipped block `written` names (card, gallery/card, gallery-soft/todos: a bare name is the pack gallery's), or null. */
|
|
98
|
+
export function shippedBlock(written, directory = packsDirectory) {
|
|
99
|
+
const id = written.includes("/") ? written : `${SHIPPED_SCOPE}/${written}`;
|
|
100
|
+
return shippedBlocks(directory).find((block) => block.id === id) ?? null;
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
/** Whether `id` is of a scope of Gallery's own packs (gallery/…, gallery-soft/…). */
|
|
104
|
+
export const isShippedId = (id, directory = packsDirectory) => shippedPackIds(directory).includes(String(id).split("/")[0]);
|
|
105
|
+
|
|
106
|
+
/**
|
|
107
|
+
* .gallery/blocks.json: { "<id>": { version, fingerprint } } of each block added or installed (one of
|
|
108
|
+
* Gallery's own, or of a pack), and `packs`, { "<pack id>": { version, fingerprint, blocks, official? } } of
|
|
109
|
+
* each pack installed (./block-packs.mjs); {} for none or a file that does not read.
|
|
110
|
+
*/
|
|
111
|
+
export function recordOf(root) {
|
|
112
|
+
try {
|
|
113
|
+
const record = JSON.parse(fs.readFileSync(layoutOf(root).blocks, "utf8"));
|
|
114
|
+
return record && typeof record === "object" && !Array.isArray(record) ? record : {};
|
|
115
|
+
} catch {
|
|
116
|
+
return {};
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
/** .gallery/blocks.json as `record` says. */
|
|
121
|
+
export function writeRecord(root, record) {
|
|
122
|
+
const file = layoutOf(root).blocks;
|
|
123
|
+
fs.mkdirSync(path.dirname(file), { recursive: true });
|
|
124
|
+
fs.writeFileSync(file, `${JSON.stringify(record, null, 2)}\n`);
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
/** Where a block of the workspace at `root` is. */
|
|
128
|
+
const folderIn = (root, id) => path.join(layoutOf(root).components, ...id.split("/"));
|
|
129
|
+
|
|
130
|
+
/**
|
|
131
|
+
* What the workspace at `root` holds of the shipped `block`: { added (a folder of its id is there),
|
|
132
|
+
* version (what its manifest says, or null), changed (its files are not what was added: changed since,
|
|
133
|
+
* or put there by some other hand), behind (it is as added, and Gallery's is another now) }.
|
|
134
|
+
*/
|
|
135
|
+
export function shippedState(root, block) {
|
|
136
|
+
const folder = folderIn(root, block.id);
|
|
137
|
+
const now = fingerprintOf(folder);
|
|
138
|
+
if (now === null) return { added: false, version: null, changed: false, behind: false };
|
|
139
|
+
let version = null;
|
|
140
|
+
try {
|
|
141
|
+
version = JSON.parse(fs.readFileSync(path.join(folder, PACKAGE_MANIFEST), "utf8")).version ?? null;
|
|
142
|
+
} catch {}
|
|
143
|
+
const kept = recordOf(root)[block.id];
|
|
144
|
+
const shipped = fingerprintOf(block.folder);
|
|
145
|
+
const changed = now !== shipped && now !== kept?.fingerprint;
|
|
146
|
+
return { added: true, version, changed, behind: !changed && now !== shipped };
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
/**
|
|
150
|
+
* Copies the shipped `block` into the workspace at `root`, unchanged: { did: "added", "updated" (from a
|
|
151
|
+
* copy as it was added, `from` its version) or "same" (nothing to do), folder }. A copy whose files
|
|
152
|
+
* changed since it was added (or that no add put there) is left as it is: an error with code "changed".
|
|
153
|
+
* The manifest is written last, what makes a folder a block to a running server's watcher, so that a
|
|
154
|
+
* block that appears is whole; files of the old copy that the new one has not go first.
|
|
155
|
+
*/
|
|
156
|
+
export function addShipped(root, block) {
|
|
157
|
+
const folder = folderIn(root, block.id);
|
|
158
|
+
const state = shippedState(root, block);
|
|
159
|
+
if (state.changed) throw Object.assign(new Error(`${block.id} was changed after it was added`), { code: "changed", folder });
|
|
160
|
+
const shipped = fingerprintOf(block.folder);
|
|
161
|
+
const record = recordOf(root);
|
|
162
|
+
if (state.added && !state.behind) {
|
|
163
|
+
if (record[block.id]?.fingerprint !== shipped) writeRecord(root, { ...record, [block.id]: { version: block.version, fingerprint: shipped } });
|
|
164
|
+
return { did: "same", folder };
|
|
165
|
+
}
|
|
166
|
+
const files = filesIn(block.folder);
|
|
167
|
+
if (state.added) for (const old of filesIn(folder)) if (!files.includes(old)) fs.rmSync(path.join(folder, old));
|
|
168
|
+
for (const file of writingOrder(files)) {
|
|
169
|
+
fs.mkdirSync(path.dirname(path.join(folder, file)), { recursive: true });
|
|
170
|
+
fs.copyFileSync(path.join(block.folder, file), path.join(folder, file));
|
|
171
|
+
}
|
|
172
|
+
writeRecord(root, { ...record, [block.id]: { version: block.version, fingerprint: shipped } });
|
|
173
|
+
return { did: state.added ? "updated" : "added", from: state.version, folder };
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
// A version's numbers (1.10.0: [1, 10, 0]), or null for one that is not three of them.
|
|
177
|
+
const numbersOf = (version) => (/^\d+\.\d+\.\d+$/.test(String(version ?? "")) ? version.split(".").map(Number) : null);
|
|
178
|
+
|
|
179
|
+
/** Whether version `a` comes after `b` (both x.y.z); `b` none or not of that form: whether they differ. */
|
|
180
|
+
export function versionAfter(a, b) {
|
|
181
|
+
const [x, y] = [numbersOf(a), numbersOf(b)];
|
|
182
|
+
if (!x || !y) return a !== b;
|
|
183
|
+
const at = x.findIndex((number, index) => number !== y[index]);
|
|
184
|
+
return at !== -1 && x[at] > y[at];
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
/**
|
|
188
|
+
* The version of the shipped `block` that the workspace at `root` does not take because its copy was
|
|
189
|
+
* changed since it was added (or no add put it there), when Gallery's comes after the copy's; else null.
|
|
190
|
+
*/
|
|
191
|
+
export function shippedNewer(root, block) {
|
|
192
|
+
const state = shippedState(root, block);
|
|
193
|
+
return state.changed && versionAfter(block.version, state.version) ? block.version : null;
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
const looked = new Map(); // a workspace's root and a shipped block's folder -> the version of it looked at
|
|
197
|
+
let told = () => {}; // where followShipped tells what it did when it is not given a log: the server's (followOnRead)
|
|
198
|
+
|
|
199
|
+
// What followShipped did, as lines of the log.
|
|
200
|
+
function followedLines(root, { updated, kept, failed }) {
|
|
201
|
+
const lines = [];
|
|
202
|
+
if (updated.length) lines.push(`Gallery's own blocks in ${root}, as they were added, updated to this Gallery's: ${updated.map(({ id, from, to }) => `${id} ${from ?? "?"} -> ${to}`).join(", ")}`);
|
|
203
|
+
for (const { id, version, shipped } of kept) lines.push(`${id} in ${root} was changed after it was added, so it stays at ${version ?? "its version"}: Gallery's is ${shipped} (设置 › 组件列表 says how to take it)`);
|
|
204
|
+
for (const { id, to, why } of failed) lines.push(`${id} in ${root} could not be updated to Gallery's ${to}: ${why}`);
|
|
205
|
+
return lines;
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
/**
|
|
209
|
+
* Bring the workspace at `root`'s copies of Gallery's own blocks (of `ids`, by default each one) up to
|
|
210
|
+
* Gallery's (in `directory`): one that is as it was added and behind is updated as addShipped updates
|
|
211
|
+
* it (the manifest written last); one changed since it was added is kept as it is. Each block and
|
|
212
|
+
* version is looked at once a process, a later call for it doing nothing, so that what reads the blocks
|
|
213
|
+
* again and again (a server's catalog, its page service) pays once. `log`: told once of what was done,
|
|
214
|
+
* a line each (by default the one followOnRead set: none in a command). Never throws: { updated: [{ id,
|
|
215
|
+
* from, to }], kept: [{ id, version, shipped }] (changed, Gallery's newer), failed: [{ id, to, why }] }.
|
|
216
|
+
*/
|
|
217
|
+
export function followShipped(root, { ids = null, directory = packsDirectory, log = null } = {}) {
|
|
218
|
+
const done = { updated: [], kept: [], failed: [] };
|
|
219
|
+
const key = path.resolve(root);
|
|
220
|
+
for (const block of shippedBlocks(directory)) {
|
|
221
|
+
if (ids && !ids.includes(block.id)) continue;
|
|
222
|
+
const at = `${key}\u0000${path.resolve(block.folder)}`;
|
|
223
|
+
if (looked.get(at) === block.version) continue;
|
|
224
|
+
looked.set(at, block.version);
|
|
225
|
+
try {
|
|
226
|
+
const state = shippedState(root, block);
|
|
227
|
+
if (state.changed && versionAfter(block.version, state.version)) done.kept.push({ id: block.id, version: state.version, shipped: block.version });
|
|
228
|
+
if (!state.behind) continue;
|
|
229
|
+
if (addShipped(root, block).did === "updated") done.updated.push({ id: block.id, from: state.version, to: block.version });
|
|
230
|
+
} catch (error) {
|
|
231
|
+
done.failed.push({ id: block.id, to: block.version, why: error?.message ?? String(error) });
|
|
232
|
+
}
|
|
233
|
+
}
|
|
234
|
+
for (const line of followedLines(key, done)) (log ?? told)(line);
|
|
235
|
+
return done;
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
const following = new Set(); // the workspaces whose server runs in this process (followOnRead), by their resolved root
|
|
239
|
+
const keyOf = (root) => (process.platform === "win32" ? path.resolve(root).toLowerCase() : path.resolve(root));
|
|
240
|
+
|
|
241
|
+
/**
|
|
242
|
+
* From now on in this process, the catalog brings the copies of Gallery's own blocks of the workspace at
|
|
243
|
+
* `root` up to Gallery's before it reads them (followShipped, its ids those of the scopes of Gallery's
|
|
244
|
+
* packs it finds), and what is done of it is told to `log` (a line): a server's, set as it starts for
|
|
245
|
+
* its own workspace (another's blocks are its own server's to follow, and a test's process reads the
|
|
246
|
+
* repository's reports/ too, which nothing of it is to write).
|
|
247
|
+
*/
|
|
248
|
+
export function followOnRead(root, log) {
|
|
249
|
+
following.add(keyOf(root));
|
|
250
|
+
told = log;
|
|
251
|
+
beforeCatalogRead((read, ids) => {
|
|
252
|
+
if (following.has(keyOf(read))) followShipped(read, { ids });
|
|
253
|
+
}, shippedPackIds());
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
// The words of a shipped block's files that name it, and what a recipe's copy names instead: its id,
|
|
257
|
+
// and the id with "-" for "/" (a class, a chart type).
|
|
258
|
+
const namesOf = (id) => [id, id.replace("/", "-")];
|
|
259
|
+
const escaped = (words) => words.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
260
|
+
|
|
261
|
+
/**
|
|
262
|
+
* The shipped block whose preview.svg the file `bytes` is, byte for byte, as Gallery ships it or as a
|
|
263
|
+
* recipe of it for the block `id` has it (every word that named it naming `id`), or null: a block made
|
|
264
|
+
* by --recipe keeps its recipe's picture until someone draws its own, which gallery block check notes.
|
|
265
|
+
*/
|
|
266
|
+
export function shippedPreviewOf(bytes, id, directory = packsDirectory) {
|
|
267
|
+
for (const block of shippedBlocks(directory)) {
|
|
268
|
+
if (block.id === id) continue; // a shipped block's own picture is its own
|
|
269
|
+
let shipped;
|
|
270
|
+
try {
|
|
271
|
+
shipped = fs.readFileSync(path.join(block.folder, "preview.svg"));
|
|
272
|
+
} catch {
|
|
273
|
+
continue;
|
|
274
|
+
}
|
|
275
|
+
if (shipped.equals(bytes) || Buffer.from(recipeFiles(block, id)["preview.svg"] ?? "").equals(bytes)) return block;
|
|
276
|
+
}
|
|
277
|
+
return null;
|
|
278
|
+
}
|
|
279
|
+
|
|
280
|
+
/**
|
|
281
|
+
* The files of a new block `id` made from the shipped `block` (gallery block new <id> --recipe <name>),
|
|
282
|
+
* by name, the manifest last: each as Gallery ships it, every word that names the shipped block naming
|
|
283
|
+
* the new one, all in one pass, so that a new name holding an old one (local/gallery-card, made of
|
|
284
|
+
* gallery/card) is not renamed again; its version 0.1.0.
|
|
285
|
+
*/
|
|
286
|
+
export function recipeFiles(block, id) {
|
|
287
|
+
const [from, to] = [namesOf(block.id), namesOf(id)];
|
|
288
|
+
const names = new RegExp(from.map(escaped).join("|"), "g");
|
|
289
|
+
const files = {};
|
|
290
|
+
for (const file of filesIn(block.folder)) {
|
|
291
|
+
const bytes = fs.readFileSync(path.join(block.folder, file));
|
|
292
|
+
if (/\.(?:json|html|md|css|js|svg)$/.test(file)) {
|
|
293
|
+
let text = bytes.toString("utf8").replace(names, (name) => to[from.indexOf(name)]);
|
|
294
|
+
if (file === PACKAGE_MANIFEST) text = text.replace(/"version":\s*"[^"]*"/, '"version": "0.1.0"');
|
|
295
|
+
files[file] = text;
|
|
296
|
+
} else files[file] = bytes;
|
|
297
|
+
}
|
|
298
|
+
return Object.fromEntries(writingOrder(Object.keys(files)).map((name) => [name, files[name]]));
|
|
299
|
+
}
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
// The sidebar's head rows (docs/workbench.md "The sidebar", **Head**; the user's word of 2026-11-09):
|
|
2
|
+
// 新建, 搜索 and each custom page, one list the reader orders by dragging its rows (no row goes into
|
|
3
|
+
// another, none into the tree, no document among them), kept for the workspace in the outline file
|
|
4
|
+
// (.gallery/outline.json's `head`, which ./outline.mjs keeps as it writes the tree, so that every browser
|
|
5
|
+
// shows the order the reader gave). A row's key: "new" (新建), "search" (搜索), or "@<slug>" for a custom
|
|
6
|
+
// page (its address in the workbench, which no slug holds). Pure: the server's (shared/pages.mjs listPages,
|
|
7
|
+
// the workbench service's head) and the workbench's (its sidebar) alike.
|
|
8
|
+
|
|
9
|
+
/** The key of the head's 新建 row. */
|
|
10
|
+
export const HEAD_NEW = "new";
|
|
11
|
+
/** The key of the head's 搜索 row. */
|
|
12
|
+
export const HEAD_SEARCH = "search";
|
|
13
|
+
/** The key of custom page `slug`'s row: @<slug>. */
|
|
14
|
+
export const pageHeadKey = (slug) => `@${slug}`;
|
|
15
|
+
/** The custom page a head key names, or null (new, search). */
|
|
16
|
+
export const headPage = (key) => (typeof key === "string" && key.startsWith("@") ? key.slice(1) : null);
|
|
17
|
+
/** How many keys a stored head keeps at most (those of pages gone stay, so that one restored goes back to its place). */
|
|
18
|
+
export const MOST_HEAD = 200;
|
|
19
|
+
|
|
20
|
+
const KEY = /^(?:new|search|@[a-z0-9]+(?:-[a-z0-9]+)*)$/;
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* `value` as a head to store: an array of keys (new, search, @<slug>), each once, MOST_HEAD at most; null
|
|
24
|
+
* for anything else (not an array, a key that is none, one twice, too many).
|
|
25
|
+
*/
|
|
26
|
+
export function storedHead(value) {
|
|
27
|
+
if (!Array.isArray(value) || value.length > MOST_HEAD) return null;
|
|
28
|
+
if (!value.every((key) => typeof key === "string" && KEY.test(key))) return null;
|
|
29
|
+
return new Set(value).size === value.length ? [...value] : null;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
/**
|
|
33
|
+
* The head's rows in their order: the keys `stored` (a head as the outline file keeps it, or null) gives,
|
|
34
|
+
* those of pages that are not there passed over, then what it does not name: 新建 first and 搜索 after it
|
|
35
|
+
* where it names neither (as before any drag), and each page of `pages` (their slugs, in the order a page
|
|
36
|
+
* goes by when the reader gave it none: shared/pages.mjs inPageOrder) after the last row it names, in that
|
|
37
|
+
* order. Always holds new and search once each, and each page of `pages` once.
|
|
38
|
+
*/
|
|
39
|
+
export function headOrder(stored, pages = []) {
|
|
40
|
+
const there = new Set(pages);
|
|
41
|
+
const named = (storedHead(stored) ?? []).filter((key) => key === HEAD_NEW || key === HEAD_SEARCH || there.has(headPage(key)));
|
|
42
|
+
if (!named.includes(HEAD_SEARCH)) named.unshift(HEAD_SEARCH);
|
|
43
|
+
if (!named.includes(HEAD_NEW)) named.splice(named.indexOf(HEAD_SEARCH), 0, HEAD_NEW);
|
|
44
|
+
for (const slug of pages) if (!named.includes(pageHeadKey(slug))) named.push(pageHeadKey(slug));
|
|
45
|
+
return named;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
/**
|
|
49
|
+
* The head with the row `key` moved before the row `before` (null: last), the others as they were: what a
|
|
50
|
+
* drop on the head makes. Unchanged where `key` is not in it or is `before`.
|
|
51
|
+
*/
|
|
52
|
+
export function movedInHead(head, key, before) {
|
|
53
|
+
if (!head.includes(key) || key === before) return [...head];
|
|
54
|
+
const rest = head.filter((one) => one !== key);
|
|
55
|
+
const at = before === null ? rest.length : rest.indexOf(before);
|
|
56
|
+
rest.splice(at < 0 ? rest.length : at, 0, key);
|
|
57
|
+
return rest;
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
/**
|
|
61
|
+
* The stored head `stored` (or null, when none is kept yet: `shown`, the head as the sidebar shows it now,
|
|
62
|
+
* stands for it) with page `slug`'s row put right after the row of `after` (a page's slug), else last: a
|
|
63
|
+
* new page's place. Keys of pages gone are kept where they stand.
|
|
64
|
+
*/
|
|
65
|
+
export function headWithPage(stored, shown, slug, after = null) {
|
|
66
|
+
const head = (storedHead(stored) ?? storedHead(shown) ?? [HEAD_NEW, HEAD_SEARCH]).filter((key) => key !== pageHeadKey(slug));
|
|
67
|
+
const at = after ? head.indexOf(pageHeadKey(after)) : -1;
|
|
68
|
+
head.splice(at < 0 ? head.length : at + 1, 0, pageHeadKey(slug));
|
|
69
|
+
return head.slice(-MOST_HEAD);
|
|
70
|
+
}
|
|
@@ -13,11 +13,21 @@ import { isMissingValue, numberReading } from "./number-reading.mjs";
|
|
|
13
13
|
// copy or delete either block (a copied pair takes a key of its own:
|
|
14
14
|
// src/editor/page/clipboard/own/chart-keys.mjs, and the commit makes sure of it against the file:
|
|
15
15
|
// src/editor/source/chart-keys.mjs).
|
|
16
|
+
//
|
|
17
|
+
// A view of a table (plan 阶段 4: a task board, a count, a chart card of a custom block's) is the same
|
|
18
|
+
// link: an instance of a custom block whose manifest's needs hold "tables" names the table by that key
|
|
19
|
+
// (VIEW_FROM), reads its rows as a chart does (the kit's runtime/table-reading.js, context.table()) and
|
|
20
|
+
// changes them only by asking the page editor (an intent: docs/editor.md, "Table views"). A key is one
|
|
21
|
+
// table's, which any number of charts and views read: TABLE_READERS are the attributes that read one.
|
|
16
22
|
|
|
17
23
|
/** On a chart's host: the key of the table it draws. */
|
|
18
24
|
export const CHART_DATA = "data-doc-chart-data";
|
|
19
25
|
/** On a table's frame (.doc-table-wrap): the key a chart reads it by. */
|
|
20
26
|
export const CHART_SOURCE = "data-doc-chart-source";
|
|
27
|
+
/** On an instance of a custom block whose needs hold "tables": the key of the table it is a view of (context.table()). */
|
|
28
|
+
export const VIEW_FROM = "data-doc-from";
|
|
29
|
+
/** The attributes that name a table by its key, a chart's host's and a view's. */
|
|
30
|
+
export const TABLE_READERS = [CHART_DATA, VIEW_FROM];
|
|
21
31
|
/** A key: a letter, then letters, digits, "_" or "-", 32 at most. */
|
|
22
32
|
export const CHART_KEY = /^[A-Za-z][\w-]{0,31}$/;
|
|
23
33
|
|
|
@@ -38,6 +48,28 @@ const FORMULA = /\\\(([\s\S]*?)\\\)|\\\[([\s\S]*?)\\\]|\$\$([\s\S]*?)\$\$/g;
|
|
|
38
48
|
*/
|
|
39
49
|
export const cellWords = (text) => text.replace(FORMULA, (_, inline, display, dollars) => inline ?? display ?? dollars).replaceAll(ZWSP, "").replace(/\s+/g, " ").trim();
|
|
40
50
|
|
|
51
|
+
// A formula KaTeX drew on a page: its TeX is its annotation (its drawing's text is its glyphs, twice over).
|
|
52
|
+
const TEX = 'annotation[encoding="application/x-tex"]';
|
|
53
|
+
|
|
54
|
+
/**
|
|
55
|
+
* A cell's text on a page as the file writes it, as near as the page tells: a formula KaTeX drew as its
|
|
56
|
+
* TeX, the editor's chip of an empty one as nothing (the file's \(\)). Its words are then cellWords'.
|
|
57
|
+
* For the kit, which reads a table on a page (runtime/table-reading.js: a chart's, a view's and a package's rows).
|
|
58
|
+
* @param {Node} node
|
|
59
|
+
* @returns {string}
|
|
60
|
+
*/
|
|
61
|
+
export function cellText(node) {
|
|
62
|
+
if (node.nodeType === 3) return /** @type {Text} */ (node).data;
|
|
63
|
+
if (node.nodeType !== 1) return "";
|
|
64
|
+
const element = /** @type {Element} */ (node);
|
|
65
|
+
if (element.hasAttribute("data-ge-empty")) return "";
|
|
66
|
+
const tex = element.classList.contains("katex") ? element.querySelector(TEX) : null;
|
|
67
|
+
if (tex) return tex.textContent ?? "";
|
|
68
|
+
let text = "";
|
|
69
|
+
for (const child of element.childNodes) text += cellText(child);
|
|
70
|
+
return text;
|
|
71
|
+
}
|
|
72
|
+
|
|
41
73
|
// A header's data-sort-type that says its column holds no numbers: its values are its words.
|
|
42
74
|
const WORD_TYPES = new Set(["text", "date"]);
|
|
43
75
|
|
|
@@ -66,7 +98,7 @@ export function cellValue(cell, type = null) {
|
|
|
66
98
|
* row of header cells alone; null when it has neither), its header cells' data-sort-type (null where
|
|
67
99
|
* none), its rows of data in the file's order (never a <tfoot>'s), each cell { words, sort } (its
|
|
68
100
|
* words, cellWords', and its data-sort-value, or null), and whether a cell of the header or the rows
|
|
69
|
-
* spans rows or columns (
|
|
101
|
+
* spans rows or columns (runtime/table-reading.js readTable reads it from the page,
|
|
70
102
|
* chart-declarations.mjs tableCells from the file).
|
|
71
103
|
*
|
|
72
104
|
* `data` is what d3.csvParse gives: an object for each row of data, in their order, its values by
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
import { parse } from "parse5";
|
|
2
|
+
import { TODO } from "./components/list.mjs";
|
|
3
|
+
import { sha256 } from "./files.mjs";
|
|
4
|
+
import { attr, BLOCK_LEVEL, elementsOf, hasClass } from "./html-tree.mjs";
|
|
5
|
+
|
|
6
|
+
// A document's to-dos as its pages show them (the items of its to-do lists, ul.doc-todo): what the
|
|
7
|
+
// workspace's facts list (src/workbench/index.mjs, workspace.query("todos")) and what a check of one
|
|
8
|
+
// from another page finds it by (src/editor/todos.mjs, workspace.setTodo: the plan's 5.1), the one
|
|
9
|
+
// reading for both, so that a ref the facts gave names the item the write looks for. Pure but for the
|
|
10
|
+
// parser and the hash: no DOM.
|
|
11
|
+
|
|
12
|
+
const SKIPPED = new Set(["script", "style", "template", "noscript", "svg", "math"]);
|
|
13
|
+
const HEADING = /^h([1-6])$/;
|
|
14
|
+
const tidy = (text) => text.replace(/[\s]+/g, " ").trim();
|
|
15
|
+
|
|
16
|
+
// The words an element holds, as a reader reads them: its text, a line break a space, nothing of a script,
|
|
17
|
+
// a style or a drawing; `stop(child)`: a child left out with what it holds.
|
|
18
|
+
function wordsOf(node, stop = () => false) {
|
|
19
|
+
let text = "";
|
|
20
|
+
const visit = (current) => {
|
|
21
|
+
for (const child of current.childNodes ?? []) {
|
|
22
|
+
if (child.nodeName === "#text") text += child.value;
|
|
23
|
+
else if (child.tagName === "br") text += " ";
|
|
24
|
+
else if (child.tagName && !SKIPPED.has(child.tagName) && !stop(child)) visit(child);
|
|
25
|
+
}
|
|
26
|
+
};
|
|
27
|
+
visit(node);
|
|
28
|
+
return tidy(text);
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
// A to-do's own words: what the item holds before its lists and the blocks it holds (a paragraph, a
|
|
32
|
+
// picture), or, where it holds no words of its own (an item written <li><p>…</p></li>), its first block's.
|
|
33
|
+
function itemWords(item) {
|
|
34
|
+
const own = wordsOf(item, (child) => BLOCK_LEVEL.has(child.tagName));
|
|
35
|
+
if (own) return own;
|
|
36
|
+
const first = elementsOf(item).find((child) => BLOCK_LEVEL.has(child.tagName) && child.tagName !== "ul" && child.tagName !== "ol");
|
|
37
|
+
return first ? wordsOf(first, (child) => child.tagName === "ul" || child.tagName === "ol") : "";
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
/**
|
|
41
|
+
* The to-dos of a document's `text` (its page's HTML, as its pages see it), in their order: [{ text,
|
|
42
|
+
* done, block, path, nth }], `path` the headings above it (their words, the outermost first: an h2 under
|
|
43
|
+
* an h1 of the body, the document's title never one), `nth` which of the to-dos of the same words under
|
|
44
|
+
* the same path it is (0 the first). With `at`, each says where its <li> starts in `text` too (`at`, the
|
|
45
|
+
* offset of its start tag), which the editor's units name it by (source/units.mjs elStart).
|
|
46
|
+
*/
|
|
47
|
+
export function todosOf(text, { at = false } = {}) {
|
|
48
|
+
const root = parse(String(text), { sourceCodeLocationInfo: at });
|
|
49
|
+
const headings = []; // [{ level, words }]
|
|
50
|
+
const todos = [];
|
|
51
|
+
const seen = new Map();
|
|
52
|
+
const visit = (node) => {
|
|
53
|
+
for (const child of elementsOf(node)) {
|
|
54
|
+
if (SKIPPED.has(child.tagName)) continue;
|
|
55
|
+
const heading = HEADING.exec(child.tagName);
|
|
56
|
+
if (heading && !hasClass(child, "doc-title")) {
|
|
57
|
+
const level = Number(heading[1]);
|
|
58
|
+
while (headings.length && headings.at(-1).level >= level) headings.pop();
|
|
59
|
+
const words = wordsOf(child);
|
|
60
|
+
if (words) headings.push({ level, words });
|
|
61
|
+
continue;
|
|
62
|
+
}
|
|
63
|
+
if (child.tagName === "li" && child.parentNode?.tagName === "ul" && hasClass(child.parentNode, TODO)) {
|
|
64
|
+
const path = headings.map(({ words }) => words);
|
|
65
|
+
const words = itemWords(child);
|
|
66
|
+
const key = JSON.stringify([words, path]);
|
|
67
|
+
const nth = seen.get(key) ?? 0;
|
|
68
|
+
seen.set(key, nth + 1);
|
|
69
|
+
todos.push({ text: words, done: attr(child, "data-checked") !== undefined, block: attr(child, "data-block-id") ?? null, path, nth, ...(at ? { at: child.sourceCodeLocation?.startOffset ?? -1 } : {}) });
|
|
70
|
+
}
|
|
71
|
+
visit(child);
|
|
72
|
+
}
|
|
73
|
+
};
|
|
74
|
+
visit(root);
|
|
75
|
+
return todos;
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
/**
|
|
79
|
+
* The version of a document's file the facts read its to-dos from (the hash of its text, as a to-do's
|
|
80
|
+
* ref carries it: workspace.query("todos")), which a check of one finds it by its place in (`nth`) while
|
|
81
|
+
* the file is still that one.
|
|
82
|
+
*/
|
|
83
|
+
export const fileVersion = (source) => sha256(source).slice(0, 16);
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import os from "node:os";
|
|
2
|
+
import path from "node:path";
|
|
3
|
+
|
|
4
|
+
// The user's own folders for Gallery, outside every workspace: "cache", what may be thrown away (the
|
|
5
|
+
// update check's answer, src/cli/updates.mjs), and "data", what Gallery keeps of the machine (the
|
|
6
|
+
// registry of the workspaces used on it, ./workspace-registry.mjs). One function, so that every system
|
|
7
|
+
// finds them alike. Node's built-ins only: gallery --version reads it, and stays as fast as Node's start.
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* The folder of `kind` ("cache" or "data"): GALLERY_CACHE_DIR or GALLERY_DATA_DIR when set (the tests
|
|
11
|
+
* name folders of their own); else on Windows %LOCALAPPDATA%\gallery for both; on macOS
|
|
12
|
+
* ~/Library/Caches/gallery and ~/Library/Application Support/gallery; elsewhere $XDG_CACHE_HOME/gallery
|
|
13
|
+
* (~/.cache/gallery) and $XDG_STATE_HOME/gallery (~/.local/state/gallery). Only a path: nothing is made.
|
|
14
|
+
*/
|
|
15
|
+
export function userDirectory(kind, { env = process.env, platform = process.platform, home = os.homedir() } = {}) {
|
|
16
|
+
const cache = kind === "cache";
|
|
17
|
+
const own = cache ? env.GALLERY_CACHE_DIR : env.GALLERY_DATA_DIR;
|
|
18
|
+
if (own) return path.resolve(own);
|
|
19
|
+
if (platform === "win32") return path.join(env.LOCALAPPDATA || path.join(home, "AppData", "Local"), "gallery");
|
|
20
|
+
if (platform === "darwin") return path.join(home, "Library", cache ? "Caches" : "Application Support", "gallery");
|
|
21
|
+
return cache
|
|
22
|
+
? path.join(env.XDG_CACHE_HOME || path.join(home, ".cache"), "gallery")
|
|
23
|
+
: path.join(env.XDG_STATE_HOME || path.join(home, ".local", "state"), "gallery");
|
|
24
|
+
}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
// Gallery's versions compared, with nothing imported: the preview server's choice of a server to use
|
|
2
|
+
// or replace (./preview-server.mjs) and gallery --version's notes (src/cli/updates.mjs, which loads
|
|
3
|
+
// nothing it can do without) read it.
|
|
4
|
+
|
|
5
|
+
/** -1, 0 or 1 as version `a` is older than, the same as or newer than `b` (numbers by dots: 0.1.0 < 0.1.10 < 0.2.0). */
|
|
6
|
+
export function compareVersions(a, b) {
|
|
7
|
+
const parts = (version) => String(version ?? "0").split(/[.+-]/).slice(0, 3).map((part) => Number.parseInt(part, 10) || 0);
|
|
8
|
+
const [x, y] = [parts(a), parts(b)];
|
|
9
|
+
for (let index = 0; index < 3; index++) if ((x[index] ?? 0) !== (y[index] ?? 0)) return (x[index] ?? 0) < (y[index] ?? 0) ? -1 : 1;
|
|
10
|
+
return 0;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
/** A released version as npm writes one, numbers alone (0.1.2): what a registry's answer must be to be believed. */
|
|
14
|
+
export const RELEASED = /^\d{1,6}\.\d{1,6}\.\d{1,6}$/;
|