@heycys/gallery 0.2.2 → 0.2.4
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/README.md +1 -1
- package/THIRD-PARTY-NOTICES.md +1 -1
- package/assets/preview/runtime.js +156 -0
- package/assets/preview/shell.html +107 -0
- package/assets/writing-preferences.md +1 -1
- package/browser/editor/components/divider/index.mjs +1 -1
- package/browser/editor/page/annotate/card.mjs +6 -0
- package/browser/editor/page/annotate/index.mjs +22 -2
- package/browser/editor/page/columns/index.mjs +1 -1
- package/browser/editor/page/conflicts.mjs +1 -1
- package/browser/editor/page/drag/index.mjs +1 -1
- package/browser/editor/page/editor.mjs +43 -5
- package/browser/editor/page/focus.mjs +104 -0
- package/browser/editor/page/handle/index.mjs +14 -2
- package/browser/editor/page/links/index.mjs +2 -2
- package/browser/editor/page/quiet.mjs +3 -3
- package/browser/editor/page/resize/index.mjs +1 -1
- package/browser/editor/page/session.mjs +4 -1
- package/browser/editor/page/ui.mjs +1 -1
- package/browser/shared/annotations.mjs +22 -3
- package/browser/shared/block-packs.mjs +13 -4
- package/browser/shared/document-look.mjs +14 -0
- package/browser/shared/drafts.mjs +1 -1
- package/browser/shared/extension-manifest.mjs +40 -12
- package/browser/shared/favorite-merge.mjs +17 -0
- package/browser/shared/favorites.mjs +77 -0
- package/browser/shared/i18n/en.mjs +123 -24
- package/browser/shared/outline-ops.mjs +109 -0
- package/browser/shared/outline.mjs +6 -0
- package/browser/shared/pages.mjs +20 -8
- package/browser/shared/paths.mjs +5 -2
- package/browser/shared/preference-documents.mjs +137 -0
- package/browser/shared/presence.mjs +94 -0
- package/browser/shared/preview-server.mjs +8 -5
- package/browser/shared/qa-levels.mjs +9 -1
- package/browser/shared/session.mjs +4 -0
- package/browser/shared/shipped-blocks.mjs +22 -4
- package/browser/shared/startup.mjs +101 -0
- package/browser/shared/workspace-address.mjs +3 -0
- package/browser/shared/workspace-columns.mjs +1 -1
- package/browser/shared/workspace-look.mjs +21 -8
- package/browser/shared/workspace-registry.mjs +6 -3
- package/browser/shared/workspace.mjs +37 -10
- package/browser/shared/writing-preferences.mjs +2 -42
- package/dist/chunk-25LYSMAE.mjs +2 -0
- package/dist/chunk-2I6ZVC5O.mjs +2 -0
- package/dist/{chunk-M4NRDYI5.mjs → chunk-2MYTOOP6.mjs} +1 -1
- package/dist/chunk-2VNENLER.mjs +2 -0
- package/dist/chunk-3FERXZF5.mjs +4 -0
- package/dist/chunk-3M6SBBGU.mjs +2 -0
- package/dist/chunk-3VCAAF34.mjs +2 -0
- package/dist/{chunk-JXXHAXYH.mjs → chunk-3ZTRLGSA.mjs} +1 -1
- package/dist/chunk-4FRA5AUE.mjs +2 -0
- package/dist/chunk-4LR2QEC2.mjs +4 -0
- package/dist/chunk-56SVJENP.mjs +966 -0
- package/dist/chunk-5CQISL2G.mjs +4 -0
- package/dist/{chunk-RRKJMHNX.mjs → chunk-5I5ZDDWC.mjs} +5 -5
- package/dist/chunk-5IHDLEB4.mjs +10 -0
- package/dist/chunk-5LRDMV7O.mjs +2 -0
- package/dist/chunk-5MVUYRKG.mjs +5 -0
- package/dist/chunk-5TLLIZT7.mjs +2 -0
- package/dist/chunk-6ILJWFYW.mjs +4 -0
- package/dist/chunk-6N25CJ6Y.mjs +3 -0
- package/dist/{chunk-SQ6Y2ZMA.mjs → chunk-7DTINW6U.mjs} +2 -2
- package/dist/chunk-7KWAGKIK.mjs +2 -0
- package/dist/chunk-7WNUOAFK.mjs +2 -0
- package/dist/chunk-7XCRW5RC.mjs +2 -0
- package/dist/{chunk-ERE2BXYV.mjs → chunk-7XSDTILF.mjs} +1 -1
- package/dist/chunk-ABKYFOVR.mjs +2 -0
- package/dist/chunk-AMUF7PUN.mjs +2 -0
- package/dist/{chunk-PLB7L22J.mjs → chunk-B2EIMERT.mjs} +2 -2
- package/dist/{chunk-QNECWMGR.mjs → chunk-B45IAAU6.mjs} +1 -1
- package/dist/chunk-B6RAGF4R.mjs +2 -0
- package/dist/chunk-BSJKFE7I.mjs +4 -0
- package/dist/chunk-C72EEVLK.mjs +2 -0
- package/dist/chunk-CRAUKZ23.mjs +4 -0
- package/dist/chunk-F4CT35KL.mjs +2 -0
- package/dist/chunk-F63BNJLG.mjs +2 -0
- package/dist/chunk-FBKUPS44.mjs +2 -0
- package/dist/chunk-FL52ZL5Z.mjs +15 -0
- package/dist/chunk-FOZCU4VW.mjs +2 -0
- package/dist/chunk-G5HV7BC3.mjs +2 -0
- package/dist/{chunk-ERLAIBOA.mjs → chunk-GB5SOYQJ.mjs} +2 -2
- package/dist/chunk-GN3SG3IF.mjs +2 -0
- package/dist/{chunk-6QWQXHAV.mjs → chunk-HFTBVEZK.mjs} +1 -1
- package/dist/chunk-IOW5HLRK.mjs +2 -0
- package/dist/chunk-IQ3GJNTI.mjs +6 -0
- package/dist/chunk-K6SPFBUJ.mjs +2 -0
- package/dist/chunk-K7Y7SPTS.mjs +2 -0
- package/dist/chunk-L2IJCEUH.mjs +2 -0
- package/dist/{chunk-GPIWQ4X4.mjs → chunk-L3VT6LM4.mjs} +1 -1
- package/dist/chunk-L4WLQYFC.mjs +5 -0
- package/dist/{chunk-FFV733MA.mjs → chunk-LAMCAGK6.mjs} +1 -1
- package/dist/chunk-LHGKPMTI.mjs +2 -0
- package/dist/chunk-LJZIYVNA.mjs +3 -0
- package/dist/chunk-LSVCTLS2.mjs +2 -0
- package/dist/chunk-LZY74XTP.mjs +2 -0
- package/dist/chunk-MC4LRSVH.mjs +2 -0
- package/dist/chunk-MCEXN4G5.mjs +2 -0
- package/dist/chunk-MTLAOCFF.mjs +181 -0
- package/dist/chunk-MZ66LN3B.mjs +2 -0
- package/dist/chunk-N5QWJRRI.mjs +2 -0
- package/dist/chunk-NF4MMOUB.mjs +2 -0
- package/dist/chunk-NHJYAJ73.mjs +3 -0
- package/dist/chunk-NRSD7SVY.mjs +2 -0
- package/dist/chunk-NT23I4XW.mjs +2 -0
- package/dist/chunk-NUALABIS.mjs +3 -0
- package/dist/chunk-NW6LAU22.mjs +2 -0
- package/dist/chunk-NWWHDGKF.mjs +5 -0
- package/dist/chunk-OFRCVMSJ.mjs +2 -0
- package/dist/chunk-OKVQQ3CX.mjs +4 -0
- package/dist/chunk-OM24O4KR.mjs +8 -0
- package/dist/{chunk-4B2TB5K2.mjs → chunk-PBMOC7KA.mjs} +2 -2
- package/dist/chunk-PVTCP43W.mjs +2 -0
- package/dist/chunk-Q62HZAJS.mjs +2 -0
- package/dist/chunk-QBJWIR3Q.mjs +2 -0
- package/dist/chunk-QDSEZX7Z.mjs +6 -0
- package/dist/chunk-QR4V4A2Z.mjs +15 -0
- package/dist/{chunk-QVGOPHOF.mjs → chunk-QRLVVZ3R.mjs} +1 -1
- package/dist/chunk-QW3QG67J.mjs +2 -0
- package/dist/chunk-R2T2EVWY.mjs +8 -0
- package/dist/{chunk-GJJRBGMY.mjs → chunk-R5RERE6G.mjs} +1 -1
- package/dist/chunk-RFHEWT3Y.mjs +5 -0
- package/dist/chunk-RS2Z2JQP.mjs +2 -0
- package/dist/chunk-S6YEC4GE.mjs +16 -0
- package/dist/chunk-SHZLMGGW.mjs +2 -0
- package/dist/chunk-TALJQM2O.mjs +2 -0
- package/dist/chunk-TLNJWEFY.mjs +22 -0
- package/dist/{chunk-6Q7ASAXJ.mjs → chunk-TQZU7D7C.mjs} +1 -1
- package/dist/chunk-UTKNWYBA.mjs +2 -0
- package/dist/chunk-V3TM3TEN.mjs +2 -0
- package/dist/chunk-V3XROSP5.mjs +7 -0
- package/dist/{chunk-6QBHU4DF.mjs → chunk-V5JTW2LH.mjs} +1 -1
- package/dist/chunk-VAXLSISW.mjs +4 -0
- package/dist/chunk-VBHI3RG6.mjs +2 -0
- package/dist/{chunk-6L6V7YR2.mjs → chunk-VKZJRGDR.mjs} +1 -1
- package/dist/chunk-VZXZM7NS.mjs +2 -0
- package/dist/chunk-WDS6HEPE.mjs +2 -0
- package/dist/chunk-WHGANNEY.mjs +13 -0
- package/dist/chunk-WMJWC4QY.mjs +56 -0
- package/dist/{chunk-VZ2RQ3AM.mjs → chunk-WWONJJQS.mjs} +1 -1
- package/dist/chunk-X4WNLFIK.mjs +2 -0
- package/dist/chunk-XNNCQROX.mjs +11 -0
- package/dist/chunk-XRYECF23.mjs +170 -0
- package/dist/{chunk-K3JKPFL5.mjs → chunk-Z4NEXXFK.mjs} +1 -1
- package/dist/{chunk-236JJXWY.mjs → chunk-ZFVF2YPV.mjs} +2 -2
- package/dist/chunk-ZM2IX3R2.mjs +2 -0
- package/dist/chunk-ZNGGDUZI.mjs +2 -0
- package/dist/chunk-ZOEJQOKT.mjs +2 -0
- package/dist/cli.mjs +1 -1
- package/dist/server.mjs +1 -1
- package/dist/update-fetch.mjs +1 -1
- package/dist/worker.mjs +1 -1
- package/kit/runtime.js +1 -0
- package/package.json +1 -1
- package/release.json +4 -4
- package/skill/SKILL.md +54 -148
- package/skill/references/building-blocks.md +4 -4
- package/skill/references/charts-and-figures.md +73 -0
- package/skill/references/extensions.md +47 -4
- package/skill/references/pages-and-data.md +22 -3
- package/skill/references/preference-files.md +7 -0
- package/skill/references/previews.md +17 -0
- package/skill/references/writing-html.md +21 -82
- package/web/assets/index-B4uUluLM.js +15 -0
- package/web/assets/index-C3vHT8sH.css +1 -0
- package/web/index.html +2 -2
- package/dist/chunk-2KAVXMKG.mjs +0 -4
- package/dist/chunk-2T4PZQEP.mjs +0 -2
- package/dist/chunk-3SKOU6OZ.mjs +0 -10
- package/dist/chunk-3XZOA7AH.mjs +0 -170
- package/dist/chunk-4KUO7R2M.mjs +0 -16
- package/dist/chunk-4OZWXZE5.mjs +0 -5
- package/dist/chunk-4SNV4HA5.mjs +0 -2
- package/dist/chunk-53XDTHTG.mjs +0 -4
- package/dist/chunk-5XV3YYLG.mjs +0 -2
- package/dist/chunk-65NTKF4N.mjs +0 -6
- package/dist/chunk-6GV3CBB2.mjs +0 -2
- package/dist/chunk-6NLXUKAY.mjs +0 -4
- package/dist/chunk-6XD6U3QA.mjs +0 -5
- package/dist/chunk-7EFHNQ5B.mjs +0 -3
- package/dist/chunk-7ISBBDJR.mjs +0 -2
- package/dist/chunk-7M2BQQGZ.mjs +0 -2
- package/dist/chunk-7UZUQQ7Q.mjs +0 -554
- package/dist/chunk-ALZ6ZENZ.mjs +0 -3
- package/dist/chunk-BLNQUR5R.mjs +0 -168
- package/dist/chunk-BMX3VUHY.mjs +0 -2
- package/dist/chunk-BN7M3IN7.mjs +0 -8
- package/dist/chunk-C257H6IA.mjs +0 -2
- package/dist/chunk-CHQU37CA.mjs +0 -2
- package/dist/chunk-DR73Y2UJ.mjs +0 -3
- package/dist/chunk-E4IHAIJ7.mjs +0 -2
- package/dist/chunk-EURLTOTZ.mjs +0 -4
- package/dist/chunk-F4ZA6JRZ.mjs +0 -3
- package/dist/chunk-GKOBB6DH.mjs +0 -2
- package/dist/chunk-GMJD7ID3.mjs +0 -2
- package/dist/chunk-IA2SIEJQ.mjs +0 -2
- package/dist/chunk-JEUK3ZO7.mjs +0 -2
- package/dist/chunk-JPG2LBQM.mjs +0 -11
- package/dist/chunk-KLQP46Y3.mjs +0 -4
- package/dist/chunk-LMUZQK5O.mjs +0 -2
- package/dist/chunk-MKIBJTJZ.mjs +0 -6
- package/dist/chunk-MNWJ4EZY.mjs +0 -2
- package/dist/chunk-NHP66IWR.mjs +0 -5
- package/dist/chunk-OEIJLMPI.mjs +0 -2
- package/dist/chunk-PDZR3L3C.mjs +0 -2
- package/dist/chunk-PUOQ65NC.mjs +0 -2
- package/dist/chunk-Q4MS6OFC.mjs +0 -2
- package/dist/chunk-Q7P3Q5YX.mjs +0 -13
- package/dist/chunk-QP7BOHE4.mjs +0 -2
- package/dist/chunk-S3SX3COT.mjs +0 -20
- package/dist/chunk-TANZRINB.mjs +0 -2
- package/dist/chunk-UGWMMEJ5.mjs +0 -15
- package/dist/chunk-ULXSPX5H.mjs +0 -5
- package/dist/chunk-USIHBCSW.mjs +0 -15
- package/dist/chunk-VPMRP2TL.mjs +0 -2
- package/dist/chunk-WFGPMCTZ.mjs +0 -4
- package/dist/chunk-XZCFPKGO.mjs +0 -2
- package/dist/chunk-ZFGMJVJC.mjs +0 -2
- package/web/assets/index-FLb9jCfl.css +0 -1
- package/web/assets/index-czjrXVjf.js +0 -15
- /package/dist/{chunk-PAREWQGB.mjs → chunk-NOGQX56R.mjs} +0 -0
|
@@ -1,5 +1,20 @@
|
|
|
1
1
|
# Extensions: sidebar columns, workbench scripts and backends
|
|
2
2
|
|
|
3
|
+
An extension can add workbench buttons/panels, a backend service, a sidebar column, or a combination. Reuse Gallery's public UI API instead of reaching into private workbench DOM. Both program extensions and sidebar-only columns use the same extensions directory and settings list.
|
|
4
|
+
|
|
5
|
+
## Development workflow
|
|
6
|
+
|
|
7
|
+
1. `gallery extension new my-tool "My tool" --ui --server` creates a disabled program template that runs as it stands: with both flags its sidebar button calls the backend's `GET /hello` through the proxy (below) and toasts the answer, the round trip to build on. Use either flag alone for one capability. With no flags it creates the existing sidebar.json-only column.
|
|
8
|
+
2. Edit the generated files and AGENT.md, which describes how an Agent should use this extension. Never put account secrets in that file.
|
|
9
|
+
3. Run `gallery extension check my-tool --shot /absolute/path/check.png`. It validates extension.json and all declared files, starts an isolated sandbox copy, waits for its backend to listen, then checks its workbench script and lists slot buttons. `--press "My tool"` also clicks that button there and prints each backend request with its status and answer and each toast; a failed request, an error toast or a throw fails the check. Paths in its failures are your own files. A disabled original stays disabled. Failed backends report their exit code and last 20 log lines; UI failures report the extension's latest workbenchError. The sandbox isolates Gallery data, not OS permissions.
|
|
10
|
+
4. Enable it when requested: `gallery extension enable my-tool`. Use `gallery extension list --json` for current capabilities, backend status and workbenchError. UI errors from extension scripts/rejections appear in Settings too.
|
|
11
|
+
5. Edits anywhere under the extension directory (except dot files and node_modules) invalidate the revision. Running backends restart; activate/dispose modules reload with their dependencies. Legacy top-level scripts require refreshing the page. Keep generated data/logs in a dot directory to avoid restart loops.
|
|
12
|
+
|
|
13
|
+
For a visual proposal before implementation, see [previews.md](previews.md). Do not add a separate approval step when the user has already approved the implementation.
|
|
14
|
+
|
|
15
|
+
## Sidebar-only columns
|
|
16
|
+
|
|
17
|
+
|
|
3
18
|
An extension gives the sidebar a column of its own, beside the workspace's own column and those of the other workspaces: a list of links, nested if you like, that the user opens in the content area. Make one only when the user asks for it ("put my usual links in the sidebar", "an entry for my team's wiki"), or when a tool you are building must show entries of its own. A single web page the user wants in the sidebar is not an extension: `gallery link add <url> "<name>"` is.
|
|
4
19
|
|
|
5
20
|
All extensions live in the default workspace’s `extensions/<id>/`. `sidebar.json` supplies an optional column; `extension.json` independently supplies optional workbench scripts, styles, a backend and Agent instructions. Project-local extension folders are not read. `gallery extension new <id> "<title>"` creates an empty sidebar.json and prints its path. Read and edit that file; the command never overwrites it. Column order and hierarchy are stored in the shared tree.
|
|
@@ -60,28 +75,56 @@ Do not write `.gallery/outline.json` for an extension: where its column sits is
|
|
|
60
75
|
|
|
61
76
|
## Installing and enabling executable extensions
|
|
62
77
|
|
|
63
|
-
Run `gallery extension install <folder | .zip>` to validate and install a complete extension in the default workspace. A ZIP may contain files at its root or inside one enclosing folder. The optional manifest `id` names the destination; otherwise the source folder/ZIP basename does. Replacement stages all files first and stops the old backend before swapping folders.
|
|
78
|
+
Run `gallery extension install <folder | .zip>` to validate and install a complete extension in the default workspace. A ZIP may contain files at its root or inside one enclosing folder. The optional manifest `id` names the destination; otherwise the source folder/ZIP basename does. Replacement stages all files first and stops the old backend before swapping folders. `gallery extension remove <id>` stops its backend and removes its folder. These commands use the running Gallery service when available.
|
|
64
79
|
|
|
65
|
-
`gallery extension list` prints capabilities and the declared Agent instruction path. When the user’s task relates to an extension, read that AGENT.md before acting.
|
|
80
|
+
`gallery extension list` prints capabilities and the declared Agent instruction path; `gallery extension list --json` returns machine-readable details. When the user’s task relates to an extension, read that AGENT.md before acting. New installs are disabled by default. Use `gallery extension enable <id>`, `gallery extension disable <id>`, or `gallery extension install <folder | .zip> --enable` to set the switch. Updates retain it; a broken manifest can be disabled but not enabled. Extensions run with Gallery's permissions: enable trusted extensions. `gallery open --settings extensions` opens their settings. Backends start lazily on the first API request, stop when disabled/removed or Gallery exits, and restart after crashes with exponential backoff.
|
|
66
81
|
|
|
67
82
|
Example `extension.json` (all capability fields optional):
|
|
68
83
|
|
|
69
84
|
```json
|
|
70
85
|
{
|
|
71
86
|
"id": "yuque-publish",
|
|
87
|
+
"name": "语雀发布",
|
|
88
|
+
"version": "1.0.0",
|
|
89
|
+
"description": "发布文档到语雀",
|
|
90
|
+
"icon": "📗",
|
|
72
91
|
"workbench": { "script": "workbench.js", "style": "workbench.css" },
|
|
73
|
-
"server": { "command": ["node", "server.mjs"] },
|
|
92
|
+
"server": { "command": ["node", "server.mjs"], "timeout": 90000 },
|
|
74
93
|
"agent": "AGENT.md"
|
|
75
94
|
}
|
|
76
95
|
```
|
|
77
96
|
|
|
78
|
-
Workbench files are served at `/__gallery/extensions/<id>/files/<relative-path>`. Paths cannot leave the extension directory or traverse symlinks. Scripts load
|
|
97
|
+
Workbench files are served at `/__gallery/extensions/<id>/files/<relative-path>`. Paths cannot leave the extension directory or traverse symlinks. Scripts load as modules only in the workbench; a cached module can be activated again after it is re-enabled. The API is available before scripts load:
|
|
79
98
|
|
|
80
99
|
- `window.gallery.slot('topbar-end')`: a stable container before the favorite button (also available on custom pages). No topbar is added to online webpages.
|
|
81
100
|
- `window.gallery.slot('sidebar-footer')`: a stable container above Settings.
|
|
82
101
|
- `window.gallery.onRoute(callback)`: immediately reports the current route, then changes; returns an unsubscribe function. Value: `{kind, ws, slug, link, title}`. `slug` is the owner-local folder name, `ws` the owner’s registry ID; `link` is the workbench URL.
|
|
83
102
|
- `await window.gallery.token()`: token for authenticated API requests.
|
|
84
103
|
|
|
104
|
+
For immediate enable, disable and update, export `activate(api)` from the workbench module. It may synchronously or asynchronously return a `dispose` function, called on disable or update. `api.slot(name)` provides this extension's own child container; Gallery removes it on disable even if no disposer is returned. Existing top-level scripts and `window.gallery` remain supported, but disabling or updating a legacy top-level script requires a page refresh to undo its effects. Stable UI classes for extensions are `g-icon-btn`, `g-sidebar-row`, `g-switch`, `g-input`, `g-btn` and `g-btn primary`; `window.gallery.toast`, `window.gallery.confirm` and `window.gallery.menu` provide common workbench interactions. `data-tip` also works on extension elements.
|
|
105
|
+
|
|
106
|
+
Sidebar icons use `--sidIco` in both themes. Buttons with `g-icon-btn` inside `sidebar-footer` and icons in `g-sidebar-row` inherit this styling automatically; use `color: var(--sidIco)` for custom sidebar icon controls. Topbar buttons keep the normal workbench icon color.
|
|
107
|
+
|
|
108
|
+
For extension development, run `gallery sandbox --extension <directory> --demo` in a foreground terminal. Open its printed address, or pass `--open`. The sandbox installs a separate enabled copy and reinstalls it when the source changes, preserving the switch in Settings. Legacy scripts need a page refresh. Ctrl+C removes the sandbox; use `--keep` to inspect the copy afterward. `--from <workspace>` copies existing content. Use `gallery sandbox env <name>` in a separate shell to target the sandbox with CLI commands. Run only extensions you trust: backends have your local OS permissions.
|
|
109
|
+
|
|
110
|
+
A lifecycle-aware script can use the scoped API and return cleanup for its own subscriptions or other effects:
|
|
111
|
+
|
|
112
|
+
```js
|
|
113
|
+
export function activate(api) {
|
|
114
|
+
const button = document.createElement('button');
|
|
115
|
+
button.className = 'g-btn primary';
|
|
116
|
+
button.textContent = 'Publish';
|
|
117
|
+
button.onclick = () => api.toast('Ready', { tone: 'info' });
|
|
118
|
+
api.slot('topbar-end').append(button);
|
|
119
|
+
const off = api.onRoute(route => { button.title = route.title; });
|
|
120
|
+
return () => off(); // Gallery also removes this extension's slot containers
|
|
121
|
+
}
|
|
122
|
+
```
|
|
123
|
+
|
|
124
|
+
The scoped API also has `token()`, `toast(message, { tone, action: { label, run } })`, `confirm({ title, message, actions, cancelId })` (returns the chosen action id), and `menu(anchor, entries)`. Confirmation actions have `{ id, label, primary?, danger? }`; menu entries have `{ label, onSelect?, danger?, disabled? }` or `{ kind: 'sep' }`. A switch uses `<span class="g-switch on"><span></span></span>` for its visual part. These methods are also available on `window.gallery` for existing scripts; use the scoped API inside `activate` so Gallery can clean its route listeners and slots. The settings link `#settings/extensions` opens the extension list and is consumed when opened.
|
|
125
|
+
|
|
126
|
+
The manifest's optional `name`, `version` and `description` appear in the list; `icon` is an emoji or a relative PNG, JPEG, WebP, GIF or SVG file inside the extension. The backend proxy times out after 30 seconds without socket activity by default. Set `server.timeout` to a whole number of milliseconds from 1000 to 600000 when a backend operation needs a longer idle interval; alternatively stream progress or heartbeats.
|
|
127
|
+
|
|
85
128
|
Use Gallery’s CSS variables: `--texPri`, `--texSec`, `--bacPri`, `--sidBac`, `--bacIntTra`, `--btnPriBg`, `--btnPriTex` (see the workbench theme for the full set). Do not select internal DOM class names. Slots retain their elements as pages change.
|
|
86
129
|
|
|
87
130
|
Backend commands run without a shell, with cwd set to the extension folder and the service’s environment and system permissions. `node` uses Gallery’s Node executable. Listen on `GALLERY_EXTENSION_HOST` (127.0.0.1) and `GALLERY_EXTENSION_PORT` (also `PORT`); `GALLERY_EXTENSION_ID` identifies the extension. Logs are `<data>/logs/extensions/<id>.log`. This internal port is managed by Gallery; users always use the one public Gallery address.
|
|
@@ -1,6 +1,25 @@
|
|
|
1
1
|
# Custom pages, and what a block reads beyond its own parts
|
|
2
2
|
|
|
3
|
-
A block stands in a document, on a custom page (自定义页: a page of the user's that you design, a board of cards being one way to write it;
|
|
3
|
+
A block stands in a document, on a custom page (自定义页: a page of the user's that you design, a board of cards being one way to write it; [Working on a custom page](#working-on-a-custom-page) is the flow on a page) or in both. [building-blocks.md](building-blocks.md) is the block itself (the kinds of part, the files, the manifest, an instance, its style, and the two places side by side in A document and a custom page) and [block-script.md](block-script.md) is its script. This page holds what only some blocks need: the manifest fields that place a block, size it as a card and give it settings; the flow of a block made for a page; and the three things a block may read beyond its own parts, each a `needs` entry: the workspace's data (`workspace`), a table of its document (`tables`) and the web (`net:<host>`).
|
|
4
|
+
|
|
5
|
+
## Working on a custom page
|
|
6
|
+
|
|
7
|
+
A custom page is the user's own page in the workbench's sidebar, yours to design when they ask for a page or a card ("首页加一张卡片…", "给我做一个读书页"): the folder `pages/<slug>/` of the workspace, `page.html` (any HTML, CSS and script of yours, [below](#a-page-is-yours-to-design); a board of cards is one way: `<div class="gallery-board" data-board-id="main">`, each card a `<section class="gallery-card" data-card-id="…" data-x data-y data-w data-h>` around one custom block's instance, in square cells, twelve to a row) and `page.json` (its title and icon), opened at `/#@<slug>`. A page is no document: no opening summary, no source line, no export, and no 写作偏好 to read for rules (a `gallery list` that made it in passing changes nothing of that). A card made for "me" (my tasks) needs who that is: a setting of the card, not written into a block's code, asked or taken as step 4 says (写作偏好 may name them: read it for that alone).
|
|
8
|
+
|
|
9
|
+
On a board the user moves, resizes, adds and deletes cards there (the grip at a card's top-right corner: a drag moves it, a click opens its menu, 大小, 设置… and 删除; 添加自定义块 is the first row of the ··· menu in the workbench's top bar, and puts a card on the page's first board), and types in them. Keep that corner clear (28 × 28 px, 6px in). The page draws no big title: its name is the sidebar's, the tab's and the top bar's, so write no `<h1>` of the page's name (one in `header.gallery-page-head` is not drawn). Its look is yours to choose (a header of your own that is no title, colors of its own in its `<style>`), written for both themes. Its own scripts are yours too, a board or none; what a card does is its block's, which the server puts in.
|
|
10
|
+
|
|
11
|
+
Reordering, renaming and trashing pages, and changing a card already on one, are the user's to ask you for, not yours to do unasked. When they ask: `gallery page set <page> --title … --icon …` renames, `gallery page move <page> --after <page>|--first` reorders, `gallery trash <page>` trashes (`gallery trash restore` puts it back), `gallery page card <page> <card id>` sets (`--set k=v`), moves (`--move x,y`), resizes (`--size w,h`) or removes (`--remove`) a card, and `gallery page reset-cards <page>` brings back the default cards (`gallery help page` has the options). They write through the server, so the open page updates at once.
|
|
12
|
+
|
|
13
|
+
1. Run `gallery page list` and `gallery block list` first: the pages there are, and the blocks a card can be (自定义页可用, and Gallery's own not yet added). "首页" is `pages/home` (a page as any: the user may rename or trash it). Gallery makes it once, when its server first starts in a workspace (`gallery init` does too), with its own cards, which the user may have moved, filled in or taken off; until then `gallery page list` and the commands of `home` say it is not made yet, and `gallery open --no-browser` makes it: run that once, then again. Extend it with `gallery page add home <block>`, not by writing its `page.html` over whole; one the user trashed stays away. A new page only when the user asks: `gallery page new <slug> "<title>"`. A blank page they made in the sidebar (新建页面, `page-…`, an empty main) is one to write whole.
|
|
14
|
+
2. Send the address first, before you write any card: the `交给用户(…):` line of `gallery page new <slug> "<title>"` (a server running prints it; without one, `gallery page open <slug> --no-browser` does), or of `gallery page open home --no-browser` for the home page, in a message of its own: the user watches the cards arrive.
|
|
15
|
+
3. On a page that is there, change only the cards the request needs. Every other card keeps its `data-card-id`, its place and its data parts as they are: the user placed them, and a note's words are theirs. Put a card on with `gallery page add <slug> <block>` (the first free spot by the block's default size, or `--x --y --w --h`; it gives the card its id and pushes down what it meets); re-read `page.html` right before each change you make in it by hand, and replace that card alone.
|
|
16
|
+
4. Use one of Gallery's own blocks when it fits the request exactly (two packs: Gallery 风格's by a bare name, and 柔光风格's as `gallery-soft/<name>`; `gallery block add <name>` puts one in, and comes before `gallery page add`): `today`, `note`, `countdown`, `habit`, `weather` (a city's weather, from Open-Meteo: it goes online), and `todos`, `recent`, `stats`, `heatmap`, which read the workspace (its to-dos, the documents edited last, its counts, its edits by day; the user ticks a to-do on `todos`, and the tick is written into the document it is in as the user's own edit, which the page's Ctrl+Z takes back); and `gallery/static` for a card that only shows what you write (a heading, links, a short list, a picture: its file in `pages/<slug>/assets/`, written `assets/<file>`; it is for a custom page alone, a document's HTML is written as it is; it takes any size of cells, 4 × 4 at first, and does not grow with its words, so write the `data-w` and `data-h` it needs).
|
|
17
|
+
- When one is close but not exact (other fields, another look, another rule), do not settle for it, and do not write a block from nothing either: copy it with `gallery block new <id> --recipe <name>` and change the copy (a count by day, glasses of water or times, starts from `habit`: `gallery block new <id> --recipe habit`; a recipe takes no `--script`, `--flow`, `--data` or `--page`): its name, words, description, `preview.svg`, writing.md and example.html, which the command lists; Gallery's own stays as it ships.
|
|
18
|
+
- Make a block of your own from nothing ([building-blocks.md](building-blocks.md), and [A block for a custom page](#a-block-for-a-custom-page) below for a card's size and settings; `gallery block new <id> --page --data` for a card that keeps what the user enters, `places` holding `page`) for a card that does something or keeps data the user changes that none of Gallery's is near, and for a read-only card over the workspace's data or the web's that none of Gallery's shows (a count by day, a rate, a feed, the rows of another document's table: `kanban`, `metric` and `chart-view` are views inside a document and read no table from a page): it is a block too (`needs` `workspace` or `net:<host>`; start from `heatmap` or `weather` with `--recipe`), not the page's own script or HTML. What a card holds stays in its card (a data part, its settings), not in the page's own HTML.
|
|
19
|
+
- A card that shows nothing without a setting the user did not give (`weather`'s city, `countdown`'s date, a block of your own with its owner) is asked about: ask the user, or take it from what the workspace says (写作偏好, the documents; ask when that is a guess), and tell them in the handoff what it holds and where you took it from, or that the card still asks for it. Give it with the add, `gallery page add home weather --set city=上海` (each `--set <key>=<value>`, no JSON to quote, held to the setting's type: a date is `YYYY-MM-DD`); for a card already there, `gallery page card <slug> <card id> --set <key>=<value>`. `gallery page check` notes a card whose required setting is empty.
|
|
20
|
+
- The switches of 设置 › 组件列表, when the user asks for one: `gallery block pack on|off <pack>` (柔光风格 is off until they ask), `gallery block menu on|off <block>` (whether the documents' "/" menu offers it), `gallery block net on|off <block>` (allow it to go online: it lists the sites first; only when the user explicitly asks for that block).
|
|
21
|
+
5. Try each gesture of a new block on its card: `gallery page try <slug> <card id> --press <selector>` (the gestures and `--steps` of `gallery block try`, on a scratch copy of the page): its `Wrote:` lines name that card's data parts alone, then the page's own Ctrl+Z gives the copy back and a fresh page reads it back; a write anywhere else (another card, the card's place) is a `FAIL`, and its exit codes are `gallery block try`'s. Then `gallery page check <slug>` until it prints `OK`: each `FAIL page.html:<line>` (an id missing or twice, cards sharing cells or past the row, a block a page does not run, a file of `assets/` not there or a frame of one, a card whose content does not fit it, a script of the page that never ends; the page's own scripts and stylesheets pass). Open the pictures it lists (1280, 1920 and 600px wide, light and dark) and read its `Changes since …` lines: they name the cards you meant to change and no other, but those that end `(the user's, on the page)`, the user's own gestures on the page since the last check (a card moved, words typed in it): leave those as they are, and do not put one back. A line that ends `(put there by Gallery)` is the home page's own today or note, there before you came (a new workspace's first check of `home` lists them): leave those too. A note that a card was pictured before the workspace answered its read means its picture says nothing of what it shows: open the page in Gallery or check again. `UNVERIFIED` (exit 3) is a page not looked at in a browser (its structure was checked): run it once more.
|
|
22
|
+
6. At the end tell the user what you changed (each card, by what it shows) and where: the page's title in the sidebar (with 新建 and 搜索), and the address again. A card that goes online (`weather`, or a block whose needs name `net:<host>`) shows nothing until the user allows it: tell them to press 允许访问 on the card ([Going online](#going-online)).
|
|
4
23
|
|
|
5
24
|
## A page is yours to design
|
|
6
25
|
|
|
@@ -37,7 +56,7 @@ What a reader edits in each place is in [Which kind of part](building-blocks.md#
|
|
|
37
56
|
|
|
38
57
|
Gallery's own blocks in a workspace (`components/gallery/<name>/`) follow Gallery: a copy as it was added is brought up to a newer Gallery's by itself, as the workspace's server starts or reads its blocks, so change no file of one (a copy someone changed stays at its version, Gallery's newer one not put over it); for a card like one of them, start your own from it with `gallery block new <id> --recipe <name>`.
|
|
39
58
|
|
|
40
|
-
Make one only where no block of Gallery's does the job and the card does something or keeps data the user changes: a card that only shows what you write is `gallery/static` (
|
|
59
|
+
Make one only where no block of Gallery's does the job and the card does something or keeps data the user changes: a card that only shows what you write is `gallery/static` (step 4 of [Working on a custom page](#working-on-a-custom-page); a heading it starts with, where more follows, is drawn as the cards' head row). The flow is [the one of building-blocks.md](building-blocks.md#the-flow), with the page in place of the document:
|
|
41
60
|
|
|
42
61
|
1. `gallery page list` and `gallery block list`, then `gallery block new <id> --page` (with `--data` for a card that keeps what a reader enters, as the goals card below: its field, its buttons and an `example()` that works on an empty card), its places `["page"]` already (and `"document"` too only when a document may hold it).
|
|
43
62
|
2. Its files: the manifest with `card` and, where the user sets something per card, `settings`; `template.html` holding a new card's data, the settings part `{}`; `kit.js` drawing from the parts on `source`, writing them by `context.edit` or `context.editJSON`, and reading its size on `layout` (`context.size`, the card's cells and pixels: lay a small card out otherwise than a big one). What a reader types goes through a field the block draws (`DocKit.input`: Enter or leaving it commits, never while an input method composes), never a text part, which a page shows read-only; no slot (a page holds no document's blocks: the check refuses one). Then `gallery block check <id>` until it prints `OK`.
|
|
@@ -220,6 +239,6 @@ DocKit.component({
|
|
|
220
239
|
|
|
221
240
|
- **It resolves** with `{ data, at, cached }`: `data` the answer's JSON (`as: "json"`, the default) or its text (`as: "text"`), `at` when it was fetched (an ISO time: say it on the card, 更新于 …, as an answer may be old where the network is not there), `cached` whether it was given from what was kept. Fetch again on `source` (a setting changed) and on a timer (`context.interval`, every few minutes at least: an answer of the last minute is given again, and a block may make 20 fetches a minute).
|
|
222
241
|
- **It rejects** with an `Error` whose `code` says why, which the block draws a state for: `consent` (the user has not allowed it yet; `hosts`, those waiting), `offline` (no network or the site not reached, and nothing kept; in an exported file, nothing embedded), `status` (the site answered an error, `status`), `type` (no JSON or text), `too-large`, `rate`, `key`, `private` (below), and `host` or `url` for an address it may not ask for (a host its needs do not name, or a redirect to one; another port, a user in it, not http(s), its own or a redirect's): fix the block. `private` is usually the reader's network setup, not the block: the address the name resolved to is on this computer or a private network, and no proxy on this computer took the name (the address is http, there is no proxy, the proxy is on another machine, or it is not running; an https address whose name resolves so is reached through a proxy on this computer by its name, its certificate held to the name). The Error's message names the host and the address, and `host` is set. Draw a plain state for it in the reader's words, as `gallery/weather` does (网络设置把天气服务指向了本地地址), not the generic failure.
|
|
223
|
-
- **Consent.** Until the user allows the block, every fetch rejects `consent` and Gallery draws over its card, under its head row, a banner of its own: your manifest's `card.consent` (else 允许联网之后显示内容), 数据来自 the site its hosts share (else <host> 等 N 个网站) and a button, 允许访问 (on a card three cells wide or less, the line over the button); pressed, Gallery asks the user, and once they say yes the block starts again by itself (its mount runs anew, and fetches). The user can take it back in 设置 › 组件列表 (允许联网), and the block starts again and asks. Draw a short state of your own for `consent` too (the button stands over it). In the handoff, tell the user to press 允许访问 on the card
|
|
242
|
+
- **Consent.** Until the user allows the block, every fetch rejects `consent` and Gallery draws over its card, under its head row, a banner of its own: your manifest's `card.consent` (else 允许联网之后显示内容), 数据来自 the site its hosts share (else <host> 等 N 个网站) and a button, 允许访问 (on a card three cells wide or less, the line over the button); pressed, Gallery asks the user, and once they say yes the block starts again by itself (its mount runs anew, and fetches). The user can take it back in 设置 › 组件列表 (允许联网), and the block starts again and asks. Draw a short state of your own for `consent` too (the button stands over it). In the handoff, tell the user to press 允许访问 on the card. The consent is the user's to give: turn it on yourself (`gallery block net on <block>`, which lists the sites first) only when they explicitly ask you to, and do not write it into `gallery.json` (its `components.net`) by hand, nor ask `gallery block try` or `gallery page try` to; `gallery page check`'s pictures show the card asking.
|
|
224
243
|
- **A key.** An API that wants one in its address names where it goes by `{key}`, in its path or its query (`https://api.example.com/v6/{key}/latest`, `…/latest?apikey={key}`), and `gallery block key <host> <key>` keeps the user's key for that host in the workspace (`.gallery/keys.json`): the server writes it in as it fetches, and no page, cache or export ever holds it. Never write a key into the block's files or a page. Prefer an API that needs none. An API that takes its key in a header alone is not reached.
|
|
225
244
|
- **A document and its export.** In a document an instance fetches as on a page; its export holds what the document's instances were given last (`context.fetch` answers from it, `cached: true`) and, for an address it holds nothing of, rejects `offline`: draw a placeholder for that, as the example does. `context.place` is `"export"` there.
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
# Writing preferences
|
|
2
|
+
|
|
3
|
+
Run `gallery preferences list` before writing or revising a document. It prints enabled files only, in configured order, with titles and absolute paths. Select the applicable files by title and scope, then read their contents; don't apply every report type to every task. For conflicts: the current user request, then applicable preferences in listed order (earlier first), then the skill.
|
|
4
|
+
|
|
5
|
+
A new Gallery starts with only `<home>/preferences/项目报告写作.md`. The old `<home>/preferences.md` is migrated to it, preserving its body, enabled state and order. Every preference lives in `<home>/preferences/<name>.md`. Settings → 写作偏好 creates/duplicates/renames/deletes tabs, reorders them and switches each on or off. A tab rename updates the Markdown filename and title; the initial document follows the same rules as all other preferences. Renaming or deleting it never recreates an extra default. Saving saves all modified tabs; switching tabs keeps their unsaved work. Closing discards unsaved content.
|
|
6
|
+
|
|
7
|
+
Enabled state and order are in `gallery.json` under `preferences: { order: [...], off: [...] }`, with paths relative to home. Unlisted new files are enabled at the end; missing files are ignored. Disabled files stay in place and are not instructions for the current task. `gallery preferences list --all --json` includes disabled files for managing settings; `gallery preferences on|off <name>` changes one. Only change files, order or enabled state when the user asks. Never add preferences on your own. Custom pages do not use document writing preferences.
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
# Interactive UI previews
|
|
2
|
+
|
|
3
|
+
Use a preview when the user asks to compare UI designs, see a prototype, or inspect a new extension's interface before implementation. For an already approved change, proceed with implementation; this tool adds no mandatory approval gate.
|
|
4
|
+
|
|
5
|
+
`gallery preview new settings` creates settings.page.html. Edit its body using existing Gallery classes and CSS variables. Then run `gallery preview settings.page.html --open --shots /absolute/path/shots`. The generated settings.preview.html is a standalone file that opens by double-click. `--out` chooses its path; `--only light,dark` selects named screenshots. Local linked scripts/styles are embedded. Remote resources and image/CSS URLs must be embedded by the author if offline delivery requires them.
|
|
6
|
+
|
|
7
|
+
The page's JSON script with id preview-config accepts title, hint, options (key/label/values), widths (name → pixels, 0 fills the window), viewport [1280,800] and shots [{name,state,run?,wait?}]. Theme and width are toolbar controls; current state is in the URL hash. Set gallery:false for generic pages. `shots[].run` is trusted JavaScript executed in the preview frame to reach a state. Screenshots use Gallery's Chrome/Edge tools with a separate temporary profile and fail on script errors.
|
|
8
|
+
|
|
9
|
+
Example JSON inside the page’s preview-config script:
|
|
10
|
+
|
|
11
|
+
```json
|
|
12
|
+
{"title":"Settings","widths":{"normal":0,"narrow":560},"shots":[{"name":"light","state":{"theme":"light"}},{"name":"dark","state":{"theme":"dark"}},{"name":"narrow","state":{"width":"narrow"}}]}
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
Use body data-backdrop="gallery" for a muted workbench backdrop. window.preview provides on(fn), state, set(next), toast, confirm, menu, closeMenu, hideTip, icon and esc. on(fn) runs once and on toolbar changes; ignore theme/width changes when they don't require rerendering. data-tip shows a tooltip. Menu and confirm dialogs handle Escape before the page.
|
|
16
|
+
|
|
17
|
+
Include meaningful states (empty, errors, disabled, detail, narrow, light/dark), inspect the actual screenshots, then give the user the standalone HTML and describe what is interactive. Rebuild after Gallery upgrades to pick up its current stylesheet.
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# Writing the page
|
|
2
2
|
|
|
3
|
-
The rules behind the blocks of [example-report.html](example-report.html).
|
|
3
|
+
The rules behind the blocks of [example-report.html](example-report.html), which shows each block once.
|
|
4
4
|
|
|
5
5
|
Write the document as an ordinary web page, with a class only where HTML has no element. `gallery export` rewrites in `doc.html` what the kit has a block for as the kit's markup and gives every block its `data-block-id`; `gallery check <slug>` lists what it would rewrite and changes nothing.
|
|
6
6
|
|
|
@@ -17,7 +17,7 @@ Each block by the name Gallery's menu gives it (the user's word for it), what yo
|
|
|
17
17
|
| 文本, 标题 2–4 | `<p>`, `<h2>`–`<h4>` | | Text and lists |
|
|
18
18
|
| 符号列表, 编号列表, 引用块 | `<ul>`, `<ol>` (`start`, `data-continue`), `<blockquote><p>` | | Text and lists |
|
|
19
19
|
| 待办事项 | `<ul><li><input type="checkbox" checked> …` | `ul.doc-todo` | Text and lists |
|
|
20
|
-
| 分割线 | `<hr>`
|
|
20
|
+
| 分割线 | `<hr>` where a visual break is useful | | The page |
|
|
21
21
|
| 折叠列表 | `<details><summary>`, never the kit's classes on it | `details.doc-details` | Text and lists |
|
|
22
22
|
| 代码块 | `<pre data-title="…"><code class="language-…">` | `div.doc-code[data-language]` | Text and lists |
|
|
23
23
|
| 公式块, a formula in a line | `<p>\[…\]</p>`, `\(…\)` | | Text and lists |
|
|
@@ -42,11 +42,11 @@ Each block by the name Gallery's menu gives it (the user's word for it), what yo
|
|
|
42
42
|
`gallery new` writes the head, the header with the title, and a starter section, which you replace; the source line and the opening summary are yours to write.
|
|
43
43
|
|
|
44
44
|
- `data-doc-id` is the slug, `<html lang>` the page's language.
|
|
45
|
-
- `doc.json`, beside the page, holds its `title`, `description` and `type` (free text naming the kind of document; `gallery new`'s `report` is fine), and may hold `source`: the most precise locator of the dataset, experiment report, document or query the materials come from (say so when that is only a supplied draft or example). Its
|
|
46
|
-
- The header holds the title, an icon before it if any (`.doc-icon`, which `gallery set --icon` writes), and at most one line of small text, the source line. The source line says in words a reader elsewhere understands where the materials come from (组内项目 X 的论文终稿与 rebuttal 材料), or names a file of `materials/`;
|
|
45
|
+
- `doc.json`, beside the page, holds its `title`, `description` and `type` (free text naming the kind of document; `gallery new`'s `report` is fine), and may hold `source`: the most precise locator of the dataset, experiment report, document or query the materials come from (say so when that is only a supplied draft or example). Its title, icon and description are the sidebar's, and the title and icon the page header's too: change them with `gallery set <slug> --title "…" --icon <emoji, or none> --description "…"`, which writes the header and `doc.json` in step. It may also hold `look`, the reader's 字体与布局 (font, text size, spacing and width; the workspace's `gallery.json` may hold a default one): keep it as it is whenever you rewrite `doc.json`, write it into the page nowhere, and change it only when the user asks (`gallery set --font …`: `gallery help set`).
|
|
46
|
+
- The header holds the title, an icon before it if any (`.doc-icon`, which `gallery set --icon` writes), and at most one line of small text, the source line. The source line says in words a reader elsewhere understands where the materials come from (组内项目 X 的论文终稿与 rebuttal 材料), or names a file of `materials/`; it holds no path of this machine (`D:\…`, `C:\Users\…`, `/home/…`), which the checks flag. The same holds for a scope line's 来源. Nothing else goes between the title and the opening summary.
|
|
47
47
|
- The opening summary comes right after the header, before the first section: `<section class="doc-summary" aria-label="概括">` (a 写作偏好 written before may write `aria-label="报告概括"`: the same block; keep the label 写作偏好 gives), a few headings as paragraphs of bold words (no `h2`–`h6`), each followed by a paragraph or a list. 写作偏好 may say what it holds; when it says nothing, a document written from materials still has one, unless the user asks for another structure or you convert a finished report. Its headings are short noun phrases that fit the kind of report (实验背景, 用途, 展区与展品 …); 写作偏好 says which.
|
|
48
|
-
- A section groups
|
|
49
|
-
- The document's own CSS goes in one inline `<style>` using the kit's variables: colors, which follow the dark theme (`--doc-text`, `--doc-muted`, `--doc-border`, `--doc-grid`, `--doc-surface`, `--doc-bg`, `--doc-accent`, `--doc-series-1` … `-6`), and fonts and sizes (`--doc-font`, the text's; `--doc-mono` or `--doc-code-font`, monospace, a code block's the second; `--doc-body-font-size`, 16px; `--doc-small-font-size`, 13px, small text). Use only the `--doc-*` names this page gives: another may name nothing, and its `var()` then quietly falls back (`--doc-mono-font` names nothing). Its code goes in one inline `<script>` at the end of `body`; the kit's own tags are added when the page is shown or exported. The checks read the script as strict TypeScript would: a type error is a note (guard a value where it can really be null), a syntax error or a name nothing defines a failure. Write JavaScript, a type in JSDoc if any (`/** @type {…} */`),
|
|
48
|
+
- A section optionally groups related blocks and draws nothing by itself. Use one when moving or organizing those blocks together is useful; it does not require a divider or a heading. Add headings and `<hr>` only where the content needs them, rather than repeating “divider + heading + content” for every group. Existing dividers are independent blocks: preserve their ids when moving them. Text may also stand straight in `main`.
|
|
49
|
+
- The document's own CSS goes in one inline `<style>` using the kit's variables: colors, which follow the dark theme (`--doc-text`, `--doc-muted`, `--doc-border`, `--doc-grid`, `--doc-surface`, `--doc-bg`, `--doc-accent`, `--doc-series-1` … `-6`), and fonts and sizes (`--doc-font`, the text's; `--doc-mono` or `--doc-code-font`, monospace, a code block's the second; `--doc-body-font-size`, 16px; `--doc-small-font-size`, 13px, small text). Use only the `--doc-*` names this page gives: another may name nothing, and its `var()` then quietly falls back (`--doc-mono-font` names nothing). Its code goes in one inline `<script>` at the end of `body`; the kit's own tags are added when the page is shown or exported. The checks read the script as strict TypeScript would: a type error is a note (guard a value where it can really be null), a syntax error or a name nothing defines a failure. Write JavaScript, a type in JSDoc if any (`/** @type {…} */`), not `: number`.
|
|
50
50
|
|
|
51
51
|
## Text and lists
|
|
52
52
|
|
|
@@ -68,13 +68,13 @@ A code block's title (`data-title`, or a `<figcaption>` beside it in a `<figure>
|
|
|
68
68
|
|
|
69
69
|
In a file that holds the kit's markup (after an export or the user's first edit in the preview), still write what you add as plain HTML: the preview and the export convert it. To chart a table the file already holds, put `data-doc-chart="<type>"` on its `table.doc-table`, the type one your script defines ([below](#figures-and-charts)), with a `<caption>` first in it for the card's title; when the `p.doc-note` right above the table is its former caption (a title, not a scope or unit line), move its words into the `<caption>` and delete the note.
|
|
70
70
|
|
|
71
|
-
A table's scope or unit line (`p.doc-note` right above it, or `p.doc-table-meta` in older documents) moves with the table. When the table becomes another block (Sheet tabs, a chart, a list), its line goes with the data, or is dropped once the new block says the same. A table folded into a disclosure: its former caption (a `p.doc-note` above it that is a title
|
|
71
|
+
A table's scope or unit line (`p.doc-note` right above it, or `p.doc-table-meta` in older documents) moves with the table. When the table becomes another block (Sheet tabs, a chart, a list), its line goes with the data, or is dropped once the new block says the same. A table folded into a disclosure: its former caption (a `p.doc-note` above it that is a title) becomes the words of the `<summary>`, which takes no id, and is deleted; its scope or unit line goes into the disclosure with it, and the table keeps its id. Tables made Sheet tabs: a scope line or caption true of every tab stays above the area as small text (dropped when the section's heading says the same); a tab's table takes no caption of its own. Older documents may hold `data-doc-table-static` (rows kept in their order) and a cell's `data-sort-value` (the number the cell is read as, sorted and charted by): keep them, and change `data-sort-value` with the cell's number.
|
|
72
72
|
|
|
73
73
|
A long table of data shows in a frame at most `min(72vh, 720px)` tall (about 15 rows) and scrolls inside it under its header row, which stays; a short table, or one mostly of words, shows whole. To show every row of a long one, write `style="--doc-table-height: none"` on its `<table>`: the export moves it onto the table's frame (`div.doc-table-wrap`), where you write it on a table already in its frame.
|
|
74
74
|
|
|
75
75
|
## Pictures
|
|
76
76
|
|
|
77
|
-
A picture comes from a file right in the document's `assets/` (no folder in it), named with 1 to 81 ASCII letters, digits, dots, dashes and underscores, the first a letter or digit, in a format a page shows (png, jpg, gif, webp, avif, svg, ico): rename a file as you copy it in (`古籍 1.png` as `assets/guji-1.png`). Copy it at the size the page needs: its long side about 2000px at most (1400px is enough at the 712px reading width; about 800px in a row of two columns, about 500px in three), photos and scans as JPEG at quality about 80, screenshots and diagrams as PNG. Gallery does not resize pictures: use a tool this machine has (ImageMagick
|
|
77
|
+
A picture comes from a file right in the document's `assets/` (no folder in it), named with 1 to 81 ASCII letters, digits, dots, dashes and underscores, the first a letter or digit, in a format a page shows (png, jpg, gif, webp, avif, svg, ico): rename a file as you copy it in (`古籍 1.png` as `assets/guji-1.png`). Copy it at the size the page needs: its long side about 2000px at most (1400px is enough at the 712px reading width; about 800px in a row of two columns, about 500px in three), photos and scans as JPEG at quality about 80, screenshots and diagrams as PNG. Gallery does not resize pictures: use a tool this machine has (ImageMagick: `magick in.png -resize 1400x1400> -quality 80 out.jpg`), or copy them as they are and let `gallery check` say which are heavy. Each further `<img>` of a picture embeds it again: show one twice only where the reader needs it twice.
|
|
78
78
|
|
|
79
79
|
A picture with no width shows at its own size, at most its column's width and 80% of the window's height (a tall scan shows whole, narrower); `width="360"` (pixels) gives it that share of the 712px reading width, `width="50%"` half the width it stands in. The share holds on a narrow page too: `width="300"` is 0.42 of a phone's 336px, 141px. A picture whose words the reader must read (a scan, a page, a screenshot of text) takes no width. A reader's click on a picture opens it large with its caption; you write nothing for it. A picture in a link follows the link; an icon or a picture shown under 48px does not open.
|
|
80
80
|
|
|
@@ -88,11 +88,11 @@ The blocks HTML has no element for, written with the kit's classes as the exampl
|
|
|
88
88
|
|
|
89
89
|
**Callout** (`div.doc-callout`): a risk, warning, state or caveat, set apart from the text; its words in a `<p>` in it, and a list or a code block after that where it needs one (`<div class="doc-callout"><p>…</p></div>`). **Highlight panel** (`<aside>`): blocks set apart on a light fill, an icon first if any; as rare as a callout.
|
|
90
90
|
|
|
91
|
-
**A block's color** (颜色): a class on the block,
|
|
91
|
+
**A block's color** (颜色): a class on the block, not a `style`, of the colors gray, brown, orange, yellow, green, blue, purple, pink and red. A paragraph, a heading, a list item or a flowchart step takes its words' color (`doc-text-<color>`), a fill (`doc-highlight-<color>`) or both; a disclosure, a code block (on its `<pre>`), a callout or a highlight panel a fill only; a table cell one of the two. Words in a line take theirs from `<mark>` or a `<span style>`.
|
|
92
92
|
|
|
93
93
|
**A block's alignment and indent** (对齐与缩进): `doc-align-center` or `doc-align-right` on a paragraph, an `h1`–`h4` or a table's frame (`div.doc-table-wrap`, when the table is narrower than the text), the left being none; `doc-indent-1` … `doc-indent-8` move a paragraph or a heading in by two body characters a level. A `text-align: center` or `right` in a paragraph's or heading's `style` is rewritten as the class.
|
|
94
94
|
|
|
95
|
-
**Columns** (`div.doc-columns` of 2 to 5 `div.doc-column`): what the reader compares across, or a picture with its words beside it (the picture's column first, so that on a phone it stands above them). `style="--doc-column-ratio: .4"` on a column gives it that share of the row: write it on every column of the row, the shares adding up to 1, or on none, and the columns share the row equally (one written on some columns only fails the check). Pictures side by side in columns: crop them to one ratio, so that their captions line up. A column holds any block but a row of columns, a section or a Sheet area. On a screen under 640px the columns stand one under another:
|
|
95
|
+
**Columns** (`div.doc-columns` of 2 to 5 `div.doc-column`): what the reader compares across, or a picture with its words beside it (the picture's column first, so that on a phone it stands above them). `style="--doc-column-ratio: .4"` on a column gives it that share of the row: write it on every column of the row, the shares adding up to 1, or on none, and the columns share the row equally (one written on some columns only fails the check). Pictures side by side in columns: crop them to one ratio, so that their captions line up. A column holds any block but a row of columns, a section or a Sheet area. On a screen under 640px the columns stand one under another: do not point at one as the left or right.
|
|
96
96
|
|
|
97
97
|
**A process or steps** (步骤流程图, `ol.doc-flow`): one step an item, drawn as a card, arrows between them. A step's title is a paragraph of bold words, then any blocks it holds; an icon may stand first in it, drawn in its number's place. The kit numbers the steps (write no 1, ① or 第一步) and lays them out in rows that fill the width; `data-direction="row"` on the list keeps them in one row, `"column"` one a row; on a step it says where the arrow after it goes. A step written the short way (`<li>收集数据<p>…</p></li>`) is rewritten as a node. A flowchart has no title or caption of its own and stands in no `<figure>`: the sentence before it says what it shows; a legend goes in a `p.doc-note` beside it. A step takes a color as a list item does. A flowchart is for steps in order, each after the one before; a flow that branches, merges or loops is a drawing of boxes and arrows like the example's, and a structure or diagram a figure ([below](#figures-and-charts)).
|
|
98
98
|
|
|
@@ -100,87 +100,26 @@ The blocks HTML has no element for, written with the kit's classes as the exampl
|
|
|
100
100
|
|
|
101
101
|
**Detail card** (详情卡片): a term's details over the page, opened by a link in the text; its `<dialog>` stands right after the link's paragraph, its id letters, digits, `-` and `_`, a letter first, and no other element's, and it starts with a plain `<h3>` of its title, the blocks after it (with no title, it starts with its blocks). `gallery qa` opens each one and checks it; its pictures show the blocks in it that changed, and `--tiles` the whole card.
|
|
102
102
|
|
|
103
|
-
**A link to another document** of the workspace is an ordinary relative link between the two files, by the other's folder name (its slug, which `gallery list` prints
|
|
103
|
+
**A link to another document** of the workspace is an ordinary relative link between the two files, by the other's folder name (its slug, which `gallery list` prints; `gallery list <address>` for an address the user gave you), not a title or a server's address: `<a href="../<slug>/doc.html">its title</a>`, `…/doc.html#<block id>` for one of its blocks, `<a href="#<block id>">` for a block of this document (the ids are the blocks' `data-block-id`). A click goes there inside Gallery, and an export of the two together links their files; a link to a document left out of an export keeps its words. The editor's page block is the same link shown with the document's icon and title (`<a class="doc-link-mention" href="../<slug>/doc.html"><span class="doc-link-mention-icon"></span>its title</a>`, written exactly so). `gallery check` notes a link to a document or a block that is not there. A slug shaped `doc-` and eight lowercase letters or digits (`doc-tacti90g`) is the workbench's page id: choose a slug of words.
|
|
104
104
|
|
|
105
|
-
**Files, bookmarks and embeds**: cards, written as the example writes them; keep what matters of each in the document's own text. A file's or an embed's caption is always there (`<figcaption></figcaption>` when there is none). A file is one file of `assets/` the reader saves: its link's `download` the name it is saved as
|
|
105
|
+
**Files, bookmarks and embeds**: cards, written as the example writes them; keep what matters of each in the document's own text. A file's or an embed's caption is always there (`<figcaption></figcaption>` when there is none). A file is one file of `assets/` the reader saves: its link's `download` the name it is saved as; keep it small, as the export embeds it. A bookmark is a paragraph holding only its link, `<p><a class="doc-bookmark" href="https://…" title="…">…</a></p>`: an `https://` address, its words the page's title, its `title` its description; the tools write the card (`figure.doc-bookmark`) and fetch nothing. An embed shows an HTML or PDF file of `assets/` (`doc-embed--file`; an HTML file's `sandbox` without `allow-same-origin`, a PDF's none), shown offline too, or an `https://` page with a `sandbox`, shown only online; `--doc-embed-height` on the figure sets its height.
|
|
106
106
|
|
|
107
107
|
## Figures and charts
|
|
108
108
|
|
|
109
|
-
A figure the reader looks at as one picture, with a title, is a card: `<figure class="doc-figure">`, its title an `h3`, a scope or unit line `p.doc-figure-caption`.
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
**A
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
- Colors come from `tokens`: `text`, `muted`, `border`, `grid`, `surface`, `bg`, `accent`, `accentSoft`, `success`, `warning`, `danger`, `series[0..5]` (the kit's variables: `series[0]` is `--doc-series-1`, `accentSoft` `--doc-accent-soft`), and status colors from `tokens.tone("success" | "danger" | "warning" | "info" | "neutral")` ([sdk/doc-tokens.d.ts](../sdk/doc-tokens.d.ts)).
|
|
118
|
-
- Text in the host is the document's font at 16px, and in a group of class `axis` the kit's axis look (13px, muted): set a `font-size` only to change that, never under 13px. Measure the label column from the longest label (draw a text in the host and read `getComputedTextLength`), never a fixed width; when that leaves the plot too little room (long labels, a phone's width), put the labels above their rows. Draw for 360px as well: fewer ticks, labels that fit. `ticks(n)` is only a hint to d3 and may draw more (on 0–8,000, `ticks(3)` draws five); `tickValues` caps the count: at most four along a phone's axis, such as the domain's ends and middle, as the example's lollipop gives them. `gallery qa` warns `ticks` where an axis's labels crowd.
|
|
119
|
-
- Keep marks off the words: a zero, reference or grid line stops short of a label or a value's text, or the text moves clear of it, and a label stands at least 4px from the mark under or beside it. A length (a bar, a stem) starts at a baseline the reader can name (zero, or the axis's start as it is labeled), never at a number picked to fit the data. A legend belongs to the card: say the encoding in its `p.doc-figure-caption` or draw a key inside the chart, never in a paragraph outside the card; name the marks by shape or series (实心/空心, the series' name), never by light or dark, which the dark theme inverts.
|
|
120
|
-
- Show each set of values once, where it is read. When the chart labels every value, or the text gives them, fold its table (a table of a chart drawn from a table: the keyed form below; of one drawn from JSON: a disclosure right after its card, as the example's slope chart has it) or leave the value labels off. Keep the table in sight only when the reader needs exact numbers the chart does not show (more columns, many rows). The text and the opening summary give the takeaway (the largest, the smallest, a total), not every value again.
|
|
121
|
-
- To change what a chart shows, change its JSON; change its `define` code to change how every chart of that type draws.
|
|
122
|
-
- An interactive one is `DocCharts.define(type, { mount })`: `mount` gets what `draw` gets and a `signal` (for `addEventListener`), starts once in the emptied host with its controls, and may return `update(context)` and `destroy()` ([sdk/doc-charts.d.ts](../sdk/doc-charts.d.ts)).
|
|
123
|
-
|
|
124
|
-
**A chart drawn from a table**, as the example's lollipop is: write `data-doc-chart="<type>"` on the `<table>`, its `<caption>` the title; the tools put the card right after the table and link the two by a key. The kit calls your type's `draw` with `data` the table's rows: an object per body row, in the file's order, keyed by the header's words (give each column words of its own, never none), and `data.columns` the header's words in order. A value is `null` for an empty cell, a dash or `n/a`; a number when the cell writes one number (`12.5%` is 12.5, `3.6亿` 360000000, `约 20` 20; read from a cell's `data-sort-value` when it has one); else the cell's words: a range (`3–5 天`), a ratio (`3 / 4`), and every cell of a column whose header cell has `data-sort-type="text"` or `"date"`. Rows of a `<tfoot>` are left out of the chart, but a table with a `<tfoot>` has no table tools in the preview: keep a total out of a table you chart and say it in the text (a total row in the body is charted as a row). Type it with `/** @type {DocTableRows} */` on the line above `const rows = data;`. The chart draws again whenever the user edits the table, and they may add, rename or delete any row: so draw everything from the rows. Domains and ticks come from the values (`[0, d3.max(…)]` for a length, `d3.extent` for a position, `.nice()`), highlights and groups from a column of the table (a 重点 or 类别 column), never from row labels, numbers or the reason for an empty cell written in the code; an empty cell draws as a gap or a neutral no-value, its reason said in the table or the text. Merged cells, or a key no table carries, draw nothing (the card says why). Give a type drawn from a table a name of its own: drawn from JSON elsewhere, its `data` would have another shape. `gallery check` prints how each one reads its table (`chart …`: its rows, each column numbers or words), and a `note` where a column reads as numbers in some rows and words in others.
|
|
125
|
-
|
|
126
|
-
Written this way, on the `<table>`, the table always shows, its card after it. To fold the table under its card from the start (the chart labels its values, or the text gives them), write the card with a key of your own and the table carrying the same key; once exported, a chart card may stay in a column or a panel while its table's frame moves elsewhere:
|
|
127
|
-
|
|
128
|
-
<!-- you write -->
|
|
129
|
-
```html
|
|
130
|
-
<figure class="doc-figure">
|
|
131
|
-
<h3>各类别的数值</h3>
|
|
132
|
-
<div data-doc-chart="table-dots" data-doc-chart-data="values"></div>
|
|
133
|
-
</figure>
|
|
134
|
-
<details>
|
|
135
|
-
<summary>数据</summary>
|
|
136
|
-
<table data-doc-chart-source="values">
|
|
137
|
-
<thead><tr><th>类别</th><th>数值</th></tr></thead>
|
|
138
|
-
<tbody><tr><td>类别 A</td><td>12</td></tr><tr><td>类别 B</td><td>18</td></tr></tbody>
|
|
139
|
-
</table>
|
|
140
|
-
</details>
|
|
141
|
-
```
|
|
142
|
-
|
|
143
|
-
```js
|
|
144
|
-
// data: the table's rows, each keyed by its header's words; data.columns the header's words in order.
|
|
145
|
-
DocCharts.define("table-dots", ({ host, data, tokens, width }) => {
|
|
146
|
-
/** @type {DocTableRows} */
|
|
147
|
-
const rows = data;
|
|
148
|
-
const [name, value] = rows.columns;
|
|
149
|
-
const points = rows.flatMap((row) => (typeof row[value] === "number" ? [{ label: String(row[name]), value: row[value] }] : []));
|
|
150
|
-
// The label column as wide as its longest label (the example's lollipop also puts long ones above their rows).
|
|
151
|
-
const probe = d3.select(host).append("svg").append("text");
|
|
152
|
-
const left = Math.ceil(d3.max(points, (point) => probe.text(point.label).node()?.getComputedTextLength() ?? 0) ?? 0) + 16;
|
|
153
|
-
probe.node()?.ownerSVGElement?.remove();
|
|
154
|
-
const tall = points.length * 36 + 40;
|
|
155
|
-
const x = d3.scaleLinear([0, d3.max(points, (point) => point.value) ?? 0], [left, width - 24]).nice();
|
|
156
|
-
const y = d3.scaleBand(points.map((point) => point.label), [8, tall - 28]);
|
|
157
|
-
const svg = d3.select(host).append("svg").attr("width", width).attr("height", tall).attr("role", "img").attr("aria-label", `${value},按${name}`);
|
|
158
|
-
// Three ticks when narrow, the domain's ends and middle: ticks(3) is a hint d3 may exceed.
|
|
159
|
-
const [low, high] = x.domain();
|
|
160
|
-
svg.append("g").attr("class", "axis").attr("transform", `translate(0,${tall - 28})`).call(d3.axisBottom(x).tickValues(width < 520 ? [low, (low + high) / 2, high] : x.ticks(5)));
|
|
161
|
-
svg.append("g").attr("class", "axis").attr("transform", `translate(${left},0)`).call(d3.axisLeft(y).tickSize(0));
|
|
162
|
-
svg.append("g").selectAll("circle").data(points).join("circle")
|
|
163
|
-
.attr("cx", (point) => x(point.value)).attr("cy", (point) => (y(point.label) ?? 0) + y.bandwidth() / 2).attr("r", 5).attr("fill", tokens.series[0]);
|
|
164
|
-
});
|
|
165
|
-
```
|
|
166
|
-
|
|
167
|
-
**A drawing in a card** (a layered structure, a diagram of parts, an architecture, a timeline), as the example's timeline, `.box-path` and `.branch` are: your own HTML and CSS, or inline SVG, inside `figure.doc-figure` after its title and caption. Give its elements classes of your own (never `doc-…`) and style them in the page's `<style>`: draw what the figure needs (boxes, lines, gaps, sizes) but not the card's frame, colored with the kit's variables so that it follows the dark theme.
|
|
168
|
-
|
|
169
|
-
- A `<figure>` inside the drawing is part of it, not a card of its own.
|
|
170
|
-
- How parts relate (who calls, reads or feeds whom; where a flow branches, merges or loops) is drawn as boxes joined by arrows, not said in a caption or repeated in a table. The example draws both kinds. `.box-path`, HTML and CSS: each box but the last draws its line (`::after`) and its arrowhead (`::before`), one box under another with arrows down on a phone, in a row with arrows right from `@media (min-width: 560px)`. `.branch`, inline SVG: one box into two, its lines ending in a `<marker>` arrowhead (`marker-end`), colored by classes with `--doc-muted`, `--doc-border` and `--doc-accent`.
|
|
171
|
-
- Give each figure's SVG `<defs>` ids a prefix of its own (`<marker id="fig-branch-arrow">`, as the example's): two figures with the same id fail the repeated-id check; a copy the user makes gets its own prefix. Write markers, gradients and clip paths as attributes (`marker-end="url(#fig-branch-arrow)"`), not in a `<style>` inside the SVG.
|
|
172
|
-
- A `viewBox` scales the drawing, its text with it: 14-unit text in a viewBox 800 wide reads at 6px on a 360px phone. Size the text in the viewBox's units so that it reads at 11px or more at 360px, or lay the drawing out for narrow widths (HTML that wraps, an `@media` rule, or a chart of your own drawn from its width). The other way too: a viewBox sized for a phone grows its text with the card on a wide page (14 units in a viewBox 320 wide read at 31px drawn 712px wide), so give such an SVG a `max-width` (the example's `.branch`: 360px).
|
|
173
|
-
- `gallery qa` pictures it, warns `overflow-in-block` when its words run past their box at some width (give them room in an `@media` rule), `cut-in-block` when a box of a fixed height cuts off its words or marks (let it grow: `min-height`) and `svg-text-small` when a viewBox draws its text under 11px.
|
|
174
|
-
|
|
175
|
-
**A whole block** (整体块): a layout of your own that is no figure (a strip of metrics, a comparison panel, controls your script handles that only change what a reader looks at), as the example's `.metric-strip` is. Give it a class of your own (never `doc-…`) and style it in the page's `<style>` with the kit's variables. The user moves it whole and can fix its words in the preview; `gallery qa` warns `overflow-in-block` and `cut-in-block` as for a drawing. A drawing, a diagram or a timeline is a figure, in a card, not a whole block.
|
|
176
|
-
|
|
177
|
-
**A picture**: a diagram, scan or photo the materials come with ([Pictures](#pictures)).
|
|
109
|
+
A figure the reader looks at as one picture, with a title, is a card: `<figure class="doc-figure">`, its title an `h3`, a scope or unit line `p.doc-figure-caption`. Inside it:
|
|
110
|
+
|
|
111
|
+
- **A chart** (anything on axes: intervals, distributions, slopes, small multiples): `<div data-doc-chart="type">` with its data as JSON, or `<table data-doc-chart="type">`, drawn from its rows, the type defined once in the document's script with `DocCharts.define(type, draw)` (d3 v7 is on the page).
|
|
112
|
+
- **A drawing** (a layered structure, a diagram of parts, an architecture, a timeline): your own HTML and CSS or inline SVG in the card, its classes your own (not `doc-…`), colored with the kit's variables.
|
|
113
|
+
- **A whole block** (整体块): a layout of your own that is no figure (a strip of metrics, a comparison panel), a class of your own styled in the page's `<style>`, outside a card.
|
|
114
|
+
- A diagram, scan or photo the materials come with is a picture ([Pictures](#pictures)).
|
|
115
|
+
|
|
116
|
+
The card draws the frame and the surface once: draw no second outer box inside it. Before you write a chart or a drawing, read [charts-and-figures.md](charts-and-figures.md): how a type is defined and what `draw` is given, colors, labels and ticks at 360px, a chart drawn from a table, and what `gallery qa` flags in a drawing.
|
|
178
117
|
|
|
179
118
|
## Do not write
|
|
180
119
|
|
|
181
120
|
- The kit's classes on what you write as plain HTML (a `<details>` given `doc-details`): write the plain element.
|
|
182
121
|
- Attributes in curly quotes (`class=”x”`, which HTML reads as part of the value): an editing tool keeping a file's “…” may make them; look at the quotes of the tags you add.
|
|
183
|
-
- A bare `<button>` in the text: a link opens a detail card; an interactive figure is a chart of your own (`DocCharts.define(type, { mount })`), and controls of your own, for what a reader only looks through (a filter, a toggle), a whole block your script handles. A plain `<select>` among them needs nothing for its dropdown: the kit opens its own flat menu for every select, light and dark
|
|
122
|
+
- A bare `<button>` in the text: a link opens a detail card; an interactive figure is a chart of your own (`DocCharts.define(type, { mount })`), and controls of your own, for what a reader only looks through (a filter, a toggle), a whole block your script handles. A plain `<select>` among them needs nothing for its dropdown: the kit opens its own flat menu for every select, light and dark (the select keeps its `value` and `change`; for a choice from a button of your own, `DocKit.choose`: [block-script.md](block-script.md)). A document's own script cannot write the file: a control that must keep what a reader enters (a ledger, a checklist, a form, a score) is a custom block's data part, even when the user does not say to use it again ([building-blocks.md](building-blocks.md): `gallery block new <id> --data`).
|
|
184
123
|
- `<colgroup>`, column widths or `.number`: the kit measures columns and aligns numbers.
|
|
185
124
|
- base64 `data:` or remote addresses for scripts, styles, fonts and pictures: put the file in `assets/` and write `assets/<file>`, which the export embeds. Links to web pages are fine.
|
|
186
125
|
- Looks of your own on the kit's blocks (a paragraph, a table, a callout): gradients, shadows, frames, margins or type sizes; the kit sets them. The sizes this page names are the exception, each in its block's `style`: `--doc-table-height`, `--doc-code-height`, `--doc-embed-height`.
|