@heycys/gallery 0.1.2 → 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/embed/page.mjs +1 -1
- package/browser/editor/components/file/page.mjs +4 -4
- package/browser/editor/components/heading/index.mjs +7 -6
- package/browser/editor/components/icons.mjs +3 -0
- 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 +6 -2
- package/browser/editor/components/installed/page.mjs +80 -13
- 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 +17 -5
- package/browser/editor/components/table/index.mjs +4 -2
- package/browser/editor/page/after/index.mjs +288 -0
- package/browser/editor/page/align.mjs +91 -0
- 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/hint.mjs +64 -27
- package/browser/editor/page/board/index.mjs +160 -71
- package/browser/editor/page/board/motion.mjs +177 -0
- package/browser/editor/page/board/settings.mjs +4 -3
- package/browser/editor/page/clipboard/index.mjs +10 -3
- package/browser/editor/page/clipboard/own/blocks.mjs +3 -4
- package/browser/editor/page/clipboard/own/describe.mjs +6 -2
- package/browser/editor/page/commit.mjs +2 -2
- package/browser/editor/page/core.mjs +3 -1
- package/browser/editor/page/custom-page.mjs +15 -11
- package/browser/editor/page/editor.mjs +31 -14
- package/browser/editor/page/history.mjs +19 -4
- package/browser/editor/page/insert/index.mjs +20 -22
- package/browser/editor/page/menu.mjs +15 -7
- package/browser/editor/page/page-objects.mjs +3 -7
- package/browser/editor/page/present-links.mjs +5 -4
- package/browser/editor/page/present-shell.mjs +63 -0
- package/browser/editor/page/selection/index.mjs +10 -2
- package/browser/editor/page/table/binding.mjs +87 -0
- package/browser/editor/page/table/icons.mjs +0 -2
- package/browser/editor/page/table/index.mjs +10 -14
- package/browser/editor/page/table/views.mjs +5 -52
- package/browser/editor/page/table/widths.mjs +82 -10
- package/browser/editor/page/typing/index.mjs +44 -12
- package/browser/editor/page/typing/leave.mjs +19 -5
- package/browser/shared/block-packs.mjs +23 -8
- package/browser/shared/component-catalog.mjs +15 -8
- package/browser/shared/component-source.mjs +3 -1
- package/browser/shared/components/heading.mjs +2 -1
- package/browser/shared/components/installed.mjs +1 -1
- package/browser/shared/components/page.mjs +2 -0
- package/browser/shared/components/paragraph.mjs +8 -1
- package/browser/shared/components/table.mjs +1 -0
- package/browser/shared/emoji/line-icons.mjs +37 -0
- package/browser/shared/http.mjs +9 -0
- package/browser/shared/i18n/en.mjs +40 -17
- package/browser/shared/outline.mjs +30 -2
- package/browser/shared/pack-manifest.mjs +12 -1
- package/browser/shared/pages.mjs +169 -57
- package/browser/shared/pinyin.mjs +92 -0
- package/browser/shared/present-step.mjs +17 -0
- package/browser/shared/sidebar-head.mjs +70 -0
- package/browser/shared/web-links.mjs +5 -0
- package/dist/chunk-2OHANJ6Q.mjs +2 -0
- package/dist/{chunk-QOUEFUCH.mjs → chunk-3MBRL2PM.mjs} +1 -1
- package/dist/{chunk-NWR2LT5B.mjs → chunk-4OKWZY5E.mjs} +1 -1
- package/dist/{chunk-RMECZA2K.mjs → chunk-5K44HLTZ.mjs} +1 -1
- package/dist/{chunk-NFMCP2HI.mjs → chunk-5XA2ZBAE.mjs} +2 -2
- package/dist/{chunk-OUUP3WKT.mjs → chunk-67N2QJYT.mjs} +1 -1
- package/dist/chunk-6KBYRA2C.mjs +2 -0
- package/dist/{chunk-SX4LJYT6.mjs → chunk-6N3PX4XX.mjs} +1 -1
- package/dist/{chunk-RFDZXFJF.mjs → chunk-7JDX4E65.mjs} +1 -1
- package/dist/chunk-7M2BQQGZ.mjs +2 -0
- package/dist/{chunk-ZUNVAXLH.mjs → chunk-7OG26PGF.mjs} +1 -1
- package/dist/{chunk-B4P2CM2J.mjs → chunk-AHN3NFKJ.mjs} +1 -1
- package/dist/chunk-ALZ6ZENZ.mjs +3 -0
- package/dist/{chunk-UGWYKHBL.mjs → chunk-AR5D57ZD.mjs} +2 -2
- package/dist/{chunk-W3BGBJQW.mjs → chunk-BFJGHSQN.mjs} +1 -1
- package/dist/{chunk-HLYV7RIH.mjs → chunk-CMA72MAG.mjs} +1 -1
- package/dist/{chunk-D4CKRD3V.mjs → chunk-DAZL73VK.mjs} +2 -2
- package/dist/{chunk-6VTU6KEO.mjs → chunk-DJISHPUL.mjs} +1 -1
- package/dist/{chunk-BPL64HGA.mjs → chunk-EAIFITAV.mjs} +1 -1
- package/dist/chunk-EP25HDAJ.mjs +2 -0
- package/dist/{chunk-6EZ7FNIK.mjs → chunk-F4ZA6JRZ.mjs} +1 -1
- package/dist/{chunk-3KJHLHUO.mjs → chunk-F6HVDZR4.mjs} +1 -1
- package/dist/{chunk-3NJACR4W.mjs → chunk-FDMAXMQA.mjs} +1 -1
- package/dist/chunk-FETSREUN.mjs +5 -0
- package/dist/{chunk-RKPWLGZ3.mjs → chunk-GHOYKMQ3.mjs} +1 -1
- package/dist/chunk-HDWTZ763.mjs +12 -0
- package/dist/{chunk-VTKNEYT3.mjs → chunk-HPOI4ZX7.mjs} +1 -1
- package/dist/{chunk-OW5NWPOJ.mjs → chunk-HXG7EOPJ.mjs} +1 -1
- package/dist/{chunk-V6RIYQZZ.mjs → chunk-ITOH5EGO.mjs} +1 -1
- package/dist/{chunk-ZWPMCK7P.mjs → chunk-IV64FFI4.mjs} +1 -1
- package/dist/chunk-J43Z6LSS.mjs +2 -0
- package/dist/chunk-J5PUIV3Y.mjs +4 -0
- package/dist/{chunk-KTKHRC6H.mjs → chunk-JA7G53PC.mjs} +1 -1
- package/dist/{chunk-NWFBE2YA.mjs → chunk-JLTZF4LA.mjs} +1 -1
- package/dist/{chunk-GY3FAUVM.mjs → chunk-JZT7I2OJ.mjs} +1 -1
- package/dist/{chunk-QKXMPUXC.mjs → chunk-K5XATEOO.mjs} +1 -1
- package/dist/chunk-L2SUIS5S.mjs +2 -0
- package/dist/{chunk-TEZAWDSQ.mjs → chunk-LM4XFQHZ.mjs} +1 -1
- package/dist/{chunk-5ZJA7CXT.mjs → chunk-MN7BZL4R.mjs} +1 -1
- package/dist/chunk-MTYYHM2G.mjs +15 -0
- package/dist/{chunk-HMYTM3GT.mjs → chunk-MXUBKDRO.mjs} +1 -1
- package/dist/{chunk-MHW7ZKOU.mjs → chunk-OEXWRJME.mjs} +1 -1
- package/dist/{chunk-CRJEG7MT.mjs → chunk-OFHXGWOX.mjs} +1 -1
- package/dist/chunk-ORID3AE7.mjs +166 -0
- package/dist/{chunk-32ZUEFZ7.mjs → chunk-PGDE24N5.mjs} +1 -1
- package/dist/{chunk-UNOYVIYR.mjs → chunk-POTA2FV4.mjs} +1 -1
- package/dist/{chunk-N7AZZLGT.mjs → chunk-QE5RG76S.mjs} +18 -17
- package/dist/{chunk-N76HWBA3.mjs → chunk-R2ZDLJYT.mjs} +1 -1
- package/dist/chunk-SWUTTZCN.mjs +2 -0
- package/dist/{chunk-POQSE4C2.mjs → chunk-TR7TWGHB.mjs} +1 -1
- package/dist/chunk-U5XL7D6A.mjs +3 -0
- package/dist/{chunk-PVER7LSC.mjs → chunk-U7NZI6N4.mjs} +2 -2
- package/dist/{chunk-Q47PLKIJ.mjs → chunk-UGWMMEJ5.mjs} +1 -1
- package/dist/chunk-UJQJKNGK.mjs +2 -0
- package/dist/chunk-UYVCQK3H.mjs +22 -0
- package/dist/{chunk-FJYN7RTH.mjs → chunk-VFX2KNHP.mjs} +1 -1
- package/dist/{chunk-UBBRTJ2R.mjs → chunk-VS7JIGJW.mjs} +1 -1
- package/dist/{chunk-NVRNLK25.mjs → chunk-W7665ZEC.mjs} +2 -2
- package/dist/{chunk-NG375ILQ.mjs → chunk-WQDQWCX5.mjs} +1 -1
- package/dist/chunk-YLPSMDIS.mjs +5 -0
- package/dist/{chunk-VXACTLO3.mjs → chunk-YNAWBAYN.mjs} +1 -1
- package/dist/{chunk-ZB4H7ZN4.mjs → chunk-YROX2O22.mjs} +1 -1
- package/dist/{chunk-YQGT4AB2.mjs → chunk-ZDLPUOAG.mjs} +1 -1
- package/dist/chunk-ZQS6H473.mjs +16 -0
- package/dist/{chunk-OJKMINIU.mjs → chunk-ZWWC4KLF.mjs} +15 -15
- package/dist/cli.mjs +1 -1
- package/dist/server.mjs +1 -1
- package/dist/worker.mjs +1 -1
- package/kit/board.css +5 -5
- package/kit/code.js +15 -15
- package/kit/report.css +120 -41
- package/kit/runtime.js +45 -7
- package/kit/tables.js +2 -0
- package/kit/ui.js +2 -0
- package/package.json +1 -1
- package/packs/gallery/chart-view/kit.js +3 -3
- package/packs/gallery/chart-view/writing.md +1 -1
- package/packs/gallery/countdown/component.json +1 -1
- package/packs/gallery/countdown/kit.js +89 -29
- package/packs/gallery/countdown/preview.svg +1 -1
- package/packs/gallery/countdown/style.css +88 -100
- package/packs/gallery/countdown/writing.md +2 -2
- package/packs/gallery/habit/component.json +3 -3
- package/packs/gallery/habit/kit.js +114 -75
- package/packs/gallery/habit/preview.svg +1 -1
- package/packs/gallery/habit/style.css +133 -205
- package/packs/gallery/habit/writing.md +2 -2
- package/packs/gallery/heatmap/component.json +2 -2
- package/packs/gallery/heatmap/kit.js +335 -173
- package/packs/gallery/heatmap/preview.svg +1 -1
- package/packs/gallery/heatmap/style.css +158 -170
- package/packs/gallery/heatmap/writing.md +2 -2
- package/packs/gallery/kanban/kit.js +3 -3
- package/packs/gallery/kanban/writing.md +1 -1
- package/packs/gallery/metric/kit.js +3 -3
- package/packs/gallery/metric/writing.md +1 -1
- package/packs/gallery/note/component.json +3 -3
- package/packs/gallery/note/kit.js +40 -13
- package/packs/gallery/note/preview.svg +1 -1
- package/packs/gallery/note/style.css +51 -30
- package/packs/gallery/note/writing.md +2 -2
- package/packs/gallery/recent/component.json +2 -2
- package/packs/gallery/recent/kit.js +141 -86
- package/packs/gallery/recent/preview.svg +1 -1
- package/packs/gallery/recent/style.css +53 -126
- package/packs/gallery/recent/writing.md +2 -2
- package/packs/gallery/static/component.json +2 -2
- package/packs/gallery/static/preview.svg +1 -1
- package/packs/gallery/static/style.css +99 -66
- package/packs/gallery/static/writing.md +2 -2
- package/packs/gallery/stats/component.json +3 -3
- package/packs/gallery/stats/kit.js +253 -72
- package/packs/gallery/stats/preview.svg +1 -1
- package/packs/gallery/stats/style.css +64 -142
- package/packs/gallery/stats/writing.md +2 -2
- package/packs/gallery/today/component.json +2 -2
- package/packs/gallery/today/kit.js +62 -27
- package/packs/gallery/today/preview.svg +1 -1
- package/packs/gallery/today/style.css +101 -72
- package/packs/gallery/today/writing.md +2 -2
- package/packs/gallery/todos/component.json +1 -1
- package/packs/gallery/todos/kit.js +218 -71
- package/packs/gallery/todos/preview.svg +1 -1
- package/packs/gallery/todos/style.css +170 -223
- package/packs/gallery/todos/writing.md +1 -1
- package/packs/gallery/weather/component.json +2 -2
- package/packs/gallery/weather/kit.js +165 -90
- package/packs/gallery/weather/preview.svg +1 -1
- package/packs/gallery/weather/style.css +100 -218
- package/packs/gallery/weather/writing.md +1 -1
- 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/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 +9 -9
- package/skill/SKILL.md +12 -12
- package/skill/references/building-blocks.md +4 -4
- package/skill/references/pages-and-data.md +13 -9
- package/skill/references/writing-html.md +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-2NRBY6AJ.mjs +0 -2
- package/dist/chunk-35NQ4PLQ.mjs +0 -2
- package/dist/chunk-4AV456RQ.mjs +0 -2
- package/dist/chunk-5XYHDBJ5.mjs +0 -2
- package/dist/chunk-6A53MZYZ.mjs +0 -2
- package/dist/chunk-6EXH3ORZ.mjs +0 -166
- package/dist/chunk-BVEFGE4B.mjs +0 -2
- package/dist/chunk-D4EURAX4.mjs +0 -4
- package/dist/chunk-DQCE7TJY.mjs +0 -5
- package/dist/chunk-FWNRPMCJ.mjs +0 -12
- package/dist/chunk-FWW4CSAZ.mjs +0 -2
- package/dist/chunk-JVHHHGEA.mjs +0 -3
- package/dist/chunk-PZDLJJTJ.mjs +0 -3
- package/dist/chunk-SXHBYZST.mjs +0 -16
- package/dist/chunk-UFNYFFKO.mjs +0 -20
- package/dist/chunk-UKSHDZZ6.mjs +0 -2
- package/dist/chunk-VJPFVNNW.mjs +0 -15
- package/dist/chunk-VS3ZMVGX.mjs +0 -5
- package/web/assets/index-BK2e_07w.js +0 -13
- package/web/assets/index-CWFI83mF.css +0 -1
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
# 天气 (gallery-soft/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
|
+
It is 柔光风格's (the pack `gallery-soft`, off until the user turns it on in 设置 › 组件列表): the same card as Gallery 风格's `gallery/weather`, its settings, its data and what the user does on it the same, in the soft look of design A (a faint wash of blue from the card's top, rounded chips, big numbers). Write it only where the user asked for 柔光风格 or the page already holds its cards.
|
|
6
|
+
|
|
7
|
+
## Settings
|
|
8
|
+
|
|
9
|
+
Its two settings are the card's form, which the user opens from the grip at the card's top right › 设置…:
|
|
10
|
+
|
|
11
|
+
| Key | Label | Type | What it is |
|
|
12
|
+
| --- | --- | --- | --- |
|
|
13
|
+
| `city` | 城市 | text | the city, as the user names it: 上海, 杭州, Berlin; looked up by that name, its first match taken |
|
|
14
|
+
| `unit` | 单位 | select | `℃` (the default) or `℉` |
|
|
15
|
+
|
|
16
|
+
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-soft/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.
|
|
17
|
+
|
|
18
|
+
## Going online
|
|
19
|
+
|
|
20
|
+
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.
|
|
21
|
+
|
|
22
|
+
## How to write it
|
|
23
|
+
|
|
24
|
+
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 gallery-soft/weather`, the instance as template.html has it, then its settings as above (`gallery page add <slug> gallery-soft/weather` does the card for you). Sizes: 4 × 2 (the default: now, the range and how it feels, the humidity and the wind), 2 × 2 (the temperature and the sky alone) and 4 × 4 (and the next five days).
|
|
25
|
+
|
|
26
|
+
## How it looks
|
|
27
|
+
|
|
28
|
+
The city beside a pin's chip and when the weather was fetched (更新于 14:05) at the top, the sky's picture in its own colors (the sun, a cloud and its shade, rain) and the temperature large beside it, the sky's words and the range beside them, the humidity and the wind under them after small pictures (on a 4 × 4 card how it feels too, and the next five days under a hairline, each its sky and its lowest and highest at the ends of a bar drawn against the whole five, warm toward the top, now ringed on today's); a 2 × 2 card the temperature beside the picture, the sky's words and the range under them; in 柔光风格's soft look (as every card of it: a faint wash of blue from the card's top, a head of a rounded tinted chip and a title, its end clear of the card's grip), light and dark. It is fetched again when its settings change and every 30 minutes. While there is nothing to show it says why on a soft disc: 写上一个城市 (no city), 找不到「…」 (a name Open-Meteo does not know), 允许联网之后显示天气 (waiting for the user's consent, the kit's button over it), 现在连不上网,取不到天气 (no network, and nothing fetched before), 网络设置把天气服务指向了本地地址 (this computer's network setup gives Open-Meteo's names an address of this computer or of a private network, which Gallery refuses). The script runs with the rights of the page's own scripts, as any block's does.
|
package/release.json
CHANGED
|
@@ -1,26 +1,26 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@heycys/gallery",
|
|
3
|
-
"version": "0.
|
|
4
|
-
"built": "2026-11-
|
|
3
|
+
"version": "0.2.0",
|
|
4
|
+
"built": "2026-11-10T06:00:12.267Z",
|
|
5
5
|
"stamps": {
|
|
6
|
-
"editor": "
|
|
6
|
+
"editor": "730eb4fe396a3d82",
|
|
7
7
|
"kit": {
|
|
8
|
-
"styles": "
|
|
8
|
+
"styles": "90714ca047271da8",
|
|
9
9
|
"katex-styles": "81d0a0b4dcb41846",
|
|
10
|
-
"runtime": "
|
|
11
|
-
"code": "
|
|
10
|
+
"runtime": "ccf037942f0fee28",
|
|
11
|
+
"code": "f893c8b464096161",
|
|
12
12
|
"state": "d4a528bd33704119",
|
|
13
13
|
"sheets": "fda7b7b754e01019",
|
|
14
14
|
"tokens": "a218d5d5f9008530",
|
|
15
|
-
"ui": "
|
|
15
|
+
"ui": "6ab6d809a853b59a",
|
|
16
16
|
"dialogs": "42866e832540bf9f",
|
|
17
17
|
"katex": "1b0a973a02ab84f0",
|
|
18
18
|
"katex-auto-render": "63e7162ddec186d6",
|
|
19
19
|
"math": "af1582414dca108c",
|
|
20
20
|
"d3": "9f5a21b6070f8353",
|
|
21
21
|
"charts": "22bde4e5900579fe",
|
|
22
|
-
"tables": "
|
|
23
|
-
"board-styles": "
|
|
22
|
+
"tables": "f776dc063389a916",
|
|
23
|
+
"board-styles": "338f6b6b6145b4dc",
|
|
24
24
|
"board": "15007a0cd8566621"
|
|
25
25
|
}
|
|
26
26
|
}
|
package/skill/SKILL.md
CHANGED
|
@@ -9,16 +9,16 @@ Create a self-contained HTML document whose claims, numbers, and visual encoding
|
|
|
9
9
|
|
|
10
10
|
## Before anything: the gallery command
|
|
11
11
|
|
|
12
|
-
This skill holds the instructions; the tools are the npm package `@heycys/gallery`, the `gallery` command. This skill is Gallery 0.
|
|
12
|
+
This skill holds the instructions; the tools are the npm package `@heycys/gallery`, the `gallery` command. This skill is Gallery 0.2.0's and needs `@heycys/gallery` ^0.2.0: a version npm's range `^0.2.0` takes, 0.2.0 or a later 0.2.x.
|
|
13
13
|
|
|
14
14
|
1. Run `gallery --version`. Its first line is the version: when it is such a version, go on to step 3. A line after it may say that something is newer; that never stops the task: say it once (the handoff will do) and go on, and update nothing without the user's yes, unless they already said in this conversation to update.
|
|
15
15
|
- `技能:<folder> …`: the Gallery skill there (this one, maybe) is older than the gallery. Tell the user so and offer to run the command the line gives (`gallery skill install`, with `--project` for a project's skill; run by `npx`, the line gives `npx -y @heycys/gallery@^<version> skill install`); after their yes, run it and tell them a new Agent session reads the new skill. Finish this task with the skill as it is.
|
|
16
16
|
- `新版本:…`: npm has a newer Gallery. Tell the user once in the conversation and offer to update; after their yes, run the line's `npm i -g …`, then `gallery skill install`, and tell them a new Agent session reads the new skill. Where you run Gallery by `npx` (no global install), the line gives `npx -y @heycys/gallery@^<its version> skill install` instead: run that after their yes, and tell them the next commands can take the newer range: `npx -y @heycys/gallery@^<its version> …`.
|
|
17
|
-
2. When `gallery` is not found, or prints a version older than `^0.
|
|
18
|
-
- When it prints a version newer than `^0.
|
|
17
|
+
2. When `gallery` is not found, or prints a version older than `^0.2.0` takes, install it with `npm i -g @heycys/gallery@^0.2.0`, then run `gallery --version` again. When the user has already said to install it (in this request or earlier in the conversation), run it without asking again; otherwise ask the user before you install anything: say that Gallery's command is missing (or which version it is) and that you would run that command, and run it once they agree.
|
|
18
|
+
- When it prints a version newer than `^0.2.0` takes, install nothing (that would take Gallery back to an older version): this skill is older than their Gallery. Tell the user and offer to run `gallery skill install` (with `--project` when the skill is the project's, in its `.claude/skills/`; a `技能:` line gives it); after their yes, run it and ask them to start a new Agent session, which reads the new skill.
|
|
19
19
|
- No Node, or `node --version` older than 22.13: tell the user to install the current LTS from https://nodejs.org (or with their system's package manager), then start again.
|
|
20
|
-
- npm says `EACCES` (macOS and Linux, where npm's global folder belongs to the system): never use `sudo`. Tell the user, and offer either of these: give npm a folder of their own (`npm config set prefix ~/.npm-global`, add `~/.npm-global/bin` to `PATH` in their shell profile, open a new terminal, install again); or run every command as `npx -y @heycys/gallery@^0.
|
|
21
|
-
- Use `npx -y @heycys/gallery@^0.
|
|
20
|
+
- npm says `EACCES` (macOS and Linux, where npm's global folder belongs to the system): never use `sudo`. Tell the user, and offer either of these: give npm a folder of their own (`npm config set prefix ~/.npm-global`, add `~/.npm-global/bin` to `PATH` in their shell profile, open a new terminal, install again); or run every command as `npx -y @heycys/gallery@^0.2.0 <command> …` instead of `gallery <command> …`.
|
|
21
|
+
- Use `npx -y @heycys/gallery@^0.2.0 <command> …` likewise wherever a global install is not allowed (a sandbox, CI). It is slower: a few seconds more per command.
|
|
22
22
|
- On Windows, `gallery` works in PowerShell right after the install, in the same terminal. Only when PowerShell says running scripts is disabled (`gallery.ps1`): run `gallery.cmd` with the same arguments, or ask the user to run `Set-ExecutionPolicy -Scope CurrentUser RemoteSigned` once.
|
|
23
23
|
- After an upgrade, run `gallery open --no-browser` once: the server of the version before stops by itself, and this starts the new one. Tell the user that `gallery skill install` brings this skill to the new version too (an Agent session started after it reads it).
|
|
24
24
|
3. The documents live in a workspace, a folder: `--workspace <dir>` (every command takes it), else `GALLERY_WORKSPACE`, else the nearest folder up from the current one holding `gallery.json`, else `Gallery` in the user's Documents folder, `~/Documents/Gallery` (made on first use; on Windows the Documents folder Explorer shows, OneDrive's when OneDrive backs it up). `gallery new`, `gallery import`, `gallery list` and `gallery open` print it as `工作区:<path>`. When a command prints `Cannot write the workspace <path> (…)` (a sandbox that allows writes only in the project, or a system that has not let the terminal into Documents), ask the user to allow Gallery to write there, or pass `--workspace <a folder in the project>` to every command.
|
|
@@ -131,7 +131,7 @@ The workbench's sidebar shows the documents as a tree: a document may sit under
|
|
|
131
131
|
|
|
132
132
|
- A new document goes where the user says: `gallery new <slug> "<title>" "<description>" --under <document>` (last under it; `--first`, first) or `--after <document>` (right after it, at its level). When they name no place, run `gallery list --tree` first when the workspace has documents, and put it under the document whose topic it belongs to (a week's notes under their project); at the top level when none fits. Say in the handoff where it went.
|
|
133
133
|
- Move documents only when the user asks you to organize them: `gallery move <document> --under <document>` (or `--top`), `--after <document>` or `--first` for its place there, each with the documents under it. No file changes, and links between documents still work. Name every move in the handoff.
|
|
134
|
-
- The sidebar lists custom pages (自定义页) too,
|
|
134
|
+
- The sidebar lists custom pages (自定义页) too, among 新建 and 搜索 in the order the user drags them to: pages, not documents ([Custom pages](#custom-pages-自定义页)). A page's slug and a document's are one set: `gallery new` refuses a page's, `gallery page new` a document's.
|
|
135
135
|
- The sidebar is in columns, one for each workspace of this machine (the default one's is 默认文档), and holds web links beside the documents. A document made or opened by `gallery new` or `gallery open` in another workspace joins the default workspace's sidebar too, as its line `默认工作区(…)的侧边栏:已加进…` says (display only: edit it in its own workspace). To put a web page in the sidebar, use `gallery link add <url> "<name>"` (`--column "<column>"`, `--under`, `--after` or `--first` for its place; `gallery link set` and `gallery link remove` change and take it out): a link is no document, so nothing checks, exports or searches it, and an address of this Gallery's own server is refused (link the document). `gallery list` and `gallery list --tree` show links and columns as the sidebar does. Say in the handoff where a link went (`位置:`).
|
|
136
136
|
- Change a document's title, page icon or description with `gallery set <document> --title "…" --icon <emoji, or none> --description "…"` (any of them): it writes the header of `doc.html` and `doc.json` in step, and the open page and the sidebar show it. Never edit `doc.json`'s title or icon, or the header, by hand for that. Re-read `doc.html` after it before you edit it.
|
|
137
137
|
|
|
@@ -139,17 +139,17 @@ The workbench's sidebar shows the documents as a tree: a document may sit under
|
|
|
139
139
|
|
|
140
140
|
A page has no 写作偏好: do not read it for rules, and Workflow step 1 is for documents (a `gallery list` that made it in passing changes nothing of that). A card made for "me" (my tasks) needs who that is: a setting of the card, never written into a block's code, asked or taken as step 4 says (写作偏好 may name them: read it for that alone, none of its rules is a page's).
|
|
141
141
|
|
|
142
|
-
A custom page is
|
|
142
|
+
A custom page is the user's own page in the workbench's sidebar, yours to design: the folder `pages/<slug>/` of the workspace, `page.html` (any HTML, CSS and script of yours, [pages-and-data.md](references/pages-and-data.md#a-page-is-yours-to-design); a board of cards is one way, `<div class="gallery-board" data-board-id="main">`, each card a `<section class="gallery-card" data-card-id="…" data-x data-y data-w data-h>` around one custom block's instance, in square cells, twelve to a row) and `page.json` (its title and icon), opened at `/#@<slug>`. On a board the user moves, resizes, adds and deletes its cards there (the grip at a card's top-right corner: a drag moves it, a click opens its menu, 大小, 设置… and 删除; 添加自定义块 is the first row of the ··· menu at the right of the workbench's top bar, and puts a card on the page's first board), and types in them. The page draws no big title: its name is the sidebar's, the tab's and the top bar's, so write no `<h1>` of the page's name (one in `header.gallery-page-head` is not drawn). Keep a card's top-right corner clear (28 × 28 px, 6px in): the grip stands over it while the pointer is on the card; you write it when they ask for a page or a card ("首页加一张卡片…", "给我做一个读书页").
|
|
143
143
|
|
|
144
|
-
1. Run `gallery page list` and `gallery block list` first: the pages there are, and the blocks a card can be (自定义页可用, and Gallery's own not yet added). "首页" is `pages/home
|
|
144
|
+
1. Run `gallery page list` and `gallery block list` first: the pages there are, and the blocks a card can be (自定义页可用, and Gallery's own not yet added). "首页" is `pages/home` (a page as any: the user may rename or trash it). Gallery makes it once, when its server first starts in a workspace (`gallery init` does too), with its own cards, which the user may have moved, filled in or taken off; until then `gallery page list` and the commands of `home` say it is not made yet, and `gallery open --no-browser` makes it: run that once, then again. Extend it with `gallery page add home <block>`, never write its `page.html` over whole; one the user trashed stays away. A new page only when the user asks: `gallery page new <slug> "<title>"`. A blank page they made in the sidebar (新建页面, `page-…`, an empty main) is one to write whole.
|
|
145
145
|
2. Send the address first, before you write any card: on the `交给用户` line of `gallery page new <slug> "<title>"` (a server running prints it; without one, `gallery page open <slug> --no-browser` does), or of `gallery page open home --no-browser` for the home page, in a message of its own: the user watches the cards arrive.
|
|
146
146
|
3. On a page that is there, change only the cards the request needs. Every other card keeps its `data-card-id`, its place and its data parts as they are: the user placed them, and a note's words are theirs. Put a card on with `gallery page add <slug> <block>` (the first free spot by the block's default size, or `--x --y --w --h`; it gives the card its id and pushes down what it meets); re-read `page.html` right before each change you make in it by hand, and replace that card alone.
|
|
147
|
-
4. Use one of Gallery's own blocks when it fits the request exactly (two packs: Gallery 风格's by a bare name, and 柔光风格's, off till the user turns it on, as `gallery-soft/<name>`; `gallery block add <name>` puts one in, and comes before `gallery page add`: `today`, `note`, `countdown`, `habit`, `weather` (a city's weather, from Open-Meteo: it goes online), and `todos`, `recent`, `stats`, `heatmap`, which read the workspace: its to-dos, the documents edited last, its counts, its edits by day; the user ticks a to-do on `todos`, and the tick is written into the document it is in as the user's own edit, which the page's Ctrl+Z takes back), and `gallery/static` for a card that only shows what you write (a heading, links, a short list, a picture: its file in `pages/<slug>/assets/`, written `assets/<file>`; it is for a custom page alone, a document's HTML is written as it is; it takes any size of cells, 4 ×
|
|
148
|
-
5. Try each gesture of a new block on its card: `gallery page try <slug> <card id> --press <selector>` (the gestures and `--steps` of `gallery block try`, on a scratch copy of the page): its `Wrote:` lines name that card's data parts alone, then the page's own Ctrl+Z gives the copy back and a fresh page reads it back. Then `gallery page check <slug>` until it prints `OK`: each `FAIL page.html:<line>` (
|
|
149
|
-
6. At the end tell the user what you changed (each card, by what it shows) and where: the page's title in the sidebar
|
|
147
|
+
4. Use one of Gallery's own blocks when it fits the request exactly (two packs: Gallery 风格's by a bare name, and 柔光风格's, off till the user turns it on, as `gallery-soft/<name>`; `gallery block add <name>` puts one in, and comes before `gallery page add`: `today`, `note`, `countdown`, `habit`, `weather` (a city's weather, from Open-Meteo: it goes online), and `todos`, `recent`, `stats`, `heatmap`, which read the workspace: its to-dos, the documents edited last, its counts, its edits by day; the user ticks a to-do on `todos`, and the tick is written into the document it is in as the user's own edit, which the page's Ctrl+Z takes back), and `gallery/static` for a card that only shows what you write (a heading, links, a short list, a picture: its file in `pages/<slug>/assets/`, written `assets/<file>`; it is for a custom page alone, a document's HTML is written as it is; it takes any size of cells, 4 × 4 at first, and does not grow with its words, so write the `data-w` and `data-h` it needs). When one is close but not exact (other fields, another look, another rule), do not settle for it, and do not write a block from nothing either: copy it with `gallery block new <id> --recipe <name>` and change the copy (a count by day, glasses of water or times, starts from `habit`: `gallery block new <id> --recipe habit`; a recipe, a block already made, takes no `--script`, `--flow`, `--data` or `--page`): its name, words, description, `preview.svg`, writing.md and example.html, which the command lists; Gallery's own stays as it ships. Make a block of your own from nothing ([references/building-blocks.md](references/building-blocks.md), and [references/pages-and-data.md](references/pages-and-data.md) for a card's size and settings and for what it reads: `gallery block new <id> --page --data` for a card that keeps what the user enters, `places` holding `page`) for a card that does something or keeps data the user changes that none of Gallery's is near, and for a read-only card over the workspace's data or the web's that none of Gallery's shows (a count by day, a rate, a feed, the rows of another document's table: `kanban`, `metric` and `chart-view` are views inside a document and read no table from a page): it is a block too (`needs` `workspace` or `net:<host>`; start from `heatmap` or `weather` with `--recipe`), never the page's own script or HTML. What a card holds stays in its card (a data part, its settings), never in the page's own HTML. A card that shows nothing without a setting the user did not give (`weather`'s city, `countdown`'s date, a block of your own with its owner) is asked about: ask the user, or take it from what the workspace says (写作偏好, the documents; ask when that is a guess), and tell them in the handoff what it holds and where you took it from, or that the card still asks for it. Give it with the add, `gallery page add home weather --set city=上海` (each `--set <key>=<value>`, no JSON to quote, held to the setting's type: a date is `YYYY-MM-DD`); for a card already there, write it in the card's settings part (its `<script type="application/json">`, as the block's writing.md shows), re-reading `page.html` right before and changing that part alone. `gallery page check` notes a card whose required setting is empty.
|
|
148
|
+
5. Try each gesture of a new block on its card: `gallery page try <slug> <card id> --press <selector>` (the gestures and `--steps` of `gallery block try`, on a scratch copy of the page): its `Wrote:` lines name that card's data parts alone, then the page's own Ctrl+Z gives the copy back and a fresh page reads it back. Then `gallery page check <slug>` until it prints `OK`: each `FAIL page.html:<line>` (an id missing or twice, cards sharing cells or past the row, a block a page does not run, a file of `assets/` not there or a frame of one, a card whose content does not fit it; the page's own scripts and stylesheets pass); open the pictures its `Not opened yet` line lists (1280, 1920 and 600px wide, light and dark) and read its `Changes since …` lines: they name the cards you meant to change and no other, but those that end `(the user's, on the page)`, the user's own gestures on the page since the last check (a card moved, words typed in it): leave those as they are, never put one back. A line that ends `(put there by Gallery)` is the home page's own today or note, there before you came (a new workspace's first check of `home` lists them): leave those too.
|
|
149
|
+
6. At the end tell the user what you changed (each card, by what it shows) and where: the page's title in the sidebar (with 新建 and 搜索), and the address again. A card that goes online (`weather`, or a block whose needs name `net:<host>`) shows nothing until the user allows it: tell them to press 允许访问 on the card, and never write that consent yourself.
|
|
150
150
|
- A page is no document: no opening summary, no source line, no export; 写作偏好 is for documents.
|
|
151
151
|
- Its look is yours to choose (a header of your own that is no title, colors of its own in its `<style>`), written for both themes: the dark ones under `:root[data-doc-effective-theme="dark"]`.
|
|
152
|
-
-
|
|
152
|
+
- Its own scripts are yours too, a board or none; what a card does is its block's, which the server puts in.
|
|
153
153
|
|
|
154
154
|
## Output contract
|
|
155
155
|
|
|
@@ -41,7 +41,7 @@ One block, one manifest and one `context` stand in either place; the two differ
|
|
|
41
41
|
When the user wants a document that uses the block too, the document comes first: `gallery new`, its address sent, its skeleton written (SKILL.md, Workflow steps 1–4). Then make the block as below, write the instance in its section at step 5, and try it there at step 6.
|
|
42
42
|
|
|
43
43
|
1. `gallery block list` first: what the workspace has now, in two groups by where a block may stand (文档里可用, in documents; 自定义页可用, on custom pages), each with its version, whether the menus can insert it, and what is there and cannot be used, with why; then Gallery's own blocks it has not added yet. When one does what the user asks, use it: `gallery block show <id>` prints its parts, how to write it and its example (`gallery block show gallery/<name>` does so for one of Gallery's own the workspace has not added yet, and ends with the line that adds it; `show` and `check` take its bare name too, `gallery block show heatmap`, as `add` does, a block of the workspace's own by that name staying `local/`'s). When one of Gallery's own does, `gallery block add <name>` puts it in as it ships, and it needs no check and no try (Gallery's own blocks, below).
|
|
44
|
-
2. `gallery block new <id>`: a new block in `<workspace>/components/<scope>/<name>/`, its `id` being `<scope>/<name>`, the scope `local` when you name none. It writes a block that passes the check, for you to replace. Add `--script` only when the block must do something when a reader uses it: a static block runs no code, is the one to start with, and is all most blocks need. Add `--flow` when it holds blocks of the document's own under its markup (a card around any content): a slot, `body` (Slots, below). Add `--data` for a block that keeps what a reader enters in the file, the usual reason to make one (a list of lines, a field that adds one, a button that takes one away): a data part `items` (JSON on one line, as `context.editJSON` writes it), a `kit.js` that reads it with `context.readJSON` and writes it with `context.editJSON`, a field (`DocKit.input`) and buttons hidden where nothing is written, and an `example()` that adds a line, which works on `template.html`'s empty instance as on `example.html`'s: rename the part and its fields for what the block keeps, and keep that shape. Add `--page` for a custom page's card (its places `["page"]`, a `card` of two sizes). `--data` and `--page` go together or alone, and either goes with `--script`; neither goes with `--flow` (a page has no slot, and `--data` is a part of its own), nor with `--recipe <name>`, which starts from one of Gallery's own (below). Each scaffold passes `gallery block check`, and `gallery block try` on its field (`--type .component-field "words" --then Enter`), as it is.
|
|
44
|
+
2. `gallery block new <id>`: a new block in `<workspace>/components/<scope>/<name>/`, its `id` being `<scope>/<name>`, the scope `local` when you name none: the default pack (默认块包, first in 设置 › 组件列表), where a single block goes, with no pack of its own to make. It writes a block that passes the check, for you to replace. Add `--script` only when the block must do something when a reader uses it: a static block runs no code, is the one to start with, and is all most blocks need. Add `--flow` when it holds blocks of the document's own under its markup (a card around any content): a slot, `body` (Slots, below). Add `--data` for a block that keeps what a reader enters in the file, the usual reason to make one (a list of lines, a field that adds one, a button that takes one away): a data part `items` (JSON on one line, as `context.editJSON` writes it), a `kit.js` that reads it with `context.readJSON` and writes it with `context.editJSON`, a field (`DocKit.input`) and buttons hidden where nothing is written, and an `example()` that adds a line, which works on `template.html`'s empty instance as on `example.html`'s: rename the part and its fields for what the block keeps, and keep that shape. Add `--page` for a custom page's card (its places `["page"]`, a `card` of two sizes). `--data` and `--page` go together or alone, and either goes with `--script`; neither goes with `--flow` (a page has no slot, and `--data` is a part of its own), nor with `--recipe <name>`, which starts from one of Gallery's own (below). Each scaffold passes `gallery block check`, and `gallery block try` on its field (`--type .component-field "words" --then Enter`), as it is.
|
|
45
45
|
3. Write its files (below): the manifest, `template.html`, `example.html`, its style and, with `--script`, `kit.js`, then what a writer needs to know.
|
|
46
46
|
4. `gallery block check <id>`, until it prints `OK`. It says each problem at its file and line; one with no line is of that file, or of the page, as a whole. Then open `overview-light.png` and `overview-dark.png` in the folder it prints, each the pictures of 360, 736 and 1024px wide of a theme side by side, `example.html` above the line and `template.html` below it, then at full size each width where they show something to fix, and `edit-1024-light.png` and `edit-360-light.png`, as the editing page draws it, `context.canEdit()` true: what the block draws only where a reader can edit (a handle, a button), which an export leaves out. A block that draws nothing more there gives the export's pictures again, and the check says so. It has run them and looked at nothing for you: a `Not opened yet: …` line right before the verdict lists every picture of the run in one place, as `gallery qa`'s does: count by it. In the handoff name the pictures you opened. A block with a data part whose export (`1024-light.png`, where `context.canEdit()` is false) still shows an enabled button, field, select or textarea gets a note: a control that writes is drawn hidden there, which you see by comparing that picture with `edit-1024-light.png`.
|
|
47
47
|
5. Use it where the user asked: in a document, write the element as `example.html` does (when the user wants no document, in one of its own made with `gallery new`, named in the handoff: step 6 tries the block there). The user finds it in "/" under its name. `gallery export <slug>` exports it as any block, and `gallery qa <slug>` pictures it among the cards. Around an instance, the document's words say what the block is and where its data comes from. A value that a reader's gesture changes (a count by column, a status, a score, a total) goes in the document's words only with when it held ("截至 11 月 5 日,…"), as an opening summary may need it; otherwise point to the block, which shows it as it is now. How to use the block on the editing page (drag a card, press a dot) goes in the handoff and in writing.md, not in the document: its export and PDF show the block read-only. Then `gallery block check <id> --documents`: it runs each instance the workspace's documents hold as step 4 runs the example, a section for each document, each problem at its line of the document's file (`board/doc.html:15`), the pictures in `documents/<slug>/` of the folder it prints, so that an instance filled otherwise than the example (a long title, an empty table) is tried as the reader's page runs it. It writes no document.
|
|
@@ -213,11 +213,11 @@ Start each one at `[data-doc-component="<id>"]`, the instance's own attribute, n
|
|
|
213
213
|
|
|
214
214
|
## Gallery's own blocks
|
|
215
215
|
|
|
216
|
-
Gallery ships blocks of its own in two packs (below): Gallery 风格, the scope `gallery`, on; and 柔光风格, `gallery-soft`, the same page cards in a softer look, off until the user turns it on in 设置 › 组件列表 (its cards are `gallery-soft/<name>`; `gallery block add gallery-soft/<name>`). Gallery 风格's: for documents `gallery/card`, a titled card around blocks of the document's, and `gallery/chart-card`, a titled card holding a table in its slot and the bar chart its script draws from it; three views of a table of the document ([A view of a table](pages-and-data.md#a-view-of-a-table)), `gallery/kanban` (看板: its rows as cards grouped by a column, a card dragged changing that cell), `gallery/metric` (指标: a count, sum or average of a column) and `gallery/chart-view` (图表: bars of a count, sum or average by a column), which the reader inserts from
|
|
216
|
+
Gallery ships blocks of its own in two packs (below): Gallery 风格, the scope `gallery`, on; and 柔光风格, `gallery-soft`, the same page cards in a softer look, off until the user turns it on in 设置 › 组件列表 (its cards are `gallery-soft/<name>`; `gallery block add gallery-soft/<name>`). Gallery 风格's: for documents `gallery/card`, a titled card around blocks of the document's, and `gallery/chart-card`, a titled card holding a table in its slot and the bar chart its script draws from it; three views of a table of the document ([A view of a table](pages-and-data.md#a-view-of-a-table)), `gallery/kanban` (看板: its rows as cards grouped by a column, a card dragged changing that cell), `gallery/metric` (指标: a count, sum or average of a column) and `gallery/chart-view` (图表: bars of a count, sum or average by a column), which the reader inserts from "/" (each reads the nearest table above it) and which you write after an ordinary table as `gallery block show gallery/<name>` prints (for a task board or a data dashboard in a document use them, never a block of your own); for custom pages `gallery/today` (问候与日期, a greeting and the date, drawn by the clock), `gallery/note` (便签, lines the user types on the card), `gallery/static` (静态卡片, any HTML of yours, only shown: a page's alone, as a document writes such HTML as it is), `gallery/countdown` (倒计时, the days to a date of its settings), `gallery/habit` (习惯打卡, a check-in a day and the streak, written as a recipe to start a block of your own from); `gallery/weather` (天气, a city of its settings, from Open-Meteo: it goes online, so tell the user to press 允许访问 on its card); and four that read the workspace (`needs` `workspace`), `gallery/todos` (我的待办, the to-dos not done of every document), `gallery/recent` (最近编辑, the documents edited last), `gallery/stats` (工作区统计, its counts) and `gallery/heatmap` (编辑热力图, the edits of each day of the past year), which a new workspace's 首页 holds with today and the note. Each one's writing.md, which `gallery block show` prints, says what it is for and how to fill it, and `gallery block list` names each one the workspace has not added, with its line. `gallery block add <name>` puts one in as it ships, `components/gallery/<name>/`, recording its version and what its files hold: write its instances as `gallery block show gallery/<name>` prints, with no check and no try. Change nothing in its folder: run again with a newer Gallery, `add` updates a copy that is as it was added, and never one changed since (what a system writes there as it shows the folder, a `.DS_Store`, a `Thumbs.db`, is no change). For a block like it of your own, `gallery block new <id> --recipe <name>` copies its files into a new block, every word that named it naming the new id (its classes too: `gallery-chart-card-bars` becomes `<scope>-<name>-bars`), its version 0.1.0: change its name, words and description first, and what is still the recipe's in the same folder (`preview.svg`, the menu's picture, still its drawing; writing.md, still about it; `example.html`, still its words: the command's last line names them, and `gallery block check` notes a `preview.svg` still Gallery's, byte for byte), then what you came for, and check and try it as any. `gallery block new` refuses the scopes `gallery` and `gallery-soft`.
|
|
217
217
|
|
|
218
218
|
## Block packs
|
|
219
219
|
|
|
220
|
-
A block pack (自定义块包) is a scope of blocks shared as one: the folder `components/<pack>/` with a `pack.json` at its top beside a folder for each block, whose ids are `<pack>/<name>` as any block's. Gallery's two packs are packs of this kind, installed into each workspace as it first starts; a scope with no `pack.json`
|
|
220
|
+
A block pack (自定义块包) is a scope of blocks shared as one: the folder `components/<pack>/` with a `pack.json` at its top beside a folder for each block, whose ids are `<pack>/<name>` as any block's. Gallery's two packs are packs of this kind, installed into each workspace as it first starts; `local/` is the default pack (默认块包: no `pack.json`, listed first), where a block made with no scope goes, so that one block needs no pack of its own; any other scope with no `pack.json` is a pack of its own, named by its scope. To share blocks the user made, when they ask: move them into a scope of their own (`team-cards/`), write its `pack.json` and hand over the folder, or a zip of it:
|
|
221
221
|
|
|
222
222
|
```json
|
|
223
223
|
{ "id": "team-cards", "name": { "zh": "团队卡片", "en": "Team cards" }, "description": "…", "version": "1.0.0", "author": "…" }
|
|
@@ -245,7 +245,7 @@ Exit 0 is all five (and those), exit 1 a failure. A failure with no line is of t
|
|
|
245
245
|
| --- | --- | --- |
|
|
246
246
|
| available | shown | run and export |
|
|
247
247
|
| out of the document's menus: 在文档菜单里显示 off in 设置 › 组件列表, or a block of a page's alone not switched on | not shown in a document's ("/", 在下方新建, the handle's grid); a custom page lists one whose places hold `page` | run and export |
|
|
248
|
-
| out of every menu: the block's master switch (at the right of its line in 设置 › 组件列表) off | not shown in a document's menus
|
|
248
|
+
| out of every menu: the block's master switch (at the right of its line in 设置 › 组件列表) off | not shown in a document's menus or a custom page's 添加自定义块; `gallery block` and `gallery page add` still name it | run and export |
|
|
249
249
|
| disabled, in 设置, or an `apiVersion` this Gallery does not run | not shown | show what they hold, read-only, with no script and no style, a script of data drawn by Gallery |
|
|
250
250
|
| missing, or a block that does not load | not shown | show what they hold, read-only, a script of data drawn by Gallery; `gallery check` says why in a note |
|
|
251
251
|
|
|
@@ -1,10 +1,14 @@
|
|
|
1
1
|
# Custom pages, and what a block reads beyond its own parts
|
|
2
2
|
|
|
3
|
-
A block stands in a document, on a custom page (自定义页: a board of cards
|
|
3
|
+
A block stands in a document, on a custom page (自定义页: a page of the user's that you design, a board of cards being one way to write it; SKILL.md, Custom pages, is the flow on a page) or in both. [building-blocks.md](building-blocks.md) is the block itself (the kinds of part, the files, the manifest, an instance, its style, and the two places side by side in A document and a custom page) and [block-script.md](block-script.md) is its script. This page holds what only some blocks need: the manifest fields that place a block, size it as a card and give it settings; the flow of a block made for a page; and the three things a block may read beyond its own parts, each a `needs` entry: the workspace's data (`workspace`), a table of its document (`tables`) and the web (`net:<host>`).
|
|
4
|
+
|
|
5
|
+
## A page is yours to design
|
|
6
|
+
|
|
7
|
+
A custom page's `page.html` is written as the request wants it: any HTML, CSS and script of your own, a board of cards, or both on one page. A board is what the user rearranges: its cards are moved, resized, added and deleted on the page, and what a card holds (a block's parts) is the user's to change; what the page's own HTML and script show, only you change. Write it inside `<main class="gallery-page">` (the page then follows the workbench's theme: its dark colors under `:root[data-doc-effective-theme="dark"]`), and its own files (a picture, a stylesheet, a script) in `pages/<slug>/assets/`, written `assets/<file>`. `gallery page check` takes a page's own scripts and stylesheets as they are, and fails what still matters: a board's cards where it has them, a file of `assets/` that is not there, a page that throws or does not load. A blank page the user made in the sidebar (新建页面: its slug `page-…`, an empty `<main class="gallery-page">`, which shows the user to ask an Agent) is one to write whole.
|
|
4
8
|
|
|
5
9
|
## Places, cards, settings and needs
|
|
6
10
|
|
|
7
|
-
A block stands in a document's flow, or as a card on a custom page's board (自定义页: a page of the workspace's own,
|
|
11
|
+
A block stands in a document's flow, or as a card on a custom page's board (自定义页: a page of the workspace's own, its board laid out on a grid of square cells, twelve to a row), or both: one block, one manifest and one `context` for either. Four fields of the manifest say how; each may be left out.
|
|
8
12
|
|
|
9
13
|
```json
|
|
10
14
|
{
|
|
@@ -21,11 +25,11 @@ A block stands in a document's flow, or as a card on a custom page's board (自
|
|
|
21
25
|
| Field | What it holds |
|
|
22
26
|
| --- | --- |
|
|
23
27
|
| `places` | `"document"`, `"page"` or both, each once: `["document"]` when left out. A block of a page's alone is in no document's menu until the user switches it on (设置 › 组件列表, 在文档菜单里显示); a custom page lists only blocks whose places hold `page` and that the user has not switched off (the master switch at the right of a block's line in 设置 › 组件列表 takes it out of every menu and of that list; what is written of it keeps showing, and `gallery page add` still names it), and a card of one whose places do not, written on a page all the same, says so there and does not run |
|
|
24
|
-
| `card` | its size on a board, in cells: `sizes`, the sizes the user picks from, `[w, h]` each, 1 to 12 wide and 1 to 24 high, the first the default (a phone's small, medium and large widget; the card's 大小 menu lists them, and dragging its corner snaps to the nearest, so a block that takes any size of the board's cells writes `min` and `max` beside them, `"min": { "w": 1, "h": 1 }, "max": { "w": 12, "h": 24 }`: the sizes then only the common ones the menu lists, each inside `min` and `max`); or, with no `sizes`, `w` (4 when left out) and `h` (the fewest whole cells its content takes when left out), with `min` and `max` as `{ w, h }`, which hold the default between them. `resize`: whether the user may drag its edge (false when left out); `fit`: `"fixed"` (the default: what does not fit scrolls in the card) or `"content"` (the card grows with what it holds and pushes the cards under it down, for a list that changes length); `bare`: true for no frame of the board's around it. With `sizes` and `"content"` together the width is the size the user picked, and the height is the content's, in whole cells, drawn and never written: a size's `h` is only the `data-h` the file holds, where `gallery page add` and the page's service put the card and what stands beside it, so write the cells its content takes at a usual length; a longer content is drawn higher and pushes the cards under it down, a shorter one is drawn lower and leaves its room empty. Read only where its places hold `page` |
|
|
28
|
+
| `card` | its size on a board, in cells: `sizes`, the sizes the user picks from, `[w, h]` each, 1 to 12 wide and 1 to 24 high, the first the default (a phone's small, medium and large widget; the card's 大小 menu lists them, and dragging its corner snaps to the nearest, so a block that takes any size of the board's cells writes `min` and `max` beside them, `"min": { "w": 1, "h": 1 }, "max": { "w": 12, "h": 24 }`: the sizes then only the common ones the menu lists, each inside `min` and `max`); or, with no `sizes`, `w` (4 when left out) and `h` (the fewest whole cells its content takes when left out), with `min` and `max` as `{ w, h }`, which hold the default between them. `resize`: whether the user may drag its edge (false when left out); `fit`: `"fixed"` (the default: what does not fit scrolls in the card) or `"content"` (the card grows with what it holds and pushes the cards under it down, for a list that changes length); `bare`: true for no frame of the board's around it; `consent`: for a block online, the line Gallery's consent banner on its card says, `{ "zh": "允许联网之后显示汇率", "en": "Allow internet access to show the rates" }` (what the user gets once they allow it; left out, 允许联网之后显示内容). With `sizes` and `"content"` together the width is the size the user picked, and the height is the content's, in whole cells, drawn and never written: a size's `h` is only the `data-h` the file holds, where `gallery page add` and the page's service put the card and what stands beside it, so write the cells its content takes at a usual length; a longer content is drawn higher and pushes the cards under it down, a shorter one is drawn lower and leaves its room empty. Read only where its places hold `page` |
|
|
25
29
|
| `settings` | the fields of the card's form (its menu's 设置…), each `{ key, label: { zh, en }, type, options, default, required }`: `key` a lowercase letter then letters and digits, each once; `type` one of `text`, `number`, `select` (with `options`, a list of words), `date` (`YYYY-MM-DD`), `switch`, `document` (a document's slug); `default` of that type; `required: true` for a setting the card cannot show anything without (weather's city: a card with none asks the reader for it, and `gallery page check` notes it). A block with settings has a part named `settings`, edited as data, a `<script type="application/json">` holding their values by key, which its `template.html` holds as a new card's (`{}` takes each default), and reads them with `context.readJSON("settings")` |
|
|
26
30
|
| `needs` | what it uses, each once: `workspace` (the workspace's data: its to-dos, recent documents, counts, edits by day, a table of another document: The workspace's data, below), `tables` (it is a view of a table of its document: A view of a table, below), `net:<host>` (the network, of that host alone: a lowercase host name, no port and no path, `*.` first for the names under it, never the name itself; the user consents first: Going online, below). 设置 › 组件列表 shows them |
|
|
27
31
|
|
|
28
|
-
A cell is 64px square whatever the window, 16px from the next, so a card `w` cells wide is `w × 64 + (w − 1) × 16` px (4 cells: 304px; 12: 944px, the board's whole row, in the middle of the page) and as high by `h`; the frame's
|
|
32
|
+
A cell is 64px square whatever the window, 16px from the next, so a card `w` cells wide is `w × 64 + (w − 1) × 16` px (4 cells: 304px; 12: 944px, the board's whole row, in the middle of the page) and as high by `h`; the frame's 16px padding comes off that for the block (a 4 × 2 card holds 272 × 112 px; the frame's line is a ring outside it). A wider window or the sidebar folded only leaves more room beside the board. A narrower one (the sidebar dragged wide, a small window) shows fewer columns, as many as fit, 4 at the least: the cards one after another in the order of their places, each as large as it is but no wider than the row (`context.size.w` says it, on `layout`), never written; the page's file keeps its twelve-column places. So size a card for the content at 64px cells, and take a big number or a long list's room from its cells, never from the window.
|
|
29
33
|
|
|
30
34
|
What a reader edits in each place is in [Which kind of part](building-blocks.md#which-kind-of-part) and [A document and a custom page](building-blocks.md#a-document-and-a-custom-page). So a block for a custom page keeps what a reader changes in a data part, with a field of its own or the card's settings, and no slot. On a page each `context.edit` is written at once, a step of the page's own undo (Ctrl+Z there takes it back, and the part with it); one made after someone else changed the same card is refused and the page shown again as the file is, so the block draws from what its parts hold (`source`), never from what it wrote last. `gallery block check` refuses a slot on such a block, notes each of its text parts (read-only on a custom page), notes a `card` on a block whose places hold no page, and fails a block with settings whose template holds no JSON object in its settings part. A field the manifest gets wrong (a place it does not know, a size off the grid, a setting's type or default, a need it does not know) keeps the block from loading, and `gallery block list` says why.
|
|
31
35
|
|
|
@@ -41,7 +45,7 @@ Make one only where no block of Gallery's does the job and the card does somethi
|
|
|
41
45
|
4. `gallery page try <slug> <card id> <gesture>` for each gesture a reader makes on it (`--press`, `--drag … --to`, `--key`, `--type`, `--select`, `--then` and `--steps`, as `gallery block try` takes them, on a scratch copy of the page): its `Wrote:` lines name the card's data parts and say `nothing else in page.html changed (card ids aside)`; a write anywhere else, the card's place or another card, fails. Then the page's own undo (Ctrl+Z) gives the copy back, and a fresh page reads the card back as it was. A setting is the card's menu's 设置…, which the block only reads: its way back needs no trial.
|
|
42
46
|
5. `gallery page check <slug>`, until it prints `OK`, then open its pictures (1280, 1920 and 600px wide, light and dark): a card whose content does not fit it scrolls inside it, which the check fails; give it the cells it needs, or `"fit": "content"` for one whose length changes (the check pictures the card as the file's data fills it now, a new card's, so a list that grows is seen long by trying a gesture on it that adds entries, or by filling it as the user will). A card that reads the workspace (Gallery's `todos`, `recent`, `stats`, `heatmap`, or your own block that reads `context.workspace`) is pictured once the workspace has answered, for up to 15 seconds; one still unanswered is a `note page.html:<line>: card <id> (<block>): the workspace had not answered its read of …` line, and the `OK` line then ends `; but N cards were pictured before the workspace answered it (see "note" above), so their pictures do not show what they read`. Such a picture says nothing of what the card shows: open the page in Gallery to see it, or run the check again.
|
|
43
47
|
|
|
44
|
-
Its look: the kit's card tokens, as Gallery's own cards draw theirs, so that it sits among them in both themes. A head of a chip (`--gallery-chip-size` square, `--gallery-chip-radius`, `--gallery-
|
|
48
|
+
Its look: the kit's card tokens, as Gallery's own cards draw theirs, so that it sits among them in both themes. Its type is `--gallery-font`, 13px. A head 20px high of a chip (`--gallery-chip-size` square, `--gallery-chip-radius`, `--gallery-fill` behind an icon of lines in `--gallery-muted`, `--gallery-chip-icon` wide) and a title (`--gallery-title-size`, 600, `--gallery-text`), a quiet meta right after it where the card has a few words to say of itself (`--gallery-meta-size`, `--gallery-faint`: 共 24 天, 今天 3 篇), 8px apart, the row one line, its end kept clear of the card's grip, which the board puts in the card's top-right corner (`padding-inline-end: var(--gallery-grip-room, 0px)` on its first row); one hero, a big number at `--gallery-numeral-weight` and `--gallery-numeral-tracking` in `--gallery-text-strong` (`--gallery-hero-size` for the card's one main number, `--gallery-figure-size` for one among others), its unit after it at `--gallery-unit` (13px), 3px from it, in `--gallery-muted`; labels in `--gallery-muted`, captions in `--gallery-faint`, lines `--gallery-hair`; the accent for a ring or a bar toward a target (on `--gallery-track`), green and red (`--gallery-good`, `--gallery-bad`, their `-soft` for a pill) only for a good or a bad state; `--gallery-face-gap` between rows; what the card is about in the middle of the room under its head at every size (a foot, a date or a week, at the bottom); the pieces of a meta line a muted 3px dot apart. With nothing to show yet, the cards' empty face under its head: a line of what is so (13.5px, 600) over what to do (12px, `--gallery-faint`), and one pale button where the reader can do it. The frame is the board's: draw no border, fill or shadow of the card's own. A button has no line: a primary one pale (`--gallery-accent-soft`, its words in `--gallery-accent-ink`), the others no fill until the pointer is on them (`--gallery-hover`).
|
|
45
49
|
|
|
46
50
|
A goals card, its title a setting and its goals a script of data, a field adding one and a box ticking one off:
|
|
47
51
|
|
|
@@ -129,7 +133,7 @@ A block whose manifest's `needs` hold `"workspace"` reads what the workspace hol
|
|
|
129
133
|
|
|
130
134
|
| Kind | Options | `data` |
|
|
131
135
|
| --- | --- | --- |
|
|
132
|
-
| `todos` | `{ done, slugs, limit }` | `[{ ref, text, done, slug, title, path }]`: each to-do of every document, those of the document edited last first, `path` the headings above it, `ref` what `setTodo` names it by |
|
|
136
|
+
| `todos` | `{ done, slugs, limit }` | `[{ ref, text, done, slug, title, icon, path }]`: each to-do of every document, those of the document edited last first, `icon` its document's (as `recent` gives it), `path` the headings above it, `ref` what `setTodo` names it by |
|
|
133
137
|
| `recent` | `{ limit }` | `[{ slug, title, icon, edited }]` |
|
|
134
138
|
| `stats` | none | `{ documents, todos: { done, total }, words, editedThisWeek }` |
|
|
135
139
|
| `activity` | `{ days }` | `[{ date, edits, words, reader, agent }]`: the edits and the words added by day, from the day Gallery started keeping them |
|
|
@@ -160,7 +164,7 @@ A block whose `needs` hold `"tables"` can be a view of a table of the document:
|
|
|
160
164
|
</div>
|
|
161
165
|
```
|
|
162
166
|
|
|
163
|
-
A key is a letter, then letters, digits, `_` or `-`, 32 at most, and names one table of the document. The reader binds one in the page too: a
|
|
167
|
+
A key is a letter, then letters, digits, `_` or `-`, 32 at most, and names one table of the document. The reader binds one in the page too: a block that reads tables is a row of "/" like any, and one made there reads the nearest table above it, the table given a new key when it has none or an earlier table carries the same key; its handle's 设置… lists the document's tables to read another. Its template holds no `data-doc-from`: each instance has its own.
|
|
164
168
|
|
|
165
169
|
```js
|
|
166
170
|
DocKit.component({
|
|
@@ -183,7 +187,7 @@ DocKit.component({
|
|
|
183
187
|
- It hears its table by `data`, its detail `"table"`, whenever a change leaves the rows other than they were (a cell typed in, a row added, moved or taken out, the key changed, the table deleted or put back by an undo), also once it has a table where it had none; or by `table.subscribe(listener)`, which returns the function that takes the listener off. Read the table again each time.
|
|
184
188
|
- It changes the table only by asking: `table.set(row, column, text)` (one cell's words, plain), `table.add(values, { after })`, `table.move(row, { before | after, values })` (its cells of `values` set in the same step: a card dropped in another column) and `table.remove(row)`. Each is one undo step of the page's, made as the table's own tools make it, and answers whether it was made: the file follows by itself, someone else's change of the same cell is merged word by word with the reader's, and a move, add or removal over someone else's change of the table waits on a card for the reader. `false` in an exported file and in 演示视图, before the page edits, for a row no longer in the table, for the last row of the body (`remove`) and for a table Gallery's tools do not manage (a merged cell, a `<tfoot>`, rows of different lengths). A name the header does not have throws.
|
|
185
189
|
- `table.canEdit()` says whether the page would take a change of the table now, asked with no change: false in an exported file, in 演示视图, before the page edits and for a table Gallery's tools do not manage, so draw the view read-only there (no handle, no button that adds or takes out a row) rather than show controls whose every write answers `false`.
|
|
186
|
-
- The reader puts a view in from
|
|
190
|
+
- The reader puts a view in from "/" (or 在下方新建), below the table it is to read or any block after it: it reads the nearest table above it. An Agent writes the table's key and the instance's `data-doc-from` itself, as above.
|
|
187
191
|
- Task boards, numbers and charts over a table are views Gallery ships: `gallery/kanban`, `gallery/metric` and `gallery/chart-view` (`gallery block add <name>`, before the instance is written: one written first stays read-only until the block is added; `gallery block show gallery/<name>` prints how to write each, a table and then the instance below it, its settings one line of JSON). Use them first; write a view of your own only for one they do not give.
|
|
188
192
|
- Never write the table yourself: not its cells, not its rows, not by `context.edit`, which writes the block's own parts alone. What the view draws is its own; the table is the document's.
|
|
189
193
|
- Keep what a reader only chooses in the view (its sort, a filter, what is folded) in `context.state`, never in the table.
|
|
@@ -216,6 +220,6 @@ DocKit.component({
|
|
|
216
220
|
|
|
217
221
|
- **It resolves** with `{ data, at, cached }`: `data` the answer's JSON (`as: "json"`, the default) or its text (`as: "text"`), `at` when it was fetched (an ISO time: say it on the card, 更新于 …, as an answer may be old where the network is not there), `cached` whether it was given from what was kept. Fetch again on `source` (a setting changed) and on a timer (`context.interval`, every few minutes at least: an answer of the last minute is given again, and a block may make 20 fetches a minute).
|
|
218
222
|
- **It rejects** with an `Error` whose `code` says why, which the block draws a state for: `consent` (the user has not allowed it yet; `hosts`, those waiting), `offline` (no network or the site not reached, and nothing kept; in an exported file, nothing embedded), `status` (the site answered an error, `status`), `type` (no JSON or text), `too-large`, `rate`, `key`, `private` (below), and `host` or `url` for an address it may not ask for (a host its needs do not name, or a redirect to one; another port, a user in it, not http(s), its own or a redirect's): fix the block. `private` is usually the reader's network setup, not the block: the address the name resolved to is on this computer or a private network, and no proxy on this computer took the name (the address is http, there is no proxy, the proxy is on another machine, or it is not running; an https address whose name resolves so is reached through a proxy on this computer by its name, its certificate held to the name). The Error's message names the host and the address, and `host` is set. Draw a plain state for it in the reader's words, as `gallery/weather` does (网络设置把天气服务指向了本地地址), not the generic failure.
|
|
219
|
-
- **Consent.** Until the user allows the block, every fetch rejects `consent` and Gallery draws over its card a
|
|
223
|
+
- **Consent.** Until the user allows the block, every fetch rejects `consent` and Gallery draws over its card, under its head row, a banner of its own: your manifest's `card.consent` (else 允许联网之后显示内容), 数据来自 the site its hosts share (else <host> 等 N 个网站) and a button, 允许访问 (on a card three cells wide or less, the line over the button); pressed, Gallery asks the user, and once they say yes the block starts again by itself (its mount runs anew, and fetches). The user can take it back in 设置 › 组件列表 (允许联网), and the block starts again and asks. Draw a short state of your own for `consent` too (the button stands over it). In the handoff, tell the user to press 允许访问 on the card; never write the consent into `gallery.json` (its `components.net`) yourself, nor ask `gallery block try` or `gallery page try` to: it is the user's to give, and `gallery page check`'s pictures show the card asking.
|
|
220
224
|
- **A key.** An API that wants one in its address names where it goes by `{key}`, in its path or its query (`https://api.example.com/v6/{key}/latest`, `…/latest?apikey={key}`), and `gallery block key <host> <key>` keeps the user's key for that host in the workspace (`.gallery/keys.json`): the server writes it in as it fetches, and no page, cache or export ever holds it. Never write a key into the block's files or a page. Prefer an API that needs none. An API that takes its key in a header alone is not reached.
|
|
221
225
|
- **A document and its export.** In a document an instance fetches as on a page; its export holds what the document's instances were given last (`context.fetch` answers from it, `cached: true`) and, for an address it holds nothing of, rejects `offline`: draw a placeholder for that, as the example does. `context.place` is `"export"` there.
|
|
@@ -90,6 +90,8 @@ The blocks HTML has no element for, written with the kit's classes as the exampl
|
|
|
90
90
|
|
|
91
91
|
**A block's color** (颜色): a class on the block, never a `style`, of the colors gray, brown, orange, yellow, green, blue, purple, pink and red. A paragraph, a heading, a list item or a flowchart step takes its words' color (`doc-text-<color>`), a fill (`doc-highlight-<color>`) or both; a disclosure, a code block (on its `<pre>`), a callout or a highlight panel a fill only; a table cell one of the two. Words in a line take theirs from `<mark>` or a `<span style>`.
|
|
92
92
|
|
|
93
|
+
**A block's alignment and indent** (对齐与缩进): `doc-align-center` or `doc-align-right` on a paragraph, an `h1`–`h4` or a table's frame (`div.doc-table-wrap`, when the table is narrower than the text), the left being none; `doc-indent-1` … `doc-indent-8` move a paragraph or a heading in by two body characters a level. A `text-align: center` or `right` in a paragraph's or heading's `style` is rewritten as the class.
|
|
94
|
+
|
|
93
95
|
**Columns** (`div.doc-columns` of 2 to 5 `div.doc-column`): what the reader compares across, or a picture with its words beside it (the picture's column first, so that on a phone it stands above them). `style="--doc-column-ratio: .4"` on a column gives it that share of the row: write it on every column of the row, the shares adding up to 1, or on none, and the columns share the row equally (one written on some columns only fails the check). Pictures side by side in columns: crop them to one ratio, so that their captions line up. A column holds any block but a row of columns, a section or a Sheet area. On a screen under 640px the columns stand one under another: never point at one as the left or right.
|
|
94
96
|
|
|
95
97
|
**A process or steps** (步骤流程图, `ol.doc-flow`): one step an item, drawn as a card, arrows between them. A step's title is a paragraph of bold words, then any blocks it holds; an icon may stand first in it, drawn in its number's place. The kit numbers the steps (write no 1, ① or 第一步) and lays them out in rows that fill the width; `data-direction="row"` on the list keeps them in one row, `"column"` one a row; on a step it says where the arrow after it goes. A step written the short way (`<li>收集数据<p>…</p></li>`) is rewritten as a node. A flowchart has no title or caption of its own and stands in no `<figure>`: the sentence before it says what it shows; a legend goes in a `p.doc-note` beside it. A step takes a color as a list item does. A flowchart is for steps in order, each after the one before; a flow that branches, merges or loops is a drawing of boxes and arrows like the example's, and a structure or diagram a figure ([below](#figures-and-charts)).
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
:root{--font:ui-sans-serif, -apple-system, BlinkMacSystemFont, "Segoe UI Variable Display", "Segoe UI", Helvetica, "PingFang SC", "Microsoft YaHei", Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol";--mono:"SFMono-Regular", Menlo, Consolas, "PT Mono", "Liberation Mono", Courier, monospace;--sb-w:270px;--dur:.2s;--texPri:#2c2c2b;--texSec:#7d7a75;--texTer:#a19e99;--texAcc:#5f5e59;--texDis:#bcbab6;--icoPri:#5c5a55;--icoSec:#8e8b86;--sidIco:#91918e;--borPri:#e6e5e3;--borSec:#f0efed;--borPriTra:#1c13011c;--borStrTra:#1b150030;--crumbSep:#d4d3cf;--bacPri:#fff;--bacSec:#f9f8f7;--bacEle:#fff;--popBac:#fff;--sidBac:#f3f2ef;--pageBac:#fff;--galleryPageBac:#fff;--bacIntTra:#211b170d;--bacTerTra:#2a1c0012;--inputBac:#f2f1ee99;--codeBg:#f9f8f7;--blue:#2383e2;--blueLine:#2383e291;--blueBg:#2383e224;--bluBacIntTra:#0079e413;--select:#2383e224;--red:#eb5757;--star:#cb912f;--btnPriBg:#2383e224;--btnPriBgHi:#2383e238;--btnPriTex:#1a69bd;--btnDanBg:#eb575724;--btnDanBgHi:#eb575738;--btnDanTex:#c4403c;--overlay:#0f0f0f99;--tipBg:#0f0f0f;--tipTex:#f0efed;--tipSub:#a19e99;--scrollThumb:#2a1c0024;--shaOutLg:0px 20px 24px 0px #1919190d, 0px 5px 8px 0px #19191907, 0px 0px 0px 1px #2a1c0012;--gra-tx:#7d7a75;--gra-sw:#f0efed;--gra-bg:#2a1c0012;--gra-bd:#1c13011c;--bro-tx:#9f765a;--bro-sw:#f5ede9;--bro-bg:#8b2e0016;--bro-bd:#7f330028;--ora-tx:#d27b2d;--ora-sw:#fbebde;--ora-bg:#e0650121;--ora-bd:#c4580034;--yel-tx:#cb9434;--yel-sw:#f9f3dc;--yel-bg:#d3a80023;--yel-bd:#d19c0048;--gre-tx:#50946e;--gre-sw:#e8f1ec;--gre-bg:#00642d17;--gre-bd:#00602628;--blu-tx:#387dc9;--blu-sw:#e5f2fc;--blu-bg:#007cd718;--blu-bd:#0076d934;--pur-tx:#9a6bb4;--pur-sw:#f3ebf9;--pur-bg:#6600b214;--pur-bd:#5c00a324;--pin-tx:#c14c8a;--pin-sw:#fae9f1;--pin-bg:#c5005d16;--pin-bd:#b7004e27;--red-tx:#cf5148;--red-sw:#fce9e7;--red-bg:#df160018;--red-bd:#ce18002a;--lightningcss-light:initial;--lightningcss-dark: ;color-scheme:light}@media (prefers-color-scheme:dark){:root:not([data-theme=light]){--texPri:#f0efed;--texSec:#ada9a3;--texTer:#7d7a75;--texAcc:#bcbab6;--texDis:#5f5e59;--icoPri:#a9a69e;--icoSec:#ada9a3;--sidIco:#9b9b9b;--borPri:#383836;--borSec:#2c2c2b;--borPriTra:#ffffeb1a;--borStrTra:#fffceb4e;--crumbSep:#383836;--bacPri:#191919;--bacSec:#202020;--bacEle:#202020;--popBac:#252525;--sidBac:#141413;--pageBac:#181818;--galleryPageBac:#191919;--bacIntTra:#ffffff0e;--bacTerTra:#fffff315;--bluBacIntTra:#4499ff1e;--inputBac:#ffffff0e;--codeBg:#ffffff08;--star:#d99e35;--overlay:#0f0f0fcc;--btnPriBg:#439bff3d;--btnPriBgHi:#439bff57;--btnPriTex:#7ab8ff;--btnDanBg:#ff685c3d;--btnDanBgHi:#ff685c57;--btnDanTex:#ff9a90;--tipBg:#2f2f2f;--tipTex:#f0efed;--tipSub:#9b9b9b;--scrollThumb:#fffff324;--shaOutLg:0px 0px 0px 1px #383836, 0px 14px 28px -6px #19191933, 0px 2px 4px -1px #1919191e;--gra-sw:#383836;--gra-bg:#ffffeb1a;--gra-bd:#ffffeb1a;--bro-sw:#45362d;--bro-bg:#ffb18131;--bro-bd:#ffb18131;--ora-sw:#53361f;--ora-bg:#ff934b47;--ora-bd:#ff934b47;--yel-sw:#504425;--yel-bg:#ffcd4b3d;--yel-bd:#ffcd4b3d;--gre-sw:#263d30;--gre-bg:#6cffac28;--gre-bd:#6cffac28;--blu-sw:#233850;--blu-bg:#439bff3d;--blu-bd:#439bff3d;--pur-sw:#3c2d47;--pur-bg:#c87dff33;--pur-bd:#c87dff33;--pin-sw:#4e2b3c;--pin-bg:#ff67b13b;--pin-bd:#ff67b13b;--red-sw:#502c29;--red-bg:#ff685c3d;--red-bd:#ff685c3d;--lightningcss-light: ;--lightningcss-dark:initial;color-scheme:dark}}:root[data-theme=dark]{--texPri:#f0efed;--texSec:#ada9a3;--texTer:#7d7a75;--texAcc:#bcbab6;--texDis:#5f5e59;--icoPri:#a9a69e;--icoSec:#ada9a3;--sidIco:#9b9b9b;--borPri:#383836;--borSec:#2c2c2b;--borPriTra:#ffffeb1a;--borStrTra:#fffceb4e;--crumbSep:#383836;--bacPri:#191919;--bacSec:#202020;--bacEle:#202020;--popBac:#252525;--sidBac:#141413;--pageBac:#181818;--galleryPageBac:#191919;--bacIntTra:#ffffff0e;--bacTerTra:#fffff315;--bluBacIntTra:#4499ff1e;--inputBac:#ffffff0e;--codeBg:#ffffff08;--star:#d99e35;--overlay:#0f0f0fcc;--btnPriBg:#439bff3d;--btnPriBgHi:#439bff57;--btnPriTex:#7ab8ff;--btnDanBg:#ff685c3d;--btnDanBgHi:#ff685c57;--btnDanTex:#ff9a90;--tipBg:#2f2f2f;--tipTex:#f0efed;--tipSub:#9b9b9b;--scrollThumb:#fffff324;--shaOutLg:0px 0px 0px 1px #383836, 0px 14px 28px -6px #19191933, 0px 2px 4px -1px #1919191e;--gra-sw:#383836;--gra-bg:#ffffeb1a;--gra-bd:#ffffeb1a;--bro-sw:#45362d;--bro-bg:#ffb18131;--bro-bd:#ffb18131;--ora-sw:#53361f;--ora-bg:#ff934b47;--ora-bd:#ff934b47;--yel-sw:#504425;--yel-bg:#ffcd4b3d;--yel-bd:#ffcd4b3d;--gre-sw:#263d30;--gre-bg:#6cffac28;--gre-bd:#6cffac28;--blu-sw:#233850;--blu-bg:#439bff3d;--blu-bd:#439bff3d;--pur-sw:#3c2d47;--pur-bg:#c87dff33;--pur-bd:#c87dff33;--pin-sw:#4e2b3c;--pin-bg:#ff67b13b;--pin-bd:#ff67b13b;--red-sw:#502c29;--red-bg:#ff685c3d;--red-bd:#ff685c3d;--lightningcss-light: ;--lightningcss-dark:initial;color-scheme:dark}*{box-sizing:border-box}html,body,#root{height:100%;margin:0}html{scrollbar-color:var(--scrollThumb) transparent}body{font-family:var(--font);background:var(--bacPri);color:var(--texPri);-webkit-font-smoothing:antialiased;font-size:16px;line-height:1.5;overflow:hidden}button{font:inherit;color:inherit;cursor:pointer;text-align:inherit;background:0 0;border:0;margin:0;padding:0}svg{fill:none;stroke:currentColor;stroke-width:1.5px;stroke-linecap:round;stroke-linejoin:round;width:100%;height:100%;display:block}svg.fill{fill:currentColor;stroke:none}svg.solid{fill:currentColor}svg.lu{stroke-width:1.75px}.ic{display:contents}body.preload *{transition:none!important}@keyframes pop-in{0%{opacity:0;transform:translateY(-2px)}}.app{height:100dvh;font-size:14px;display:flex}.main{background:var(--bacPri);flex-direction:column;flex:1;min-width:0;font-size:16px;display:flex;position:relative}.icon-btn{width:28px;height:28px;color:var(--icoSec);border-radius:6px;flex:none;justify-content:center;align-items:center;transition:background 20ms ease-in;display:inline-flex}.icon-btn svg{width:20px;height:20px}.icon-btn svg.lu{width:18px;height:18px}.icon-btn:hover{background:var(--bacIntTra)}.ghost-btn{height:28px;color:var(--texTer);white-space:nowrap;border-radius:6px;align-items:center;gap:6px;padding:0 8px;font-size:14px;display:inline-flex}.ghost-btn svg{width:16px;height:16px}.ghost-btn:hover{background:var(--bacIntTra)}.ghost-btn.sm{height:24px}.row-act{width:20px;height:20px;color:var(--icoSec);border-radius:4px;flex:none;justify-content:center;align-items:center;display:flex}.row-act svg{width:16px;height:16px}.row-act:hover{background:var(--bacTerTra)}.pg-icon{width:20px;height:20px;color:var(--sidIco);flex:none;justify-content:center;align-items:center;font-size:16px;line-height:1;display:inline-flex}.pg-icon svg.lu{width:18px;height:18px}.pg-icon .page-icon{object-fit:cover;border-radius:3px;width:18px;height:18px;display:block}.pg-icon .page-icon.site-icon{object-fit:contain;border-radius:3px;width:16px;height:16px}.pg-icon .glyph-icon{background:currentColor;width:18px;height:18px;display:block;-webkit-mask:none 50%/contain no-repeat;mask:none 50%/contain no-repeat}.glyph-icon[data-icon$=_gray\.svg]{color:var(--lightningcss-light,#55534e)var(--lightningcss-dark,#d3d3d3)}.glyph-icon[data-icon$=_lightgray\.svg]{color:var(--lightningcss-light,#a6a299)var(--lightningcss-dark,#7f7f7f)}.glyph-icon[data-icon$=_brown\.svg]{color:var(--lightningcss-light,#9f6b53)var(--lightningcss-dark,#aa755f)}.glyph-icon[data-icon$=_yellow\.svg]{color:var(--lightningcss-light,#cb912f)var(--lightningcss-dark,#ca8e1b)}.glyph-icon[data-icon$=_orange\.svg]{color:var(--lightningcss-light,#d9730d)var(--lightningcss-dark,#d87620)}.glyph-icon[data-icon$=_green\.svg]{color:var(--lightningcss-light,#448361)var(--lightningcss-dark,#2d9964)}.glyph-icon[data-icon$=_blue\.svg]{color:var(--lightningcss-light,#337ea9)var(--lightningcss-dark,#2e7cd1)}.glyph-icon[data-icon$=_purple\.svg]{color:var(--lightningcss-light,#9065b0)var(--lightningcss-dark,#8d5bc1)}.glyph-icon[data-icon$=_pink\.svg]{color:var(--lightningcss-light,#c14c8a)var(--lightningcss-dark,#c94079)}.glyph-icon[data-icon$=_red\.svg]{color:var(--lightningcss-light,#d44c47)var(--lightningcss-dark,#cd4945)}.menu{z-index:1000;background:var(--popBac);min-width:240px;max-width:320px;box-shadow:var(--shaOutLg);-webkit-user-select:none;user-select:none;border-radius:10px;outline:none;padding:6px 0;font-size:14px;line-height:1.2;animation:.12s ease-out pop-in;position:fixed;top:0;left:0}.menu-head{color:var(--texSec);padding:6px 12px;font-size:12px;font-weight:500;line-height:14px}.menu-item{cursor:pointer;height:28px;color:var(--texPri);border-radius:6px;align-items:center;gap:8px;margin:0 4px 1px;padding:0 8px;display:flex}.menu:not(.controlled) .menu-item:hover,.menu-item.active{background:var(--bacIntTra)}.menu-item.danger:hover,.menu-item.danger.active{color:var(--red)}.menu-item.off,.menu-item.off:hover,.menu-item.off .mi-icon,.menu-item.off:hover .mi-icon{color:var(--texDis);cursor:default}.menu:not(.controlled) .menu-item.off:hover{background:0 0}.menu-item.danger:not(.off):hover .mi-icon,.menu-item.danger:not(.off).active .mi-icon{color:var(--red)}.mi-icon{width:20px;height:20px;color:var(--icoPri);flex:none;justify-content:center;align-items:center;display:flex}.mi-icon svg{width:18px;height:18px}.mi-icon svg.lu{width:16px;height:16px}.mi-label{white-space:nowrap;text-overflow:ellipsis;flex:1;min-width:0;overflow:hidden}.mi-line{text-overflow:ellipsis;display:block;overflow:hidden}.mi-detail{color:var(--texTer);margin-top:2px;font-size:12px}.mi-kbd{max-width:45%;color:var(--texTer);white-space:nowrap;text-overflow:ellipsis;flex:none;margin-left:8px;font-size:12px;overflow:hidden}.mi-kbd:empty{display:none}.mi-arrow{width:16px;height:16px;color:var(--texTer);flex:none}.mi-arrow svg{stroke-width:1.6px}.mi-check{width:16px;height:16px;color:var(--texPri);flex:none}.mi-check svg{stroke-width:1.8px}.mi-switch{box-sizing:border-box;background:#8783784d;border-radius:44px;flex:none;align-items:center;width:28px;height:16px;margin-left:8px;padding:2px;transition:background .2s;display:flex;position:relative}.mi-switch.on{background:var(--blue)}.mi-switch>span{background:#fff;border-radius:50%;flex:none;width:12px;height:12px;transition:transform .2s ease-out;box-shadow:0 1px 2px #0f0f0f33}.mi-switch.on>span{transform:translate(12px)}@media (prefers-color-scheme:dark){:root:not([data-theme=light]) .mi-switch:not(.on){background:#caccce4d}}:root[data-theme=dark] .mi-switch:not(.on){background:#caccce4d}.menu-sep{background:var(--bacTerTra);height:1px;margin:3px 12px 4px}.menu-foot{color:var(--texTer);padding:4px 12px 2px;font-size:12px;line-height:1.6}.menu-note{color:var(--texSec);padding:4px 12px 8px;font-size:13px;line-height:1.6}.menu-empty{color:var(--texTer);padding:8px 12px;font-size:13px}.menu-sub{min-width:180px}.menu-wide{width:320px}.pop-search{padding:2px 8px 6px}.pop-input{border:1px solid var(--borPriTra);background:var(--inputBac);width:100%;height:28px;color:var(--texPri);font:inherit;border-radius:6px;outline:none;padding:0 8px;font-size:14px}.pop-input:focus{border-color:var(--blue);box-shadow:0 0 0 1px var(--blue)}.pop-list{max-height:320px;overflow-y:auto}.trash-item{border-radius:6px;align-items:center;gap:8px;height:30px;margin:0 4px;padding:0 4px 0 8px;display:flex}.trash-item:hover{background:var(--bacIntTra)}.trash-item .t{white-space:nowrap;text-overflow:ellipsis;flex:1;min-width:0;overflow:hidden}.tip{z-index:3000;pointer-events:none;background:var(--tipBg);max-width:260px;color:var(--tipTex);box-shadow:var(--shaOutLg);overflow-wrap:anywhere;opacity:0;border-radius:6px;padding:4px 8px;font-size:12px;font-weight:500;line-height:1.45;transition:opacity .1s;position:fixed;top:0;left:0}.tip.show{opacity:1}.tip .sub{color:var(--tipSub);font-weight:400}.toast{z-index:2500;background:var(--tipBg);width:fit-content;max-width:min(640px,100vw - 32px);color:var(--tipTex);box-shadow:var(--shaOutLg);opacity:0;pointer-events:none;border-radius:8px;align-items:center;gap:10px;margin:0 auto;padding:8px 14px;font-size:14px;transition:opacity .18s,transform .18s;display:flex;position:fixed;bottom:24px;left:0;right:0;transform:translateY(10px)}.toast.show{opacity:1;transform:none}.toast.show button{pointer-events:auto}.toast.error:before{content:"";background:#ff6b6b;border-radius:50%;flex:none;width:6px;height:6px}.toast button{white-space:nowrap;color:#5ea8f2;border-radius:4px;flex:none;margin-right:-6px;padding:2px 6px;font-weight:500}.toast button:hover{background:#ffffff14}.dialog-overlay{align-items:flex-start;padding-top:18vh}.dialog{background:var(--popBac);width:min(420px,100%);box-shadow:var(--shaOutLg);border-radius:12px;padding:20px 20px 16px;animation:.12s ease-out pop-in}.dialog-title{color:var(--texPri);font-size:16px;font-weight:600;line-height:1.4}.dialog-message{color:var(--texSec);margin-top:8px;font-size:14px;line-height:1.6}.dialog-actions{justify-content:flex-end;gap:8px;margin-top:18px;display:flex}.dialog-btn{height:32px;color:var(--texPri);white-space:nowrap;border-radius:6px;padding:0 14px;font-size:14px;transition:background 20ms ease-in}.dialog-btn:hover:not(:disabled){background:var(--bacIntTra)}.dialog-btn:focus-visible{background:var(--bacTerTra);outline:none}.dialog-btn.primary{background:var(--btnPriBg);color:var(--btnPriTex);font-weight:500}.dialog-btn.primary:hover:not(:disabled),.dialog-btn.primary:focus-visible{background:var(--btnPriBgHi)}.dialog-btn.danger.primary{background:var(--btnDanBg);color:var(--btnDanTex)}.dialog-btn.danger.primary:hover:not(:disabled),.dialog-btn.danger.primary:focus-visible{background:var(--btnDanBgHi)}.dialog-btn:disabled{opacity:.5;cursor:default}.modal{z-index:1500;background:var(--overlay);justify-content:center;align-items:flex-start;padding:12vh 16px 0;display:flex;position:fixed;inset:0}.search-panel{background:var(--popBac);width:min(620px,100%);box-shadow:var(--shaOutLg);border-radius:12px;animation:.12s ease-out pop-in;overflow:hidden}.search-bar{border-bottom:1px solid var(--borSec);align-items:center;gap:10px;height:52px;padding:0 16px;display:flex}.search-bar svg{width:20px;height:20px;color:var(--icoSec);flex:none}.search-bar input{min-width:0;color:var(--texPri);font:inherit;background:0 0;border:0;outline:0;flex:1;font-size:16px}.search-bar input::placeholder{color:var(--texTer)}.search-list{max-height:60vh;padding:4px 0 8px;overflow-y:auto}.search-item{cursor:pointer;border-radius:6px;align-items:center;gap:10px;height:36px;margin:0 6px;padding:0 10px;display:flex}.search-item.active{background:var(--bacIntTra)}.search-item .t{white-space:nowrap;text-overflow:ellipsis;flex:none;max-width:60%;overflow:hidden}.search-item .path{text-align:right;min-width:0;color:var(--texTer);white-space:nowrap;text-overflow:ellipsis;flex:1;font-size:12px;overflow:hidden}.search-main{flex-direction:column;flex:1;gap:1px;min-width:0;display:flex}.search-line{align-items:center;gap:10px;min-width:0;display:flex}.search-item.with-hit{align-items:flex-start;height:auto;min-height:36px;padding-top:6px;padding-bottom:6px}.search-item.with-hit .pg-icon{margin-top:1px}.search-snippet{min-width:0;color:var(--texSec);white-space:nowrap;text-overflow:ellipsis;font-size:13px;line-height:18px;overflow:hidden}.search-item.more{align-items:center;height:28px;min-height:0;padding:0 10px 0 40px}.search-item mark{color:var(--texPri);background:0 0;font-weight:600}.search-note{color:var(--texTer);padding:6px 16px 2px;font-size:12px}.link-view{background:var(--pageBac);flex:1;min-height:0;position:relative}.link-view.off,.link-pane.off{display:none}.link-pane{display:flex;position:absolute;inset:0}.link-frame{background:#fff;border:0;flex:1;width:100%;height:100%;display:block}.link-refused{flex:1}.link-refused-icon{width:36px;height:36px;color:var(--texTer);margin-bottom:6px}.link-refused-icon svg{width:36px;height:36px}.link-refused-url{word-break:break-all;max-width:min(560px,90%)!important;color:var(--texTer)!important;font-size:13px!important}.report-view{flex:1;min-height:0;position:relative}.report-frame{background:var(--pageBac);border:0;width:100%;height:100%;display:block}body.dragging iframe,body.resizing iframe{pointer-events:none}.report-state{text-align:center;flex-direction:column;flex:1;justify-content:center;align-items:center;gap:6px;min-height:0;padding:24px;display:flex}.report-state h2{margin:0;font-size:20px;font-weight:600}.report-state p{max-width:460px;color:var(--texSec);margin:0;font-size:14px;line-height:1.6}.report-state .muted{color:var(--texTer)}.report-state-actions{gap:8px;margin-top:10px;display:flex}.report-frame[data-pending]{opacity:0;pointer-events:none;position:absolute;inset:0}.card-underlay{z-index:900;background:var(--overlay);animation:.16s ease-out card-underlay-fade;position:fixed;inset:0}body.card-open .sb-resizer,body.card-open .sb-edge{pointer-events:none}@keyframes card-underlay-fade{0%{opacity:0}}@media (prefers-reduced-motion:reduce){.card-underlay{animation:none}}.report-view.off{display:none}.xf-overlay{z-index:1500;background:var(--overlay);justify-content:center;align-items:center;padding:16px;display:flex;position:fixed;inset:0}.xf-export,.xf-import{background:var(--popBac);box-shadow:var(--shaOutLg);color:var(--texPri);border-radius:12px;animation:.12s ease-out pop-in}.xf-export{width:320px;max-width:100%;padding:24px;font-size:14px}.xf-row{justify-content:space-between;align-items:center;height:28px;display:flex}.xf-label{color:var(--texTer);white-space:nowrap;margin-inline-end:auto;line-height:21px}.xf-select{white-space:nowrap;cursor:pointer;-webkit-user-select:none;user-select:none;height:28px;color:var(--texPri);border-radius:6px;align-items:center;gap:6px;margin-inline-end:-6px;padding:0 8px;line-height:1.2;transition:background 20ms ease-in;display:flex}.xf-select:hover,.xf-select.open{background:var(--bacIntTra)}.xf-select svg{width:14px;height:14px;color:var(--icoSec);stroke-width:1.6px}.xf-select:focus-visible,.xf-btn:focus-visible,.xf-choose:focus-visible{background:var(--bacTerTra);outline:none}.xf-switch:focus-visible{box-shadow:0 0 0 3px var(--blueBg);outline:none}.xf-scale-row{height:32px}.xf-scale{background:var(--inputBac);width:60px;height:28px;box-shadow:0 0 0 1px var(--borPriTra);color:var(--texPri);font:inherit;text-align:end;border:none;border-radius:6px;outline:none;padding:4px 10px;font-size:14px}.xf-scale:focus{box-shadow:0 0 0 1px var(--blue) inset, 0 0 0 1px var(--blue)}.xf-error{min-height:32px;color:var(--red);align-items:center;padding:4px 0;font-size:12px;line-height:16px;display:flex}.xf-switch-row{height:32px}.xf-switch-row .xf-label{line-height:20px}.xf-switch{box-sizing:content-box;cursor:pointer;background:#8783784d;border-radius:44px;flex-shrink:0;width:26px;height:14px;padding:2px;transition:background .2s,box-shadow .2s;display:flex;position:relative}.xf-switch.on{background:var(--blue)}.xf-switch>span{background:#fff;border-radius:44px;width:14px;height:14px;transition:transform .2s ease-out,background .2s ease-out}.xf-switch.on>span{transform:translate(12px)}.xf-switch.disabled{opacity:.4;cursor:default}@media (prefers-color-scheme:dark){:root:not([data-theme=light]) .xf-switch:not(.on){background:#caccce4d}}:root[data-theme=dark] .xf-switch:not(.on){background:#caccce4d}.xf-actions{justify-content:flex-end;align-items:center;gap:8px;margin-top:16px;display:flex}.xf-btn{white-space:nowrap;cursor:pointer;-webkit-user-select:none;user-select:none;border-radius:6px;justify-content:center;align-items:center;height:28px;padding:0 8px;font-size:14px;line-height:1.2;transition:background 20ms ease-in;display:inline-flex}.xf-btn.gray{color:var(--texSec)}.xf-btn.gray:hover{background:var(--bacIntTra)}.xf-btn.blue{background:var(--btnPriBg);color:var(--btnPriTex);font-weight:500}.xf-btn.blue:hover,.xf-btn.blue:focus-visible{background:var(--btnPriBgHi)}.xf-btn[aria-disabled=true]{opacity:.4;pointer-events:none}.menu.menu-select{z-index:1600;width:180px;min-width:180px}.menu-select .mi-icon:empty{display:none}.xf-import{flex-direction:column;gap:14px;width:min(460px,100vw - 32px);padding:20px 20px 18px;font-size:14px;display:flex}.xf-import-head{flex-direction:column;gap:2px;min-width:0;display:flex}.xf-import-title{font-size:16px;font-weight:600;line-height:1.4}.xf-import-where{color:var(--texSec);white-space:nowrap;text-overflow:ellipsis;font-size:13px;line-height:1.5;overflow:hidden}.xf-drop{border:1px dashed var(--borStrTra);color:var(--texPri);cursor:pointer;-webkit-user-select:none;user-select:none;border-radius:10px;flex-direction:column;align-items:center;gap:6px;padding:30px 16px 26px;transition:background .12s,border-color .12s;display:flex}.xf-drop:hover{background:var(--bacIntTra)}.xf-drop.dragging{border-color:var(--blue);background:var(--bluBacIntTra)}.xf-drop:focus-visible{background:var(--bacTerTra);outline:none}.xf-drop svg{width:28px;height:28px;color:var(--icoSec);stroke-width:1.4px;margin-bottom:4px;transition:color .12s}.xf-drop.dragging svg{color:var(--blue)}.xf-drop-main{line-height:20px}.xf-choose{color:var(--blue);margin-inline-start:2px}.xf-drop-kinds,.xf-import-note{color:var(--texTer);font-size:12px;line-height:16px}.pref-overlay{z-index:1500;background:var(--overlay);justify-content:center;align-items:center;padding:24px;display:flex;position:fixed;inset:0}.pref-dialog{background:var(--bacPri);width:min(880px,100%);height:min(86vh,900px);box-shadow:var(--shaOutLg);border-radius:12px;flex-direction:column;animation:.12s ease-out pop-in;display:flex;overflow:hidden}.pref-head{border-bottom:1px solid var(--borSec);flex:none;align-items:center;gap:10px;height:48px;padding:0 12px 0 20px;display:flex}.pref-title{color:var(--texPri);flex:none;font-size:14px;font-weight:600}.pref-sub{white-space:nowrap;text-overflow:ellipsis;min-width:0;color:var(--texSec);flex:1;font-size:13px;overflow:hidden}.pref-actions{flex:none;align-items:center;gap:4px;display:flex}.pref-save{height:28px;color:var(--btnPriTex);background:var(--btnPriBg);white-space:nowrap;border-radius:6px;flex:none;padding:0 10px;font-size:14px;font-weight:500}.pref-save:hover:not(:disabled),.pref-save:focus-visible{background:var(--btnPriBgHi);outline:none}.pref-save:disabled{opacity:.5;cursor:default}.pref-note{border-bottom:1px solid var(--borSec);background:var(--bacSec);color:var(--texSec);overflow-wrap:anywhere;flex:none;padding:8px 20px;font-size:13px;line-height:1.5}.pref-body{background:var(--bacPri);flex:1;min-height:0;position:relative}.pref-frame{background:var(--pageBac);border:0;width:100%;height:100%;position:absolute;inset:0}.pref-frame[data-pending]{opacity:0;pointer-events:none}.pref-loading{opacity:0;height:2px;animation:.2s ease-out .3s forwards pref-loading-in;position:absolute;top:0;left:0;right:0;overflow:hidden}.pref-loading:before{content:"";background:var(--borStrTra);border-radius:1px;width:24%;animation:1.6s ease-in-out infinite pref-loading-pass;position:absolute;top:0;bottom:0;left:0}@keyframes pref-loading-in{to{opacity:1}}@keyframes pref-loading-pass{0%{transform:translate(-100%)}to{transform:translate(417%)}}@media (prefers-reduced-motion:reduce){.pref-loading:before{width:100%;animation:none}}.comp-dialog{width:min(640px,100%);height:min(86vh,720px)}.comp-body{flex:1;min-height:0;padding:4px 20px 20px;overflow-y:auto}.comp-group{color:var(--texPri);margin:16px 0 4px;font-size:14px;font-weight:600}.comp-lead,.comp-empty{color:var(--texSec);padding:4px 0 8px;font-size:13px;line-height:1.5}.comp-problem{color:var(--texPri);margin-top:12px;font-size:13px;line-height:1.5}.comp-row{border-top:1px solid var(--borSec);align-items:center;gap:16px;padding:8px 0;display:flex}.comp-row.comp-block{gap:8px;padding:6px 0}.comp-icon{width:20px;height:20px;color:var(--icoPri);flex:none;justify-content:center;align-items:center;display:flex}.comp-icon svg{stroke-width:1.25px;width:20px;height:20px}.comp-name{min-width:0;color:var(--texPri);overflow-wrap:anywhere;flex:1;font-size:14px;line-height:20px}.comp-row.comp-pkg{padding:0;display:block}.comp-line{border-radius:6px;align-items:center;gap:8px;margin:0 -8px;padding:2px 8px;display:flex}.comp-line:hover{background:var(--bacIntTra)}.comp-head{text-align:left;min-width:0;min-height:28px;font:inherit;color:inherit;cursor:pointer;background:0 0;flex:1;align-items:center;gap:8px;padding:0;display:flex}.comp-head .comp-name{flex:0 auto}.comp-chev{width:14px;height:14px;color:var(--texTer);flex:none}.comp-chev svg{stroke-width:1.6px;transition:transform .15s ease-out}.comp-row[data-open] .comp-chev svg{transform:rotate(90deg)}.comp-tag{color:var(--texTer);flex:none;margin-left:auto;padding-left:8px;font-size:12px}.comp-detail{flex-direction:column;gap:2px;padding:0 0 10px 28px;display:flex}.comp-meta{max-width:100%;color:var(--texTer);overflow-wrap:anywhere;font-size:12px;line-height:18px;display:block}.comp-note{color:var(--texSec);overflow-wrap:anywhere;font-size:13px;line-height:18px}.comp-state{color:var(--texTer)}.comp-opts{flex-direction:column;margin-top:6px;display:flex}.comp-opt{text-align:left;font:inherit;color:inherit;cursor:pointer;background:0 0;border-radius:6px;align-items:center;gap:16px;margin:0 -8px;padding:6px 8px;display:flex}.comp-opt:hover{background:var(--bacIntTra)}.comp-opt-text{flex-direction:column;flex:1;gap:1px;min-width:0;display:flex}.comp-opt .comp-toggle-name{color:var(--texPri);font-size:14px;line-height:20px}.comp-opt-hint{color:var(--texSec);overflow-wrap:anywhere;font-size:13px;line-height:18px}.comp-opt .mi-switch{margin:0}.comp-opt[aria-disabled=true]{cursor:default;opacity:.5}.comp-opt[aria-disabled=true]:hover{background:0 0}.comp-packs{grid-template-columns:repeat(auto-fill,minmax(176px,1fr));gap:8px;margin:4px 0 8px;display:grid}.comp-pack{background:var(--bacIntTra);border-radius:10px;align-items:center;gap:8px;min-height:64px;padding:0 12px 0 0;display:flex;position:relative}.comp-pack:hover{background:var(--bacTerTra)}.comp-pack-open{text-align:left;min-width:0;font:inherit;color:inherit;cursor:pointer;background:0 0;border-radius:10px 0 0 10px;flex:1;align-self:stretch;align-items:center;gap:10px;padding:10px 0 10px 12px;display:flex}.comp-pack-open:focus-visible,.comp-pack-add:focus-visible{outline:2px solid var(--blue);outline-offset:-2px}.comp-pack-icon{background:var(--bacPri);width:32px;height:32px;color:var(--icoPri);border-radius:8px;flex:none;justify-content:center;align-items:center;font-size:18px;line-height:1;display:flex}.comp-pack-icon svg{stroke-width:1.25px;width:18px;height:18px}.comp-pack-words{flex-direction:column;flex:1;gap:2px;min-width:0;display:flex}.comp-pack-name{color:var(--texPri);white-space:nowrap;text-overflow:ellipsis;font-size:14px;font-weight:500;line-height:20px;overflow:hidden}.comp-pack-meta{min-width:0;color:var(--texTer);white-space:nowrap;text-overflow:ellipsis;gap:8px;font-size:12px;line-height:16px;display:flex;overflow:hidden}.comp-pack-author{text-overflow:ellipsis;min-width:0;overflow:hidden}.comp-pack[data-off] .comp-pack-name{color:var(--texSec)}.comp-pack-add{font:inherit;color:var(--texSec);cursor:pointer;justify-content:center;padding:0 12px}.comp-pack-add .comp-pack-icon{width:20px;height:20px;color:var(--texSec);background:0 0}.comp-pack-add .comp-pack-icon svg{stroke-width:1.6px;width:16px;height:16px}.comp-pack-add .comp-pack-name{color:var(--texSec);flex:none;font-weight:400}.comp-pack-add[aria-expanded=true]{background:var(--bacTerTra)}.comp-import{flex-direction:column;align-items:flex-start;gap:4px;margin:0 0 8px;display:flex}.comp-import-row{align-items:center;gap:8px;width:100%;display:flex}.comp-import-row .pop-input{flex:1;min-width:0}.comp-import-row .dialog-btn{flex:none;height:28px;padding:0 12px;font-size:13px}.comp-import-pick{height:24px;font:inherit;color:var(--texSec);cursor:pointer;background:0 0;border-radius:6px;margin:0 -6px;padding:0 6px;font-size:13px}.comp-import-pick:hover:not(:disabled){background:var(--bacIntTra)}.comp-import-error{color:var(--red);overflow-wrap:anywhere;font-size:13px;line-height:1.5}.comp-back{height:26px;font:inherit;color:var(--texSec);cursor:pointer;background:0 0;border-radius:6px;align-items:center;gap:4px;margin:0 0 6px -6px;padding:0 8px 0 6px;font-size:13px;display:inline-flex}.comp-back:hover{background:var(--bacIntTra)}.comp-pack-head{align-items:center;gap:10px;padding:2px 0 6px;display:flex}.comp-pack-view>.comp-note{margin-bottom:6px}.comp-pack-view .comp-lead{padding-top:6px}.comp-toggle{cursor:pointer;background:0 0;flex:none;align-items:center;height:24px;padding:0;display:flex}.comp-toggle .mi-switch{margin:0}.comp-toggle[aria-disabled=true]{cursor:default;opacity:.5}.present{z-index:2000;background:var(--bacPri);position:fixed;inset:0}.present-frame{background:var(--pageBac);transform-origin:0 0;border:0;width:100%;height:100%;position:absolute;top:0;left:0}.present-ink{pointer-events:none;touch-action:none;width:100%;height:100%;position:absolute;inset:0}.present:is([data-tool=laser],[data-tool=pen],[data-tool=marker],[data-tool=eraser]) .present-ink{pointer-events:auto}.present[data-tool=laser] .present-ink{cursor:none}.present[data-tool=pen] .present-ink{cursor:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='16' height='16'%3E%3Ccircle cx='8' cy='8' r='4' fill='%23e03e3e' stroke='white' stroke-width='1.5'/%3E%3C/svg%3E") 8 8,crosshair}.present[data-tool=marker] .present-ink{cursor:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='22' height='22'%3E%3Crect x='3' y='3' width='16' height='16' rx='5' fill='rgba(255,204,0,.55)' stroke='rgba(120,90,0,.55)' stroke-width='1'/%3E%3C/svg%3E") 11 11,crosshair}.present[data-tool=eraser] .present-ink{cursor:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='24' height='24'%3E%3Ccircle cx='12' cy='12' r='10' fill='rgba(140,140,140,.28)' stroke='rgba(110,110,110,.9)' stroke-width='1.5'/%3E%3C/svg%3E") 12 12,default}.present-notice{background:var(--tipBg);color:var(--tipTex);box-shadow:var(--shaOutLg);white-space:nowrap;pointer-events:none;border-radius:8px;padding:8px 14px;font-size:14px;position:absolute;bottom:24px;left:50%;transform:translate(-50%)}.present-bar{background:var(--popBac);box-shadow:var(--shaOutLg);border-radius:10px;align-items:center;gap:2px;padding:4px;transition:opacity .3s;display:flex;position:absolute;bottom:16px;left:16px}.present-bar.idle{opacity:.25}.present-btn{width:32px;height:32px;color:var(--icoPri);border-radius:6px;justify-content:center;align-items:center;display:flex}.present-btn:hover{background:var(--bacIntTra)}.present-btn[aria-pressed=true]{background:var(--bacTerTra);color:var(--texPri)}.present-btn:disabled{opacity:.35;pointer-events:none}.present-btn svg{width:18px;height:18px}.present-sep{background:var(--borSec);flex:none;width:1px;height:18px;margin:0 4px}.present-zoom{min-width:48px;height:32px;color:var(--texPri);font-variant-numeric:tabular-nums;text-align:center;border-radius:6px;flex:none;padding:0 4px;font-size:13px}.present-zoom:hover{background:var(--bacIntTra)}.present-ink{mix-blend-mode:multiply}:root[data-theme=dark] .present-ink{mix-blend-mode:screen}@media (prefers-color-scheme:dark){:root:not([data-theme=light]) .present-ink{mix-blend-mode:screen}}body:has(.present) .toast{display:none}.sb-container{z-index:20;width:var(--sb-w);background:var(--sidBac);transition:width var(--dur) ease;flex:none;position:relative}.sb-container.collapsed{width:0}.sb-anchor{z-index:9;width:0;position:absolute;top:0;bottom:0;left:0}.sidebar{width:var(--sb-w);height:100%;transition-property:width,opacity,transform,visibility;transition-duration:var(--dur);flex-direction:column;transition-timing-function:ease;display:flex;position:relative}.sidebar .float-bg{z-index:-1;background:var(--sidBac);box-shadow:var(--shaOutLg);border-radius:0 14px 14px 0;display:none;position:absolute;inset:0}.sb-inner{flex-direction:column;flex:1;min-height:0;display:flex;overflow:hidden}.sidebar.floating{height:calc(100vh - 91px);transform:translateX(calc(20px - var(--sb-w))) translateY(59px);opacity:0;visibility:hidden;pointer-events:none}.sidebar.floating .float-bg{display:block}.sidebar.floating .sb-inner{border-radius:0 14px 14px 0}.sidebar.floating:before{content:"";height:15px;position:absolute;top:-15px;left:0;right:0}.sidebar.floating.peek{opacity:1;visibility:visible;pointer-events:auto;transform:translate(0)translateY(59px)}.sidebar.mobile{height:auto;width:min(var(--sb-w), 86vw);visibility:hidden;pointer-events:none;position:fixed;top:0;bottom:0;left:0;transform:translate(-100%)}.sidebar.mobile .float-bg{display:block}.sidebar.mobile .sb-inner{border-radius:0 14px 14px 0}.sidebar.mobile.mobile-open{visibility:visible;pointer-events:auto;transform:none}.sb-backdrop{z-index:1;background:var(--overlay);display:none;position:fixed;inset:0}.sb-backdrop.show{display:block}.sb-edge{z-index:8;width:32px;display:none;position:fixed;top:44px;bottom:0;left:0}.app.peekable .sb-edge{display:block}.sb-resizer{cursor:col-resize;z-index:10;width:12px;position:absolute;top:0;bottom:0;right:-11px}.sb-resizer:after{content:"";background:0 0;width:2px;transition:background .15s;position:absolute;top:0;bottom:0;left:-1px}.sb-resizer:hover:after,body.resizing .sb-resizer:after{background:var(--borStrTra)}body.resizing,body.resizing *{cursor:col-resize!important;-webkit-user-select:none!important;user-select:none!important}body.resizing .sb-container,body.resizing .sidebar{transition:none!important}.sb-head{flex-direction:column;flex:none;gap:1px;padding:8px 8px 4px;transition:box-shadow .15s;display:flex}.sb-head.scrolled{box-shadow:0 1px 0 var(--borSec)}.sb-top{align-items:center;gap:5px;height:28px;margin-bottom:7px;padding-left:5px;display:flex}.sidebar.floating .sb-top{display:none}.sb-brand{white-space:nowrap;min-width:0;color:var(--texPri);cursor:default;-webkit-user-select:none;user-select:none;font-family:Iowan Old Style,Palatino Linotype,Palatino,Book Antiqua,Georgia,serif;font-size:19px;font-weight:400;line-height:28px;overflow:hidden}.sb-act{min-width:0;height:30px;color:var(--texSec);text-align:left;border-radius:6px;align-items:center;gap:8px;padding:0 8px;font-size:14px;font-weight:500;transition:background 20ms ease-in;display:flex}.sb-act:hover{background:var(--bacIntTra)}.sb-act-icon{width:22px;height:20px;color:var(--sidIco);flex:none;justify-content:center;align-items:center;display:flex}.sb-act-icon svg{width:18px;height:18px}.sb-act-label{white-space:nowrap;text-overflow:ellipsis;min-width:0;overflow:hidden}.sb-brand.home{cursor:pointer}.sb-rows{flex-direction:column;gap:1px;display:flex;position:relative}.sb-page{cursor:pointer;-webkit-user-select:none;user-select:none;outline:none}.sb-act.selected{background:var(--bacIntTra);color:var(--texPri)}.sb-act.selected:hover,.sb-act.menu-open,.sb-page:focus-visible{background:var(--bacTerTra)}.sb-page .pg-icon{justify-content:center;align-items:center;width:20px;height:20px;display:flex}.sb-page.renaming{cursor:default}.sb-page .sb-page-actions{margin-right:-2px;padding-right:0}.sb-page:hover .sb-page-actions,.sb-page.menu-open .sb-page-actions{display:flex}.sb-act.drag-src{opacity:.4}body.dragging .sb-act:not(.selected):hover{background:0 0}body.dragging .sb-page-actions{display:none!important}.sb-page .row-rename{margin:0 -2px 0 -6px;font-weight:400}.sb-scroll{scrollbar-width:thin;scrollbar-color:var(--scrollThumb) transparent;flex:1;min-height:0;padding:6px 0 12px;position:relative;overflow:hidden auto}.section{margin:0 8px 4px}.section.expanded{padding-bottom:12px}.sec-head{-webkit-user-select:none;user-select:none;align-items:center;height:30px;padding:0 2px;display:flex}.sec-toggle{border-radius:6px;flex:0 auto;align-items:center;gap:2px;min-width:0;height:22px;padding:0 4px 0 6px;display:inline-flex}.sec-text{white-space:nowrap;text-overflow:ellipsis;min-width:0;line-height:16px;overflow:hidden}.sec-toggle:hover,.sec-head.menu-open .sec-toggle{background:var(--bacIntTra)}.sec-label{color:var(--texTer);font-size:12px;font-weight:500;line-height:16px}.sec-chev{width:12px;height:12px;color:var(--texTer);opacity:0;flex:none;transition:opacity .1s}.sec-chev svg{stroke-width:1.8px;transition:transform .2s ease-out}.section.expanded .sec-chev svg{transform:rotate(90deg)}.sec-toggle:hover .sec-chev,.sec-head.menu-open .sec-chev{opacity:1}.tree{margin-top:1px}.row{height:30px;padding:5px 8px 5px calc(8px + var(--depth,0) * 8px);cursor:pointer;-webkit-user-select:none;user-select:none;color:var(--texAcc);border-radius:6px;align-items:center;margin-bottom:1px;font-size:14px;display:flex;position:relative}.row:hover,.row.menu-open{background:var(--bacIntTra)}.row.selected{background:var(--bacIntTra);color:var(--texPri)}.row.selected:hover,.row.selected.menu-open{background:var(--bacTerTra)}.row-icon{flex:none;justify-content:center;align-items:center;width:22px;height:20px;margin-right:8px;display:flex;position:relative}.row-chevron{width:20px;height:20px;color:var(--texTer);opacity:0;border-radius:4px;justify-content:center;align-items:center;display:flex;position:absolute;top:0;left:1px}.row-chevron svg{stroke-width:1.8px;width:12px;height:12px;transition:transform .2s ease-out}.node.open>.row .row-chevron svg{transform:rotate(90deg)}.row.has-kids:hover .row-chevron{opacity:1}.row.has-kids:hover .pg-icon{opacity:0}.row-chevron:hover{background:var(--bacTerTra)}.row-title{white-space:nowrap;text-overflow:ellipsis;flex:0 auto;min-width:0;line-height:21px;overflow:hidden}.row-actions{flex:none;align-items:center;gap:2px;margin-left:auto;padding-left:4px;display:none}.row:hover .row-actions,.row.menu-open .row-actions{display:flex}.row.renaming{cursor:default}.row.renaming .row-actions{display:none}.row-rename{background:var(--inputBac);min-width:0;height:24px;color:var(--texPri);font:inherit;box-shadow:inset 0 0 0 1px var(--blueLine), 0 0 0 2px var(--blueBg);border:0;border-radius:4px;outline:none;flex:1;margin:0 -2px 0 -6px;padding:0 6px;font-size:14px}@media (hover:none){.row.has-kids .row-chevron{opacity:1}.row.has-kids .pg-icon{opacity:0}}body.dragging,body.dragging *{cursor:grabbing!important;-webkit-user-select:none!important;user-select:none!important}body.dragging .row:not(.selected):hover{background:0 0}body.dragging .row-actions{display:none!important}body.dragging .row:hover .row-chevron{opacity:0}body.dragging .row:hover .pg-icon{opacity:1}.row.drag-src{opacity:.4}.row.drop-inside{background:var(--blueBg)!important}.drop-line{background:var(--blueLine);pointer-events:none;z-index:5;border-radius:2px;height:3px;display:none;position:absolute}.drop-line.show{display:block}.drag-ghost{z-index:3000;pointer-events:none;background:var(--popBac);height:30px;color:var(--texPri);box-shadow:var(--shaOutLg);opacity:.9;white-space:nowrap;border-radius:6px;align-items:center;gap:8px;padding:0 10px 0 8px;font-size:14px;display:flex;position:fixed;top:0;left:0;overflow:hidden}.drag-ghost .t{text-overflow:ellipsis;overflow:hidden}.sb-foot{flex:none;align-items:center;gap:4px;height:44px;padding:0 8px;display:flex}.ws-btn{min-width:0;height:28px;color:var(--texSec);text-align:left;border-radius:6px;flex:1;align-items:center;gap:8px;padding:0 6px 0 8px;font-size:14px;font-weight:500;display:flex}.ws-btn svg{width:18px;height:18px;color:var(--sidIco);flex:none}.ws-btn:hover,.ws-btn.menu-open{background:var(--bacIntTra)}.ws-name{white-space:nowrap;text-overflow:ellipsis;min-width:0;overflow:hidden}@media (width<=768px){.sb-resizer{display:none}}.sb-note{color:var(--texTer);margin:4px 16px;font-size:13px}.sb-note.inset{margin:2px 8px 4px;padding-left:8px}.ws-dot{background:var(--texDis);border-radius:50%;flex:none;width:7px;height:7px}.ws-dot.ready{background:var(--gre-tx)}.ws-dot.loading{background:var(--yel-tx)}.ws-dot.offline,.ws-dot.error{background:var(--red-tx)}.sec-head{position:relative}.sec-actions{flex:none;align-items:center;gap:2px;margin-left:auto;padding-left:4px;padding-right:6px;display:none}.sec-head:hover .sec-actions,.sec-head.menu-open .sec-actions{display:flex}.sec-head .row-rename{flex:none;width:calc(100% - 8px);height:24px;margin:0 4px;font-size:12px}body.dragging .sec-actions{display:none!important}.section.drag-src{opacity:.4}.sb-empty{height:26px;margin:2px 0 4px;padding:0 8px 0 38px;line-height:26px}.sb-ext-note{overflow-wrap:anywhere;line-height:1.5}.row-tag{min-width:0;color:var(--texTer);white-space:nowrap;text-align:right;text-overflow:ellipsis;flex:1 1 0;padding-left:6px;font-size:12px;overflow:hidden}.row:hover .row-tag,.row.menu-open .row-tag{display:none}.link-form{padding:0 0 2px}.link-field{padding:2px 12px 6px;display:block}.link-label{color:var(--texSec);margin-bottom:4px;font-size:12px;display:block}.link-error{color:var(--red);margin:0 12px 6px;font-size:13px;line-height:1.5}.link-actions{justify-content:flex-end;gap:8px;padding:6px 12px 4px;display:flex}.link-actions .dialog-btn{height:28px;padding:0 12px;font-size:13px}.row.missing .row-title,.row.missing .pg-icon{color:var(--texTer);opacity:.7}.sec-above{color:var(--texTer);margin-left:4px;font-size:12px;font-weight:400;line-height:16px}.project-form{padding:0 0 2px}.project-path{align-items:center;gap:8px;padding:2px 12px 8px;display:flex}.project-path .pop-input{flex:1;min-width:0}.project-path .dialog-btn{flex:none;height:28px;padding:0 12px;font-size:13px}.project-list{border-top:1px solid var(--borSec);scrollbar-width:thin;scrollbar-color:var(--scrollThumb) transparent;max-height:300px;padding:4px 6px;overflow-y:auto}.project-row{height:30px;padding:5px 8px 5px calc(4px + var(--depth,0) * 8px);cursor:pointer;-webkit-user-select:none;user-select:none;color:var(--texAcc);border-radius:6px;align-items:center;gap:8px;margin-bottom:1px;font-size:14px;display:flex}.project-row:hover{background:var(--bacIntTra)}.project-row.selected{background:var(--bacIntTra);color:var(--texPri)}.project-row.selected:hover{background:var(--bacTerTra)}.project-toggle{width:20px;height:20px;color:var(--texTer);border-radius:4px;flex:none;justify-content:center;align-items:center;display:flex}.project-toggle:hover:not(:disabled){background:var(--bacTerTra)}.project-toggle svg{stroke-width:1.8px;width:12px;height:12px;transition:transform .2s ease-out}.project-toggle[aria-expanded=true] svg{transform:rotate(90deg)}.project-toggle:disabled{visibility:hidden}.project-row .mi-icon{color:var(--sidIco)}.project-document{padding-left:calc(4px + 28px + var(--depth,0) * 8px)}.project-above{color:var(--texTer);margin-left:6px;font-size:12px;font-weight:400}.project-count{color:var(--texTer);flex:none;font-size:12px}.tb-right .icon-btn.annot-open,.tb-right .icon-btn.annot-open:hover{background:var(--bacTerTra)}.menu.annot-list{width:320px;margin-top:4px}.annot-list .menu-scroll{max-height:384px;overflow-y:auto}.annot-list .menu-scroll .menu-item{height:44px}.annot-list .menu-scroll .mi-icon{display:none}.topbar{background:var(--bacPri);z-index:5;flex:none;align-items:center;gap:8px;height:44px;padding:0 12px;display:flex;position:relative}.topbar.tb-page{background:var(--galleryPageBac)}.tb-left{flex:1;align-items:center;min-width:0;display:flex}.tb-menu{color:var(--icoPri);margin:0 4px 0 1px;display:none}.app.sb-collapsed .tb-menu{display:inline-flex}.crumbs{align-items:center;min-width:0;display:flex;overflow:hidden}.crumb-wrap{display:contents}.crumb{white-space:nowrap;min-width:0;max-width:220px;height:24px;color:var(--texPri);border-radius:6px;align-items:center;gap:6px;padding:2px 6px;font-size:14px;display:inline-flex}.crumb:hover{background:var(--bacIntTra)}.crumb .t{text-overflow:ellipsis;overflow:hidden}.crumb .emoji{font-size:14px;line-height:1}.crumb.crumb-rename{width:220px;padding:0}.crumb-rename .row-rename{margin:0}.crumb-sep{color:var(--crumbSep);-webkit-user-select:none;user-select:none;flex:none;margin:0 1px;font-size:13px}.crumb-pop{z-index:1000;background:var(--popBac);width:180px;max-height:calc(100vh - 16px);box-shadow:var(--shaOutLg);-webkit-user-select:none;user-select:none;scrollbar-width:thin;scrollbar-color:var(--scrollThumb) transparent;border-radius:10px;flex-direction:column;gap:1px;padding:4px;font-size:14px;line-height:1.2;display:flex;position:fixed;top:0;left:0;overflow-y:auto}.crumb-pop-head{color:var(--texSec);white-space:nowrap;flex:none;margin:6px 0 8px;padding:0 8px;font-size:12px;font-weight:500}.crumb-pop-item{cursor:pointer;height:28px;color:var(--texPri);border-radius:6px;flex:none;align-items:center;gap:8px;padding:0 8px;display:flex}.crumb-pop-item:hover,.crumb-pop-item.open,.crumb-pop-item.trigger{background:var(--bacIntTra)}.crumb-pop-item.current{background:var(--bluBacIntTra)}.crumb-pop-item .t{white-space:nowrap;text-overflow:ellipsis;flex:1;min-width:0;overflow:hidden}.crumb-pop-item.more{color:var(--texSec)}.crumb-pop-arrow{width:16px;height:16px;color:var(--texDis);flex:none}.crumb-pop-arrow svg{stroke-width:1.8px}.tb-right{flex:none;align-items:center;gap:2px;display:flex}.tb-right .icon-btn{color:var(--icoPri)}.tb-right .icon-btn.on{color:var(--star)}.tb-right .icon-btn.menu-open{background:var(--bacIntTra)}.edited{color:var(--texTer);white-space:nowrap;margin-right:8px;font-size:14px}@media (width<=1000px){.edited{display:none}}.session-badge{white-space:nowrap;border-radius:10px;flex:none;margin-left:8px;padding:1px 8px;font-size:12px;line-height:20px}.session-badge.muted{color:var(--texTer)}.session-badge.warn{color:var(--ora-tx);background:var(--ora-bg)}.session-badge.danger{color:var(--red-tx);background:var(--red-bg)}.menu.look-menu{width:224px;max-width:none;padding-bottom:8px}.look-fonts,.look-row{gap:4px;padding:0 8px;display:flex}.look-fonts{margin-bottom:4px}.look-font,.look-option{min-width:0;color:var(--texPri);font:inherit;cursor:pointer;background:0 0;border:0;border-radius:6px;flex:1 1 0;transition:background 20ms ease-in}.look-font{flex-direction:column;align-items:center;padding:8px 4px 6px;display:flex}.look-glyph{white-space:nowrap;height:30px;font-size:24px;line-height:30px}.look-caption{color:var(--texSec);white-space:nowrap;text-overflow:ellipsis;max-width:100%;margin-top:2px;font-size:12px;line-height:16px;overflow:hidden}.look-option{white-space:nowrap;justify-content:center;align-items:center;height:28px;padding:0 4px;font-size:14px;display:flex}.look-font:hover,.look-option:hover{background:var(--bacIntTra)}.look-row.look-off .look-option{opacity:.45}.look-font.on .look-glyph,.look-option.on{color:var(--blue)}.look-font:focus-visible,.look-option:focus-visible{background:var(--bacTerTra);outline:none}.look-menu .menu-sep{margin:8px 12px 4px}.link-crumb{cursor:default}.link-crumb:hover{background:0 0}.link-crumb .pg-icon{flex:none;justify-content:center;align-items:center;width:18px;height:18px;display:flex}.link-crumb .pg-icon svg,.link-crumb .pg-icon img{width:16px;height:16px}.tb-open{color:var(--texSec);margin-right:2px}
|