hd-garden 0.4.1 → 0.5.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 (55) hide show
  1. package/.agents/skills/garden-interactive-chart/SKILL.md +5 -5
  2. package/Makefile +2 -3
  3. package/app/a2/[slug]/page.tsx +0 -1
  4. package/app/a2/page.tsx +1 -1
  5. package/app/about/page.tsx +8 -12
  6. package/app/admin/page.tsx +2 -2
  7. package/app/blog/[...path]/page.tsx +2 -12
  8. package/app/blog/page.tsx +2 -2
  9. package/app/columns/[column]/[...path]/page.tsx +2 -3
  10. package/app/columns/page.tsx +2 -2
  11. package/app/components/AdminDashboard.tsx +3 -3
  12. package/app/components/ArticleMeasure.tsx +114 -42
  13. package/app/components/ArticleTags.tsx +17 -0
  14. package/app/components/BlogArchive.tsx +85 -33
  15. package/app/components/ContentEmptyState.tsx +6 -6
  16. package/app/components/GardenAdminGuide.tsx +1 -1
  17. package/app/components/GardenContentGuide.tsx +1 -2
  18. package/app/components/GardenMediaGuide.tsx +3 -3
  19. package/app/components/GithubProfile.tsx +1 -1
  20. package/app/components/MarkdownImage.tsx +4 -2
  21. package/app/components/SiteFooter.tsx +5 -5
  22. package/app/components/SiteHeader.tsx +1 -5
  23. package/app/components/TagRedirect.tsx +17 -0
  24. package/app/garden/page.tsx +6 -6
  25. package/app/garden-modules.d.ts +0 -1
  26. package/app/globals.css +19 -101
  27. package/app/lib/a2-meta.ts +10 -0
  28. package/app/lib/a2-preview.ts +0 -2
  29. package/app/lib/content.ts +10 -7
  30. package/app/lib/fallback-site-config.ts +15 -15
  31. package/app/lib/generated-content.ts +58 -47
  32. package/app/lib/tag-filter.ts +114 -0
  33. package/app/not-found.tsx +13 -0
  34. package/app/page.tsx +9 -26
  35. package/app/styles/a2.css +96 -15
  36. package/app/styles/shell.css +54 -59
  37. package/app/styles/tokens.css +35 -22
  38. package/app/tags/page.tsx +20 -9
  39. package/package.json +1 -1
  40. package/scripts/build-content.mjs +3 -3
  41. package/scripts/check-post.mjs +0 -3
  42. package/scripts/new-post.mjs +1 -3
  43. package/site.config.yaml +15 -15
  44. package/templates/site/Makefile +2 -3
  45. package/templates/site/site.config.yaml +15 -15
  46. package/ui/garden/check.mjs +2 -4
  47. package/ui/garden/enhance.mjs +57 -0
  48. package/ui/garden/title.mjs +5 -8
  49. package/ui/host.mjs +13 -13
  50. package/ui/preview/dist/garden-ui.css +11 -11
  51. package/ui/preview/dist/garden-ui.esm.js +6 -6
  52. package/ui/preview/dist/garden-ui.iife.js +7 -7
  53. package/ui/react/components/media.tsx +2 -2
  54. package/ui/react/ui.css +11 -11
  55. package/app/components/TagIndex.tsx +0 -97
