@heycys/gallery 0.1.1 → 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/THIRD-PARTY-NOTICES.md +2 -2
- package/browser/editor/components/align.mjs +58 -0
- package/browser/editor/components/code/index.mjs +1 -1
- package/browser/editor/components/columns/page.mjs +4 -4
- package/browser/editor/components/embed/index.mjs +2 -2
- package/browser/editor/components/embed/page.mjs +1 -1
- package/browser/editor/components/file/page.mjs +4 -4
- package/browser/editor/components/flowchart/add.mjs +7 -6
- package/browser/editor/components/flowchart/page.mjs +1 -1
- package/browser/editor/components/heading/index.mjs +7 -6
- package/browser/editor/components/icons.mjs +11 -0
- package/browser/editor/components/image/crop.mjs +6 -9
- package/browser/editor/components/image/index.mjs +2 -0
- package/browser/editor/components/image/page.mjs +172 -90
- package/browser/editor/components/installed/index.mjs +15 -4
- package/browser/editor/components/installed/page.mjs +103 -25
- package/browser/editor/components/installed/served.mjs +6 -5
- package/browser/editor/components/instances.mjs +18 -0
- package/browser/editor/components/list/page.mjs +3 -6
- package/browser/editor/components/media/icons.mjs +13 -8
- package/browser/editor/components/media/page.mjs +5 -3
- package/browser/editor/components/media/toolbar.mjs +12 -3
- package/browser/editor/components/paragraph/index.mjs +4 -3
- package/browser/editor/components/registry.mjs +30 -9
- package/browser/editor/components/table/index.mjs +61 -2
- package/browser/editor/components/table/page.mjs +1 -1
- package/browser/editor/page/after/index.mjs +288 -0
- package/browser/editor/page/align.mjs +91 -0
- package/browser/editor/page/annotate/card.mjs +3 -6
- package/browser/editor/page/autosave.mjs +310 -37
- package/browser/editor/page/beside.mjs +5 -6
- package/browser/editor/page/block-menu/index.mjs +6 -3
- package/browser/editor/page/blocks.mjs +3 -1
- package/browser/editor/page/board/client.mjs +57 -0
- package/browser/editor/page/board/hint.mjs +182 -0
- package/browser/editor/page/board/history.mjs +119 -0
- package/browser/editor/page/board/index.mjs +1059 -0
- package/browser/editor/page/board/motion.mjs +177 -0
- package/browser/editor/page/board/settings.mjs +210 -0
- package/browser/editor/page/caret.mjs +1 -1
- package/browser/editor/page/changes/bar.mjs +6 -14
- package/browser/editor/page/changes/index.mjs +2 -2
- package/browser/editor/page/clipboard/import/html.mjs +29 -6
- package/browser/editor/page/clipboard/import/inline.mjs +32 -0
- package/browser/editor/page/clipboard/import/markdown.mjs +58 -13
- package/browser/editor/page/clipboard/import/read.mjs +6 -1
- package/browser/editor/page/clipboard/import/to-blocks.mjs +44 -12
- package/browser/editor/page/clipboard/import/yuque.mjs +622 -0
- package/browser/editor/page/clipboard/index.mjs +133 -15
- package/browser/editor/page/clipboard/own/blocks.mjs +13 -14
- package/browser/editor/page/clipboard/own/chart-keys.mjs +41 -28
- package/browser/editor/page/clipboard/own/describe.mjs +6 -2
- package/browser/editor/page/clipboard/own/selection.mjs +1 -1
- package/browser/editor/page/columns/index.mjs +48 -46
- package/browser/editor/page/commit.mjs +80 -22
- package/browser/editor/page/conflicts.mjs +7 -7
- package/browser/editor/page/core.mjs +34 -16
- package/browser/editor/page/custom-page.mjs +110 -0
- package/browser/editor/page/editor.mjs +71 -17
- package/browser/editor/page/emoji-picker/styles.mjs +7 -12
- package/browser/editor/page/emoji-picker/upload.mjs +2 -2
- package/browser/editor/page/handle/index.mjs +5 -8
- package/browser/editor/page/history.mjs +41 -6
- package/browser/editor/page/insert/index.mjs +20 -22
- package/browser/editor/page/links/index.mjs +5 -3
- package/browser/editor/page/links/pages.mjs +27 -9
- package/browser/editor/page/look.mjs +54 -3
- package/browser/editor/page/margin.mjs +18 -3
- package/browser/editor/page/media-menu/index.mjs +6 -7
- package/browser/editor/page/menu.mjs +33 -14
- package/browser/editor/page/notices.mjs +2 -2
- package/browser/editor/page/page-objects.mjs +9 -2
- package/browser/editor/page/panel.mjs +4 -9
- package/browser/editor/page/present-links.mjs +15 -5
- package/browser/editor/page/present-shell.mjs +63 -0
- package/browser/editor/page/resize/index.mjs +42 -29
- package/browser/editor/page/selection/index.mjs +10 -2
- package/browser/editor/page/served.mjs +14 -0
- package/browser/editor/page/session.mjs +48 -4
- package/browser/editor/page/slash-menu/index.mjs +3 -3
- package/browser/editor/page/table/binding.mjs +87 -0
- package/browser/editor/page/table/cells.mjs +102 -46
- package/browser/editor/page/table/index.mjs +24 -9
- package/browser/editor/page/table/pictures.mjs +299 -0
- package/browser/editor/page/table/views.mjs +103 -0
- package/browser/editor/page/table/widths.mjs +82 -10
- package/browser/editor/page/text-select/index.mjs +26 -12
- package/browser/editor/page/todo-writes.mjs +75 -0
- package/browser/editor/page/typing/index.mjs +97 -15
- package/browser/editor/page/typing/leave.mjs +19 -5
- package/browser/editor/page/ui.mjs +13 -0
- package/browser/shared/block-packs.mjs +419 -0
- package/browser/shared/board-places.mjs +224 -0
- package/browser/shared/card-size.mjs +59 -0
- package/browser/shared/colors.mjs +3 -2
- package/browser/shared/component-catalog.mjs +330 -46
- package/browser/shared/component-source.mjs +39 -0
- package/browser/shared/components/heading.mjs +2 -1
- package/browser/shared/components/index.mjs +12 -3
- package/browser/shared/components/installed.mjs +35 -3
- package/browser/shared/components/page.mjs +20 -8
- package/browser/shared/components/paragraph.mjs +8 -1
- package/browser/shared/components/state.mjs +5 -1
- package/browser/shared/components/table.mjs +1 -0
- package/browser/shared/document-look.mjs +10 -5
- package/browser/shared/drafts.mjs +432 -0
- package/browser/shared/emoji/line-icons.mjs +37 -0
- package/browser/shared/extension-sidebar.mjs +126 -0
- package/browser/shared/extensions.mjs +79 -0
- package/browser/shared/file-table.mjs +101 -0
- package/browser/shared/http.mjs +9 -0
- package/browser/shared/i18n/en.mjs +330 -27
- package/browser/shared/json-layout.mjs +47 -0
- package/browser/shared/net-cache.mjs +133 -0
- package/browser/shared/net-keys.mjs +32 -0
- package/browser/shared/net-policy.mjs +177 -0
- package/browser/shared/outline-shape.mjs +128 -0
- package/browser/shared/outline.mjs +359 -67
- package/browser/shared/pack-manifest.mjs +88 -0
- package/browser/shared/page-address.mjs +6 -3
- package/browser/shared/page-cards.mjs +308 -0
- package/browser/shared/page-links.mjs +69 -6
- package/browser/shared/pages.mjs +500 -0
- package/browser/shared/paths.mjs +6 -0
- package/browser/shared/pinyin.mjs +92 -0
- package/browser/shared/present-step.mjs +17 -0
- package/browser/shared/preview-server.mjs +3 -7
- package/browser/shared/session.mjs +8 -1
- package/browser/shared/shipped-blocks.mjs +299 -0
- package/browser/shared/sidebar-head.mjs +70 -0
- package/browser/shared/table-chart.mjs +33 -1
- package/browser/shared/todos.mjs +83 -0
- package/browser/shared/user-directory.mjs +24 -0
- package/browser/shared/versions.mjs +14 -0
- package/browser/shared/web-links.mjs +139 -0
- package/browser/shared/workspace-columns.mjs +120 -0
- package/browser/shared/workspace-name.mjs +154 -0
- package/browser/shared/workspace-query.mjs +125 -0
- package/browser/shared/workspace-registry.mjs +272 -0
- package/browser/shared/workspace.mjs +171 -20
- package/dist/chunk-2OHANJ6Q.mjs +2 -0
- package/dist/chunk-3MBRL2PM.mjs +16 -0
- package/dist/chunk-4OKWZY5E.mjs +2 -0
- package/dist/chunk-4OZWXZE5.mjs +5 -0
- package/dist/chunk-5K44HLTZ.mjs +2 -0
- package/dist/{chunk-5ZKJ3H4P.mjs → chunk-5XA2ZBAE.mjs} +3 -3
- package/dist/{chunk-4FS7Z7WR.mjs → chunk-67N2QJYT.mjs} +1 -1
- package/dist/chunk-6KBYRA2C.mjs +2 -0
- package/dist/chunk-6N3PX4XX.mjs +8 -0
- package/dist/{chunk-V5JTW2LH.mjs → chunk-6QBHU4DF.mjs} +1 -1
- package/dist/chunk-7JDX4E65.mjs +13 -0
- package/dist/chunk-7M2BQQGZ.mjs +2 -0
- package/dist/chunk-7OG26PGF.mjs +2 -0
- package/dist/chunk-AHN3NFKJ.mjs +3 -0
- package/dist/chunk-ALZ6ZENZ.mjs +3 -0
- package/dist/chunk-AR5D57ZD.mjs +170 -0
- package/dist/{chunk-W3BGBJQW.mjs → chunk-BFJGHSQN.mjs} +1 -1
- package/dist/{chunk-LS4F7JUM.mjs → chunk-BZ5RAF7L.mjs} +1 -1
- package/dist/chunk-CMA72MAG.mjs +2 -0
- package/dist/{chunk-LCTHTZIL.mjs → chunk-DAZL73VK.mjs} +91 -91
- package/dist/{chunk-Y6RLRPG3.mjs → chunk-DJISHPUL.mjs} +1 -1
- package/dist/chunk-DR73Y2UJ.mjs +3 -0
- package/dist/{chunk-FDLXYYG4.mjs → chunk-EAIFITAV.mjs} +1 -1
- package/dist/{chunk-TMYZB6AV.mjs → chunk-EKNHM3P4.mjs} +1 -1
- package/dist/chunk-EP25HDAJ.mjs +2 -0
- package/dist/{chunk-GB5SOYQJ.mjs → chunk-ERLAIBOA.mjs} +2 -2
- package/dist/chunk-EURLTOTZ.mjs +4 -0
- package/dist/chunk-F4ZA6JRZ.mjs +3 -0
- package/dist/chunk-F6HVDZR4.mjs +2 -0
- package/dist/chunk-FDMAXMQA.mjs +2 -0
- package/dist/chunk-FETSREUN.mjs +5 -0
- package/dist/chunk-GHOYKMQ3.mjs +4 -0
- package/dist/{chunk-2B5E4CDJ.mjs → chunk-GPIWQ4X4.mjs} +1 -1
- package/dist/chunk-HDWTZ763.mjs +12 -0
- package/dist/chunk-HPOI4ZX7.mjs +6 -0
- package/dist/{chunk-BGGDRNYQ.mjs → chunk-HXG7EOPJ.mjs} +1 -1
- package/dist/chunk-IA4PSIMD.mjs +2 -0
- package/dist/{chunk-E7LWZRXY.mjs → chunk-ITOH5EGO.mjs} +1 -1
- package/dist/chunk-IV64FFI4.mjs +2 -0
- package/dist/chunk-J43Z6LSS.mjs +2 -0
- package/dist/chunk-J5PUIV3Y.mjs +4 -0
- package/dist/chunk-JA7G53PC.mjs +2 -0
- package/dist/chunk-JEUK3ZO7.mjs +2 -0
- package/dist/chunk-JLTZF4LA.mjs +2 -0
- package/dist/chunk-JZT7I2OJ.mjs +2 -0
- package/dist/chunk-K5XATEOO.mjs +2 -0
- package/dist/chunk-L2SUIS5S.mjs +2 -0
- package/dist/chunk-L7UP52JO.mjs +2 -0
- package/dist/chunk-LM4XFQHZ.mjs +2 -0
- package/dist/chunk-MN7BZL4R.mjs +2 -0
- package/dist/chunk-MTYYHM2G.mjs +15 -0
- package/dist/chunk-MXUBKDRO.mjs +15 -0
- package/dist/chunk-NAMN3RAF.mjs +2 -0
- package/dist/{chunk-SYGN7GLU.mjs → chunk-OEXWRJME.mjs} +1 -1
- package/dist/chunk-OFHXGWOX.mjs +2 -0
- package/dist/chunk-ORID3AE7.mjs +166 -0
- package/dist/chunk-PAREWQGB.mjs +4 -0
- package/dist/chunk-PGDE24N5.mjs +2 -0
- package/dist/chunk-POTA2FV4.mjs +2 -0
- package/dist/chunk-PUOQ65NC.mjs +2 -0
- package/dist/chunk-Q4UEPUWF.mjs +2 -0
- package/dist/chunk-QE5RG76S.mjs +549 -0
- package/dist/chunk-R2ZDLJYT.mjs +10 -0
- package/dist/{chunk-7DTINW6U.mjs → chunk-SQ6Y2ZMA.mjs} +2 -2
- package/dist/chunk-SWUTTZCN.mjs +2 -0
- package/dist/chunk-TANZRINB.mjs +2 -0
- package/dist/chunk-TR7TWGHB.mjs +2 -0
- package/dist/chunk-U5XL7D6A.mjs +3 -0
- package/dist/{chunk-XNROSH2T.mjs → chunk-U7NZI6N4.mjs} +2 -2
- package/dist/chunk-UGWMMEJ5.mjs +15 -0
- package/dist/chunk-UJQJKNGK.mjs +2 -0
- package/dist/chunk-UYVCQK3H.mjs +22 -0
- package/dist/chunk-VFX2KNHP.mjs +4 -0
- package/dist/chunk-VS7JIGJW.mjs +24 -0
- package/dist/chunk-W7665ZEC.mjs +6 -0
- package/dist/chunk-WQDQWCX5.mjs +2 -0
- package/dist/chunk-YI43RG4P.mjs +2 -0
- package/dist/chunk-YLPSMDIS.mjs +5 -0
- package/dist/chunk-YNAWBAYN.mjs +3 -0
- package/dist/chunk-YROX2O22.mjs +2 -0
- package/dist/chunk-ZDLPUOAG.mjs +6 -0
- package/dist/{chunk-IVDLMMBD.mjs → chunk-ZHEHPMBK.mjs} +1 -1
- package/dist/chunk-ZQS6H473.mjs +16 -0
- package/dist/chunk-ZTHICSSF.mjs +2 -0
- package/dist/chunk-ZWWC4KLF.mjs +20 -0
- package/dist/cli.mjs +1 -1
- package/dist/server.mjs +1 -1
- package/dist/{chunk-U6KNPJPR.mjs → update-fetch.mjs} +1 -1
- package/dist/worker.mjs +1 -1
- package/kit/board.css +95 -0
- package/kit/board.js +250 -0
- package/kit/charts.js +5 -71
- package/kit/code.js +17 -17
- package/kit/report.css +335 -18
- package/kit/runtime.js +1638 -125
- package/kit/state.js +10 -1
- package/kit/tables.js +130 -43
- package/kit/ui.js +79 -35
- package/package.json +2 -1
- package/packs/gallery/card/component.json +14 -0
- package/packs/gallery/card/example.html +10 -0
- package/packs/gallery/card/preview.svg +1 -0
- package/packs/gallery/card/style.css +6 -0
- package/packs/gallery/card/template.html +6 -0
- package/packs/gallery/card/writing.md +14 -0
- package/packs/gallery/chart-card/component.json +15 -0
- package/packs/gallery/chart-card/example.html +14 -0
- package/packs/gallery/chart-card/kit.js +130 -0
- package/packs/gallery/chart-card/preview.svg +1 -0
- package/packs/gallery/chart-card/style.css +42 -0
- package/packs/gallery/chart-card/template.html +13 -0
- package/packs/gallery/chart-card/writing.md +20 -0
- package/packs/gallery/chart-view/component.json +20 -0
- package/packs/gallery/chart-view/example.html +13 -0
- package/packs/gallery/chart-view/kit.js +355 -0
- package/packs/gallery/chart-view/preview.svg +1 -0
- package/packs/gallery/chart-view/style.css +94 -0
- package/packs/gallery/chart-view/template.html +3 -0
- package/packs/gallery/chart-view/writing.md +22 -0
- package/packs/gallery/countdown/component.json +18 -0
- package/packs/gallery/countdown/example.html +3 -0
- package/packs/gallery/countdown/kit.js +216 -0
- package/packs/gallery/countdown/preview.svg +1 -0
- package/packs/gallery/countdown/style.css +118 -0
- package/packs/gallery/countdown/template.html +3 -0
- package/packs/gallery/countdown/writing.md +22 -0
- package/packs/gallery/habit/component.json +14 -0
- package/packs/gallery/habit/example.html +3 -0
- package/packs/gallery/habit/kit.js +334 -0
- package/packs/gallery/habit/preview.svg +1 -0
- package/packs/gallery/habit/style.css +174 -0
- package/packs/gallery/habit/template.html +3 -0
- package/packs/gallery/habit/writing.md +21 -0
- package/packs/gallery/heatmap/component.json +18 -0
- package/packs/gallery/heatmap/example.html +3 -0
- package/packs/gallery/heatmap/kit.js +513 -0
- package/packs/gallery/heatmap/preview.svg +1 -0
- package/packs/gallery/heatmap/style.css +189 -0
- package/packs/gallery/heatmap/template.html +3 -0
- package/packs/gallery/heatmap/writing.md +21 -0
- package/packs/gallery/kanban/component.json +18 -0
- package/packs/gallery/kanban/example.html +12 -0
- package/packs/gallery/kanban/kit.js +540 -0
- package/packs/gallery/kanban/preview.svg +1 -0
- package/packs/gallery/kanban/style.css +212 -0
- package/packs/gallery/kanban/template.html +3 -0
- package/packs/gallery/kanban/writing.md +20 -0
- package/packs/gallery/metric/component.json +22 -0
- package/packs/gallery/metric/example.html +15 -0
- package/packs/gallery/metric/kit.js +248 -0
- package/packs/gallery/metric/preview.svg +1 -0
- package/packs/gallery/metric/style.css +92 -0
- package/packs/gallery/metric/template.html +3 -0
- package/packs/gallery/metric/writing.md +23 -0
- package/packs/gallery/note/component.json +14 -0
- package/packs/gallery/note/example.html +3 -0
- package/packs/gallery/note/kit.js +129 -0
- package/packs/gallery/note/preview.svg +1 -0
- package/packs/gallery/note/style.css +97 -0
- package/packs/gallery/note/template.html +3 -0
- package/packs/gallery/note/writing.md +18 -0
- package/packs/gallery/pack.json +8 -0
- package/packs/gallery/recent/component.json +13 -0
- package/packs/gallery/recent/example.html +1 -0
- package/packs/gallery/recent/kit.js +293 -0
- package/packs/gallery/recent/preview.svg +1 -0
- package/packs/gallery/recent/style.css +85 -0
- package/packs/gallery/recent/template.html +1 -0
- package/packs/gallery/recent/writing.md +15 -0
- package/packs/gallery/static/component.json +13 -0
- package/packs/gallery/static/example.html +11 -0
- package/packs/gallery/static/preview.svg +1 -0
- package/packs/gallery/static/style.css +171 -0
- package/packs/gallery/static/template.html +1 -0
- package/packs/gallery/static/writing.md +18 -0
- package/packs/gallery/stats/component.json +13 -0
- package/packs/gallery/stats/example.html +1 -0
- package/packs/gallery/stats/kit.js +347 -0
- package/packs/gallery/stats/preview.svg +1 -0
- package/packs/gallery/stats/style.css +73 -0
- package/packs/gallery/stats/template.html +1 -0
- package/packs/gallery/stats/writing.md +11 -0
- package/packs/gallery/today/component.json +12 -0
- package/packs/gallery/today/example.html +1 -0
- package/packs/gallery/today/kit.js +220 -0
- package/packs/gallery/today/preview.svg +1 -0
- package/packs/gallery/today/style.css +149 -0
- package/packs/gallery/today/template.html +1 -0
- package/packs/gallery/today/writing.md +14 -0
- package/packs/gallery/todos/component.json +19 -0
- package/packs/gallery/todos/example.html +3 -0
- package/packs/gallery/todos/kit.js +489 -0
- package/packs/gallery/todos/preview.svg +1 -0
- package/packs/gallery/todos/style.css +214 -0
- package/packs/gallery/todos/template.html +3 -0
- package/packs/gallery/todos/writing.md +30 -0
- package/packs/gallery/weather/component.json +19 -0
- package/packs/gallery/weather/example.html +3 -0
- package/packs/gallery/weather/kit.js +387 -0
- package/packs/gallery/weather/preview.svg +1 -0
- package/packs/gallery/weather/style.css +140 -0
- package/packs/gallery/weather/template.html +3 -0
- package/packs/gallery/weather/writing.md +26 -0
- package/packs/gallery-soft/countdown/component.json +18 -0
- package/packs/gallery-soft/countdown/example.html +3 -0
- package/packs/gallery-soft/countdown/kit.js +206 -0
- package/packs/gallery-soft/countdown/preview.svg +1 -0
- package/packs/gallery-soft/countdown/style.css +211 -0
- package/packs/gallery-soft/countdown/template.html +3 -0
- package/packs/gallery-soft/countdown/writing.md +24 -0
- package/packs/gallery-soft/habit/component.json +14 -0
- package/packs/gallery-soft/habit/example.html +3 -0
- package/packs/gallery-soft/habit/kit.js +366 -0
- package/packs/gallery-soft/habit/preview.svg +1 -0
- package/packs/gallery-soft/habit/style.css +251 -0
- package/packs/gallery-soft/habit/template.html +3 -0
- package/packs/gallery-soft/habit/writing.md +23 -0
- package/packs/gallery-soft/heatmap/component.json +18 -0
- package/packs/gallery-soft/heatmap/example.html +3 -0
- package/packs/gallery-soft/heatmap/kit.js +498 -0
- package/packs/gallery-soft/heatmap/preview.svg +1 -0
- package/packs/gallery-soft/heatmap/style.css +181 -0
- package/packs/gallery-soft/heatmap/template.html +3 -0
- package/packs/gallery-soft/heatmap/writing.md +23 -0
- package/packs/gallery-soft/note/component.json +14 -0
- package/packs/gallery-soft/note/example.html +3 -0
- package/packs/gallery-soft/note/kit.js +162 -0
- package/packs/gallery-soft/note/preview.svg +1 -0
- package/packs/gallery-soft/note/style.css +148 -0
- package/packs/gallery-soft/note/template.html +3 -0
- package/packs/gallery-soft/note/writing.md +20 -0
- package/packs/gallery-soft/pack.json +8 -0
- package/packs/gallery-soft/recent/component.json +13 -0
- package/packs/gallery-soft/recent/example.html +1 -0
- package/packs/gallery-soft/recent/kit.js +335 -0
- package/packs/gallery-soft/recent/preview.svg +1 -0
- package/packs/gallery-soft/recent/style.css +160 -0
- package/packs/gallery-soft/recent/template.html +1 -0
- package/packs/gallery-soft/recent/writing.md +17 -0
- package/packs/gallery-soft/static/component.json +13 -0
- package/packs/gallery-soft/static/example.html +12 -0
- package/packs/gallery-soft/static/preview.svg +1 -0
- package/packs/gallery-soft/static/style.css +186 -0
- package/packs/gallery-soft/static/template.html +1 -0
- package/packs/gallery-soft/static/writing.md +20 -0
- package/packs/gallery-soft/stats/component.json +13 -0
- package/packs/gallery-soft/stats/example.html +1 -0
- package/packs/gallery-soft/stats/kit.js +341 -0
- package/packs/gallery-soft/stats/preview.svg +1 -0
- package/packs/gallery-soft/stats/style.css +119 -0
- package/packs/gallery-soft/stats/template.html +1 -0
- package/packs/gallery-soft/stats/writing.md +13 -0
- package/packs/gallery-soft/today/component.json +12 -0
- package/packs/gallery-soft/today/example.html +1 -0
- package/packs/gallery-soft/today/kit.js +222 -0
- package/packs/gallery-soft/today/preview.svg +1 -0
- package/packs/gallery-soft/today/style.css +178 -0
- package/packs/gallery-soft/today/template.html +1 -0
- package/packs/gallery-soft/today/writing.md +16 -0
- package/packs/gallery-soft/todos/component.json +19 -0
- package/packs/gallery-soft/todos/example.html +3 -0
- package/packs/gallery-soft/todos/kit.js +527 -0
- package/packs/gallery-soft/todos/preview.svg +1 -0
- package/packs/gallery-soft/todos/style.css +212 -0
- package/packs/gallery-soft/todos/template.html +3 -0
- package/packs/gallery-soft/todos/writing.md +32 -0
- package/packs/gallery-soft/weather/component.json +19 -0
- package/packs/gallery-soft/weather/example.html +3 -0
- package/packs/gallery-soft/weather/kit.js +411 -0
- package/packs/gallery-soft/weather/preview.svg +1 -0
- package/packs/gallery-soft/weather/style.css +185 -0
- package/packs/gallery-soft/weather/template.html +3 -0
- package/packs/gallery-soft/weather/writing.md +28 -0
- package/release.json +12 -10
- package/sdk/doc-kit.d.ts +396 -5
- package/sdk/doc-state.d.ts +2 -0
- package/skill/SKILL.md +56 -23
- package/skill/references/block-script.md +140 -0
- package/skill/references/building-blocks.md +257 -0
- package/skill/references/extensions.md +59 -0
- package/skill/references/pages-and-data.md +225 -0
- package/skill/references/writing-html.md +8 -4
- package/skill/sdk/doc-kit.d.ts +396 -5
- package/skill/sdk/doc-state.d.ts +2 -0
- package/web/assets/index-BM_K-Auu.css +1 -0
- package/web/assets/index-DRslOBiv.js +15 -0
- package/web/index.html +2 -2
- package/dist/chunk-3HIRPVLU.mjs +0 -2
- package/dist/chunk-5MHMDLZD.mjs +0 -4
- package/dist/chunk-64K7IPLO.mjs +0 -255
- package/dist/chunk-6QXGZM36.mjs +0 -8
- package/dist/chunk-6RGJOMJP.mjs +0 -16
- package/dist/chunk-AJ73XJF3.mjs +0 -2
- package/dist/chunk-AUZGSZJH.mjs +0 -13
- package/dist/chunk-BFE45AKL.mjs +0 -2
- package/dist/chunk-BXO2ZY5P.mjs +0 -2
- package/dist/chunk-CEH4MRCC.mjs +0 -2
- package/dist/chunk-CY2FNNAB.mjs +0 -16
- package/dist/chunk-DFUDV4LX.mjs +0 -2
- package/dist/chunk-DKXG4XDG.mjs +0 -2
- package/dist/chunk-EZQ34M3F.mjs +0 -124
- package/dist/chunk-EZY3WC6Z.mjs +0 -15
- package/dist/chunk-FUKQNOQS.mjs +0 -9
- package/dist/chunk-JPOSLGOC.mjs +0 -6
- package/dist/chunk-JVHHHGEA.mjs +0 -3
- package/dist/chunk-L3QKH4OK.mjs +0 -26
- package/dist/chunk-LAE5NQ4B.mjs +0 -2
- package/dist/chunk-LEF6DRCK.mjs +0 -59
- package/dist/chunk-NO5NJCHO.mjs +0 -2
- package/dist/chunk-NQPVAU63.mjs +0 -2
- package/dist/chunk-NSKUTQ5J.mjs +0 -5
- package/dist/chunk-O35FIXRB.mjs +0 -2
- package/dist/chunk-P2CAZPDP.mjs +0 -3
- package/dist/chunk-PL6GHLGD.mjs +0 -15
- package/dist/chunk-QJIR2BLP.mjs +0 -6
- package/dist/chunk-QUPLVPB2.mjs +0 -7
- package/dist/chunk-R7BNENLY.mjs +0 -4
- package/dist/chunk-S6O4UHLC.mjs +0 -2
- package/dist/chunk-SGJWQKEI.mjs +0 -2
- package/dist/chunk-TX6JH7TR.mjs +0 -2
- package/dist/chunk-TYK6VNAB.mjs +0 -10
- package/dist/chunk-UALRNVSE.mjs +0 -4
- package/dist/chunk-V3HXVQEM.mjs +0 -2
- package/dist/chunk-V5VXUJKG.mjs +0 -2
- package/dist/chunk-VBXMADMP.mjs +0 -2
- package/dist/chunk-VNV55RUA.mjs +0 -2
- package/dist/chunk-VPD2PS35.mjs +0 -2
- package/dist/chunk-W4VKN3GF.mjs +0 -7
- package/dist/chunk-W5BXXPDJ.mjs +0 -3
- package/dist/chunk-XUNHRCOG.mjs +0 -6
- package/skill/references/building-components.md +0 -367
- package/web/assets/index-Bh74DfsV.css +0 -1
- package/web/assets/index-UW0RyFFt.js +0 -13
|
@@ -0,0 +1,513 @@
|
|
|
1
|
+
// gallery/heatmap (编辑热力图): the workspace's record of edits by day, as GitHub draws a year of
|
|
2
|
+
// contributions: a column a week (Monday at the top, as a Chinese calendar starts it), a square a day,
|
|
3
|
+
// darker for a day of more, read through context.workspace.query("activity") (its manifest's needs hold
|
|
4
|
+
// "workspace": the server's record, .gallery/state/activity.json, a reader's commits and the Agent's
|
|
5
|
+
// writes, by day). Its one setting, `words` (按字数显示, the card's form: the grip at its top right ›
|
|
6
|
+
// 设置…, kept in its data part `settings`, which the board writes and this block only reads), draws the
|
|
7
|
+
// words a day added (its net change, a day that took more away than it added drawn as none) instead of
|
|
8
|
+
// how many edits it had. It asks for every day 53 weeks draw (the record keeps as many); a day before the
|
|
9
|
+
// record started is a small gray dot, never an empty square, and a day to come is not drawn. It reads again
|
|
10
|
+
// whenever the workspace says its record changed (the `data` signal, "activity") and as a day begins (the
|
|
11
|
+
// kit's clock), and draws again as its card changes size (`layout`, and its own ResizeObserver on the room
|
|
12
|
+
// the squares have) or its settings change (`source`). Where the workspace cannot be read (an exported
|
|
13
|
+
// file, where it has no server; a server that does not answer) the squares are empty and a line over them
|
|
14
|
+
// says why. The words are the page's language (the UI's where Gallery says it, else the page's lang).
|
|
15
|
+
//
|
|
16
|
+
// Its face (the pack's design B, in the kit's card tokens): a head of the chip (a calendar), 编辑热力图
|
|
17
|
+
// and its quiet meta; the squares the hero, five shades of the accent by how a day stands among the days
|
|
18
|
+
// recorded (`levelsOf`: the quarter of them with least, and so on, never by a straight line to the most,
|
|
19
|
+
// so that a busy day does not make every other pale); today's square ringed; the months' names over the
|
|
20
|
+
// weeks they begin in and 一 三 五 beside the rows; under them, less to more. Laid out by the card's cells
|
|
21
|
+
// (`data-layout`, by context.size): "full" (8 × 4, the default, and 12 × 4) squares of 23px, 4px apart,
|
|
22
|
+
// as many weeks as fit (14, 26), and at their left the figures (`summaryOf`): what the weeks are (近 14 周),
|
|
23
|
+
// the edits (or words) in them, large, the average a day, the days with any, the longest run of days in
|
|
24
|
+
// a row and today's, and a bar of how they split between the reader and the Agent; "compact" (4 × 4) squares
|
|
25
|
+
// of 21px over a line of the total and the days with any; "strip" (12 × 3, a card three cells high or
|
|
26
|
+
// less) squares of 14px (smaller where the card is lower), a year of them, the total and the days in the
|
|
27
|
+
// head's meta, and the day the record began said by the legend's dot. A record begun within the week is
|
|
28
|
+
// said so (从 11月11日 开始记录), and an export's figures say the time they are of (截至 …). A pointer on a
|
|
29
|
+
// square shows its day: its edits (or words), and the reader's and the Agent's.
|
|
30
|
+
|
|
31
|
+
const WORDS = {
|
|
32
|
+
zh: {
|
|
33
|
+
title: "编辑热力图",
|
|
34
|
+
weeks: (/** @type {number} */ count) => `近 ${count} 周`,
|
|
35
|
+
year: "过去一年",
|
|
36
|
+
added: "新增",
|
|
37
|
+
editsUnit: "次编辑",
|
|
38
|
+
wordsUnit: "字",
|
|
39
|
+
tenThousand: "万字",
|
|
40
|
+
average: (/** @type {string} */ value, /** @type {boolean} */ words) => ["平均每天 ", value, words ? " 字" : " 次"],
|
|
41
|
+
active: "有编辑的天数",
|
|
42
|
+
run: "最长连续",
|
|
43
|
+
today: "今天",
|
|
44
|
+
days: "天",
|
|
45
|
+
times: "次",
|
|
46
|
+
you: "你",
|
|
47
|
+
agent: "Agent",
|
|
48
|
+
activeDays: (/** @type {number} */ count) => `${count} 天有编辑`,
|
|
49
|
+
stripMeta: (/** @type {string} */ period, /** @type {string} */ total, /** @type {number} */ days) => [`${period} ${total}`, `${days} 天`],
|
|
50
|
+
totalEdits: (/** @type {string} */ count) => `${count} 次编辑`,
|
|
51
|
+
byWords: "按字数",
|
|
52
|
+
fresh: "刚开始记录",
|
|
53
|
+
freshSince: (/** @type {string} */ date) => `从 ${date} 开始记录`,
|
|
54
|
+
freshSaid: ["以后每天写了多少,", "都会在右边亮起一格"],
|
|
55
|
+
before: "开始记录之前",
|
|
56
|
+
beforeSince: (/** @type {string} */ date) => `${date} 开始记录之前`,
|
|
57
|
+
upTo: (/** @type {string} */ when) => `截至 ${when}`,
|
|
58
|
+
less: "少",
|
|
59
|
+
more: "多",
|
|
60
|
+
tip: (/** @type {string} */ date, /** @type {number} */ edits, /** @type {number} */ words, /** @type {boolean} */ byWords) => `${date} · ${byWords ? `${words >= 0 ? "+" : "−"}${Math.abs(words).toLocaleString("zh-CN")} 字` : `${edits} 次编辑`}`,
|
|
61
|
+
split: (/** @type {number} */ you, /** @type {number} */ agent) => `你 ${you} 次 · Agent ${agent} 次`,
|
|
62
|
+
unrecorded: "还没开始记录",
|
|
63
|
+
offline: "在 Gallery 里打开时显示",
|
|
64
|
+
failed: "读不到工作区的编辑记录",
|
|
65
|
+
date: (/** @type {Date} */ date) => `${date.getMonth() + 1}月${date.getDate()}日`,
|
|
66
|
+
weekday: (/** @type {Date} */ date) => `${date.getMonth() + 1}月${date.getDate()}日 ${["周日", "周一", "周二", "周三", "周四", "周五", "周六"][date.getDay()]}`,
|
|
67
|
+
month: (/** @type {number} */ month) => `${month + 1}月`,
|
|
68
|
+
rows: ["一", "", "三", "", "五", "", ""],
|
|
69
|
+
locale: "zh-CN",
|
|
70
|
+
},
|
|
71
|
+
en: {
|
|
72
|
+
title: "Editing heatmap",
|
|
73
|
+
weeks: (/** @type {number} */ count) => `Last ${count} weeks`,
|
|
74
|
+
year: "Past year",
|
|
75
|
+
added: " added",
|
|
76
|
+
editsUnit: "edits",
|
|
77
|
+
wordsUnit: "words",
|
|
78
|
+
tenThousand: "",
|
|
79
|
+
average: (/** @type {string} */ value, /** @type {boolean} */ words) => ["", value, words ? " words a day" : " a day"],
|
|
80
|
+
active: "Days with edits",
|
|
81
|
+
run: "Longest run",
|
|
82
|
+
today: "Today",
|
|
83
|
+
days: "d",
|
|
84
|
+
times: "",
|
|
85
|
+
you: "You",
|
|
86
|
+
agent: "Agent",
|
|
87
|
+
activeDays: (/** @type {number} */ count) => `${count} ${count === 1 ? "day" : "days"} with edits`,
|
|
88
|
+
stripMeta: (/** @type {string} */ period, /** @type {string} */ total, /** @type {number} */ days) => [`${period}: ${total}`, `${days} ${days === 1 ? "day" : "days"}`],
|
|
89
|
+
totalEdits: (/** @type {string} */ count) => `${count} edits`,
|
|
90
|
+
byWords: "by words",
|
|
91
|
+
fresh: "Just started",
|
|
92
|
+
freshSince: (/** @type {string} */ date) => `Recording since ${date}`,
|
|
93
|
+
freshSaid: ["Each day you write lights a square on the right"],
|
|
94
|
+
before: "Before recording",
|
|
95
|
+
beforeSince: (/** @type {string} */ date) => `Before ${date}`,
|
|
96
|
+
upTo: (/** @type {string} */ when) => `As of ${when}`,
|
|
97
|
+
less: "Less",
|
|
98
|
+
more: "More",
|
|
99
|
+
tip: (/** @type {string} */ date, /** @type {number} */ edits, /** @type {number} */ words, /** @type {boolean} */ byWords) => `${date} · ${byWords ? `${words >= 0 ? "+" : "−"}${Math.abs(words).toLocaleString("en")} words` : `${edits} ${edits === 1 ? "edit" : "edits"}`}`,
|
|
100
|
+
split: (/** @type {number} */ you, /** @type {number} */ agent) => `You ${you} · Agent ${agent}`,
|
|
101
|
+
unrecorded: "Not recorded yet",
|
|
102
|
+
offline: "Shown when opened in Gallery",
|
|
103
|
+
failed: "The workspace's record of edits could not be read",
|
|
104
|
+
date: (/** @type {Date} */ date) => `${["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"][date.getMonth()]} ${date.getDate()}`,
|
|
105
|
+
weekday: (/** @type {Date} */ date) => `${["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"][date.getDay()]}, ${["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"][date.getMonth()]} ${date.getDate()}`,
|
|
106
|
+
month: (/** @type {number} */ month) => ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"][month],
|
|
107
|
+
rows: ["Mon", "", "Wed", "", "Fri", "", ""],
|
|
108
|
+
locale: "en",
|
|
109
|
+
},
|
|
110
|
+
};
|
|
111
|
+
|
|
112
|
+
/** The language the page speaks: the UI's where Gallery says it (data-ge-language), else its lang's. */
|
|
113
|
+
function languageOf(/** @type {HTMLElement} */ root) {
|
|
114
|
+
const ui = root.getAttribute("data-ge-language");
|
|
115
|
+
return (ui !== null ? ui === "en" : /^en(?:-|$)/i.test(root.lang)) ? "en" : "zh";
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
const MOST_WEEKS = 53;
|
|
119
|
+
/** The days of the record it reads: as many as 53 weeks draw at the most (on a Sunday, its first square 370 days back). */
|
|
120
|
+
const DAYS = MOST_WEEKS * 7;
|
|
121
|
+
/** The weekdays' column and the months' row, in px. */
|
|
122
|
+
const LABELS = 20;
|
|
123
|
+
const MONTHS = 18;
|
|
124
|
+
const two = (/** @type {number} */ value) => String(value).padStart(2, "0");
|
|
125
|
+
/** A local day as the record writes it, YYYY-MM-DD. @param {Date} date */
|
|
126
|
+
const dayOf = (date) => `${date.getFullYear()}-${two(date.getMonth() + 1)}-${two(date.getDate())}`;
|
|
127
|
+
/** The day `count` days after `date` (before, negative), at noon. @param {Date} date @param {number} count */
|
|
128
|
+
const after = (date, count) => new Date(date.getFullYear(), date.getMonth(), date.getDate() + count, 12);
|
|
129
|
+
|
|
130
|
+
/**
|
|
131
|
+
* How a card of `size` (context.size: its cells, or null where no card holds it, a document) lays its face
|
|
132
|
+
* out: "grid" two cells high or less (8 × 2: the squares alone, the user's word of 2026-11-09), "strip" three
|
|
133
|
+
* cells high, "compact" four wide or less, else "full".
|
|
134
|
+
* @param {{ w: number, h: number } | null | undefined} size
|
|
135
|
+
* @returns {"full" | "compact" | "strip" | "grid"}
|
|
136
|
+
*/
|
|
137
|
+
function layoutOf(size) {
|
|
138
|
+
if (!size) return "full";
|
|
139
|
+
if (size.h <= 2) return "grid";
|
|
140
|
+
if (size.h <= 3) return "strip";
|
|
141
|
+
return size.w <= 4 ? "compact" : "full";
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
/**
|
|
145
|
+
* The squares of a layout in a room of `width` x `height` px (the field's: the weekdays' column and the
|
|
146
|
+
* months' row inside it): { pitch (from one square to the next), cell (a square's side), gap, weeks }.
|
|
147
|
+
* "full" 23px squares 4px apart, "compact" 21px; "strip" and "grid" 14px, 3px apart, smaller where the room is
|
|
148
|
+
* lower (seven of them and the months' row in its height, 4px at the least, 2px apart under 10px); as many
|
|
149
|
+
* weeks as the width holds, 1 to 53.
|
|
150
|
+
* @param {"full" | "compact" | "strip" | "grid"} layout
|
|
151
|
+
* @param {number} width
|
|
152
|
+
* @param {number} height
|
|
153
|
+
*/
|
|
154
|
+
function fitOf(layout, width, height) {
|
|
155
|
+
let pitch = layout === "full" ? 27 : layout === "compact" ? 25 : 17;
|
|
156
|
+
let gap = pitch === 17 ? 3 : 4;
|
|
157
|
+
if ((layout === "strip" || layout === "grid") && Number.isFinite(height)) {
|
|
158
|
+
pitch = Math.max(6, Math.min(17, Math.floor((height - MONTHS + gap) / 7)));
|
|
159
|
+
gap = pitch < 12 ? 2 : 3;
|
|
160
|
+
}
|
|
161
|
+
const weeks = Math.max(1, Math.min(MOST_WEEKS, Math.floor((width - LABELS + gap) / pitch)));
|
|
162
|
+
return { pitch, cell: pitch - gap, gap, weeks };
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
/**
|
|
166
|
+
* The weeks drawn, the last the one of `today` (a Date), `weeks` of them: [[{ date, day, future }…7]…],
|
|
167
|
+
* each a column, Monday first; `future` a day after today, which is not drawn.
|
|
168
|
+
* @param {Date} today
|
|
169
|
+
* @param {number} weeks
|
|
170
|
+
*/
|
|
171
|
+
function weeksOf(today, weeks) {
|
|
172
|
+
const monday = after(today, -((today.getDay() + 6) % 7));
|
|
173
|
+
const columns = [];
|
|
174
|
+
for (let week = weeks - 1; week >= 0; week--) {
|
|
175
|
+
const start = after(monday, -7 * week);
|
|
176
|
+
columns.push(Array.from({ length: 7 }, (_, row) => {
|
|
177
|
+
const date = after(start, row);
|
|
178
|
+
return { date, day: dayOf(date), future: dayOf(date) > dayOf(today) };
|
|
179
|
+
}));
|
|
180
|
+
}
|
|
181
|
+
return columns;
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
/**
|
|
185
|
+
* The bounds of the levels of `values` (a day's edits, or the words it added, of every day recorded): the
|
|
186
|
+
* values at 38%, 68% and 90% of the days with any, so that each shade holds a share of the days; for fewer
|
|
187
|
+
* than five such days, a quarter, a half and three quarters of the most.
|
|
188
|
+
* @param {number[]} values
|
|
189
|
+
*/
|
|
190
|
+
function levelsOf(values) {
|
|
191
|
+
const some = values.filter((value) => value > 0).sort((a, b) => a - b);
|
|
192
|
+
if (some.length < 5) {
|
|
193
|
+
const most = some[some.length - 1] ?? 0;
|
|
194
|
+
return [most / 4, most / 2, (3 * most) / 4];
|
|
195
|
+
}
|
|
196
|
+
return [some[Math.floor(some.length * 0.38)], some[Math.floor(some.length * 0.68)], some[Math.floor(some.length * 0.9)]];
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
/**
|
|
200
|
+
* The level of a day's square, 0 (none) to 4 (the most), of `value` by the bounds `levels` (levelsOf's).
|
|
201
|
+
* @param {number} value
|
|
202
|
+
* @param {number[]} levels
|
|
203
|
+
*/
|
|
204
|
+
function levelOf(value, levels) {
|
|
205
|
+
if (!(value > 0)) return 0;
|
|
206
|
+
if (value <= levels[0]) return 1;
|
|
207
|
+
if (value <= levels[1]) return 2;
|
|
208
|
+
return value <= levels[2] ? 3 : 4;
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
/**
|
|
212
|
+
* What the card says of the record `days` (workspace.query("activity")'s data: [{ date, edits, words,
|
|
213
|
+
* reader, agent }], from the day it started or 53 weeks back to today) over the `weeks` it draws (`today`,
|
|
214
|
+
* a Date), counting `words` (the setting) or edits: `values` (each day's, by its date), `levels`, `since`
|
|
215
|
+
* (the first day recorded), and the figures: `total` (in the weeks drawn), `average` (a day, of the days
|
|
216
|
+
* recorded in them), `active` (days with any edit), `run` (the longest run of them), `today` (its value),
|
|
217
|
+
* `you` and `agent` (the edits of each), and `fresh` (the record began within the week).
|
|
218
|
+
* @param {Array<{ date: string, edits: number, words: number, reader?: { edits: number }, agent?: { edits: number } }>} days
|
|
219
|
+
* @param {boolean} words
|
|
220
|
+
* @param {number} weeks
|
|
221
|
+
* @param {Date} today
|
|
222
|
+
*/
|
|
223
|
+
function summaryOf(days, words, weeks, today) {
|
|
224
|
+
const valueOf = (/** @type {{ edits: number, words: number }} */ day) => (words ? Math.max(0, day.words) : day.edits);
|
|
225
|
+
const values = new Map(days.map((day) => [day.date, valueOf(day)]));
|
|
226
|
+
const since = days[0]?.date ?? null;
|
|
227
|
+
const first = dayOf(after(today, -((today.getDay() + 6) % 7) - 7 * (weeks - 1)));
|
|
228
|
+
const shown = days.filter((day) => day.date >= first && day.date <= dayOf(today));
|
|
229
|
+
let run = 0;
|
|
230
|
+
let longest = 0;
|
|
231
|
+
for (const day of shown) {
|
|
232
|
+
run = day.edits > 0 ? run + 1 : 0;
|
|
233
|
+
longest = Math.max(longest, run);
|
|
234
|
+
}
|
|
235
|
+
const total = shown.reduce((sum, day) => sum + valueOf(day), 0);
|
|
236
|
+
const agent = shown.reduce((sum, day) => sum + (day.agent?.edits ?? 0), 0);
|
|
237
|
+
const you = shown.reduce((sum, day) => sum + (day.reader?.edits ?? 0), 0);
|
|
238
|
+
const now = days.find((day) => day.date === dayOf(today));
|
|
239
|
+
return {
|
|
240
|
+
values, since, levels: levelsOf([...values.values()]),
|
|
241
|
+
total, average: shown.length > 0 ? total / shown.length : 0, active: shown.filter((day) => day.edits > 0).length, run: longest,
|
|
242
|
+
today: now ? valueOf(now) : 0, you, agent, fresh: since !== null && since > dayOf(after(today, -7)),
|
|
243
|
+
};
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
/**
|
|
247
|
+
* An element of the face, of `kind` (its class).
|
|
248
|
+
* @template {keyof HTMLElementTagNameMap} K
|
|
249
|
+
* @param {K} tag
|
|
250
|
+
* @param {string} kind
|
|
251
|
+
* @param {string} [text]
|
|
252
|
+
*/
|
|
253
|
+
function made(tag, kind, text) {
|
|
254
|
+
const node = document.createElement(tag);
|
|
255
|
+
node.className = `gallery-heatmap-${kind}`;
|
|
256
|
+
if (text !== undefined) node.textContent = text;
|
|
257
|
+
return node;
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
DocKit.component({
|
|
261
|
+
id: "gallery/heatmap",
|
|
262
|
+
on: ["data", "source", "layout", "clock"],
|
|
263
|
+
mount(host, context) {
|
|
264
|
+
const language = languageOf(document.documentElement);
|
|
265
|
+
const words = WORDS[language];
|
|
266
|
+
const format = (/** @type {number} */ value) => new Intl.NumberFormat(words.locale, { maximumFractionDigits: 0 }).format(value);
|
|
267
|
+
const face = made("div", "face");
|
|
268
|
+
const head = made("div", "head");
|
|
269
|
+
const meta = made("span", "line");
|
|
270
|
+
const chip = made("span", "chip");
|
|
271
|
+
chip.setAttribute("aria-hidden", "true");
|
|
272
|
+
chip.innerHTML = '<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.9" stroke-linecap="round" stroke-linejoin="round"><rect x="3.5" y="5" width="17" height="15.5" rx="3"/><path d="M3.5 10h17M8 3v4M16 3v4"/></svg>';
|
|
273
|
+
head.append(chip, made("span", "title", words.title), meta);
|
|
274
|
+
const body = made("div", "body");
|
|
275
|
+
// The figures beside the squares (a full card), or the line over them (a compact one).
|
|
276
|
+
const aside = made("div", "aside");
|
|
277
|
+
const period = made("span", "label");
|
|
278
|
+
const total = made("span", "total");
|
|
279
|
+
const totalNumber = made("span", "number");
|
|
280
|
+
const totalUnit = made("span", "unit");
|
|
281
|
+
total.append(totalNumber, totalUnit);
|
|
282
|
+
const average = made("span", "average");
|
|
283
|
+
const facts = made("dl", "facts");
|
|
284
|
+
const who = made("div", "who");
|
|
285
|
+
const split = made("span", "split");
|
|
286
|
+
const youBar = made("i", "you-bar");
|
|
287
|
+
const agentBar = made("i", "agent-bar");
|
|
288
|
+
split.append(youBar, agentBar);
|
|
289
|
+
const whoWords = made("span", "who-words");
|
|
290
|
+
who.append(split, whoWords);
|
|
291
|
+
aside.append(period, total, average, facts, who);
|
|
292
|
+
const field = made("div", "field");
|
|
293
|
+
const area = made("div", "area");
|
|
294
|
+
const months = made("div", "months");
|
|
295
|
+
const rows = made("div", "rows");
|
|
296
|
+
for (const label of words.rows) rows.append(made("span", "row", label));
|
|
297
|
+
const grid = made("div", "grid");
|
|
298
|
+
// The tip stands over the card, in the page's top layer (a popover; where a browser has none, fixed to the
|
|
299
|
+
// window), never inside the card, whose overflow a tip near its edge would widen into a scrollbar.
|
|
300
|
+
const tip = made("div", "tip");
|
|
301
|
+
const popover = typeof tip.showPopover === "function";
|
|
302
|
+
if (popover) tip.popover = "manual";
|
|
303
|
+
else tip.hidden = true;
|
|
304
|
+
tip.setAttribute("aria-hidden", "true");
|
|
305
|
+
area.append(months, rows, grid, tip);
|
|
306
|
+
const legend = made("div", "legend");
|
|
307
|
+
const note = made("span", "note");
|
|
308
|
+
legend.append(made("span", "less", words.less), ...[0, 1, 2, 3, 4].map((level) => {
|
|
309
|
+
const square = made("span", "square");
|
|
310
|
+
square.dataset.level = String(level);
|
|
311
|
+
return square;
|
|
312
|
+
}), made("span", "more", words.more), note);
|
|
313
|
+
const overlay = made("p", "overlay");
|
|
314
|
+
overlay.hidden = true;
|
|
315
|
+
field.append(area, legend, overlay);
|
|
316
|
+
body.append(aside, field);
|
|
317
|
+
// As wide as the corner a board's grip takes of the content's top right (--gallery-grip-room, a custom
|
|
318
|
+
// property CSS alone resolves), measured where the months' row is the face's first (the squares alone).
|
|
319
|
+
const gripRoom = made("i", "grip-room");
|
|
320
|
+
gripRoom.setAttribute("aria-hidden", "true");
|
|
321
|
+
face.append(head, body, gripRoom);
|
|
322
|
+
host.append(face);
|
|
323
|
+
const workspace = context.workspace;
|
|
324
|
+
if (!workspace) return void context.fail(new Error("its manifest's needs hold \"workspace\": context.workspace is not there"));
|
|
325
|
+
|
|
326
|
+
/** @type {Array<{ date: string, edits: number, words: number, reader?: { edits: number, words: number }, agent?: { edits: number, words: number } }> | null} */
|
|
327
|
+
let days = null;
|
|
328
|
+
let at = "";
|
|
329
|
+
let failure = "";
|
|
330
|
+
let drawn = "";
|
|
331
|
+
const kv = (/** @type {string} */ name, /** @type {string} */ value, /** @type {string} */ unit) => {
|
|
332
|
+
const row = made("div", "fact");
|
|
333
|
+
const said = made("dd", "fact-value", value);
|
|
334
|
+
if (unit) said.append(made("small", "fact-unit", unit));
|
|
335
|
+
row.append(made("dt", "fact-name", name), said);
|
|
336
|
+
return row;
|
|
337
|
+
};
|
|
338
|
+
const bigOf = (/** @type {number} */ value, /** @type {boolean} */ byWords) => {
|
|
339
|
+
if (!byWords) return [format(value), language === "zh" ? words.editsUnit : ` ${words.editsUnit}`];
|
|
340
|
+
if (language === "zh" && value >= 10_000) return [(value / 10_000).toFixed(1), words.tenThousand];
|
|
341
|
+
return [format(value), language === "zh" ? words.wordsUnit : ` ${words.wordsUnit}`];
|
|
342
|
+
};
|
|
343
|
+
const draw = () => {
|
|
344
|
+
const settings = context.readJSON("settings");
|
|
345
|
+
if (settings === undefined) return; // no JSON: the instance has failed, and Gallery shows what it holds
|
|
346
|
+
const byWords = settings !== null && typeof settings === "object" && settings.words === true;
|
|
347
|
+
const layout = layoutOf(context.size);
|
|
348
|
+
face.dataset.layout = layout;
|
|
349
|
+
const today = new Date();
|
|
350
|
+
// The room the squares have: the field's, the legend's taken off (a strip's height says how large they are).
|
|
351
|
+
const room = { width: field.clientWidth || 600, height: field.clientHeight > 0 ? field.clientHeight - legend.offsetHeight : Infinity };
|
|
352
|
+
const { pitch, cell, gap, weeks } = fitOf(layout, room.width, room.height);
|
|
353
|
+
const summary = summaryOf(days ?? [], byWords, weeks, today);
|
|
354
|
+
const exported = context.place === "export" && at;
|
|
355
|
+
const fresh = days !== null && summary.fresh;
|
|
356
|
+
face.toggleAttribute("data-fresh", fresh);
|
|
357
|
+
face.toggleAttribute("data-unread", Boolean(failure));
|
|
358
|
+
const key = JSON.stringify([layout, pitch, weeks, dayOf(today), byWords, days, failure, at]);
|
|
359
|
+
if (key === drawn) return;
|
|
360
|
+
drawn = key;
|
|
361
|
+
hide(); // the squares drawn anew: the one it stood over is gone
|
|
362
|
+
// The head's meta.
|
|
363
|
+
const [bigValue, bigUnit] = bigOf(summary.total, byWords);
|
|
364
|
+
const atWhen = exported ? (() => { const when = new Date(at); return `${words.date(when)} ${two(when.getHours())}:${two(when.getMinutes())}`; })() : "";
|
|
365
|
+
if (failure) meta.textContent = "";
|
|
366
|
+
else if (layout === "strip") {
|
|
367
|
+
const [first, second] = words.stripMeta(weeks >= 52 ? words.year : words.weeks(weeks), byWords ? `${bigValue} ${bigUnit.trim()}` : words.totalEdits(format(summary.total)), summary.active);
|
|
368
|
+
const dot = made("span", "dot", "·");
|
|
369
|
+
meta.replaceChildren(first, dot, second);
|
|
370
|
+
} else if (layout === "compact") meta.textContent = words.weeks(weeks) + (byWords ? ` · ${words.byWords}` : "");
|
|
371
|
+
else meta.textContent = fresh ? words.fresh : exported ? words.upTo(atWhen) : byWords ? words.byWords : "";
|
|
372
|
+
// The figures.
|
|
373
|
+
totalNumber.textContent = failure ? "—" : bigValue;
|
|
374
|
+
totalUnit.textContent = failure ? "" : bigUnit;
|
|
375
|
+
if (fresh && summary.since) {
|
|
376
|
+
period.textContent = words.freshSince(words.date(new Date(`${summary.since}T12:00:00`)));
|
|
377
|
+
average.replaceChildren();
|
|
378
|
+
// Its clauses each whole on a line where one fits (style.css), so that it breaks after the comma.
|
|
379
|
+
const said = made("p", "fresh");
|
|
380
|
+
said.append(...words.freshSaid.map((clause) => made("span", "clause", clause)));
|
|
381
|
+
facts.replaceChildren(said);
|
|
382
|
+
} else {
|
|
383
|
+
period.textContent = layout === "compact" ? "" : `${words.weeks(weeks)}${byWords ? words.added : ""}`;
|
|
384
|
+
const [before, value, afterwards] = words.average(byWords ? format(Math.round(summary.average)) : summary.average.toFixed(1), byWords);
|
|
385
|
+
average.replaceChildren(before, made("b", "strong", value), afterwards);
|
|
386
|
+
const todayName = exported ? words.date(new Date(at)) : words.today;
|
|
387
|
+
facts.replaceChildren(
|
|
388
|
+
kv(words.active, String(summary.active), words.days),
|
|
389
|
+
kv(words.run, String(summary.run), words.days),
|
|
390
|
+
kv(todayName, byWords ? format(summary.today) : String(summary.today), byWords ? words.wordsUnit : words.times),
|
|
391
|
+
);
|
|
392
|
+
}
|
|
393
|
+
if (layout === "compact") average.replaceChildren(words.activeDays(summary.active));
|
|
394
|
+
const both = summary.you + summary.agent;
|
|
395
|
+
const youShare = both > 0 ? Math.round((100 * summary.you) / both) : 0;
|
|
396
|
+
youBar.style.flex = String(summary.you || (both ? 0 : 1));
|
|
397
|
+
agentBar.style.flex = String(summary.agent);
|
|
398
|
+
const label = (/** @type {string} */ kind, /** @type {string} */ name, /** @type {number} */ share) => {
|
|
399
|
+
const piece = made("span", kind);
|
|
400
|
+
piece.append(made("i", "swatch"), `${name} `, made("b", "strong", `${share}%`));
|
|
401
|
+
return piece;
|
|
402
|
+
};
|
|
403
|
+
whoWords.replaceChildren(label("you", words.you, youShare), label("agent", words.agent, both > 0 ? 100 - youShare : 0));
|
|
404
|
+
who.hidden = both === 0 || fresh;
|
|
405
|
+
// The legend's note: since when the record is kept, where days before it are drawn.
|
|
406
|
+
const columns = weeksOf(today, weeks);
|
|
407
|
+
const firstDay = columns[0][0].day;
|
|
408
|
+
const before = days !== null && summary.since !== null && summary.since > firstDay;
|
|
409
|
+
note.replaceChildren(...(before && layout !== "compact" ? [made("s", "dot-key"), layout === "strip" ? words.beforeSince(words.date(new Date(`${summary.since}T12:00:00`))) : words.before] : []));
|
|
410
|
+
overlay.hidden = !failure;
|
|
411
|
+
overlay.textContent = failure;
|
|
412
|
+
// The squares.
|
|
413
|
+
face.style.setProperty("--gallery-heatmap-cell", `${cell}px`);
|
|
414
|
+
face.style.setProperty("--gallery-heatmap-gap", `${gap}px`);
|
|
415
|
+
face.style.setProperty("--gallery-heatmap-weeks", String(weeks));
|
|
416
|
+
const byDate = new Map((days ?? []).map((item) => [item.date, item]));
|
|
417
|
+
grid.replaceChildren(...columns.flatMap((column) => column.map(({ date, day, future }) => {
|
|
418
|
+
const square = made("span", "day");
|
|
419
|
+
if (future) {
|
|
420
|
+
square.classList.add("gallery-heatmap-future");
|
|
421
|
+
return square;
|
|
422
|
+
}
|
|
423
|
+
square.dataset.date = day;
|
|
424
|
+
if (day === dayOf(today)) square.classList.add("gallery-heatmap-today");
|
|
425
|
+
const recorded = days !== null && summary.since !== null && day >= summary.since;
|
|
426
|
+
if (!recorded) {
|
|
427
|
+
square.classList.add("gallery-heatmap-before");
|
|
428
|
+
square.setAttribute("aria-label", `${words.weekday(date)} · ${days === null ? failure : words.unrecorded}`);
|
|
429
|
+
return square;
|
|
430
|
+
}
|
|
431
|
+
const entry = byDate.get(day);
|
|
432
|
+
square.dataset.level = String(levelOf(summary.values.get(day) ?? 0, summary.levels));
|
|
433
|
+
square.setAttribute("aria-label", `${words.tip(words.weekday(date), entry?.edits ?? 0, entry?.words ?? 0, byWords)}(${words.split(entry?.reader?.edits ?? 0, entry?.agent?.edits ?? 0)})`);
|
|
434
|
+
return square;
|
|
435
|
+
})));
|
|
436
|
+
// A month's name over the week its first day falls in (the first week's too, but where the next is
|
|
437
|
+
// fewer than three weeks after it).
|
|
438
|
+
const starts = columns.flatMap((column, index) => (index === 0 || column[0].date.getMonth() !== columns[index - 1][0].date.getMonth() ? [index] : []));
|
|
439
|
+
if (starts.length > 1 && starts[1] < 3) starts.shift();
|
|
440
|
+
months.replaceChildren(...starts.map((index) => {
|
|
441
|
+
const name = made("span", "month", words.month(columns[index][0].date.getMonth()));
|
|
442
|
+
name.style.setProperty("--gallery-heatmap-week", String(index));
|
|
443
|
+
return name;
|
|
444
|
+
}));
|
|
445
|
+
// The squares alone: the months' row is the card's first, and a name that would reach into the grip's corner is left out.
|
|
446
|
+
if (layout === "grid") {
|
|
447
|
+
const end = face.getBoundingClientRect().right - gripRoom.offsetWidth;
|
|
448
|
+
for (const name of [...months.children]) if (name.getBoundingClientRect().right > end) name.remove();
|
|
449
|
+
}
|
|
450
|
+
};
|
|
451
|
+
// A pointer on a square: its day, its count and whose, over it (under it where the window has no room
|
|
452
|
+
// above), its middle at the square's but held 8px inside the window, the arrow at the square.
|
|
453
|
+
const hide = () => {
|
|
454
|
+
if (popover) {
|
|
455
|
+
if (tip.matches(":popover-open")) tip.hidePopover();
|
|
456
|
+
} else tip.hidden = true;
|
|
457
|
+
};
|
|
458
|
+
const show = (/** @type {Event} */ event) => {
|
|
459
|
+
const square = /** @type {HTMLElement | null} */ (/** @type {HTMLElement} */ (event.target).closest?.(".gallery-heatmap-day[data-date]"));
|
|
460
|
+
if (!square || !grid.contains(square)) return hide();
|
|
461
|
+
const [first, second] = (square.getAttribute("aria-label") ?? "").replace(/)$/, "").split("(");
|
|
462
|
+
tip.replaceChildren(first, ...(second ? [made("small", "tip-split", second)] : []));
|
|
463
|
+
if (popover) {
|
|
464
|
+
if (!tip.matches(":popover-open")) tip.showPopover();
|
|
465
|
+
} else tip.hidden = false;
|
|
466
|
+
const box = square.getBoundingClientRect();
|
|
467
|
+
const width = tip.offsetWidth;
|
|
468
|
+
const height = tip.offsetHeight;
|
|
469
|
+
const left = Math.max(8, Math.min(innerWidth - 8 - width, box.left + box.width / 2 - width / 2));
|
|
470
|
+
const below = box.top - 8 - height < 8;
|
|
471
|
+
tip.style.left = `${Math.round(left)}px`;
|
|
472
|
+
tip.style.top = `${Math.round(below ? box.bottom + 8 : box.top - 8 - height)}px`;
|
|
473
|
+
tip.style.setProperty("--gallery-heatmap-arrow", `${Math.round(Math.max(10, Math.min(width - 10, box.left + box.width / 2 - left)))}px`);
|
|
474
|
+
tip.toggleAttribute("data-below", below);
|
|
475
|
+
};
|
|
476
|
+
context.listen(grid, "pointerover", show);
|
|
477
|
+
context.listen(grid, "pointerleave", hide);
|
|
478
|
+
// A scroll (the page's, or a card's) moves the square from under it: gone until the pointer is on one again.
|
|
479
|
+
context.listen(document, "scroll", hide, { capture: true, passive: true });
|
|
480
|
+
context.signal?.addEventListener("abort", hide, { once: true });
|
|
481
|
+
let asking = 0; // the last read asked: an older answer that comes after it is dropped
|
|
482
|
+
const read = () => {
|
|
483
|
+
const ticket = ++asking;
|
|
484
|
+
workspace.query("activity", { days: DAYS }).then(({ data, at: when }) => {
|
|
485
|
+
if (ticket !== asking || context.signal.aborted) return;
|
|
486
|
+
days = data;
|
|
487
|
+
at = typeof when === "string" ? when : "";
|
|
488
|
+
failure = "";
|
|
489
|
+
draw();
|
|
490
|
+
}, (/** @type {any} */ error) => {
|
|
491
|
+
if (ticket !== asking || context.signal.aborted) return;
|
|
492
|
+
days = null;
|
|
493
|
+
failure = error?.code === "offline" ? words.offline : words.failed;
|
|
494
|
+
draw();
|
|
495
|
+
});
|
|
496
|
+
};
|
|
497
|
+
draw();
|
|
498
|
+
read();
|
|
499
|
+
// The room the squares have, its height too: a card given its height after the first draw (a board laid
|
|
500
|
+
// out late) is drawn again as it gets it.
|
|
501
|
+
if (typeof ResizeObserver === "function") {
|
|
502
|
+
const watch = new ResizeObserver(() => draw());
|
|
503
|
+
watch.observe(body);
|
|
504
|
+
context.signal?.addEventListener("abort", () => watch.disconnect(), { once: true });
|
|
505
|
+
}
|
|
506
|
+
return {
|
|
507
|
+
update(reason, detail) {
|
|
508
|
+
if ((reason === "data" && detail === "activity") || (reason === "clock" && detail === "day")) read();
|
|
509
|
+
else if (reason !== "data" && reason !== "clock") draw();
|
|
510
|
+
},
|
|
511
|
+
};
|
|
512
|
+
},
|
|
513
|
+
});
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 240 120"><rect width="240" height="120" rx="8" fill="#f3f3f1"/><rect x="10.5" y="8.5" width="219" height="103" rx="8" fill="#ffffff" stroke="#e6e6e3"/><rect x="20" y="16" width="10" height="10" rx="3" fill="#efefed"/><rect x="34" y="18.5" width="36" height="5" rx="2.5" fill="#37352f"/><rect x="20" y="34" width="18" height="4" rx="2" fill="#a6a5a1"/><rect x="20" y="42" width="36" height="12" rx="3" fill="#1d1d1b"/><rect x="20" y="58" width="30" height="4" rx="2" fill="#d4d3cf"/><rect x="20" y="70" width="26" height="3.5" rx="1.75" fill="#a6a5a1"/><rect x="62" y="70" width="10" height="3.5" rx="1.75" fill="#37352f"/><rect x="20" y="78" width="26" height="3.5" rx="1.75" fill="#a6a5a1"/><rect x="62" y="78" width="10" height="3.5" rx="1.75" fill="#37352f"/><rect x="20" y="86" width="26" height="3.5" rx="1.75" fill="#a6a5a1"/><rect x="62" y="86" width="10" height="3.5" rx="1.75" fill="#37352f"/><rect x="20" y="98" width="32" height="3" rx="1.5" fill="#4084cf"/><rect x="54" y="98" width="22" height="3" rx="1.5" fill="#b0cbeb"/><rect x="92" y="28" width="7" height="7" rx="1.8" fill="#90b6e3"/><rect x="92" y="37" width="7" height="7" rx="1.8" fill="#90b6e3"/><rect x="92" y="46" width="7" height="7" rx="1.8" fill="#ececea"/><rect x="92" y="55" width="7" height="7" rx="1.8" fill="#d1e2f6"/><rect x="92" y="64" width="7" height="7" rx="1.8" fill="#90b6e3"/><rect x="92" y="73" width="7" height="7" rx="1.8" fill="#d1e2f6"/><rect x="92" y="82" width="7" height="7" rx="1.8" fill="#ececea"/><rect x="101" y="28" width="7" height="7" rx="1.8" fill="#4d88d3"/><rect x="101" y="37" width="7" height="7" rx="1.8" fill="#90b6e3"/><rect x="101" y="46" width="7" height="7" rx="1.8" fill="#90b6e3"/><rect x="101" y="55" width="7" height="7" rx="1.8" fill="#d1e2f6"/><rect x="101" y="64" width="7" height="7" rx="1.8" fill="#4d88d3"/><rect x="101" y="73" width="7" height="7" rx="1.8" fill="#d1e2f6"/><rect x="101" y="82" width="7" height="7" rx="1.8" fill="#ececea"/><rect x="110" y="28" width="7" height="7" rx="1.8" fill="#90b6e3"/><rect x="110" y="37" width="7" height="7" rx="1.8" fill="#d1e2f6"/><rect x="110" y="46" width="7" height="7" rx="1.8" fill="#4d88d3"/><rect x="110" y="55" width="7" height="7" rx="1.8" fill="#d1e2f6"/><rect x="110" y="64" width="7" height="7" rx="1.8" fill="#90b6e3"/><rect x="110" y="73" width="7" height="7" rx="1.8" fill="#ececea"/><rect x="110" y="82" width="7" height="7" rx="1.8" fill="#ececea"/><rect x="119" y="28" width="7" height="7" rx="1.8" fill="#ececea"/><rect x="119" y="37" width="7" height="7" rx="1.8" fill="#2e5e9c"/><rect x="119" y="46" width="7" height="7" rx="1.8" fill="#2e5e9c"/><rect x="119" y="55" width="7" height="7" rx="1.8" fill="#ececea"/><rect x="119" y="64" width="7" height="7" rx="1.8" fill="#90b6e3"/><rect x="119" y="73" width="7" height="7" rx="1.8" fill="#d1e2f6"/><rect x="119" y="82" width="7" height="7" rx="1.8" fill="#ececea"/><rect x="128" y="28" width="7" height="7" rx="1.8" fill="#90b6e3"/><rect x="128" y="37" width="7" height="7" rx="1.8" fill="#90b6e3"/><rect x="128" y="46" width="7" height="7" rx="1.8" fill="#4d88d3"/><rect x="128" y="55" width="7" height="7" rx="1.8" fill="#d1e2f6"/><rect x="128" y="64" width="7" height="7" rx="1.8" fill="#d1e2f6"/><rect x="128" y="73" width="7" height="7" rx="1.8" fill="#d1e2f6"/><rect x="128" y="82" width="7" height="7" rx="1.8" fill="#ececea"/><rect x="137" y="28" width="7" height="7" rx="1.8" fill="#d1e2f6"/><rect x="137" y="37" width="7" height="7" rx="1.8" fill="#90b6e3"/><rect x="137" y="46" width="7" height="7" rx="1.8" fill="#d1e2f6"/><rect x="137" y="55" width="7" height="7" rx="1.8" fill="#d1e2f6"/><rect x="137" y="64" width="7" height="7" rx="1.8" fill="#4d88d3"/><rect x="137" y="73" width="7" height="7" rx="1.8" fill="#ececea"/><rect x="137" y="82" width="7" height="7" rx="1.8" fill="#ececea"/><rect x="146" y="28" width="7" height="7" rx="1.8" fill="#ececea"/><rect x="146" y="37" width="7" height="7" rx="1.8" fill="#2e5e9c"/><rect x="146" y="46" width="7" height="7" rx="1.8" fill="#d1e2f6"/><rect x="146" y="55" width="7" height="7" rx="1.8" fill="#2e5e9c"/><rect x="146" y="64" width="7" height="7" rx="1.8" fill="#90b6e3"/><rect x="146" y="73" width="7" height="7" rx="1.8" fill="#ececea"/><rect x="146" y="82" width="7" height="7" rx="1.8" fill="#d1e2f6"/><rect x="155" y="28" width="7" height="7" rx="1.8" fill="#90b6e3"/><rect x="155" y="37" width="7" height="7" rx="1.8" fill="#4d88d3"/><rect x="155" y="46" width="7" height="7" rx="1.8" fill="#4d88d3"/><rect x="155" y="55" width="7" height="7" rx="1.8" fill="#ececea"/><rect x="155" y="64" width="7" height="7" rx="1.8" fill="#d1e2f6"/><rect x="155" y="73" width="7" height="7" rx="1.8" fill="#ececea"/><rect x="155" y="82" width="7" height="7" rx="1.8" fill="#ececea"/><rect x="164" y="28" width="7" height="7" rx="1.8" fill="#ececea"/><rect x="164" y="37" width="7" height="7" rx="1.8" fill="#90b6e3"/><rect x="164" y="46" width="7" height="7" rx="1.8" fill="#4d88d3"/><rect x="164" y="55" width="7" height="7" rx="1.8" fill="#90b6e3"/><rect x="164" y="64" width="7" height="7" rx="1.8" fill="#2e5e9c"/><rect x="164" y="73" width="7" height="7" rx="1.8" fill="#ececea"/><rect x="164" y="82" width="7" height="7" rx="1.8" fill="#ececea"/><rect x="173" y="28" width="7" height="7" rx="1.8" fill="#90b6e3"/><rect x="173" y="37" width="7" height="7" rx="1.8" fill="#90b6e3"/><rect x="173" y="46" width="7" height="7" rx="1.8" fill="#4d88d3"/><rect x="173" y="55" width="7" height="7" rx="1.8" fill="#90b6e3"/><rect x="173" y="64" width="7" height="7" rx="1.8" fill="#90b6e3"/><rect x="173" y="73" width="7" height="7" rx="1.8" fill="#ececea"/><rect x="173" y="82" width="7" height="7" rx="1.8" fill="#ececea"/><rect x="182" y="28" width="7" height="7" rx="1.8" fill="#4d88d3"/><rect x="182" y="37" width="7" height="7" rx="1.8" fill="#ececea"/><rect x="182" y="46" width="7" height="7" rx="1.8" fill="#d1e2f6"/><rect x="182" y="55" width="7" height="7" rx="1.8" fill="#4d88d3"/><rect x="182" y="64" width="7" height="7" rx="1.8" fill="#4d88d3"/><rect x="182" y="73" width="7" height="7" rx="1.8" fill="#d1e2f6"/><rect x="182" y="82" width="7" height="7" rx="1.8" fill="#d1e2f6"/><rect x="191" y="28" width="7" height="7" rx="1.8" fill="#4d88d3"/><rect x="191" y="37" width="7" height="7" rx="1.8" fill="#4d88d3"/><rect x="191" y="46" width="7" height="7" rx="1.8" fill="#90b6e3"/><rect x="191" y="55" width="7" height="7" rx="1.8" fill="#90b6e3"/><rect x="191" y="64" width="7" height="7" rx="1.8" fill="#ececea"/><rect x="191" y="73" width="7" height="7" rx="1.8" fill="#ececea"/><rect x="191" y="82" width="7" height="7" rx="1.8" fill="#ececea"/><rect x="200" y="28" width="7" height="7" rx="1.8" fill="#d1e2f6"/><rect x="200" y="37" width="7" height="7" rx="1.8" fill="#d1e2f6"/><rect x="200" y="46" width="7" height="7" rx="1.8" fill="#4d88d3"/><rect x="200" y="55" width="7" height="7" rx="1.8" fill="#4d88d3"/><rect x="200" y="64" width="7" height="7" rx="1.8" fill="#d1e2f6"/><rect x="200" y="73" width="7" height="7" rx="1.8" fill="#d1e2f6"/><rect x="200" y="82" width="7" height="7" rx="1.8" fill="#ececea"/><rect x="209" y="28" width="7" height="7" rx="1.8" fill="#d1e2f6"/><rect x="209" y="37" width="7" height="7" rx="1.8" fill="#90b6e3"/><rect x="209" y="46" width="7" height="7" rx="1.8" fill="#90b6e3"/><rect x="209" y="55" width="7" height="7" rx="1.8" fill="#ececea"/></svg>
|