@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.
Files changed (473) hide show
  1. package/THIRD-PARTY-NOTICES.md +2 -2
  2. package/browser/editor/components/align.mjs +58 -0
  3. package/browser/editor/components/code/index.mjs +1 -1
  4. package/browser/editor/components/columns/page.mjs +4 -4
  5. package/browser/editor/components/embed/index.mjs +2 -2
  6. package/browser/editor/components/embed/page.mjs +1 -1
  7. package/browser/editor/components/file/page.mjs +4 -4
  8. package/browser/editor/components/flowchart/add.mjs +7 -6
  9. package/browser/editor/components/flowchart/page.mjs +1 -1
  10. package/browser/editor/components/heading/index.mjs +7 -6
  11. package/browser/editor/components/icons.mjs +11 -0
  12. package/browser/editor/components/image/crop.mjs +6 -9
  13. package/browser/editor/components/image/index.mjs +2 -0
  14. package/browser/editor/components/image/page.mjs +172 -90
  15. package/browser/editor/components/installed/index.mjs +15 -4
  16. package/browser/editor/components/installed/page.mjs +103 -25
  17. package/browser/editor/components/installed/served.mjs +6 -5
  18. package/browser/editor/components/instances.mjs +18 -0
  19. package/browser/editor/components/list/page.mjs +3 -6
  20. package/browser/editor/components/media/icons.mjs +13 -8
  21. package/browser/editor/components/media/page.mjs +5 -3
  22. package/browser/editor/components/media/toolbar.mjs +12 -3
  23. package/browser/editor/components/paragraph/index.mjs +4 -3
  24. package/browser/editor/components/registry.mjs +30 -9
  25. package/browser/editor/components/table/index.mjs +61 -2
  26. package/browser/editor/components/table/page.mjs +1 -1
  27. package/browser/editor/page/after/index.mjs +288 -0
  28. package/browser/editor/page/align.mjs +91 -0
  29. package/browser/editor/page/annotate/card.mjs +3 -6
  30. package/browser/editor/page/autosave.mjs +310 -37
  31. package/browser/editor/page/beside.mjs +5 -6
  32. package/browser/editor/page/block-menu/index.mjs +6 -3
  33. package/browser/editor/page/blocks.mjs +3 -1
  34. package/browser/editor/page/board/client.mjs +57 -0
  35. package/browser/editor/page/board/hint.mjs +182 -0
  36. package/browser/editor/page/board/history.mjs +119 -0
  37. package/browser/editor/page/board/index.mjs +1059 -0
  38. package/browser/editor/page/board/motion.mjs +177 -0
  39. package/browser/editor/page/board/settings.mjs +210 -0
  40. package/browser/editor/page/caret.mjs +1 -1
  41. package/browser/editor/page/changes/bar.mjs +6 -14
  42. package/browser/editor/page/changes/index.mjs +2 -2
  43. package/browser/editor/page/clipboard/import/html.mjs +29 -6
  44. package/browser/editor/page/clipboard/import/inline.mjs +32 -0
  45. package/browser/editor/page/clipboard/import/markdown.mjs +58 -13
  46. package/browser/editor/page/clipboard/import/read.mjs +6 -1
  47. package/browser/editor/page/clipboard/import/to-blocks.mjs +44 -12
  48. package/browser/editor/page/clipboard/import/yuque.mjs +622 -0
  49. package/browser/editor/page/clipboard/index.mjs +133 -15
  50. package/browser/editor/page/clipboard/own/blocks.mjs +13 -14
  51. package/browser/editor/page/clipboard/own/chart-keys.mjs +41 -28
  52. package/browser/editor/page/clipboard/own/describe.mjs +6 -2
  53. package/browser/editor/page/clipboard/own/selection.mjs +1 -1
  54. package/browser/editor/page/columns/index.mjs +48 -46
  55. package/browser/editor/page/commit.mjs +80 -22
  56. package/browser/editor/page/conflicts.mjs +7 -7
  57. package/browser/editor/page/core.mjs +34 -16
  58. package/browser/editor/page/custom-page.mjs +110 -0
  59. package/browser/editor/page/editor.mjs +71 -17
  60. package/browser/editor/page/emoji-picker/styles.mjs +7 -12
  61. package/browser/editor/page/emoji-picker/upload.mjs +2 -2
  62. package/browser/editor/page/handle/index.mjs +5 -8
  63. package/browser/editor/page/history.mjs +41 -6
  64. package/browser/editor/page/insert/index.mjs +20 -22
  65. package/browser/editor/page/links/index.mjs +5 -3
  66. package/browser/editor/page/links/pages.mjs +27 -9
  67. package/browser/editor/page/look.mjs +54 -3
  68. package/browser/editor/page/margin.mjs +18 -3
  69. package/browser/editor/page/media-menu/index.mjs +6 -7
  70. package/browser/editor/page/menu.mjs +33 -14
  71. package/browser/editor/page/notices.mjs +2 -2
  72. package/browser/editor/page/page-objects.mjs +9 -2
  73. package/browser/editor/page/panel.mjs +4 -9
  74. package/browser/editor/page/present-links.mjs +15 -5
  75. package/browser/editor/page/present-shell.mjs +63 -0
  76. package/browser/editor/page/resize/index.mjs +42 -29
  77. package/browser/editor/page/selection/index.mjs +10 -2
  78. package/browser/editor/page/served.mjs +14 -0
  79. package/browser/editor/page/session.mjs +48 -4
  80. package/browser/editor/page/slash-menu/index.mjs +3 -3
  81. package/browser/editor/page/table/binding.mjs +87 -0
  82. package/browser/editor/page/table/cells.mjs +102 -46
  83. package/browser/editor/page/table/index.mjs +24 -9
  84. package/browser/editor/page/table/pictures.mjs +299 -0
  85. package/browser/editor/page/table/views.mjs +103 -0
  86. package/browser/editor/page/table/widths.mjs +82 -10
  87. package/browser/editor/page/text-select/index.mjs +26 -12
  88. package/browser/editor/page/todo-writes.mjs +75 -0
  89. package/browser/editor/page/typing/index.mjs +97 -15
  90. package/browser/editor/page/typing/leave.mjs +19 -5
  91. package/browser/editor/page/ui.mjs +13 -0
  92. package/browser/shared/block-packs.mjs +419 -0
  93. package/browser/shared/board-places.mjs +224 -0
  94. package/browser/shared/card-size.mjs +59 -0
  95. package/browser/shared/colors.mjs +3 -2
  96. package/browser/shared/component-catalog.mjs +330 -46
  97. package/browser/shared/component-source.mjs +39 -0
  98. package/browser/shared/components/heading.mjs +2 -1
  99. package/browser/shared/components/index.mjs +12 -3
  100. package/browser/shared/components/installed.mjs +35 -3
  101. package/browser/shared/components/page.mjs +20 -8
  102. package/browser/shared/components/paragraph.mjs +8 -1
  103. package/browser/shared/components/state.mjs +5 -1
  104. package/browser/shared/components/table.mjs +1 -0
  105. package/browser/shared/document-look.mjs +10 -5
  106. package/browser/shared/drafts.mjs +432 -0
  107. package/browser/shared/emoji/line-icons.mjs +37 -0
  108. package/browser/shared/extension-sidebar.mjs +126 -0
  109. package/browser/shared/extensions.mjs +79 -0
  110. package/browser/shared/file-table.mjs +101 -0
  111. package/browser/shared/http.mjs +9 -0
  112. package/browser/shared/i18n/en.mjs +330 -27
  113. package/browser/shared/json-layout.mjs +47 -0
  114. package/browser/shared/net-cache.mjs +133 -0
  115. package/browser/shared/net-keys.mjs +32 -0
  116. package/browser/shared/net-policy.mjs +177 -0
  117. package/browser/shared/outline-shape.mjs +128 -0
  118. package/browser/shared/outline.mjs +359 -67
  119. package/browser/shared/pack-manifest.mjs +88 -0
  120. package/browser/shared/page-address.mjs +6 -3
  121. package/browser/shared/page-cards.mjs +308 -0
  122. package/browser/shared/page-links.mjs +69 -6
  123. package/browser/shared/pages.mjs +500 -0
  124. package/browser/shared/paths.mjs +6 -0
  125. package/browser/shared/pinyin.mjs +92 -0
  126. package/browser/shared/present-step.mjs +17 -0
  127. package/browser/shared/preview-server.mjs +3 -7
  128. package/browser/shared/session.mjs +8 -1
  129. package/browser/shared/shipped-blocks.mjs +299 -0
  130. package/browser/shared/sidebar-head.mjs +70 -0
  131. package/browser/shared/table-chart.mjs +33 -1
  132. package/browser/shared/todos.mjs +83 -0
  133. package/browser/shared/user-directory.mjs +24 -0
  134. package/browser/shared/versions.mjs +14 -0
  135. package/browser/shared/web-links.mjs +139 -0
  136. package/browser/shared/workspace-columns.mjs +120 -0
  137. package/browser/shared/workspace-name.mjs +154 -0
  138. package/browser/shared/workspace-query.mjs +125 -0
  139. package/browser/shared/workspace-registry.mjs +272 -0
  140. package/browser/shared/workspace.mjs +171 -20
  141. package/dist/chunk-2OHANJ6Q.mjs +2 -0
  142. package/dist/chunk-3MBRL2PM.mjs +16 -0
  143. package/dist/chunk-4OKWZY5E.mjs +2 -0
  144. package/dist/chunk-4OZWXZE5.mjs +5 -0
  145. package/dist/chunk-5K44HLTZ.mjs +2 -0
  146. package/dist/{chunk-5ZKJ3H4P.mjs → chunk-5XA2ZBAE.mjs} +3 -3
  147. package/dist/{chunk-4FS7Z7WR.mjs → chunk-67N2QJYT.mjs} +1 -1
  148. package/dist/chunk-6KBYRA2C.mjs +2 -0
  149. package/dist/chunk-6N3PX4XX.mjs +8 -0
  150. package/dist/{chunk-V5JTW2LH.mjs → chunk-6QBHU4DF.mjs} +1 -1
  151. package/dist/chunk-7JDX4E65.mjs +13 -0
  152. package/dist/chunk-7M2BQQGZ.mjs +2 -0
  153. package/dist/chunk-7OG26PGF.mjs +2 -0
  154. package/dist/chunk-AHN3NFKJ.mjs +3 -0
  155. package/dist/chunk-ALZ6ZENZ.mjs +3 -0
  156. package/dist/chunk-AR5D57ZD.mjs +170 -0
  157. package/dist/{chunk-W3BGBJQW.mjs → chunk-BFJGHSQN.mjs} +1 -1
  158. package/dist/{chunk-LS4F7JUM.mjs → chunk-BZ5RAF7L.mjs} +1 -1
  159. package/dist/chunk-CMA72MAG.mjs +2 -0
  160. package/dist/{chunk-LCTHTZIL.mjs → chunk-DAZL73VK.mjs} +91 -91
  161. package/dist/{chunk-Y6RLRPG3.mjs → chunk-DJISHPUL.mjs} +1 -1
  162. package/dist/chunk-DR73Y2UJ.mjs +3 -0
  163. package/dist/{chunk-FDLXYYG4.mjs → chunk-EAIFITAV.mjs} +1 -1
  164. package/dist/{chunk-TMYZB6AV.mjs → chunk-EKNHM3P4.mjs} +1 -1
  165. package/dist/chunk-EP25HDAJ.mjs +2 -0
  166. package/dist/{chunk-GB5SOYQJ.mjs → chunk-ERLAIBOA.mjs} +2 -2
  167. package/dist/chunk-EURLTOTZ.mjs +4 -0
  168. package/dist/chunk-F4ZA6JRZ.mjs +3 -0
  169. package/dist/chunk-F6HVDZR4.mjs +2 -0
  170. package/dist/chunk-FDMAXMQA.mjs +2 -0
  171. package/dist/chunk-FETSREUN.mjs +5 -0
  172. package/dist/chunk-GHOYKMQ3.mjs +4 -0
  173. package/dist/{chunk-2B5E4CDJ.mjs → chunk-GPIWQ4X4.mjs} +1 -1
  174. package/dist/chunk-HDWTZ763.mjs +12 -0
  175. package/dist/chunk-HPOI4ZX7.mjs +6 -0
  176. package/dist/{chunk-BGGDRNYQ.mjs → chunk-HXG7EOPJ.mjs} +1 -1
  177. package/dist/chunk-IA4PSIMD.mjs +2 -0
  178. package/dist/{chunk-E7LWZRXY.mjs → chunk-ITOH5EGO.mjs} +1 -1
  179. package/dist/chunk-IV64FFI4.mjs +2 -0
  180. package/dist/chunk-J43Z6LSS.mjs +2 -0
  181. package/dist/chunk-J5PUIV3Y.mjs +4 -0
  182. package/dist/chunk-JA7G53PC.mjs +2 -0
  183. package/dist/chunk-JEUK3ZO7.mjs +2 -0
  184. package/dist/chunk-JLTZF4LA.mjs +2 -0
  185. package/dist/chunk-JZT7I2OJ.mjs +2 -0
  186. package/dist/chunk-K5XATEOO.mjs +2 -0
  187. package/dist/chunk-L2SUIS5S.mjs +2 -0
  188. package/dist/chunk-L7UP52JO.mjs +2 -0
  189. package/dist/chunk-LM4XFQHZ.mjs +2 -0
  190. package/dist/chunk-MN7BZL4R.mjs +2 -0
  191. package/dist/chunk-MTYYHM2G.mjs +15 -0
  192. package/dist/chunk-MXUBKDRO.mjs +15 -0
  193. package/dist/chunk-NAMN3RAF.mjs +2 -0
  194. package/dist/{chunk-SYGN7GLU.mjs → chunk-OEXWRJME.mjs} +1 -1
  195. package/dist/chunk-OFHXGWOX.mjs +2 -0
  196. package/dist/chunk-ORID3AE7.mjs +166 -0
  197. package/dist/chunk-PAREWQGB.mjs +4 -0
  198. package/dist/chunk-PGDE24N5.mjs +2 -0
  199. package/dist/chunk-POTA2FV4.mjs +2 -0
  200. package/dist/chunk-PUOQ65NC.mjs +2 -0
  201. package/dist/chunk-Q4UEPUWF.mjs +2 -0
  202. package/dist/chunk-QE5RG76S.mjs +549 -0
  203. package/dist/chunk-R2ZDLJYT.mjs +10 -0
  204. package/dist/{chunk-7DTINW6U.mjs → chunk-SQ6Y2ZMA.mjs} +2 -2
  205. package/dist/chunk-SWUTTZCN.mjs +2 -0
  206. package/dist/chunk-TANZRINB.mjs +2 -0
  207. package/dist/chunk-TR7TWGHB.mjs +2 -0
  208. package/dist/chunk-U5XL7D6A.mjs +3 -0
  209. package/dist/{chunk-XNROSH2T.mjs → chunk-U7NZI6N4.mjs} +2 -2
  210. package/dist/chunk-UGWMMEJ5.mjs +15 -0
  211. package/dist/chunk-UJQJKNGK.mjs +2 -0
  212. package/dist/chunk-UYVCQK3H.mjs +22 -0
  213. package/dist/chunk-VFX2KNHP.mjs +4 -0
  214. package/dist/chunk-VS7JIGJW.mjs +24 -0
  215. package/dist/chunk-W7665ZEC.mjs +6 -0
  216. package/dist/chunk-WQDQWCX5.mjs +2 -0
  217. package/dist/chunk-YI43RG4P.mjs +2 -0
  218. package/dist/chunk-YLPSMDIS.mjs +5 -0
  219. package/dist/chunk-YNAWBAYN.mjs +3 -0
  220. package/dist/chunk-YROX2O22.mjs +2 -0
  221. package/dist/chunk-ZDLPUOAG.mjs +6 -0
  222. package/dist/{chunk-IVDLMMBD.mjs → chunk-ZHEHPMBK.mjs} +1 -1
  223. package/dist/chunk-ZQS6H473.mjs +16 -0
  224. package/dist/chunk-ZTHICSSF.mjs +2 -0
  225. package/dist/chunk-ZWWC4KLF.mjs +20 -0
  226. package/dist/cli.mjs +1 -1
  227. package/dist/server.mjs +1 -1
  228. package/dist/{chunk-U6KNPJPR.mjs → update-fetch.mjs} +1 -1
  229. package/dist/worker.mjs +1 -1
  230. package/kit/board.css +95 -0
  231. package/kit/board.js +250 -0
  232. package/kit/charts.js +5 -71
  233. package/kit/code.js +17 -17
  234. package/kit/report.css +335 -18
  235. package/kit/runtime.js +1638 -125
  236. package/kit/state.js +10 -1
  237. package/kit/tables.js +130 -43
  238. package/kit/ui.js +79 -35
  239. package/package.json +2 -1
  240. package/packs/gallery/card/component.json +14 -0
  241. package/packs/gallery/card/example.html +10 -0
  242. package/packs/gallery/card/preview.svg +1 -0
  243. package/packs/gallery/card/style.css +6 -0
  244. package/packs/gallery/card/template.html +6 -0
  245. package/packs/gallery/card/writing.md +14 -0
  246. package/packs/gallery/chart-card/component.json +15 -0
  247. package/packs/gallery/chart-card/example.html +14 -0
  248. package/packs/gallery/chart-card/kit.js +130 -0
  249. package/packs/gallery/chart-card/preview.svg +1 -0
  250. package/packs/gallery/chart-card/style.css +42 -0
  251. package/packs/gallery/chart-card/template.html +13 -0
  252. package/packs/gallery/chart-card/writing.md +20 -0
  253. package/packs/gallery/chart-view/component.json +20 -0
  254. package/packs/gallery/chart-view/example.html +13 -0
  255. package/packs/gallery/chart-view/kit.js +355 -0
  256. package/packs/gallery/chart-view/preview.svg +1 -0
  257. package/packs/gallery/chart-view/style.css +94 -0
  258. package/packs/gallery/chart-view/template.html +3 -0
  259. package/packs/gallery/chart-view/writing.md +22 -0
  260. package/packs/gallery/countdown/component.json +18 -0
  261. package/packs/gallery/countdown/example.html +3 -0
  262. package/packs/gallery/countdown/kit.js +216 -0
  263. package/packs/gallery/countdown/preview.svg +1 -0
  264. package/packs/gallery/countdown/style.css +118 -0
  265. package/packs/gallery/countdown/template.html +3 -0
  266. package/packs/gallery/countdown/writing.md +22 -0
  267. package/packs/gallery/habit/component.json +14 -0
  268. package/packs/gallery/habit/example.html +3 -0
  269. package/packs/gallery/habit/kit.js +334 -0
  270. package/packs/gallery/habit/preview.svg +1 -0
  271. package/packs/gallery/habit/style.css +174 -0
  272. package/packs/gallery/habit/template.html +3 -0
  273. package/packs/gallery/habit/writing.md +21 -0
  274. package/packs/gallery/heatmap/component.json +18 -0
  275. package/packs/gallery/heatmap/example.html +3 -0
  276. package/packs/gallery/heatmap/kit.js +513 -0
  277. package/packs/gallery/heatmap/preview.svg +1 -0
  278. package/packs/gallery/heatmap/style.css +189 -0
  279. package/packs/gallery/heatmap/template.html +3 -0
  280. package/packs/gallery/heatmap/writing.md +21 -0
  281. package/packs/gallery/kanban/component.json +18 -0
  282. package/packs/gallery/kanban/example.html +12 -0
  283. package/packs/gallery/kanban/kit.js +540 -0
  284. package/packs/gallery/kanban/preview.svg +1 -0
  285. package/packs/gallery/kanban/style.css +212 -0
  286. package/packs/gallery/kanban/template.html +3 -0
  287. package/packs/gallery/kanban/writing.md +20 -0
  288. package/packs/gallery/metric/component.json +22 -0
  289. package/packs/gallery/metric/example.html +15 -0
  290. package/packs/gallery/metric/kit.js +248 -0
  291. package/packs/gallery/metric/preview.svg +1 -0
  292. package/packs/gallery/metric/style.css +92 -0
  293. package/packs/gallery/metric/template.html +3 -0
  294. package/packs/gallery/metric/writing.md +23 -0
  295. package/packs/gallery/note/component.json +14 -0
  296. package/packs/gallery/note/example.html +3 -0
  297. package/packs/gallery/note/kit.js +129 -0
  298. package/packs/gallery/note/preview.svg +1 -0
  299. package/packs/gallery/note/style.css +97 -0
  300. package/packs/gallery/note/template.html +3 -0
  301. package/packs/gallery/note/writing.md +18 -0
  302. package/packs/gallery/pack.json +8 -0
  303. package/packs/gallery/recent/component.json +13 -0
  304. package/packs/gallery/recent/example.html +1 -0
  305. package/packs/gallery/recent/kit.js +293 -0
  306. package/packs/gallery/recent/preview.svg +1 -0
  307. package/packs/gallery/recent/style.css +85 -0
  308. package/packs/gallery/recent/template.html +1 -0
  309. package/packs/gallery/recent/writing.md +15 -0
  310. package/packs/gallery/static/component.json +13 -0
  311. package/packs/gallery/static/example.html +11 -0
  312. package/packs/gallery/static/preview.svg +1 -0
  313. package/packs/gallery/static/style.css +171 -0
  314. package/packs/gallery/static/template.html +1 -0
  315. package/packs/gallery/static/writing.md +18 -0
  316. package/packs/gallery/stats/component.json +13 -0
  317. package/packs/gallery/stats/example.html +1 -0
  318. package/packs/gallery/stats/kit.js +347 -0
  319. package/packs/gallery/stats/preview.svg +1 -0
  320. package/packs/gallery/stats/style.css +73 -0
  321. package/packs/gallery/stats/template.html +1 -0
  322. package/packs/gallery/stats/writing.md +11 -0
  323. package/packs/gallery/today/component.json +12 -0
  324. package/packs/gallery/today/example.html +1 -0
  325. package/packs/gallery/today/kit.js +220 -0
  326. package/packs/gallery/today/preview.svg +1 -0
  327. package/packs/gallery/today/style.css +149 -0
  328. package/packs/gallery/today/template.html +1 -0
  329. package/packs/gallery/today/writing.md +14 -0
  330. package/packs/gallery/todos/component.json +19 -0
  331. package/packs/gallery/todos/example.html +3 -0
  332. package/packs/gallery/todos/kit.js +489 -0
  333. package/packs/gallery/todos/preview.svg +1 -0
  334. package/packs/gallery/todos/style.css +214 -0
  335. package/packs/gallery/todos/template.html +3 -0
  336. package/packs/gallery/todos/writing.md +30 -0
  337. package/packs/gallery/weather/component.json +19 -0
  338. package/packs/gallery/weather/example.html +3 -0
  339. package/packs/gallery/weather/kit.js +387 -0
  340. package/packs/gallery/weather/preview.svg +1 -0
  341. package/packs/gallery/weather/style.css +140 -0
  342. package/packs/gallery/weather/template.html +3 -0
  343. package/packs/gallery/weather/writing.md +26 -0
  344. package/packs/gallery-soft/countdown/component.json +18 -0
  345. package/packs/gallery-soft/countdown/example.html +3 -0
  346. package/packs/gallery-soft/countdown/kit.js +206 -0
  347. package/packs/gallery-soft/countdown/preview.svg +1 -0
  348. package/packs/gallery-soft/countdown/style.css +211 -0
  349. package/packs/gallery-soft/countdown/template.html +3 -0
  350. package/packs/gallery-soft/countdown/writing.md +24 -0
  351. package/packs/gallery-soft/habit/component.json +14 -0
  352. package/packs/gallery-soft/habit/example.html +3 -0
  353. package/packs/gallery-soft/habit/kit.js +366 -0
  354. package/packs/gallery-soft/habit/preview.svg +1 -0
  355. package/packs/gallery-soft/habit/style.css +251 -0
  356. package/packs/gallery-soft/habit/template.html +3 -0
  357. package/packs/gallery-soft/habit/writing.md +23 -0
  358. package/packs/gallery-soft/heatmap/component.json +18 -0
  359. package/packs/gallery-soft/heatmap/example.html +3 -0
  360. package/packs/gallery-soft/heatmap/kit.js +498 -0
  361. package/packs/gallery-soft/heatmap/preview.svg +1 -0
  362. package/packs/gallery-soft/heatmap/style.css +181 -0
  363. package/packs/gallery-soft/heatmap/template.html +3 -0
  364. package/packs/gallery-soft/heatmap/writing.md +23 -0
  365. package/packs/gallery-soft/note/component.json +14 -0
  366. package/packs/gallery-soft/note/example.html +3 -0
  367. package/packs/gallery-soft/note/kit.js +162 -0
  368. package/packs/gallery-soft/note/preview.svg +1 -0
  369. package/packs/gallery-soft/note/style.css +148 -0
  370. package/packs/gallery-soft/note/template.html +3 -0
  371. package/packs/gallery-soft/note/writing.md +20 -0
  372. package/packs/gallery-soft/pack.json +8 -0
  373. package/packs/gallery-soft/recent/component.json +13 -0
  374. package/packs/gallery-soft/recent/example.html +1 -0
  375. package/packs/gallery-soft/recent/kit.js +335 -0
  376. package/packs/gallery-soft/recent/preview.svg +1 -0
  377. package/packs/gallery-soft/recent/style.css +160 -0
  378. package/packs/gallery-soft/recent/template.html +1 -0
  379. package/packs/gallery-soft/recent/writing.md +17 -0
  380. package/packs/gallery-soft/static/component.json +13 -0
  381. package/packs/gallery-soft/static/example.html +12 -0
  382. package/packs/gallery-soft/static/preview.svg +1 -0
  383. package/packs/gallery-soft/static/style.css +186 -0
  384. package/packs/gallery-soft/static/template.html +1 -0
  385. package/packs/gallery-soft/static/writing.md +20 -0
  386. package/packs/gallery-soft/stats/component.json +13 -0
  387. package/packs/gallery-soft/stats/example.html +1 -0
  388. package/packs/gallery-soft/stats/kit.js +341 -0
  389. package/packs/gallery-soft/stats/preview.svg +1 -0
  390. package/packs/gallery-soft/stats/style.css +119 -0
  391. package/packs/gallery-soft/stats/template.html +1 -0
  392. package/packs/gallery-soft/stats/writing.md +13 -0
  393. package/packs/gallery-soft/today/component.json +12 -0
  394. package/packs/gallery-soft/today/example.html +1 -0
  395. package/packs/gallery-soft/today/kit.js +222 -0
  396. package/packs/gallery-soft/today/preview.svg +1 -0
  397. package/packs/gallery-soft/today/style.css +178 -0
  398. package/packs/gallery-soft/today/template.html +1 -0
  399. package/packs/gallery-soft/today/writing.md +16 -0
  400. package/packs/gallery-soft/todos/component.json +19 -0
  401. package/packs/gallery-soft/todos/example.html +3 -0
  402. package/packs/gallery-soft/todos/kit.js +527 -0
  403. package/packs/gallery-soft/todos/preview.svg +1 -0
  404. package/packs/gallery-soft/todos/style.css +212 -0
  405. package/packs/gallery-soft/todos/template.html +3 -0
  406. package/packs/gallery-soft/todos/writing.md +32 -0
  407. package/packs/gallery-soft/weather/component.json +19 -0
  408. package/packs/gallery-soft/weather/example.html +3 -0
  409. package/packs/gallery-soft/weather/kit.js +411 -0
  410. package/packs/gallery-soft/weather/preview.svg +1 -0
  411. package/packs/gallery-soft/weather/style.css +185 -0
  412. package/packs/gallery-soft/weather/template.html +3 -0
  413. package/packs/gallery-soft/weather/writing.md +28 -0
  414. package/release.json +12 -10
  415. package/sdk/doc-kit.d.ts +396 -5
  416. package/sdk/doc-state.d.ts +2 -0
  417. package/skill/SKILL.md +56 -23
  418. package/skill/references/block-script.md +140 -0
  419. package/skill/references/building-blocks.md +257 -0
  420. package/skill/references/extensions.md +59 -0
  421. package/skill/references/pages-and-data.md +225 -0
  422. package/skill/references/writing-html.md +8 -4
  423. package/skill/sdk/doc-kit.d.ts +396 -5
  424. package/skill/sdk/doc-state.d.ts +2 -0
  425. package/web/assets/index-BM_K-Auu.css +1 -0
  426. package/web/assets/index-DRslOBiv.js +15 -0
  427. package/web/index.html +2 -2
  428. package/dist/chunk-3HIRPVLU.mjs +0 -2
  429. package/dist/chunk-5MHMDLZD.mjs +0 -4
  430. package/dist/chunk-64K7IPLO.mjs +0 -255
  431. package/dist/chunk-6QXGZM36.mjs +0 -8
  432. package/dist/chunk-6RGJOMJP.mjs +0 -16
  433. package/dist/chunk-AJ73XJF3.mjs +0 -2
  434. package/dist/chunk-AUZGSZJH.mjs +0 -13
  435. package/dist/chunk-BFE45AKL.mjs +0 -2
  436. package/dist/chunk-BXO2ZY5P.mjs +0 -2
  437. package/dist/chunk-CEH4MRCC.mjs +0 -2
  438. package/dist/chunk-CY2FNNAB.mjs +0 -16
  439. package/dist/chunk-DFUDV4LX.mjs +0 -2
  440. package/dist/chunk-DKXG4XDG.mjs +0 -2
  441. package/dist/chunk-EZQ34M3F.mjs +0 -124
  442. package/dist/chunk-EZY3WC6Z.mjs +0 -15
  443. package/dist/chunk-FUKQNOQS.mjs +0 -9
  444. package/dist/chunk-JPOSLGOC.mjs +0 -6
  445. package/dist/chunk-JVHHHGEA.mjs +0 -3
  446. package/dist/chunk-L3QKH4OK.mjs +0 -26
  447. package/dist/chunk-LAE5NQ4B.mjs +0 -2
  448. package/dist/chunk-LEF6DRCK.mjs +0 -59
  449. package/dist/chunk-NO5NJCHO.mjs +0 -2
  450. package/dist/chunk-NQPVAU63.mjs +0 -2
  451. package/dist/chunk-NSKUTQ5J.mjs +0 -5
  452. package/dist/chunk-O35FIXRB.mjs +0 -2
  453. package/dist/chunk-P2CAZPDP.mjs +0 -3
  454. package/dist/chunk-PL6GHLGD.mjs +0 -15
  455. package/dist/chunk-QJIR2BLP.mjs +0 -6
  456. package/dist/chunk-QUPLVPB2.mjs +0 -7
  457. package/dist/chunk-R7BNENLY.mjs +0 -4
  458. package/dist/chunk-S6O4UHLC.mjs +0 -2
  459. package/dist/chunk-SGJWQKEI.mjs +0 -2
  460. package/dist/chunk-TX6JH7TR.mjs +0 -2
  461. package/dist/chunk-TYK6VNAB.mjs +0 -10
  462. package/dist/chunk-UALRNVSE.mjs +0 -4
  463. package/dist/chunk-V3HXVQEM.mjs +0 -2
  464. package/dist/chunk-V5VXUJKG.mjs +0 -2
  465. package/dist/chunk-VBXMADMP.mjs +0 -2
  466. package/dist/chunk-VNV55RUA.mjs +0 -2
  467. package/dist/chunk-VPD2PS35.mjs +0 -2
  468. package/dist/chunk-W4VKN3GF.mjs +0 -7
  469. package/dist/chunk-W5BXXPDJ.mjs +0 -3
  470. package/dist/chunk-XUNHRCOG.mjs +0 -6
  471. package/skill/references/building-components.md +0 -367
  472. package/web/assets/index-Bh74DfsV.css +0 -1
  473. package/web/assets/index-UW0RyFFt.js +0 -13