@@ -6,25 +6,25 @@ import { ArrowRight, Article, Books, Quotes } from "@phosphor-icons/react/ssr";
6
6
  const emptyContent = {
7
7
  posts: {
8
8
  icon: Article,
9
- eyebrow: "NO POSTS YET / 暂无博文",
9
+ eyebrow: "暂无博文",
10
10
  title: "暂无博文。",
11
- description: "发布文章后会在这里按主题与时间归档。",
11
+ description: "文章会按时间排在这里。",
12
12
  actionHref: "/",
13
13
  actionLabel: "返回首页",
14
14
  },
15
15
  thoughts: {
16
16
  icon: Quotes,
17
- eyebrow: "NO THOUGHTS YET / 暂无随想",
17
+ eyebrow: "暂无随想",
18
18
  title: "暂无随想。",
19
- description: "日常的碎片记录、短笔记与链接会落在这里。",
19
+ description: "短笔记和链接会在这里。",
20
20
  actionHref: "/blog",
21
21
  actionLabel: "先读博文",
22
22
  },
23
23
  columns: {
24
24
  icon: Books,
25
- eyebrow: "NO COLUMNS YET / 暂无专栏",
25
+ eyebrow: "暂无专栏",
26
26
  title: "暂无专栏。",
27
- description: "文章积累成系列后会在这里按顺序呈现。",
27
+ description: "一组文章会按顺序列在这里。",
28
28
  actionHref: "/blog",
29
29
  actionLabel: "浏览全部博文",
30
30
  },
@@ -17,7 +17,7 @@ const adminJobs = [
17
17
  },
18
18
  {
19
19
  title: "改文章里的交互",
20
- description: "写作台把一句话收成可交互的块。组件页能看到每一种块长什么样。",
20
+ description: "写作台把一句话收成可以动手试的一块。",
21
21
  },
22
22
  ];
23
23
 
