hd-garden 0.10.4 → 0.11.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/.agents/skills/garden-ui/SKILL.md +11 -10
- package/README.en.md +1 -1
- package/README.md +2 -2
- package/app/components/garden/GardenBlock.tsx +20 -4
- package/app/components/garden/blocks.tsx +6 -118
- package/app/globals.css +1 -0
- package/app/lib/garden-docs-meta.ts +3 -3
- package/app/lib/generated-content.ts +1 -1
- package/app/lib/i18n.ts +0 -6
- package/app/lib/remark-garden.mjs +61 -5
- package/app/styles/a2.css +25 -112
- package/app/styles/tokens.css +5 -0
- package/docs/handbook/ai-writing.md +3 -3
- package/docs/handbook/components/compose.md +354 -0
- package/docs/handbook/components/html.md +1 -1
- package/docs/handbook/components/image.md +1 -1
- package/docs/handbook/components/interactive.md +4 -1
- package/docs/handbook/components/link-card.md +1 -1
- package/docs/handbook/components.md +23 -35
- package/docs/handbook/design.md +25 -34
- package/docs/handbook/en/ai-writing.md +3 -3
- package/docs/handbook/en/components/compose.md +352 -0
- package/docs/handbook/en/components/html.md +1 -1
- package/docs/handbook/en/components/image.md +1 -1
- package/docs/handbook/en/components/interactive.md +4 -1
- package/docs/handbook/en/components.md +23 -36
- package/docs/handbook/en/design.md +25 -33
- package/docs/handbook/en/index.md +5 -5
- package/docs/handbook/en/reference/compose.md +99 -0
- package/docs/handbook/en/reference.md +2 -2
- package/docs/handbook/en/workflow.md +8 -6
- package/docs/handbook/index.md +5 -5
- package/docs/handbook/reference/compose.md +99 -0
- package/docs/handbook/reference.md +2 -2
- package/docs/handbook/workflow.md +8 -6
- package/editors/dist/typora/main.js +164 -136
- package/editors/dist/vscode/garden-ui-0.1.0.vsix +0 -0
- package/package.json +14 -2
- package/scripts/handbook-allowlist.mjs +0 -8
- package/scripts/handbook-facts.mjs +6 -36
- package/scripts/ui-cli.mjs +5 -1
- package/templates/garden-blocks.md +34 -31
- package/templates/garden-snippets.plist +3 -8
- package/templates/skills-en/garden-ui/SKILL.md +11 -10
- package/ui/README.md +1 -0
- package/ui/compose/compose.css +806 -0
- package/ui/compose/dil.mjs +443 -0
- package/ui/compose/examples.mjs +28 -0
- package/ui/compose/index.mjs +7 -0
- package/ui/compose/markup.mjs +364 -0
- package/ui/compose/parse.mjs +21 -0
- package/ui/compose/render.mjs +247 -0
- package/ui/core/cli-locale.mjs +4 -0
- package/ui/core/fence.mjs +13 -1
- package/ui/core/fix-prompt.mjs +1 -0
- package/ui/core/garden-fence.mjs +4 -1
- package/ui/core/scan.mjs +28 -2
- package/ui/core/transform.mjs +12 -0
- package/ui/core/validate.mjs +6 -4
- package/ui/garden/catalog.mjs +58 -35
- package/ui/garden/check.mjs +22 -6
- package/ui/garden/parse.mjs +26 -0
- package/ui/garden/snippets.mjs +15 -13
- package/ui/garden/word-count.mjs +10 -18
- package/ui/preview/dist/garden-ui.esm.js +158 -132
- package/ui/preview/dist/garden-ui.iife.js +157 -131
- package/ui/prompt/build.mjs +1 -0
- package/ui/prompt/recipes/compose.md +40 -0
- package/ui/prompt/rules.md +3 -3
- package/ui/react/CatalogPage.tsx +2 -2
- package/ui/react/runtime.tsx +5 -1
- package/docs/handbook/components/figure.md +0 -59
- package/docs/handbook/en/components/figure.md +0 -59
- package/docs/handbook/en/reference/figure.md +0 -84
- package/docs/handbook/reference/figure.md +0 -84
package/app/styles/a2.css
CHANGED
|
@@ -73,8 +73,7 @@ body {
|
|
|
73
73
|
.g-card,
|
|
74
74
|
.g-timeline,
|
|
75
75
|
.g-sandbox,
|
|
76
|
-
.g-html
|
|
77
|
-
.g-figure {
|
|
76
|
+
.g-html {
|
|
78
77
|
box-shadow: none;
|
|
79
78
|
}
|
|
80
79
|
|
|
@@ -289,6 +288,17 @@ body {
|
|
|
289
288
|
max-width: var(--col);
|
|
290
289
|
}
|
|
291
290
|
|
|
291
|
+
/* The compare post puts two wide diagrams side by side. */
|
|
292
|
+
@media (min-width: 1260px) {
|
|
293
|
+
.post-reading-page:has(.g-compose-pair) .article-reading-layout {
|
|
294
|
+
grid-template-columns: 24px minmax(0, 1fr) var(--rail);
|
|
295
|
+
}
|
|
296
|
+
|
|
297
|
+
.post-reading-page:has(.g-compose-pair) .article-reading-column {
|
|
298
|
+
max-width: none;
|
|
299
|
+
}
|
|
300
|
+
}
|
|
301
|
+
|
|
292
302
|
.post-reading-page .article-reading-layout > .toc {
|
|
293
303
|
grid-column: 3;
|
|
294
304
|
grid-row: 1;
|
|
@@ -785,6 +795,17 @@ html[data-theme="dark"] .markdown-body > p > img:not([class]) {
|
|
|
785
795
|
background: transparent;
|
|
786
796
|
}
|
|
787
797
|
|
|
798
|
+
.table-wrap td .markdown-image-trigger {
|
|
799
|
+
margin: 0;
|
|
800
|
+
}
|
|
801
|
+
|
|
802
|
+
.table-wrap td .markdown-image-trigger img {
|
|
803
|
+
width: 280px;
|
|
804
|
+
max-width: 100%;
|
|
805
|
+
height: auto;
|
|
806
|
+
border-radius: 6px;
|
|
807
|
+
}
|
|
808
|
+
|
|
788
809
|
@media (min-width: 900px) {
|
|
789
810
|
.ux-wide {
|
|
790
811
|
margin-left: calc(-1 * var(--wl, 0px)) !important;
|
|
@@ -885,8 +906,6 @@ html[data-theme="dark"] .markdown-body > p > img:not([class]) {
|
|
|
885
906
|
.g-cmp,
|
|
886
907
|
.g-timeline,
|
|
887
908
|
.g-chart,
|
|
888
|
-
.g-figure,
|
|
889
|
-
.g-explore,
|
|
890
909
|
.g-html,
|
|
891
910
|
.g-idea,
|
|
892
911
|
.g-legacy,
|
|
@@ -895,77 +914,9 @@ html[data-theme="dark"] .markdown-body > p > img:not([class]) {
|
|
|
895
914
|
box-shadow: none;
|
|
896
915
|
}
|
|
897
916
|
|
|
898
|
-
.g-explore {
|
|
899
|
-
border: 1px solid var(--rule);
|
|
900
|
-
border-radius: var(--r);
|
|
901
|
-
padding: 12px 14px 14px;
|
|
902
|
-
background: transparent;
|
|
903
|
-
max-width: 100%;
|
|
904
|
-
}
|
|
905
|
-
|
|
906
|
-
.g-explore [role="tablist"] {
|
|
907
|
-
display: flex;
|
|
908
|
-
flex-wrap: wrap;
|
|
909
|
-
gap: 6px;
|
|
910
|
-
margin: 0;
|
|
911
|
-
padding: 0;
|
|
912
|
-
}
|
|
913
|
-
|
|
914
|
-
.g-explore [role="tab"] {
|
|
915
|
-
font: 500 14px / 1 var(--sans);
|
|
916
|
-
padding: 9px 12px;
|
|
917
|
-
min-height: 44px;
|
|
918
|
-
border-radius: 999px;
|
|
919
|
-
border: 1px solid var(--rule);
|
|
920
|
-
background: transparent;
|
|
921
|
-
color: var(--soft);
|
|
922
|
-
cursor: pointer;
|
|
923
|
-
}
|
|
924
|
-
|
|
925
|
-
.g-explore [role="tab"][aria-selected="true"] {
|
|
926
|
-
border-color: var(--blue);
|
|
927
|
-
color: var(--blue);
|
|
928
|
-
background: var(--blue-tint);
|
|
929
|
-
}
|
|
930
|
-
|
|
931
|
-
.dx-wrap {
|
|
932
|
-
overflow: visible;
|
|
933
|
-
margin-top: 10px;
|
|
934
|
-
max-width: 100%;
|
|
935
|
-
}
|
|
936
|
-
|
|
937
|
-
.dx-wrap svg {
|
|
938
|
-
display: block;
|
|
939
|
-
width: 100%;
|
|
940
|
-
max-width: 100%;
|
|
941
|
-
height: auto;
|
|
942
|
-
}
|
|
943
|
-
|
|
944
|
-
.g-explore:not([data-sel="all"]) .dx-wrap [data-p]:not(.on),
|
|
945
|
-
.g-explore:not([data-sel="all"]) .dx-wrap text:not(.on) {
|
|
946
|
-
opacity: 0.22;
|
|
947
|
-
}
|
|
948
|
-
|
|
949
|
-
.g-explore .on {
|
|
950
|
-
opacity: 1;
|
|
951
|
-
}
|
|
952
|
-
|
|
953
|
-
.dx-exp p {
|
|
954
|
-
margin: 10px 0 0;
|
|
955
|
-
}
|
|
956
|
-
|
|
957
|
-
.g-explore figcaption {
|
|
958
|
-
font-size: 13px;
|
|
959
|
-
color: var(--muted);
|
|
960
|
-
margin-top: 8px;
|
|
961
|
-
text-align: left;
|
|
962
|
-
}
|
|
963
|
-
|
|
964
917
|
.g-sandbox,
|
|
965
918
|
.g-play,
|
|
966
|
-
.g-html
|
|
967
|
-
.g-explore,
|
|
968
|
-
.dx-wrap {
|
|
919
|
+
.g-html {
|
|
969
920
|
max-width: 100%;
|
|
970
921
|
}
|
|
971
922
|
|
|
@@ -973,7 +924,6 @@ html[data-theme="dark"] .markdown-body > p > img:not([class]) {
|
|
|
973
924
|
.g-stat,
|
|
974
925
|
.g-cmp,
|
|
975
926
|
.g-timeline,
|
|
976
|
-
.g-figure,
|
|
977
927
|
.g-html {
|
|
978
928
|
border: 1px solid var(--rule);
|
|
979
929
|
border-radius: var(--r);
|
|
@@ -982,8 +932,7 @@ html[data-theme="dark"] .markdown-body > p > img:not([class]) {
|
|
|
982
932
|
|
|
983
933
|
.g-card,
|
|
984
934
|
.g-cmp,
|
|
985
|
-
.g-html
|
|
986
|
-
.g-figure {
|
|
935
|
+
.g-html {
|
|
987
936
|
padding: 14px 16px;
|
|
988
937
|
}
|
|
989
938
|
|
|
@@ -1163,7 +1112,6 @@ html[data-theme="dark"] .markdown-body > p > img:not([class]) {
|
|
|
1163
1112
|
min-width: 3px;
|
|
1164
1113
|
}
|
|
1165
1114
|
|
|
1166
|
-
.g-figure svg,
|
|
1167
1115
|
.g-mermaid svg,
|
|
1168
1116
|
.dx-svg {
|
|
1169
1117
|
display: block;
|
|
@@ -1172,16 +1120,6 @@ html[data-theme="dark"] .markdown-body > p > img:not([class]) {
|
|
|
1172
1120
|
height: auto;
|
|
1173
1121
|
}
|
|
1174
1122
|
|
|
1175
|
-
.g-figure:not([data-sel="all"]) [data-p]:not(.on),
|
|
1176
|
-
.g-figure:not([data-sel="all"]) text:not(.on) {
|
|
1177
|
-
opacity: 0.22;
|
|
1178
|
-
}
|
|
1179
|
-
|
|
1180
|
-
.g-figure [data-p].on,
|
|
1181
|
-
.g-figure text.on {
|
|
1182
|
-
opacity: 1;
|
|
1183
|
-
}
|
|
1184
|
-
|
|
1185
1123
|
.g-mermaid {
|
|
1186
1124
|
margin: 28px 0;
|
|
1187
1125
|
padding: 16px;
|
|
@@ -1399,19 +1337,10 @@ html[data-theme="dark"] .markdown-body > p > img:not([class]) {
|
|
|
1399
1337
|
padding-right: 44px;
|
|
1400
1338
|
}
|
|
1401
1339
|
|
|
1402
|
-
.ux-fs:not(.g-sandbox) > .ux-fsbar + .g-explore {
|
|
1403
|
-
padding-right: 14px;
|
|
1404
|
-
}
|
|
1405
|
-
|
|
1406
1340
|
.ux-fs:not(.g-sandbox) > .ux-fsbar + .g-sandbox {
|
|
1407
1341
|
padding-right: 0;
|
|
1408
1342
|
}
|
|
1409
1343
|
|
|
1410
|
-
.ux-fs:not(.g-sandbox) > .ux-fsbar + .g-explore > [role="tablist"] {
|
|
1411
|
-
padding-right: 44px;
|
|
1412
|
-
box-sizing: border-box;
|
|
1413
|
-
}
|
|
1414
|
-
|
|
1415
1344
|
.ux-fs:fullscreen,
|
|
1416
1345
|
.ux-fs.ux-fs-on {
|
|
1417
1346
|
background: var(--paper);
|
|
@@ -1793,13 +1722,6 @@ html[data-theme="dark"] .gf-scrim { background: rgb(0 0 0 / 45%); }
|
|
|
1793
1722
|
font-family: var(--sans);
|
|
1794
1723
|
}
|
|
1795
1724
|
|
|
1796
|
-
.garden-doc-page .g-explore:not([data-sel="all"]) .dx-wrap [data-p]:not(.on),
|
|
1797
|
-
.garden-doc-page .g-explore:not([data-sel="all"]) .dx-wrap text:not(.on),
|
|
1798
|
-
.garden-doc-page .g-figure:not([data-sel="all"]) [data-p]:not(.on),
|
|
1799
|
-
.garden-doc-page .g-figure:not([data-sel="all"]) text:not(.on) {
|
|
1800
|
-
opacity: 0.56;
|
|
1801
|
-
}
|
|
1802
|
-
|
|
1803
1725
|
.garden-doc-page > .toc {
|
|
1804
1726
|
margin-top: 8px;
|
|
1805
1727
|
position: sticky;
|
|
@@ -2641,15 +2563,6 @@ html[data-theme="dark"] .ref-demo { --rd-s: #262624; --rd-p: #1f1e1d; --rd-i: #e
|
|
|
2641
2563
|
.ref-demo-in .toc-mobile-trigger { opacity: 0; visibility: hidden; pointer-events: none; }
|
|
2642
2564
|
}
|
|
2643
2565
|
|
|
2644
|
-
/* figure reference page: the drawing needs room, so the example stacks
|
|
2645
|
-
(preview on top, full width; code below). Scoped to the reference demo;
|
|
2646
|
-
figures in articles are untouched. */
|
|
2647
|
-
@media (min-width: 1024px) {
|
|
2648
|
-
.ref-demo[data-name="figure"] { grid-template-columns: minmax(0, 1fr); background: var(--rd-p); }
|
|
2649
|
-
.ref-demo[data-name="figure"] .ref-pane[data-p="v"] { grid-column: 1; grid-row: 1; }
|
|
2650
|
-
.ref-demo[data-name="figure"] .ref-pane[data-p="c"] { grid-column: 1; grid-row: 2; background: var(--rd-s); border-top: 1px solid var(--rd-r); }
|
|
2651
|
-
}
|
|
2652
|
-
|
|
2653
2566
|
/* ===== v0.10.1 tip keep (after git checkout of a2.css from 9a80f7e5) ===== */
|
|
2654
2567
|
|
|
2655
2568
|
/* List pages: PageIntro rides on .sh-head; keep eyebrow in the same vertical rhythm. */
|
package/app/styles/tokens.css
CHANGED
|
@@ -33,6 +33,9 @@
|
|
|
33
33
|
--accent-soft: var(--blue-tint);
|
|
34
34
|
--selection: #e8e5db;
|
|
35
35
|
--hl: #ffe58f;
|
|
36
|
+
/* Two lane-arrow emphases. Same hues as the note and tip callouts, not a second palette. */
|
|
37
|
+
--flow: #2c55b4;
|
|
38
|
+
--flow-back: #2d6a3e;
|
|
36
39
|
--red: #d82d48;
|
|
37
40
|
--red-text: #c2263f;
|
|
38
41
|
--red-tint: #fbeef0;
|
|
@@ -94,6 +97,8 @@ html[data-theme="dark"] {
|
|
|
94
97
|
--accent-soft: var(--blue-tint);
|
|
95
98
|
--selection: rgb(238 236 231 / 18%);
|
|
96
99
|
--hl: #5e4e17;
|
|
100
|
+
--flow: #93b2f4;
|
|
101
|
+
--flow-back: #8fcb9f;
|
|
97
102
|
--red: #f29aab;
|
|
98
103
|
--red-text: #f29aab;
|
|
99
104
|
--red-tint: rgb(242 154 171 / 12%);
|
|
@@ -21,7 +21,7 @@ order: 2
|
|
|
21
21
|
```
|
|
22
22
|
````
|
|
23
23
|
|
|
24
|
-
草稿(`draft: true`)里可以保留未编译的想法;非草稿文章里还有未编译的想法时,`npx garden ui check` 和 `npx garden check` 都会报 `garden-idea` 错误。Agent 会根据内容把想法编译成 `garden
|
|
24
|
+
草稿(`draft: true`)里可以保留未编译的想法;非草稿文章里还有未编译的想法时,`npx garden ui check` 和 `npx garden check` 都会报 `garden-idea` 错误。Agent 会根据内容把想法编译成 `garden compose`、`card`、`stat`、`compare` 等内置组件,或者在一段话就能说清时直接写回普通段落。
|
|
25
25
|
|
|
26
26
|
## 2. 随包安装的三个 skill
|
|
27
27
|
|
|
@@ -112,8 +112,8 @@ npx garden editors install --typora
|
|
|
112
112
|
|
|
113
113
|
不借助 AI 手写组件时,可以直接使用包内自带的模板与代码片段:
|
|
114
114
|
|
|
115
|
-
- `make new` 创建的草稿底部自带一段 `<!-- 组件速查 ... -->`
|
|
116
|
-
- `templates/garden-blocks.md`
|
|
115
|
+
- `make new` 创建的草稿底部自带一段 `<!-- 组件速查 ... -->` 注释,包含想法块和各个组件的示例,写完可直接删掉。
|
|
116
|
+
- `templates/garden-blocks.md` 汇总了想法块与各个组件的适用场景(`when` / `whenNot`)和可复制示例;macOS 与 Typora / Alfred 用户可导入 `templates/garden-snippets.plist`,输入 `;gidea`(或 `;garden想法`)、`;gcard`、`;gstat`、`;gcompare`、`;gtimeline`、`;gchart`、`;gcompose`、`;ghtml`、`;ginteractive`、`;gfile`、`;grel`、`;glist`、`;gchoice` 即可展开对应围栏。`;gcompose` 展开的是带一句白话的 `garden compose`。
|
|
117
117
|
- 编辑器插件的用法见上一节。`npx garden ui catalog` 在本地生成 `.garden/ui-catalog.html` 离线组件画廊。
|
|
118
118
|
|
|
119
119
|
## 8. 可选的独立管理后台
|
|
@@ -0,0 +1,354 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: 说明图(compose)
|
|
3
|
+
navTitle: 说明图
|
|
4
|
+
description: 在文章里写几句白话,让 AI 拼出静态说明图。
|
|
5
|
+
section: components
|
|
6
|
+
order: 36
|
|
7
|
+
badge: compose
|
|
8
|
+
---
|
|
9
|
+
|
|
10
|
+
写文章想画一张结构图时,输入 `/garden` 选「compose(想法)」。文章里会插入一个 `garden compose` 围栏。你在里面用白话写清结构,再对 AI 说「编译这篇」,AI 就会把这句话留在 `<intent>` 里,并用 Markdown 叶子和组件标签拼出静态说明图。
|
|
11
|
+
|
|
12
|
+
## 怎么写
|
|
13
|
+
|
|
14
|
+
围栏里只写你想让读者看见的结构,不要写样式。
|
|
15
|
+
|
|
16
|
+
把四件事写清楚:
|
|
17
|
+
|
|
18
|
+
- **分几块**:是三列并排、从上到下五层,还是上下两行。
|
|
19
|
+
- **每块叫什么**:用图上要摆出来的短词。解释放在名字下面那一行,别把一整句话当标题。
|
|
20
|
+
- **谁连谁**:谁先到谁、从一处散开,还是几处收到一起。没有先后顺序,就直接写「这几块没有先后」。
|
|
21
|
+
- **哪块是重点**:直接点名,比如「中间那列是重点」「下面一行才是重点」。
|
|
22
|
+
|
|
23
|
+
不要写颜色、圆角、灰胶囊、字重、间距、阴影、要不要撑满。外观由组件默认样式决定,写了反而乱。全部标签见 [组件参考 · compose](/garden/reference/compose)。
|
|
24
|
+
|
|
25
|
+
## 最佳实践
|
|
26
|
+
|
|
27
|
+
写围栏时,最常见的失误有两个:一是只写一个主题词,没给结构;二是把精力花在规定颜色、圆角和字重上。下面按五种常见结构,列出改写前后的写法。
|
|
28
|
+
|
|
29
|
+
**三列并排,中间接起来**
|
|
30
|
+
|
|
31
|
+
只写「画一张权限图」,AI 不知道分几列、每列放什么;写成「三列等宽,中间用浅灰圆角,字重轻一点」,又全在规定外观。
|
|
32
|
+
|
|
33
|
+
把三列的名字、每列底下的条目和中间的连接写出来:
|
|
34
|
+
|
|
35
|
+
````markdown
|
|
36
|
+
```garden compose
|
|
37
|
+
三列:User 下面是 Alice、Bob;Role 下面是管理员、审核员;
|
|
38
|
+
Permission 下面是 orders:read、orders:approve。
|
|
39
|
+
Role 在中间,把用户和权限接起来。Role 是重点。
|
|
40
|
+
```
|
|
41
|
+
````
|
|
42
|
+
|
|
43
|
+
**先到一处,再散开**
|
|
44
|
+
|
|
45
|
+
不要写「画个单点登录,箭头好看一点,间距均匀」。把谁先连向哪里、再同时分给哪几个系统写清楚:
|
|
46
|
+
|
|
47
|
+
````markdown
|
|
48
|
+
```garden compose
|
|
49
|
+
用户浏览器先到身份提供方,再同时连到 HR、Finance、Project 三个系统。
|
|
50
|
+
三个系统都信任同一个身份提供方。身份提供方是重点。
|
|
51
|
+
```
|
|
52
|
+
````
|
|
53
|
+
|
|
54
|
+
**自上而下分层**
|
|
55
|
+
|
|
56
|
+
不要写「五张通栏卡片,第二张和第五张上色,箭头画细」。直接列出五层的名字、哪两层需要突出,以及是不是每次请求都按顺序走完:
|
|
57
|
+
|
|
58
|
+
````markdown
|
|
59
|
+
```garden compose
|
|
60
|
+
从上到下五层:浏览器、身份服务、BFF、业务服务、授权决策。
|
|
61
|
+
身份服务和授权决策是重点,其余是经过的路径。
|
|
62
|
+
不是每次请求都按这个顺序走完。
|
|
63
|
+
```
|
|
64
|
+
````
|
|
65
|
+
|
|
66
|
+
**一件事的多个切面**
|
|
67
|
+
|
|
68
|
+
不要写「两行两列加下面两张卡片,标题不要加粗」。把六个切面的短名、每块要回答的问题,以及「没有先后顺序」交代清楚:
|
|
69
|
+
|
|
70
|
+
````markdown
|
|
71
|
+
```garden compose
|
|
72
|
+
用户发起请求后,先看四件事:认证(你是谁)、凭证(怎么证明)、
|
|
73
|
+
授权(有没有权)、验证(数据合不合法)。
|
|
74
|
+
落到业务和存储时,再看传输和保密。这六块没有严格的先后。
|
|
75
|
+
```
|
|
76
|
+
````
|
|
77
|
+
|
|
78
|
+
**上下两行对比**
|
|
79
|
+
|
|
80
|
+
不要写「上面无框,下面灰色胶囊,贴着内容,不要撑满」。直接写哪一行是常规背景、哪一行是真正要强调的循环:
|
|
81
|
+
|
|
82
|
+
````markdown
|
|
83
|
+
```garden compose
|
|
84
|
+
上面一行是常规交付:理解需求 → 设计方案 → 开发上线。
|
|
85
|
+
下面一行是探索循环:提出假设 → 低成本验证 → 迭代或放弃。
|
|
86
|
+
上面是背景,下面一行才是重点。
|
|
87
|
+
```
|
|
88
|
+
````
|
|
89
|
+
|
|
90
|
+
## 能力示例
|
|
91
|
+
|
|
92
|
+
**下面这些图只是示例**,用来展示 `compose` 能拼出哪几类常见结构。图里的权限、登录、API 等词只是为了把格子填满,写文章时换成你自己的主题即可。
|
|
93
|
+
|
|
94
|
+
### 三列中间接
|
|
95
|
+
|
|
96
|
+
左右两列靠中间一列连起来,底下用 `<join>` 收成一句话。
|
|
97
|
+
|
|
98
|
+
```garden compose
|
|
99
|
+
<intent>
|
|
100
|
+
三列:User 下面是 Alice 和 Bob,Role 下面是管理员和审核员,Permission 下面是 orders:read 和 orders:approve。Role 在中间,把用户和权限接起来。Role 是要先看见的一层。
|
|
101
|
+
</intent>
|
|
102
|
+
<row align="center">
|
|
103
|
+
<stack align="center">
|
|
104
|
+
<title>User</title>
|
|
105
|
+
<text>Alice</text>
|
|
106
|
+
<text>Bob</text>
|
|
107
|
+
</stack>
|
|
108
|
+
<band tone="accent" align="center">
|
|
109
|
+
<title>Role</title>
|
|
110
|
+
<text>管理员</text>
|
|
111
|
+
<text>审核员</text>
|
|
112
|
+
</band>
|
|
113
|
+
<stack align="center">
|
|
114
|
+
<title>Permission</title>
|
|
115
|
+
<text>orders:read</text>
|
|
116
|
+
<text>orders:approve</text>
|
|
117
|
+
</stack>
|
|
118
|
+
</row>
|
|
119
|
+
<join>角色连接用户和权限</join>
|
|
120
|
+
<text tone="muted" align="center">概念关系:User ↔ Role ↔ Permission</text>
|
|
121
|
+
```
|
|
122
|
+
|
|
123
|
+
### 先汇再散
|
|
124
|
+
|
|
125
|
+
先流向中间那一层,再用 `<fan>` 同时分到下面几列。
|
|
126
|
+
|
|
127
|
+
```garden compose
|
|
128
|
+
<intent>
|
|
129
|
+
用户浏览器先到身份提供方。身份提供方再同时连到 HR、Finance、Project。三个系统信任同一个身份提供方。身份提供方是要先看见的一层。
|
|
130
|
+
</intent>
|
|
131
|
+
<stack align="center">
|
|
132
|
+
<pill>用户浏览器</pill>
|
|
133
|
+
<arrow dir="down"/>
|
|
134
|
+
<band tone="accent" align="center">
|
|
135
|
+
<title>Identity Provider(IdP)</title>
|
|
136
|
+
<text>统一完成身份验证、维护登录状态、签发身份断言</text>
|
|
137
|
+
</band>
|
|
138
|
+
<fan n="3"/>
|
|
139
|
+
<row align="center">
|
|
140
|
+
<title>HR 系统</title>
|
|
141
|
+
<title>Finance 系统</title>
|
|
142
|
+
<title>Project 系统</title>
|
|
143
|
+
</row>
|
|
144
|
+
<text tone="muted" align="center">三个系统都信任同一个身份提供方</text>
|
|
145
|
+
</stack>
|
|
146
|
+
```
|
|
147
|
+
|
|
148
|
+
### 自上而下分层
|
|
149
|
+
|
|
150
|
+
几层按顺序往下走,重点层用 `<band>`,经过的层只留文字。
|
|
151
|
+
|
|
152
|
+
```garden compose
|
|
153
|
+
<intent>
|
|
154
|
+
从上到下五层:浏览器、身份服务、BFF、业务服务、授权决策。身份服务和授权决策是要强调的两层,其余是经过的路径。不是每次请求都按这个顺序走完。
|
|
155
|
+
</intent>
|
|
156
|
+
<stack align="center">
|
|
157
|
+
<box frame="text" align="center">
|
|
158
|
+
<badge>①</badge>
|
|
159
|
+
<title>浏览器 / App</title>
|
|
160
|
+
<text>Cookie、Session、OAuth Client</text>
|
|
161
|
+
</box>
|
|
162
|
+
<arrow dir="down"/>
|
|
163
|
+
<band tone="accent" align="center">
|
|
164
|
+
<badge>②</badge>
|
|
165
|
+
<title>身份服务 IdP / IAM</title>
|
|
166
|
+
<text>Passkey、MFA、OIDC、会话管理</text>
|
|
167
|
+
</band>
|
|
168
|
+
<arrow dir="down"/>
|
|
169
|
+
<box frame="text" align="center">
|
|
170
|
+
<badge>③</badge>
|
|
171
|
+
<title>BFF / API Gateway</title>
|
|
172
|
+
<text>会话验证、Token 校验、入口授权控制</text>
|
|
173
|
+
</box>
|
|
174
|
+
<arrow dir="down"/>
|
|
175
|
+
<box frame="text" align="center">
|
|
176
|
+
<badge>④</badge>
|
|
177
|
+
<title>业务服务</title>
|
|
178
|
+
<text>订单、支付、账户、资源对象</text>
|
|
179
|
+
</box>
|
|
180
|
+
<arrow dir="down"/>
|
|
181
|
+
<band tone="tip" align="center">
|
|
182
|
+
<badge>⑤</badge>
|
|
183
|
+
<title>授权决策系统</title>
|
|
184
|
+
<text>RBAC + ABAC + ReBAC + Policy Engine</text>
|
|
185
|
+
</band>
|
|
186
|
+
<text tone="muted" align="start">逻辑职责示意:并非所有请求都按此顺序经过各层。身份服务通常在登录阶段交互,业务服务则在请求执行时调用授权决策能力。</text>
|
|
187
|
+
</stack>
|
|
188
|
+
```
|
|
189
|
+
|
|
190
|
+
### 一件事的多个切面
|
|
191
|
+
|
|
192
|
+
没有严格先后的几块内容,用 `<row>` 和 `<box>` 分成上下两组并排摆开。
|
|
193
|
+
|
|
194
|
+
```garden compose
|
|
195
|
+
<intent>
|
|
196
|
+
用户要改订单地址。先分成认证、凭证、授权、验证,每块一个问题。然后再看传输和保密。这六块不是严格的先后步骤。
|
|
197
|
+
</intent>
|
|
198
|
+
<stack align="center">
|
|
199
|
+
<title>用户发起 API 请求</title>
|
|
200
|
+
<text tone="muted">例如:修改订单收货地址</text>
|
|
201
|
+
</stack>
|
|
202
|
+
<arrow dir="down"/>
|
|
203
|
+
<row>
|
|
204
|
+
<box>
|
|
205
|
+
<title>认证</title>
|
|
206
|
+
<text>你是谁?</text>
|
|
207
|
+
<text tone="muted">Authentication</text>
|
|
208
|
+
</box>
|
|
209
|
+
<box>
|
|
210
|
+
<title>凭证</title>
|
|
211
|
+
<text>如何证明你的身份?</text>
|
|
212
|
+
<text tone="muted">Credential</text>
|
|
213
|
+
</box>
|
|
214
|
+
</row>
|
|
215
|
+
<row>
|
|
216
|
+
<box>
|
|
217
|
+
<title>授权</title>
|
|
218
|
+
<text>你有权修改这笔订单吗?</text>
|
|
219
|
+
<text tone="muted">Authorization</text>
|
|
220
|
+
</box>
|
|
221
|
+
<box>
|
|
222
|
+
<title>验证</title>
|
|
223
|
+
<text>提交的数据是否合法?</text>
|
|
224
|
+
<text tone="muted">Verification</text>
|
|
225
|
+
</box>
|
|
226
|
+
</row>
|
|
227
|
+
<arrow dir="down"/>
|
|
228
|
+
<stack align="center">
|
|
229
|
+
<title>业务操作与数据存储</title>
|
|
230
|
+
</stack>
|
|
231
|
+
<row>
|
|
232
|
+
<box>
|
|
233
|
+
<title>传输</title>
|
|
234
|
+
<text>网络中能否被窃听、篡改、冒充?</text>
|
|
235
|
+
</box>
|
|
236
|
+
<box>
|
|
237
|
+
<title>保密</title>
|
|
238
|
+
<text>敏感数据泄露后能否被读取?</text>
|
|
239
|
+
</box>
|
|
240
|
+
</row>
|
|
241
|
+
<text tone="muted">概念示意:六者并不是严格串行的执行阶段,传输保护贯穿网络通信,保密措施也可能覆盖客户端与服务端。</text>
|
|
242
|
+
```
|
|
243
|
+
|
|
244
|
+
### 外框套子项
|
|
245
|
+
|
|
246
|
+
大框里再摆一排徽章或两列要点,适合画「一层里面包含几条检查」。
|
|
247
|
+
|
|
248
|
+
```garden compose
|
|
249
|
+
<intent>
|
|
250
|
+
用户意图经过 Agent,再经过策略执行点,最后到工具执行器。策略点里是四条约束。策略点是要先看见的一层。
|
|
251
|
+
</intent>
|
|
252
|
+
<stack align="center">
|
|
253
|
+
<title>User Intent + Authorization</title>
|
|
254
|
+
<text tone="muted">明确任务目标、用户身份与授权范围</text>
|
|
255
|
+
<arrow dir="down"/>
|
|
256
|
+
<band align="center">
|
|
257
|
+
<title>Agent / LLM</title>
|
|
258
|
+
<text>负责理解、推理、规划和提出执行意图</text>
|
|
259
|
+
<row align="center">
|
|
260
|
+
<badge>Untrusted Context</badge>
|
|
261
|
+
<badge>Memory</badge>
|
|
262
|
+
<badge>Tool Results</badge>
|
|
263
|
+
</row>
|
|
264
|
+
</band>
|
|
265
|
+
<arrow dir="down"/>
|
|
266
|
+
<box align="center" mark="shield">
|
|
267
|
+
<title>Policy Enforcement Point</title>
|
|
268
|
+
<text tone="muted" align="center">独立于 LLM 的确定性执行控制</text>
|
|
269
|
+
<row align="center">
|
|
270
|
+
<text>权限与资源范围</text>
|
|
271
|
+
<text>操作参数校验</text>
|
|
272
|
+
</row>
|
|
273
|
+
<row align="center">
|
|
274
|
+
<text>任务意图约束</text>
|
|
275
|
+
<text>高风险操作审批</text>
|
|
276
|
+
</row>
|
|
277
|
+
</box>
|
|
278
|
+
<arrow dir="down"/>
|
|
279
|
+
<title>Tool Executor</title>
|
|
280
|
+
<text tone="muted">按最小权限执行、记录审计、支持中断</text>
|
|
281
|
+
</stack>
|
|
282
|
+
```
|
|
283
|
+
|
|
284
|
+
### 多角色来回交互
|
|
285
|
+
|
|
286
|
+
几个角色按先后发消息、退回结果时,用 `<lanes>` 画成泳道。
|
|
287
|
+
|
|
288
|
+
```garden compose
|
|
289
|
+
<intent>
|
|
290
|
+
用户、客户端、授权服务器三条泳道,六步授权码加 PKCE。
|
|
291
|
+
</intent>
|
|
292
|
+
<lanes>
|
|
293
|
+
<actor>用户</actor>
|
|
294
|
+
<actor>客户端</actor>
|
|
295
|
+
<actor>授权服务器</actor>
|
|
296
|
+
<message from="1" to="2" tone="forward">点击登录 / 授权</message>
|
|
297
|
+
<message from="2" to="3" tone="forward">发起授权请求 + PKCE</message>
|
|
298
|
+
<message from="3" to="1" tone="back">用户身份验证与授权</message>
|
|
299
|
+
<message from="3" to="2" tone="back">重定向返回 Code</message>
|
|
300
|
+
<message from="2" to="3" tone="forward">Code + Verifier 换 Token</message>
|
|
301
|
+
<message from="3" to="2" tone="back">返回 Token</message>
|
|
302
|
+
</lanes>
|
|
303
|
+
<text tone="muted">简化示意:真实流程还包含浏览器跳转、回调绑定、授权码及令牌校验等细节。</text>
|
|
304
|
+
```
|
|
305
|
+
|
|
306
|
+
### 两行流程对比
|
|
307
|
+
|
|
308
|
+
上面一行放常规做法当背景,中间加 `<divider/>`,下面一行用胶囊突出真正想讲的循环。
|
|
309
|
+
|
|
310
|
+
```garden compose
|
|
311
|
+
<intent>
|
|
312
|
+
上面一行是交付顺序:理解需求、设计方案、开发上线。下面一行才是要强调的决策循环:提出假设、低成本验证、迭代或放弃。上面是背景,下面是重点。
|
|
313
|
+
</intent>
|
|
314
|
+
<row align="center">
|
|
315
|
+
<title align="center">理解需求</title>
|
|
316
|
+
<arrow dir="right"/>
|
|
317
|
+
<title align="center">设计方案</title>
|
|
318
|
+
<arrow dir="right"/>
|
|
319
|
+
<title align="center">开发上线</title>
|
|
320
|
+
</row>
|
|
321
|
+
<divider/>
|
|
322
|
+
<row align="center">
|
|
323
|
+
<pill tone="muted">提出假设</pill>
|
|
324
|
+
<arrow dir="right"/>
|
|
325
|
+
<pill tone="muted">低成本验证</pill>
|
|
326
|
+
<arrow dir="right"/>
|
|
327
|
+
<pill tone="muted">迭代或放弃</pill>
|
|
328
|
+
</row>
|
|
329
|
+
<text tone="muted">第二行才是产品探索更强调的决策循环。</text>
|
|
330
|
+
```
|
|
331
|
+
|
|
332
|
+
## 可调参数(play)
|
|
333
|
+
|
|
334
|
+
静态说明图还差一步、读者要拧参数时,仍写 `garden compose`,在围栏里用同一套 DIL 写法:
|
|
335
|
+
|
|
336
|
+
- `{@body const [n, setN] = DIL.useState(3)}` 声明状态
|
|
337
|
+
- `{@body const total = n * 24}` 派生值
|
|
338
|
+
- `{total}` / `value={n}` 插值
|
|
339
|
+
- `{#if …}{:else}{/if}`、`{#each … as item, i}{/each}` 控制流
|
|
340
|
+
- 小写控件:`<slider>`、`<choice>`、`<button>`、`<pie>` / `<chart>`、`<stat>`
|
|
341
|
+
|
|
342
|
+
旧的 `garden interactive` 与 PascalCase `<State>` / `<Slider>` 仅作兼容,新文章不要再写。完整映射见仓库 `docs/compose-dil.md`。
|
|
343
|
+
|
|
344
|
+
```garden compose #compose-play-demo
|
|
345
|
+
caption: 拧一下席位,看月费。
|
|
346
|
+
intent: |
|
|
347
|
+
让读者调席位,看月费怎么变。
|
|
348
|
+
---
|
|
349
|
+
{@body const [seats, setSeats] = DIL.useState(3)}
|
|
350
|
+
{@body const total = seats * 24}
|
|
351
|
+
<slider min={1} max={12} value={seats} onChange={setSeats} label="席位" />
|
|
352
|
+
<stat label="月费" value={total} unit="USD" />
|
|
353
|
+
```
|
|
354
|
+
|
|
@@ -34,7 +34,7 @@ code: |
|
|
|
34
34
|
```
|
|
35
35
|
|
|
36
36
|
- **什么时候用**:内置组件画不出来的画布动画、物理模拟或独立小工具。
|
|
37
|
-
- **什么时候不用**:只需要拖动滑杆算公式时用[可调公式与参数](/garden/components/interactive)
|
|
37
|
+
- **什么时候不用**:只需要拖动滑杆算公式时用[可调公式与参数](/garden/components/interactive);说明图用 [compose](/garden/components/compose)。
|
|
38
38
|
|
|
39
39
|
可以这样对 AI 说:
|
|
40
40
|
|
|
@@ -9,7 +9,7 @@ order: 45
|
|
|
9
9
|
图片单独成段时会包进图框,并在下方显示图注。
|
|
10
10
|
|
|
11
11
|
- **什么时候用**:这张图属于文章,读者需要看到图下说明。
|
|
12
|
-
- **什么时候不用**:只是装饰时,把 `alt` 写成以 `image`、`截图` 或 `img`
|
|
12
|
+
- **什么时候不用**:只是装饰时,把 `alt` 写成以 `image`、`截图` 或 `img` 开头的占位词,这样不会出现图注。要按部分点开说明时用[说明图](/garden/components/compose);要提供下载时用[文件下载与预览](/garden/components/file)。
|
|
13
13
|
|
|
14
14
|
长文 `content/posts/my-post.md` 的配图放在同名目录 `content/posts/my-post/`。正文用 Markdown 图片语法引用,地址写成 `./my-post/diagram.svg`,方括号里的 `alt` 写成图注。
|
|
15
15
|
|
|
@@ -7,7 +7,10 @@ order: 38
|
|
|
7
7
|
badge: interactive
|
|
8
8
|
---
|
|
9
9
|
|
|
10
|
-
|
|
10
|
+
> **已废弃。** 新文章请写 [`compose`](/garden/components/compose),用 ChatGPT 同款 DIL(`{@body}` / `{expr}` / `{#if}` / `{#each}` 与小写标签)。旧的 `garden interactive` 围栏仍会当作 compose play 解析以兼容,之后会像 `figure` 一样删掉。
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
```garden compose #reading-time
|
|
11
14
|
caption: 示例:按字数、阅读速度和配图数估算一篇文章的阅读时间。数字只用来演示组件,不是统计结果。
|
|
12
15
|
---
|
|
13
16
|
<State words={6000} speed={400} images={8} />
|