hd-garden 0.3.13 → 0.4.1

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.
Files changed (60) hide show
  1. package/.agents/skills/garden-interactive-chart/SKILL.md +6 -6
  2. package/.agents/skills/garden-ui/SKILL.md +4 -4
  3. package/app/a2/[slug]/page.tsx +61 -0
  4. package/app/a2/page.tsx +27 -0
  5. package/app/blog/[...path]/page.tsx +32 -22
  6. package/app/blog/page.tsx +6 -7
  7. package/app/columns/[column]/[...path]/page.tsx +32 -25
  8. package/app/columns/page.tsx +38 -52
  9. package/app/components/ArticleMeasure.tsx +95 -0
  10. package/app/components/ArticleTitle.tsx +20 -0
  11. package/app/components/BlogArchive.tsx +106 -102
  12. package/app/components/MarkdownArticle.tsx +145 -66
  13. package/app/components/MermaidDiagram.tsx +44 -71
  14. package/app/components/SiteFooter.tsx +3 -7
  15. package/app/components/SiteHeader.tsx +55 -41
  16. package/app/components/TableOfContents.tsx +3 -2
  17. package/app/components/TagIndex.tsx +97 -0
  18. package/app/components/garden/GardenBlock.tsx +45 -0
  19. package/app/components/garden/blocks.tsx +530 -0
  20. package/app/components/garden/chrome.tsx +350 -0
  21. package/app/components/garden/sandbox-message.ts +16 -0
  22. package/app/garden-modules.d.ts +2 -0
  23. package/app/globals.css +17 -12
  24. package/app/layout.tsx +9 -0
  25. package/app/lib/a2-meta.ts +22 -0
  26. package/app/lib/a2-preview.ts +50 -0
  27. package/app/lib/content.ts +52 -6
  28. package/app/lib/markdown-plugins.ts +2 -0
  29. package/app/lib/remark-a2.mjs +208 -0
  30. package/app/lib/remark-garden.mjs +88 -0
  31. package/app/page.tsx +122 -93
  32. package/app/styles/a2.css +1383 -0
  33. package/app/styles/shell.css +438 -0
  34. package/app/styles/tokens.css +111 -0
  35. package/app/tags/page.tsx +28 -0
  36. package/app/ui-parity/page.tsx +3 -2
  37. package/package.json +1 -1
  38. package/scripts/build-content.mjs +11 -1
  39. package/scripts/check-post.mjs +18 -4
  40. package/scripts/new-post.mjs +3 -0
  41. package/site.config.yaml +1 -1
  42. package/templates/garden-blocks.md +128 -0
  43. package/templates/garden-snippets.plist +121 -0
  44. package/ui/garden/catalog.mjs +196 -0
  45. package/ui/garden/check.mjs +103 -0
  46. package/ui/garden/enhance.mjs +89 -0
  47. package/ui/garden/parse.mjs +198 -0
  48. package/ui/garden/snippets.mjs +109 -0
  49. package/ui/garden/title.mjs +37 -0
  50. package/ui/garden/word-count.mjs +266 -0
  51. package/ui/host.mjs +45 -28
  52. package/ui/parity-fixtures.mjs +1 -1
  53. package/ui/preview/dist/garden-ui.css +81 -77
  54. package/ui/preview/dist/garden-ui.esm.js +124 -89
  55. package/ui/preview/dist/garden-ui.iife.js +124 -89
  56. package/ui/prompt/rules.md +17 -1
  57. package/ui/react/CatalogPage.tsx +12 -0
  58. package/ui/react/components/display.tsx +1 -1
  59. package/ui/react/components/media.tsx +2 -2
  60. package/ui/react/ui.css +81 -77