@@ -23,7 +23,6 @@ const postSource = `---
23
23
  title: 我的第一篇文章
24
24
  date: 2026-08-03 09:00:00
25
25
  description: 这篇文章记录我为什么重新开始写博客。
26
- topic: 写作
27
26
  tags: [Markdown, 博客]
28
27
  pinned: false
29
28
  cover: writing/first-post.jpg
@@ -100,7 +99,7 @@ const guides: Guide[] = [
100
99
  <>文件名就是地址。标题和日期写在开头。先存着就标成草稿。</>,
101
100
  <>图片、音频、视频和链接按顺序放进 <code>media</code>。</>,
102
101
  ],
103
- result: "它会出现在随想页和首页,并且有自己的链接。",
102
+ result: "它会出现在随想页,并且有自己的链接。",
104
103
  path: "content/thoughts/walk-after-rain.md",
105
104
  source: thoughtSource,
106
105
  language: "markdown",
@@ -5,7 +5,7 @@ const embedTypes = [
5
5
  },
6
6
  {
7
7
  title: "X / Twitter",
8
- description: "显示成一张带出处的卡片,不依赖对方的脚本。",
8
+ description: "显示成一张带出处的卡片。",
9
9
  },
10
10
  {
11
11
  title: "微信公众号",
@@ -13,7 +13,7 @@ const embedTypes = [
13
13
  },
14
14
  {
15
15
  title: "其他网站",
16
- description: "自己写标题、摘要和封面。不在构建时去抓那个网址。",
16
+ description: "自己写标题、摘要和封面。",
17
17
  },
18
18
  ];
19
19
 
@@ -53,7 +53,7 @@ export function GardenMediaGuide() {
53
53
  </ul>
54
54
 
55
55
  <p className="garden-media-boundary">
56
- 摘要写在文章里。构建时不去抓任意网址。原站打不开,文章还在。需要时用 <code>make embed URL=...</code> 拉一次,看过再贴进去。
56
+ 摘要写在文章里。原站打不开,文章还在。需要时用 <code>make embed URL=...</code> 拉一次,看过再贴进去。
57
57
  </p>
58
58
  </section>
59
59
  );
@@ -253,7 +253,7 @@ export async function GithubProfile() {
253
253
  <header>
254
254
  <div>
255
255
  <p className="eyebrow">PINNED / 置顶仓库</p>
256
- <h3 id="github-pinned-title">正在持续构建的项目</h3>
256
+ <h3 id="github-pinned-title">正在做的项目</h3>
257
257
  </div>
258
258
  <PushPin size={20} aria-hidden="true" />
259
259
  </header>
@@ -2,9 +2,11 @@
2
2
 
3
3
  import { useEffect, useState, type ComponentPropsWithoutRef } from "react";
4
4
 
5
- type MarkdownImageProps = ComponentPropsWithoutRef<"img">;
5
+ // react-markdown also hands over its syntax-tree `node`; it must not reach the DOM.
6
+ type MarkdownImageProps = ComponentPropsWithoutRef<"img"> & { node?: unknown };
6
7
 
7
- export function MarkdownImage({ alt = "", src, ...props }: MarkdownImageProps) {
8
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars
9
+ export function MarkdownImage({ alt = "", src, node, ...props }: MarkdownImageProps) {
8
10
  const [open, setOpen] = useState(false);
9
11
  const description = alt || "查看原图";
10
12
 
@@ -9,13 +9,13 @@ export function SiteFooter() {
9
9
  © {new Date().getFullYear()} {siteConfig.author.name} · {siteConfig.footer}
10
10
  <span className="footer-framework"> · 基于 <a href="https://github.com/hedon954/garden" target="_blank" rel="noreferrer">Garden</a> 构建</span>
11
11
  </p>
12
- <div>
13
- <a href={githubUrl} aria-label="GitHub" rel="me">
14
- <GithubLogo size={19} />
12
+ <div className="sh-foot-links">
13
+ <a href={githubUrl} rel="me">
14
+ <GithubLogo size={16} aria-hidden="true" />
15
15
  GitHub
16
16
  </a>
17
- <a href="/rss.xml" aria-label="RSS 订阅">
18
- <Rss size={18} />
17
+ <a href="/rss.xml">
18
+ <Rss size={16} aria-hidden="true" />
19
19
  RSS
20
20
  </a>
21
21
  </div>
@@ -197,7 +197,6 @@ export function SiteHeader() {
197
197
  { name: "title", weight: 0.5 },
198
198
  { name: "description", weight: 0.3 },
199
199
  { name: "content", weight: 0.15 },
200
- { name: "topic", weight: 0.05 },
201
200
  ],
202
201
  threshold: 0.36,
203
202
  ignoreLocation: true,
@@ -401,10 +400,7 @@ export function SiteHeader() {
401
400
  className={`search-result${activeResult === index ? " active" : ""}`}
402
401
  >
403
402
  <span>
404
- <HighlightedText
405
- text={result.item.topic}
406
- ranges={rangesFor(result.matches, "topic")}
407
- />
403
+ {result.item.section}
408
404
  </span>
409
405
  <strong>
410
406
  <HighlightedText
@@ -0,0 +1,17 @@
1
+ "use client";
2
+
3
+ import { useRouter, useSearchParams } from "next/navigation";
4
+ import { useEffect } from "react";
5
+ import { TAG_PARAM, selectedTags, tagFilterHref } from "../lib/tag-filter";
6
+
7
+ /** Old `/tags?t=X` links open the same filter on `/blog?t=X`. */
8
+ export function TagRedirect() {
9
+ const router = useRouter();
10
+ const params = useSearchParams();
11
+ const tags = selectedTags(params.getAll(TAG_PARAM));
12
+ const target = tags.length ? tagFilterHref(tags) : "";
13
+ useEffect(() => {
14
+ if (target) router.replace(target);
15
+ }, [router, target]);
16
+ return null;
17
+ }
@@ -7,7 +7,7 @@ import { siteConfig } from "../site.config";
7
7
 
8
8
  export const metadata = {
9
9
  title: "Garden",
10
- description: "用 Markdown 写文章。推送到 GitHub 之后,页面、搜索和 RSS 一起生成。",
10
+ description: "用 Markdown 写文章。推送之后,页面、搜索和 RSS 一起更新。",
11
11
  };
12
12
 
13
13
  const jumps = [
@@ -45,7 +45,7 @@ const setupSteps = [
45
45
  {
46
46
  title: "发布",
47
47
  command: "make update",
48
- body: "先检查,再提交并推送。main 更新后,网站、搜索和 RSS 会重新生成。",
48
+ body: "先检查,再提交并推送。main 更新后,网站、搜索和 RSS 会一起更新。",
49
49
  },
50
50
  ];
51
51
 
@@ -54,7 +54,7 @@ export default function GardenPage() {
54
54
  <main className="page-shell garden-page">
55
55
  <PageIntro title={siteConfig.pages.garden.title} subtitle={siteConfig.pages.garden.subtitle}>
56
56
  <p className="garden-lede">
57
- 文章放在你自己的仓库里。你改文件,GitHub 构建网站。
57
+ 文章放在你自己的仓库里。你改文件,网站跟着更新。
58
58
  </p>
59
59
  <div className="garden-actions">
60
60
  <a
@@ -133,10 +133,10 @@ export default function GardenPage() {
133
133
  <header className="garden-section-heading">
134
134
  <h2 id="garden-after-title">推送之后</h2>
135
135
  </header>
136
- <p className="garden-after-lead">你的仓库,到 GitHub 构建,再到公开网站。</p>
136
+ <p className="garden-after-lead">推送之后,网站公开更新。</p>
137
137
  <div className="garden-after-copy">
138
- <p>框架画页面。你的文章不放在框架仓库里,而在你自己的内容仓库。读者打开的是生成出来的静态页。</p>
139
- <p>同一次构建会带上正文、目录、前后篇、搜索、RSS 和 sitemap。后台和评论都可以以后再加,不接也能发布。</p>
138
+ <p>文章在你自己的仓库里。读者打开的是已经发布的页面。</p>
139
+ <p>一次更新会带上正文、目录、前后篇、搜索、RSS 和 sitemap。后台和评论都可以以后再加。</p>
140
140
  </div>
141
141
  </section>
142
142
 
@@ -18,7 +18,6 @@ declare module "@garden/generated-content" {
18
18
  updated?: string;
19
19
  publishAt?: string;
20
20
  draft?: boolean;
21
- topic?: string;
22
21
  tags?: string[];
23
22
  references?: { title: string; url?: string }[];
24
23
  pinned?: boolean;
package/app/globals.css CHANGED
@@ -3,8 +3,8 @@
3
3
  @import "./admin-ui.css";
4
4
 
5
5
  :root {
6
- --paper: #f8f8f6;
7
- --paper-deep: #eeeeeb;
6
+ --paper: #faf9f5;
7
+ --paper-deep: #f0eee6;
8
8
  --card: #ffffff;
9
9
  --ink: #202124;
10
10
  --ink-soft: #34383d;
@@ -12,28 +12,28 @@
12
12
  --faint: #a1a6ad;
13
13
  --line: #deded9;
14
14
  --line-strong: #c9c9c2;
15
- --accent: #d82d48;
16
- --accent-soft: #f9e8eb;
17
- --selection: #f3c9d1;
15
+ --accent: #30302e;
16
+ --accent-soft: #f0eee6;
17
+ --selection: #e8e5db;
18
18
  --font-mono: var(--font-geist-mono), "SFMono-Regular", Consolas,
19
19
  "Liberation Mono", "Noto Sans Mono CJK SC", monospace;
20
- --content: 700px;
20
+ --content: 740px;
21
21
  --wide: 1040px;
22
22
  }
23
23
 
24
24
  :root[data-theme="dark"] {
25
- --paper: #171819;
26
- --paper-deep: #202224;
27
- --card: #1e2022;
25
+ --paper: #1f1e1d;
26
+ --paper-deep: #262624;
27
+ --card: #262624;
28
28
  --ink: #ededeb;
29
29
  --ink-soft: #d8d8d4;
30
30
  --muted: #a6adb6;
31
31
  --faint: #747b84;
32
32
  --line: #35383b;
33
33
  --line-strong: #4b4f54;
34
- --accent: #ff5d76;
35
- --accent-soft: #3b242a;
36
- --selection: #68333e;
34
+ --accent: #eeece7;
35
+ --accent-soft: #30302e;
36
+ --selection: rgb(238 236 231 / 18%);
37
37
  }
38
38
 
39
39
  * {
@@ -252,11 +252,6 @@ button {
252
252
  margin-top: 72px;
253
253
  }
254
254
 
255
- .home-thought-list {
256
- display: grid;
257
- gap: 24px;
258
- }
259
-
260
255
  .section-heading {
261
256
  min-height: 40px;
262
257
  margin-bottom: 21px;
@@ -1423,32 +1418,6 @@ button {
1423
1418
  color: var(--accent);
1424
1419
  }
1425
1420
 
1426
- .topic-strip {
1427
- display: flex;
1428
- flex-wrap: wrap;
1429
- gap: 8px;
1430
- margin: 8px 0 38px;
1431
- }
1432
-
1433
- .topic-strip a {
1434
- padding: 6px 10px;
1435
- background: var(--paper-deep);
1436
- color: var(--muted);
1437
- font-size: 11px;
1438
- border: 1px solid transparent;
1439
- }
1440
-
1441
- .topic-strip a:hover,
1442
- .topic-strip a:focus-visible {
1443
- color: var(--ink);
1444
- border-color: var(--line-strong);
1445
- }
1446
-
1447
- .topic-strip a.active {
1448
- background: var(--ink);
1449
- color: var(--paper);
1450
- }
1451
-
1452
1421
  .archive-list {
1453
1422
  border-top: 1px solid var(--line-strong);
1454
1423
  }
@@ -1496,13 +1465,6 @@ button {
1496
1465
  border: 1px solid var(--line);
1497
1466
  }
1498
1467
 
1499
- .archive-topic {
1500
- color: var(--accent);
1501
- font-size: 10px;
1502
- font-weight: 700;
1503
- letter-spacing: 0.05em;
1504
- }
1505
-
1506
1468
  .pinned-badge {
1507
1469
  margin-left: 9px;
1508
1470
  display: inline-flex;
@@ -2089,12 +2051,14 @@ button {
2089
2051
 
2090
2052
  .markdown-body a {
2091
2053
  text-decoration: underline;
2092
- text-decoration-color: var(--accent);
2054
+ text-decoration-color: color-mix(in srgb, var(--ink) 35%, transparent);
2093
2055
  text-underline-offset: 4px;
2094
2056
  }
2095
2057
 
2058
+ /* Links stay ink; hover darkens and thickens the underline instead. */
2096
2059
  .markdown-body a:hover {
2097
- color: var(--accent);
2060
+ text-decoration-color: var(--ink);
2061
+ text-decoration-thickness: 2px;
2098
2062
  }
2099
2063
 
2100
2064
  /* A per-line border stays continuous across inline code and descenders. */
@@ -2186,25 +2150,6 @@ button {
2186
2150
  color: var(--accent);
2187
2151
  }
2188
2152
 
2189
- .markdown-body table {
2190
- width: 100%;
2191
- margin: 34px 0;
2192
- border-collapse: collapse;
2193
- font-size: 12px;
2194
- }
2195
-
2196
- .markdown-body th,
2197
- .markdown-body td {
2198
- padding: 11px 13px;
2199
- border: 1px solid var(--line);
2200
- text-align: left;
2201
- }
2202
-
2203
- .markdown-body th {
2204
- background: var(--paper-deep);
2205
- color: var(--ink);
2206
- }
2207
-
2208
2153
  .markdown-body pre {
2209
2154
  position: relative;
2210
2155
  margin: 32px 0;
@@ -2879,25 +2824,10 @@ button {
2879
2824
  color: var(--accent);
2880
2825
  }
2881
2826
 
2882
- .article-references + .article-tags,
2883
2827
  .article-references + .next-entry {
2884
2828
  margin-top: 36px;
2885
2829
  }
2886
2830
 
2887
- .article-tags {
2888
- display: flex;
2889
- flex-wrap: wrap;
2890
- gap: 8px;
2891
- margin: 68px 0 24px;
2892
- }
2893
-
2894
- .article-tags span {
2895
- padding: 4px 8px;
2896
- background: var(--paper-deep);
2897
- color: var(--muted);
2898
- font-size: 10px;
2899
- }
2900
-
2901
2831
  .webmentions,
2902
2832
  .comments {
2903
2833
  margin-top: 78px;
@@ -3078,7 +3008,7 @@ button {
3078
3008
  margin: 0 auto;
3079
3009
  padding: 58px 0 120px;
3080
3010
  display: grid;
3081
- grid-template-columns: var(--column-sidebar-width) minmax(0, 700px) var(--column-sidebar-width);
3011
+ grid-template-columns: var(--column-sidebar-width) minmax(0, var(--content)) var(--column-sidebar-width);
3082
3012
  gap: 54px;
3083
3013
  justify-content: center;
3084
3014
  }
@@ -3697,12 +3627,6 @@ button {
3697
3627
  color: var(--accent);
3698
3628
  }
3699
3629
 
3700
- .footer-framework a {
3701
- text-decoration: underline;
3702
- text-decoration-color: var(--line-strong);
3703
- text-underline-offset: 3px;
3704
- }
3705
-
3706
3630
  @media (max-width: 1080px) {
3707
3631
  .post-reading-page {
3708
3632
  --toc-width: 210px;
@@ -3917,7 +3841,7 @@ button {
3917
3841
  }
3918
3842
 
3919
3843
  .column-reading-page {
3920
- grid-template-columns: minmax(0, 700px);
3844
+ grid-template-columns: minmax(0, var(--content));
3921
3845
  }
3922
3846
 
3923
3847
  .series-nav {
@@ -4202,8 +4126,7 @@ button {
4202
4126
  gap: 4px 9px;
4203
4127
  }
4204
4128
 
4205
- .archive-meta time,
4206
- .archive-topic {
4129
+ .archive-meta time {
4207
4130
  font-size: 9px;
4208
4131
  }
4209
4132
 
@@ -4274,11 +4197,6 @@ button {
4274
4197
  font-size: 17px;
4275
4198
  }
4276
4199
 
4277
- .markdown-body table {
4278
- display: block;
4279
- overflow-x: auto;
4280
- }
4281
-
4282
4200
  .markdown-body .external-embed-card,
4283
4201
  .markdown-body .external-embed-card:has(> img) {
4284
4202
  grid-template-columns: 1fr 22px;
@@ -13,6 +13,16 @@ export function demoDateLabel(value: string) {
13
13
  return `${date.getUTCFullYear()} 年 ${date.getUTCMonth() + 1} 月 ${date.getUTCDate()} 日`;
14
14
  }
15
15
 
16
+ /** Home list label. The current Shanghai year drops the year so the column stays narrow. */
17
+ export function homeListDate(value: string, now = new Date()) {
18
+ const date = shanghaiDate(value);
19
+ if (!date) return value;
20
+ const today = shanghaiDate(now.toISOString());
21
+ const monthDay = `${date.getUTCMonth() + 1} 月 ${date.getUTCDate()} 日`;
22
+ if (today && date.getUTCFullYear() === today.getUTCFullYear()) return monthDay;
23
+ return `${date.getUTCFullYear()} 年 ${monthDay}`;
24
+ }
25
+
16
26
  export function demoDateTime(value: string) {
17
27
  const date = shanghaiDate(value);
18
28
  if (!date) return value.slice(0, 10);
@@ -17,7 +17,6 @@ export type A2Article = {
17
17
  title: string;
18
18
  description: string;
19
19
  date: string;
20
- topic: string;
21
20
  cover: string;
22
21
  original: string;
23
22
  content: string;
@@ -42,7 +41,6 @@ export function readA2Article(slug: string): A2Article | null {
42
41
  title: String(data.title ?? slug),
43
42
  description: String(data.description ?? ""),
44
43
  date,
45
- topic: String(data.topic ?? ""),
46
44
  cover: cover && !/^https?:/iu.test(cover) ? `https://hedon.top/media/covers/${cover}` : cover,
