hd-garden 0.8.0 → 0.8.2
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 +2 -2
- package/.env.en.example +67 -0
- package/README.en.md +2 -2
- package/README.md +2 -2
- package/app/a2/[slug]/page.tsx +4 -3
- package/app/a2/page.tsx +4 -3
- package/app/about/page.tsx +8 -9
- package/app/admin/page.tsx +7 -6
- package/app/admin/preview/[...path]/page.tsx +2 -1
- package/app/admin/ui/blocks/page.tsx +2 -1
- package/app/admin/ui/catalog/page.tsx +2 -1
- package/app/admin/ui/evals/page.tsx +2 -1
- package/app/admin/ui/page.tsx +2 -1
- package/app/blog/[...path]/page.tsx +7 -6
- package/app/blog/page.tsx +4 -2
- package/app/columns/[column]/[...path]/page.tsx +8 -7
- package/app/columns/page.tsx +12 -8
- package/app/components/AdminUiShell.tsx +4 -3
- package/app/components/ArticleMeasure.tsx +6 -3
- package/app/components/ArticleReferences.tsx +4 -1
- package/app/components/ArticleTags.tsx +3 -2
- package/app/components/BlogArchive.tsx +20 -16
- package/app/components/Comments.tsx +16 -10
- package/app/components/ContentEmptyState.tsx +29 -28
- package/app/components/ExternalEmbed.tsx +15 -14
- package/app/components/GardenContentGuide.tsx +10 -2
- package/app/components/GardenDocsNav.tsx +4 -2
- package/app/components/GiscusComments.tsx +2 -1
- package/app/components/GithubLiveOverview.tsx +10 -8
- package/app/components/GithubProfile.tsx +31 -21
- package/app/components/HandbookLangSwitch.tsx +8 -4
- package/app/components/HandbookView.tsx +92 -9
- package/app/components/MarkdownArticle.tsx +31 -7
- package/app/components/MermaidDiagram.tsx +4 -3
- package/app/components/SiteChrome.tsx +3 -3
- package/app/components/SiteFooter.tsx +1 -1
- package/app/components/SiteHeader.tsx +13 -4
- package/app/components/ThoughtCard.tsx +16 -14
- package/app/components/UiBlock.tsx +3 -2
- package/app/components/Webmentions.tsx +11 -11
- package/app/components/WidgetChart.tsx +8 -6
- package/app/components/garden/FilePreview.tsx +2 -2
- package/app/components/garden/GardenBlock.tsx +7 -0
- package/app/components/garden/GardenFile.tsx +2 -2
- package/app/components/garden/RefDemo.tsx +62 -0
- package/app/components/garden/blocks.tsx +56 -8
- package/app/components/garden/patterns.tsx +497 -0
- package/app/garden/[...slug]/page.tsx +3 -2
- package/app/garden/en/page.tsx +7 -7
- package/app/garden/page.tsx +3 -2
- package/app/globals.css +49 -1
- package/app/lib/a2-meta.ts +26 -3
- package/app/lib/content.ts +2 -2
- package/app/lib/garden-docs-meta.ts +24 -0
- package/app/lib/github-id.mjs +8 -0
- package/app/lib/handbook-switch.mjs +12 -0
- package/app/lib/i18n.ts +401 -2
- package/app/lib/rehype-field-tables.mjs +47 -0
- package/app/lib/remark-a2.mjs +18 -8
- package/app/lib/remark-link-card.mjs +22 -0
- package/app/lib/remark-ref-demos.mjs +42 -0
- package/app/lib/tag-filter.ts +9 -2
- package/app/not-found.tsx +32 -4
- package/app/page.tsx +17 -14
- package/app/rss.xml/route.ts +2 -1
- package/app/styles/a2.css +338 -0
- package/app/styles/shell.css +15 -2
- package/app/tags/page.tsx +7 -5
- package/app/thoughts/[slug]/page.tsx +2 -1
- package/app/thoughts/page/[n]/page.tsx +1 -1
- package/app/thoughts/page.tsx +2 -1
- package/app/ui-parity/page.tsx +38 -22
- package/bin/garden.mjs +129 -19
- package/docs/handbook/ai-writing.md +2 -2
- package/docs/handbook/assets/reading-layout-en.svg +26 -0
- package/docs/handbook/components/card.md +43 -22
- package/docs/handbook/components/chart.md +10 -26
- package/docs/handbook/components/choice.md +42 -0
- package/docs/handbook/components/compare.md +32 -17
- package/docs/handbook/components/figure.md +33 -46
- package/docs/handbook/components/file.md +10 -15
- package/docs/handbook/components/html.md +10 -30
- package/docs/handbook/components/interactive.md +9 -35
- package/docs/handbook/components/list.md +65 -0
- package/docs/handbook/components/relations.md +95 -0
- package/docs/handbook/components/stat.md +10 -28
- package/docs/handbook/components/timeline.md +13 -28
- package/docs/handbook/components.md +210 -19
- package/docs/handbook/config.md +5 -3
- package/docs/handbook/deploy.md +1 -1
- package/docs/handbook/design.md +20 -12
- package/docs/handbook/en/ai-writing.md +2 -2
- package/docs/handbook/en/components/card.md +42 -21
- package/docs/handbook/en/components/chart.md +10 -26
- package/docs/handbook/en/components/choice.md +42 -0
- package/docs/handbook/en/components/compare.md +30 -15
- package/docs/handbook/en/components/figure.md +29 -42
- package/docs/handbook/en/components/file.md +9 -14
- package/docs/handbook/en/components/html.md +9 -29
- package/docs/handbook/en/components/interactive.md +8 -34
- package/docs/handbook/en/components/list.md +65 -0
- package/docs/handbook/en/components/relations.md +95 -0
- package/docs/handbook/en/components/stat.md +9 -27
- package/docs/handbook/en/components/timeline.md +9 -24
- package/docs/handbook/en/components.md +211 -19
- package/docs/handbook/en/config.md +32 -30
- package/docs/handbook/en/deploy.md +12 -12
- package/docs/handbook/en/design.md +19 -12
- package/docs/handbook/en/index.md +2 -2
- package/docs/handbook/en/reference/card.md +85 -0
- package/docs/handbook/en/reference/chart.md +68 -0
- package/docs/handbook/en/reference/choice.md +69 -0
- package/docs/handbook/en/reference/compare.md +59 -0
- package/docs/handbook/en/reference/figure.md +84 -0
- package/docs/handbook/en/reference/file/checklist.md +17 -0
- package/docs/handbook/en/reference/file.md +50 -0
- package/docs/handbook/en/reference/html.md +62 -0
- package/docs/handbook/en/reference/interactive.md +71 -0
- package/docs/handbook/en/reference/list.md +72 -0
- package/docs/handbook/en/reference/relations.md +113 -0
- package/docs/handbook/en/reference/stat.md +60 -0
- package/docs/handbook/en/reference/timeline.md +56 -0
- package/docs/handbook/en/reference.md +26 -0
- package/docs/handbook/en/start.md +2 -2
- package/docs/handbook/en/workflow.md +6 -5
- package/docs/handbook/en/writing.md +3 -2
- package/docs/handbook/index.md +1 -1
- package/docs/handbook/reference/card.md +85 -0
- package/docs/handbook/reference/chart.md +68 -0
- package/docs/handbook/reference/choice.md +69 -0
- package/docs/handbook/reference/compare.md +59 -0
- package/docs/handbook/reference/figure.md +84 -0
- package/docs/handbook/reference/file/checklist.md +17 -0
- package/docs/handbook/reference/file.md +50 -0
- package/docs/handbook/reference/html.md +62 -0
- package/docs/handbook/reference/interactive.md +71 -0
- package/docs/handbook/reference/list.md +72 -0
- package/docs/handbook/reference/relations.md +113 -0
- package/docs/handbook/reference/stat.md +60 -0
- package/docs/handbook/reference/timeline.md +56 -0
- package/docs/handbook/reference.md +26 -0
- package/docs/handbook/start.md +1 -1
- package/docs/handbook/workflow.md +6 -5
- package/docs/handbook/writing.md +3 -2
- package/next.config.ts +6 -0
- package/package.json +2 -1
- package/public/images/garden/ref-card-book.svg +1 -0
- package/public/images/garden/ref-card-lamp.svg +1 -0
- package/scripts/build-content.mjs +37 -16
- package/scripts/favicon-ico.mjs +9 -6
- package/scripts/file-preview.mjs +10 -7
- package/scripts/handbook-allowlist.mjs +18 -0
- package/scripts/handbook-facts.mjs +305 -11
- package/scripts/link-assets.mjs +7 -0
- package/scripts/new-post.mjs +18 -9
- package/scripts/prepare-pages-output.mjs +30 -18
- package/scripts/redirects.mjs +17 -6
- package/templates/garden-blocks.md +67 -0
- package/templates/garden-snippets.plist +61 -0
- package/templates/site/Makefile.en +45 -0
- package/templates/site/README.en.md +15 -0
- package/templates/site/site.config.en.yaml +55 -0
- package/templates/skills-en/garden-interactive-chart/SKILL.md +84 -0
- package/templates/skills-en/garden-interactive-chart/references/shell.html +49 -0
- package/templates/skills-en/garden-interactive-chart/references/style.md +61 -0
- package/templates/skills-en/garden-post-review/SKILL.md +63 -0
- package/templates/skills-en/garden-ui/SKILL.md +118 -0
- package/templates/workflows/pages.en.yml +195 -0
- package/templates/workflows/pages.yml +195 -0
- package/ui/garden/catalog.mjs +205 -4
- package/ui/garden/check.mjs +6 -0
- package/ui/garden/file-block.mjs +8 -7
- package/ui/garden/html-lang.mjs +73 -1
- package/ui/garden/markdown-links.mjs +7 -4
- package/ui/garden/parse.mjs +45 -0
- package/ui/garden/relations.mjs +252 -0
- package/ui/garden/search-index.mjs +6 -4
- package/ui/garden/source-icon.mjs +54 -0
- package/ui/parity-fixtures.mjs +77 -0
- package/ui/preview/dist/garden-ui.esm.js +41 -4
- package/ui/preview/dist/garden-ui.iife.js +41 -4
- package/ui/prompt/rules.md +28 -1
- package/ui/react/components/chart.tsx +1 -1
- package/ui/react/components/display.tsx +1 -1
- package/ui/react/lang.tsx +4 -0
- package/ui/react/parity.tsx +8 -6
- package/worker/index.ts +8 -2
|
@@ -16,6 +16,7 @@ import {
|
|
|
16
16
|
GardenUnknown,
|
|
17
17
|
} from "./blocks";
|
|
18
18
|
import { GardenFile } from "./GardenFile";
|
|
19
|
+
import { GardenChoice, GardenList, GardenRelations } from "./patterns";
|
|
19
20
|
|
|
20
21
|
export function GardenBlock({ dataPayload }: { dataPayload?: string }) {
|
|
21
22
|
const lang = useUiLang();
|
|
@@ -45,6 +46,12 @@ export function GardenBlock({ dataPayload }: { dataPayload?: string }) {
|
|
|
45
46
|
case "file":
|
|
46
47
|
// Post bodies render file cards on the server (MarkdownArticle); this path has no Markdown preview.
|
|
47
48
|
return <GardenFile props={props} lang={lang} />;
|
|
49
|
+
case "relations":
|
|
50
|
+
return <GardenRelations props={props} />;
|
|
51
|
+
case "list":
|
|
52
|
+
return <GardenList props={props} />;
|
|
53
|
+
case "choice":
|
|
54
|
+
return <GardenChoice props={props} />;
|
|
48
55
|
default:
|
|
49
56
|
return <GardenUnknown name={String(block.name)} />;
|
|
50
57
|
}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
// Server component: the card for `garden file`. Only the 预览 control is a client island.
|
|
2
|
-
import { ui, type UiLang } from "../../lib/i18n";
|
|
2
|
+
import { siteLang, ui, type UiLang } from "../../lib/i18n";
|
|
3
3
|
import { blockFiles, fileMeta } from "../../../ui/garden/file-block.mjs";
|
|
4
4
|
import { ActionGlyph, FileGlyph, safeFileHref } from "./file-icons";
|
|
5
5
|
import { FilePreview, type PreviewFile } from "./FilePreview";
|
|
@@ -22,7 +22,7 @@ const PREVIEWS = new Set(["md", "html", "pdf"]);
|
|
|
22
22
|
|
|
23
23
|
export function GardenFile({ props, lang }: { props: Record<string, unknown>; lang?: UiLang }) {
|
|
24
24
|
const t = ui(lang);
|
|
25
|
-
const block = blockFiles(props) as { layout?: string; title?: string; files: FileEntry[] };
|
|
25
|
+
const block = blockFiles(props, lang ?? siteLang) as { layout?: string; title?: string; files: FileEntry[] };
|
|
26
26
|
const files = block.files.filter((file) => safeFileHref(file.url));
|
|
27
27
|
if (!files.length) return null;
|
|
28
28
|
const group = block.layout === "group";
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
|
|
3
|
+
import { Children, isValidElement, useEffect, useRef, useState, type ReactNode } from "react";
|
|
4
|
+
|
|
5
|
+
const LABELS = {
|
|
6
|
+
zh: { preview: "效果", code: "代码", tabs: "示例视图" },
|
|
7
|
+
en: { preview: "Preview", code: "Code", tabs: "Example view" },
|
|
8
|
+
} as const;
|
|
9
|
+
|
|
10
|
+
// Examples on screen right now; while any is visible on a narrow screen the
|
|
11
|
+
// floating contents button steps aside so it never covers code.
|
|
12
|
+
const visible = new Set<Element>();
|
|
13
|
+
const sync = () => document.documentElement.classList.toggle("ref-demo-in", visible.size > 0);
|
|
14
|
+
|
|
15
|
+
/** Code on the left and the real block on the right; tabs below 1024px. */
|
|
16
|
+
export function RefDemo({ children, lang = "zh", name }: { children?: ReactNode; lang?: "zh" | "en"; name?: string }) {
|
|
17
|
+
const t = LABELS[lang];
|
|
18
|
+
const [tab, setTab] = useState<"v" | "c">("v");
|
|
19
|
+
const ref = useRef<HTMLDivElement>(null);
|
|
20
|
+
const [code, preview] = Children.toArray(children).filter(isValidElement);
|
|
21
|
+
|
|
22
|
+
useEffect(() => {
|
|
23
|
+
const el = ref.current;
|
|
24
|
+
if (!el || typeof IntersectionObserver === "undefined") return;
|
|
25
|
+
const io = new IntersectionObserver((entries) => {
|
|
26
|
+
for (const entry of entries) {
|
|
27
|
+
if (entry.isIntersecting) visible.add(entry.target);
|
|
28
|
+
else visible.delete(entry.target);
|
|
29
|
+
}
|
|
30
|
+
sync();
|
|
31
|
+
});
|
|
32
|
+
io.observe(el);
|
|
33
|
+
return () => {
|
|
34
|
+
io.disconnect();
|
|
35
|
+
visible.delete(el);
|
|
36
|
+
sync();
|
|
37
|
+
};
|
|
38
|
+
}, []);
|
|
39
|
+
|
|
40
|
+
const tabButton = (id: "v" | "c", label: string) => (
|
|
41
|
+
<button type="button" role="tab" aria-selected={tab === id} data-t={id} onClick={() => setTab(id)}>
|
|
42
|
+
{label}
|
|
43
|
+
</button>
|
|
44
|
+
);
|
|
45
|
+
|
|
46
|
+
return (
|
|
47
|
+
<div className="ref-demo" ref={ref} data-tab={tab} data-name={name}>
|
|
48
|
+
<div className="ref-tabs" role="tablist" aria-label={t.tabs}>
|
|
49
|
+
{tabButton("v", t.preview)}
|
|
50
|
+
{tabButton("c", t.code)}
|
|
51
|
+
</div>
|
|
52
|
+
<div className="ref-pane" data-p="c" data-off={tab !== "c" ? "" : undefined}>
|
|
53
|
+
<p className="ref-pane-h">{t.code}</p>
|
|
54
|
+
{code}
|
|
55
|
+
</div>
|
|
56
|
+
<div className="ref-pane" data-p="v" data-off={tab !== "v" ? "" : undefined}>
|
|
57
|
+
<p className="ref-pane-h">{t.preview}</p>
|
|
58
|
+
{preview}
|
|
59
|
+
</div>
|
|
60
|
+
</div>
|
|
61
|
+
);
|
|
62
|
+
}
|
|
@@ -10,6 +10,15 @@ import { compileUiBlock } from "../../../ui/core/compile.mjs";
|
|
|
10
10
|
import { splitCompareLine } from "../../../ui/garden/compare-line.mjs";
|
|
11
11
|
import { RuntimeLangProvider, UiErrorCard, UiFigure, type Diagnostic, type UiPayload } from "../../../ui/react";
|
|
12
12
|
import { FullscreenFrame, SandboxFrame } from "./chrome";
|
|
13
|
+
import { SourceMark, VerdictIcon } from "./patterns";
|
|
14
|
+
|
|
15
|
+
const BASE_PATH = (process.env.NEXT_PUBLIC_BASE_PATH ?? "").replace(/\/+$/u, "");
|
|
16
|
+
|
|
17
|
+
/** A `/public` path (`/images/a.svg`) gets the site's basePath in front. */
|
|
18
|
+
function publicSrc(src: string) {
|
|
19
|
+
if (!BASE_PATH || !src.startsWith("/") || src.startsWith("//") || src.startsWith(`${BASE_PATH}/`)) return src;
|
|
20
|
+
return `${BASE_PATH}${src}`;
|
|
21
|
+
}
|
|
13
22
|
|
|
14
23
|
function Rich({ text }: { text: string }) {
|
|
15
24
|
return (
|
|
@@ -33,15 +42,16 @@ function SourceChip({ source }: { source: unknown }) {
|
|
|
33
42
|
if (item && typeof item === "object" && "url" in item) {
|
|
34
43
|
const url = String((item as { url?: unknown }).url ?? "");
|
|
35
44
|
const site = String((item as { site?: unknown }).site ?? hostOf(url));
|
|
36
|
-
|
|
45
|
+
const icon = (item as { icon?: unknown }).icon;
|
|
46
|
+
return { url, site, icon: typeof icon === "string" ? icon : undefined };
|
|
37
47
|
}
|
|
38
48
|
return null;
|
|
39
|
-
}).filter((item): item is { url: string; site: string } => Boolean(item?.url));
|
|
49
|
+
}).filter((item): item is { url: string; site: string; icon?: string } => Boolean(item?.url));
|
|
40
50
|
if (!list.length) return null;
|
|
41
51
|
return (
|
|
42
|
-
<span className="g-srcs">
|
|
52
|
+
<span className={list.length > 1 ? "g-srcs is-multi" : "g-srcs"}>
|
|
43
53
|
<a className="g-src ext" href={list[0].url} target="_blank" rel="noopener noreferrer">
|
|
44
|
-
<
|
|
54
|
+
<SourceMark href={list[0].url} icon={list[0].icon} />
|
|
45
55
|
<span>{list[0].site}</span>
|
|
46
56
|
</a>
|
|
47
57
|
{list.length > 1 ? <span className="g-src-more">+{list.length - 1}</span> : null}
|
|
@@ -54,22 +64,36 @@ function itemsOf(props: Record<string, unknown>) {
|
|
|
54
64
|
}
|
|
55
65
|
|
|
56
66
|
export function GardenCard({ props }: { props: Record<string, unknown> }) {
|
|
67
|
+
if (Array.isArray(props.cards)) {
|
|
68
|
+
return (
|
|
69
|
+
<div className="g-entities">
|
|
70
|
+
{props.cards.map((card, index) => (
|
|
71
|
+
<GardenCardItem key={index} props={(card ?? {}) as Record<string, unknown>} row />
|
|
72
|
+
))}
|
|
73
|
+
</div>
|
|
74
|
+
);
|
|
75
|
+
}
|
|
76
|
+
return <GardenCardItem props={props} />;
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
function GardenCardItem({ props, row = false }: { props: Record<string, unknown>; row?: boolean }) {
|
|
57
80
|
const url = typeof props.url === "string" ? props.url : "";
|
|
58
81
|
const title = String(props.title ?? url);
|
|
59
82
|
const description = typeof props.description === "string" ? props.description : typeof props.text === "string" ? props.text : "";
|
|
60
83
|
const points = Array.isArray(props.points) ? props.points : Array.isArray(props.items) ? props.items : [];
|
|
61
84
|
return (
|
|
62
|
-
<article className="g-entity">
|
|
85
|
+
<article className={`g-entity${row ? " g-entity-row" : ""}`}>
|
|
63
86
|
{typeof props.image === "string" ? (
|
|
64
87
|
<div className="g-entity-img">
|
|
65
88
|
{/* eslint-disable-next-line @next/next/no-img-element */}
|
|
66
|
-
<img src={props.image} alt={String(props.alt ?? title)} />
|
|
89
|
+
<img src={publicSrc(props.image)} alt={String(props.alt ?? title)} />
|
|
67
90
|
</div>
|
|
68
91
|
) : null}
|
|
69
92
|
<div className="g-entity-b">
|
|
70
93
|
<h4 className="g-entity-t">{url ? <a className="ext" href={url} target="_blank" rel="noopener noreferrer"><Rich text={title} /></a> : <Rich text={title} />}</h4>
|
|
71
94
|
{typeof props.meta === "string" ? <p className="g-entity-m"><Rich text={props.meta} /></p> : null}
|
|
72
95
|
{description ? <p><Rich text={description} /> <SourceChip source={props.source} /></p> : null}
|
|
96
|
+
{typeof props.takeaway === "string" ? <p className="g-entity-k"><Rich text={props.takeaway} /></p> : null}
|
|
73
97
|
</div>
|
|
74
98
|
{points.length ? (
|
|
75
99
|
<ol className="g-entity-list">
|
|
@@ -119,8 +143,31 @@ function CompareLine({ line }: { line: string }) {
|
|
|
119
143
|
);
|
|
120
144
|
}
|
|
121
145
|
|
|
146
|
+
function verdictOf(entry: unknown) {
|
|
147
|
+
if (!entry || typeof entry !== "object") return "";
|
|
148
|
+
const value = String((entry as Record<string, unknown>).verdict ?? "").trim().toLowerCase();
|
|
149
|
+
return value === "good" || value === "bad" ? value : "";
|
|
150
|
+
}
|
|
151
|
+
|
|
122
152
|
export function GardenCompare({ props }: { props: Record<string, unknown> }) {
|
|
123
153
|
const items = Array.isArray(props.items) ? props.items as unknown[] : [];
|
|
154
|
+
if (items.some((entry) => verdictOf(entry))) {
|
|
155
|
+
return (
|
|
156
|
+
<div className="g-verdicts" role="group">
|
|
157
|
+
{items.map((entry, index) => {
|
|
158
|
+
const item = (entry && typeof entry === "object" ? entry : { text: String(entry ?? "") }) as Record<string, unknown>;
|
|
159
|
+
const verdict = verdictOf(item);
|
|
160
|
+
const texts = item.text == null ? [] : Array.isArray(item.text) ? item.text : [item.text];
|
|
161
|
+
return (
|
|
162
|
+
<section className={`g-verdict${verdict ? ` is-${verdict}` : ""}`} key={index}>
|
|
163
|
+
<h4><VerdictIcon verdict={verdict} /><Rich text={String(item.title ?? "")} /></h4>
|
|
164
|
+
{texts.map((paragraph, paragraphIndex) => <p key={paragraphIndex}><Rich text={String(paragraph)} /></p>)}
|
|
165
|
+
</section>
|
|
166
|
+
);
|
|
167
|
+
})}
|
|
168
|
+
</div>
|
|
169
|
+
);
|
|
170
|
+
}
|
|
124
171
|
return (
|
|
125
172
|
<div className="g-compare" role="group">
|
|
126
173
|
{items.map((entry, index) => {
|
|
@@ -128,7 +175,8 @@ export function GardenCompare({ props }: { props: Record<string, unknown> }) {
|
|
|
128
175
|
return <section className="g-cmp" key={index}><CompareLine line={String(entry)} /></section>;
|
|
129
176
|
}
|
|
130
177
|
if (!entry || typeof entry !== "object") return null;
|
|
131
|
-
const { title, text, ...rest } = entry as Record<string, unknown>;
|
|
178
|
+
const { title, text, verdict: _verdict, ...rest } = entry as Record<string, unknown>;
|
|
179
|
+
void _verdict;
|
|
132
180
|
const texts = text == null ? [] : Array.isArray(text) ? text : [text];
|
|
133
181
|
return (
|
|
134
182
|
<section className="g-cmp" key={index}>
|
|
@@ -316,7 +364,7 @@ export function GardenFigure({ props, children }: { props: Record<string, unknow
|
|
|
316
364
|
{typeof props.image === "string" ? (
|
|
317
365
|
<div className="fig-card">
|
|
318
366
|
{/* eslint-disable-next-line @next/next/no-img-element */}
|
|
319
|
-
<img src={props.image} alt={String(props.alt ?? props.caption ?? "")} />
|
|
367
|
+
<img src={publicSrc(props.image)} alt={String(props.alt ?? props.caption ?? "")} />
|
|
320
368
|
</div>
|
|
321
369
|
) : null}
|
|
322
370
|
{typeof props.mermaid === "string" ? <pre className="code"><code>{props.mermaid}</code></pre> : null}
|