@@ -1,4 +1,20 @@
1
- # 把作者的意图写成 Garden 的 ui 块
1
+ # 把作者的想法编译成 Garden 块
2
+
3
+ 文章里只有一种写法:`garden` 围栏。名字只有 card、stat、compare、timeline、chart、figure、html、interactive。裸 `garden` 围栏是作者的想法,发布前编译掉。不要再写 `ui`、`widget`、`embed`、`intent` 或 `garden:名字`。
4
+
5
+ ## 只用作者的原文
6
+
7
+ - 只用作者已经写过的句子。不改措辞,不补例子,不编数字。
8
+ - 不写测验,不写「作用」「适用」「特点」「说明」「要点」「互动版」「示例图」「点击」「点按」这类填充标签或过程旁白。
9
+ - 并排格子只放大约 60 字以内的短句。格子里放不下的,留在正文。
10
+ - 不要把连续段落拆成步骤。读者没有状态可以改时,不要做 interactive。
11
+ - 计算器只给复杂公式。一次乘法留在正文里。
12
+ - 保留作者自己的 mermaid。全局概览图保持一整张,不要拆开。
13
+ - 正文已经读得清楚时,不要再套一个组件。
14
+
15
+ interactive 的正文仍用下面的组件和属性。那是 interactive 的内部零件,不是文章里的名字。
16
+
17
+ # 把作者的意图写成 Garden 的 interactive 块
2
18
 
3
19
  你在帮一位技术博客作者,把他用自然语言写下的"这里想让读者动手看看",写成 Garden 站点能直接绘制的 `ui` 块。读者在网页上拖滑杆、翻步骤、点格子,全部在本地计算,不会再调用模型。
4
20
 
@@ -3,6 +3,7 @@
3
3
  import { marked } from "marked";
4
4
  import { useMemo, useState, useSyncExternalStore } from "react";
5
5
  import { COMPONENTS, GROUPS } from "../core/catalog.mjs";
6
+ import { CATALOG, GARDEN_NAMES, IDEA } from "../garden/catalog.mjs";
6
7
  import { compileUiBlock } from "../core/compile.mjs";
7
8
  import { DEMOS, demoFence } from "../core/demos.mjs";
8
9
  import { scanFences } from "../core/fence.mjs";
