@heycys/gallery 0.1.2 → 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/THIRD-PARTY-NOTICES.md +2 -2
- package/browser/editor/components/align.mjs +58 -0
- package/browser/editor/components/code/index.mjs +1 -1
- package/browser/editor/components/embed/page.mjs +1 -1
- package/browser/editor/components/file/page.mjs +4 -4
- package/browser/editor/components/heading/index.mjs +7 -6
- package/browser/editor/components/icons.mjs +3 -0
- package/browser/editor/components/image/index.mjs +2 -0
- package/browser/editor/components/image/page.mjs +172 -90
- package/browser/editor/components/installed/index.mjs +6 -2
- package/browser/editor/components/installed/page.mjs +80 -13
- package/browser/editor/components/media/icons.mjs +13 -8
- package/browser/editor/components/media/page.mjs +5 -3
- package/browser/editor/components/media/toolbar.mjs +12 -3
- package/browser/editor/components/paragraph/index.mjs +4 -3
- package/browser/editor/components/registry.mjs +17 -5
- package/browser/editor/components/table/index.mjs +4 -2
- package/browser/editor/page/after/index.mjs +288 -0
- package/browser/editor/page/align.mjs +91 -0
- package/browser/editor/page/beside.mjs +5 -6
- package/browser/editor/page/block-menu/index.mjs +6 -3
- package/browser/editor/page/blocks.mjs +3 -1
- package/browser/editor/page/board/hint.mjs +64 -27
- package/browser/editor/page/board/index.mjs +160 -71
- package/browser/editor/page/board/motion.mjs +177 -0
- package/browser/editor/page/board/settings.mjs +4 -3
- package/browser/editor/page/clipboard/index.mjs +10 -3
- package/browser/editor/page/clipboard/own/blocks.mjs +3 -4
- package/browser/editor/page/clipboard/own/describe.mjs +6 -2
- package/browser/editor/page/commit.mjs +2 -2
- package/browser/editor/page/core.mjs +3 -1
- package/browser/editor/page/custom-page.mjs +15 -11
- package/browser/editor/page/editor.mjs +31 -14
- package/browser/editor/page/history.mjs +19 -4
- package/browser/editor/page/insert/index.mjs +20 -22
- package/browser/editor/page/menu.mjs +15 -7
- package/browser/editor/page/page-objects.mjs +3 -7
- package/browser/editor/page/present-links.mjs +5 -4
- package/browser/editor/page/present-shell.mjs +63 -0
- package/browser/editor/page/selection/index.mjs +10 -2
- package/browser/editor/page/table/binding.mjs +87 -0
- package/browser/editor/page/table/icons.mjs +0 -2
- package/browser/editor/page/table/index.mjs +10 -14
- package/browser/editor/page/table/views.mjs +5 -52
- package/browser/editor/page/table/widths.mjs +82 -10
- package/browser/editor/page/typing/index.mjs +44 -12
- package/browser/editor/page/typing/leave.mjs +19 -5
- package/browser/shared/block-packs.mjs +23 -8
- package/browser/shared/component-catalog.mjs +15 -8
- package/browser/shared/component-source.mjs +3 -1
- package/browser/shared/components/heading.mjs +2 -1
- package/browser/shared/components/installed.mjs +1 -1
- package/browser/shared/components/page.mjs +2 -0
- package/browser/shared/components/paragraph.mjs +8 -1
- package/browser/shared/components/table.mjs +1 -0
- package/browser/shared/emoji/line-icons.mjs +37 -0
- package/browser/shared/http.mjs +9 -0
- package/browser/shared/i18n/en.mjs +40 -17
- package/browser/shared/outline.mjs +30 -2
- package/browser/shared/pack-manifest.mjs +12 -1
- package/browser/shared/pages.mjs +169 -57
- package/browser/shared/pinyin.mjs +92 -0
- package/browser/shared/present-step.mjs +17 -0
- package/browser/shared/sidebar-head.mjs +70 -0
- package/browser/shared/web-links.mjs +5 -0
- package/dist/chunk-2OHANJ6Q.mjs +2 -0
- package/dist/{chunk-QOUEFUCH.mjs → chunk-3MBRL2PM.mjs} +1 -1
- package/dist/{chunk-NWR2LT5B.mjs → chunk-4OKWZY5E.mjs} +1 -1
- package/dist/{chunk-RMECZA2K.mjs → chunk-5K44HLTZ.mjs} +1 -1
- package/dist/{chunk-NFMCP2HI.mjs → chunk-5XA2ZBAE.mjs} +2 -2
- package/dist/{chunk-OUUP3WKT.mjs → chunk-67N2QJYT.mjs} +1 -1
- package/dist/chunk-6KBYRA2C.mjs +2 -0
- package/dist/{chunk-SX4LJYT6.mjs → chunk-6N3PX4XX.mjs} +1 -1
- package/dist/{chunk-RFDZXFJF.mjs → chunk-7JDX4E65.mjs} +1 -1
- package/dist/chunk-7M2BQQGZ.mjs +2 -0
- package/dist/{chunk-ZUNVAXLH.mjs → chunk-7OG26PGF.mjs} +1 -1
- package/dist/{chunk-B4P2CM2J.mjs → chunk-AHN3NFKJ.mjs} +1 -1
- package/dist/chunk-ALZ6ZENZ.mjs +3 -0
- package/dist/{chunk-UGWYKHBL.mjs → chunk-AR5D57ZD.mjs} +2 -2
- package/dist/{chunk-W3BGBJQW.mjs → chunk-BFJGHSQN.mjs} +1 -1
- package/dist/{chunk-HLYV7RIH.mjs → chunk-CMA72MAG.mjs} +1 -1
- package/dist/{chunk-D4CKRD3V.mjs → chunk-DAZL73VK.mjs} +2 -2
- package/dist/{chunk-6VTU6KEO.mjs → chunk-DJISHPUL.mjs} +1 -1
- package/dist/{chunk-BPL64HGA.mjs → chunk-EAIFITAV.mjs} +1 -1
- package/dist/chunk-EP25HDAJ.mjs +2 -0
- package/dist/{chunk-6EZ7FNIK.mjs → chunk-F4ZA6JRZ.mjs} +1 -1
- package/dist/{chunk-3KJHLHUO.mjs → chunk-F6HVDZR4.mjs} +1 -1
- package/dist/{chunk-3NJACR4W.mjs → chunk-FDMAXMQA.mjs} +1 -1
- package/dist/chunk-FETSREUN.mjs +5 -0
- package/dist/{chunk-RKPWLGZ3.mjs → chunk-GHOYKMQ3.mjs} +1 -1
- package/dist/chunk-HDWTZ763.mjs +12 -0
- package/dist/{chunk-VTKNEYT3.mjs → chunk-HPOI4ZX7.mjs} +1 -1
- package/dist/{chunk-OW5NWPOJ.mjs → chunk-HXG7EOPJ.mjs} +1 -1
- package/dist/{chunk-V6RIYQZZ.mjs → chunk-ITOH5EGO.mjs} +1 -1
- package/dist/{chunk-ZWPMCK7P.mjs → chunk-IV64FFI4.mjs} +1 -1
- package/dist/chunk-J43Z6LSS.mjs +2 -0
- package/dist/chunk-J5PUIV3Y.mjs +4 -0
- package/dist/{chunk-KTKHRC6H.mjs → chunk-JA7G53PC.mjs} +1 -1
- package/dist/{chunk-NWFBE2YA.mjs → chunk-JLTZF4LA.mjs} +1 -1
- package/dist/{chunk-GY3FAUVM.mjs → chunk-JZT7I2OJ.mjs} +1 -1
- package/dist/{chunk-QKXMPUXC.mjs → chunk-K5XATEOO.mjs} +1 -1
- package/dist/chunk-L2SUIS5S.mjs +2 -0
- package/dist/{chunk-TEZAWDSQ.mjs → chunk-LM4XFQHZ.mjs} +1 -1
- package/dist/{chunk-5ZJA7CXT.mjs → chunk-MN7BZL4R.mjs} +1 -1
- package/dist/chunk-MTYYHM2G.mjs +15 -0
- package/dist/{chunk-HMYTM3GT.mjs → chunk-MXUBKDRO.mjs} +1 -1
- package/dist/{chunk-MHW7ZKOU.mjs → chunk-OEXWRJME.mjs} +1 -1
- package/dist/{chunk-CRJEG7MT.mjs → chunk-OFHXGWOX.mjs} +1 -1
- package/dist/chunk-ORID3AE7.mjs +166 -0
- package/dist/{chunk-32ZUEFZ7.mjs → chunk-PGDE24N5.mjs} +1 -1
- package/dist/{chunk-UNOYVIYR.mjs → chunk-POTA2FV4.mjs} +1 -1
- package/dist/{chunk-N7AZZLGT.mjs → chunk-QE5RG76S.mjs} +18 -17
- package/dist/{chunk-N76HWBA3.mjs → chunk-R2ZDLJYT.mjs} +1 -1
- package/dist/chunk-SWUTTZCN.mjs +2 -0
- package/dist/{chunk-POQSE4C2.mjs → chunk-TR7TWGHB.mjs} +1 -1
- package/dist/chunk-U5XL7D6A.mjs +3 -0
- package/dist/{chunk-PVER7LSC.mjs → chunk-U7NZI6N4.mjs} +2 -2
- package/dist/{chunk-Q47PLKIJ.mjs → chunk-UGWMMEJ5.mjs} +1 -1
- package/dist/chunk-UJQJKNGK.mjs +2 -0
- package/dist/chunk-UYVCQK3H.mjs +22 -0
- package/dist/{chunk-FJYN7RTH.mjs → chunk-VFX2KNHP.mjs} +1 -1
- package/dist/{chunk-UBBRTJ2R.mjs → chunk-VS7JIGJW.mjs} +1 -1
- package/dist/{chunk-NVRNLK25.mjs → chunk-W7665ZEC.mjs} +2 -2
- package/dist/{chunk-NG375ILQ.mjs → chunk-WQDQWCX5.mjs} +1 -1
- package/dist/chunk-YLPSMDIS.mjs +5 -0
- package/dist/{chunk-VXACTLO3.mjs → chunk-YNAWBAYN.mjs} +1 -1
- package/dist/{chunk-ZB4H7ZN4.mjs → chunk-YROX2O22.mjs} +1 -1
- package/dist/{chunk-YQGT4AB2.mjs → chunk-ZDLPUOAG.mjs} +1 -1
- package/dist/chunk-ZQS6H473.mjs +16 -0
- package/dist/{chunk-OJKMINIU.mjs → chunk-ZWWC4KLF.mjs} +15 -15
- package/dist/cli.mjs +1 -1
- package/dist/server.mjs +1 -1
- package/dist/worker.mjs +1 -1
- package/kit/board.css +5 -5
- package/kit/code.js +15 -15
- package/kit/report.css +120 -41
- package/kit/runtime.js +45 -7
- package/kit/tables.js +2 -0
- package/kit/ui.js +2 -0
- package/package.json +1 -1
- package/packs/gallery/chart-view/kit.js +3 -3
- package/packs/gallery/chart-view/writing.md +1 -1
- package/packs/gallery/countdown/component.json +1 -1
- package/packs/gallery/countdown/kit.js +89 -29
- package/packs/gallery/countdown/preview.svg +1 -1
- package/packs/gallery/countdown/style.css +88 -100
- package/packs/gallery/countdown/writing.md +2 -2
- package/packs/gallery/habit/component.json +3 -3
- package/packs/gallery/habit/kit.js +114 -75
- package/packs/gallery/habit/preview.svg +1 -1
- package/packs/gallery/habit/style.css +133 -205
- package/packs/gallery/habit/writing.md +2 -2
- package/packs/gallery/heatmap/component.json +2 -2
- package/packs/gallery/heatmap/kit.js +335 -173
- package/packs/gallery/heatmap/preview.svg +1 -1
- package/packs/gallery/heatmap/style.css +158 -170
- package/packs/gallery/heatmap/writing.md +2 -2
- package/packs/gallery/kanban/kit.js +3 -3
- package/packs/gallery/kanban/writing.md +1 -1
- package/packs/gallery/metric/kit.js +3 -3
- package/packs/gallery/metric/writing.md +1 -1
- package/packs/gallery/note/component.json +3 -3
- package/packs/gallery/note/kit.js +40 -13
- package/packs/gallery/note/preview.svg +1 -1
- package/packs/gallery/note/style.css +51 -30
- package/packs/gallery/note/writing.md +2 -2
- package/packs/gallery/recent/component.json +2 -2
- package/packs/gallery/recent/kit.js +141 -86
- package/packs/gallery/recent/preview.svg +1 -1
- package/packs/gallery/recent/style.css +53 -126
- package/packs/gallery/recent/writing.md +2 -2
- package/packs/gallery/static/component.json +2 -2
- package/packs/gallery/static/preview.svg +1 -1
- package/packs/gallery/static/style.css +99 -66
- package/packs/gallery/static/writing.md +2 -2
- package/packs/gallery/stats/component.json +3 -3
- package/packs/gallery/stats/kit.js +253 -72
- package/packs/gallery/stats/preview.svg +1 -1
- package/packs/gallery/stats/style.css +64 -142
- package/packs/gallery/stats/writing.md +2 -2
- package/packs/gallery/today/component.json +2 -2
- package/packs/gallery/today/kit.js +62 -27
- package/packs/gallery/today/preview.svg +1 -1
- package/packs/gallery/today/style.css +101 -72
- package/packs/gallery/today/writing.md +2 -2
- package/packs/gallery/todos/component.json +1 -1
- package/packs/gallery/todos/kit.js +218 -71
- package/packs/gallery/todos/preview.svg +1 -1
- package/packs/gallery/todos/style.css +170 -223
- package/packs/gallery/todos/writing.md +1 -1
- package/packs/gallery/weather/component.json +2 -2
- package/packs/gallery/weather/kit.js +165 -90
- package/packs/gallery/weather/preview.svg +1 -1
- package/packs/gallery/weather/style.css +100 -218
- package/packs/gallery/weather/writing.md +1 -1
- package/packs/gallery-soft/countdown/component.json +18 -0
- package/packs/gallery-soft/countdown/example.html +3 -0
- package/packs/gallery-soft/countdown/kit.js +206 -0
- package/packs/gallery-soft/countdown/preview.svg +1 -0
- package/packs/gallery-soft/countdown/style.css +211 -0
- package/packs/gallery-soft/countdown/template.html +3 -0
- package/packs/gallery-soft/countdown/writing.md +24 -0
- package/packs/gallery-soft/habit/component.json +14 -0
- package/packs/gallery-soft/habit/example.html +3 -0
- package/packs/gallery-soft/habit/kit.js +366 -0
- package/packs/gallery-soft/habit/preview.svg +1 -0
- package/packs/gallery-soft/habit/style.css +251 -0
- package/packs/gallery-soft/habit/template.html +3 -0
- package/packs/gallery-soft/habit/writing.md +23 -0
- package/packs/gallery-soft/heatmap/component.json +18 -0
- package/packs/gallery-soft/heatmap/example.html +3 -0
- package/packs/gallery-soft/heatmap/kit.js +498 -0
- package/packs/gallery-soft/heatmap/preview.svg +1 -0
- package/packs/gallery-soft/heatmap/style.css +181 -0
- package/packs/gallery-soft/heatmap/template.html +3 -0
- package/packs/gallery-soft/heatmap/writing.md +23 -0
- package/packs/gallery-soft/note/component.json +14 -0
- package/packs/gallery-soft/note/example.html +3 -0
- package/packs/gallery-soft/note/kit.js +162 -0
- package/packs/gallery-soft/note/preview.svg +1 -0
- package/packs/gallery-soft/note/style.css +148 -0
- package/packs/gallery-soft/note/template.html +3 -0
- package/packs/gallery-soft/note/writing.md +20 -0
- package/packs/gallery-soft/recent/component.json +13 -0
- package/packs/gallery-soft/recent/example.html +1 -0
- package/packs/gallery-soft/recent/kit.js +335 -0
- package/packs/gallery-soft/recent/preview.svg +1 -0
- package/packs/gallery-soft/recent/style.css +160 -0
- package/packs/gallery-soft/recent/template.html +1 -0
- package/packs/gallery-soft/recent/writing.md +17 -0
- package/packs/gallery-soft/static/component.json +13 -0
- package/packs/gallery-soft/static/example.html +12 -0
- package/packs/gallery-soft/static/preview.svg +1 -0
- package/packs/gallery-soft/static/style.css +186 -0
- package/packs/gallery-soft/static/template.html +1 -0
- package/packs/gallery-soft/static/writing.md +20 -0
- package/packs/gallery-soft/stats/component.json +13 -0
- package/packs/gallery-soft/stats/example.html +1 -0
- package/packs/gallery-soft/stats/kit.js +341 -0
- package/packs/gallery-soft/stats/preview.svg +1 -0
- package/packs/gallery-soft/stats/style.css +119 -0
- package/packs/gallery-soft/stats/template.html +1 -0
- package/packs/gallery-soft/stats/writing.md +13 -0
- package/packs/gallery-soft/today/component.json +12 -0
- package/packs/gallery-soft/today/example.html +1 -0
- package/packs/gallery-soft/today/kit.js +222 -0
- package/packs/gallery-soft/today/preview.svg +1 -0
- package/packs/gallery-soft/today/style.css +178 -0
- package/packs/gallery-soft/today/template.html +1 -0
- package/packs/gallery-soft/today/writing.md +16 -0
- package/packs/gallery-soft/todos/component.json +19 -0
- package/packs/gallery-soft/todos/example.html +3 -0
- package/packs/gallery-soft/todos/kit.js +527 -0
- package/packs/gallery-soft/todos/preview.svg +1 -0
- package/packs/gallery-soft/todos/style.css +212 -0
- package/packs/gallery-soft/todos/template.html +3 -0
- package/packs/gallery-soft/todos/writing.md +32 -0
- package/packs/gallery-soft/weather/component.json +19 -0
- package/packs/gallery-soft/weather/example.html +3 -0
- package/packs/gallery-soft/weather/kit.js +411 -0
- package/packs/gallery-soft/weather/preview.svg +1 -0
- package/packs/gallery-soft/weather/style.css +185 -0
- package/packs/gallery-soft/weather/template.html +3 -0
- package/packs/gallery-soft/weather/writing.md +28 -0
- package/release.json +9 -9
- package/skill/SKILL.md +12 -12
- package/skill/references/building-blocks.md +4 -4
- package/skill/references/pages-and-data.md +13 -9
- package/skill/references/writing-html.md +2 -0
- package/web/assets/index-BM_K-Auu.css +1 -0
- package/web/assets/index-DRslOBiv.js +15 -0
- package/web/index.html +2 -2
- package/dist/chunk-2NRBY6AJ.mjs +0 -2
- package/dist/chunk-35NQ4PLQ.mjs +0 -2
- package/dist/chunk-4AV456RQ.mjs +0 -2
- package/dist/chunk-5XYHDBJ5.mjs +0 -2
- package/dist/chunk-6A53MZYZ.mjs +0 -2
- package/dist/chunk-6EXH3ORZ.mjs +0 -166
- package/dist/chunk-BVEFGE4B.mjs +0 -2
- package/dist/chunk-D4EURAX4.mjs +0 -4
- package/dist/chunk-DQCE7TJY.mjs +0 -5
- package/dist/chunk-FWNRPMCJ.mjs +0 -12
- package/dist/chunk-FWW4CSAZ.mjs +0 -2
- package/dist/chunk-JVHHHGEA.mjs +0 -3
- package/dist/chunk-PZDLJJTJ.mjs +0 -3
- package/dist/chunk-SXHBYZST.mjs +0 -16
- package/dist/chunk-UFNYFFKO.mjs +0 -20
- package/dist/chunk-UKSHDZZ6.mjs +0 -2
- package/dist/chunk-VJPFVNNW.mjs +0 -15
- package/dist/chunk-VS3ZMVGX.mjs +0 -5
- package/web/assets/index-BK2e_07w.js +0 -13
- package/web/assets/index-CWFI83mF.css +0 -1
|
@@ -14,6 +14,8 @@ import { BLOCK_TYPES, LEAVES_BY_ENTER, accepts } from "../../components/registry
|
|
|
14
14
|
// too) moves out after the box, which goes if nothing is left in it (`leaveBox`).
|
|
15
15
|
// - A block of a type that says `resettable` (a quote's paragraph, a list item) turns into a
|
|
16
16
|
// paragraph where it stands, its container splitting around it (convert.mjs).
|
|
17
|
+
// - Backspace in an empty block of a type that says `emptyToText` (a heading, small text) turns it
|
|
18
|
+
// into an empty paragraph where it stands (`emptied`; the user's, 2026-11-09).
|
|
17
19
|
// Enter in a title that goes into its content (a disclosure, a card, a code block) is another rule
|
|
18
20
|
// (their components').
|
|
19
21
|
|
|
@@ -36,8 +38,10 @@ export function leaveBox(host) {
|
|
|
36
38
|
* and touchedBy (a structural undo step), convertHost, typeOf and targetsOf (convert.mjs).
|
|
37
39
|
*/
|
|
38
40
|
export function createLeaving({ struct, touchedBy, convertHost, typeOf, targetsOf }) {
|
|
39
|
-
// A block of a type that
|
|
40
|
-
const
|
|
41
|
+
// A block of a type that says `field` (resettable, emptyToText), which can be body text where it stands.
|
|
42
|
+
const says = (host, field) => BLOCK_TYPES[typeOf(host)]?.[field] === true && targetsOf(host).includes("paragraph");
|
|
43
|
+
const resets = (host) => says(host, "resettable");
|
|
44
|
+
const toText = (host) => convertHost(host, "paragraph");
|
|
41
45
|
|
|
42
46
|
// Enter on an empty text block. True when it left its container or became text.
|
|
43
47
|
function enter(host) {
|
|
@@ -52,7 +56,7 @@ export function createLeaving({ struct, touchedBy, convertHost, typeOf, targetsO
|
|
|
52
56
|
return true;
|
|
53
57
|
}
|
|
54
58
|
if (!resets(host)) return false;
|
|
55
|
-
|
|
59
|
+
toText(host);
|
|
56
60
|
return true;
|
|
57
61
|
}
|
|
58
62
|
|
|
@@ -60,9 +64,19 @@ export function createLeaving({ struct, touchedBy, convertHost, typeOf, targetsO
|
|
|
60
64
|
// quote's first paragraph), turns into body text before the container. True when it did.
|
|
61
65
|
function backspace(host) {
|
|
62
66
|
if (!resets(host) || host.parentElement?.firstElementChild !== host) return false;
|
|
63
|
-
|
|
67
|
+
toText(host);
|
|
64
68
|
return true;
|
|
65
69
|
}
|
|
66
70
|
|
|
67
|
-
|
|
71
|
+
// Backspace in an empty text block of a type that says `emptyToText` (a heading, small text): it turns
|
|
72
|
+
// into an empty paragraph where it stands, the caret in it, one undo step (the user's, 2026-11-09: as an
|
|
73
|
+
// emptied item or quote paragraph, and as every container left empty, goes back to body text). True
|
|
74
|
+
// when it did.
|
|
75
|
+
function emptied(host) {
|
|
76
|
+
if (!isEmpty(host) || !says(host, "emptyToText")) return false;
|
|
77
|
+
toText(host);
|
|
78
|
+
return true;
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
return { enter, backspace, emptied };
|
|
68
82
|
}
|
|
@@ -2,7 +2,7 @@ import fs from "node:fs";
|
|
|
2
2
|
import path from "node:path";
|
|
3
3
|
import { componentSettings, problemIn, writeComponentSettings } from "./component-catalog.mjs";
|
|
4
4
|
import { refusal, said } from "./i18n/index.mjs";
|
|
5
|
-
import { PACK_FILE, PACK_ID, readPackManifest } from "./pack-manifest.mjs";
|
|
5
|
+
import { DEFAULT_PACK, OWN_SCOPE, PACK_FILE, PACK_ID, readPackManifest } from "./pack-manifest.mjs";
|
|
6
6
|
import { packsDirectory } from "./paths.mjs";
|
|
7
7
|
import { filesIn, fingerprintOf, fingerprintOfFiles, isSystemFile, recordOf, shippedBlocks, shippedPackIds, versionAfter, writeRecord, writingOrder } from "./shipped-blocks.mjs";
|
|
8
8
|
import { DEVICE_NAMES, PACKAGE_MANIFEST, layoutOf, markerOf, packageFolders } from "./workspace.mjs";
|
|
@@ -10,8 +10,9 @@ import { DEVICE_NAMES, PACKAGE_MANIFEST, layoutOf, markerOf, packageFolders } fr
|
|
|
10
10
|
// Block packs (自定义块包: notes/plans/block-packs-plan-2026-11-09.md; docs/render.md "Block packs"). A pack
|
|
11
11
|
// is a scope of the workspace's custom blocks, components/<id>/, with its pack.json (./pack-manifest.mjs)
|
|
12
12
|
// and a folder of each of its blocks, <id>/<name>/, the blocks' ids <id>/<name> as ever, so that nothing
|
|
13
|
-
// written of a block changes; a scope with no pack.json
|
|
14
|
-
//
|
|
13
|
+
// written of a block changes; a scope with no pack.json is a pack of its own, named by its scope, and
|
|
14
|
+
// local/ (OWN_SCOPE: gallery block new <name>'s, where an Agent's block goes when it names no pack) is the
|
|
15
|
+
// default pack (默认块包, pack-manifest.mjs DEFAULT_PACK), always listed, first. A pack is shared as its folder, or a zip of it (the folder itself, or what it
|
|
15
16
|
// holds, at the zip's top), and installed into a workspace by gallery block pack install (src/cli/component.mjs)
|
|
16
17
|
// or 设置 › 组件列表's 导入 (src/server/component-settings.mjs), which both read it (src/transfer/pack-source.mjs)
|
|
17
18
|
// and hand its files here, checked alike:
|
|
@@ -43,6 +44,18 @@ import { DEVICE_NAMES, PACKAGE_MANIFEST, layoutOf, markerOf, packageFolders } fr
|
|
|
43
44
|
/** Gallery's own packs that a workspace has switched off when they are first installed. */
|
|
44
45
|
export const OFF_AT_FIRST = Object.freeze(["gallery-soft"]);
|
|
45
46
|
|
|
47
|
+
/**
|
|
48
|
+
* The ids of Gallery's own packs that are off though gallery.json names no switch for them: one off at first
|
|
49
|
+
* (OFF_AT_FIRST) that this workspace has not installed yet, which its first install will switch off. A
|
|
50
|
+
* start that installs none (NO_PACKS, a workspace made by hand) has the library offer Gallery's own blocks
|
|
51
|
+
* from the package, and a pack that is off when it comes in is not one of them. `switches` is the catalog
|
|
52
|
+
* settings' `packs` (true on, false off, by id).
|
|
53
|
+
*/
|
|
54
|
+
export function offUntilInstalled(root, switches = {}) {
|
|
55
|
+
const installed = recordOf(root).packs;
|
|
56
|
+
return OFF_AT_FIRST.filter((id) => switches?.[id] === undefined && !isTable(installed?.[id]));
|
|
57
|
+
}
|
|
58
|
+
|
|
46
59
|
/** The environment variable that keeps a start (and gallery init) from installing Gallery's own packs: the tests' workspaces. */
|
|
47
60
|
export const NO_PACKS = "GALLERY_NO_PACKS";
|
|
48
61
|
|
|
@@ -285,14 +298,16 @@ const both = (problem) => ({ zh: problemIn("zh", problem), en: problemIn("en", p
|
|
|
285
298
|
* switch, gallery.json's components.packs), changed (of what was installed, the blocks changed since, and
|
|
286
299
|
* pack.json where it was), newer (of one of Gallery's own that was changed since, Gallery's version of it
|
|
287
300
|
* when that comes after the one installed, which is not put over it; else null) }]: Gallery's own first,
|
|
288
|
-
* then those installed, then the workspace's own, each by id
|
|
301
|
+
* then those installed, then the workspace's own, each by id; and before them all the default pack (local/,
|
|
302
|
+
* OWN_SCOPE: kind "default", named and described by DEFAULT_PACK, its switch as any pack's), whether or
|
|
303
|
+
* not it holds a block yet: where an Agent's block goes when it names no pack.
|
|
289
304
|
*/
|
|
290
305
|
export function workspacePacks(root, { settings = null, shippedIds = shippedPackIds(), directory = packsDirectory } = {}) {
|
|
291
306
|
const { components } = layoutOf(root);
|
|
292
307
|
const record = recordOf(root);
|
|
293
308
|
const installed = isTable(record.packs) ? record.packs : {};
|
|
294
309
|
const blocks = packageFolders(root);
|
|
295
|
-
const scopes = new Set(blocks.map(({ id }) => id.split("/")[0]));
|
|
310
|
+
const scopes = new Set([OWN_SCOPE, ...blocks.map(({ id }) => id.split("/")[0])]);
|
|
296
311
|
try {
|
|
297
312
|
for (const name of fs.readdirSync(components)) if (PACK_ID.test(name) && fs.existsSync(path.join(components, name, PACK_FILE))) scopes.add(name);
|
|
298
313
|
} catch {}
|
|
@@ -336,7 +351,7 @@ export function workspacePacks(root, { settings = null, shippedIds = shippedPack
|
|
|
336
351
|
const ownBlocks = official ? shippedBlocks(directory) : [];
|
|
337
352
|
const behind = official && shipped && changed.some((block) => (block.endsWith(`/${PACK_FILE}`) ? versionAfter(shipped.version, manifest?.version ?? null) : (ownBlocks.some((one) => one.id === block) && versionAfter(ownBlocks.find((one) => one.id === block).version, versionAt(block)))));
|
|
338
353
|
const newer = behind ? shipped.version : null;
|
|
339
|
-
const told = manifest ?? (problem ? null : shipped);
|
|
354
|
+
const told = id === OWN_SCOPE ? DEFAULT_PACK : manifest ?? (problem ? null : shipped);
|
|
340
355
|
return {
|
|
341
356
|
id,
|
|
342
357
|
name: told?.name ?? { zh: id, en: id },
|
|
@@ -345,7 +360,7 @@ export function workspacePacks(root, { settings = null, shippedIds = shippedPack
|
|
|
345
360
|
author: told?.author ?? null,
|
|
346
361
|
homepage: told?.homepage ?? null,
|
|
347
362
|
icon: told?.icon ?? null,
|
|
348
|
-
kind: official ? "official" : was ? "installed" : "own",
|
|
363
|
+
kind: id === OWN_SCOPE ? "default" : official ? "official" : was ? "installed" : "own",
|
|
349
364
|
problem: problem ? both(problem) : null,
|
|
350
365
|
blocks: ids.length,
|
|
351
366
|
enabled: switches[id] !== false,
|
|
@@ -353,7 +368,7 @@ export function workspacePacks(root, { settings = null, shippedIds = shippedPack
|
|
|
353
368
|
newer,
|
|
354
369
|
};
|
|
355
370
|
});
|
|
356
|
-
const rank = ({ id, kind }) => (kind === "official" ? shippedIds.indexOf(id) : kind === "installed" ? 1000 : 2000);
|
|
371
|
+
const rank = ({ id, kind }) => (kind === "default" ? -1 : kind === "official" ? shippedIds.indexOf(id) : kind === "installed" ? 1000 : 2000);
|
|
357
372
|
return listed.sort((a, b) => rank(a) - rank(b) || (a.id < b.id ? -1 : 1));
|
|
358
373
|
}
|
|
359
374
|
|
|
@@ -10,7 +10,7 @@ import { writeAtomic } from "./files.mjs";
|
|
|
10
10
|
import { attr, walk } from "./html-tree.mjs";
|
|
11
11
|
import { HOST, NET, netHostsOf } from "./net-policy.mjs";
|
|
12
12
|
import { inLanguage, refusal, said, saying, told } from "./i18n/index.mjs";
|
|
13
|
-
import { PACK_FILE, PACK_ID, readPackManifest } from "./pack-manifest.mjs";
|
|
13
|
+
import { DEFAULT_PACK, OWN_SCOPE, PACK_FILE, PACK_ID, readPackManifest } from "./pack-manifest.mjs";
|
|
14
14
|
import { DEVICE_NAMES, PACKAGE_MANIFEST, WORKSPACE_MARK, findWorkspace, layoutOf, markerOf, packageFolders } from "./workspace.mjs";
|
|
15
15
|
|
|
16
16
|
// 组件包, custom blocks (自定义块) as the UI and the Agent's documents call them: what the workspace's
|
|
@@ -64,7 +64,7 @@ const PLACES = ["document", "page"];
|
|
|
64
64
|
const DOCUMENT_ONLY = ["document"];
|
|
65
65
|
// What `card` says of a card on a board, in cells of the grid: a row is 12 of them, and a card at most
|
|
66
66
|
// 24 high.
|
|
67
|
-
const CARD_FIELDS = ["sizes", "w", "h", "min", "max", "resize", "fit", "bare"];
|
|
67
|
+
const CARD_FIELDS = ["sizes", "w", "h", "min", "max", "resize", "fit", "bare", "consent"];
|
|
68
68
|
const GRID = { w: 12, h: 24 };
|
|
69
69
|
const FITS = ["fixed", "content"];
|
|
70
70
|
const NO_CARD = { sizes: null, any: false, w: 4, h: null, min: { w: 1, h: 1 }, max: { ...GRID }, resize: false, fit: "fixed", bare: false };
|
|
@@ -268,7 +268,9 @@ function placesOf(places) {
|
|
|
268
268
|
// the fewest whole cells its content takes). With `sizes`, the first is the default, and no w or h is
|
|
269
269
|
// written beside them; a min or a max beside them frees the card (`any`): the sizes are the common ones
|
|
270
270
|
// its 大小 menu lists, any whole size between min and max is its too (resizing by the corner, a place),
|
|
271
|
-
// and each of the sizes stands inside them.
|
|
271
|
+
// and each of the sizes stands inside them. `consent` ({ zh, en }, where it says one) is what the kit's
|
|
272
|
+
// banner on its card says while it waits for the reader to let it online (允许联网之后显示天气), in place of
|
|
273
|
+
// the kit's own line (允许联网之后显示内容).
|
|
272
274
|
function cardOf(card) {
|
|
273
275
|
if (card === undefined) return NO_CARD;
|
|
274
276
|
if (!isTable(card)) fail(said("{0} 要写成一张表", "card"));
|
|
@@ -307,12 +309,14 @@ function cardOf(card) {
|
|
|
307
309
|
}
|
|
308
310
|
for (const flag of ["resize", "bare"]) if (card[flag] !== undefined && typeof card[flag] !== "boolean") fail(said("{0} 要写成 true 或 false", `card.${flag}`));
|
|
309
311
|
if (card.fit !== undefined && !FITS.includes(card.fit)) fail(said("card.fit 只能是 fixed 或 content"));
|
|
312
|
+
if (card.consent !== undefined) bothLanguages(card.consent, "card.consent");
|
|
310
313
|
return {
|
|
311
314
|
sizes: card.sizes ? card.sizes.map(([width, height]) => [width, height]) : null,
|
|
312
315
|
any, w, h, min, max,
|
|
313
316
|
resize: card.resize ?? false,
|
|
314
317
|
fit: card.fit ?? "fixed",
|
|
315
318
|
bare: card.bare ?? false,
|
|
319
|
+
...(card.consent !== undefined ? { consent: { zh: card.consent.zh, en: card.consent.en } } : {}),
|
|
316
320
|
};
|
|
317
321
|
}
|
|
318
322
|
|
|
@@ -635,7 +639,8 @@ export function readCatalog(root = workspaceRoot(), held = NO_SETTINGS, { on = n
|
|
|
635
639
|
/**
|
|
636
640
|
* What the pack.json of each scope of `scopes` (and of each folder of components/ that holds one) names
|
|
637
641
|
* it: a Map, by scope, of { zh, en }, or null where it has none or one that does not read (a scope of
|
|
638
|
-
* blocks with no pack.json is a pack of its own by its scope's name:
|
|
642
|
+
* blocks with no pack.json is a pack of its own by its scope's name, the default pack, local/, by its own:
|
|
643
|
+
* ./pack-manifest.mjs DEFAULT_PACK, ./block-packs.mjs).
|
|
639
644
|
*/
|
|
640
645
|
export function packNames(root, scopes = []) {
|
|
641
646
|
const { components } = layoutOf(root);
|
|
@@ -647,7 +652,7 @@ export function packNames(root, scopes = []) {
|
|
|
647
652
|
for (const scope of [...new Set([...scopes, ...withFile])].sort()) {
|
|
648
653
|
let name = null;
|
|
649
654
|
try {
|
|
650
|
-
name = readPackManifest(readFileSync(path.join(components, scope, PACK_FILE), "utf8")).name;
|
|
655
|
+
name = scope === OWN_SCOPE ? DEFAULT_PACK.name : readPackManifest(readFileSync(path.join(components, scope, PACK_FILE), "utf8")).name;
|
|
651
656
|
} catch {}
|
|
652
657
|
names.set(scope, name);
|
|
653
658
|
}
|
|
@@ -687,9 +692,9 @@ const stateOf = (found, settings) => (found.problem ? (found.disabled ? "disable
|
|
|
687
692
|
* What the kit is told of a package: where its instances are, its parts, what it leaves on a page, how far
|
|
688
693
|
* its content's shape goes, and what it uses (`needs`, where it names any: the kit gives an instance
|
|
689
694
|
* context.workspace for "workspace", context.fetch for a host of the net and context.table() for
|
|
690
|
-
* "tables").
|
|
695
|
+
* "tables"), and the line its card's consent banner says (`consent`, its card's, where it says one).
|
|
691
696
|
*/
|
|
692
|
-
export const descriptionOf = ({ id, match, parts, runtime, schema, needs }) => ({ id, match, parts, ...(runtime ? { runtime } : {}), ...(schema !== undefined ? { schema } : {}), ...(needs?.length ? { needs } : {}) });
|
|
697
|
+
export const descriptionOf = ({ id, match, parts, runtime, schema, needs, card }) => ({ id, match, parts, ...(runtime ? { runtime } : {}), ...(schema !== undefined ? { schema } : {}), ...(needs?.length ? { needs } : {}), ...(card?.consent ? { consent: card.consent } : {}) });
|
|
693
698
|
|
|
694
699
|
/**
|
|
695
700
|
* What the kit is told of a catalog, each by DocKit.describe, the one way a page learns a package's
|
|
@@ -786,7 +791,8 @@ export const templateOf = (found) => readTemplate(found).markup ?? null;
|
|
|
786
791
|
* no route and no dynamic import. One entry for each package that loads, by id: { id, version, name:
|
|
787
792
|
* { zh, en }, description: { zh, en }, words, definition, stamp, template (the markup "/" puts in: one
|
|
788
793
|
* instance of it, or null), preview (the address of its picture, or null), state ("normal", or "hidden": a menu offers what is "normal" and reads no setting), places (which the page's
|
|
789
|
-
* settingState reads with gallery.json's lists as its event stream says them), needs,
|
|
794
|
+
* settingState reads with gallery.json's lists as its event stream says them), needs, settings (the fields of its 设置 form, a
|
|
795
|
+
* manifest's `settings`, [] where it has none), markdown, assets (the kit's files it asks for,
|
|
790
796
|
* by id), tags (packageTags: what loads it in a page that was served without it, the line that tells the
|
|
791
797
|
* kit of its parts among them), pack ({ id, name }: the pack it is of, its scope, and what its pack.json names
|
|
792
798
|
* it, null where none does: a menu writes the pack's name after a block's in grey where two packs offer
|
|
@@ -806,6 +812,7 @@ export const menuOf = ({ packages, settings = NO_SETTINGS, packs = new Map() })
|
|
|
806
812
|
state: stateOf(found, settings),
|
|
807
813
|
places: found.places,
|
|
808
814
|
needs: found.needs,
|
|
815
|
+
settings: found.settings,
|
|
809
816
|
markdown: found.markdown,
|
|
810
817
|
assets: found.assets,
|
|
811
818
|
tags: packageTags(found),
|
|
@@ -16,7 +16,7 @@ export const SOURCE_ATTRIBUTES = ["data-checked", "rowspan", "colspan", "data-so
|
|
|
16
16
|
|
|
17
17
|
/**
|
|
18
18
|
* The classes that are a block's or a cell's look, which a reader sets and the file keeps: a text color
|
|
19
|
-
* or a fill (doc-text-<color>, doc-highlight-<color>), a cell's alignments and its bold (table.mjs's
|
|
19
|
+
* or a fill (doc-text-<color>, doc-highlight-<color>), a text block's alignment and indent (a table's frame's alignment is the same two classes), a cell's alignments and its bold (table.mjs's
|
|
20
20
|
* CELL_ALIGN_CLASSES, CELL_VALIGN_CLASSES, CELL_BOLD_CLASS, the editor's CELL_LOOKS). What the kit and
|
|
21
21
|
* the editor toggle as they lay a page out (a table's number and doc-table--auto, a code block's
|
|
22
22
|
* folds) is none, so that no component hears its own layout as a change of the file, and draws again
|
|
@@ -28,6 +28,8 @@ export const LOOK_CLASSES = new Set([
|
|
|
28
28
|
// file would bring its description, prose and all, into the kit's runtime (tests/unit/installed.mjs
|
|
29
29
|
// holds the two lists together).
|
|
30
30
|
"doc-align-left", "doc-align-center", "doc-align-right", "doc-valign-top", "doc-valign-middle", "doc-valign-bottom", "doc-bold",
|
|
31
|
+
// A paragraph's or a heading's indent (the editor's components/align.mjs INDENTS; its alignment is a cell's classes above).
|
|
32
|
+
...Array.from({ length: 8 }, (_, index) => `doc-indent-${index + 1}`),
|
|
31
33
|
]);
|
|
32
34
|
|
|
33
35
|
/** Whether a class attribute's look classes (LOOK_CLASSES) differ from `before` to `after`, either null for none. */
|
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
// A heading, levels 1 to 4 (the fourth body-sized): a basic block.
|
|
1
|
+
// A heading, levels 1 to 4 (the fourth body-sized): a basic block. Aligned and indented as a paragraph
|
|
2
|
+
// is (paragraph.mjs TEXT_ALIGN_CLASSES, described there and by the table).
|
|
2
3
|
export default {
|
|
3
4
|
id: "heading",
|
|
4
5
|
category: "block",
|
|
@@ -124,7 +124,7 @@ export const PACKAGE_MARK = "data-doc-package";
|
|
|
124
124
|
export const ARRIVING = "data-ge-arriving";
|
|
125
125
|
|
|
126
126
|
/**
|
|
127
|
-
* Whether the document's insert entries ("/", 在下方新建, the handle's grid
|
|
127
|
+
* Whether the document's insert entries ("/", 在下方新建, the handle's grid) offer the
|
|
128
128
|
* block `id` whose manifest's `places` are those (left out: ["document"]), by gallery.json's lists
|
|
129
129
|
* (`settings`: hidden, shown, disabled, unlisted, packsOff, each left out for none): one that says it stands in a
|
|
130
130
|
* document is offered unless hidden; one that does not, only where shown; one disabled never, as it does
|
|
@@ -47,6 +47,8 @@ export default {
|
|
|
47
47
|
// a copy of the view keeps; never written in doc.html.
|
|
48
48
|
state: { html: ["data-doc-theme", ...Object.values(LOOK_ATTRIBUTES)] },
|
|
49
49
|
internal: ["doc-display*", "data-doc-export-copy", "data-theme", "doc-export-id", "doc-reveal", "doc-kit-error", "doc-net-consent*", "data-doc-snapshot",
|
|
50
|
+
// A consent bar on a card under 240px of content (runtime/net.js), its line over its button.
|
|
51
|
+
"data-doc-net-narrow",
|
|
50
52
|
// The time an export's snapshot was made (its data-doc-snapshot tag's: render/net-snapshot.mjs), which context.workspace.query answers as `at`.
|
|
51
53
|
"data-at",
|
|
52
54
|
// A custom page's (no document's: src/render/page-html.mjs, the kit's board/): its cards' cells, the Agent's
|
|
@@ -1,9 +1,16 @@
|
|
|
1
1
|
// A paragraph (文本), or small text (小字, p.doc-note): a basic block. Small text may end in a part at
|
|
2
2
|
// the line's right end (span.doc-tab: the page editor's Tab).
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* A paragraph's or a heading's alignment and indent (the page editor's 对齐与缩进): centred or at the
|
|
6
|
+
* right (left is neither), moved in by levels of two body characters (styles/flow.css).
|
|
7
|
+
*/
|
|
8
|
+
export const TEXT_ALIGN_CLASSES = ["doc-align-center", "doc-align-right", ...Array.from({ length: 8 }, (_, index) => `doc-indent-${index + 1}`)];
|
|
9
|
+
|
|
3
10
|
export default {
|
|
4
11
|
id: "paragraph",
|
|
5
12
|
category: "block",
|
|
6
13
|
match: "p",
|
|
7
14
|
tail: ".doc-tab", // small text's end part, a span at the line's right end
|
|
8
|
-
classes: ["doc-note", "doc-tab"],
|
|
15
|
+
classes: ["doc-note", "doc-tab", ...TEXT_ALIGN_CLASSES.filter((name) => name.startsWith("doc-indent-"))], // the alignments are the table's (a cell's), the same classes
|
|
9
16
|
};
|
|
@@ -30,6 +30,7 @@ export default {
|
|
|
30
30
|
"data-number-columns": "off: no column read as numbers (none centered, none sortable by number), on the table or its frame",
|
|
31
31
|
"data-doc-chart-source": "on its frame: the key a chart drawn from it reads it by (data-doc-chart-data on the chart's host)",
|
|
32
32
|
},
|
|
33
|
+
// The frame may be placed centred or at the right (doc-align-center, doc-align-right, a text block's: the page editor's 对齐 ›).
|
|
33
34
|
// A cell may also be given a text color or a fill (doc-text-*, doc-highlight-*: text.mjs), an alignment, a vertical one and bold
|
|
34
35
|
// (doc-bold); a header row's cell's look is doc-bold doc-highlight-gray, as the page editor gives it (a header column's th scope="row" none).
|
|
35
36
|
classes: ["doc-table", "doc-table-wrap", "doc-table-meta", "doc-table--sticky-first", ...CELL_ALIGN_CLASSES, ...CELL_VALIGN_CLASSES, CELL_BOLD_CLASS],
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import { ICON_COLOR_VALUES } from "./icon-value.mjs";
|
|
2
|
+
|
|
3
|
+
// Gallery's own line icons as a custom page's icon (page.json's `icon`): the look of the workbench's sidebar
|
|
4
|
+
// head, whose 新建 and 搜索 are Lucide's line icons (a 1.75 line in 24 units, workbench/app/components/icons.ts),
|
|
5
|
+
// so that a page Gallery makes stands among them in the same hand (the user's word of 2026-11-09: no filled
|
|
6
|
+
// icon there). A value is `/icons/lucide/<name>.svg`, with no color of its own: the workbench masks it in the
|
|
7
|
+
// color of where it stands (the sidebar's icon gray, as an icon of no icon's color), the browser tab draws it
|
|
8
|
+
// in the tab's gray (as a page with no icon, icon-value.mjs DEFAULT_TAB_ICON). It is none of the three kinds
|
|
9
|
+
// of a document's icon (icon-value.mjs iconKind: no document has one), nor an icon of the 图标 tab: Gallery's
|
|
10
|
+
// default home page's house (src/editor/home-page.mjs HOME_ICON), alone so far. The icon route draws it
|
|
11
|
+
// (src/render/emoji.mjs iconImage).
|
|
12
|
+
|
|
13
|
+
const LINE_ICONS = {
|
|
14
|
+
// Lucide's house (1.67.0), the one the sidebar drew for the home page before its page.json said its icon.
|
|
15
|
+
house: '<path d="M15 21v-8a1 1 0 0 0-1-1h-4a1 1 0 0 0-1 1v8"/><path d="M3 10a2 2 0 0 1 .709-1.528l7-5.999a2 2 0 0 1 2.582 0l7 5.999A2 2 0 0 1 21 10v9a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2z"/>',
|
|
16
|
+
};
|
|
17
|
+
const LINE = /^\/icons\/lucide\/([a-z0-9-]+)\.svg$/;
|
|
18
|
+
|
|
19
|
+
/** The value of Gallery's line icon `name` (one LINE_ICONS has). */
|
|
20
|
+
export const lineIconValue = (name) => `/icons/lucide/${name}.svg`;
|
|
21
|
+
|
|
22
|
+
/** Whether `value` names one of Gallery's line icons. */
|
|
23
|
+
export const isLineIcon = (value) => lineIconSvg(value) !== null;
|
|
24
|
+
|
|
25
|
+
const [TAB_LIGHT, TAB_DARK] = ICON_COLOR_VALUES.gray;
|
|
26
|
+
|
|
27
|
+
/**
|
|
28
|
+
* The SVG of the line icon `value` names, or null (none of them): its lines in `color` (black, the
|
|
29
|
+
* workbench's mask); with `tab`, a browser tab's, its box cropped to `1 1 22 22` as the tab's icon of a
|
|
30
|
+
* page with no icon is, in the tab glyphs' gray, light or dark as the system is.
|
|
31
|
+
*/
|
|
32
|
+
export function lineIconSvg(value, { color = "currentColor", tab = false } = {}) {
|
|
33
|
+
const name = typeof value === "string" ? LINE.exec(value)?.[1] : null;
|
|
34
|
+
if (!name || !Object.hasOwn(LINE_ICONS, name)) return null;
|
|
35
|
+
const style = tab ? `<style>svg{color:${TAB_LIGHT}}@media (prefers-color-scheme:dark){svg{color:${TAB_DARK}}}</style>` : "";
|
|
36
|
+
return `<svg xmlns="http://www.w3.org/2000/svg" viewBox="${tab ? "1 1 22 22" : "0 0 24 24"}" fill="none" stroke="${tab ? "currentColor" : color}" stroke-width="1.75" stroke-linecap="round" stroke-linejoin="round">${style}${LINE_ICONS[name]}</svg>`;
|
|
37
|
+
}
|
package/browser/shared/http.mjs
CHANGED
|
@@ -1,6 +1,15 @@
|
|
|
1
1
|
// The local server's answers: JSON for its endpoints (the editor's saves, the workbench's commands),
|
|
2
2
|
// and files for its routes.
|
|
3
3
|
|
|
4
|
+
// Who may show a page of Gallery's in a frame (its HTML: the workbench, a document, a custom page): a page of
|
|
5
|
+
// its own origin, and a Gallery server of this computer, http://127.0.0.1 at any port (a workbench showing a
|
|
6
|
+
// draft of another workspace from that workspace's server, docs/workbench.md "Drafts of other workspaces";
|
|
7
|
+
// what such a frame may say and hear is still held to the servers vouched for). Never a site elsewhere, which
|
|
8
|
+
// could lay an editable page under a decoy, the reader's clicks and keys then editing the files (the security
|
|
9
|
+
// review of 0.2.0), nor localhost, which may lead to another program on [::1] (no workbench is shown there:
|
|
10
|
+
// src/server/routes.mjs toLoopback).
|
|
11
|
+
export const FRAMED_BY = { "Content-Security-Policy": "frame-ancestors 'self' http://127.0.0.1:*" };
|
|
12
|
+
|
|
4
13
|
// A JSON answer.
|
|
5
14
|
export function sendJson(response, status, body) {
|
|
6
15
|
response.statusCode = status;
|
|
@@ -383,7 +383,7 @@ export default {
|
|
|
383
383
|
"不加载它的脚本和样式,已有的块只显示内容": "Its script and style aren't loaded. Existing blocks show only what they hold",
|
|
384
384
|
"文档菜单里出现哪些块,这个工作区加载哪些自定义块。": "Which blocks the document menus offer, and which custom blocks this workspace loads.",
|
|
385
385
|
"文档菜单里出现哪些块,这个工作区加载哪些自定义块": "Which blocks the document menus offer, and which custom blocks this workspace loads",
|
|
386
|
-
"块包的开关关掉后,它的块都不在
|
|
386
|
+
"块包的开关关掉后,它的块都不在 “/”和添加自定义块里;已经写在文档和页面里的块照常显示。": "With a pack's switch off, none of its blocks is offered in “/” or Add custom block; those already in documents and pages show as ever.",
|
|
387
387
|
"打开块包「{0}」": "Open the pack “{0}”",
|
|
388
388
|
"{0} 个块": "{0} blocks",
|
|
389
389
|
"启用块包": "Pack on",
|
|
@@ -391,18 +391,18 @@ export default {
|
|
|
391
391
|
"Gallery 自带": "Gallery's own",
|
|
392
392
|
"工作区自己写的块": "This workspace's own blocks",
|
|
393
393
|
"pack.json 读不出来:{0}": "pack.json can't be read: {0}",
|
|
394
|
-
"这个块包关着:它的块都不在
|
|
394
|
+
"这个块包关着:它的块都不在 “/”和添加自定义块里;已经写在文档和页面里的块照常显示。": "This pack is off: none of its blocks is offered in “/” or Add custom block; those already in documents and pages show as ever.",
|
|
395
395
|
"这个块包装上后改过({0}),Gallery 的新版本 {1} 不会换上改过的部分;没改过的块照常更新。": "This pack was changed after it was installed ({0}): Gallery's new version {1} is not put over what changed; the blocks not changed are updated as ever.",
|
|
396
396
|
"这个块包装上后改过({0}):再装一次新版本时,改过的部分保持不变。": "This pack was changed after it was installed ({0}): installing a new version keeps what changed as it is.",
|
|
397
397
|
"这个块包里还没有块。": "This pack has no blocks yet.",
|
|
398
398
|
"已导入块包「{0}」{1}": "Imported the pack “{0}” {1}",
|
|
399
399
|
"块包「{0}」已更新到 {1}": "The pack “{0}” is updated to {1}",
|
|
400
400
|
"块包「{0}」{1} 已经装好了": "The pack “{0}” {1} is installed already",
|
|
401
|
-
"自定义块按块包放:每个块包右边的开关管它的块在
|
|
401
|
+
"自定义块按块包放:每个块包右边的开关管它的块在 “/”和添加自定义块里提不提供;点一个块包看它的块。": "Custom blocks come in packs: the switch at a pack's right says whether its blocks are offered in “/” and Add custom block; click a pack to see its blocks.",
|
|
402
402
|
"这个工作区还没有自定义块:让 Agent 做一个,或导入一个块包,它们放在工作区的 components 文件夹里。": "This workspace has no custom blocks yet: ask an Agent to make one, or import a block pack. They live in the workspace's components folder.",
|
|
403
|
-
"每个块右边的开关管
|
|
403
|
+
"每个块右边的开关管 “/”和添加自定义块里提不提供它,默认打开;点一行看它的说明和别的开关。": "The switch right of each block decides whether \"/\" and Add custom block offer it, on by default. Click a row for what it is and its other switches.",
|
|
404
404
|
"在所有菜单里提供": "Offer in every menu",
|
|
405
|
-
"
|
|
405
|
+
"总开关关掉后,“/”和添加自定义块里都不再提供它;已经写在文档和页面里的块照常显示。": "With the master switch off, it is no longer offered in \"/\" or Add custom block. Blocks already written into documents and pages keep showing.",
|
|
406
406
|
"每个块右边的开关是「在文档菜单里显示」:关掉的块不再出现在 “/”、在下方新建和手柄的网格里,已有的块照常。": "The switch right of each block is \"Show in document menus\": a block switched off leaves \"/\", Add below and the handle's grid. Existing blocks stay as they are.",
|
|
407
407
|
"这个块总在文档菜单里": "This block is always in the document menus",
|
|
408
408
|
"读不出 component.json": "component.json cannot be read",
|
|
@@ -854,7 +854,6 @@ export default {
|
|
|
854
854
|
"在左侧插入": "Insert left",
|
|
855
855
|
"在右侧插入": "Insert right",
|
|
856
856
|
"均分列宽": "Even column widths",
|
|
857
|
-
"视图": "View",
|
|
858
857
|
"自动调整列宽": "Auto-fit column widths",
|
|
859
858
|
"列": "Column",
|
|
860
859
|
"行": "Row",
|
|
@@ -1026,6 +1025,9 @@ export default {
|
|
|
1026
1025
|
"左对齐": "Align left",
|
|
1027
1026
|
"居中对齐": "Align center",
|
|
1028
1027
|
"右对齐": "Align right",
|
|
1028
|
+
"对齐与缩进": "Align and indent",
|
|
1029
|
+
"增加缩进": "Indent",
|
|
1030
|
+
"减少缩进": "Outdent",
|
|
1029
1031
|
"粘贴图片链接…": "Paste an image link…",
|
|
1030
1032
|
"嵌入图片": "Embed image",
|
|
1031
1033
|
"适用于网络上的任何图片。": "Works with any image on the web.",
|
|
@@ -1048,6 +1050,9 @@ export default {
|
|
|
1048
1050
|
"替换图片": "Replace image",
|
|
1049
1051
|
"恢复原始大小": "Original size",
|
|
1050
1052
|
"已恢复原始大小 · Ctrl+Z 撤销": "Original size restored · Ctrl+Z to undo",
|
|
1053
|
+
"同步宽度到全局": "Use this width for all images",
|
|
1054
|
+
"页面上的图片已经都是这个宽度。": "The images on this page are all this width already.",
|
|
1055
|
+
"已将 {0} 张图片设为同一宽度 · Ctrl+Z 撤销": "{0} images set to the same width · Ctrl+Z to undo",
|
|
1051
1056
|
"上一张": "Previous",
|
|
1052
1057
|
"下一张": "Next",
|
|
1053
1058
|
"查看图片": "Image viewer",
|
|
@@ -1275,6 +1280,7 @@ export default {
|
|
|
1275
1280
|
"这份文档的标题和说明读不出来": "This document's title and description could not be read",
|
|
1276
1281
|
"应用到全部文档": "Apply to all documents",
|
|
1277
1282
|
"这份文档的字体与布局用到全部文档,新建的文档也一样": "Use this document's font and layout in every document, new ones too",
|
|
1283
|
+
"这份文档的字体与布局用到它所在工作区的全部文档,新建的文档也一样": "Use this document's font and layout in every document of its workspace, new ones too",
|
|
1278
1284
|
"已应用到全部文档": "Applied to all documents",
|
|
1279
1285
|
"已应用到全部文档,替换了 {0} 篇的单独设置": "Applied to all documents; own settings replaced in {0}",
|
|
1280
1286
|
"没有应用到全部文档:{0}": "Not applied to all documents: {0}",
|
|
@@ -1282,7 +1288,6 @@ export default {
|
|
|
1282
1288
|
"自定义页": "Custom page",
|
|
1283
1289
|
"更多页面": "More pages",
|
|
1284
1290
|
"未命名页面": "Untitled page",
|
|
1285
|
-
"首页不能移到回收区": "The home page cannot be moved to the trash",
|
|
1286
1291
|
"找不到这个页面": "This page was not found",
|
|
1287
1292
|
"标题不能是空的,也不能超过 200 个字": "A title cannot be empty or longer than 200 characters",
|
|
1288
1293
|
// 自定义页顶栏右上角的 ···(页的菜单)
|
|
@@ -1308,6 +1313,9 @@ export default {
|
|
|
1308
1313
|
"这个块不能放在页面上": "This block cannot go on a page",
|
|
1309
1314
|
"卡片设置": "Card settings",
|
|
1310
1315
|
"(未选择)": "(none)",
|
|
1316
|
+
// 自定义块的设置:视图读哪一张表格
|
|
1317
|
+
"表格 {0}": "Table {0}",
|
|
1318
|
+
"表格 {0} · {1}": "Table {0} · {1}",
|
|
1311
1319
|
// 首页:恢复默认卡片(侧栏里首页的菜单)和第一次打开时的说明
|
|
1312
1320
|
"恢复默认卡片": "Restore default cards",
|
|
1313
1321
|
"已放回默认卡片:{0}": "Default cards put back: {0}",
|
|
@@ -1315,18 +1323,18 @@ export default {
|
|
|
1315
1323
|
"没能放回:{0}": "Could not put back: {0}",
|
|
1316
1324
|
"默认卡片都在,没有要放回的": "All the default cards are there: nothing to put back",
|
|
1317
1325
|
"没能恢复默认卡片": "The default cards could not be restored",
|
|
1318
|
-
"
|
|
1326
|
+
"这一页之后又改过,在页面上按 Ctrl+Z 撤销": "This page changed since: press Ctrl+Z on the page to undo",
|
|
1319
1327
|
"放回的卡片之后被改过或拿掉了,没有撤销": "The cards put back were changed or taken out since: nothing undone",
|
|
1320
|
-
"
|
|
1328
|
+
"这一页的卡片可以自己摆": "This page's cards are yours to arrange",
|
|
1321
1329
|
"拖卡片右上角的 {0} 移动它,点一下它打开菜单(大小、设置、删除),点页面右上角的 ··· 里的「添加自定义块」加一张。": "Drag {0} at a card's top right to move it, click it to open the card's menu (Size, Settings, Delete), and use Add custom block in the ··· menu at the top right of the page to add one.",
|
|
1322
1330
|
"拖卡片右上角的 {0} 移动它,点一下它打开菜单(大小、设置、删除),点页面右上方的「添加自定义块」加一张。": "Drag {0} at a card's top right to move it, click it to open the card's menu (Size, Settings, Delete), and use Add custom block at the top right of the page to add one.",
|
|
1323
1331
|
"想要新卡片或新页面,跟 Agent 说,比如:": "For a new card or a new page, ask your Agent, for example:",
|
|
1324
|
-
"用 Gallery
|
|
1332
|
+
"用 Gallery 在「{0}」这一页加一张卡片,记我每天喝了几杯水。别动我摆好的卡片。": "Use Gallery to add a card to my page “{0}” that counts the glasses of water I drink each day. Leave the cards I placed where they are.",
|
|
1325
1333
|
"复制": "Copy",
|
|
1326
1334
|
"已复制": "Copied",
|
|
1327
1335
|
"已复制这句话,发给 Agent 就行": "Copied: send it to your Agent",
|
|
1328
1336
|
"关闭这条说明": "Close this note",
|
|
1329
|
-
"
|
|
1337
|
+
"这一页的说明": "About this page",
|
|
1330
1338
|
"没能记下这条说明已关闭": "Could not keep this note closed",
|
|
1331
1339
|
// 联网:卡片上的「允许访问」和组件列表的「允许联网」打开的同意框(netConsent.ts)
|
|
1332
1340
|
"这个块现在没有要联网的地方": "This block reaches no website now",
|
|
@@ -1337,11 +1345,23 @@ export default {
|
|
|
1337
1345
|
"允许联网": "Online",
|
|
1338
1346
|
"允许它从这些网站取数据:{0}": "Lets it fetch data from these websites: {0}",
|
|
1339
1347
|
"这个块不联网": "This block reaches no website",
|
|
1340
|
-
"
|
|
1341
|
-
"
|
|
1342
|
-
"
|
|
1343
|
-
"
|
|
1344
|
-
"
|
|
1348
|
+
"加到这一页": "Add to this page",
|
|
1349
|
+
"有了新的默认卡片": "New default cards",
|
|
1350
|
+
"点「加到这一页」放进空位,已有的卡片不动。以后也可以在这一页的菜单中点「恢复默认卡片」。": "Add to this page puts them in the empty spots and leaves your cards as they are. Later, Restore default cards in this page's menu does it too.",
|
|
1351
|
+
"新的默认卡片": "New default cards",
|
|
1352
|
+
"没能把卡片放到这一页": "The cards could not be put on this page",
|
|
1353
|
+
// 侧栏头部的拖动、自定义页的 ··· 菜单和新建页面、默认块包(SidebarHead.tsx、reportMenus.tsx、board/hint.mjs、ComponentSettings.tsx)
|
|
1354
|
+
"还没有块。让 Agent 写一个自定义块,没有指定块包时就放在这里。": "No blocks yet. Ask an Agent for a custom block: one it puts in no pack of its own goes here.",
|
|
1355
|
+
"新建页面": "New page",
|
|
1356
|
+
"一个空白页,放在这一页下面,让 Agent 来写": "A blank page under this one, for an Agent to write",
|
|
1357
|
+
"重命名、新建页面等…": "Rename, new page and more…",
|
|
1358
|
+
"页面的操作": "Page actions",
|
|
1359
|
+
"用 Gallery 把「{0}」这个自定义页写出来:放上我这周的待办,和离月底还有几天。": "Use Gallery to write my custom page “{0}”: this week's to-dos, and how many days are left in the month.",
|
|
1360
|
+
"这一页还是空的": "This page is empty",
|
|
1361
|
+
"自定义页由 Agent 来写:可以是一页卡片,也可以是它为你做的任何网页。": "An Agent writes a custom page: a page of cards, or any web page it makes for you.",
|
|
1362
|
+
"跟 Agent 说你想在这里放什么,比如:": "Tell your Agent what you want here, for example:",
|
|
1363
|
+
"空白的自定义页": "A blank custom page",
|
|
1364
|
+
"侧栏头部的顺序不对": "The order of the sidebar's top rows is not valid",
|
|
1345
1365
|
// 侧栏的栏和网页链接(SidebarTree.tsx、LinkForm.tsx、LinkView.tsx,服务器的 link、link-set)
|
|
1346
1366
|
"这是 Gallery 自己的地址,请直接链接文档": "This is Gallery's own address: link the document instead",
|
|
1347
1367
|
"这个网站不允许在别的页面里显示": "This website doesn't let other pages show it",
|
|
@@ -1388,7 +1408,10 @@ export default {
|
|
|
1388
1408
|
"只改它在这里的显示位置,文件不动": "Changes only where it shows here: no file moves",
|
|
1389
1409
|
"在文件夹中显示": "Show in folder",
|
|
1390
1410
|
"在它的工作区里打开": "Open in its workspace",
|
|
1391
|
-
"
|
|
1411
|
+
"「{0}」已移至它所在工作区的回收区": "“{0}” moved to the trash of its workspace",
|
|
1412
|
+
"副本在它所在的工作区里": "The copy is made in its workspace",
|
|
1413
|
+
"导入的页面在它所在的工作区里": "The imported pages are made in its workspace",
|
|
1414
|
+
"进它所在工作区的回收区": "Goes to the trash of its workspace",
|
|
1392
1415
|
"从文档树移除": "Remove from the sidebar",
|
|
1393
1416
|
"只移除这一条,不删除底稿": "Removes this entry only: the draft is not deleted",
|
|
1394
1417
|
"找不到底稿:本机登记的两个工作区编号相同": "Draft not found: two registered workspaces share one id",
|
|
@@ -4,6 +4,7 @@ import path from "node:path";
|
|
|
4
4
|
import { writeAtomic } from "./files.mjs";
|
|
5
5
|
import { extensionColumnIds } from "./extensions.mjs";
|
|
6
6
|
import { DOCS, entryPattern, extensionGroupId, GROUP_LIMITS, groupOf, isForeign, isTop, newGroupId, topIn, topOf, validGroups } from "./outline-shape.mjs";
|
|
7
|
+
import { storedHead } from "./sidebar-head.mjs";
|
|
7
8
|
import { shownWorkspaces, snapshotOf } from "./workspace-columns.mjs";
|
|
8
9
|
import { layoutOf, listDocumentSlugs, listLinkSlugs, pageSlug } from "./workspace.mjs";
|
|
9
10
|
|
|
@@ -38,6 +39,9 @@ import { layoutOf, listDocumentSlugs, listLinkSlugs, pageSlug } from "./workspac
|
|
|
38
39
|
// got yet comes last (not written until the outline is), one whose extension is gone drops out, and what an
|
|
39
40
|
// outline says of its entries is passed over (an extension's entries are its own, never the outline's).
|
|
40
41
|
// Their place is what the outline keeps of them.
|
|
42
|
+
// The file also keeps the order of the sidebar's head rows (`head`: 新建, 搜索 and the custom pages,
|
|
43
|
+
// ./sidebar-head.mjs), which only a drag of a head row and a new page write (writeHead), and every write
|
|
44
|
+
// of the tree keeps as it was (writeOutline).
|
|
41
45
|
// Written by the workspace's server (src/workbench/service.mjs: the workbench's moves and columns, a new,
|
|
42
46
|
// copied, restored or imported document, a new link, gallery new --under, gallery move and gallery link
|
|
43
47
|
// add while it runs, in the queue its saves go through), and by a gallery command when no server runs
|
|
@@ -137,6 +141,8 @@ const OLD_DOCS_NAMES = ["文档", "Documents"];
|
|
|
137
141
|
*/
|
|
138
142
|
export function storedOf(file) {
|
|
139
143
|
if (!file || typeof file !== "object" || Array.isArray(file)) return null;
|
|
144
|
+
// A file that holds the head's order alone (writeHead's, before any tree was written) holds no tree.
|
|
145
|
+
if (!Object.hasOwn(file, "children") && !Object.hasOwn(file, "groups")) return null;
|
|
140
146
|
const groups = [];
|
|
141
147
|
const children = {};
|
|
142
148
|
const take = (id, own) => {
|
|
@@ -367,11 +373,33 @@ export function fileOf(value) {
|
|
|
367
373
|
};
|
|
368
374
|
}
|
|
369
375
|
|
|
370
|
-
/**
|
|
376
|
+
/**
|
|
377
|
+
* Write outline `value` ({ groups?, children }) of workspace `root` (.gallery/ made when there is none yet),
|
|
378
|
+
* the head's order the file holds kept as it is (writeHead's).
|
|
379
|
+
*/
|
|
371
380
|
export async function writeOutline(root, value) {
|
|
372
381
|
const file = layoutOf(root).outline;
|
|
373
382
|
await fs.mkdir(path.dirname(file), { recursive: true });
|
|
374
|
-
|
|
383
|
+
const head = storedHead((await readJson(file))?.head);
|
|
384
|
+
return writeAtomic(file, `${JSON.stringify({ ...fileOf(value), ...(head ? { head } : {}) }, null, 2)}\n`);
|
|
385
|
+
}
|
|
386
|
+
|
|
387
|
+
/** The head's order as workspace `root`'s outline file keeps it (./sidebar-head.mjs storedHead), or null where it keeps none. */
|
|
388
|
+
export async function readStoredHead(root) {
|
|
389
|
+
return storedHead((await readJson(layoutOf(root).outline))?.head);
|
|
390
|
+
}
|
|
391
|
+
|
|
392
|
+
/**
|
|
393
|
+
* Write the head's order `head` (a stored head: ./sidebar-head.mjs) into workspace `root`'s outline file,
|
|
394
|
+
* all else it holds as it was (a file there is none of yet holds it alone, which reads as no tree:
|
|
395
|
+
* storedOf). Run under the outline's lock (withOutlineLock), as every write of the file is.
|
|
396
|
+
*/
|
|
397
|
+
export async function writeHead(root, head) {
|
|
398
|
+
const file = layoutOf(root).outline;
|
|
399
|
+
await fs.mkdir(path.dirname(file), { recursive: true });
|
|
400
|
+
const value = await readJson(file);
|
|
401
|
+
const kept = value && typeof value === "object" && !Array.isArray(value) ? value : {};
|
|
402
|
+
return writeAtomic(file, `${JSON.stringify({ ...kept, head: storedHead(head) ?? [] }, null, 2)}\n`);
|
|
375
403
|
}
|
|
376
404
|
|
|
377
405
|
/** The key `slug` sits under in `children` (a column's top key at a top level), or null when the outline holds it not. */
|
|
@@ -23,9 +23,20 @@ export const PACK_FILE = "pack.json";
|
|
|
23
23
|
/** What a pack's id, a scope, may be: as a block id's scope (shared/components/installed.mjs PACKAGE_ID). */
|
|
24
24
|
export const PACK_ID = /^[a-z0-9][a-z0-9-]*$/;
|
|
25
25
|
|
|
26
|
-
/**
|
|
26
|
+
/**
|
|
27
|
+
* The scope a block of the workspace's own is in (gallery block new local/<name>, or a <name> alone), which
|
|
28
|
+
* no pack installed takes: the default pack (默认块包, DEFAULT_PACK), where an Agent's block goes when it
|
|
29
|
+
* names no pack, so that a single block needs no pack of its own. It has no pack.json (none may name it):
|
|
30
|
+
* its name and words are these, and 设置 › 组件列表 lists it first, its blocks or none (shared/block-packs.mjs).
|
|
31
|
+
*/
|
|
27
32
|
export const OWN_SCOPE = "local";
|
|
28
33
|
|
|
34
|
+
/** What the default pack (OWN_SCOPE's) is called and says of itself, in both languages. */
|
|
35
|
+
export const DEFAULT_PACK = Object.freeze({
|
|
36
|
+
name: Object.freeze({ zh: "默认块包", en: "Default pack" }),
|
|
37
|
+
description: Object.freeze({ zh: "Agent 写自定义块时没有指定块包,块就放在这里。只写一个块,不用另建块包。", en: "Where an Agent's custom block goes when it names no pack: a single block needs no pack of its own." }),
|
|
38
|
+
});
|
|
39
|
+
|
|
29
40
|
const FIELDS = ["id", "name", "description", "version", "author", "homepage", "icon"];
|
|
30
41
|
const VERSION = /^\d+\.\d+\.\d+$/;
|
|
31
42
|
const isTable = (value) => typeof value === "object" && value !== null && !Array.isArray(value);
|