@heycys/gallery 0.1.1 → 0.1.2
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 +1 -1
- package/browser/editor/components/columns/page.mjs +4 -4
- package/browser/editor/components/embed/index.mjs +2 -2
- package/browser/editor/components/flowchart/add.mjs +7 -6
- package/browser/editor/components/flowchart/page.mjs +1 -1
- package/browser/editor/components/icons.mjs +8 -0
- package/browser/editor/components/image/crop.mjs +6 -9
- package/browser/editor/components/installed/index.mjs +11 -4
- package/browser/editor/components/installed/page.mjs +27 -16
- package/browser/editor/components/installed/served.mjs +6 -5
- package/browser/editor/components/instances.mjs +18 -0
- package/browser/editor/components/list/page.mjs +3 -6
- package/browser/editor/components/registry.mjs +13 -4
- package/browser/editor/components/table/index.mjs +59 -2
- package/browser/editor/components/table/page.mjs +1 -1
- package/browser/editor/page/annotate/card.mjs +3 -6
- package/browser/editor/page/autosave.mjs +310 -37
- package/browser/editor/page/board/client.mjs +57 -0
- package/browser/editor/page/board/hint.mjs +145 -0
- package/browser/editor/page/board/history.mjs +119 -0
- package/browser/editor/page/board/index.mjs +970 -0
- package/browser/editor/page/board/settings.mjs +209 -0
- package/browser/editor/page/caret.mjs +1 -1
- package/browser/editor/page/changes/bar.mjs +6 -14
- package/browser/editor/page/changes/index.mjs +2 -2
- package/browser/editor/page/clipboard/import/html.mjs +29 -6
- package/browser/editor/page/clipboard/import/inline.mjs +32 -0
- package/browser/editor/page/clipboard/import/markdown.mjs +58 -13
- package/browser/editor/page/clipboard/import/read.mjs +6 -1
- package/browser/editor/page/clipboard/import/to-blocks.mjs +44 -12
- package/browser/editor/page/clipboard/import/yuque.mjs +622 -0
- package/browser/editor/page/clipboard/index.mjs +124 -13
- package/browser/editor/page/clipboard/own/blocks.mjs +11 -11
- package/browser/editor/page/clipboard/own/chart-keys.mjs +41 -28
- package/browser/editor/page/clipboard/own/selection.mjs +1 -1
- package/browser/editor/page/columns/index.mjs +48 -46
- package/browser/editor/page/commit.mjs +80 -22
- package/browser/editor/page/conflicts.mjs +7 -7
- package/browser/editor/page/core.mjs +31 -15
- package/browser/editor/page/custom-page.mjs +106 -0
- package/browser/editor/page/editor.mjs +51 -14
- package/browser/editor/page/emoji-picker/styles.mjs +7 -12
- package/browser/editor/page/emoji-picker/upload.mjs +2 -2
- package/browser/editor/page/handle/index.mjs +5 -8
- package/browser/editor/page/history.mjs +24 -4
- package/browser/editor/page/links/index.mjs +5 -3
- package/browser/editor/page/links/pages.mjs +27 -9
- package/browser/editor/page/look.mjs +54 -3
- package/browser/editor/page/margin.mjs +18 -3
- package/browser/editor/page/media-menu/index.mjs +6 -7
- package/browser/editor/page/menu.mjs +18 -7
- package/browser/editor/page/notices.mjs +2 -2
- package/browser/editor/page/page-objects.mjs +13 -2
- package/browser/editor/page/panel.mjs +4 -9
- package/browser/editor/page/present-links.mjs +11 -2
- package/browser/editor/page/resize/index.mjs +42 -29
- package/browser/editor/page/served.mjs +14 -0
- package/browser/editor/page/session.mjs +48 -4
- package/browser/editor/page/slash-menu/index.mjs +3 -3
- package/browser/editor/page/table/cells.mjs +102 -46
- package/browser/editor/page/table/icons.mjs +2 -0
- package/browser/editor/page/table/index.mjs +29 -10
- package/browser/editor/page/table/pictures.mjs +299 -0
- package/browser/editor/page/table/views.mjs +150 -0
- package/browser/editor/page/text-select/index.mjs +26 -12
- package/browser/editor/page/todo-writes.mjs +75 -0
- package/browser/editor/page/typing/index.mjs +53 -3
- package/browser/editor/page/ui.mjs +13 -0
- package/browser/shared/block-packs.mjs +404 -0
- package/browser/shared/board-places.mjs +224 -0
- package/browser/shared/card-size.mjs +59 -0
- package/browser/shared/colors.mjs +3 -2
- package/browser/shared/component-catalog.mjs +323 -46
- package/browser/shared/component-source.mjs +37 -0
- package/browser/shared/components/index.mjs +12 -3
- package/browser/shared/components/installed.mjs +35 -3
- package/browser/shared/components/page.mjs +18 -8
- package/browser/shared/components/state.mjs +5 -1
- package/browser/shared/document-look.mjs +10 -5
- package/browser/shared/drafts.mjs +432 -0
- package/browser/shared/extension-sidebar.mjs +126 -0
- package/browser/shared/extensions.mjs +79 -0
- package/browser/shared/file-table.mjs +101 -0
- package/browser/shared/i18n/en.mjs +307 -27
- package/browser/shared/json-layout.mjs +47 -0
- package/browser/shared/net-cache.mjs +133 -0
- package/browser/shared/net-keys.mjs +32 -0
- package/browser/shared/net-policy.mjs +177 -0
- package/browser/shared/outline-shape.mjs +128 -0
- package/browser/shared/outline.mjs +331 -67
- package/browser/shared/pack-manifest.mjs +77 -0
- package/browser/shared/page-address.mjs +6 -3
- package/browser/shared/page-cards.mjs +308 -0
- package/browser/shared/page-links.mjs +69 -6
- package/browser/shared/pages.mjs +388 -0
- package/browser/shared/paths.mjs +6 -0
- package/browser/shared/preview-server.mjs +3 -7
- package/browser/shared/session.mjs +8 -1
- package/browser/shared/shipped-blocks.mjs +299 -0
- package/browser/shared/table-chart.mjs +33 -1
- package/browser/shared/todos.mjs +83 -0
- package/browser/shared/user-directory.mjs +24 -0
- package/browser/shared/versions.mjs +14 -0
- package/browser/shared/web-links.mjs +134 -0
- package/browser/shared/workspace-columns.mjs +120 -0
- package/browser/shared/workspace-name.mjs +154 -0
- package/browser/shared/workspace-query.mjs +125 -0
- package/browser/shared/workspace-registry.mjs +272 -0
- package/browser/shared/workspace.mjs +171 -20
- package/dist/chunk-2NRBY6AJ.mjs +2 -0
- package/dist/chunk-32ZUEFZ7.mjs +2 -0
- package/dist/chunk-35NQ4PLQ.mjs +2 -0
- package/dist/chunk-3KJHLHUO.mjs +2 -0
- package/dist/chunk-3NJACR4W.mjs +2 -0
- package/dist/chunk-4AV456RQ.mjs +2 -0
- package/dist/chunk-4OZWXZE5.mjs +5 -0
- package/dist/chunk-5XYHDBJ5.mjs +2 -0
- package/dist/chunk-5ZJA7CXT.mjs +2 -0
- package/dist/chunk-6A53MZYZ.mjs +2 -0
- package/dist/chunk-6EXH3ORZ.mjs +166 -0
- package/dist/chunk-6EZ7FNIK.mjs +3 -0
- package/dist/{chunk-V5JTW2LH.mjs → chunk-6QBHU4DF.mjs} +1 -1
- package/dist/{chunk-Y6RLRPG3.mjs → chunk-6VTU6KEO.mjs} +1 -1
- package/dist/chunk-B4P2CM2J.mjs +3 -0
- package/dist/{chunk-FDLXYYG4.mjs → chunk-BPL64HGA.mjs} +1 -1
- package/dist/chunk-BVEFGE4B.mjs +2 -0
- package/dist/{chunk-LS4F7JUM.mjs → chunk-BZ5RAF7L.mjs} +1 -1
- package/dist/chunk-CRJEG7MT.mjs +2 -0
- package/dist/{chunk-LCTHTZIL.mjs → chunk-D4CKRD3V.mjs} +91 -91
- package/dist/chunk-D4EURAX4.mjs +4 -0
- package/dist/chunk-DQCE7TJY.mjs +5 -0
- package/dist/chunk-DR73Y2UJ.mjs +3 -0
- package/dist/{chunk-TMYZB6AV.mjs → chunk-EKNHM3P4.mjs} +1 -1
- package/dist/{chunk-GB5SOYQJ.mjs → chunk-ERLAIBOA.mjs} +2 -2
- package/dist/chunk-EURLTOTZ.mjs +4 -0
- package/dist/chunk-FJYN7RTH.mjs +4 -0
- package/dist/chunk-FWNRPMCJ.mjs +12 -0
- package/dist/chunk-FWW4CSAZ.mjs +2 -0
- package/dist/{chunk-2B5E4CDJ.mjs → chunk-GPIWQ4X4.mjs} +1 -1
- package/dist/chunk-GY3FAUVM.mjs +2 -0
- package/dist/chunk-HLYV7RIH.mjs +2 -0
- package/dist/chunk-HMYTM3GT.mjs +15 -0
- package/dist/chunk-IA4PSIMD.mjs +2 -0
- package/dist/chunk-JEUK3ZO7.mjs +2 -0
- package/dist/chunk-KTKHRC6H.mjs +2 -0
- package/dist/chunk-L7UP52JO.mjs +2 -0
- package/dist/{chunk-SYGN7GLU.mjs → chunk-MHW7ZKOU.mjs} +1 -1
- package/dist/chunk-N76HWBA3.mjs +10 -0
- package/dist/chunk-N7AZZLGT.mjs +548 -0
- package/dist/chunk-NAMN3RAF.mjs +2 -0
- package/dist/{chunk-5ZKJ3H4P.mjs → chunk-NFMCP2HI.mjs} +3 -3
- package/dist/chunk-NG375ILQ.mjs +2 -0
- package/dist/chunk-NVRNLK25.mjs +6 -0
- package/dist/chunk-NWFBE2YA.mjs +2 -0
- package/dist/chunk-NWR2LT5B.mjs +2 -0
- package/dist/chunk-OJKMINIU.mjs +20 -0
- package/dist/{chunk-4FS7Z7WR.mjs → chunk-OUUP3WKT.mjs} +1 -1
- package/dist/{chunk-BGGDRNYQ.mjs → chunk-OW5NWPOJ.mjs} +1 -1
- package/dist/chunk-PAREWQGB.mjs +4 -0
- package/dist/chunk-POQSE4C2.mjs +2 -0
- package/dist/chunk-PUOQ65NC.mjs +2 -0
- package/dist/{chunk-XNROSH2T.mjs → chunk-PVER7LSC.mjs} +2 -2
- package/dist/chunk-PZDLJJTJ.mjs +3 -0
- package/dist/chunk-Q47PLKIJ.mjs +15 -0
- package/dist/chunk-Q4UEPUWF.mjs +2 -0
- package/dist/chunk-QKXMPUXC.mjs +2 -0
- package/dist/chunk-QOUEFUCH.mjs +16 -0
- package/dist/chunk-RFDZXFJF.mjs +13 -0
- package/dist/chunk-RKPWLGZ3.mjs +4 -0
- package/dist/chunk-RMECZA2K.mjs +2 -0
- package/dist/{chunk-7DTINW6U.mjs → chunk-SQ6Y2ZMA.mjs} +2 -2
- package/dist/chunk-SX4LJYT6.mjs +8 -0
- package/dist/chunk-SXHBYZST.mjs +16 -0
- package/dist/chunk-TANZRINB.mjs +2 -0
- package/dist/chunk-TEZAWDSQ.mjs +2 -0
- package/dist/chunk-UBBRTJ2R.mjs +24 -0
- package/dist/chunk-UFNYFFKO.mjs +20 -0
- package/dist/chunk-UGWYKHBL.mjs +170 -0
- package/dist/chunk-UKSHDZZ6.mjs +2 -0
- package/dist/chunk-UNOYVIYR.mjs +2 -0
- package/dist/{chunk-E7LWZRXY.mjs → chunk-V6RIYQZZ.mjs} +1 -1
- package/dist/chunk-VJPFVNNW.mjs +15 -0
- package/dist/chunk-VS3ZMVGX.mjs +5 -0
- package/dist/chunk-VTKNEYT3.mjs +6 -0
- package/dist/chunk-VXACTLO3.mjs +3 -0
- package/dist/chunk-YI43RG4P.mjs +2 -0
- package/dist/chunk-YQGT4AB2.mjs +6 -0
- package/dist/chunk-ZB4H7ZN4.mjs +2 -0
- package/dist/{chunk-IVDLMMBD.mjs → chunk-ZHEHPMBK.mjs} +1 -1
- package/dist/chunk-ZTHICSSF.mjs +2 -0
- package/dist/chunk-ZUNVAXLH.mjs +2 -0
- package/dist/chunk-ZWPMCK7P.mjs +2 -0
- package/dist/cli.mjs +1 -1
- package/dist/server.mjs +1 -1
- package/dist/{chunk-U6KNPJPR.mjs → update-fetch.mjs} +1 -1
- package/dist/worker.mjs +1 -1
- package/kit/board.css +95 -0
- package/kit/board.js +250 -0
- package/kit/charts.js +5 -71
- package/kit/code.js +14 -14
- package/kit/report.css +255 -17
- package/kit/runtime.js +1600 -125
- package/kit/state.js +10 -1
- package/kit/tables.js +128 -43
- package/kit/ui.js +77 -35
- package/package.json +2 -1
- package/packs/gallery/card/component.json +14 -0
- package/packs/gallery/card/example.html +10 -0
- package/packs/gallery/card/preview.svg +1 -0
- package/packs/gallery/card/style.css +6 -0
- package/packs/gallery/card/template.html +6 -0
- package/packs/gallery/card/writing.md +14 -0
- package/packs/gallery/chart-card/component.json +15 -0
- package/packs/gallery/chart-card/example.html +14 -0
- package/packs/gallery/chart-card/kit.js +130 -0
- package/packs/gallery/chart-card/preview.svg +1 -0
- package/packs/gallery/chart-card/style.css +42 -0
- package/packs/gallery/chart-card/template.html +13 -0
- package/packs/gallery/chart-card/writing.md +20 -0
- package/packs/gallery/chart-view/component.json +20 -0
- package/packs/gallery/chart-view/example.html +13 -0
- package/packs/gallery/chart-view/kit.js +355 -0
- package/packs/gallery/chart-view/preview.svg +1 -0
- package/packs/gallery/chart-view/style.css +94 -0
- package/packs/gallery/chart-view/template.html +3 -0
- package/packs/gallery/chart-view/writing.md +22 -0
- package/packs/gallery/countdown/component.json +18 -0
- package/packs/gallery/countdown/example.html +3 -0
- package/packs/gallery/countdown/kit.js +156 -0
- package/packs/gallery/countdown/preview.svg +1 -0
- package/packs/gallery/countdown/style.css +130 -0
- package/packs/gallery/countdown/template.html +3 -0
- package/packs/gallery/countdown/writing.md +22 -0
- package/packs/gallery/habit/component.json +14 -0
- package/packs/gallery/habit/example.html +3 -0
- package/packs/gallery/habit/kit.js +295 -0
- package/packs/gallery/habit/preview.svg +1 -0
- package/packs/gallery/habit/style.css +246 -0
- package/packs/gallery/habit/template.html +3 -0
- package/packs/gallery/habit/writing.md +21 -0
- package/packs/gallery/heatmap/component.json +18 -0
- package/packs/gallery/heatmap/example.html +3 -0
- package/packs/gallery/heatmap/kit.js +351 -0
- package/packs/gallery/heatmap/preview.svg +1 -0
- package/packs/gallery/heatmap/style.css +201 -0
- package/packs/gallery/heatmap/template.html +3 -0
- package/packs/gallery/heatmap/writing.md +21 -0
- package/packs/gallery/kanban/component.json +18 -0
- package/packs/gallery/kanban/example.html +12 -0
- package/packs/gallery/kanban/kit.js +540 -0
- package/packs/gallery/kanban/preview.svg +1 -0
- package/packs/gallery/kanban/style.css +212 -0
- package/packs/gallery/kanban/template.html +3 -0
- package/packs/gallery/kanban/writing.md +20 -0
- package/packs/gallery/metric/component.json +22 -0
- package/packs/gallery/metric/example.html +15 -0
- package/packs/gallery/metric/kit.js +248 -0
- package/packs/gallery/metric/preview.svg +1 -0
- package/packs/gallery/metric/style.css +92 -0
- package/packs/gallery/metric/template.html +3 -0
- package/packs/gallery/metric/writing.md +23 -0
- package/packs/gallery/note/component.json +14 -0
- package/packs/gallery/note/example.html +3 -0
- package/packs/gallery/note/kit.js +102 -0
- package/packs/gallery/note/preview.svg +1 -0
- package/packs/gallery/note/style.css +76 -0
- package/packs/gallery/note/template.html +3 -0
- package/packs/gallery/note/writing.md +18 -0
- package/packs/gallery/pack.json +8 -0
- package/packs/gallery/recent/component.json +13 -0
- package/packs/gallery/recent/example.html +1 -0
- package/packs/gallery/recent/kit.js +238 -0
- package/packs/gallery/recent/preview.svg +1 -0
- package/packs/gallery/recent/style.css +158 -0
- package/packs/gallery/recent/template.html +1 -0
- package/packs/gallery/recent/writing.md +15 -0
- package/packs/gallery/static/component.json +13 -0
- package/packs/gallery/static/example.html +11 -0
- package/packs/gallery/static/preview.svg +1 -0
- package/packs/gallery/static/style.css +138 -0
- package/packs/gallery/static/template.html +1 -0
- package/packs/gallery/static/writing.md +18 -0
- package/packs/gallery/stats/component.json +13 -0
- package/packs/gallery/stats/example.html +1 -0
- package/packs/gallery/stats/kit.js +166 -0
- package/packs/gallery/stats/preview.svg +1 -0
- package/packs/gallery/stats/style.css +151 -0
- package/packs/gallery/stats/template.html +1 -0
- package/packs/gallery/stats/writing.md +11 -0
- package/packs/gallery/today/component.json +12 -0
- package/packs/gallery/today/example.html +1 -0
- package/packs/gallery/today/kit.js +185 -0
- package/packs/gallery/today/preview.svg +1 -0
- package/packs/gallery/today/style.css +120 -0
- package/packs/gallery/today/template.html +1 -0
- package/packs/gallery/today/writing.md +14 -0
- package/packs/gallery/todos/component.json +19 -0
- package/packs/gallery/todos/example.html +3 -0
- package/packs/gallery/todos/kit.js +342 -0
- package/packs/gallery/todos/preview.svg +1 -0
- package/packs/gallery/todos/style.css +267 -0
- package/packs/gallery/todos/template.html +3 -0
- package/packs/gallery/todos/writing.md +30 -0
- package/packs/gallery/weather/component.json +19 -0
- package/packs/gallery/weather/example.html +3 -0
- package/packs/gallery/weather/kit.js +312 -0
- package/packs/gallery/weather/preview.svg +1 -0
- package/packs/gallery/weather/style.css +258 -0
- package/packs/gallery/weather/template.html +3 -0
- package/packs/gallery/weather/writing.md +26 -0
- package/packs/gallery-soft/pack.json +8 -0
- package/release.json +12 -10
- package/sdk/doc-kit.d.ts +396 -5
- package/sdk/doc-state.d.ts +2 -0
- package/skill/SKILL.md +56 -23
- package/skill/references/block-script.md +140 -0
- package/skill/references/building-blocks.md +257 -0
- package/skill/references/extensions.md +59 -0
- package/skill/references/pages-and-data.md +221 -0
- package/skill/references/writing-html.md +6 -4
- package/skill/sdk/doc-kit.d.ts +396 -5
- package/skill/sdk/doc-state.d.ts +2 -0
- package/web/assets/index-BK2e_07w.js +13 -0
- package/web/assets/index-CWFI83mF.css +1 -0
- package/web/index.html +2 -2
- package/dist/chunk-3HIRPVLU.mjs +0 -2
- package/dist/chunk-5MHMDLZD.mjs +0 -4
- package/dist/chunk-64K7IPLO.mjs +0 -255
- package/dist/chunk-6QXGZM36.mjs +0 -8
- package/dist/chunk-6RGJOMJP.mjs +0 -16
- package/dist/chunk-AJ73XJF3.mjs +0 -2
- package/dist/chunk-AUZGSZJH.mjs +0 -13
- package/dist/chunk-BFE45AKL.mjs +0 -2
- package/dist/chunk-BXO2ZY5P.mjs +0 -2
- package/dist/chunk-CEH4MRCC.mjs +0 -2
- package/dist/chunk-CY2FNNAB.mjs +0 -16
- package/dist/chunk-DFUDV4LX.mjs +0 -2
- package/dist/chunk-DKXG4XDG.mjs +0 -2
- package/dist/chunk-EZQ34M3F.mjs +0 -124
- package/dist/chunk-EZY3WC6Z.mjs +0 -15
- package/dist/chunk-FUKQNOQS.mjs +0 -9
- package/dist/chunk-JPOSLGOC.mjs +0 -6
- package/dist/chunk-L3QKH4OK.mjs +0 -26
- package/dist/chunk-LAE5NQ4B.mjs +0 -2
- package/dist/chunk-LEF6DRCK.mjs +0 -59
- package/dist/chunk-NO5NJCHO.mjs +0 -2
- package/dist/chunk-NQPVAU63.mjs +0 -2
- package/dist/chunk-NSKUTQ5J.mjs +0 -5
- package/dist/chunk-O35FIXRB.mjs +0 -2
- package/dist/chunk-P2CAZPDP.mjs +0 -3
- package/dist/chunk-PL6GHLGD.mjs +0 -15
- package/dist/chunk-QJIR2BLP.mjs +0 -6
- package/dist/chunk-QUPLVPB2.mjs +0 -7
- package/dist/chunk-R7BNENLY.mjs +0 -4
- package/dist/chunk-S6O4UHLC.mjs +0 -2
- package/dist/chunk-SGJWQKEI.mjs +0 -2
- package/dist/chunk-TX6JH7TR.mjs +0 -2
- package/dist/chunk-TYK6VNAB.mjs +0 -10
- package/dist/chunk-UALRNVSE.mjs +0 -4
- package/dist/chunk-V3HXVQEM.mjs +0 -2
- package/dist/chunk-V5VXUJKG.mjs +0 -2
- package/dist/chunk-VBXMADMP.mjs +0 -2
- package/dist/chunk-VNV55RUA.mjs +0 -2
- package/dist/chunk-VPD2PS35.mjs +0 -2
- package/dist/chunk-W4VKN3GF.mjs +0 -7
- package/dist/chunk-W5BXXPDJ.mjs +0 -3
- package/dist/chunk-XUNHRCOG.mjs +0 -6
- package/skill/references/building-components.md +0 -367
- package/web/assets/index-Bh74DfsV.css +0 -1
- package/web/assets/index-UW0RyFFt.js +0 -13
|
@@ -1,367 +0,0 @@
|
|
|
1
|
-
# Building a component
|
|
2
|
-
|
|
3
|
-
A component package is a block to use again: it lives in the workspace, the user finds it in the "/" menu of every document there, and a document holds its instances as ordinary elements.
|
|
4
|
-
|
|
5
|
-
Make one only when the user clearly wants a block to use again ("做一个以后还能用的组件"). A document is written with the kit's blocks and, for a layout of its own, a whole block ([writing-html.md](writing-html.md#kit-blocks)): never make a package for one document, and never to get a look or a chart a document's own `<style>` and `<script>` can give it.
|
|
6
|
-
|
|
7
|
-
The interface is experimental in Gallery 0.x: what this page says may change between versions, and a package may need changing with it.
|
|
8
|
-
|
|
9
|
-
## The flow
|
|
10
|
-
|
|
11
|
-
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 package as below, and write the instance in its section at step 6.
|
|
12
|
-
|
|
13
|
-
1. `gallery component list` first: what the workspace has now, each with its version, whether the menus can insert it, and what is there and cannot be used, with why. When one does what the user asks, use it: `gallery component show <id>` prints its parts, how to write it and its example.
|
|
14
|
-
2. `gallery component new <id>`: a new package 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).
|
|
15
|
-
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.
|
|
16
|
-
4. `gallery component 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. In the handoff name the pictures you opened.
|
|
17
|
-
5. Try each gesture a reader makes, in the page, with `gallery component try`, one command for each: `--drag <selector> --to <selector>` (a card dragged to another column or place), `--press <selector>` (a dot, a button) or `--key <selector> <key>` (Enter, Space or an arrow on a control the block draws), as `gallery component try <slug> --drag .kanban-card --to ".kanban-column:nth-child(3)"`. Write the instance into the document first, where step 6 puts it (when the user wants no document, into one of its own made with `gallery new`, named in the handoff), and copy `doc.html`; name the instance after the slug by its `data-block-id` when the document holds more than one. Each selector is the first element of the instance that it finds, as `kit.js` draws it: `Nothing in the instance is …` lists the classes the instance shows. The command opens the document's page alone, editable, in a Chrome or Edge of its own, headless, makes the gesture there with the pointer or the keys (a drag in steps, released as it comes onto its target), waits until `doc.html` has it, and prints what it wrote: `Wrote: tasks (-1 +1 of its 8 lines); nothing outside the instance changed (data-block-id aside)`, each part with the lines the gesture took out and put in. Then it presses Ctrl+Z once and says `Undone: one Ctrl+Z, and doc.html is as it was (data-block-id aside)`: the document is left as it was, and `--keep` leaves the write instead. Open the picture its `Picture of the instance after the …` line names. A `note` line asks what the check's notes ask (a write that lays a part out anew: change the write as Writing back says). Exit 1 is a problem to fix in the package: a gesture that wrote nothing says what came of it (no `context.edit` came of it, the page refused one and the console says why, an HTML5 drag was dropped nowhere: a list a card is dropped on cancels `dragenter` as well as `dragover`), and an undo that did not give the file back says what still differs; fix it, run `gallery component check <id>`, and try the gesture again. A `FAIL` that says `doc.html` holds what the gesture wrote is a trial cut off after its write (the page offline, a card held for the reader, a load of its own): that write is yours to put back, `doc.html` read again first, as the next paragraph says, before you try again. Exit 2 is a mistake in the command. Exit 3 (`UNVERIFIED`) is a trial not seen through that left nothing of the gesture in `doc.html`, its line saying what the file holds, what someone else wrote meanwhile included, which stays: run it once more. Each try shows on every page open on the document, the user's at the address you sent too: the write, then the undo. Say so in the handoff when the user may have watched it.
|
|
18
|
-
A gesture the command cannot make (the block inserted from "/" by its name, or a word of `words`, the pinyin of its name; words typed in its text parts or in a field it draws; a gesture of several steps), make yourself when you can drive Chrome or Edge by its DevTools protocol, from Node 22's own `fetch` and `WebSocket`, with nothing to install. Start one of its own at the `Agent 自用` address that `gallery new`, `gallery import` or `gallery open` prints: the document's page alone, editable, with no frame around it (`--headless=new --remote-debugging-port=<port> --user-data-dir=<a new folder> <address>`; `http://127.0.0.1:<port>/json/list` gives the tab's `webSocketDebuggerUrl`, and `Input.dispatchMouseEvent`, `Input.dispatchKeyEvent` and `Runtime.evaluate` do the rest). Copy `doc.html` first. A gesture's write goes to the file by itself: `<html>`'s `data-ge-save` leaves `saved` (`waiting`, then `syncing`) and says `saved` again once the file has it (`held`: a card waits for the reader; `offline` or `stopped`: the server). Then read the part in `doc.html`: it holds what the gesture meant, and nothing outside it changed but `data-block-id`: the page gives a block it saves a change of one where it has none (the instance, the section it stands in), and an undo leaves it, so compare `doc.html` with your copy with every `data-block-id` taken out. Press Ctrl+Z once with the focus in no field the block draws (in an `input`, a `select`, a `textarea` or an editable element of its own, Ctrl+Z is that field's: a click on a paragraph beside the block takes the focus off it), wait for `saved`, and see the part as it was. At the end `doc.html` is your copy again, but for those ids and what the user changed meanwhile at the address you sent: undo each step, the insert too, then close your Chrome. Anything of the trial an undo left (the page was loaded again, a card held a step), take out yourself once your Chrome is closed, as any change of yours, `doc.html` read again first: the instance, and an empty paragraph you made for it, keeping the rest and the ids. Write the whole copy back only where `doc.html` differs from it in what the trial left alone, ids aside, and never while a page of yours is open on the document: over more, it takes away what the user wrote meanwhile and shows them a card saying so, and a page of yours open on it holds on a card of its own.
|
|
19
|
-
In the handoff name the gestures you tried, and only those, each by its command or its steps and what it wrote, and what the user changed meanwhile, which stays. When you could not try one, by the command or yourself, say plainly in the handoff that you did not try it in the page.
|
|
20
|
-
6. Use it where the user asked: in a document, write the element as `example.html` does. 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.
|
|
21
|
-
|
|
22
|
-
Tell the user the component's name and where it is. A change to a package reaches every page open on it, by itself.
|
|
23
|
-
|
|
24
|
-
## The files
|
|
25
|
-
|
|
26
|
-
| File | What it is |
|
|
27
|
-
| --- | --- |
|
|
28
|
-
| `component.json` | the manifest, plain data: all that Gallery itself reads of the package |
|
|
29
|
-
| `template.html` | what "/" puts in a document: one instance, with what a new one holds. `gallery component check` requires it: with none, or one a new block cannot be, no menu offers the block, and `gallery component list` and 设置 › 组件列表 say so |
|
|
30
|
-
| `example.html` | an instance as a writer would fill it: what `gallery component show` prints and what `gallery component check` runs |
|
|
31
|
-
| writing.md | how to write it, for an Agent: what it is for, when to use it, what goes in each part. `gallery component show` prints it |
|
|
32
|
-
| `style.css` | its look, optional |
|
|
33
|
-
| `kit.js` | its script, optional, one classic script |
|
|
34
|
-
| `preview.svg` | a picture for the menu, optional: a reader resting on its row sees it beside the description, or the description alone |
|
|
35
|
-
|
|
36
|
-
## The manifest
|
|
37
|
-
|
|
38
|
-
```json
|
|
39
|
-
{
|
|
40
|
-
"id": "local/metrics",
|
|
41
|
-
"apiVersion": 1,
|
|
42
|
-
"version": "1.0.0",
|
|
43
|
-
"name": { "zh": "指标条", "en": "Metric strip" },
|
|
44
|
-
"description": { "zh": "一排数字和它们的说明", "en": "A row of numbers and what they say" },
|
|
45
|
-
"words": "zhibiaotiao kpi metrics 指标 数字",
|
|
46
|
-
"parts": {
|
|
47
|
-
"title": { "at": ":scope > h3", "edit": "text" },
|
|
48
|
-
"numbers": { "at": ":scope > dl", "edit": "none" }
|
|
49
|
-
},
|
|
50
|
-
"markdown": "parts"
|
|
51
|
-
}
|
|
52
|
-
```
|
|
53
|
-
|
|
54
|
-
| Field | What it holds |
|
|
55
|
-
| --- | --- |
|
|
56
|
-
| `id` | `<scope>/<name>`, as its folder is, each in lowercase letters, digits and hyphens |
|
|
57
|
-
| `apiVersion` | 1 |
|
|
58
|
-
| `version` | which version of it this is: shown, never compared |
|
|
59
|
-
| `name`, `description` | `{ "zh": …, "en": … }`, both: what the menu shows |
|
|
60
|
-
| `words` | optional: what the menu finds it by, besides its name. Write the pinyin of a Chinese name here, the whole name in one word (`任务看板 renwukanban kanban`): "/" goes by the letters an input method is composing, and finds the block while all of them are being composed only by a word that holds them. The check gives a note on a Chinese name no word here spells whole, a syllable a character: it counts how many syllables of pinyin a word reads as, and does not know which characters they spell |
|
|
61
|
-
| `parts` | its parts by name, below |
|
|
62
|
-
| `runtime` | optional: what its script leaves on a page, `{ "generated": [selectors], "attrs": { selector: [names] } }` |
|
|
63
|
-
| `assets` | optional: what it needs besides its script and style: the kit's files by id (`d3`, `charts`, `tables`, `dialogs`, `sheets`, `state`, `tokens`, `code`, `math`, `katex`, `katex-styles`, `katex-auto-render`), and files of its own folder a style names, by their path. `katex` gives a script the name `katex`, and what it draws needs `katex-styles` beside it, or a formula shows twice |
|
|
64
|
-
| `markdown` | optional: `parts` (the default: a table part as a table, a text part as a paragraph) or `text` (its words alone), how it exports to Markdown |
|
|
65
|
-
| `schema` | optional: the whole number of the newest shape of content its script reads, 1 when it says none: "When the content's shape changes", below |
|
|
66
|
-
|
|
67
|
-
A package's manifest holds nothing else: a field it does not know keeps the package from loading, and `gallery component list` says why.
|
|
68
|
-
|
|
69
|
-
## Parts
|
|
70
|
-
|
|
71
|
-
A part is an element of an instance that the file means something by. `at` finds it: `:scope > h3`, `:scope > div.note > p`, step by step from the instance, or one selector for any depth, or a list of those with commas; each step a tag, `.class`, `[attr]` or `[attr=value]`. A part counts the elements `at` finds in one instance, each once: an instance holds at least `min` of them (1 when the manifest says none) and at most `max` (any number when it says none); `optional: true` lets it hold none, whatever `min` says. An instance with too few or too many fails `gallery check` for every document that holds one, and a `template.html` with too few or too many is in no menu.
|
|
72
|
-
|
|
73
|
-
A group of parts repeated, an item of three parts three or four times, is its three parts, each reaching into the item and each with the same `min` and `max`:
|
|
74
|
-
|
|
75
|
-
```json
|
|
76
|
-
"parts": {
|
|
77
|
-
"name": { "at": ":scope > div.item > p.name", "edit": "text", "min": 3, "max": 4 },
|
|
78
|
-
"value": { "at": ":scope > div.item > p.value", "edit": "text", "min": 3, "max": 4 },
|
|
79
|
-
"change": { "at": ":scope > div.item > p.change", "edit": "text", "min": 3, "max": 4 }
|
|
80
|
-
}
|
|
81
|
-
```
|
|
82
|
-
|
|
83
|
-
Each part is counted across the instance on its own: the check does not hold the parts of one item to each other, so four items, one of them without its `change`, pass, three changes being enough. Say in writing.md that every item holds all three.
|
|
84
|
-
|
|
85
|
-
`edit` says whose a part is:
|
|
86
|
-
|
|
87
|
-
| `edit` | What it means now |
|
|
88
|
-
| --- | --- |
|
|
89
|
-
| `text` | words the user types in, in the browser. It holds words and marks alone (`strong`, `em`, `b`, `i`, `u`, `s`, `code`, `a`, `sub`, `sup`, `br`): a heading, a paragraph, a label. With anything else in it, a block, a field, a picture, a comment, an element it does not close, the editor leaves it read-only, and the check fails it |
|
|
90
|
-
| `none` | the component's: read it, draw from it. The user changes it through the source alone |
|
|
91
|
-
| `data` | what a script reads its data from and writes back to (a table, a `<script type="application/json">`): the component's alone, written by `context.edit` and by nothing else, told to it when it changes |
|
|
92
|
-
| `flow` | a slot: blocks of the document's own in the instance, a `<div data-doc-slot="<name>">` of its markup and no `at` (Slots, below) |
|
|
93
|
-
|
|
94
|
-
What stands in an instance belongs by region:
|
|
95
|
-
|
|
96
|
-
| Where | Whose events and contents |
|
|
97
|
-
| --- | --- |
|
|
98
|
-
| a `text` part | the editor's: Enter, Backspace, undo and the selection work as in any text |
|
|
99
|
-
| a `data` part | the component's, and only `context.edit` changes its content. A `text` part in one, or around one, is no text part: the file holds one or the other there |
|
|
100
|
-
| what the manifest's `runtime` names, and all else in the instance | the component's: the editor leaves its clicks and keys alone |
|
|
101
|
-
| a slot, a `flow` part, and what it holds | the editor's: any block, as in the page; the component reads it and never writes in it |
|
|
102
|
-
| the instance as a whole, its handle | Gallery's: moving, copying and deleting it |
|
|
103
|
-
|
|
104
|
-
In the page the user types words in the text parts, edits the blocks of a slot as any, and moves, copies or deletes the instance whole; a component changes its data parts by `context.edit` on a gesture of the reader's, a drag or a press, and nothing else of it changes there. No item of a repeated group of text parts is added or taken out on the page, its text parts being the file's words: an item more or fewer is a change of the source, so say so in writing.md. A component whose items come and go keeps them in a data part, where a control of its own adds, renames or removes one by `context.edit`, as a move is written.
|
|
105
|
-
|
|
106
|
-
A component reads a text part and never writes one: what a user types there is the file's, and a script that writes it on the `source` signal hears itself without end. It draws in what is its own, and writes a data part by `context.edit` alone: a change made straight to the part stands on that page and may end up anywhere, or nowhere.
|
|
107
|
-
|
|
108
|
-
## Slots
|
|
109
|
-
|
|
110
|
-
A slot is where an instance holds blocks of the document's own under its own markup: a card with a title over any content, a frame around a few paragraphs and a table. Its part is edited as `flow`, with no `at`, `min` or `max`, a name of lowercase letters, digits and hyphens, and `"optional": true` when an instance may have none:
|
|
111
|
-
|
|
112
|
-
```json
|
|
113
|
-
"parts": {
|
|
114
|
-
"title": { "at": ":scope > h3", "edit": "text" },
|
|
115
|
-
"body": { "edit": "flow" }
|
|
116
|
-
}
|
|
117
|
-
```
|
|
118
|
-
|
|
119
|
-
In the markup it is a `<div>` or `<section>` of the instance's own, marked with that name, once in an instance, never the instance itself and with no `data-block-id`:
|
|
120
|
-
|
|
121
|
-
<!-- the file holds -->
|
|
122
|
-
```html
|
|
123
|
-
<div class="brief" data-doc-component="local/brief">
|
|
124
|
-
<h3>本周要点</h3>
|
|
125
|
-
<div class="brief-body" data-doc-slot="body">
|
|
126
|
-
<p>上线了新的导出流程。</p>
|
|
127
|
-
<ul>
|
|
128
|
-
<li>导出更快</li>
|
|
129
|
-
<li>离线文件更小</li>
|
|
130
|
-
</ul>
|
|
131
|
-
</div>
|
|
132
|
-
</div>
|
|
133
|
-
```
|
|
134
|
-
|
|
135
|
-
`gallery component new <id> --flow` writes one, `body`, in place of the text paragraph. What a slot holds is written as anywhere in the document ([writing-html.md](writing-html.md)): paragraphs, headings, lists, tables, formulas, code, a chart card, pictures, a disclosure, columns, another instance; no section and no tab area. Gallery converts, spaces and draws it as it does the page's. `template.html` gives it what a new instance starts with, an empty paragraph (`<p></p>`) where the reader starts typing; `example.html` some blocks a writer would put there.
|
|
136
|
-
|
|
137
|
-
On the page the reader edits a slot's blocks as any of the page's: types in them, splits and turns them, moves them in and out by their handles, adds blocks there with "/", undoes. Where the package is missing, turned off or fails, the slot is still the document's and still editable; the rest of the instance shows as it stands.
|
|
138
|
-
|
|
139
|
-
The slot is the reader's, not the component's:
|
|
140
|
-
|
|
141
|
-
- `context.part("body")` gives the slot element, to read: its height, its words, its headings. A change of what it holds comes as `source`, whoever made it.
|
|
142
|
-
- A component never writes in it, moves it or takes it off: what it holds is the reader's words, and a page would take a change there for the reader's, and save it. It draws outside the slot, in what its manifest's `runtime` names, as `local/brief` draws its count of words under it. `gallery component check` fails a script that changes what a slot holds or where it stands, as it mounts, as it is put back and as its example makes its edit. `context.edit` on a slot throws.
|
|
143
|
-
- Its style reaches no block in the slot: a selector that goes down from the instance by a blank (`[data-doc-component="local/brief"] p`) styles the slot's paragraphs too, which read as the page's. Write each step with `>` (`[data-doc-component="local/brief"] > h3`), or wrap the rules in `@scope ([data-doc-component="local/brief"]) to ([data-doc-slot]) { … }`; the check gives a note on each that goes down.
|
|
144
|
-
- With `"markdown": "parts"` a slot is written as its blocks, in its place among the parts; with `"text"`, its words.
|
|
145
|
-
|
|
146
|
-
## Writing an instance
|
|
147
|
-
|
|
148
|
-
<!-- the file holds -->
|
|
149
|
-
```html
|
|
150
|
-
<div class="metrics" data-doc-component="local/metrics">
|
|
151
|
-
<h3>本周指标</h3>
|
|
152
|
-
<dl>
|
|
153
|
-
<dt>收入</dt><dd>12 万</dd>
|
|
154
|
-
<dt>新客</dt><dd>3–5 位</dd>
|
|
155
|
-
</dl>
|
|
156
|
-
</div>
|
|
157
|
-
```
|
|
158
|
-
|
|
159
|
-
An instance is a `<div>` or `<section>` naming its package, straight in the page or in anything that holds blocks. Classes and attributes of your own are free in it; `doc-*` and `data-doc-*` are the kit's. Nothing of Gallery's goes into an instance: no conversion, no spacing, no formula, no other component's script, but in its slots, which are the document's. Write no `data-block-id` in `template.html`: every block gets its own.
|
|
160
|
-
|
|
161
|
-
`template.html` is one instance and nothing around it, closed by its own end tag, with as many of each part as the manifest says. Write what shows well when nothing is filled in yet: the user's first look at the block is this. Nothing in it runs or leaves its block: no script but data (`<script type="application/json">`), no `on…` attribute or address of code, no `<style>`, `<link>` or `<iframe>`, no `style` that positions it `fixed`, `absolute` or `sticky`, nothing of the editor's (`data-ge-*`). No menu offers a template that breaks this, and the check fails it at its line. `example.html` may hold several, and blocks around them.
|
|
162
|
-
|
|
163
|
-
Put what the block says in the instance itself: an element a reader can read without its script, so that a reader of a file the package is not in, or a Markdown export, still has it. Where the package is missing or turned off, or its script fails or starts nothing, Gallery shows the instance as it stands and draws a script of data in it as it draws any, read-only: an array of objects as a table, an object as its keys and values, any other array as a list, cut short and saying so past twenty entries, three levels down or a few hundred values. A package with no script draws nothing of its scripts of data: what such a block says is in elements. A component that cannot fully read what it finds leaves it as it stands. A table part it leaves showing, drawing and hiding nothing. A script of data it hands to Gallery with `context.fail(error)` (or by throwing): Gallery then shows the instance as it stands, its script of data drawn read-only as above, its text parts read-only too until the page is loaded again. It never rebuilds what it found and writes that over it, and what it leaves alone nothing writes. Write no snapshot of what the block draws beside its data unless writing.md says how the snapshot is made again from that one source: otherwise it goes stale, unseen.
|
|
164
|
-
|
|
165
|
-
A picture in an instance is the document's, a file of the document's `assets/` folder. `example.html` and `template.html` stand in no document, so a picture there is a `data:` address, or stands in the style, a file its `assets` name.
|
|
166
|
-
|
|
167
|
-
## Style
|
|
168
|
-
|
|
169
|
-
Every selector stands in the instance, whatever it is:
|
|
170
|
-
|
|
171
|
-
```css
|
|
172
|
-
[data-doc-component="local/metrics"] dl { display: grid; grid-auto-flow: column; }
|
|
173
|
-
[data-doc-component="local/metrics"] dt { color: var(--doc-muted); }
|
|
174
|
-
@media (max-width: 480px) {
|
|
175
|
-
[data-doc-component="local/metrics"] dl { grid-auto-flow: row; }
|
|
176
|
-
}
|
|
177
|
-
```
|
|
178
|
-
|
|
179
|
-
An instance stands `--doc-block-gap` from what is around it, in whatever state it is: the kit gives it that margin, and a `margin` on the instance itself changes it.
|
|
180
|
-
|
|
181
|
-
Start each one at `[data-doc-component="<id>"]`, the instance's own attribute, not a class of yours: a class is anybody's. A selector may have something before that, which only says when it applies, and nothing reaches outside it or beside it (`+`, `~`; in nesting, `& + p` is beside the instance when `&` is the instance, and fine when `&` is something in it): the check names each that does, with its line. Colors come from the kit's variables, which follow the dark theme: `--doc-text`, `--doc-muted`, `--doc-border`, `--doc-grid`, `--doc-surface`, `--doc-bg`, `--doc-accent`, `--doc-accent-soft`, `--doc-series-1` … `-6` ([writing-html.md](writing-html.md#the-page)). Text on a `--doc-accent` fill is `--doc-bg`, never `#fff`: the dark theme's accent is light. Text on `--doc-accent-soft` is `--doc-text`. A picture or a font a style names is a file of the package, listed in `assets`; an export embeds it. No `@import` and no address elsewhere.
|
|
182
|
-
|
|
183
|
-
## Script
|
|
184
|
-
|
|
185
|
-
`kit.js` is one classic script, no module and no `import`. It runs in a function of its own, on the page and in an offline file, and the types are in `sdk/doc-kit.d.ts`:
|
|
186
|
-
|
|
187
|
-
```js
|
|
188
|
-
DocKit.component({
|
|
189
|
-
id: "local/metrics",
|
|
190
|
-
on: ["source"],
|
|
191
|
-
mount(host, context) {
|
|
192
|
-
const drawn = document.createElement("div");
|
|
193
|
-
drawn.className = "metrics-drawn";
|
|
194
|
-
host.append(drawn);
|
|
195
|
-
const draw = () => { drawn.textContent = context.part("title")?.textContent ?? ""; };
|
|
196
|
-
draw();
|
|
197
|
-
return { update: draw };
|
|
198
|
-
},
|
|
199
|
-
});
|
|
200
|
-
```
|
|
201
|
-
|
|
202
|
-
Its manifest says what that draws: `"runtime": { "generated": [".metrics-drawn"] }`.
|
|
203
|
-
|
|
204
|
-
- `mount(host, context)` starts one instance from what the file says. It runs again on a node an undo puts back, and in an exported file: before each mount the kit takes off what `runtime` names and calls `dehydrate`, so that mount, dehydrate, mount gives the same DOM. `gallery component check` tests it, and names what piles up.
|
|
205
|
-
- Whatever it adds to an instance is named in the manifest's `runtime`, `generated` for the nodes it makes and `attrs` for the marks it sets, or taken off in `dehydrate(host)`. A selector there goes down from the instance, and `:scope` is the instance itself (`"attrs": { ":scope": ["aria-busy"] }`). `dehydrate` may be given a host with nothing on it.
|
|
206
|
-
- A component draws in its instance, with ordinary elements. Nothing goes on `document.body` or in the head, and no attribute on what stands around the instance: what must stand elsewhere for a while (a tooltip, a popover) `destroy` takes away, and a listener outside the instance ends with `context.signal`. `gallery component check` names what piles up outside. A shadow root is not forbidden, but `gallery qa` and `gallery component check` do not look into one and the kit's theme stops at it, so what stands there goes unchecked.
|
|
207
|
-
- No `alert`, `confirm`, `prompt` or `window.open`: a dialog stops a reader's page until it is answered, and the check fails it.
|
|
208
|
-
- `on` lists the signals `update(reason)` hears: `source` (a text or data part changed, or what a slot holds, whoever changed it: an undo too), `editable` (`context.canEdit()` has just become true), `resize`, `theme`, `viewport`, `fonts`, `reveal`, `layout` (a card's size changed where widths do not tell: a resize in the editor), `content` (a change inside the instance, heard only with `owns: false`, for a component that leaves what it draws to the kit to watch). `owns` (default true): the kit watches nothing the component draws, only its parts.
|
|
209
|
-
- `context.part(name)` is a part of this instance (of a slot, its element, to read), `context.state({ version, defaults })` its reading state, of no other instance, `context.frame(draw)` draws in the kit's frame, `context.signal` ends with the instance (give it to `addEventListener`), `context.fail(error)` says it failed, `context.canEdit()` and `context.edit(name, change)` write back: below.
|
|
210
|
-
- A component that throws fails that instance alone: it shows what it holds, read-only, its text parts too, until the page is loaded again.
|
|
211
|
-
- `kit.js` is type-checked against `sdk/` as strict TypeScript would: a syntax error, a name nothing defines and what the SDK does not say fail the check, and any other word of the types is a note. A part and a draft are typed `HTMLElement`, and `querySelector` gives an `Element`: name what it is, `/** @type {HTMLTableElement} */ (table)`, or test it (`node instanceof HTMLElement`), and guard what can be null (`event.dataTransfer`, `context.part(…)`).
|
|
212
|
-
- An export blocks the network: no `fetch`, `XMLHttpRequest`, `WebSocket`, `EventSource`, `sendBeacon` or `import()`, and no `eval`. `gallery component check` refuses them, and `localStorage`: what a reader chooses goes in `context.state`.
|
|
213
|
-
|
|
214
|
-
The SDK's types are named as they stand, with no `import`: `sdk/doc-kit.d.ts` declares them for every script. `DocComponentContext` is what `mount` is given, `DocComponentHandle` what it returns, `DocComponentSignal` what `update` hears and `DocComponent` what `DocKit.component` registers. A function the mount hands its context to names it so:
|
|
215
|
-
|
|
216
|
-
```js
|
|
217
|
-
/** @param {DocComponentContext} context */
|
|
218
|
-
function titleOf(context) {
|
|
219
|
-
return context.part("title")?.textContent?.trim() ?? "";
|
|
220
|
-
}
|
|
221
|
-
```
|
|
222
|
-
|
|
223
|
-
A component runs with the rights of a document's own script: on the page, with its origin, able to do what any script of the document can. Say so in writing.md when the block has a script, and put in the workspace only what the user or you wrote.
|
|
224
|
-
|
|
225
|
-
## Writing back
|
|
226
|
-
|
|
227
|
-
What a reader does in the block goes to the file through a part edited as `data`:
|
|
228
|
-
|
|
229
|
-
```js
|
|
230
|
-
// The row numbered `from` put before the row numbered `before`, or last, with the blank before it, so
|
|
231
|
-
// that a table written a row a line stays so: what a drop calls, and the example too.
|
|
232
|
-
/** @param {DocComponentContext} context @param {number} from @param {number | null} before */
|
|
233
|
-
function move(context, from, before) {
|
|
234
|
-
return context.edit("tasks", (table) => {
|
|
235
|
-
const body = /** @type {HTMLTableElement} */ (table).tBodies[0];
|
|
236
|
-
const blankBefore = (node) => (node?.previousSibling?.nodeType === Node.TEXT_NODE && !node.previousSibling.textContent.trim() ? node.previousSibling : null);
|
|
237
|
-
const row = body.rows[from];
|
|
238
|
-
const next = before === null ? null : body.rows[before];
|
|
239
|
-
const at = next ? blankBefore(next) ?? next : body.lastChild?.nodeType === Node.TEXT_NODE ? body.lastChild : null;
|
|
240
|
-
for (const node of [blankBefore(row), row]) if (node) body.insertBefore(node, at);
|
|
241
|
-
});
|
|
242
|
-
}
|
|
243
|
-
|
|
244
|
-
DocKit.component({
|
|
245
|
-
id: "local/board",
|
|
246
|
-
on: ["source", "editable"],
|
|
247
|
-
mount(host, context) {
|
|
248
|
-
const draw = () => { /* draw the board from context.part("tasks"), handles only if context.canEdit(); a drop calls move(context, from, before) */ };
|
|
249
|
-
draw();
|
|
250
|
-
return { update: draw };
|
|
251
|
-
},
|
|
252
|
-
example(host, context) {
|
|
253
|
-
move(context, 0, null);
|
|
254
|
-
},
|
|
255
|
-
});
|
|
256
|
-
```
|
|
257
|
-
|
|
258
|
-
`example(host, context)` calls the change a gesture calls (`move` here), on a small edit of its own: `gallery component check` runs it on its way back to the file, so that what it tries is the code a reader's drag or press runs, and an example that writes the part some other way tries nothing a reader does.
|
|
259
|
-
|
|
260
|
-
- `context.edit(name, change)` hands `change` a draft of the part, off the page, and what it does to what the draft holds goes onto the page when it returns: draw from the part afterwards, as for any change, on `source`, which comes once `edit` has returned (a moment later, before the next frame; never inside it). There is nothing to wait for and no save to ask for. Saving, undo, a redo and a conflict with an Agent's write are Gallery's, as for words typed: each `edit` is one undo step, so call it once for a gesture, at its end, and not at every step of a drag. A gesture that writes two parts (a card moved and the move counted) names both in one edit, `context.edit(["tasks", "log"], ({ tasks, log }) => { … })`, and is one step; two edits are two steps.
|
|
261
|
-
- Write on a reader's gesture alone, a press, a drop or a key, never as the block mounts or hears a signal: a mount runs each time a page opens it, an undo puts it back or a reader inserts it, and what it writes there a page would write each time, with nothing done. Draw what the parts hold as they are. `gallery component check` fails a component that writes as it mounts, or as it hears `editable` or `source`, once `context.canEdit()` is true.
|
|
262
|
-
- It answers at once whether it was taken. `false` means nothing happened. That is so while `context.canEdit()` is false (always in an exported file and its PDF and in 演示视图, and until the page has come to edit: ask for `editable` to hear when; the editing page printed is still the editing page), when `change` throws, when it changed the part on the page rather than the draft it is handed (the draft is what goes in: what the page shows of the part is set back), and when what it made cannot go in the file: a script, an `on…` attribute, an address of code, `data-block-id`, `data-ge-*`, an element that would not read back as itself (a `<tr>` straight in a `<table>` with a `<tbody>`), the part's own tag or attributes changed, or more than 1 MB in one part. The console says which. What goes in is a copy of the draft, so a draft kept after the change returns writes nothing. `change` runs at once: it cannot wait for anything.
|
|
263
|
-
- Only what changed is written, only inside that part, and every other byte of the file stays. A `data` part is written whole, so what a change leaves alone in it may come back spelled as a browser spells it: `中` as `中`.
|
|
264
|
-
- A part that nothing edits is never written. So a component that cannot fully read what a part holds (a version it does not know, markup it did not write) leaves it alone and shows it read-only: it never rebuilds it and writes that over it. An edit that changes nothing writes nothing.
|
|
265
|
-
- A `<script type="application/json">` part is the same: read `JSON.parse(part.textContent)`, and in `change` set `script.textContent` to the JSON (the scorecard's, below, keeps the layout it was written in). Write `</` as `<\/` and `<!--` as `\u003c!--`, which could end the script, or the edit is refused.
|
|
266
|
-
- Keep what a reader only chooses (a filter, what is open) in `context.state`, and write to a part what the document says: what another reader should find there.
|
|
267
|
-
- An instance a component wrote can come back through undo: mount and draw from what the parts hold, whatever they hold.
|
|
268
|
-
- Someone else may write the file while the page is open (an Agent, another tab, the CLI). An edit of a part they left alone goes in beside what they changed; one of a part they changed waits on a card for the reader, who keeps theirs or writes the page's over it, and nothing of that is the component's to decide. The parts one `context.edit` writes go or wait together, so write in one edit what only makes sense together (a card moved and the count of moves), and in edits of their own what does not. Either way it next finds the part as the file then holds it: by a mount, as the page is shown again once nothing waits, or by `source`, when the reader undoes the choice. Draw from the part each time, never from what an edit last wrote.
|
|
269
|
-
|
|
270
|
-
### Two examples: a table and a script of data
|
|
271
|
-
|
|
272
|
-
Two packages written as this page says show the two kinds of data part. Each writes its part once for a gesture and draws from it on every `source`.
|
|
273
|
-
|
|
274
|
-
| | Its data part | What a reader does | Where its script does not run |
|
|
275
|
-
| --- | --- | --- | --- |
|
|
276
|
-
| 任务看板, a task board | `"tasks": { "at": ":scope > table", "edit": "data" }`: a row a task, its first cell the card's title, its second its status; an attribute of the package's own on the instance lists the columns, empty ones too | drags a card to another column or place: its row moves and its status cell takes the column's (adding a task is an edit like a move, when the board offers it) | the table |
|
|
277
|
-
| 评分表, a scorecard | `"scores": { "at": ":scope > script", "edit": "data" }`: `{ "scale": 5, "criteria": [{ "name": "价格", "weight": 3 }], "options": [{ "name": "供应商甲", "scores": [4] }] }` | presses a dot: that score | what the JSON holds, drawn by Gallery where the kit runs and the package does not: an array of objects as a table, an object as keys and values |
|
|
278
|
-
|
|
279
|
-
Use a table when what the block says reads as a table by itself, rows of words that a reader with no script, a Markdown export or another program should find as written, and that the script arranges and moves. Use a script of data when the block holds values it works from rather than words to read: numbers and true or false, keyed or nested, that a table would hold as words to parse back (a weight, a score for each criterion). Either way, what the block works out (a total, a ranking, a count by column) is drawn, never written beside the data.
|
|
280
|
-
|
|
281
|
-
A write keeps the part as it is laid out, so that a reader's change is a change of a line or two in the file. Move a row with the blank before it (`blankBefore` below), and write JSON back with `jsonIn` below. jsonIn keeps JSON on one line where it was on one. Otherwise it gives each entry of an object or a list a line of its own, but keeps on one line an object or list whose entries are all values or lists of values (`{ "name": "供应商甲", "scores": [4, 3] }`, `[[1, 2], [3, 4]]`): a list of objects, and an object that holds one, is spread over lines. So lay out the JSON in `template.html` and `example.html` the way jsonIn writes it:
|
|
282
|
-
|
|
283
|
-
```json
|
|
284
|
-
{
|
|
285
|
-
"scale": 5,
|
|
286
|
-
"criteria": [
|
|
287
|
-
{ "name": "价格", "weight": 3 },
|
|
288
|
-
{ "name": "质量", "weight": 2 }
|
|
289
|
-
],
|
|
290
|
-
"options": [
|
|
291
|
-
{ "name": "供应商甲", "scores": [4, 3] }
|
|
292
|
-
]
|
|
293
|
-
}
|
|
294
|
-
```
|
|
295
|
-
|
|
296
|
-
The board's drop and the scorecard's press:
|
|
297
|
-
|
|
298
|
-
```js
|
|
299
|
-
// The board: the row numbered `from` to the column `status`, before the row numbered `before`, or last.
|
|
300
|
-
const blankBefore = (node) => (node?.previousSibling?.nodeType === Node.TEXT_NODE && !node.previousSibling.textContent.trim() ? node.previousSibling : null);
|
|
301
|
-
context.edit("tasks", (table) => {
|
|
302
|
-
const body = /** @type {HTMLTableElement} */ (table).tBodies[0];
|
|
303
|
-
const row = body.rows[from];
|
|
304
|
-
const next = before === null ? null : body.rows[before];
|
|
305
|
-
const at = next ? blankBefore(next) ?? next : body.lastChild?.nodeType === Node.TEXT_NODE ? body.lastChild : null;
|
|
306
|
-
row.cells[1].textContent = status;
|
|
307
|
-
for (const node of [blankBefore(row), row]) if (node) body.insertBefore(node, at);
|
|
308
|
-
});
|
|
309
|
-
|
|
310
|
-
// The scorecard: the option numbered `option` given `score` on the criterion numbered `criterion`.
|
|
311
|
-
const isValue = (value) => value === null || typeof value !== "object";
|
|
312
|
-
const isFlat = (value) => Object.values(value).every((each) => isValue(each) || (Array.isArray(each) && each.every(isValue)));
|
|
313
|
-
function laidOut(value, indent) {
|
|
314
|
-
if (isValue(value)) return JSON.stringify(value);
|
|
315
|
-
const list = Array.isArray(value);
|
|
316
|
-
const items = Object.entries(value).map(([key, each]) => `${list ? "" : `${JSON.stringify(key)}: `}${laidOut(each, `${indent} `)}`);
|
|
317
|
-
if (items.length === 0) return list ? "[]" : "{}";
|
|
318
|
-
if (isFlat(value)) return list ? `[${items.join(", ")}]` : `{ ${items.join(", ")} }`;
|
|
319
|
-
return `${list ? "[" : "{"}\n${items.map((item) => `${indent} ${item}`).join(",\n")}\n${indent}${list ? "]" : "}"}`;
|
|
320
|
-
}
|
|
321
|
-
function jsonIn(text, value) {
|
|
322
|
-
const start = text.length - text.trimStart().length;
|
|
323
|
-
const end = text.trimEnd().length;
|
|
324
|
-
const indent = text.slice(text.lastIndexOf("\n", start) + 1, start);
|
|
325
|
-
const json = text.slice(start, end).includes("\n") ? laidOut(value, indent) : JSON.stringify(value);
|
|
326
|
-
return text.slice(0, start) + json.replaceAll("</", "<\\/").replaceAll("<!--", "\\u003c!--") + text.slice(end);
|
|
327
|
-
}
|
|
328
|
-
context.edit("scores", (script) => {
|
|
329
|
-
const data = JSON.parse(script.textContent);
|
|
330
|
-
data.options[option].scores[criterion] = score;
|
|
331
|
-
script.textContent = jsonIn(script.textContent, data);
|
|
332
|
-
});
|
|
333
|
-
```
|
|
334
|
-
|
|
335
|
-
While it draws the board, the board hides the table, `table.hidden = true`, a mark its manifest's `runtime` names (`"attrs": { ":scope > table": ["hidden"] }`), so that no file or copy holds it and the table shows wherever the script does not draw. A drag is best made with pointer events (`pointerdown`, `pointermove`, `pointerup`, `setPointerCapture`), which work with touch too. With HTML5 drag and drop, a list a card can be dropped on cancels `dragenter` as well as `dragover`, or a release just as the pointer enters it is refused.
|
|
336
|
-
|
|
337
|
-
### When the content's shape changes
|
|
338
|
-
|
|
339
|
-
An instance may say in which shape it holds its content, `data-doc-schema="2"`, a whole number you choose and write in the package's template and examples, and the manifest's `schema` says the newest the component reads. An instance past that, or one whose `data-doc-schema` is no number, was written by a newer version of the package: it is read-only whole, its text parts too, `context.canEdit()` is false for it, the component shows it read-only, and `gallery check` says so in a note. A package upgrade never touches a document: to move content to a new shape, change it as a task of its own.
|
|
340
|
-
|
|
341
|
-
## What it says
|
|
342
|
-
|
|
343
|
-
`gallery component check <id>` prints five sections, each `FAIL <file>:<line>: …` for what to fix and `note …` for what is advice:
|
|
344
|
-
|
|
345
|
-
1. the manifest: as Gallery reads it, `template.html` there, no text part that holds more than words and marks, a note on a Chinese name no word of `words` spells whole in pinyin, by the count of its syllables;
|
|
346
|
-
2. `kit.js`: what a browser refuses, what an export refuses, what it registers, a type check against `sdk/`, what the types alone say of code a browser runs being a note;
|
|
347
|
-
3. `style.css`: each selector, what an export cannot hold;
|
|
348
|
-
4. `template.html` and `example.html`: as the page of a document, by what `gallery check` runs, and `template.html` as what a menu can put in;
|
|
349
|
-
5. both in a temporary document, exported, in Chrome or Edge under the export's policy: the console, a dialog or a window it opens, a page that loads itself again or stops answering, mount and dehydrate, what piles up in the instance or outside it, a text part the component redraws, a data part a mount changes, a write with no gesture once the page takes edits, the way back to the file, a page wider than the window, and the pictures. The way back runs the component's `example` (above), a small edit made by the change a reader's gesture calls: it must change a data part and nothing else, the server must take what it wrote, and with the part put back, as an undo does, the block must show what it showed. Its `way back` line says what the example wrote, each part and how many of its lines changed, and that the server took it; a note says a write that lays a part out anew (lines a change did not mean, a line left blank), and a list a card is dropped on that listens for `dragover` and not for `dragenter`, at the line of `kit.js` that listens. A package with a data part and no `example` gets a note: nothing has tried its way back. Exit 3 and `UNVERIFIED` when no browser ran it, or the browser went while it ran: run it again, or export a document that holds it and look yourself.
|
|
350
|
-
|
|
351
|
-
Exit 0 is all five, exit 1 a failure. A failure with no line is of that file as a whole, or, as `the page`, of what ran. A package the user turned off in 设置 is checked as any, with a note saying so: passing the check does not turn it on, and that stays theirs to do.
|
|
352
|
-
|
|
353
|
-
## States
|
|
354
|
-
|
|
355
|
-
| State | In the menus | Instances there already |
|
|
356
|
-
| --- | --- | --- |
|
|
357
|
-
| available | shown | run and export |
|
|
358
|
-
| hidden, in 设置 | not shown | run and export |
|
|
359
|
-
| 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 |
|
|
360
|
-
| missing, or a package 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 |
|
|
361
|
-
|
|
362
|
-
In an export the package's script runs with `context.canEdit()` false: the block is drawn as on the page, read-only, every edit answering false, so draw nothing to drag or press there. What the instance holds shows by itself only where its script does not draw:
|
|
363
|
-
|
|
364
|
-
- a table part, with JavaScript off, in a Markdown export, and where the package is missing, turned off or failed;
|
|
365
|
-
- a script of data, drawn read-only by Gallery where the package is missing, turned off or failed (`context.fail`); nothing of it shows with JavaScript off.
|
|
366
|
-
|
|
367
|
-
A package whose template a menu cannot take is in no menu in any state; its instances are written by hand as `gallery component show` prints. The user chooses hidden and disabled, and can hide a block of Gallery's own too: `gallery component list` names those last, and you leave them out of what you write unless the user asks for one. Write an instance only of what `gallery component list` gives as a component to write with. A document never loses what an instance holds: moved, copied or sent to someone with no such package, it stays in the file.
|
|
@@ -1 +0,0 @@
|
|
|
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;--bacIntTra:#211b170d;--bacTerTra:#2a1c0012;--inputBac:#f2f1ee99;--codeBg:#f9f8f7;--blue:#2383e2;--blueLine:#2383e291;--blueBg:#2383e224;--bluBacIntTra:#0079e413;--select:#2383e224;--red:#eb5757;--star:#cb912f;--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;--bacIntTra:#ffffff0e;--bacTerTra:#fffff315;--bluBacIntTra:#4499ff1e;--inputBac:#ffffff0e;--codeBg:#ffffff08;--star:#d99e35;--overlay:#0f0f0fcc;--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;--bacIntTra:#ffffff0e;--bacTerTra:#fffff315;--bluBacIntTra:#4499ff1e;--inputBac:#ffffff0e;--codeBg:#ffffff08;--star:#d99e35;--overlay:#0f0f0fcc;--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 .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);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;box-shadow:inset 0 0 0 1px var(--borPriTra);color:var(--texPri);border-radius:6px;padding:0 14px;font-size:14px}.dialog-btn:hover{background:var(--bacIntTra)}.dialog-btn.primary{background:var(--blue);color:#fff;box-shadow:none}.dialog-btn.primary:hover{background:#1d74cc}.dialog-btn.danger.primary{background:var(--red)}.dialog-btn:focus-visible{outline:2px solid var(--blue);outline-offset:2px}.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}.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}}.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-switch:focus-visible,.xf-choose:focus-visible{outline:2px solid var(--blue);outline-offset:1px}.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(--blue);color:#fff;font-weight:500}.xf-btn.blue:hover{filter:brightness(.92)}.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{outline:2px solid var(--blue);outline-offset:2px}.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(--texPri);white-space:nowrap;border-radius:6px;flex:none;padding:0 10px;font-size:14px}.pref-save:hover:not(:disabled){background:var(--bacIntTra)}.pref-save:disabled{color:var(--texTer);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-text{flex:1;min-width:0}.comp-name{min-width:0;color:var(--texPri);overflow-wrap:anywhere;flex:1;font-size:14px;line-height:20px}.comp-meta{max-width:100%;color:var(--texTer);margin-left:8px;font-size:12px;display:inline-block}.comp-note{color:var(--texSec);overflow-wrap:anywhere;font-size:13px;line-height:18px}.comp-state{color:var(--texTer)}.comp-toggles{flex:none;align-items:center;gap:12px;display:flex}.comp-toggle{height:24px;color:var(--texSec);cursor:pointer;background:0 0;flex:none;align-items:center;gap:6px;padding:0;font-size:13px;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-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;align-items:center;gap:2px;height:22px;padding:0 4px 0 6px;display:inline-flex}.sec-toggle:hover,.sec-head.menu-open .sec-toggle{background:var(--bacIntTra)}.sec-label{color:var(--texTer);white-space:nowrap;font-size:12px;font-weight:500;line-height:16px}.sec-chev{width:12px;height:12px;color:var(--texTer);opacity:0;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:1;min-width:0;line-height:21px;overflow:hidden}.row-actions{flex:none;align-items:center;gap:2px;margin-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)}.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}.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-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-font.on .look-glyph,.look-option.on{color:var(--blue)}.look-font:focus-visible,.look-option:focus-visible{outline:2px solid var(--blue);outline-offset:-2px}.look-menu .menu-sep{margin:8px 12px 4px}
|