@@ -149,6 +150,17 @@ export function CatalogPage({ recipes = [], onStart }: { recipes?: RecipeSource[
149
150
 
150
151
  return (
151
152
  <div className="garden-catalog">
153
+ <section className="garden-author-catalog">
154
+ <h2>写作块</h2>
155
+ <p>文章里只写 <code>garden</code> 围栏。下面是名字。再往下的清单是 interactive 的内部零件,不是文章里的名字。</p>
156
+ <ul>
157
+ <li><code>garden</code> · {IDEA.label}。{IDEA.when}</li>
158
+ {GARDEN_NAMES.map((name) => {
159
+ const spec = CATALOG[name as keyof typeof CATALOG];
160
+ return <li key={name}><code>garden {name}</code> · {spec.label}。{spec.when}</li>;
161
+ })}
162
+ </ul>
163
+ </section>
152
164
  <nav className="garden-catalog-nav" aria-label="大类">
153
165
  <input type="search" placeholder="搜索" value={query} onChange={(event) => setQuery(event.target.value)} aria-label="搜索组件" />
154
166
  {categories.map((name) => (
@@ -282,7 +282,7 @@ function Cite({ node, env }: { node: UiNode; env: Env }) {
282
282
  const icon = href ? faviconSrc(href) : null;
283
283
  const body = (
284
284
  <>
285
- {icon ? <img src={icon} alt="" width={12} height={12} /> : null}
285
+ {icon ? <span className="garden-ui-cite-icon" aria-hidden="true" style={{ backgroundImage: `url("${icon}")` }} /> : null}
286
286
  {label}
287
287
  </>
288
288
  );
@@ -97,8 +97,8 @@ let mermaidQueue: Promise<unknown> = Promise.resolve();
97
97
 
98
98
  const MERMAID_FONT = 'ui-sans-serif, -apple-system, system-ui, "Segoe UI", Helvetica, Arial, "PingFang SC", sans-serif';
99
99
  const MERMAID_THEMES = {
100
- light: { background: "#f9f9f9", primaryColor: "#ffffff", primaryBorderColor: "#dddddd", primaryTextColor: "#171717", lineColor: "#888888", secondaryColor: "#f5f5f5", tertiaryColor: "#f5f5f5" },
101
- dark: { background: "#171717", primaryColor: "#2a2a2a", primaryBorderColor: "#ffffff33", primaryTextColor: "#ededed", lineColor: "#afafaf", secondaryColor: "#303030", tertiaryColor: "#303030" },
100
+ light: { background: "#F8F7F3", primaryColor: "#FFFFFF", primaryBorderColor: "#D6D2C9", primaryTextColor: "#1B1A18", lineColor: "#6E6B64", secondaryColor: "#F0EEE8", tertiaryColor: "#F0EEE8", fontSize: "14px" },
101
+ dark: { background: "#161513", primaryColor: "#1E1D1A", primaryBorderColor: "#45423C", primaryTextColor: "#EEECE7", lineColor: "#A09B91", secondaryColor: "#22211D", tertiaryColor: "#22211D", fontSize: "14px" },
102
102
  };
103
103
 
104
104
  function renderMermaid(source: string, id: string, dark: boolean) {
package/ui/react/ui.css CHANGED
@@ -6,41 +6,41 @@
6
6
  .garden-ui,
7
7
  .garden-catalog,
8
8
  .garden-ui-preview {
9
- --gui-bg: #fff;
10
- --gui-chart: #f4f4f4;
11
- --gui-track: #e4e4e4;
12
- --gui-thumb: #fff;
13
- --gui-slider-track: #0d0d0d1f;
14
- --gui-slider-thumb: #333;
15
- --gui-text: #0d0d0d;
16
- --gui-muted: #5d5d5d;
17
- --gui-subtle: #8f8f8f;
18
- --gui-completed: #777;
19
- --gui-border: #0000001a;
20
- --gui-border-soft: #00000014;
21
- --gui-border-strong: #0000001f;
22
- --gui-control-border: #ccc;
23
- --gui-check-border: #d2d2d2;
24
- --gui-control-bg: #fff;
25
- --gui-surface: #f5f5f5;
26
- --gui-chip: #f3f3f3;
27
- --gui-hover: #f5f5f5;
28
- --gui-solid: #171717;
29
- --gui-solid-hover: #303030;
30
- --gui-on-solid: #fff;
31
- --gui-segment: #ededed;
32
- --gui-segment-selected: #fff;
33
- --gui-segment-shadow: 0 1px 4px -1px #0003;
34
- --gui-progress: #0d0d0d;
35
- --gui-progress-track: #f3f3f3;
36
- --gui-focus: #0285ff;
37
- --gui-bubble: #eaf2ff;
38
- --gui-popover-border: #0000000d;
39
- --gui-shadow: 0 2px 6px #00000014;
40
- --gui-code-bg: #f9f9f9;
41
- --gui-accent: #0285ff;
42
- --gui-series-plain: #171717;
43
- --gui-series-accent: #0285ff;
9
+ --gui-bg: var(--card, #fff);
10
+ --gui-chart: var(--well);
11
+ --gui-track: var(--rule, #e6e3dc);
12
+ --gui-thumb: var(--card, #fff);
13
+ --gui-slider-track: var(--rule, #e6e3dc);
14
+ --gui-slider-thumb: var(--ink, #1b1a18);
15
+ --gui-text: var(--ink, #1b1a18);
16
+ --gui-muted: var(--muted, #6e6b64);
17
+ --gui-subtle: var(--grey, #737069);
18
+ --gui-completed: var(--muted, #6e6b64);
19
+ --gui-border: var(--rule, #e6e3dc);
20
+ --gui-border-soft: var(--rule, #e6e3dc);
21
+ --gui-border-strong: var(--rule-strong, #d6d2c9);
22
+ --gui-control-border: var(--rule-strong, #d6d2c9);
23
+ --gui-check-border: var(--rule-strong, #d6d2c9);
24
+ --gui-control-bg: var(--card, #fff);
25
+ --gui-surface: var(--well, #f0eee8);
26
+ --gui-chip: var(--well, #f0eee8);
27
+ --gui-hover: var(--well, #f0eee8);
28
+ --gui-solid: var(--ink, #1b1a18);
29
+ --gui-solid-hover: var(--soft, #4a4844);
30
+ --gui-on-solid: var(--paper, #f8f7f3);
31
+ --gui-segment: var(--well, #f0eee8);
32
+ --gui-segment-selected: var(--card, #fff);
33
+ --gui-segment-shadow: none;
34
+ --gui-progress: var(--blue, #2c55b4);
35
+ --gui-progress-track: var(--well, #f0eee8);
36
+ --gui-focus: var(--blue, #2c55b4);
37
+ --gui-bubble: var(--blue-tint, #eaf0fc);
38
+ --gui-popover-border: var(--rule, #e6e3dc);
39
+ --gui-shadow: none;
40
+ --gui-code-bg: var(--well, #f0eee8);
41
+ --gui-accent: var(--blue, #2c55b4);
42
+ --gui-series-plain: var(--ink, #1b1a18);
43
+ --gui-series-accent: var(--blue);
44
44
  --gui-series-new: #00a240;
45
45
  --gui-series-waste: #e02e2a;
46
46
  --gui-series-same: #924ff7;
@@ -56,7 +56,7 @@
56
56
  --gui-discovery: #924ff7;
57
57
  --gui-discovery-text: #8046d9;
58
58
  --gui-discovery-soft: #924ff71a;
59
- --gui-font: -apple-system-body, ui-sans-serif, -apple-system, system-ui, "Segoe UI", Helvetica, "Apple Color Emoji", Arial, sans-serif, "Segoe UI Emoji", "Segoe UI Symbol";
59
+ --gui-font: var(--sans, -apple-system, BlinkMacSystemFont, "PingFang SC", "Hiragino Sans GB", "Noto Sans SC", sans-serif);
60
60
  --gui-mono: ui-monospace, "SF Mono", SFMono-Regular, Menlo, Consolas, "Liberation Mono", monospace;
61
61
  }
62
62
 
@@ -67,40 +67,41 @@
67
67
  .garden-ui[data-theme="dark"],
68
68
  .garden-catalog[data-theme="dark"],
69
69
  .garden-ui-preview[data-theme="dark"] {
70
- --gui-bg: #0e0e0e;
71
- --gui-chart: #212121;
72
- --gui-text: #ededed;
73
- --gui-muted: #cdcdcd;
74
- --gui-subtle: #afafaf;
75
- --gui-completed: #afafaf;
76
- --gui-border: #ffffff1a;
77
- --gui-border-soft: #ffffff0d;
78
- --gui-border-strong: #fff3;
79
- --gui-control-border: #fff3;
80
- --gui-check-border: #fff3;
81
- --gui-control-bg: #303030;
82
- --gui-surface: #2a2a2a;
83
- --gui-chip: #303030;
84
- --gui-hover: #ffffff1a;
85
- --gui-solid: #ededed;
86
- --gui-solid-hover: #dcdcdc;
87
- --gui-on-solid: #0d0d0d;
88
- --gui-segment: #303030;
89
- --gui-segment-selected: #303030;
70
+ --gui-bg: var(--card);
71
+ --gui-chart: var(--well);
72
+ --gui-text: var(--ink);
73
+ --gui-muted: var(--muted);
74
+ --gui-subtle: var(--grey);
75
+ --gui-completed: var(--muted);
76
+ --gui-border: var(--rule);
77
+ --gui-border-soft: var(--rule);
78
+ --gui-border-strong: var(--rule-strong);
79
+ --gui-control-border: var(--rule-strong);
80
+ --gui-check-border: var(--rule-strong);
81
+ --gui-control-bg: var(--card);
82
+ --gui-surface: var(--well);
83
+ --gui-chip: var(--well);
84
+ --gui-hover: var(--tint);
85
+ --gui-solid: var(--ink);
86
+ --gui-solid-hover: var(--soft);
87
+ --gui-on-solid: var(--paper);
88
+ --gui-segment: var(--well);
89
+ --gui-segment-selected: var(--card);
90
90
  --gui-segment-shadow: none;
91
- --gui-track: #3a3a3a;
92
- --gui-thumb: #fff;
93
- --gui-slider-track: #ffffff26;
94
- --gui-slider-thumb: #ededed;
95
- --gui-progress: #0285ff;
96
- --gui-progress-track: #303030;
97
- --gui-focus: #3a83f7;
98
- --gui-bubble: #133463;
99
- --gui-popover-border: #ffffff26;
100
- --gui-shadow: 0 2px 8px #00000066;
101
- --gui-code-bg: #171717;
102
- --gui-accent: #0285ff;
103
- --gui-series-plain: #ededed;
91
+ --gui-track: var(--rule);
92
+ --gui-thumb: var(--card);
93
+ --gui-slider-track: var(--rule-strong);
94
+ --gui-slider-thumb: var(--ink);
95
+ --gui-progress: var(--blue);
96
+ --gui-progress-track: var(--well);
97
+ --gui-focus: var(--blue);
98
+ --gui-bubble: var(--blue-tint);
99
+ --gui-popover-border: var(--rule);
100
+ --gui-shadow: none;
101
+ --gui-code-bg: var(--well);
102
+ --gui-accent: var(--blue);
103
+ --gui-series-plain: var(--ink);
104
+ --gui-series-accent: var(--blue);
104
105
  --gui-series-new: #04b84c;
105
106
  --gui-series-waste: #fa423e;
106
107
  --gui-info: #0285ff;
@@ -919,13 +920,14 @@
919
920
  line-height: 1.3 !important;
920
921
  letter-spacing: normal !important;
921
922
  }
922
- .garden-ui-diagram-canvas .garden-ui-diagram-on rect,
923
- .garden-ui-diagram-canvas .garden-ui-diagram-on polygon,
924
- .garden-ui-diagram-canvas .garden-ui-diagram-on circle,
925
- .garden-ui-diagram-canvas rect.garden-ui-diagram-on { fill: var(--gui-info-soft) !important; stroke: var(--gui-accent) !important; }
926
- .garden-ui-diagram-canvas .garden-ui-diagram-on .nodeLabel,
927
- .garden-ui-diagram-canvas .garden-ui-diagram-on text { color: var(--gui-accent) !important; fill: var(--gui-accent) !important; }
928
- .garden-ui-diagram-canvas path.garden-ui-diagram-on { stroke: var(--gui-accent) !important; stroke-width: 2px !important; }
923
+ /* Selected nodes keep the 「全部」 look, text included. Only the rest fades. */
924
+ .garden-ui-diagram-canvas:has(.garden-ui-diagram-on) .node:not(.garden-ui-diagram-on),
925
+ .garden-ui-diagram-canvas:has(.garden-ui-diagram-on) .statediagram-state:not(.garden-ui-diagram-on),
926
+ .garden-ui-diagram-canvas:has(.garden-ui-diagram-on) .cluster:not(.garden-ui-diagram-on) { opacity: 0.22; }
927
+ .garden-ui-diagram-canvas .garden-ui-diagram-on,
928
+ .garden-ui-diagram-canvas .garden-ui-diagram-on text,
929
+ .garden-ui-diagram-canvas .garden-ui-diagram-on .nodeLabel { opacity: 1; }
930
+ .garden-ui-diagram-canvas path.garden-ui-diagram-on { stroke: var(--gui-accent); stroke-width: 2px; }
929
931
 
930
932
  .garden-ui-sandbox {
931
933
  display: block;
@@ -1131,7 +1133,9 @@
1131
1133
  position: relative;
1132
1134
  top: -2px;
1133
1135
  }
1134
- .garden-ui-cite img { width: 12px; height: 12px; border-radius: 2px; }
1136
+ .garden-ui-cite img,
1137
+ .garden-ui-cite-icon { width: 12px; height: 12px; border-radius: 2px; }
1138
+ .garden-ui-cite-icon { display: inline-block; background-position: center; background-size: contain; background-repeat: no-repeat; vertical-align: -2px; }
1135
1139
 
1136
1140
  .garden-ui-pie { display: flex; flex-direction: column; align-items: stretch; gap: 0; margin: 0; }
1137
1141
  .garden-ui-pie-title { align-self: stretch; margin: 0 0 8px; color: var(--gui-text); font-size: 16px; font-weight: 600; line-height: 26px; text-align: start; }