@@ -0,0 +1,411 @@
1
+ // gallery-soft/weather (天气, 柔光风格): Gallery 风格's gallery/weather in the soft look, the same logic. A
2
+ // city's weather now and for the days ahead, from Open-Meteo (open-meteo.com, no key), for a custom page. Its
3
+ // settings, `city` (a name as the reader writes it: 上海, Berlin) and `unit` (℃ or ℉), are the card's form (the
4
+ // grip at its top right › 设置…), kept in the data part `settings`, which the board writes and this block only
5
+ // reads. The city is looked up by name (geocoding-api.open-meteo.com: its first match, its coordinates), its
6
+ // weather fetched for them (api.open-meteo.com: now, and each day's highest, lowest and sky for five days),
7
+ // both through context.fetch, the server fetching for it: its needs name the two hosts, and nothing is
8
+ // fetched until the reader allows them (the kit then shows 允许访问 over the card and starts the block again
9
+ // once the reader says yes). Fetched again as its settings change (`source`) and every 30 minutes; the
10
+ // server keeps an answer a minute and gives what it kept when the network is not there, which the card says
11
+ // by its time (更新于 14:05). What it says while there is nothing to
12
+ // show (no city yet, one not found, waiting for the reader's consent, the network not there, this computer's
13
+ // network setup sending Open-Meteo's names to an address of its own or of a private network, which the
14
+ // server refuses: code "private") is the cards' empty face, a soft disc with a picture over a line and what
15
+ // to do. In the page's language.
16
+ //
17
+ // Its face, laid out by its card's size (`context.size`, read again on `layout`; data-w, data-h, data-pad): a
18
+ // head of a pin's chip and the city, when at its end; the sky's picture (the sun, a cloud, rain in their own
19
+ // colors) and the temperature large side by side, the sky's words and today's lowest and highest beside them;
20
+ // how it feels, the humidity and the wind under them; on a 4 × 4 card the five days ahead, each its lowest and
21
+ // highest at either end of a bar drawn against the lowest and highest of all five, today's now marked on it;
22
+ // a 2 × 2 card the temperature and the picture, the sky's words and the range under them.
23
+
24
+ const WORDS = {
25
+ zh: {
26
+ title: "天气",
27
+ pick: "写上一个城市",
28
+ where: "右上角手柄 › 设置…",
29
+ whereShort: "手柄 › 设置…",
30
+ loading: "正在取天气…",
31
+ unknown: (/** @type {string} */ city) => `找不到「${city}」:换一个写法试试`,
32
+ unknownLine: (/** @type {string} */ city) => `找不到「${city}」`,
33
+ unknownHow: "换个写法试试,比如「上海」「Berlin」",
34
+ unknownHowShort: "换个写法试试",
35
+ consent: "允许联网之后显示天气",
36
+ consentShort: "允许联网后显示",
37
+ offline: "现在连不上网,取不到天气",
38
+ offlineShort: "现在连不上网",
39
+ offlineHow: "连上之后会自己再取",
40
+ private: "网络设置把天气服务指向了本地地址,取不到天气",
41
+ privateLine: "网络设置把天气服务指向了本地地址",
42
+ privateHow: "取不到天气",
43
+ failed: "没能取到天气",
44
+ at: (/** @type {string} */ time) => `更新于 ${time}`,
45
+ feels: (/** @type {string} */ value) => `体感 ${value}`,
46
+ humidity: (/** @type {number} */ value) => `湿度 ${value}%`,
47
+ wind: (/** @type {number} */ value) => `风 ${value} km/h`,
48
+ highLow: (/** @type {string} */ high, /** @type {string} */ low) => `最高 ${high} · 最低 ${low}`,
49
+ today: "今天",
50
+ weekdays: ["周日", "周一", "周二", "周三", "周四", "周五", "周六"],
51
+ sky: {
52
+ clear: "晴", mostly: "大部晴朗", partly: "多云", overcast: "阴", fog: "雾", drizzle: "毛毛雨", "freezing-drizzle": "冻毛毛雨",
53
+ rain: "雨", "light-rain": "小雨", "heavy-rain": "大雨", "freezing-rain": "冻雨", snow: "雪", "light-snow": "小雪", "heavy-snow": "大雪",
54
+ grains: "雪粒", showers: "阵雨", "snow-showers": "阵雪", thunder: "雷阵雨", hail: "雷阵雨伴冰雹", unknown: "天气未知",
55
+ },
56
+ },
57
+ en: {
58
+ title: "Weather",
59
+ pick: "Name a city",
60
+ where: "The grip at the top right › Settings…",
61
+ whereShort: "Grip › Settings…",
62
+ loading: "Fetching the weather…",
63
+ unknown: (/** @type {string} */ city) => `No place called “${city}”: try another spelling`,
64
+ unknownLine: (/** @type {string} */ city) => `No place called “${city}”`,
65
+ unknownHow: "Try another spelling, as “Shanghai” or “Berlin”",
66
+ unknownHowShort: "Try another spelling",
67
+ consent: "Shown once it may go online",
68
+ consentShort: "Shown once online",
69
+ offline: "Offline: no weather now",
70
+ offlineShort: "Offline",
71
+ offlineHow: "It fetches again once online",
72
+ private: "The network setup sends the weather service to a local address",
73
+ privateLine: "The network setup sends the weather service to a local address",
74
+ privateHow: "No weather from there",
75
+ failed: "The weather could not be fetched",
76
+ at: (/** @type {string} */ time) => `Updated ${time}`,
77
+ feels: (/** @type {string} */ value) => `Feels ${value}`,
78
+ humidity: (/** @type {number} */ value) => `Humidity ${value}%`,
79
+ wind: (/** @type {number} */ value) => `Wind ${value} km/h`,
80
+ highLow: (/** @type {string} */ high, /** @type {string} */ low) => `High ${high} · Low ${low}`,
81
+ today: "Today",
82
+ weekdays: ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"],
83
+ sky: {
84
+ clear: "Clear", mostly: "Mostly clear", partly: "Partly cloudy", overcast: "Overcast", fog: "Fog", drizzle: "Drizzle", "freezing-drizzle": "Freezing drizzle",
85
+ rain: "Rain", "light-rain": "Light rain", "heavy-rain": "Heavy rain", "freezing-rain": "Freezing rain", snow: "Snow", "light-snow": "Light snow", "heavy-snow": "Heavy snow",
86
+ grains: "Snow grains", showers: "Showers", "snow-showers": "Snow showers", thunder: "Thunderstorm", hail: "Thunderstorm with hail", unknown: "Unknown",
87
+ },
88
+ },
89
+ };
90
+
91
+ /** The language the page speaks: the UI's where Gallery says it (data-ge-language), else its lang's. */
92
+ function languageOf(/** @type {HTMLElement} */ root) {
93
+ const ui = root.getAttribute("data-ge-language");
94
+ return (ui !== null ? ui === "en" : /^en(?:-|$)/i.test(root.lang)) ? "en" : "zh";
95
+ }
96
+
97
+ /**
98
+ * The sky a WMO weather code says (what Open-Meteo answers with), as { words (its key in WORDS' sky),
99
+ * picture (which of the pictures draws it) }; `day` false draws a clear or mostly clear sky with the moon.
100
+ * @param {unknown} code
101
+ * @param {boolean} day
102
+ */
103
+ function skyOf(code, day = true) {
104
+ const sun = day ? "sun" : "moon";
105
+ /** @type {Record<number, [string, string]>} */
106
+ const skies = {
107
+ 0: ["clear", sun], 1: ["mostly", sun], 2: ["partly", day ? "partly" : "partly-night"], 3: ["overcast", "cloud"],
108
+ 45: ["fog", "fog"], 48: ["fog", "fog"], 51: ["drizzle", "rain"], 53: ["drizzle", "rain"], 55: ["drizzle", "rain"], 56: ["freezing-drizzle", "rain"], 57: ["freezing-drizzle", "rain"],
109
+ 61: ["light-rain", "rain"], 63: ["rain", "rain"], 65: ["heavy-rain", "rain"], 66: ["freezing-rain", "rain"], 67: ["freezing-rain", "rain"],
110
+ 71: ["light-snow", "snow"], 73: ["snow", "snow"], 75: ["heavy-snow", "snow"], 77: ["grains", "snow"],
111
+ 80: ["showers", "rain"], 81: ["showers", "rain"], 82: ["showers", "rain"], 85: ["snow-showers", "snow"], 86: ["snow-showers", "snow"],
112
+ 95: ["thunder", "thunder"], 96: ["hail", "thunder"], 99: ["hail", "thunder"],
113
+ };
114
+ const [words, picture] = typeof code === "number" && skies[code] ? skies[code] : ["unknown", "cloud"];
115
+ return { words, picture };
116
+ }
117
+
118
+ /**
119
+ * The address a city's name is looked up at (Open-Meteo's geocoding: its first match, in `language`).
120
+ * @param {string} city
121
+ * @param {"zh" | "en"} language
122
+ */
123
+ const searchAddress = (city, language) => `https://geocoding-api.open-meteo.com/v1/search?name=${encodeURIComponent(city)}&count=1&language=${language}&format=json`;
124
+
125
+ /**
126
+ * The address of the weather at a place (its coordinates, to two decimals: one address for one place,
127
+ * which the server keeps), in `unit` (℃ or ℉): now, and five days, by the place's own clock.
128
+ * @param {{ latitude: number, longitude: number }} place
129
+ * @param {string} unit
130
+ */
131
+ const forecastAddress = (place, unit) => `https://api.open-meteo.com/v1/forecast?latitude=${place.latitude.toFixed(2)}&longitude=${place.longitude.toFixed(2)}`
132
+ + "&current=temperature_2m,apparent_temperature,relative_humidity_2m,wind_speed_10m,weather_code,is_day"
133
+ + `&daily=weather_code,temperature_2m_max,temperature_2m_min&timezone=auto&forecast_days=5${unit === "℉" ? "&temperature_unit=fahrenheit" : ""}`;
134
+
135
+ /**
136
+ * The first place a lookup's answer gives ({ name, latitude, longitude, region }), or null for none.
137
+ * @param {any} answer
138
+ */
139
+ function placeOf(answer) {
140
+ const found = Array.isArray(answer?.results) ? answer.results[0] : null;
141
+ if (!found || typeof found.latitude !== "number" || typeof found.longitude !== "number") return null;
142
+ return { name: String(found.name ?? ""), latitude: found.latitude, longitude: found.longitude, region: String(found.admin1 ?? found.country ?? "") };
143
+ }
144
+
145
+ /** A temperature as the card writes it: whole degrees, a degree sign, a minus that is one. @param {unknown} value */
146
+ const degrees = (value) => (typeof value === "number" && Number.isFinite(value) ? `${Math.round(value)}°`.replace(/^-/, "−") : "–");
147
+
148
+ /**
149
+ * What the card says, in `language`, of `state`: { kind: "pick" } (no city), { kind: "loading", city },
150
+ * { kind: "unknown", city } (no such place), { kind: "consent", city }, { kind: "offline", city },
151
+ * { kind: "private", city } (the server refused the address this computer's resolver gave: one of this
152
+ * computer or of a private network, its network setup's doing), { kind: "failed", city }, or
153
+ * { kind: "weather", place, forecast (Open-Meteo's answer), at (when it was fetched, ISO) }. Its head (the city, and when), and either a note (with its line and what to do,
154
+ * long and short, for the empty face) or the weather: the sky's picture and words, the temperature, today's
155
+ * range (highest / lowest), its lowest and highest apart, how it feels, the humidity, the wind, the more
156
+ * line's pieces, the temperature now as a number, and the days ahead.
157
+ * @param {any} state
158
+ * @param {"zh" | "en"} language
159
+ */
160
+ function faceOf(state, language) {
161
+ const words = WORDS[language];
162
+ const head = { city: state.city || state.place?.name || words.title, at: "" };
163
+ if (state.kind !== "weather") {
164
+ /** @type {Record<string, string>} */
165
+ const notes = { pick: words.pick, loading: words.loading, consent: words.consent, offline: words.offline, private: words.private, failed: words.failed };
166
+ const note = state.kind === "unknown" ? words.unknown(state.city) : notes[state.kind] ?? words.failed;
167
+ /** @type {Record<string, [string, string, string, string]>} the empty face's line and what to do, long and short */
168
+ const empty = {
169
+ pick: [words.pick, words.where, words.pick, words.whereShort],
170
+ loading: [words.loading, "", words.loading, ""],
171
+ unknown: [words.unknownLine(state.city), words.unknownHow, words.unknownLine(state.city), words.unknownHowShort],
172
+ consent: [words.consent, "", words.consentShort, ""],
173
+ offline: [words.offline, words.offlineHow, words.offlineShort, ""],
174
+ private: [words.privateLine, words.privateHow, words.privateLine, words.privateHow],
175
+ failed: [words.failed, "", words.failed, ""],
176
+ };
177
+ const [line, how, lineShort, howShort] = empty[state.kind] ?? empty.failed;
178
+ if (state.kind === "pick") head.city = words.title;
179
+ return { head, note, hint: state.kind === "pick" || state.kind === "unknown" ? words.where : "", empty: { line, how, lineShort, howShort }, now: null, days: [] };
180
+ }
181
+ const { current = {}, daily = {} } = state.forecast ?? {};
182
+ const sky = skyOf(current.weather_code, current.is_day !== 0);
183
+ const fetched = typeof state.at === "string" ? new Date(state.at) : null;
184
+ const two = (/** @type {number} */ value) => String(value).padStart(2, "0");
185
+ head.at = fetched && !Number.isNaN(fetched.getTime()) ? words.at(`${two(fetched.getHours())}:${two(fetched.getMinutes())}`) : "";
186
+ const range = (/** @type {number} */ index) => `${degrees(daily.temperature_2m_max?.[index])} / ${degrees(daily.temperature_2m_min?.[index])}`;
187
+ const feels = typeof current.apparent_temperature === "number" ? words.feels(degrees(current.apparent_temperature)) : null;
188
+ const humidity = typeof current.relative_humidity_2m === "number" ? words.humidity(Math.round(current.relative_humidity_2m)) : null;
189
+ const wind = typeof current.wind_speed_10m === "number" ? words.wind(Math.round(current.wind_speed_10m)) : null;
190
+ const more = [feels, humidity, wind].filter((piece) => piece !== null);
191
+ const dates = Array.isArray(daily.time) ? daily.time : [];
192
+ const days = dates.slice(0, 5).map((/** @type {string} */ date, /** @type {number} */ index) => {
193
+ const [year, month, day] = String(date).split("-").map(Number);
194
+ const weekday = index === 0 ? words.today : words.weekdays[new Date(Date.UTC(year, month - 1, day)).getUTCDay()] ?? "";
195
+ const [high, low] = [daily.temperature_2m_max?.[index], daily.temperature_2m_min?.[index]];
196
+ return { weekday, picture: skyOf(daily.weather_code?.[index]).picture, sky: words.sky[skyOf(daily.weather_code?.[index]).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 };
197
+ });
198
+ const temperature = typeof current.temperature_2m === "number" && Number.isFinite(current.temperature_2m) ? current.temperature_2m : null;
199
+ return {
200
+ head, note: "", hint: "", empty: null,
201
+ now: { picture: sky.picture, sky: words.sky[sky.words], temperature: degrees(current.temperature_2m), range: dates.length ? range(0) : "", low: days[0]?.low ?? "", high: days[0]?.high ?? "", feels, humidity, wind, more, value: temperature },
202
+ days,
203
+ };
204
+ }
205
+
206
+ // The sky's pictures, two-toned on a 64 x 64 grid, each color the face's (style.css): the sun with its rays,
207
+ // a cloud with its shade, rain, snow, a bolt, the moon, fog.
208
+ const SUN = (/** @type {number} */ cx, /** @type {number} */ cy, /** @type {number} */ r) => {
209
+ const rays = [0, 45, 90, 135, 180, 225, 270, 315].map((angle) => {
210
+ const turn = (angle * Math.PI) / 180;
211
+ const [inner, outer] = [r + 4.5, r + 8.5];
212
+ return `<line x1="${(cx + Math.cos(turn) * inner).toFixed(1)}" y1="${(cy + Math.sin(turn) * inner).toFixed(1)}" x2="${(cx + Math.cos(turn) * outer).toFixed(1)}" y2="${(cy + Math.sin(turn) * outer).toFixed(1)}"/>`;
213
+ }).join("");
214
+ return `<g class="gallery-soft-weather-rays" stroke-width="2.6" stroke-linecap="round">${rays}</g><circle class="gallery-soft-weather-sun" cx="${cx}" cy="${cy}" r="${r}"/><circle class="gallery-soft-weather-core" cx="${cx - r * 0.22}" cy="${cy - r * 0.22}" r="${r * 0.62}"/>`;
215
+ };
216
+ const CLOUD = (/** @type {number} */ dx, /** @type {number} */ dy, /** @type {number} */ scale, /** @type {string} */ fill = "cloud", /** @type {string} */ shade = "shade") => `<g transform="translate(${dx} ${dy}) scale(${scale})"><g class="gallery-soft-weather-${shade}"><circle cx="20" cy="33" r="10"/><circle cx="31" cy="25" r="13"/><circle cx="43" cy="32" r="9.5"/><rect x="18" y="31" width="27" height="12" rx="6"/></g><g class="gallery-soft-weather-${fill}"><circle cx="20" cy="31" r="10"/><circle cx="31" cy="23" r="13"/><circle cx="43" cy="30" r="9.5"/><rect x="18" y="29" width="27" height="12" rx="6"/></g></g>`;
217
+ const MOON = (/** @type {number} */ cx, /** @type {number} */ cy, /** @type {number} */ r) => `<path class="gallery-soft-weather-moon" d="M${cx + r * 0.62} ${cy + r * 0.55}A${r} ${r} 0 1 1 ${cx - r * 0.35} ${cy - r * 0.94}A${r * 0.78} ${r * 0.78} 0 0 0 ${cx + r * 0.62} ${cy + r * 0.55}z"/>`;
218
+ const PICTURES = {
219
+ sun: SUN(32, 32, 12),
220
+ moon: MOON(32, 32, 15),
221
+ partly: SUN(24, 23, 10) + CLOUD(8, 14, 0.95),
222
+ "partly-night": MOON(25, 22, 11) + CLOUD(8, 14, 0.95),
223
+ cloud: CLOUD(-2, 2, 0.8, "shade", "shade") + CLOUD(6, 10, 0.95),
224
+ fog: `${CLOUD(2, -2, 0.95)}<g class="gallery-soft-weather-mist" stroke-width="2.8" stroke-linecap="round"><line x1="14" y1="48" x2="50" y2="48"/><line x1="20" y1="55" x2="44" y2="55"/></g>`,
225
+ rain: `${CLOUD(2, 2, 0.95)}<g class="gallery-soft-weather-rain" stroke-width="2.8" stroke-linecap="round"><line x1="24" y1="47" x2="21" y2="54"/><line x1="33" y1="47" x2="30" y2="54"/><line x1="42" y1="47" x2="39" y2="54"/></g>`,
226
+ snow: `${CLOUD(2, 2, 0.95)}<g class="gallery-soft-weather-snow"><circle cx="23" cy="51" r="2.4"/><circle cx="32" cy="55" r="2.4"/><circle cx="41" cy="51" r="2.4"/></g>`,
227
+ thunder: `${CLOUD(2, 0, 0.95)}<path class="gallery-soft-weather-bolt" d="M34 41l-7 10h5.5l-2.5 9 8.5-12h-5.5l3-7z"/>`,
228
+ none: '<g class="gallery-soft-weather-track"><circle cx="20" cy="33" r="10"/><circle cx="31" cy="25" r="13"/><circle cx="43" cy="32" r="9.5"/><rect x="18" y="31" width="27" height="12" rx="6"/></g>',
229
+ };
230
+
231
+ // The small line pictures of the face (24 x 24): the head's pin, the empty face's, the more line's.
232
+ const LINES = {
233
+ pin: '<path d="M12 21s-6.2-5.6-6.2-11a6.2 6.2 0 1 1 12.4 0c0 5.4-6.2 11-6.2 11z"/><circle cx="12" cy="10" r="2.2"/>',
234
+ globe: '<circle cx="12" cy="12" r="8.6"/><path d="M3.4 12h17.2M12 3.4c2.4 2.4 3.6 5.3 3.6 8.6s-1.2 6.2-3.6 8.6M12 3.4C9.6 5.8 8.4 8.7 8.4 12s1.2 6.2 3.6 8.6"/>',
235
+ cloudoff: '<path d="M7 18.5h10.2a3.8 3.8 0 0 0 1.4-7.3A6 6 0 0 0 7.6 9.6 4.5 4.5 0 0 0 7 18.5z"/><path d="M4 4l16 16"/>',
236
+ search: '<circle cx="11" cy="11" r="6.3"/><path d="M20 20l-4.3-4.3"/>',
237
+ thermo: '<path d="M10 14.3V5.2a2 2 0 1 1 4 0v9.1a4 4 0 1 1-4 0z"/>',
238
+ drop: '<path d="M12 3.6s5.8 6.2 5.8 10.2a5.8 5.8 0 0 1-11.6 0C6.2 9.8 12 3.6 12 3.6z"/>',
239
+ wind: '<path d="M3.5 9.5h11a2.6 2.6 0 1 0-2.6-2.6"/><path d="M3.5 14h14.6a2.6 2.6 0 1 1-2.6 2.6"/>',
240
+ };
241
+
242
+ /**
243
+ * The size the face is laid out by: its card's cells (`context.size`), or `fallback` (the manifest's first
244
+ * size) where no card is; and the frame's padding for it, as the soft cards pad theirs: "xs" on a card one
245
+ * cell high, "s" on a small one (2 × 2 and less), "l" on one 3 cells high or more, else "m".
246
+ * @param {DocComponentSize | null | undefined} size
247
+ * @param {[number, number]} fallback
248
+ */
249
+ function sizeOf(size, fallback) {
250
+ const w = size?.w ?? fallback[0];
251
+ const h = size?.h ?? fallback[1];
252
+ return { w, h, pad: h === 1 ? "xs" : w <= 2 && h <= 2 ? "s" : h >= 3 ? "l" : "m" };
253
+ }
254
+
255
+ /**
256
+ * An element of the face, of `kind` (its class).
257
+ * @template {keyof HTMLElementTagNameMap} K
258
+ * @param {K} tag
259
+ * @param {string} kind
260
+ * @param {string} [text]
261
+ */
262
+ function made(tag, kind, text) {
263
+ const node = document.createElement(tag);
264
+ node.className = `gallery-soft-weather-${kind}`;
265
+ if (text !== undefined) node.textContent = text;
266
+ return node;
267
+ }
268
+
269
+ /** A sky's picture, as an svg element, `size` px square. @param {string} picture @param {number} size */
270
+ function pictureOf(picture, size) {
271
+ const svg = document.createElementNS("http://www.w3.org/2000/svg", "svg");
272
+ svg.setAttribute("viewBox", "0 0 64 64");
273
+ svg.setAttribute("width", String(size));
274
+ svg.setAttribute("height", String(size));
275
+ svg.setAttribute("aria-hidden", "true");
276
+ svg.setAttribute("class", "gallery-soft-weather-picture");
277
+ svg.innerHTML = PICTURES[/** @type {keyof typeof PICTURES} */ (picture)] ?? PICTURES.cloud;
278
+ return svg;
279
+ }
280
+
281
+ /** A line picture of the face, as a span holding its svg. @param {keyof typeof LINES} name @param {string} kind */
282
+ function lineOf(name, kind) {
283
+ const holder = made("span", kind);
284
+ holder.setAttribute("aria-hidden", "true");
285
+ holder.innerHTML = `<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round">${LINES[name]}</svg>`;
286
+ return holder;
287
+ }
288
+
289
+ DocKit.component({
290
+ id: "gallery-soft/weather",
291
+ on: ["source", "layout"],
292
+ mount(host, context) {
293
+ const language = languageOf(document.documentElement);
294
+ const face = made("div", "face");
295
+ host.append(face);
296
+ /** @type {any} */
297
+ let shown = { kind: "loading", city: "" };
298
+ const draw = (/** @type {any} */ state) => {
299
+ shown = state;
300
+ const { w, h, pad } = sizeOf(context.size, [4, 2]);
301
+ const small = w <= 2;
302
+ const tall = h >= 3;
303
+ const said = faceOf(state, language);
304
+ const head = made("div", "head");
305
+ head.append(lineOf("pin", "chip"), made("span", "city", said.head.city), made("span", "at", small ? "" : said.head.at));
306
+ /** @type {Element[]} */
307
+ const parts = [head];
308
+ if (said.now) {
309
+ const now = said.now;
310
+ const temperature = made("span", "temperature", now.temperature.replace(/°$/, ""));
311
+ temperature.append(made("sup", "degree", "°"));
312
+ if (small) {
313
+ const top = made("div", "row");
314
+ top.append(temperature, pictureOf(now.picture, 46));
315
+ const line = made("p", "line", `${now.sky} `);
316
+ line.append(made("span", "range", `${now.low} / ${now.high}`));
317
+ parts.push(top, line);
318
+ } else {
319
+ const words = made("span", "words");
320
+ words.append(made("b", "sky", now.sky), made("span", "range", tall ? WORDS[language].highLow(now.high, now.low) : [`${now.low} / ${now.high}`, now.feels].filter(Boolean).join(" · ")));
321
+ const row = made("div", "now");
322
+ row.append(pictureOf(now.picture, tall ? 54 : 52), temperature, words);
323
+ const more = made("p", "more");
324
+ /** @type {Array<[keyof typeof LINES, string | null]>} */
325
+ const pieces = tall ? [["thermo", now.feels], ["drop", now.humidity], ["wind", now.wind]] : [["drop", now.humidity], ["wind", now.wind]];
326
+ more.append(...pieces.filter(([, words]) => words !== null).map(([picture, words]) => {
327
+ const piece = made("span", "piece");
328
+ piece.append(lineOf(picture, "icon"), String(words));
329
+ return piece;
330
+ }));
331
+ parts.push(row, more);
332
+ if (tall) {
333
+ const days = made("ol", "days");
334
+ const spans = said.days.flatMap((day) => day.span ?? []);
335
+ const [lowest, highest] = [Math.min(...spans), Math.max(...spans)];
336
+ const share = (/** @type {number} */ value) => `${(((value - lowest) / (highest - lowest)) * 100).toFixed(1)}%`;
337
+ days.replaceChildren(...said.days.map((day, index) => {
338
+ const item = made("li", "day");
339
+ const picture = pictureOf(day.picture, 24);
340
+ picture.setAttribute("aria-label", day.sky);
341
+ picture.removeAttribute("aria-hidden");
342
+ picture.setAttribute("role", "img");
343
+ const bar = made("span", "bar");
344
+ bar.setAttribute("aria-hidden", "true");
345
+ if (day.span && highest > lowest) {
346
+ const fill = made("i", "fill");
347
+ fill.style.left = share(day.span[0]);
348
+ fill.style.right = `${(100 - parseFloat(share(day.span[1]))).toFixed(1)}%`;
349
+ bar.append(fill);
350
+ if (index === 0 && now.value !== null) {
351
+ const mark = made("b", "mark");
352
+ mark.style.left = share(Math.min(highest, Math.max(lowest, now.value)));
353
+ bar.append(mark);
354
+ }
355
+ }
356
+ item.append(made("span", "weekday", day.weekday), picture, made("span", "low", day.low), bar, made("span", "high", day.high));
357
+ return item;
358
+ }));
359
+ parts.push(days);
360
+ }
361
+ }
362
+ } else if (said.empty) {
363
+ const empty = made("div", "empty");
364
+ /** @type {Record<string, keyof typeof LINES>} */
365
+ const discs = { pick: "pin", consent: "globe", offline: "cloudoff", private: "globe", unknown: "search", failed: "cloudoff" };
366
+ if (state.kind === "loading") {
367
+ const waiting = made("span", "disc");
368
+ waiting.append(pictureOf("none", 28));
369
+ empty.append(waiting);
370
+ } else empty.append(lineOf(discs[state.kind] ?? "cloudoff", "disc"));
371
+ empty.append(made("p", "note", small ? said.empty.lineShort : said.empty.line));
372
+ const how = small ? said.empty.howShort : said.empty.how;
373
+ if (how) empty.append(made("p", "how", how));
374
+ parts.push(empty);
375
+ }
376
+ face.replaceChildren(...parts);
377
+ Object.assign(face.dataset, { kind: state.kind, w: String(w), h: String(h), pad });
378
+ };
379
+ let asked = 0; // the latest load: an earlier one that answers later draws nothing
380
+ const load = async () => {
381
+ const mine = ++asked;
382
+ const settings = context.readJSON("settings");
383
+ if (settings === undefined) return; // no JSON: the instance has failed, and Gallery shows what it holds
384
+ const city = typeof settings?.city === "string" ? settings.city.trim() : "";
385
+ const unit = settings?.unit === "℉" ? "℉" : "℃";
386
+ if (!city) return draw({ kind: "pick" });
387
+ draw({ kind: "loading", city });
388
+ try {
389
+ const found = placeOf((await context.fetch(searchAddress(city, language))).data);
390
+ if (mine !== asked) return;
391
+ if (!found) return draw({ kind: "unknown", city });
392
+ const answer = await context.fetch(forecastAddress(found, unit));
393
+ if (mine !== asked) return;
394
+ draw({ kind: "weather", city, place: found, forecast: answer.data, at: answer.at });
395
+ } catch (error) {
396
+ if (mine !== asked) return;
397
+ const code = /** @type {DocFetchError} */ (error).code;
398
+ draw({ kind: code === "consent" || code === "offline" || code === "private" ? code : "failed", city });
399
+ if (!code) context.fail(error); // no refusal of the server's: the block's own mistake, which the kit says
400
+ }
401
+ };
402
+ load();
403
+ context.interval(load, 30 * 60_000);
404
+ return {
405
+ update(reason) {
406
+ if (reason === "source") load();
407
+ else if (reason === "layout") draw(shown);
408
+ },
409
+ };
410
+ },
411
+ });
@@ -0,0 +1 @@
1
+ <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 240 120"><defs><linearGradient id="w" x1="0" y1="0" x2="0" y2="1"><stop offset="0" stop-color="#3e7ac6" stop-opacity=".07"/><stop offset=".52" stop-color="#3e7ac6" stop-opacity="0"/></linearGradient></defs><rect width="240" height="120" rx="8" fill="#f3f3f1"/><rect x="16.5" y="12.5" width="207" height="95" rx="14" fill="#ffffff" stroke="#e8e7e4"/><rect x="17" y="13" width="206" height="94" rx="13.5" fill="url(#w)"/><rect x="30" y="24" width="14" height="14" rx="4.5" fill="#ecf3fb"/><rect x="34" y="30" width="6" height="2" rx="1" fill="#3e7ac6"/><rect x="50" y="28" width="22" height="6" rx="3" fill="#37352f"/><rect x="176" y="28" width="28" height="6" rx="3" fill="#c4c2bd"/><circle cx="44" cy="62" r="7" fill="#f6b23c"/><g fill="#dfe5ed"><circle cx="47" cy="72" r="6"/><circle cx="55" cy="67" r="8"/><circle cx="62" cy="72" r="6"/><rect x="45" y="70" width="18" height="8" rx="4"/></g><rect x="78" y="56" width="30" height="24" rx="12" fill="#1f1f1f"/><rect x="116" y="58" width="22" height="7" rx="3.5" fill="#37352f"/><rect x="116" y="72" width="54" height="5" rx="2.5" fill="#c4c2bd"/><rect x="30" y="90" width="44" height="5" rx="2.5" fill="#c4c2bd"/><rect x="82" y="90" width="52" height="5" rx="2.5" fill="#c4c2bd"/></svg>
@@ -0,0 +1,185 @@
1
+ /* 柔光风格's weather. Every selector starts at the instance and goes down from it, so that nothing
2
+ here reaches the rest of the page. The soft look's tokens first, light and dark (light-dark(): the
3
+ page's color scheme, which follows its theme), the sky's own colors among them (the sun, its core, a
4
+ cloud and its shade, rain), then the face: a faint wash of the accent from the card's top over the soft
5
+ card's fill; a head of a pin's chip and the city, when at its end (fading while the grip shows); the sky's
6
+ picture and the temperature large, the sky's words and the range beside them; how it feels, the humidity
7
+ and the wind under them, each after a small picture; on a tall card the days ahead under a hairline, a
8
+ row each (the day, its sky, its lowest, a bar from the lowest to the highest of the five, warm toward the
9
+ top, today's now a ring on it, its highest); on a 2 × 2 card the temperature beside the picture over the
10
+ sky's words. Nothing to show: the cards' empty face. On a custom page the face is the card's whole room,
11
+ taken out over the card's padding and given the soft frame's (data-pad), the board's line around it;
12
+ where no card is (a document, as gallery block check shows it) the face frames itself at a 4 × 2 card's size. */
13
+ [data-doc-component="gallery-soft/weather"] {
14
+ --soft-font: "PingFang SC", "Segoe UI", "Microsoft YaHei", system-ui, sans-serif;
15
+ --soft-num: "Segoe UI", "PingFang SC", "Microsoft YaHei", sans-serif;
16
+ --soft-card: light-dark(#ffffff, #1f1f20);
17
+ --soft-card-line: light-dark(rgb(28 28 32 / 6.5%), rgb(255 255 255 / 7.5%));
18
+ --soft-card-shadow: 0 0 0 1px var(--soft-card-line), 0 1px 2px light-dark(rgb(28 28 32 / 3.5%), rgb(0 0 0 / 0%)), 0 8px 24px -14px light-dark(rgb(28 28 32 / 12%), rgb(0 0 0 / 60%));
19
+ --soft-wash: linear-gradient(180deg, light-dark(rgb(62 122 198 / 6%), rgb(126 173 226 / 7%)) 0%, transparent 52%);
20
+ --soft-text: light-dark(#37352f, #d9d9dc);
21
+ --soft-strong: light-dark(#1f1f1f, #f1f1f2);
22
+ --soft-muted: light-dark(#7a7a7f, #9d9da3);
23
+ --soft-accent: light-dark(#3e7ac6, #7eade2);
24
+ --soft-accent-soft: light-dark(#ecf3fb, rgb(126 173 226 / 14%));
25
+ --soft-accent-mid: light-dark(#afcaea, #4a6f9b);
26
+ --soft-track: light-dark(rgb(28 28 32 / 7%), rgb(255 255 255 / 8%));
27
+ --soft-cloud: light-dark(#e4e9f0, #6d7787);
28
+ --soft-cloud-shade: light-dark(#ccd5e0, #555e6c);
29
+ --soft-sun: light-dark(#f6b23c, #f2b046);
30
+ --soft-sun-core: light-dark(#fbc960, #f7c868);
31
+ --soft-rain: light-dark(#5b91d2, #7eade2);
32
+ --soft-range: linear-gradient(90deg, light-dark(#98c2e8, #5e8fc6), light-dark(#f5b75a, #e3a24a));
33
+ --soft-grip-room: 0px;
34
+ > .gallery-soft-weather-face {
35
+ --soft-pad: 20px;
36
+ position: relative;
37
+ box-sizing: border-box;
38
+ display: flex;
39
+ flex-direction: column;
40
+ min-width: 0;
41
+ width: 304px;
42
+ max-width: 100%;
43
+ height: 144px;
44
+ padding: calc(var(--soft-pad) - var(--soft-edge, 0px));
45
+ overflow: hidden;
46
+ border-radius: 16px;
47
+ box-shadow: var(--soft-card-shadow);
48
+ background: var(--soft-wash), var(--soft-card);
49
+ color: var(--soft-text);
50
+ font: 13px/1.5 var(--soft-font);
51
+ -webkit-font-smoothing: antialiased;
52
+ }
53
+ > .gallery-soft-weather-face[data-pad="s"] { --soft-pad: 18px; }
54
+ > .gallery-soft-weather-face[data-pad="l"] { --soft-pad: 24px; }
55
+ > .gallery-soft-weather-face[data-pad="xs"] { padding: 0 calc(16px - var(--soft-edge, 0px)); justify-content: center; }
56
+ /* The head: the pin's chip, the city, when at its end. */
57
+ > .gallery-soft-weather-face > .gallery-soft-weather-head {
58
+ display: flex;
59
+ align-items: center;
60
+ gap: 10px;
61
+ flex: none;
62
+ height: 28px;
63
+ min-width: 0;
64
+ padding-inline-end: var(--soft-grip-room);
65
+ }
66
+ > .gallery-soft-weather-face > .gallery-soft-weather-head > .gallery-soft-weather-chip {
67
+ display: grid;
68
+ place-items: center;
69
+ flex: none;
70
+ width: 28px;
71
+ height: 28px;
72
+ border-radius: 8px;
73
+ background: var(--soft-accent-soft);
74
+ color: var(--soft-accent);
75
+ }
76
+ > .gallery-soft-weather-face > .gallery-soft-weather-head > .gallery-soft-weather-chip > svg { display: block; width: 16px; height: 16px; }
77
+ > .gallery-soft-weather-face > .gallery-soft-weather-head > .gallery-soft-weather-city { min-width: 0; overflow: hidden; white-space: nowrap; text-overflow: ellipsis; font-size: 14px; font-weight: 600; color: var(--soft-strong); }
78
+ > .gallery-soft-weather-face > .gallery-soft-weather-head > .gallery-soft-weather-at {
79
+ flex: none;
80
+ margin-left: auto;
81
+ margin-inline-end: calc(-1 * var(--soft-grip-room));
82
+ font-size: 12px;
83
+ color: var(--soft-muted);
84
+ white-space: nowrap;
85
+ opacity: calc(1 - var(--gallery-grip-shown, 0));
86
+ transition: opacity .12s ease-out;
87
+ }
88
+ > .gallery-soft-weather-face[data-pad="s"] > .gallery-soft-weather-head { gap: 8px; height: 24px; }
89
+ > .gallery-soft-weather-face[data-pad="s"] > .gallery-soft-weather-head > .gallery-soft-weather-chip { width: 24px; height: 24px; border-radius: 7px; }
90
+ > .gallery-soft-weather-face[data-pad="s"] > .gallery-soft-weather-head > .gallery-soft-weather-chip > svg { width: 14px; height: 14px; }
91
+ > .gallery-soft-weather-face[data-pad="s"] > .gallery-soft-weather-head > .gallery-soft-weather-city { font-size: 13px; }
92
+ /* The sky's pictures, in their own colors. */
93
+ .gallery-soft-weather-picture { display: block; flex: none; }
94
+ .gallery-soft-weather-rays { stroke: var(--soft-sun); }
95
+ .gallery-soft-weather-sun { fill: var(--soft-sun); }
96
+ .gallery-soft-weather-core { fill: var(--soft-sun-core); }
97
+ .gallery-soft-weather-moon { fill: var(--soft-sun-core); }
98
+ .gallery-soft-weather-cloud { fill: var(--soft-cloud); }
99
+ .gallery-soft-weather-shade { fill: var(--soft-cloud-shade); }
100
+ .gallery-soft-weather-rain { stroke: var(--soft-rain); }
101
+ .gallery-soft-weather-mist { stroke: var(--soft-cloud-shade); }
102
+ .gallery-soft-weather-snow { fill: var(--soft-accent-mid); }
103
+ .gallery-soft-weather-bolt { fill: var(--soft-sun); }
104
+ .gallery-soft-weather-track { fill: var(--soft-track); }
105
+ /* Now: the picture, the temperature, the sky's words and the range. */
106
+ > .gallery-soft-weather-face > .gallery-soft-weather-now { display: flex; align-items: center; gap: 14px; margin-top: auto; min-width: 0; }
107
+ > .gallery-soft-weather-face[data-pad="l"] > .gallery-soft-weather-now { margin-top: 10px; }
108
+ > .gallery-soft-weather-face .gallery-soft-weather-temperature {
109
+ position: relative;
110
+ flex: none;
111
+ font: 700 44px/1 var(--soft-num);
112
+ letter-spacing: -.03em;
113
+ font-variant-numeric: tabular-nums;
114
+ color: var(--soft-strong);
115
+ white-space: nowrap;
116
+ }
117
+ > .gallery-soft-weather-face .gallery-soft-weather-temperature > .gallery-soft-weather-degree {
118
+ position: relative;
119
+ top: 2px;
120
+ margin-left: 1px;
121
+ font-size: 22px;
122
+ font-weight: 600;
123
+ line-height: 1;
124
+ letter-spacing: 0;
125
+ vertical-align: top;
126
+ }
127
+ > .gallery-soft-weather-face > .gallery-soft-weather-now > .gallery-soft-weather-words { display: flex; flex-direction: column; gap: 3px; min-width: 0; }
128
+ > .gallery-soft-weather-face > .gallery-soft-weather-now > .gallery-soft-weather-words > .gallery-soft-weather-sky { overflow: hidden; white-space: nowrap; text-overflow: ellipsis; font-size: 14px; font-weight: 600; color: var(--soft-strong); }
129
+ > .gallery-soft-weather-face > .gallery-soft-weather-now > .gallery-soft-weather-words > .gallery-soft-weather-range { overflow: hidden; white-space: nowrap; text-overflow: ellipsis; font: 12px/1.5 var(--soft-num); color: var(--soft-muted); }
130
+ > .gallery-soft-weather-face > .gallery-soft-weather-more { display: flex; align-items: center; gap: 12px; margin: 10px 0 0; overflow: hidden; font-size: 12px; color: var(--soft-muted); white-space: nowrap; }
131
+ > .gallery-soft-weather-face[data-pad="l"] > .gallery-soft-weather-more { margin-top: 8px; }
132
+ > .gallery-soft-weather-face > .gallery-soft-weather-more > .gallery-soft-weather-piece { display: inline-flex; align-items: center; gap: 4px; }
133
+ > .gallery-soft-weather-face > .gallery-soft-weather-more > .gallery-soft-weather-piece > .gallery-soft-weather-icon { display: block; width: 13px; height: 13px; opacity: .85; }
134
+ > .gallery-soft-weather-face > .gallery-soft-weather-more > .gallery-soft-weather-piece > .gallery-soft-weather-icon > svg { display: block; width: 100%; height: 100%; }
135
+ /* The days ahead (a tall card's). */
136
+ > .gallery-soft-weather-face > .gallery-soft-weather-days { display: flex; flex-direction: column; margin: auto 0 0; padding: 6px 0 0; list-style: none; box-shadow: inset 0 1px 0 var(--soft-track); }
137
+ > .gallery-soft-weather-face > .gallery-soft-weather-days > .gallery-soft-weather-day { display: grid; grid-template-columns: 38px 22px 30px minmax(0, 1fr) 30px; align-items: center; gap: 8px; height: 24px; font-size: 12.5px; }
138
+ > .gallery-soft-weather-face > .gallery-soft-weather-days > .gallery-soft-weather-day > .gallery-soft-weather-picture { width: 24px; height: 24px; }
139
+ > .gallery-soft-weather-face > .gallery-soft-weather-days > .gallery-soft-weather-day > .gallery-soft-weather-weekday { color: var(--soft-text); white-space: nowrap; }
140
+ > .gallery-soft-weather-face > .gallery-soft-weather-days > .gallery-soft-weather-day > .gallery-soft-weather-low { font-family: var(--soft-num); text-align: right; color: var(--soft-muted); }
141
+ > .gallery-soft-weather-face > .gallery-soft-weather-days > .gallery-soft-weather-day > .gallery-soft-weather-high { font-family: var(--soft-num); font-weight: 600; color: var(--soft-strong); }
142
+ > .gallery-soft-weather-face > .gallery-soft-weather-days > .gallery-soft-weather-day > .gallery-soft-weather-bar { position: relative; height: 5px; border-radius: 3px; background: var(--soft-track); }
143
+ > .gallery-soft-weather-face > .gallery-soft-weather-days > .gallery-soft-weather-day > .gallery-soft-weather-bar > .gallery-soft-weather-fill { position: absolute; top: 0; bottom: 0; border-radius: 3px; background: var(--soft-range); }
144
+ > .gallery-soft-weather-face > .gallery-soft-weather-days > .gallery-soft-weather-day > .gallery-soft-weather-bar > .gallery-soft-weather-mark { position: absolute; top: -2px; width: 9px; height: 9px; margin-left: -4.5px; border-radius: 50%; background: var(--soft-card); box-shadow: 0 0 0 2px var(--soft-strong); }
145
+ /* A 2 × 2 card: the temperature beside the picture, the sky's words under them. */
146
+ > .gallery-soft-weather-face > .gallery-soft-weather-row { display: flex; align-items: center; justify-content: space-between; margin-top: auto; }
147
+ > .gallery-soft-weather-face > .gallery-soft-weather-line { margin: 8px 0 0; overflow: hidden; white-space: nowrap; text-overflow: ellipsis; font-size: 12px; color: var(--soft-text); }
148
+ > .gallery-soft-weather-face > .gallery-soft-weather-line > .gallery-soft-weather-range { font-family: var(--soft-num); color: var(--soft-muted); }
149
+ /* Nothing to show: the cards' empty face. */
150
+ > .gallery-soft-weather-face > .gallery-soft-weather-empty { display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 4px; flex: 1; min-height: 0; text-align: center; }
151
+ > .gallery-soft-weather-face > .gallery-soft-weather-empty > .gallery-soft-weather-disc { display: grid; place-items: center; flex: none; width: 44px; height: 44px; margin-bottom: 8px; border-radius: 50%; background: var(--soft-track); color: var(--soft-muted); }
152
+ > .gallery-soft-weather-face > .gallery-soft-weather-empty > .gallery-soft-weather-disc > svg { display: block; width: 20px; height: 20px; }
153
+ > .gallery-soft-weather-face > .gallery-soft-weather-empty > .gallery-soft-weather-disc > .gallery-soft-weather-picture { width: 28px; height: 28px; }
154
+ > .gallery-soft-weather-face > .gallery-soft-weather-empty > .gallery-soft-weather-note { margin: 0; font-size: 13px; color: var(--soft-text); }
155
+ > .gallery-soft-weather-face > .gallery-soft-weather-empty > .gallery-soft-weather-how { margin: 0; font-size: 12px; color: var(--soft-muted); }
156
+ /* A 2 × 2 card: a smaller disc, a line each, so that the three stand clear of the head. */
157
+ > .gallery-soft-weather-face[data-pad="s"] > .gallery-soft-weather-empty { gap: 0; }
158
+ > .gallery-soft-weather-face[data-pad="s"] > .gallery-soft-weather-empty > .gallery-soft-weather-disc { width: 30px; height: 30px; margin-bottom: 4px; }
159
+ > .gallery-soft-weather-face[data-pad="s"] > .gallery-soft-weather-empty > .gallery-soft-weather-disc > svg { width: 15px; height: 15px; }
160
+ > .gallery-soft-weather-face[data-pad="s"] > .gallery-soft-weather-empty > .gallery-soft-weather-disc > .gallery-soft-weather-picture { width: 22px; height: 22px; }
161
+ > .gallery-soft-weather-face[data-pad="s"] > .gallery-soft-weather-empty > :is(.gallery-soft-weather-note, .gallery-soft-weather-how) { max-width: 100%; overflow: hidden; white-space: nowrap; text-overflow: ellipsis; }
162
+ > .gallery-soft-weather-face[data-pad="s"] > .gallery-soft-weather-empty > .gallery-soft-weather-note { font-size: 12.5px; line-height: 18px; }
163
+ > .gallery-soft-weather-face[data-pad="s"] > .gallery-soft-weather-empty > .gallery-soft-weather-how { line-height: 16px; }
164
+ /* A card 2 cells high and wider: the disc beside its line and what to do, which under the head have no room for a column. */
165
+ > .gallery-soft-weather-face[data-pad="m"] > .gallery-soft-weather-empty { display: grid; grid-template-columns: auto minmax(0, max-content); column-gap: 12px; row-gap: 2px; align-content: center; justify-content: center; text-align: left; }
166
+ > .gallery-soft-weather-face[data-pad="m"] > .gallery-soft-weather-empty > .gallery-soft-weather-disc { grid-row: 1 / span 2; width: 36px; height: 36px; margin: 0; }
167
+ > .gallery-soft-weather-face[data-pad="m"] > .gallery-soft-weather-empty > .gallery-soft-weather-disc > svg { width: 17px; height: 17px; }
168
+ > .gallery-soft-weather-face[data-pad="m"] > .gallery-soft-weather-empty > .gallery-soft-weather-disc > .gallery-soft-weather-picture { width: 24px; height: 24px; }
169
+ > .gallery-soft-weather-face[data-pad="m"] > .gallery-soft-weather-empty > :is(.gallery-soft-weather-note, .gallery-soft-weather-how) { overflow: hidden; white-space: nowrap; text-overflow: ellipsis; }
170
+ > .gallery-soft-weather-face[data-pad="m"] > .gallery-soft-weather-empty > .gallery-soft-weather-note { align-self: end; }
171
+ > .gallery-soft-weather-face[data-pad="m"] > .gallery-soft-weather-empty > .gallery-soft-weather-how { align-self: start; }
172
+ > .gallery-soft-weather-face[data-pad="m"] > .gallery-soft-weather-empty > .gallery-soft-weather-note:last-child { grid-row: 1 / span 2; align-self: center; }
173
+ }
174
+ /* On a custom page: the face over the card's whole room, its padding the soft frame's, the board's line around it; the head's end kept clear of the grip's corner. */
175
+ .gallery-card > [data-doc-component="gallery-soft/weather"] { height: 100%; }
176
+ .gallery-card > [data-doc-component="gallery-soft/weather"] > .gallery-soft-weather-face {
177
+ --soft-edge: 1px;
178
+ --soft-grip-room: max(0px, calc(40px - var(--soft-pad)));
179
+ width: auto;
180
+ max-width: none;
181
+ height: calc(100% + 2 * var(--gallery-card-pad));
182
+ margin: calc(-1 * var(--gallery-card-pad));
183
+ border-radius: calc(var(--gallery-card-radius) - 1px);
184
+ box-shadow: none;
185
+ }
@@ -0,0 +1,3 @@
1
+ <div data-doc-component="gallery-soft/weather">
2
+ <script type="application/json">{}</script>
3
+ </div>