@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,387 @@
|
|
|
1
|
+
// gallery/weather (天气): a city's weather now and for the days ahead, from Open-Meteo (open-meteo.com,
|
|
2
|
+
// no key), for a custom page. Its settings, `city` (a name as the reader writes it: 上海, Berlin) and
|
|
3
|
+
// `unit` (℃ or ℉), are the card's form (the grip at its top right › 设置…), kept in the data part
|
|
4
|
+
// `settings`, which the board writes and this block only reads. The city is looked up by name
|
|
5
|
+
// (geocoding-api.open-meteo.com: its first match, its coordinates), its weather fetched for them
|
|
6
|
+
// (api.open-meteo.com: now, and each day's highest, lowest and sky for six days, today and the five after
|
|
7
|
+
// it), both through context.fetch, the server fetching for it: its needs name the two hosts, and nothing
|
|
8
|
+
// is fetched until the reader allows them (the kit then shows 允许访问 on the card and starts the block
|
|
9
|
+
// again once the reader says yes). Fetched again as its settings change (`source`) and every 30 minutes;
|
|
10
|
+
// the server keeps an answer a minute and gives what it kept when the network is not there, which the
|
|
11
|
+
// card says by its time (更新于 09:05; an answer kept more than 10 minutes, when the network is not there,
|
|
12
|
+
// the head's sign of no network and when it was fetched, 昨天 21:40). In the page's language.
|
|
13
|
+
//
|
|
14
|
+
// Its face (the pack's design B, in the kit's card tokens), laid out by the card's cells (`data-layout`, by
|
|
15
|
+
// context.size, read again on `layout`): a head of the chip (a place's pin), the city and when; the sky's
|
|
16
|
+
// picture (drawn in its own colors: the sun's orange, a cloud's gray, the rain's blue) beside the
|
|
17
|
+
// temperature, the hero, and the sky's words and today's lowest and highest; under them how it feels,
|
|
18
|
+
// the air's humidity and the wind (its direction and speed). A narrow card (2 wide) the picture and the
|
|
19
|
+
// temperature at the bottom and one line under them; a tall one (4 high) the next five days at the
|
|
20
|
+
// bottom, each its weekday, its sky, its lowest, a bar from its lowest to its highest on the scale of all
|
|
21
|
+
// of them, cold to warm, and its highest. What it says while there is nothing to show (no city yet, one
|
|
22
|
+
// not found, waiting for the reader's consent, the network not there, this computer's network setup
|
|
23
|
+
// sending Open-Meteo's names to an address of its own or of a private network, which the server refuses:
|
|
24
|
+
// code "private") is the cards' empty face under the head: what is so, and what to do, faint.
|
|
25
|
+
|
|
26
|
+
const WORDS = {
|
|
27
|
+
zh: {
|
|
28
|
+
title: "天气",
|
|
29
|
+
states: {
|
|
30
|
+
pick: ["写上一个城市", "在卡片右上角的 设置… 里填,比如「杭州」"],
|
|
31
|
+
loading: ["正在取天气…", ""],
|
|
32
|
+
consent: ["允许联网之后显示天气", "数据来自 open-meteo.com"],
|
|
33
|
+
offline: ["现在连不上网,取不到天气", "连上以后会自己再取"],
|
|
34
|
+
private: ["取不到天气", "网络设置把天气服务指向了本地地址"],
|
|
35
|
+
failed: ["没能取到天气", "过一会儿会自己再取"],
|
|
36
|
+
},
|
|
37
|
+
unknown: (/** @type {string} */ city) => [`找不到「${city}」`, "换个写法试试,比如「上海」"],
|
|
38
|
+
at: (/** @type {string} */ time) => `更新于 ${time}`,
|
|
39
|
+
yesterday: (/** @type {string} */ time) => `昨天 ${time}`,
|
|
40
|
+
day: (/** @type {number} */ month, /** @type {number} */ day, /** @type {string} */ time) => `${month}月${day}日 ${time}`,
|
|
41
|
+
feels: (/** @type {string} */ value) => `体感 ${value}`,
|
|
42
|
+
winds: ["北风", "东北风", "东风", "东南风", "南风", "西南风", "西风", "西北风"],
|
|
43
|
+
wind: (/** @type {string} */ from, /** @type {number} */ value) => `${from} ${value} km/h`,
|
|
44
|
+
today: "今天",
|
|
45
|
+
weekdays: ["周日", "周一", "周二", "周三", "周四", "周五", "周六"],
|
|
46
|
+
sky: {
|
|
47
|
+
clear: "晴", mostly: "大部晴朗", partly: "多云", overcast: "阴", fog: "雾", drizzle: "毛毛雨", "freezing-drizzle": "冻毛毛雨",
|
|
48
|
+
rain: "雨", "light-rain": "小雨", "heavy-rain": "大雨", "freezing-rain": "冻雨", snow: "雪", "light-snow": "小雪", "heavy-snow": "大雪",
|
|
49
|
+
grains: "雪粒", showers: "阵雨", "snow-showers": "阵雪", thunder: "雷阵雨", hail: "雷阵雨伴冰雹", unknown: "天气未知",
|
|
50
|
+
},
|
|
51
|
+
},
|
|
52
|
+
en: {
|
|
53
|
+
title: "Weather",
|
|
54
|
+
states: {
|
|
55
|
+
pick: ["Name a city", "In Settings… at the card's top right, such as “Berlin”"],
|
|
56
|
+
loading: ["Fetching the weather…", ""],
|
|
57
|
+
consent: ["Allow internet access to show the weather", "From open-meteo.com"],
|
|
58
|
+
offline: ["Offline: no weather now", "It fetches again once online"],
|
|
59
|
+
private: ["No weather", "The network setup sends the weather service to a local address"],
|
|
60
|
+
failed: ["The weather could not be fetched", "It tries again in a while"],
|
|
61
|
+
},
|
|
62
|
+
unknown: (/** @type {string} */ city) => [`No place called “${city}”`, "Try another spelling, such as “Berlin”"],
|
|
63
|
+
at: (/** @type {string} */ time) => `Updated ${time}`,
|
|
64
|
+
yesterday: (/** @type {string} */ time) => `Yesterday ${time}`,
|
|
65
|
+
day: (/** @type {number} */ month, /** @type {number} */ day, /** @type {string} */ time) => `${["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"][month - 1]} ${day} ${time}`,
|
|
66
|
+
feels: (/** @type {string} */ value) => `Feels ${value}`,
|
|
67
|
+
winds: ["N", "NE", "E", "SE", "S", "SW", "W", "NW"],
|
|
68
|
+
wind: (/** @type {string} */ from, /** @type {number} */ value) => `${from} ${value} km/h`,
|
|
69
|
+
today: "Today",
|
|
70
|
+
weekdays: ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"],
|
|
71
|
+
sky: {
|
|
72
|
+
clear: "Clear", mostly: "Mostly clear", partly: "Partly cloudy", overcast: "Overcast", fog: "Fog", drizzle: "Drizzle", "freezing-drizzle": "Freezing drizzle",
|
|
73
|
+
rain: "Rain", "light-rain": "Light rain", "heavy-rain": "Heavy rain", "freezing-rain": "Freezing rain", snow: "Snow", "light-snow": "Light snow", "heavy-snow": "Heavy snow",
|
|
74
|
+
grains: "Snow grains", showers: "Showers", "snow-showers": "Snow showers", thunder: "Thunderstorm", hail: "Thunderstorm with hail", unknown: "Unknown",
|
|
75
|
+
},
|
|
76
|
+
},
|
|
77
|
+
};
|
|
78
|
+
|
|
79
|
+
/** How old a kept answer is before the head says it is (with no network): 10 minutes. */
|
|
80
|
+
const STALE = 10 * 60_000;
|
|
81
|
+
|
|
82
|
+
/** The language the page speaks: the UI's where Gallery says it (data-ge-language), else its lang's. */
|
|
83
|
+
function languageOf(/** @type {HTMLElement} */ root) {
|
|
84
|
+
const ui = root.getAttribute("data-ge-language");
|
|
85
|
+
return (ui !== null ? ui === "en" : /^en(?:-|$)/i.test(root.lang)) ? "en" : "zh";
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
/**
|
|
89
|
+
* The sky a WMO weather code says (what Open-Meteo answers with), as { words (its key in WORDS' sky),
|
|
90
|
+
* picture (which of the pictures draws it) }; `day` false draws a clear or mostly clear sky with the moon.
|
|
91
|
+
* @param {unknown} code
|
|
92
|
+
* @param {boolean} day
|
|
93
|
+
*/
|
|
94
|
+
function skyOf(code, day = true) {
|
|
95
|
+
const sun = day ? "sun" : "moon";
|
|
96
|
+
/** @type {Record<number, [string, string]>} */
|
|
97
|
+
const skies = {
|
|
98
|
+
0: ["clear", sun], 1: ["mostly", sun], 2: ["partly", day ? "partly" : "partly-night"], 3: ["overcast", "cloud"],
|
|
99
|
+
45: ["fog", "fog"], 48: ["fog", "fog"], 51: ["drizzle", "rain"], 53: ["drizzle", "rain"], 55: ["drizzle", "rain"], 56: ["freezing-drizzle", "rain"], 57: ["freezing-drizzle", "rain"],
|
|
100
|
+
61: ["light-rain", "rain"], 63: ["rain", "rain"], 65: ["heavy-rain", "rain"], 66: ["freezing-rain", "rain"], 67: ["freezing-rain", "rain"],
|
|
101
|
+
71: ["light-snow", "snow"], 73: ["snow", "snow"], 75: ["heavy-snow", "snow"], 77: ["grains", "snow"],
|
|
102
|
+
80: ["showers", "rain"], 81: ["showers", "rain"], 82: ["showers", "rain"], 85: ["snow-showers", "snow"], 86: ["snow-showers", "snow"],
|
|
103
|
+
95: ["thunder", "thunder"], 96: ["hail", "thunder"], 99: ["hail", "thunder"],
|
|
104
|
+
};
|
|
105
|
+
const [words, picture] = typeof code === "number" && skies[code] ? skies[code] : ["unknown", "cloud"];
|
|
106
|
+
return { words, picture };
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
/**
|
|
110
|
+
* The address a city's name is looked up at (Open-Meteo's geocoding: its first match, in `language`).
|
|
111
|
+
* @param {string} city
|
|
112
|
+
* @param {"zh" | "en"} language
|
|
113
|
+
*/
|
|
114
|
+
const searchAddress = (city, language) => `https://geocoding-api.open-meteo.com/v1/search?name=${encodeURIComponent(city)}&count=1&language=${language}&format=json`;
|
|
115
|
+
|
|
116
|
+
/**
|
|
117
|
+
* The address of the weather at a place (its coordinates, to two decimals: one address for one place,
|
|
118
|
+
* which the server keeps), in `unit` (℃ or ℉): now, and six days (today and the five after it), by the
|
|
119
|
+
* place's own clock.
|
|
120
|
+
* @param {{ latitude: number, longitude: number }} place
|
|
121
|
+
* @param {string} unit
|
|
122
|
+
*/
|
|
123
|
+
const forecastAddress = (place, unit) => `https://api.open-meteo.com/v1/forecast?latitude=${place.latitude.toFixed(2)}&longitude=${place.longitude.toFixed(2)}`
|
|
124
|
+
+ "¤t=temperature_2m,apparent_temperature,relative_humidity_2m,wind_speed_10m,wind_direction_10m,weather_code,is_day"
|
|
125
|
+
+ `&daily=weather_code,temperature_2m_max,temperature_2m_min&timezone=auto&forecast_days=6${unit === "℉" ? "&temperature_unit=fahrenheit" : ""}`;
|
|
126
|
+
|
|
127
|
+
/**
|
|
128
|
+
* The first place a lookup's answer gives ({ name, latitude, longitude, region }), or null for none.
|
|
129
|
+
* @param {any} answer
|
|
130
|
+
*/
|
|
131
|
+
function placeOf(answer) {
|
|
132
|
+
const found = Array.isArray(answer?.results) ? answer.results[0] : null;
|
|
133
|
+
if (!found || typeof found.latitude !== "number" || typeof found.longitude !== "number") return null;
|
|
134
|
+
return { name: String(found.name ?? ""), latitude: found.latitude, longitude: found.longitude, region: String(found.admin1 ?? found.country ?? "") };
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
/** A temperature as the card writes it: whole degrees, a degree sign, a minus that is one. @param {unknown} value */
|
|
138
|
+
const degrees = (value) => (typeof value === "number" && Number.isFinite(value) ? `${Math.round(value)}°`.replace(/^-/, "−") : "–");
|
|
139
|
+
|
|
140
|
+
/**
|
|
141
|
+
* What the card says, in `language`, of `state` at `now`: { kind: "pick" } (no city), { kind: "loading",
|
|
142
|
+
* city }, { kind: "unknown", city } (no such place), { kind: "consent", city }, { kind: "offline", city },
|
|
143
|
+
* { kind: "private", city } (the server refused the address this computer's resolver gave: one of this
|
|
144
|
+
* computer or of a private network, its network setup's doing), { kind: "failed", city }, or
|
|
145
|
+
* { kind: "weather", place, forecast (Open-Meteo's answer), at (when it was fetched, ISO), cached }. Its head
|
|
146
|
+
* (the city, when, and whether that is an answer kept from before the network went: `stale`), and either a
|
|
147
|
+
* note and its hint (the empty face) or the weather: the sky's picture and words, the temperature, today's
|
|
148
|
+
* lowest and highest, the more line's pieces ({ icon, text }), and the five days after today.
|
|
149
|
+
* @param {any} state
|
|
150
|
+
* @param {"zh" | "en"} language
|
|
151
|
+
* @param {Date} [now]
|
|
152
|
+
*/
|
|
153
|
+
function faceOf(state, language, now = new Date()) {
|
|
154
|
+
const words = WORDS[language];
|
|
155
|
+
const named = state.kind === "pick" || state.kind === "unknown";
|
|
156
|
+
const head = { city: named ? words.title : state.city || state.place?.name || words.title, at: "", stale: false };
|
|
157
|
+
if (state.kind !== "weather") {
|
|
158
|
+
/** @type {Record<string, string[]>} */
|
|
159
|
+
const states = words.states;
|
|
160
|
+
const [note, hint] = state.kind === "unknown" ? words.unknown(state.city) : states[state.kind] ?? states.failed;
|
|
161
|
+
return { head, note, hint, now: null, days: [] };
|
|
162
|
+
}
|
|
163
|
+
const { current = {}, daily = {} } = state.forecast ?? {};
|
|
164
|
+
const sky = skyOf(current.weather_code, current.is_day !== 0);
|
|
165
|
+
const fetched = typeof state.at === "string" ? new Date(state.at) : null;
|
|
166
|
+
const two = (/** @type {number} */ value) => String(value).padStart(2, "0");
|
|
167
|
+
if (fetched && !Number.isNaN(fetched.getTime())) {
|
|
168
|
+
const time = `${two(fetched.getHours())}:${two(fetched.getMinutes())}`;
|
|
169
|
+
head.stale = state.cached === true && now.getTime() - fetched.getTime() > STALE;
|
|
170
|
+
const day = (/** @type {Date} */ date) => Date.UTC(date.getFullYear(), date.getMonth(), date.getDate()) / 86_400_000;
|
|
171
|
+
const ago = day(now) - day(fetched);
|
|
172
|
+
head.at = !head.stale ? words.at(time) : ago === 0 ? time : ago === 1 ? words.yesterday(time) : words.day(fetched.getMonth() + 1, fetched.getDate(), time);
|
|
173
|
+
}
|
|
174
|
+
const range = (/** @type {number} */ index) => `${degrees(daily.temperature_2m_min?.[index])} / ${degrees(daily.temperature_2m_max?.[index])}`;
|
|
175
|
+
const more = [
|
|
176
|
+
typeof current.apparent_temperature === "number" ? { icon: "feels", text: words.feels(degrees(current.apparent_temperature)) } : null,
|
|
177
|
+
typeof current.relative_humidity_2m === "number" ? { icon: "humidity", text: `${Math.round(current.relative_humidity_2m)}%` } : null,
|
|
178
|
+
typeof current.wind_speed_10m === "number" ? { icon: "wind", text: words.wind(typeof current.wind_direction_10m === "number" ? words.winds[Math.round(current.wind_direction_10m / 45) % 8] : "", Math.round(current.wind_speed_10m)).trim() } : null,
|
|
179
|
+
].filter((piece) => piece !== null);
|
|
180
|
+
const dates = Array.isArray(daily.time) ? daily.time : [];
|
|
181
|
+
const days = dates.slice(1, 6).map((/** @type {string} */ date, /** @type {number} */ at) => {
|
|
182
|
+
const index = at + 1;
|
|
183
|
+
const [year, month, day] = String(date).split("-").map(Number);
|
|
184
|
+
const weekday = words.weekdays[new Date(Date.UTC(year, month - 1, day)).getUTCDay()] ?? "";
|
|
185
|
+
const [high, low] = [daily.temperature_2m_max?.[index], daily.temperature_2m_min?.[index]];
|
|
186
|
+
const kind = skyOf(daily.weather_code?.[index]);
|
|
187
|
+
return { weekday, picture: kind.picture, sky: words.sky[kind.words], range: range(index), high: degrees(high), low: degrees(low), span: typeof high === "number" && typeof low === "number" && Number.isFinite(high) && Number.isFinite(low) ? [low, high] : null };
|
|
188
|
+
});
|
|
189
|
+
const span = typeof daily.temperature_2m_max?.[0] === "number" && typeof daily.temperature_2m_min?.[0] === "number" ? [daily.temperature_2m_min[0], daily.temperature_2m_max[0]] : null;
|
|
190
|
+
return { head, note: "", hint: "", now: { picture: sky.picture, sky: words.sky[sky.words], temperature: degrees(current.temperature_2m), range: dates.length ? range(0) : "", span, more }, days };
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
// The sky's pictures, each drawn on a box of 64 in its own colors (style.css: the sun's orange, a cloud's
|
|
194
|
+
// gray, the rain's blue, as the instance's custom properties say them in light and dark).
|
|
195
|
+
const cloud = (x = 0, y = 0, scale = 1, tone = "cloud") => `<g transform="translate(${x} ${y}) scale(${scale})" class="gallery-weather-${tone}"><rect x="13" y="34" width="39" height="15" rx="7.5"/><circle cx="24" cy="35" r="8.5"/><circle cx="35.5" cy="30" r="11.5"/><circle cx="45.5" cy="38" r="7.5"/></g>`;
|
|
196
|
+
function sunAt(cx, cy, r) {
|
|
197
|
+
let rays = "";
|
|
198
|
+
for (let i = 0; i < 8; i++) {
|
|
199
|
+
const a = (i * Math.PI) / 4;
|
|
200
|
+
rays += `<line x1="${(cx + (r + 5) * Math.cos(a)).toFixed(1)}" y1="${(cy + (r + 5) * Math.sin(a)).toFixed(1)}" x2="${(cx + (r + 9.5) * Math.cos(a)).toFixed(1)}" y2="${(cy + (r + 9.5) * Math.sin(a)).toFixed(1)}"/>`;
|
|
201
|
+
}
|
|
202
|
+
return `<g class="gallery-weather-sun"><circle cx="${cx}" cy="${cy}" r="${r}"/><g class="gallery-weather-rays" stroke-width="3" stroke-linecap="round">${rays}</g></g>`;
|
|
203
|
+
}
|
|
204
|
+
const moonAt = (cx, cy, r) => `<path class="gallery-weather-moon" d="M${cx + r * 0.35} ${cy - r}a${r} ${r} 0 1 0 ${r * 0.65} ${r * 1.55}a${r * 0.8} ${r * 0.8} 0 0 1 -${r * 0.65} -${r * 1.55}z"/>`;
|
|
205
|
+
const PICTURES = {
|
|
206
|
+
sun: sunAt(32, 32, 11),
|
|
207
|
+
moon: moonAt(30, 32, 14),
|
|
208
|
+
partly: sunAt(24, 23, 9) + cloud(5, 5, 0.95),
|
|
209
|
+
"partly-night": moonAt(22, 22, 11) + cloud(5, 5, 0.95),
|
|
210
|
+
cloud: cloud(-6, -8, 0.9, "cloud-2") + cloud(4, 2, 1),
|
|
211
|
+
fog: `${cloud(0, -8, 1)}<g class="gallery-weather-mist" stroke-width="3.2" stroke-linecap="round"><line x1="14" y1="49" x2="50" y2="49"/><line x1="20" y1="56" x2="44" y2="56"/></g>`,
|
|
212
|
+
rain: `${cloud(0, -6, 1)}<g class="gallery-weather-rain" stroke-width="3.2" stroke-linecap="round"><line x1="24" y1="49" x2="21.5" y2="55"/><line x1="33.5" y1="49" x2="31" y2="55"/><line x1="43" y1="49" x2="40.5" y2="55"/></g>`,
|
|
213
|
+
snow: `${cloud(0, -6, 1)}<g class="gallery-weather-snow"><circle cx="23" cy="52" r="2.4"/><circle cx="32.5" cy="56" r="2.4"/><circle cx="42" cy="52" r="2.4"/></g>`,
|
|
214
|
+
thunder: `${cloud(0, -8, 1)}<path class="gallery-weather-bolt" d="M34 40l-7 10h6l-3 9 9-12h-6l3-7z"/>`,
|
|
215
|
+
};
|
|
216
|
+
// The more line's small pictures, of lines, 24 x 24.
|
|
217
|
+
const ICONS = {
|
|
218
|
+
feels: '<path d="M10 13.8V5.5a2 2 0 1 1 4 0v8.3a3.8 3.8 0 1 1-4 0z"/>',
|
|
219
|
+
humidity: '<path d="M12 4s5.5 6 5.5 10a5.5 5.5 0 0 1-11 0C6.5 10 12 4 12 4z"/>',
|
|
220
|
+
wind: '<path d="M3.5 9.5h10a2.8 2.8 0 1 0-2.8-2.8M3.5 14.5h14a2.8 2.8 0 1 1-2.8 2.8M3.5 12h6"/>',
|
|
221
|
+
offline: '<path d="M3.5 3.5l17 17M9 16.2a4.5 4.5 0 0 1 5.5-.5M5.5 12.5a9.5 9.5 0 0 1 3.6-2.3M18.6 12.6a9.5 9.5 0 0 0-3-2.1M2.5 9a14 14 0 0 1 3.5-2.3M21.5 9A14 14 0 0 0 10.6 5.3"/><circle cx="12" cy="19.5" r=".9" fill="currentColor"/>',
|
|
222
|
+
};
|
|
223
|
+
const lines = (/** @type {string} */ drawing) => `<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.7" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true">${drawing}</svg>`;
|
|
224
|
+
|
|
225
|
+
/**
|
|
226
|
+
* An element of the face, of `kind` (its class).
|
|
227
|
+
* @template {keyof HTMLElementTagNameMap} K
|
|
228
|
+
* @param {K} tag
|
|
229
|
+
* @param {string} kind
|
|
230
|
+
*/
|
|
231
|
+
function made(tag, kind) {
|
|
232
|
+
const node = document.createElement(tag);
|
|
233
|
+
node.className = `gallery-weather-${kind}`;
|
|
234
|
+
return node;
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
/** A sky's picture, as an svg element. @param {string} picture */
|
|
238
|
+
function pictureOf(picture) {
|
|
239
|
+
const svg = document.createElementNS("http://www.w3.org/2000/svg", "svg");
|
|
240
|
+
svg.setAttribute("viewBox", "0 0 64 64");
|
|
241
|
+
svg.setAttribute("aria-hidden", "true");
|
|
242
|
+
svg.setAttribute("class", "gallery-weather-picture");
|
|
243
|
+
svg.innerHTML = PICTURES[/** @type {keyof typeof PICTURES} */ (picture)] ?? PICTURES.cloud;
|
|
244
|
+
return svg;
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
DocKit.component({
|
|
248
|
+
id: "gallery/weather",
|
|
249
|
+
on: ["source", "layout"],
|
|
250
|
+
mount(host, context) {
|
|
251
|
+
const language = languageOf(document.documentElement);
|
|
252
|
+
const face = made("div", "face");
|
|
253
|
+
host.append(face);
|
|
254
|
+
const layout = () => {
|
|
255
|
+
const size = context.size;
|
|
256
|
+
face.dataset.layout = !size ? "wide" : size.w <= 2 ? "narrow" : size.h >= 4 ? "tall" : "wide";
|
|
257
|
+
};
|
|
258
|
+
const draw = (/** @type {any} */ state) => {
|
|
259
|
+
const said = faceOf(state, language);
|
|
260
|
+
const head = made("p", "head");
|
|
261
|
+
const chip = made("span", "chip");
|
|
262
|
+
chip.setAttribute("aria-hidden", "true");
|
|
263
|
+
chip.innerHTML = '<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.9" stroke-linecap="round" stroke-linejoin="round"><path d="M12 21s-6.5-5.6-6.5-11a6.5 6.5 0 0 1 13 0c0 5.4-6.5 11-6.5 11z"/><circle cx="12" cy="10" r="2.3"/></svg>';
|
|
264
|
+
const city = made("span", "city");
|
|
265
|
+
city.textContent = said.head.city;
|
|
266
|
+
const at = made("span", "at");
|
|
267
|
+
if (said.head.stale) {
|
|
268
|
+
const sign = made("span", "stale");
|
|
269
|
+
sign.innerHTML = lines(ICONS.offline);
|
|
270
|
+
sign.title = said.head.at;
|
|
271
|
+
at.append(sign);
|
|
272
|
+
}
|
|
273
|
+
// The time in words of its own: a narrow card shows the sign of an answer kept from before alone (style.css).
|
|
274
|
+
const when = made("span", "when");
|
|
275
|
+
when.textContent = said.head.at;
|
|
276
|
+
at.append(when);
|
|
277
|
+
head.append(chip, city, at);
|
|
278
|
+
/** @type {HTMLElement[]} */
|
|
279
|
+
const parts = [head];
|
|
280
|
+
if (said.now) {
|
|
281
|
+
const now = made("div", "now");
|
|
282
|
+
const temperature = made("span", "temperature");
|
|
283
|
+
temperature.textContent = said.now.temperature;
|
|
284
|
+
const words = made("span", "words");
|
|
285
|
+
const sky = made("span", "sky");
|
|
286
|
+
sky.textContent = said.now.sky;
|
|
287
|
+
const range = made("span", "range");
|
|
288
|
+
range.textContent = said.now.range;
|
|
289
|
+
words.append(sky, range);
|
|
290
|
+
now.append(pictureOf(said.now.picture), temperature, words);
|
|
291
|
+
const more = made("p", "more");
|
|
292
|
+
more.replaceChildren(...said.now.more.map(({ icon, text }) => {
|
|
293
|
+
const span = made("span", "piece");
|
|
294
|
+
span.innerHTML = lines(ICONS[/** @type {keyof typeof ICONS} */ (icon)]);
|
|
295
|
+
span.append(text);
|
|
296
|
+
return span;
|
|
297
|
+
}));
|
|
298
|
+
const days = made("ol", "days");
|
|
299
|
+
const spans = [...said.days.flatMap((day) => (day.span ? [day.span] : [])), ...(said.now.span ? [said.now.span] : [])];
|
|
300
|
+
const lowest = Math.min(...spans.map(([low]) => low));
|
|
301
|
+
const highest = Math.max(...spans.map(([, high]) => high));
|
|
302
|
+
days.replaceChildren(...said.days.map((day) => {
|
|
303
|
+
const item = made("li", "day");
|
|
304
|
+
const weekday = made("span", "weekday");
|
|
305
|
+
weekday.textContent = day.weekday;
|
|
306
|
+
const low = made("span", "low");
|
|
307
|
+
low.textContent = day.low;
|
|
308
|
+
const bar = made("span", "bar");
|
|
309
|
+
bar.setAttribute("aria-hidden", "true");
|
|
310
|
+
if (day.span && highest > lowest) {
|
|
311
|
+
// The day's part of the whole scale, its colors the scale's own there: the gradient as wide as the scale, moved under it.
|
|
312
|
+
const from = (day.span[0] - lowest) / (highest - lowest);
|
|
313
|
+
const to = (day.span[1] - lowest) / (highest - lowest);
|
|
314
|
+
const fill = made("span", "fill");
|
|
315
|
+
fill.style.left = `${from * 100}%`;
|
|
316
|
+
fill.style.right = `${(1 - to) * 100}%`;
|
|
317
|
+
const part = Math.max(to - from, 0.01);
|
|
318
|
+
fill.style.backgroundSize = `${100 / part}% 100%`;
|
|
319
|
+
fill.style.backgroundPosition = `${1 - part > 0 ? (from / (1 - part)) * 100 : 0}% 0`;
|
|
320
|
+
bar.append(fill);
|
|
321
|
+
}
|
|
322
|
+
const high = made("span", "high");
|
|
323
|
+
high.textContent = day.high;
|
|
324
|
+
const picture = pictureOf(day.picture);
|
|
325
|
+
picture.setAttribute("aria-label", day.sky);
|
|
326
|
+
picture.removeAttribute("aria-hidden");
|
|
327
|
+
picture.setAttribute("role", "img");
|
|
328
|
+
item.append(weekday, picture, low, bar, high);
|
|
329
|
+
return item;
|
|
330
|
+
}));
|
|
331
|
+
// A narrow card's one line under the temperature: the sky, then today's lowest and highest.
|
|
332
|
+
const line = made("p", "line");
|
|
333
|
+
const lineSky = document.createElement("b");
|
|
334
|
+
lineSky.textContent = said.now.sky;
|
|
335
|
+
const dot = made("span", "dot");
|
|
336
|
+
dot.textContent = "·";
|
|
337
|
+
line.append(lineSky, dot, said.now.range);
|
|
338
|
+
parts.push(now, line, more, days);
|
|
339
|
+
} else {
|
|
340
|
+
const empty = made("div", "empty");
|
|
341
|
+
const note = made("p", "note");
|
|
342
|
+
note.textContent = said.note;
|
|
343
|
+
empty.append(note);
|
|
344
|
+
if (said.hint) {
|
|
345
|
+
const hint = made("p", "hint");
|
|
346
|
+
hint.textContent = said.hint;
|
|
347
|
+
empty.append(hint);
|
|
348
|
+
}
|
|
349
|
+
parts.push(empty);
|
|
350
|
+
}
|
|
351
|
+
face.replaceChildren(...parts);
|
|
352
|
+
face.dataset.kind = state.kind;
|
|
353
|
+
layout();
|
|
354
|
+
};
|
|
355
|
+
let asked = 0; // the latest load: an earlier one that answers later draws nothing
|
|
356
|
+
const load = async () => {
|
|
357
|
+
const mine = ++asked;
|
|
358
|
+
const settings = context.readJSON("settings");
|
|
359
|
+
if (settings === undefined) return; // no JSON: the instance has failed, and Gallery shows what it holds
|
|
360
|
+
const city = typeof settings?.city === "string" ? settings.city.trim() : "";
|
|
361
|
+
const unit = settings?.unit === "℉" ? "℉" : "℃";
|
|
362
|
+
if (!city) return draw({ kind: "pick" });
|
|
363
|
+
draw({ kind: "loading", city });
|
|
364
|
+
try {
|
|
365
|
+
const found = placeOf((await context.fetch(searchAddress(city, language))).data);
|
|
366
|
+
if (mine !== asked) return;
|
|
367
|
+
if (!found) return draw({ kind: "unknown", city });
|
|
368
|
+
const answer = await context.fetch(forecastAddress(found, unit));
|
|
369
|
+
if (mine !== asked) return;
|
|
370
|
+
draw({ kind: "weather", city, place: found, forecast: answer.data, at: answer.at, cached: answer.cached });
|
|
371
|
+
} catch (error) {
|
|
372
|
+
if (mine !== asked) return;
|
|
373
|
+
const code = /** @type {DocFetchError} */ (error).code;
|
|
374
|
+
draw({ kind: code === "consent" || code === "offline" || code === "private" ? code : "failed", city });
|
|
375
|
+
if (!code) context.fail(error); // no refusal of the server's: the block's own mistake, which the kit says
|
|
376
|
+
}
|
|
377
|
+
};
|
|
378
|
+
load();
|
|
379
|
+
context.interval(load, 30 * 60_000);
|
|
380
|
+
return {
|
|
381
|
+
update(reason) {
|
|
382
|
+
if (reason === "source") load();
|
|
383
|
+
else if (reason === "layout") layout();
|
|
384
|
+
},
|
|
385
|
+
};
|
|
386
|
+
},
|
|
387
|
+
});
|
|
@@ -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="16.5" y="12.5" width="207" height="95" rx="8" fill="#ffffff" stroke="#e6e6e3"/><rect x="28" y="22" width="10" height="10" rx="3" fill="#efefed"/><rect x="42" y="24.5" width="18" height="5" rx="2.5" fill="#37352f"/><rect x="64" y="24.5" width="34" height="5" rx="2.5" fill="#d4d3cf"/><g fill="#f3a935" stroke="#f3a935"><circle cx="40" cy="52" r="6"/><path d="M40 41v3M40 60v3M29 52h3M48 52h3M32.5 44.5l2 2M45.5 44.5l-2 2M32.5 59.5l2-2" stroke-width="1.6" stroke-linecap="round"/></g><g fill="#dde2e9"><rect x="38" y="56" width="22" height="9" rx="4.5"/><circle cx="45" cy="57" r="5"/><circle cx="52" cy="54" r="6.5"/></g><rect x="70" y="44" width="34" height="22" rx="3" fill="#1d1d1b"/><rect x="112" y="46" width="16" height="6" rx="3" fill="#37352f"/><rect x="112" y="57" width="26" height="5" rx="2.5" fill="#a6a5a1"/><rect x="28" y="88" width="40" height="5" rx="2.5" fill="#a6a5a1"/><rect x="80" y="88" width="26" height="5" rx="2.5" fill="#a6a5a1"/><rect x="132" y="88" width="54" height="5" rx="2.5" fill="#a6a5a1"/></svg>
|
|
@@ -0,0 +1,140 @@
|
|
|
1
|
+
/* Every selector starts at the instance and goes down a step at a time (>), so that nothing here
|
|
2
|
+
reaches the rest of the page. The pack's design B, in the kit's card tokens, laid out by the card's cells
|
|
3
|
+
(the face's data-layout): "wide" (4 × 2) the head (the chip, a pin, the city, when, faint), the sky's
|
|
4
|
+
picture (50px) beside the temperature (46px, the hero) and the sky's words over today's lowest and
|
|
5
|
+
highest, and at the bottom how it feels, the humidity and the wind, each after a small picture; "narrow"
|
|
6
|
+
(2 × 2) the picture (40px) and the temperature (40px) at the bottom and one line under them; "tall" (4 ×
|
|
7
|
+
4) the picture larger (60px) and, at the bottom over a hairline, the next five days, each a row of its
|
|
8
|
+
weekday, its sky (22px), its lowest (faint), a bar of its span on the scale of all of them (the cold
|
|
9
|
+
blue to the warm orange) and its highest (600). The pictures have their own colors (the sun's orange, a
|
|
10
|
+
cloud's gray, the rain's blue), in light and dark. A state with nothing to show is the cards' empty face
|
|
11
|
+
under the head. Light and dark. */
|
|
12
|
+
[data-doc-component="gallery/weather"] {
|
|
13
|
+
--gallery-weather-sun: light-dark(#f3a935, #f4b045);
|
|
14
|
+
--gallery-weather-cloud: light-dark(#dde2e9, #68717e);
|
|
15
|
+
--gallery-weather-cloud-2: light-dark(#c4cbd5, #4a515b);
|
|
16
|
+
--gallery-weather-rain: light-dark(#5e90d8, #70a1e2);
|
|
17
|
+
--gallery-weather-cool: light-dark(#88b2e3, #6b9bd7);
|
|
18
|
+
--gallery-weather-hot: light-dark(#f3b45a, #efa94a);
|
|
19
|
+
font-family: var(--gallery-font);
|
|
20
|
+
font-size: 13px;
|
|
21
|
+
line-height: 1.5;
|
|
22
|
+
color: var(--gallery-text);
|
|
23
|
+
> .gallery-weather-face { display: flex; flex-direction: column; box-sizing: border-box; min-height: 0; }
|
|
24
|
+
> .gallery-weather-face > .gallery-weather-head {
|
|
25
|
+
display: flex;
|
|
26
|
+
align-items: center;
|
|
27
|
+
gap: 8px;
|
|
28
|
+
flex: none;
|
|
29
|
+
height: 20px;
|
|
30
|
+
min-width: 0;
|
|
31
|
+
margin: 0;
|
|
32
|
+
padding-inline-end: var(--gallery-grip-room, 0px);
|
|
33
|
+
}
|
|
34
|
+
> .gallery-weather-face > .gallery-weather-head > .gallery-weather-chip {
|
|
35
|
+
flex: none;
|
|
36
|
+
display: grid;
|
|
37
|
+
place-items: center;
|
|
38
|
+
width: var(--gallery-chip-size);
|
|
39
|
+
height: var(--gallery-chip-size);
|
|
40
|
+
border-radius: var(--gallery-chip-radius);
|
|
41
|
+
background: var(--gallery-fill);
|
|
42
|
+
color: var(--gallery-muted);
|
|
43
|
+
}
|
|
44
|
+
> .gallery-weather-face > .gallery-weather-head > .gallery-weather-chip > svg { display: block; width: var(--gallery-chip-icon); height: var(--gallery-chip-icon); }
|
|
45
|
+
> .gallery-weather-face > .gallery-weather-head > .gallery-weather-city {
|
|
46
|
+
min-width: 0;
|
|
47
|
+
overflow: hidden;
|
|
48
|
+
white-space: nowrap;
|
|
49
|
+
text-overflow: ellipsis;
|
|
50
|
+
font-size: var(--gallery-title-size);
|
|
51
|
+
line-height: var(--gallery-title-line);
|
|
52
|
+
font-weight: 600;
|
|
53
|
+
color: var(--gallery-text);
|
|
54
|
+
}
|
|
55
|
+
> .gallery-weather-face > .gallery-weather-head > .gallery-weather-at { display: inline-flex; align-items: center; gap: 4px; flex: none; font-size: var(--gallery-meta-size); color: var(--gallery-faint); white-space: nowrap; font-variant-numeric: tabular-nums; }
|
|
56
|
+
> .gallery-weather-face > .gallery-weather-head > .gallery-weather-at > .gallery-weather-stale { display: inline-flex; color: var(--gallery-warm); }
|
|
57
|
+
> .gallery-weather-face > .gallery-weather-head > .gallery-weather-at > .gallery-weather-stale > svg { width: 12px; height: 12px; stroke-width: 2; }
|
|
58
|
+
> .gallery-weather-face > .gallery-weather-now { display: flex; align-items: center; gap: 10px; flex: none; margin-top: 10px; }
|
|
59
|
+
> .gallery-weather-face > .gallery-weather-now > .gallery-weather-picture { flex: none; width: 50px; height: 50px; overflow: visible; }
|
|
60
|
+
> .gallery-weather-face > .gallery-weather-now > .gallery-weather-temperature {
|
|
61
|
+
font-size: 46px;
|
|
62
|
+
line-height: 1;
|
|
63
|
+
font-weight: 500;
|
|
64
|
+
letter-spacing: -.04em;
|
|
65
|
+
font-variant-numeric: lining-nums;
|
|
66
|
+
color: var(--gallery-text-strong);
|
|
67
|
+
}
|
|
68
|
+
> .gallery-weather-face > .gallery-weather-now > .gallery-weather-words { display: flex; flex-direction: column; gap: 2px; margin-left: 6px; min-width: 0; }
|
|
69
|
+
> .gallery-weather-face > .gallery-weather-now > .gallery-weather-words > .gallery-weather-sky { font-size: 14px; line-height: 18px; font-weight: 600; color: var(--gallery-text); white-space: nowrap; }
|
|
70
|
+
> .gallery-weather-face > .gallery-weather-now > .gallery-weather-words > .gallery-weather-range { font-size: 12.5px; line-height: 16px; color: var(--gallery-muted); font-variant-numeric: tabular-nums; white-space: nowrap; }
|
|
71
|
+
> .gallery-weather-face > .gallery-weather-line { display: none; }
|
|
72
|
+
> .gallery-weather-face > .gallery-weather-more { display: flex; gap: 14px; flex: none; margin: auto 0 0; font-size: 12px; line-height: 16px; color: var(--gallery-muted); white-space: nowrap; overflow: hidden; }
|
|
73
|
+
> .gallery-weather-face > .gallery-weather-more > .gallery-weather-piece { display: inline-flex; align-items: center; gap: 4px; }
|
|
74
|
+
> .gallery-weather-face > .gallery-weather-more > .gallery-weather-piece > svg { flex: none; width: 13px; height: 13px; color: var(--gallery-faint); }
|
|
75
|
+
> .gallery-weather-face > .gallery-weather-days { display: none; }
|
|
76
|
+
/* The pictures' own colors. */
|
|
77
|
+
> .gallery-weather-face svg .gallery-weather-sun { fill: var(--gallery-weather-sun); stroke: var(--gallery-weather-sun); }
|
|
78
|
+
> .gallery-weather-face svg .gallery-weather-sun > circle { stroke: none; }
|
|
79
|
+
> .gallery-weather-face svg .gallery-weather-moon { fill: var(--gallery-weather-sun); }
|
|
80
|
+
> .gallery-weather-face svg .gallery-weather-cloud { fill: var(--gallery-weather-cloud); }
|
|
81
|
+
> .gallery-weather-face svg .gallery-weather-cloud-2 { fill: var(--gallery-weather-cloud-2); }
|
|
82
|
+
> .gallery-weather-face svg :is(.gallery-weather-rain, .gallery-weather-mist) { stroke: var(--gallery-weather-rain); }
|
|
83
|
+
> .gallery-weather-face svg .gallery-weather-mist { stroke: var(--gallery-weather-cloud-2); }
|
|
84
|
+
> .gallery-weather-face svg .gallery-weather-snow { fill: var(--gallery-weather-cool); }
|
|
85
|
+
> .gallery-weather-face svg .gallery-weather-bolt { fill: var(--gallery-weather-sun); }
|
|
86
|
+
|
|
87
|
+
/* A narrow card: the picture and the temperature at the bottom, one line under them. */
|
|
88
|
+
/* Its head the city alone, but for the sign of an answer kept from before the network went (its time in its title), so that yesterday's weather never reads as now's. */
|
|
89
|
+
> .gallery-weather-face[data-layout="narrow"] > .gallery-weather-head > .gallery-weather-at:not(:has(> .gallery-weather-stale)) { display: none; }
|
|
90
|
+
> .gallery-weather-face[data-layout="narrow"] > .gallery-weather-head > .gallery-weather-at > .gallery-weather-when { display: none; }
|
|
91
|
+
> .gallery-weather-face[data-layout="narrow"] > .gallery-weather-now { margin-top: auto; gap: 4px; }
|
|
92
|
+
> .gallery-weather-face[data-layout="narrow"] > .gallery-weather-now > .gallery-weather-picture { width: 40px; height: 40px; }
|
|
93
|
+
> .gallery-weather-face[data-layout="narrow"] > .gallery-weather-now > .gallery-weather-temperature { font-size: 40px; }
|
|
94
|
+
> .gallery-weather-face[data-layout="narrow"] > .gallery-weather-now > .gallery-weather-words,
|
|
95
|
+
> .gallery-weather-face[data-layout="narrow"] > .gallery-weather-more { display: none; }
|
|
96
|
+
> .gallery-weather-face[data-layout="narrow"] > .gallery-weather-line { display: block; margin: 6px 0 0; font-size: 12.5px; line-height: 16px; color: var(--gallery-muted); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; font-variant-numeric: tabular-nums; }
|
|
97
|
+
> .gallery-weather-face[data-layout="narrow"] > .gallery-weather-line > b { font-weight: 600; color: var(--gallery-text); }
|
|
98
|
+
> .gallery-weather-face[data-layout="narrow"] > .gallery-weather-line > .gallery-weather-dot { margin: 0 5px; color: var(--gallery-faintest); }
|
|
99
|
+
/* A tall card: the five days ahead at the bottom. */
|
|
100
|
+
> .gallery-weather-face[data-layout="tall"] > .gallery-weather-now { margin-top: 14px; }
|
|
101
|
+
> .gallery-weather-face[data-layout="tall"] > .gallery-weather-now > .gallery-weather-picture { width: 60px; height: 60px; }
|
|
102
|
+
> .gallery-weather-face[data-layout="tall"] > .gallery-weather-more { margin-top: 12px; }
|
|
103
|
+
> .gallery-weather-face[data-layout="tall"] > .gallery-weather-days {
|
|
104
|
+
display: flex;
|
|
105
|
+
flex-direction: column;
|
|
106
|
+
margin: auto 0 0;
|
|
107
|
+
padding: 6px 0 0;
|
|
108
|
+
border-top: 1px solid var(--gallery-hair);
|
|
109
|
+
list-style: none;
|
|
110
|
+
}
|
|
111
|
+
> .gallery-weather-face > .gallery-weather-days > .gallery-weather-day {
|
|
112
|
+
display: grid;
|
|
113
|
+
grid-template-columns: 34px 24px 30px 1fr 30px;
|
|
114
|
+
align-items: center;
|
|
115
|
+
gap: 6px;
|
|
116
|
+
height: 26px;
|
|
117
|
+
font-size: 12.5px;
|
|
118
|
+
font-variant-numeric: tabular-nums;
|
|
119
|
+
}
|
|
120
|
+
> .gallery-weather-face > .gallery-weather-days > .gallery-weather-day > .gallery-weather-weekday { color: var(--gallery-text); }
|
|
121
|
+
> .gallery-weather-face > .gallery-weather-days > .gallery-weather-day > .gallery-weather-picture { width: 22px; height: 22px; overflow: visible; }
|
|
122
|
+
> .gallery-weather-face > .gallery-weather-days > .gallery-weather-day > .gallery-weather-low { color: var(--gallery-faint); text-align: right; }
|
|
123
|
+
> .gallery-weather-face > .gallery-weather-days > .gallery-weather-day > .gallery-weather-high { color: var(--gallery-text); font-weight: 600; }
|
|
124
|
+
> .gallery-weather-face > .gallery-weather-days > .gallery-weather-day > .gallery-weather-bar { position: relative; height: 5px; border-radius: 3px; background: var(--gallery-fill); }
|
|
125
|
+
> .gallery-weather-face > .gallery-weather-days > .gallery-weather-day > .gallery-weather-bar > .gallery-weather-fill {
|
|
126
|
+
position: absolute;
|
|
127
|
+
top: 0;
|
|
128
|
+
bottom: 0;
|
|
129
|
+
border-radius: 3px;
|
|
130
|
+
background-image: linear-gradient(90deg, var(--gallery-weather-cool), var(--gallery-weather-hot));
|
|
131
|
+
}
|
|
132
|
+
/* Nothing to show yet: the cards' empty face under the head. */
|
|
133
|
+
> .gallery-weather-face > .gallery-weather-empty { flex: 1; display: flex; flex-direction: column; justify-content: center; gap: 4px; min-height: 0; }
|
|
134
|
+
> .gallery-weather-face > .gallery-weather-empty > p { margin: 0; }
|
|
135
|
+
> .gallery-weather-face > .gallery-weather-empty > .gallery-weather-note { font-size: 13.5px; line-height: 20px; font-weight: 600; color: var(--gallery-text); }
|
|
136
|
+
> .gallery-weather-face > .gallery-weather-empty > .gallery-weather-hint { font-size: 12px; line-height: 18px; color: var(--gallery-faint); }
|
|
137
|
+
}
|
|
138
|
+
/* On a custom page the face fills the card the board frames. */
|
|
139
|
+
.gallery-card > [data-doc-component="gallery/weather"] { height: 100%; }
|
|
140
|
+
.gallery-card > [data-doc-component="gallery/weather"] > .gallery-weather-face { height: 100%; }
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
# 天气 (gallery/weather)
|
|
2
|
+
|
|
3
|
+
A card for a custom page (its places are `page`): a city's weather now (the sky's picture and words, the temperature, today's highest and lowest, how it feels, the humidity and the wind) and, on a tall card, the next five days. The data comes from Open-Meteo (open-meteo.com), which needs no key. Use it when the user asks for the weather on a page, its home page among them.
|
|
4
|
+
|
|
5
|
+
## Settings
|
|
6
|
+
|
|
7
|
+
Its two settings are the card's form, which the user opens from the grip at the card's top right › 设置…:
|
|
8
|
+
|
|
9
|
+
| Key | Label | Type | What it is |
|
|
10
|
+
| --- | --- | --- | --- |
|
|
11
|
+
| `city` | 城市 | text | the city, as the user names it: 上海, 杭州, Berlin; looked up by that name, its first match taken |
|
|
12
|
+
| `unit` | 单位 | select | `℃` (the default) or `℉` |
|
|
13
|
+
|
|
14
|
+
They are kept in its data part `settings`, a `<script type="application/json">`, as example.html does: `{"city":"上海","unit":"℃"}` (on one line and compact, as the card's 设置… writes it back). The city is the one setting it cannot show anything without (`required` in its manifest): when the user did not say which, ask them, or take it from what the workspace says of where they live (写作偏好, the documents; a trip is not a home: ask when that is a guess), and tell them in the handoff which you did; never hand over a card with no city unsaid. `gallery page add <slug> gallery/weather --set city=上海` writes it with the add (`--set unit=℉` the unit); for a card already there, write the city in its settings part. `{}` (template.html, what a menu adds) is a card with no city yet, which asks for one (右上角手柄 › 设置…), and `gallery page check` notes it. The block reads them and writes nothing.
|
|
15
|
+
|
|
16
|
+
## Going online
|
|
17
|
+
|
|
18
|
+
Its needs name the two hosts it reaches, `net:api.open-meteo.com` (the weather) and `net:geocoding-api.open-meteo.com` (a city's name to its coordinates). Gallery fetches nothing for it until the user allows those: the card then shows 允许访问 api.open-meteo.com 等 2 个网站, a press of which opens Gallery's consent dialog, and the card fetches once the user says yes. Tell the user so when you put the card on a page ("点卡片上的「允许访问」"). They can take it back in 设置 › 组件列表 (允许联网). Never write the consent into gallery.json yourself: it is the user's to give.
|
|
19
|
+
|
|
20
|
+
## How to write it
|
|
21
|
+
|
|
22
|
+
Put it on a custom page as a card of its board, `<section class="gallery-card" data-card-id="…" data-x data-y data-w data-h>`, holding one instance, after `gallery block add weather`, the instance as template.html has it, then its settings as above (`gallery page add <slug> gallery/weather` does the card for you). Sizes: 4 × 2 (the default: now, today's range and the more line), 2 × 2 (the temperature and the sky alone) and 4 × 4 (and the next five days).
|
|
23
|
+
|
|
24
|
+
## How it looks
|
|
25
|
+
|
|
26
|
+
In Gallery 风格's look (the kit's card tokens, light and dark): a head of a small gray chip and a title, its end clear of the card's grip; one hero; the rest small and gray; the accent on the data and on today alone. Its head is a pin's chip, the city and when it was fetched (更新于 09:05; with no network, an answer kept from before says when, after a sign). The sky's picture, in its own colors (the sun's orange, a cloud's gray, the rain's blue), stands beside the temperature, the hero, and the sky's words over today's lowest and highest; at the bottom how it feels, the humidity and the wind, each after a small picture. A 2 × 2 card keeps the picture, the temperature and one line; a 4 × 4 card adds the next five days at the bottom, each its weekday, its sky, its lowest and highest at either end of a bar on the scale of all of them, cold blue to warm orange. Until the reader allows it online, or with no city, a city it cannot find or no network, the card says so under its head, and what to do faint under that.
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
{
|
|
2
|
+
"id": "gallery-soft/countdown",
|
|
3
|
+
"apiVersion": 1,
|
|
4
|
+
"version": "1.0.0",
|
|
5
|
+
"name": { "zh": "倒计时", "en": "Countdown" },
|
|
6
|
+
"description": { "zh": "离某一天还有几天,宽卡片旁边放一页小日历;到了那天说就是今天,过了说已过几天", "en": "How many days until a date, a page of a calendar beside it on a wide card: today on the day, and the days since after it" },
|
|
7
|
+
"words": "daojishi daoshu countdown days until 倒计时 倒数日 纪念日 日子",
|
|
8
|
+
"parts": {
|
|
9
|
+
"settings": { "at": ":scope > script", "edit": "data" }
|
|
10
|
+
},
|
|
11
|
+
"runtime": { "generated": [":scope > .gallery-soft-countdown-face"] },
|
|
12
|
+
"places": ["page"],
|
|
13
|
+
"card": { "sizes": [[2, 2], [4, 2]], "resize": true },
|
|
14
|
+
"settings": [
|
|
15
|
+
{ "key": "title", "label": { "zh": "名称", "en": "Name" }, "type": "text", "default": "" },
|
|
16
|
+
{ "key": "date", "label": { "zh": "日期", "en": "Date" }, "type": "date", "required": true }
|
|
17
|
+
]
|
|
18
|
+
}
|