47
45
  original: originals[slug] ?? "",
48
46
  content: parsed.content,
@@ -26,6 +26,13 @@ export const columnEntryPath = (entry: Pick<ContentEntry, "column" | "path">) =>
26
26
  export const columnHref = (entry: Pick<ContentEntry, "column" | "path">) =>
27
27
  `/columns/${entry.column}/${columnEntryPath(entry)}`;
28
28
 
29
+ /** The column a post belongs to (the first one, if it is listed in several). */
30
+ export const columnOfPost = (post: Pick<ContentEntry, "path">) => {
31
+ const entry = columns.find((item) => item.path === post.path && item.column);
32
+ return entry?.column ? { slug: entry.column, title: entry.columnTitle ?? entry.column } : undefined;
33
+ };
34
+ export const columnIndexHref = (slug: string) => `/columns#${slug}`;
35
+
29
36
  export const formatDate = (value: string, withTime = false) => {
30
37
  if (!withTime) return demoDateLabel(value);
31
38
  const canonical = canonicalSiteDate(value) ?? value;
@@ -128,30 +135,26 @@ export const searchRecords = [
128
135
  ...posts.map((item) => ({
129
136
  title: item.title,
130
137
  description: item.description ?? "",
131
- topic: item.topic ?? "博文",
138
+ section: "文章",
132
139
  path: postHref(item),
133
140
  content: toSearchableText(item.content),
134
141
  })),
135
142
  ...columns.map((item) => ({
136
143
  title: item.title,
137
144
  description: item.description ?? "",
138
- topic: item.columnTitle ?? "专栏",
145
+ section: item.columnTitle ?? "专栏",
139
146
  path: columnHref(item),
140
147
  content: toSearchableText(item.content),
141
148
  })),
142
149
  ...thoughts.map((item) => ({
143
150
  title: item.title,
144
151
  description: toSearchableText(item.content),
145
- topic: "随想",
152
+ section: "随想",
146
153
  path: `/thoughts/${item.slug}`,
147
154
  content: toSearchableText(item.content),
148
155
  })),
149
156
  ];
150
157
 
151
- export const topics = Array.from(
152
- new Set(posts.map((post) => post.topic).filter(Boolean)),
153
- ) as string[];
154
-
155
158
  export const findPost = (path: string): ContentEntry | undefined =>
156
159
  posts.find((post) => post.path === path);
157
160
 
@@ -1,44 +1,44 @@
1
1
  export const siteConfig = {
2
2
  name: "Garden",
3
- tagline: "写作 · 构建 · 保持好奇",
4
- description: "一个可 fork、可长期维护的 Markdown 个人博客系统。",
3
+ tagline: "写作 · 记录 · 保持好奇",
4
+ description: "文章、随想和专栏。",
5
5
  locale: "zh_CN",
6
6
  author: {
7
7
  name: "Your Name",
8
8
  github: "your-github-id",
9
- githubBio: "Write a short introduction for your GitHub profile card.",
9
+ githubBio: "一句自我介绍。",
10
10
  githubPinned: [] as string[],
11
11
  },
12
12
  pages: {
13
13
  home: {
14
14
  title: "记一些正在做的事,\n和想清楚的问题。",
15
- subtitle: "关注软件工程、系统设计与技术实践,也记录偶发的探索和工作笔记。",
15
+ subtitle: "软件、笔记,和偶尔的工作记录。",
16
16
  },
17
17
  blog: {
18
18
  title: "博文",
19
- subtitle: "阶段性的完整梳理与技术总结。",
19
+ subtitle: "写完的长文。",
20
20
  },
21
21
  thoughts: {
22
22
  title: "随想",
23
- subtitle: "碎片的念头、偶遇的灵感、短笔记与链接。",
23
+ subtitle: "短笔记、图片和链接。",
24
24
  },
25
25
  columns: {
26
26
  title: "专栏",
27
- subtitle: "按顺序组织的专题系列,沿着清晰的脉络连点成线。",
27
+ subtitle: "按顺序读的一组文章。",
28
28
  },
29
29
  about: {
30
30
  title: "你好,我是 Your Name。",
31
- subtitle: "欢迎来到我的个人网站。",
32
- heading: "关于我与这里",
31
+ subtitle: "文章和笔记都在这里。",
32
+ heading: "关于",
33
33
  paragraphs: [
34
- "一名工程师 / 创作者。平时主要关注系统开发、技术探索与软件设计。",
35
- "这里是我的公开工作台与数字自留地。比起社交网络上的碎片动态,我更倾向于把探索过程沉淀为有据可查的代码、设计与长篇笔记。",
34
+ "一名工程师。平时写代码,也把想清楚的问题记下来。",
35
+ "这里放文章、随想和专栏。",
36
36
  ],
37
37
  quote: "",
38
38
  focus: [
39
- "软件工程与系统架构",
40
- "原生工具与高质量交互",
41
- "个人长期知识沉淀",
39
+ "软件",
40
+ "笔记",
41
+ "日常",
42
42
  ],
43
43
  cta: {
44
44
  href: "/blog",
@@ -50,7 +50,7 @@ export const siteConfig = {
50
50
  subtitle: "",
51
51
  },
52
52
  },
53
- footer: "持续记录与构建。",
53
+ footer: "持续记录。",
54
54
  };
55
55
 
56
56
  export const githubUrl = `https://github.com/${siteConfig.author.github}`;