hd-garden 0.7.0 → 0.8.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.
Files changed (110) hide show
  1. package/.agents/skills/garden-ui/SKILL.md +26 -19
  2. package/README.en.md +57 -0
  3. package/README.md +31 -46
  4. package/app/blog/[...path]/page.tsx +9 -1
  5. package/app/columns/[column]/[...path]/page.tsx +10 -12
  6. package/app/components/ArticlePager.tsx +32 -0
  7. package/app/components/Comments.tsx +2 -1
  8. package/app/components/FeedMore.tsx +70 -0
  9. package/app/components/GardenDocsNav.tsx +25 -20
  10. package/app/components/HandbookLangRedirect.tsx +30 -0
  11. package/app/components/HandbookLangSwitch.tsx +49 -0
  12. package/app/components/HandbookView.tsx +187 -0
  13. package/app/components/MarkdownArticle.tsx +11 -5
  14. package/app/components/MarkdownImage.tsx +6 -4
  15. package/app/components/SiteChrome.tsx +11 -2
  16. package/app/components/SiteFooter.tsx +5 -3
  17. package/app/components/SiteHeader.tsx +27 -23
  18. package/app/components/TableOfContents.tsx +15 -9
  19. package/app/components/ThoughtFeed.tsx +41 -0
  20. package/app/components/UiLang.tsx +18 -0
  21. package/app/components/Webmentions.tsx +3 -2
  22. package/app/components/garden/FilePreview.tsx +13 -11
  23. package/app/components/garden/GardenBlock.tsx +3 -1
  24. package/app/components/garden/GardenFile.tsx +9 -7
  25. package/app/components/garden/blocks.tsx +34 -24
  26. package/app/components/garden/chrome.tsx +20 -13
  27. package/app/garden/[...slug]/page.tsx +10 -130
  28. package/app/garden/en/[...slug]/page.tsx +28 -0
  29. package/app/garden/en/page.tsx +16 -0
  30. package/app/garden/page.tsx +7 -74
  31. package/app/garden-modules.d.ts +3 -0
  32. package/app/layout.tsx +2 -4
  33. package/app/lib/content.ts +12 -2
  34. package/app/lib/garden-docs-meta.ts +60 -5
  35. package/app/lib/handbook-path.ts +11 -0
  36. package/app/lib/i18n.ts +222 -0
  37. package/app/lib/page-alternates.ts +2 -2
  38. package/app/not-found.tsx +5 -3
  39. package/app/site.config.ts +1 -1
  40. package/app/styles/a2.css +101 -32
  41. package/app/styles/shell.css +6 -0
  42. package/app/thoughts/page/[n]/page.tsx +44 -0
  43. package/app/thoughts/page.tsx +2 -6
  44. package/bin/garden.mjs +4 -0
  45. package/docs/handbook/ai-writing.md +99 -0
  46. package/docs/handbook/components/card.md +2 -0
  47. package/docs/handbook/components/chart.md +2 -0
  48. package/docs/handbook/components/compare.md +10 -12
  49. package/docs/handbook/components/figure.md +2 -0
  50. package/docs/handbook/components/file.md +2 -0
  51. package/docs/handbook/components/html.md +2 -0
  52. package/docs/handbook/components/interactive.md +2 -0
  53. package/docs/handbook/components/stat.md +2 -0
  54. package/docs/handbook/components/timeline.md +2 -0
  55. package/docs/handbook/components.md +1 -1
  56. package/docs/handbook/config.md +2 -2
  57. package/docs/handbook/deploy.md +1 -1
  58. package/docs/handbook/design.md +3 -3
  59. package/docs/handbook/en/ai-writing.md +99 -0
  60. package/docs/handbook/en/components/card.md +46 -0
  61. package/docs/handbook/en/components/chart.md +54 -0
  62. package/docs/handbook/en/components/compare.md +38 -0
  63. package/docs/handbook/en/components/figure.md +72 -0
  64. package/docs/handbook/en/components/file/checklist.md +17 -0
  65. package/docs/handbook/en/components/file.md +34 -0
  66. package/docs/handbook/en/components/html.md +69 -0
  67. package/docs/handbook/en/components/interactive.md +67 -0
  68. package/docs/handbook/en/components/stat.md +57 -0
  69. package/docs/handbook/en/components/timeline.md +52 -0
  70. package/docs/handbook/en/components.md +30 -0
  71. package/docs/handbook/en/config.md +125 -0
  72. package/docs/handbook/en/deploy.md +273 -0
  73. package/docs/handbook/en/design.md +81 -0
  74. package/docs/handbook/en/index.md +192 -0
  75. package/docs/handbook/en/start.md +92 -0
  76. package/docs/handbook/en/workflow.md +81 -0
  77. package/docs/handbook/en/writing.md +156 -0
  78. package/docs/handbook/index.md +98 -3
  79. package/docs/handbook/writing.md +18 -10
  80. package/package.json +1 -1
  81. package/scripts/build-content.mjs +23 -3
  82. package/scripts/handbook-facts.mjs +34 -0
  83. package/scripts/html-lang.mjs +36 -0
  84. package/scripts/static-404.mjs +25 -0
  85. package/scripts/ui-cli.mjs +14 -8
  86. package/templates/site/site.config.yaml +2 -0
  87. package/ui/core/apply.mjs +22 -4
  88. package/ui/core/cli-locale.mjs +67 -0
  89. package/ui/core/fence.mjs +18 -3
  90. package/ui/core/fix-prompt.mjs +18 -15
  91. package/ui/core/garden-fence.mjs +64 -0
  92. package/ui/core/scan.mjs +19 -3
  93. package/ui/garden/adjacent.mjs +21 -0
  94. package/ui/garden/check.mjs +6 -0
  95. package/ui/garden/html-lang.mjs +16 -0
  96. package/ui/garden/paging.mjs +30 -0
  97. package/ui/preview/dist/garden-ui.css +9 -9
  98. package/ui/preview/dist/garden-ui.esm.js +169 -169
  99. package/ui/preview/dist/garden-ui.iife.js +169 -169
  100. package/ui/react/components/chart.tsx +7 -4
  101. package/ui/react/components/display.tsx +6 -3
  102. package/ui/react/components/inputs.tsx +6 -3
  103. package/ui/react/components/layout.tsx +6 -4
  104. package/ui/react/components/media.tsx +7 -4
  105. package/ui/react/components/sandbox.tsx +3 -1
  106. package/ui/react/index.tsx +11 -7
  107. package/ui/react/lang.tsx +85 -0
  108. package/ui/react/runtime.tsx +3 -1
  109. package/ui/react/ui.css +9 -9
  110. package/worker/index.ts +8 -1
