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.
- package/.agents/skills/garden-interactive-chart/SKILL.md +5 -5
- package/Makefile +2 -3
- package/app/a2/[slug]/page.tsx +0 -1
- package/app/a2/page.tsx +1 -1
- package/app/about/page.tsx +8 -12
- package/app/admin/page.tsx +2 -2
- package/app/blog/[...path]/page.tsx +2 -12
- package/app/blog/page.tsx +2 -2
- package/app/columns/[column]/[...path]/page.tsx +2 -3
- package/app/columns/page.tsx +2 -2
- package/app/components/AdminDashboard.tsx +3 -3
- package/app/components/ArticleMeasure.tsx +114 -42
- package/app/components/ArticleTags.tsx +17 -0
- package/app/components/BlogArchive.tsx +85 -33
- package/app/components/ContentEmptyState.tsx +6 -6
- package/app/components/GardenAdminGuide.tsx +1 -1
- package/app/components/GardenContentGuide.tsx +1 -2
- package/app/components/GardenMediaGuide.tsx +3 -3
- package/app/components/GithubProfile.tsx +1 -1
- package/app/components/MarkdownImage.tsx +4 -2
- package/app/components/SiteFooter.tsx +5 -5
- package/app/components/SiteHeader.tsx +1 -5
- package/app/components/TagRedirect.tsx +17 -0
- package/app/garden/page.tsx +6 -6
- package/app/garden-modules.d.ts +0 -1
- package/app/globals.css +19 -101
- package/app/lib/a2-meta.ts +10 -0
- package/app/lib/a2-preview.ts +0 -2
- package/app/lib/content.ts +10 -7
- package/app/lib/fallback-site-config.ts +15 -15
- package/app/lib/generated-content.ts +58 -47
- package/app/lib/tag-filter.ts +114 -0
- package/app/not-found.tsx +13 -0
- package/app/page.tsx +9 -26
- package/app/styles/a2.css +96 -15
- package/app/styles/shell.css +54 -59
- package/app/styles/tokens.css +35 -22
- package/app/tags/page.tsx +20 -9
- package/package.json +1 -1
- package/scripts/build-content.mjs +3 -3
- package/scripts/check-post.mjs +0 -3
- package/scripts/new-post.mjs +1 -3
- package/site.config.yaml +15 -15
- package/templates/site/Makefile +2 -3
- package/templates/site/site.config.yaml +15 -15
- package/ui/garden/check.mjs +2 -4
- package/ui/garden/enhance.mjs +57 -0
- package/ui/garden/title.mjs +5 -8
- package/ui/host.mjs +13 -13
- package/ui/preview/dist/garden-ui.css +11 -11
- package/ui/preview/dist/garden-ui.esm.js +6 -6
- package/ui/preview/dist/garden-ui.iife.js +7 -7
- package/ui/react/components/media.tsx +2 -2
- package/ui/react/ui.css +11 -11
- 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: "
|
|
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: "
|
|
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: "
|
|
25
|
+
eyebrow: "暂无专栏",
|
|
26
26
|
title: "暂无专栏。",
|
|
27
|
-
description: "
|
|
27
|
+
description: "一组文章会按顺序列在这里。",
|
|
28
28
|
actionHref: "/blog",
|
|
29
29
|
actionLabel: "浏览全部博文",
|
|
30
30
|
},
|
|
@@ -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
|
-
|
|
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"
|
|
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
|
-
|
|
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
|
-
|
|
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}
|
|
14
|
-
<GithubLogo size={
|
|
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"
|
|
18
|
-
<Rss size={
|
|
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
|
-
|
|
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
|
+
}
|
package/app/garden/page.tsx
CHANGED
|
@@ -7,7 +7,7 @@ import { siteConfig } from "../site.config";
|
|
|
7
7
|
|
|
8
8
|
export const metadata = {
|
|
9
9
|
title: "Garden",
|
|
10
|
-
description: "用 Markdown
|
|
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
|
-
|
|
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"
|
|
136
|
+
<p className="garden-after-lead">推送之后,网站公开更新。</p>
|
|
137
137
|
<div className="garden-after-copy">
|
|
138
|
-
<p
|
|
139
|
-
<p
|
|
138
|
+
<p>文章在你自己的仓库里。读者打开的是已经发布的页面。</p>
|
|
139
|
+
<p>一次更新会带上正文、目录、前后篇、搜索、RSS 和 sitemap。后台和评论都可以以后再加。</p>
|
|
140
140
|
</div>
|
|
141
141
|
</section>
|
|
142
142
|
|
package/app/garden-modules.d.ts
CHANGED
package/app/globals.css
CHANGED
|
@@ -3,8 +3,8 @@
|
|
|
3
3
|
@import "./admin-ui.css";
|
|
4
4
|
|
|
5
5
|
:root {
|
|
6
|
-
--paper: #
|
|
7
|
-
--paper-deep: #
|
|
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: #
|
|
16
|
-
--accent-soft: #
|
|
17
|
-
--selection: #
|
|
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:
|
|
20
|
+
--content: 740px;
|
|
21
21
|
--wide: 1040px;
|
|
22
22
|
}
|
|
23
23
|
|
|
24
24
|
:root[data-theme="dark"] {
|
|
25
|
-
--paper: #
|
|
26
|
-
--paper-deep: #
|
|
27
|
-
--card: #
|
|
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: #
|
|
35
|
-
--accent-soft: #
|
|
36
|
-
--selection:
|
|
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(--
|
|
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(--
|
|
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,
|
|
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,
|
|
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;
|
package/app/lib/a2-meta.ts
CHANGED
|
@@ -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);
|
package/app/lib/a2-preview.ts
CHANGED
|
@@ -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,
|
package/app/lib/content.ts
CHANGED
|
@@ -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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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: "
|
|
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: "
|
|
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}`;
|