hd-garden 0.3.13 → 0.4.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/app/a2/[slug]/page.tsx +61 -0
- package/app/a2/page.tsx +27 -0
- package/app/blog/[...path]/page.tsx +33 -22
- package/app/blog/page.tsx +6 -7
- package/app/columns/[column]/[...path]/page.tsx +33 -25
- package/app/columns/page.tsx +38 -52
- package/app/components/ArticleMeasure.tsx +95 -0
- package/app/components/ArticleTitle.tsx +20 -0
- package/app/components/BlogArchive.tsx +106 -102
- package/app/components/MarkdownArticle.tsx +145 -66
- package/app/components/MermaidDiagram.tsx +44 -71
- package/app/components/SiteFooter.tsx +3 -7
- package/app/components/SiteHeader.tsx +55 -41
- package/app/components/TableOfContents.tsx +3 -2
- package/app/components/TagIndex.tsx +97 -0
- package/app/components/garden/GardenBlock.tsx +45 -0
- package/app/components/garden/blocks.tsx +530 -0
- package/app/components/garden/chrome.tsx +350 -0
- package/app/components/garden/sandbox-message.ts +16 -0
- package/app/garden-modules.d.ts +2 -0
- package/app/globals.css +17 -12
- package/app/layout.tsx +9 -0
- package/app/lib/a2-meta.ts +22 -0
- package/app/lib/a2-preview.ts +50 -0
- package/app/lib/content.ts +48 -5
- package/app/lib/markdown-plugins.ts +2 -0
- package/app/lib/remark-a2.mjs +208 -0
- package/app/lib/remark-garden.mjs +88 -0
- package/app/page.tsx +122 -93
- package/app/styles/a2.css +1383 -0
- package/app/styles/shell.css +438 -0
- package/app/styles/tokens.css +111 -0
- package/app/tags/page.tsx +28 -0
- package/app/ui-parity/page.tsx +3 -2
- package/package.json +1 -1
- package/scripts/build-content.mjs +11 -1
- package/scripts/check-post.mjs +18 -4
- package/scripts/new-post.mjs +3 -0
- package/site.config.yaml +1 -1
- package/templates/garden-blocks.md +128 -0
- package/templates/garden-snippets.plist +121 -0
- package/ui/garden/catalog.mjs +196 -0
- package/ui/garden/check.mjs +103 -0
- package/ui/garden/enhance.mjs +89 -0
- package/ui/garden/parse.mjs +198 -0
- package/ui/garden/snippets.mjs +109 -0
- package/ui/garden/title.mjs +37 -0
- package/ui/garden/word-count.mjs +266 -0
- package/ui/host.mjs +45 -28
- package/ui/parity-fixtures.mjs +1 -1
- package/ui/preview/dist/garden-ui.css +81 -77
- package/ui/preview/dist/garden-ui.esm.js +124 -89
- package/ui/preview/dist/garden-ui.iife.js +124 -89
- package/ui/prompt/rules.md +17 -1
- package/ui/react/CatalogPage.tsx +12 -0
- package/ui/react/components/display.tsx +1 -1
- package/ui/react/components/media.tsx +2 -2
- package/ui/react/ui.css +81 -77
|
@@ -0,0 +1,266 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Article word count, the same rule as the A2 demo generator (`lib/page.mjs`):
|
|
3
|
+
*
|
|
4
|
+
* renderedHtml.replace(/<[^>]+>/g, "").replace(/\s/g, "").length
|
|
5
|
+
*
|
|
6
|
+
* There is no second filter that drops code, tables, or math. Whatever text the
|
|
7
|
+
* renderer leaves between tags is counted, including characters that HTML
|
|
8
|
+
* escaping expanded (`&` → `&`). Whitespace of every kind is removed first.
|
|
9
|
+
*
|
|
10
|
+
* What that means for each construct:
|
|
11
|
+
*
|
|
12
|
+
* - Fenced code is included. The source is emitted inside `<pre><code>`.
|
|
13
|
+
* Highlight markup is only tags, so it does not change the count.
|
|
14
|
+
* - Inline code is included.
|
|
15
|
+
* - Tables are included (the cell text).
|
|
16
|
+
* - Math is included as the text KaTeX emits (visible glyphs and the MathML
|
|
17
|
+
* annotation). The TeX source is not counted a second time on top of that.
|
|
18
|
+
* - Garden block props are not counted as YAML keys. Only text the widget
|
|
19
|
+
* actually emits is counted:
|
|
20
|
+
* - `garden html` that is a full document (the demo's `sandbox` fence) goes
|
|
21
|
+
* into an iframe `srcdoc` attribute. The tag strip deletes the attribute,
|
|
22
|
+
* so the document and its props are excluded. A `fallback:` line is
|
|
23
|
+
* emitted in `<noscript>` and is counted.
|
|
24
|
+
* - `garden html` that is already a widget fragment is inlined, so its text
|
|
25
|
+
* (including `<script>` text) is counted.
|
|
26
|
+
* - `garden figure` emits tab labels, part explanations, the caption, and
|
|
27
|
+
* SVG `<text>`. Prop keys and part ids stay in attributes and are excluded.
|
|
28
|
+
* - A heading written `## 1.2 Title` keeps the digits (they move into
|
|
29
|
+
* `.sec-no`). The dot is dropped. The space was never going to be counted.
|
|
30
|
+
*
|
|
31
|
+
* The Go parity article comes out at 35,105. The demo page prints 35,234 for
|
|
32
|
+
* the same prose and the same fenced code. The missing 129 characters are the
|
|
33
|
+
* demo sandbox's `fallback:` paragraph, which that source renders in
|
|
34
|
+
* `<noscript>` and this parity article does not contain.
|
|
35
|
+
*/
|
|
36
|
+
import katex from "katex";
|
|
37
|
+
import { Marked } from "marked";
|
|
38
|
+
import { parse as parseYaml } from "yaml";
|
|
39
|
+
|
|
40
|
+
const marked = new Marked({
|
|
41
|
+
gfm: true,
|
|
42
|
+
breaks: false,
|
|
43
|
+
renderer: {
|
|
44
|
+
code(token) {
|
|
45
|
+
const text = typeof token === "string" ? token : token.text ?? "";
|
|
46
|
+
const lang = typeof token === "string" ? "" : token.lang ?? "";
|
|
47
|
+
const name = String(lang).split(/\s/u)[0] ?? "";
|
|
48
|
+
const body = escapeHtml(text);
|
|
49
|
+
if (name === "mermaid") {
|
|
50
|
+
return `<figure class="g-mermaid"><pre class="code mermaid-src"><code>${body}</code></pre></figure>\n`;
|
|
51
|
+
}
|
|
52
|
+
return `<pre class="code"><code class="hljs${name ? ` language-${escapeHtml(name)}` : ""}">${body}</code></pre>\n`;
|
|
53
|
+
},
|
|
54
|
+
},
|
|
55
|
+
extensions: [
|
|
56
|
+
{
|
|
57
|
+
name: "mathBlock",
|
|
58
|
+
level: "block",
|
|
59
|
+
start(src) {
|
|
60
|
+
return src.indexOf("$$");
|
|
61
|
+
},
|
|
62
|
+
tokenizer(src) {
|
|
63
|
+
const match = /^\$\$\s*\n?([\s\S]+?)\n?\$\$\s*(?:\n|$)/u.exec(src);
|
|
64
|
+
if (!match) return undefined;
|
|
65
|
+
return { type: "mathBlock", raw: match[0], tex: match[1] };
|
|
66
|
+
},
|
|
67
|
+
renderer(token) {
|
|
68
|
+
return `<div class="math-display">${katex.renderToString(String(token.tex ?? "").trim(), { displayMode: true, throwOnError: false })}</div>\n`;
|
|
69
|
+
},
|
|
70
|
+
},
|
|
71
|
+
{
|
|
72
|
+
name: "mathInline",
|
|
73
|
+
level: "inline",
|
|
74
|
+
start(src) {
|
|
75
|
+
const index = src.indexOf("$");
|
|
76
|
+
return index < 0 ? undefined : index;
|
|
77
|
+
},
|
|
78
|
+
tokenizer(src) {
|
|
79
|
+
const match = /^\$(?!\s)((?:\\\$|[^$\n])+?)(?<!\s)\$(?!\d)/u.exec(src);
|
|
80
|
+
if (!match) return undefined;
|
|
81
|
+
return { type: "mathInline", raw: match[0], tex: match[1] };
|
|
82
|
+
},
|
|
83
|
+
renderer(token) {
|
|
84
|
+
return katex.renderToString(String(token.tex ?? ""), { throwOnError: false });
|
|
85
|
+
},
|
|
86
|
+
},
|
|
87
|
+
],
|
|
88
|
+
});
|
|
89
|
+
|
|
90
|
+
function escapeHtml(value) {
|
|
91
|
+
return String(value ?? "")
|
|
92
|
+
.replace(/&/g, "&")
|
|
93
|
+
.replace(/</g, "<")
|
|
94
|
+
.replace(/>/g, ">")
|
|
95
|
+
.replace(/"/g, """);
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
function splitProps(body) {
|
|
99
|
+
const text = String(body ?? "").replace(/\s+$/u, "");
|
|
100
|
+
const lines = text.split("\n");
|
|
101
|
+
const sep = lines.findIndex((line, index) => index > 0 && /^---\s*$/u.test(line));
|
|
102
|
+
if (sep === -1) return { yamlText: text, children: "" };
|
|
103
|
+
return { yamlText: lines.slice(0, sep).join("\n"), children: lines.slice(sep + 1).join("\n").replace(/^\n/u, "") };
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
function readYaml(yamlText) {
|
|
107
|
+
try {
|
|
108
|
+
const parsed = yamlText.trim() ? parseYaml(yamlText) : {};
|
|
109
|
+
return parsed && typeof parsed === "object" ? parsed : {};
|
|
110
|
+
} catch {
|
|
111
|
+
return null;
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
function isHtmlDocument(body) {
|
|
116
|
+
return /^\s*(?:<!doctype|<html|<style|<script)/iu.test(body);
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
function sandboxHtml(title, body) {
|
|
120
|
+
const fallback = /^fallback:\s*(.*)$/mu.exec(body);
|
|
121
|
+
const src = fallback ? body.replace(/^fallback:\s*.*(?:\n|$)/mu, "") : body;
|
|
122
|
+
const noscript = fallback ? `<noscript><p>${escapeHtml(fallback[1])}</p></noscript>` : "";
|
|
123
|
+
return `<div class="g-sandbox"><iframe title="${escapeHtml(title)}" srcdoc="${escapeHtml(src)}"></iframe>${noscript}</div>`;
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
function inline(value) {
|
|
127
|
+
return marked.parseInline(String(value ?? ""), { async: false });
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
function figureHtml(data, svg) {
|
|
131
|
+
const parts = Array.isArray(data.parts) ? data.parts : [];
|
|
132
|
+
const tabs = parts.map((part) => `<button type="button" data-sel="${escapeHtml(part.id)}">${escapeHtml(part.label ?? "")}</button>`).join("");
|
|
133
|
+
const notes = parts.map((part) => `<p data-exp="${escapeHtml(part.id)}">${inline(part.text ?? "")}</p>`).join("");
|
|
134
|
+
const caption = data.caption ? `<figcaption>${inline(data.caption)}</figcaption>` : "";
|
|
135
|
+
return `<figure class="g-explore"><div role="tablist">${tabs}</div><div class="dx-wrap">${svg}</div><div class="dx-exp">${notes}</div>${caption}</figure>`;
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
function visibleStrings(value, html) {
|
|
139
|
+
if (typeof value === "string") html.push(inline(value));
|
|
140
|
+
else if (Array.isArray(value)) value.forEach((item) => visibleStrings(item, html));
|
|
141
|
+
else if (value && typeof value === "object") {
|
|
142
|
+
for (const [key, item] of Object.entries(value)) {
|
|
143
|
+
if (key === "id" || key === "url" || key === "src" || key === "svg" || key === "svgFile") continue;
|
|
144
|
+
visibleStrings(item, html);
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
function gardenHtml(info, body) {
|
|
150
|
+
const name = info.trim().split(/\s+/u)[0]?.toLowerCase() ?? "";
|
|
151
|
+
const { yamlText, children } = splitProps(body);
|
|
152
|
+
if (name === "html" || name === "interactive") {
|
|
153
|
+
const data = readYaml(yamlText) ?? {};
|
|
154
|
+
const title = typeof data.title === "string" ? data.title : "";
|
|
155
|
+
const document = children.trim() ? children : body;
|
|
156
|
+
if (!children.trim() || isHtmlDocument(document)) return sandboxHtml(title, document);
|
|
157
|
+
return document;
|
|
158
|
+
}
|
|
159
|
+
if (name === "figure") {
|
|
160
|
+
const data = readYaml(yamlText);
|
|
161
|
+
if (!data) return `<pre class="code"><code>${escapeHtml(body)}</code></pre>`;
|
|
162
|
+
return figureHtml(data, children);
|
|
163
|
+
}
|
|
164
|
+
const data = readYaml(yamlText);
|
|
165
|
+
if (!data) return `<pre class="code"><code>${escapeHtml(body)}</code></pre>`;
|
|
166
|
+
const bits = [];
|
|
167
|
+
visibleStrings(data, bits);
|
|
168
|
+
if (children.trim()) bits.push(children);
|
|
169
|
+
return bits.join("");
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
function renderBlocks(markdown) {
|
|
173
|
+
const lines = String(markdown ?? "").split("\n");
|
|
174
|
+
const parts = [];
|
|
175
|
+
let buffer = [];
|
|
176
|
+
const flush = () => {
|
|
177
|
+
if (!buffer.length) return;
|
|
178
|
+
parts.push(marked.parse(buffer.join("\n"), { async: false }));
|
|
179
|
+
buffer = [];
|
|
180
|
+
};
|
|
181
|
+
for (let index = 0; index < lines.length; index += 1) {
|
|
182
|
+
const opened = /^(`{3,}|~{3,})(.*)$/u.exec(lines[index]);
|
|
183
|
+
if (!opened) {
|
|
184
|
+
buffer.push(lines[index]);
|
|
185
|
+
continue;
|
|
186
|
+
}
|
|
187
|
+
const marker = opened[1];
|
|
188
|
+
const info = opened[2].trim();
|
|
189
|
+
const lang = info.split(/\s+/u)[0]?.toLowerCase() ?? "";
|
|
190
|
+
const body = [];
|
|
191
|
+
index += 1;
|
|
192
|
+
while (index < lines.length && !new RegExp(`^${marker[0]}{${marker.length},}\\s*$`, "u").test(lines[index])) {
|
|
193
|
+
body.push(lines[index]);
|
|
194
|
+
index += 1;
|
|
195
|
+
}
|
|
196
|
+
if (lang === "garden") {
|
|
197
|
+
flush();
|
|
198
|
+
parts.push(gardenHtml(info.slice("garden".length).trim(), body.join("\n")));
|
|
199
|
+
} else {
|
|
200
|
+
buffer.push(lines[index - body.length - 1], ...body, lines[index] ?? marker);
|
|
201
|
+
}
|
|
202
|
+
}
|
|
203
|
+
flush();
|
|
204
|
+
return parts.join("\n");
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
function numberHeadings(html, markdown) {
|
|
208
|
+
let h2 = 0;
|
|
209
|
+
let h3 = 0;
|
|
210
|
+
const numbered = /^#{2,3}\s+\d/mu.test(markdown);
|
|
211
|
+
const minLevel = /^##\s/mu.test(markdown) ? 2 : 3;
|
|
212
|
+
return html.replace(/<h([234])>(.*?)<\/h\1>/gu, (all, level, inner) => {
|
|
213
|
+
const sourceLevel = Number(level);
|
|
214
|
+
const mapped = sourceLevel - minLevel + 2;
|
|
215
|
+
if (mapped > 3) return `<h4>${inner}</h4>`;
|
|
216
|
+
const text = inner
|
|
217
|
+
.replace(/<[^>]+>/g, "")
|
|
218
|
+
.replace(/"/g, "\"")
|
|
219
|
+
.replace(/'/g, "'")
|
|
220
|
+
.replace(/</g, "<")
|
|
221
|
+
.replace(/>/g, ">")
|
|
222
|
+
.replace(/&/g, "&");
|
|
223
|
+
const numberedHeading = /^(\d+(?:\.\d+)*)\.?\s+(.*)$/u.exec(text);
|
|
224
|
+
let number = "";
|
|
225
|
+
let body = inner;
|
|
226
|
+
if (numberedHeading) {
|
|
227
|
+
number = numberedHeading[1];
|
|
228
|
+
body = inner.replace(/^(\d+(?:\.\d+)*)\.?\s+/u, "");
|
|
229
|
+
} else if (!numbered) {
|
|
230
|
+
if (mapped === 2) {
|
|
231
|
+
h2 += 1;
|
|
232
|
+
h3 = 0;
|
|
233
|
+
number = String(h2);
|
|
234
|
+
} else {
|
|
235
|
+
h3 += 1;
|
|
236
|
+
number = h2 ? `${h2}.${h3}` : String(h3);
|
|
237
|
+
}
|
|
238
|
+
}
|
|
239
|
+
return `<h${mapped}>${number ? `<span class="sec-no">${number}</span>` : ""}${body}</h${mapped}>`;
|
|
240
|
+
});
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
const ALERT_TITLE = { note: "提醒", tip: "建议", important: "重要", warning: "警告", caution: "注意" };
|
|
244
|
+
|
|
245
|
+
function githubAlerts(html) {
|
|
246
|
+
return html.replace(/<blockquote>\s*<p>\[!(NOTE|TIP|IMPORTANT|WARNING|CAUTION)\][ \t]*([^\n<]*)\n?/gu, (_, kind, title) => {
|
|
247
|
+
const name = String(kind).toLowerCase();
|
|
248
|
+
const label = title.trim() ? escapeHtml(title.trim()) : ALERT_TITLE[name];
|
|
249
|
+
return `<blockquote class="markdown-alert markdown-alert-${name}"><p class="markdown-alert-title">${label}</p><p>`;
|
|
250
|
+
});
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
function captionImages(html) {
|
|
254
|
+
return html.replace(/<p>(<img [^>]+>)<\/p>/gu, (_, img) => {
|
|
255
|
+
const alt = (/alt="([^"]*)"/u.exec(img) ?? [])[1] ?? "";
|
|
256
|
+
const title = (/title="([^"]*)"/u.exec(img) ?? [])[1] ?? "";
|
|
257
|
+
const caption = title || (alt && !/^image|^截图|^img/iu.test(alt) ? alt : "");
|
|
258
|
+
return `<figure class="fig"><div class="fig-card">${img}</div>${caption ? `<figcaption>${caption}</figcaption>` : ""}</figure>`;
|
|
259
|
+
});
|
|
260
|
+
}
|
|
261
|
+
|
|
262
|
+
/** Rendered-article word count. Pure: no DOM, safe to run while generating content. */
|
|
263
|
+
export function countDemoWords(markdown) {
|
|
264
|
+
const html = githubAlerts(captionImages(numberHeadings(renderBlocks(markdown), markdown)));
|
|
265
|
+
return html.replace(/<[^>]+>/g, "").replace(/\s/g, "").length;
|
|
266
|
+
}
|
package/ui/host.mjs
CHANGED
|
@@ -53,26 +53,34 @@ export function isHttpsUrl(value) {
|
|
|
53
53
|
|
|
54
54
|
const THEMES = {
|
|
55
55
|
light: {
|
|
56
|
-
|
|
57
|
-
text: "#
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
56
|
+
ink: "#1B1A18",
|
|
57
|
+
text: "#2D2C29",
|
|
58
|
+
soft: "#4A4844",
|
|
59
|
+
muted: "#6E6B64",
|
|
60
|
+
grey: "#737069",
|
|
61
|
+
rule: "#E6E3DC",
|
|
62
|
+
ruleStrong: "#D6D2C9",
|
|
63
|
+
card: "#FFFFFF",
|
|
64
|
+
paper: "#F8F7F3",
|
|
65
|
+
well: "#F0EEE8",
|
|
66
|
+
blue: "#2C55B4",
|
|
67
|
+
blueTint: "#EAF0FC",
|
|
68
|
+
blueLine: "rgba(44,85,180,.28)",
|
|
65
69
|
},
|
|
66
70
|
dark: {
|
|
67
|
-
|
|
68
|
-
text: "#
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
71
|
+
ink: "#EEECE7",
|
|
72
|
+
text: "#DCD9D2",
|
|
73
|
+
soft: "#BDB9B0",
|
|
74
|
+
muted: "#A09B91",
|
|
75
|
+
grey: "#A09B91",
|
|
76
|
+
rule: "#2F2D29",
|
|
77
|
+
ruleStrong: "#45423C",
|
|
78
|
+
card: "#1E1D1A",
|
|
79
|
+
paper: "#161513",
|
|
80
|
+
well: "#22211D",
|
|
81
|
+
blue: "#93B2F4",
|
|
82
|
+
blueTint: "rgba(147,178,244,.13)",
|
|
83
|
+
blueLine: "rgba(147,178,244,.35)",
|
|
76
84
|
},
|
|
77
85
|
};
|
|
78
86
|
|
|
@@ -80,19 +88,28 @@ function tokenCss(theme) {
|
|
|
80
88
|
const token = THEMES[theme] ?? THEMES.light;
|
|
81
89
|
return `
|
|
82
90
|
:root {
|
|
83
|
-
color: ${token.
|
|
91
|
+
color: ${token.text};
|
|
92
|
+
color-scheme: ${theme === "dark" ? "dark" : "light"};
|
|
84
93
|
background: transparent;
|
|
85
|
-
font-family: -apple-system
|
|
86
|
-
--
|
|
87
|
-
--
|
|
88
|
-
--
|
|
89
|
-
--
|
|
90
|
-
--
|
|
91
|
-
--
|
|
92
|
-
--
|
|
93
|
-
--
|
|
94
|
+
font-family: -apple-system, BlinkMacSystemFont, "PingFang SC", "Hiragino Sans GB", "Noto Sans SC", sans-serif;
|
|
95
|
+
--ink: ${token.ink};
|
|
96
|
+
--text: ${token.text};
|
|
97
|
+
--soft: ${token.soft};
|
|
98
|
+
--muted: ${token.muted};
|
|
99
|
+
--grey: ${token.grey};
|
|
100
|
+
--rule: ${token.rule};
|
|
101
|
+
--rule-strong: ${token.ruleStrong};
|
|
102
|
+
--card: ${token.card};
|
|
103
|
+
--paper: ${token.paper};
|
|
104
|
+
--well: ${token.well};
|
|
105
|
+
--blue: ${token.blue};
|
|
106
|
+
--blue-tint: ${token.blueTint};
|
|
107
|
+
--blue-line: ${token.blueLine};
|
|
94
108
|
}
|
|
109
|
+
html, body { background: transparent !important; overflow: hidden !important; height: auto !important; }
|
|
95
110
|
body { margin: 0; }
|
|
111
|
+
body > :first-child { padding-right: 44px; box-sizing: border-box; }
|
|
112
|
+
svg { max-width: 100%; height: auto; }
|
|
96
113
|
`;
|
|
97
114
|
}
|
|
98
115
|
|
package/ui/parity-fixtures.mjs
CHANGED
|
@@ -70,7 +70,7 @@ fmt.Println(b)\`} />
|
|
|
70
70
|
id: "parity-sandbox",
|
|
71
71
|
width: 768,
|
|
72
72
|
body: `${header("parity-sandbox", "目录以外的交互放在无网络的画布里。")}
|
|
73
|
-
<Sandbox title="计数" html={"<p id=\\"n\\">0</p><button id=\\"b\\" type=\\"button\\">加一</button>"} css="button{color:var(--
|
|
73
|
+
<Sandbox title="计数" html={"<p id=\\"n\\">0</p><button id=\\"b\\" type=\\"button\\">加一</button>"} css="button{color:var(--blue)}" js="document.getElementById('b').onclick=()=>{const n=document.getElementById('n');n.textContent=String(Number(n.textContent)+1)}" />
|
|
74
74
|
`,
|
|
75
75
|
},
|
|
76
76
|
];
|
|
@@ -6,41 +6,41 @@
|
|
|
6
6
|
.garden-ui,
|
|
7
7
|
.garden-catalog,
|
|
8
8
|
.garden-ui-preview {
|
|
9
|
-
--gui-bg: #fff;
|
|
10
|
-
--gui-chart:
|
|
11
|
-
--gui-track: #
|
|
12
|
-
--gui-thumb: #fff;
|
|
13
|
-
--gui-slider-track: #
|
|
14
|
-
--gui-slider-thumb: #
|
|
15
|
-
--gui-text: #
|
|
16
|
-
--gui-muted: #
|
|
17
|
-
--gui-subtle: #
|
|
18
|
-
--gui-completed: #
|
|
19
|
-
--gui-border: #
|
|
20
|
-
--gui-border-soft: #
|
|
21
|
-
--gui-border-strong: #
|
|
22
|
-
--gui-control-border: #
|
|
23
|
-
--gui-check-border: #
|
|
24
|
-
--gui-control-bg: #fff;
|
|
25
|
-
--gui-surface: #
|
|
26
|
-
--gui-chip: #
|
|
27
|
-
--gui-hover: #
|
|
28
|
-
--gui-solid: #
|
|
29
|
-
--gui-solid-hover: #
|
|
30
|
-
--gui-on-solid: #
|
|
31
|
-
--gui-segment: #
|
|
32
|
-
--gui-segment-selected: #fff;
|
|
33
|
-
--gui-segment-shadow:
|
|
34
|
-
--gui-progress: #
|
|
35
|
-
--gui-progress-track: #
|
|
36
|
-
--gui-focus: #
|
|
37
|
-
--gui-bubble: #
|
|
38
|
-
--gui-popover-border: #
|
|
39
|
-
--gui-shadow:
|
|
40
|
-
--gui-code-bg: #
|
|
41
|
-
--gui-accent: #
|
|
42
|
-
--gui-series-plain: #
|
|
43
|
-
--gui-series-accent:
|
|
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:
|
|
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:
|
|
71
|
-
--gui-chart:
|
|
72
|
-
--gui-text:
|
|
73
|
-
--gui-muted:
|
|
74
|
-
--gui-subtle:
|
|
75
|
-
--gui-completed:
|
|
76
|
-
--gui-border:
|
|
77
|
-
--gui-border-soft:
|
|
78
|
-
--gui-border-strong:
|
|
79
|
-
--gui-control-border:
|
|
80
|
-
--gui-check-border:
|
|
81
|
-
--gui-control-bg:
|
|
82
|
-
--gui-surface:
|
|
83
|
-
--gui-chip:
|
|
84
|
-
--gui-hover:
|
|
85
|
-
--gui-solid:
|
|
86
|
-
--gui-solid-hover:
|
|
87
|
-
--gui-on-solid:
|
|
88
|
-
--gui-segment:
|
|
89
|
-
--gui-segment-selected:
|
|
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:
|
|
92
|
-
--gui-thumb:
|
|
93
|
-
--gui-slider-track:
|
|
94
|
-
--gui-slider-thumb:
|
|
95
|
-
--gui-progress:
|
|
96
|
-
--gui-progress-track:
|
|
97
|
-
--gui-focus:
|
|
98
|
-
--gui-bubble:
|
|
99
|
-
--gui-popover-border:
|
|
100
|
-
--gui-shadow:
|
|
101
|
-
--gui-code-bg:
|
|
102
|
-
--gui-accent:
|
|
103
|
-
--gui-series-plain:
|
|
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
|
-
.
|
|
923
|
-
.garden-ui-diagram-canvas .garden-ui-diagram-on
|
|
924
|
-
.garden-ui-diagram-canvas .garden-ui-diagram-on
|
|
925
|
-
.garden-ui-diagram-canvas
|
|
926
|
-
.garden-ui-diagram-canvas .garden-ui-diagram-on
|
|
927
|
-
.garden-ui-diagram-canvas .garden-ui-diagram-on text
|
|
928
|
-
.garden-ui-diagram-canvas
|
|
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
|
|
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; }
|