@@ -0,0 +1,34 @@
1
+ ---
2
+ title: File Download & Preview (file)
3
+ navTitle: file
4
+ description: Attach one or more files with automatic format and size badges, download links, and inline preview.
5
+ section: components
6
+ order: 39
7
+ badge: file
8
+ ---
9
+
10
+ Write "use `file` to attach a pre-publish checklist that readers can preview inline or download" inside a `garden` idea block, and the Agent generates the `garden file` block below via the `garden-ui` skill (hand-written syntax follows).
11
+
12
+ ```garden file
13
+ src: ./file/checklist.md
14
+ title: Pre-publish Checklist
15
+ note: Sample Markdown attachment; click Preview to read inline or Download to save the file
16
+ ```
17
+
18
+ ````markdown
19
+ ```garden file
20
+ src: ./file/checklist.md
21
+ title: Pre-publish Checklist
22
+ note: Sample Markdown attachment; click Preview to read inline or Download to save the file
23
+ ```
24
+ ````
25
+
26
+ - **Use when**: Attaching config files, datasets, PDFs, images, or Markdown documents for readers to download or preview inline (use `files` for multiple attachments).
27
+ - **Skip when**: Showing a regular illustration in the middle of an article; use standard Markdown image syntax `![]()` instead.
28
+
29
+ | Field | Required | Type | Description |
30
+ | :--- | :--- | :--- | :--- |
31
+ | `src` | Required for single file | path or URL | Relative path (must stay inside the content root), `/public` path, or `https://` URL |
32
+ | `title` | No | string | Display title (defaults to filename; serves as the group heading when using `files`) |
33
+ | `note` | No | string | Short note shown below the filename |
34
+ | `files` | Required for multi-file | `{ src, title?, note? }[]` | List of multiple attachments (mutually exclusive with top-level `src`) |
@@ -0,0 +1,69 @@
1
+ ---
2
+ title: Embedded Web Snippet (html)
3
+ navTitle: html
4
+ description: Run a self-contained HTML, CSS, and JavaScript demo inside a sandboxed iframe.
5
+ section: components
6
+ order: 37
7
+ badge: html
8
+ ---
9
+
10
+ Write "use `html` to embed a small widget that counts characters as the reader types" inside a `garden` idea block, and the Agent generates the `garden html` block below via the `garden-ui` skill (hand-written syntax follows).
11
+
12
+ ```garden html
13
+ title: Character Count Widget
14
+ height: 156
15
+ code: |
16
+ <!doctype html>
17
+ <html lang="en">
18
+ <head>
19
+ <meta charset="utf-8" />
20
+ <style>
21
+ body { margin: 0; padding: 16px 18px; font: 14px/1.6 system-ui, sans-serif; color: #1b1a18; background: #faf9f5; }
22
+ input { width: 100%; box-sizing: border-box; padding: 8px 10px; border: 1px solid #d5d1c8; border-radius: 6px; font: inherit; background: #fff; color: #1b1a18; }
23
+ .meta { margin-top: 10px; color: #6e6b64; font-variant-numeric: tabular-nums; }
24
+ strong { color: #1b1a18; }
25
+ </style>
26
+ </head>
27
+ <body>
28
+ <input id="txt" value="Keep your posts in a Git repository and push to deploy." aria-label="Sample text input" />
29
+ <div class="meta">Characters: <strong id="count">55</strong></div>
30
+ <script>
31
+ const input = document.getElementById("txt");
32
+ const count = document.getElementById("count");
33
+ input.addEventListener("input", () => { count.textContent = String(input.value.length); });
34
+ </script>
35
+ </body>
36
+ </html>
37
+ ```
38
+
39
+ ````markdown
40
+ ```garden html
41
+ title: Character Count Widget
42
+ height: 156
43
+ code: |
44
+ <!doctype html>
45
+ <html lang="en">
46
+ <head><meta charset="utf-8" /></head>
47
+ <body>
48
+ <input id="txt" value="Keep your posts in a Git repository and push to deploy." />
49
+ <div>Characters: <strong id="count">55</strong></div>
50
+ <script>
51
+ const input = document.getElementById("txt");
52
+ const count = document.getElementById("count");
53
+ input.addEventListener("input", () => { count.textContent = String(input.value.length); });
54
+ </script>
55
+ </body>
56
+ </html>
57
+ ```
58
+ ````
59
+
60
+ - **Use when**: Running custom DOM scripts, Canvas drawings, or self-contained HTML snippets (either inline via `code` or loaded from a sibling `.html` file via `src`).
61
+ - **Skip when**: You only need sliders wired to a formula (use [`interactive`](/garden/en/components/interactive)) or a diagram with clickable regions (use [`figure`](/garden/en/components/figure)).
62
+
63
+ | Field | Required | Type | Description |
64
+ | :--- | :--- | :--- | :--- |
65
+ | `src` | Either this or `code` | relative path | Path to a `.html` file in the same directory or sibling asset directory |
66
+ | `code` | Either this or `src` | multiline string | Inline HTML markup (alias `html` is also accepted) |
67
+ | `title` | Recommended | string | Header bar title and accessible `iframe` title |
68
+ | `height` | No | number | Initial height in pixels (defaults to `260`; resizes to fit content after load) |
69
+ | `caption` | No | string | Caption shown below the frame |
@@ -0,0 +1,67 @@
1
+ ---
2
+ title: Interactive Formula & Parameters (interactive)
3
+ navTitle: interactive
4
+ description: Let readers drag sliders or switches to recalculate formulas and charts in real time.
5
+ section: components
6
+ order: 38
7
+ badge: interactive
8
+ ---
9
+
10
+ Write "let readers drag word count, reading speed, and image count sliders to see how estimated reading time changes" inside a `garden` idea block, and the Agent generates the `garden interactive` block below via the `garden-ui` skill (hand-written syntax follows).
11
+
12
+ ```garden interactive #reading-time
13
+ caption: "Example: estimate reading time from word count, reading speed, and image count. Numbers are illustrative only."
14
+ ---
15
+ <State words={6000} speed={400} images={8} />
16
+ <Let textMinutes={round(words / speed)} />
17
+ <Let imageMinutes={round(images * 12 / 60)} />
18
+ <Let parts={[{ part: "Prose", minutes: textMinutes }, { part: "Images", minutes: imageMinutes }]} />
19
+
20
+ <Slider bind="words" label="Word count" min={1000} max={20000} step={500} unit="words" />
21
+ <Slider bind="speed" label="Reading speed" min={200} max={800} step={50} unit="wpm" />
22
+ <Slider bind="images" label="Image count" min={0} max={30} step={1} unit="images" />
23
+
24
+ <Stat label="Example: estimated reading time" value={textMinutes + imageMinutes} unit="min" hint="Counting 12 seconds per image" />
25
+ <Chart data={parts} x={part} yLabel="min">
26
+ <Bar y={minutes} label="Example" />
27
+ </Chart>
28
+ ```
29
+
30
+ ````markdown
31
+ ```garden interactive #reading-time
32
+ caption: "Example: estimate reading time from word count, reading speed, and image count. Numbers are illustrative only."
33
+ ---
34
+ <State words={6000} speed={400} images={8} />
35
+ <Let textMinutes={round(words / speed)} />
36
+ <Let imageMinutes={round(images * 12 / 60)} />
37
+ <Let parts={[{ part: "Prose", minutes: textMinutes }, { part: "Images", minutes: imageMinutes }]} />
38
+
39
+ <Slider bind="words" label="Word count" min={1000} max={20000} step={500} unit="words" />
40
+ <Slider bind="speed" label="Reading speed" min={200} max={800} step={50} unit="wpm" />
41
+ <Slider bind="images" label="Image count" min={0} max={30} step={1} unit="images" />
42
+
43
+ <Stat label="Example: estimated reading time" value={textMinutes + imageMinutes} unit="min" hint="Counting 12 seconds per image" />
44
+ <Chart data={parts} x={part} yLabel="min">
45
+ <Bar y={minutes} label="Example" />
46
+ </Chart>
47
+ ```
48
+ ````
49
+
50
+ - **Use when**: Explaining a multi-variable formula, capacity estimate, or parameter tradeoff where dragging a slider reveals how the output responds.
51
+ - **Skip when**: A block has only `<Steps>` without any state or input control (fails with `steps-prose`), or every `<Let>` is a single multiplication like `a * b` (fails with `interactive-trivial`). Write plain prose in both cases.
52
+
53
+ Metadata goes above `---`, and declarative tags go below it:
54
+
55
+ | Field or Tag | Required | Description |
56
+ | :--- | :--- | :--- |
57
+ | `#reading-time` | Recommended | Block identifier on the fence line (lowercase letters, digits, and hyphens) |
58
+ | `caption` | Yes | One sentence explaining what the reader can observe |
59
+ | `intent` | No | The original natural-language prompt this block was compiled from |
60
+ | `expect` | No | Array of `{ given: {...}, name: expectedValue }` assertions checked by `garden ui check` |
61
+ | `<State />` | Yes | Declares mutable state variables and their initial values, e.g. `<State words={6000} />` |
62
+ | `<Let />` | No | Computes derived values or data arrays from state |
63
+ | `<Slider />` / `<Choice />` / `<Toggle />` | Yes | Input controls bound to a state variable via `bind`; `Slider` requires `label`, `min`, and `max` |
64
+ | `<Stat />` | No | Displays a highlighted computed value; requires `label` and `value` |
65
+ | `<Chart />` | No | Plots a function curve with `sweep` or a bar/line chart with `data` and `<Bar>` / `<Line>` |
66
+
67
+ Run `npx garden ui catalog` to inspect the full tag and attribute reference in `.garden/ui-catalog.html`.
@@ -0,0 +1,57 @@
1
+ ---
2
+ title: Key Figures (stat)
3
+ navTitle: stat
4
+ description: Display 2 to 4 key numbers, units, and short captions side by side.
5
+ section: components
6
+ order: 32
7
+ badge: stat
8
+ ---
9
+
10
+ Write "use `stat` to list the width limits for the prose column, wide figures, and wide tables" inside a `garden` idea block, and the Agent generates the `garden stat` block below via the `garden-ui` skill (hand-written syntax follows).
11
+
12
+ ```garden stat
13
+ items:
14
+ - label: Reading Column
15
+ value: "740"
16
+ unit: px
17
+ caption: Default prose column width
18
+ - label: Wide Figure Limit
19
+ value: "1040"
20
+ unit: px
21
+ caption: Extends up to 150px on each side
22
+ - label: Wide Table Limit
23
+ value: "1340"
24
+ unit: px
25
+ caption: Extends up to 300px on each side
26
+ ```
27
+
28
+ ````markdown
29
+ ```garden stat
30
+ items:
31
+ - label: Reading Column
32
+ value: "740"
33
+ unit: px
34
+ caption: Default prose column width
35
+ - label: Wide Figure Limit
36
+ value: "1040"
37
+ unit: px
38
+ caption: Extends up to 150px on each side
39
+ - label: Wide Table Limit
40
+ value: "1340"
41
+ unit: px
42
+ caption: Extends up to 300px on each side
43
+ ```
44
+ ````
45
+
46
+ - **Use when**: Pulling 2 to 4 core numbers, thresholds, or specs out of prose so readers can scan them side by side.
47
+ - **Skip when**: You only have one number (keep it in prose) or you have multiple rows and columns (use a Markdown table).
48
+
49
+ | Field | Required | Type | Description |
50
+ | :--- | :--- | :--- | :--- |
51
+ | `items` | No | object[] | Array of stat items; for a single stat you can place the fields at the top level |
52
+ | `label` | Yes | string | Metric name shown above the number |
53
+ | `value` | Yes | string or number | Primary figure rendered in large tabular type |
54
+ | `unit` | No | string | Unit shown immediately to the right of `value` |
55
+ | `caption` | No | string | Short note below the figure |
56
+ | `text` | No | string | Additional explanatory text |
57
+ | `source` | No | string or `{ title, url }` | Source attribution badge |
@@ -0,0 +1,52 @@
1
+ ---
2
+ title: Step Timeline (timeline)
3
+ navTitle: timeline
4
+ description: Order release milestones, incident steps, or build stages along a vertical sequence.
5
+ section: components
6
+ order: 34
7
+ badge: timeline
8
+ ---
9
+
10
+ Write "use `timeline` to list the three stages of the static publishing pipeline in order" inside a `garden` idea block, and the Agent generates the `garden timeline` block below via the `garden-ui` skill (hand-written syntax follows).
11
+
12
+ ```garden timeline
13
+ title: Static Publishing Pipeline Stages
14
+ items:
15
+ - date: Step 1
16
+ title: Sync Content and Assets
17
+ text: Run `npx garden sync` to validate Front Matter, copy image attachments, and generate the search index and RSS feed.
18
+ - date: Step 2
19
+ title: Build Static Site Output
20
+ text: Run `STATIC_EXPORT=1 npx garden build` to prerender every route into `dist/client/`.
21
+ - date: Step 3
22
+ title: Validate Output and Deploy
23
+ text: Run `npm run pages:validate` to confirm `index.html` exists and no `.env`, source directories, `.map` or `.md` files, or symlinks were included, then publish to GitHub Pages.
24
+ ```
25
+
26
+ ````markdown
27
+ ```garden timeline
28
+ title: Static Publishing Pipeline Stages
29
+ items:
30
+ - date: Step 1
31
+ title: Sync Content and Assets
32
+ text: Run `npx garden sync` to validate Front Matter, copy image attachments, and generate the search index and RSS feed.
33
+ - date: Step 2
34
+ title: Build Static Site Output
35
+ text: Run `STATIC_EXPORT=1 npx garden build` to prerender every route into `dist/client/`.
36
+ - date: Step 3
37
+ title: Validate Output and Deploy
38
+ text: Run `npm run pages:validate` to confirm `index.html` exists and no `.env`, source directories, `.map` or `.md` files, or symlinks were included, then publish to GitHub Pages.
39
+ ```
40
+ ````
41
+
42
+ - **Use when**: Walking through incident timestamps, evolution stages, or pipeline steps in chronological order (at least 2 items).
43
+ - **Skip when**: Listing unordered points with no sequence; use a regular bullet list instead.
44
+
45
+ | Field | Required | Type | Description |
46
+ | :--- | :--- | :--- | :--- |
47
+ | `title` | No | string | Heading above the timeline |
48
+ | `items` | Yes | object[] (at least 2) | Ordered list of steps |
49
+ | `items[].date` | No | string | Timestamp, stage label, or step number above the item title |
50
+ | `items[].title` | Yes | string | Step heading |
51
+ | `items[].text` | No | string | Detailed explanation for the step |
52
+ | `items[].source` | No | string or `{ title, url }` | Source attribution badge |
@@ -0,0 +1,30 @@
1
+ ---
2
+ title: Components Overview
3
+ navTitle: Overview
4
+ description: What each of the 9 built-in garden components is for, its fence name, and its required fields.
5
+ section: components
6
+ order: 30
7
+ ---
8
+
9
+ You can describe any of these 9 components in a single sentence inside a `garden` idea block and let your Agent generate the block with the `garden-ui` skill (see [Writing with AI](/garden/en/ai-writing)). When writing by hand, open a ```` ```garden <name> ```` code block with the English component name (`card`, `stat`, `compare`, `timeline`, `chart`, `figure`, `html`, `interactive`, or `file`); parameters use YAML, while `interactive` takes declarative tags below `---`.
10
+
11
+ ## Component Quick Reference
12
+
13
+ | Component | Code Fence | When to Use | Minimum Requirement |
14
+ | :--- | :--- | :--- | :--- |
15
+ | [card](/garden/en/components/card) | ```` ```garden card ```` | Summarize a paper, open-source project, or subsystem | Provide `description` or `points` |
16
+ | [stat](/garden/en/components/stat) | ```` ```garden stat ```` | Place 2 to 4 key numbers and units side by side | Each item requires `label` and `value` |
17
+ | [compare](/garden/en/components/compare) | ```` ```garden compare ```` | Compare 2 or 3 options or before/after tradeoffs side by side | At least 2 `items`, ~60 characters per cell |
18
+ | [timeline](/garden/en/components/timeline) | ```` ```garden timeline ```` | Walk through debugging steps or release stages in order | At least 2 `items` |
19
+ | [chart](/garden/en/components/chart) | ```` ```garden chart ```` | Plot proportional bars from YAML rows (includes an expandable table) | At least 2 rows in `data` |
20
+ | [figure](/garden/en/components/figure) | ```` ```garden figure ```` | Highlight regions of an SVG or image diagram with step buttons | Either `svg` or `image` |
21
+ | [html](/garden/en/components/html) | ```` ```garden html ```` | Run a self-contained HTML/JS demo in a sandboxed `iframe` | Either `src` or `code` |
22
+ | [interactive](/garden/en/components/interactive) | ```` ```garden interactive ```` | Let readers drag sliders or switches to evaluate a non-trivial formula | Must include an input control and a formula beyond a single multiplication |
23
+ | [file](/garden/en/components/file) | ```` ```garden file ```` | Offer local or remote attachments for download and inline preview | Either `src` or `files` |
24
+
25
+ ## Authoring Rules
26
+
27
+ 1. **Use standard Markdown first**: Write regular paragraphs, ordered lists, and comparison tables in plain Markdown, and reach for a `garden` fence only when a structured block makes the point easier to read.
28
+ 2. **Do not duplicate the same numbers**: A `chart` block already includes an expandable data table underneath, so do not put a second Markdown table with the same figures in the same section.
29
+ 3. **Inline formatting works inside fields**: Text fields such as `text`, `description`, `caption`, and `points` accept inline `**bold**`, `` `code` ``, and `<u>highlighter underline</u>`.
30
+ 4. **Preview every component locally**: Run `npx garden ui catalog` to generate `.garden/ui-catalog.html` and open it in your browser.
@@ -0,0 +1,125 @@
1
+ ---
2
+ title: Site & Column Config
3
+ navTitle: Site & Column Config
4
+ description: Configure site metadata, page headings, and brand icons in site.config.yaml, and organize series in content/columns.yaml.
5
+ section: getting-started
6
+ order: 3
7
+ ---
8
+
9
+ Global site copy and appearance settings live in `site.config.yaml` at the repository root, while series definitions live in `content/columns.yaml`. Run `npx garden sync` (or `make dev`) after editing to apply changes.
10
+
11
+ ## 1. Full `site.config.yaml` Structure
12
+
13
+ Here is the default `site.config.yaml` shipped with the site template:
14
+
15
+ ```yaml
16
+ name: Garden
17
+ tagline: 写作 · 记录 · 保持好奇
18
+ description: 文章、随想和专栏。
19
+ locale: zh_CN
20
+ # 站点的公开地址。文章里指向这个地址的完整网址会按站内链接显示。
21
+ # url: https://blog.example.com
22
+ # 站点图标,不写时使用 Garden 自带的图标。
23
+ # brand:
24
+ # logo: brand/logo.svg
25
+ # favicon: /favicon.svg
26
+ # appleTouchIcon: /apple-touch-icon.png
27
+
28
+ author:
29
+ name: Your Name
30
+ github: your-github-id
31
+ githubBio: 一句自我介绍。
32
+ githubPinned: []
33
+
34
+ pages:
35
+ home:
36
+ title: |-
37
+ 记一些正在做的事,
38
+ 和想清楚的问题。
39
+ subtitle: 软件、笔记,和偶尔的工作记录。
40
+ blog:
41
+ title: 博文
42
+ subtitle: 写完的长文。
43
+ thoughts:
44
+ title: 随想
45
+ subtitle: 短笔记、图片和链接。
46
+ columns:
47
+ title: 专栏
48
+ subtitle: 按顺序读的一组文章。
49
+ about:
50
+ title: 你好,我是 Your Name。
51
+ subtitle: 文章和笔记都在这里。
52
+ heading: 关于
53
+ paragraphs:
54
+ - 一名工程师。平时写代码,也把想清楚的问题记下来。
55
+ - 这里放文章、随想和专栏。
56
+ quote: ""
57
+ focus:
58
+ - 软件
59
+ - 笔记
60
+ - 日常
61
+ cta:
62
+ href: /blog
63
+ label: 浏览博文
64
+ garden:
65
+ title: "用 Markdown 写。\n推送之后,网站自己更新。"
66
+ subtitle: ""
67
+
68
+ footer: 持续记录。
69
+ ```
70
+
71
+ ### Top-level and Author Fields
72
+
73
+ | Field | Description |
74
+ | :--- | :--- |
75
+ | `name` | Site name shown in the top-left header, browser title suffix, and RSS feed title |
76
+ | `tagline` | Site tagline |
77
+ | `description` | Site summary used for the home page SEO description and RSS channel description |
78
+ | `locale` | Language and region tag (`zh_CN` by default; setting `en_US` switches the site chrome to English at build time) |
79
+ | `url` | Public root URL of the site (such as `https://blog.example.com`). Full URLs pointing to this address inside posts are treated as internal links |
80
+ | `author.name` | Author name displayed in article metadata, the About page, and the footer |
81
+ | `author.github` | GitHub username (without the full URL), used to link your GitHub profile and fetch public activity for the About page |
82
+ | `author.githubBio` | Fallback bio used when the build environment has no `GITHUB_TOKEN` |
83
+ | `author.githubPinned` | Fallback list of pinned repositories when `GITHUB_TOKEN` is not set locally |
84
+ | `footer` | Short signature text in the footer |
85
+
86
+ > [!NOTE] Note
87
+ > Trailing slashes on internal URLs are not configured in `site.config.yaml`: static exports (`STATIC_EXPORT=1`) always enable trailing slashes, and server builds can enable them with `TRAILING_SLASH=1`.
88
+
89
+ ### `pages` Top-level Page Headings
90
+
91
+ Each key under `pages` sets the header copy for a top-level route:
92
+
93
+ - **`pages.home`, `pages.blog`, `pages.thoughts`, `pages.columns`, `pages.garden`**: Each accepts `title` and `subtitle`. On `/garden/`, the Chinese overview page reads `pages.garden.title` (splitting into two lines on ` | `) and `pages.garden.subtitle`.
94
+ - **`pages.about`**: Alongside `title` and `subtitle`, supports `heading` (section heading), `paragraphs` (array of paragraphs), `quote` (pull quote), `focus` (array of topic tags), and `cta` (`{ href, label }` button).
95
+
96
+ ### `brand` Custom Icons and Redirects
97
+
98
+ - **`brand.logo`**: SVG mark placed to the left of the site name in the header. Resolved relative to the site root (for example `brand/logo.svg`), sanitized and inlined at build time so it inherits `currentColor`. Set to `false` to hide the header mark.
99
+ - **`brand.favicon` and `brand.appleTouchIcon`**: Paths served from `public/` (such as `/favicon.svg` and `/apple-touch-icon.png`); set `appleTouchIcon` to `false` to omit the tag.
100
+ - **`redirects`**: Top-level map in `site.config.yaml` for moved posts (for example `"/2024/01/20/old-post/": "/blog/new-post/"`). The build emits redirect pages at the old paths and rewrites matching internal links inside post bodies to the new destination.
101
+
102
+ ## 2. Configuring Columns (`content/columns.yaml`)
103
+
104
+ Columns group multiple posts from `content/posts/` into an ordered reading series. Edit `content/columns.yaml`:
105
+
106
+ ```yaml
107
+ columns:
108
+ - slug: building-in-public
109
+ title: Building in Public
110
+ status: Ongoing
111
+ description: Notes from initial prototype to production release.
112
+ cover: windowsill-herbs.svg
113
+ posts:
114
+ - building-in-public/smallest-closed-loop
115
+ - building-in-public/ship-with-evidence
116
+ ```
117
+
118
+ | Field | Required | Description |
119
+ | :--- | :--- | :--- |
120
+ | `slug` | Yes | Column identifier (lowercase letters, digits, and hyphens only), generating routes at `/columns/<slug>/<post>` |
121
+ | `title` | Yes | Column title (also shown beside member posts on `/blog`) |
122
+ | `description` | Yes | Column summary shown on `/columns` cards |
123
+ | `status` | No | Status badge text |
124
+ | `cover` | No | Cover image path relative to `content/covers/` |
125
+ | `posts` | Yes | Ordered array of post paths relative to `content/posts/`, without the `.md` extension |