feat(cms): 后台扩展五件——关于页 markdown 化/社交/头像/favicon/分轨首页

- T1 关于页=markdown 文档:about.yaml intro 扩为多段 markdown(zh/en),
  AboutPage 用 @astrojs/markdown-remark 的 createMarkdownProcessor(进程
  内单例复用)+ set:html 渲染,正文 p/ul/strong/a 对齐站点排版;名片与
  技能卡结构不动
- T2 社交链接单一数据源:home.yaml socials[](label/url/icon)+
  SocialLinks.astro(图标注册表白名单:github/rss/email/bilibili/x,
  未登记 icon 回退纯文字),首页 zh/en 内联硬编码社交块删除
- T3 头像与 favicon 可上传:schema avatar: image()(Astro Image 出 60px
  WebP,未设回退渐变 SVG);home.yaml favicon → BaseLayout link[rel=icon]
  按扩展名给 type,留空回退 /favicon.svg
- T4 首页分轨:PostList perTrack → 阅读轨/技术轨两段各限 6,各自出口
  (阅读→/books/ 技术→/archives/,en 同构);E2E 断言改为两段各≤6+各自
  出口+阅读在前
- T5 后台列表日期:posts summary「{{pubDate}} · {{title}}」、moments
  「{{fields.pubDate}} · {{fields.text}}」+sortable;photos 无 frontmatter
  日期(JSON sidecar)保持分组 · 标题并在文档写明原因
- 顺手修 content-lint 漏报:中文文件名在 HTML 里为 %XX 编码,脚本直接
  拼盘上路径导致 6 条"缺图"误报 → 加 decodeURI
- 清理:删除书封误传遗留的双重嵌套目录文件

车道:op-gitea(5/5,build+E2E 37/37+lint 47 页 0/0/0);收编复验:
build 46 页 + E2E 37/37 连跑(首跑两红为车道并发构建擦 dist 的瞬时态,
复跑绿)

验证: node v26.13.0 + astro 7.4.4 全量构建 46 页 exit 0;E2E 37/37;
      content-lint 0/0/0;books details/命令面板 playwright 实测

Spec: none (后台能力扩展,车道级交付)

Co-authored-by: GLM-5.3
This commit is contained in:
wait4xandGLM-5.3 committed 2026-11-02 15:46:41 +08:00
1 parent 227bc24797
commit 328ab68f18
16 files changed
+409 -146

No files matched your search

+4 -48
View File
@@ -9,6 +9,7 @@ import ProjectWall from '../../components/geek/ProjectWall.astro';
import Heatmap from '../../components/geek/Heatmap.astro';
import { t } from '../../i18n/ui';
import { homeTagline } from '../../lib/site-content';
import SocialLinks from '../../components/SocialLinks.astro';
const posts = (await getCollection('posts', ({ data }) => !data.draft && !data.tags.includes('hidden'))).sort(
(a, b) => b.data.pubDate.getTime() - a.data.pubDate.getTime(),
@@ -25,55 +26,10 @@ const tagline = await homeTagline('en');
<BaseLayout title="wait4x" description="wait4x's blog: reading · code · photography">
<IdCard>
<p class="tagline">{tagline}</p>
<div class="socials">
<a
class="tap social"
href="https://github.com/wait4xx"
rel="noopener noreferrer"
aria-label="GitHub"
title="GitHub"
>
<svg viewBox="0 0 24 24" width="16" height="16" fill="currentColor" aria-hidden="true">
<path
d="M12 2C6.48 2 2 6.58 2 12.25c0 4.53 2.87 8.37 6.84 9.73.5.1.68-.22.68-.49 0-.24-.01-.88-.01-1.73-2.78.62-3.37-1.37-3.37-1.37-.45-1.18-1.11-1.5-1.11-1.5-.91-.63.07-.62.07-.62 1 .07 1.53 1.06 1.53 1.06.89 1.57 2.34 1.12 2.91.85.09-.66.35-1.11.63-1.37-2.22-.26-4.56-1.14-4.56-5.07 0-1.12.39-2.03 1.03-2.75-.1-.26-.45-1.3.1-2.7 0 0 .84-.28 2.75 1.05a9.3 9.3 0 0 1 5 0c1.91-1.33 2.75-1.05 2.75-1.05.55 1.4.2 2.44.1 2.7.64.72 1.03 1.63 1.03 2.75 0 3.94-2.34 4.8-4.57 5.06.36.32.68.94.68 1.9 0 1.37-.01 2.47-.01 2.81 0 .27.18.6.69.49A10.26 10.26 0 0 0 22 12.25C22 6.58 17.52 2 12 2Z"
></path>
</svg>
</a>
<a class="tap social" href="/en/rss.xml" aria-label="RSS feed" title="RSS feed">
<svg
viewBox="0 0 24 24"
width="16"
height="16"
fill="none"
stroke="currentColor"
stroke-width="1.8"
stroke-linecap="round"
aria-hidden="true"
>
<path d="M4 11.5a8.5 8.5 0 0 1 8.5 8.5M4 4.5a15.5 15.5 0 0 1 15.5 15.5"></path>
<circle cx="5.4" cy="18.6" r="1.5" fill="currentColor" stroke="none"></circle>
</svg>
</a>
<a class="tap social" href="mailto:admin@wait4x.online" aria-label="Email" title="Email">
<svg
viewBox="0 0 24 24"
width="16"
height="16"
fill="none"
stroke="currentColor"
stroke-width="1.8"
stroke-linecap="round"
stroke-linejoin="round"
aria-hidden="true"
>
<rect x="3" y="5.5" width="18" height="13" rx="2.5"></rect>
<path d="m4 7.5 8 5.5 8-5.5"></path>
</svg>
</a>
</div>
</IdCard>
<SocialLinks />
</IdCard>
<PostList {posts} locale="en" titleOverrides={enTitle} limit={6} moreHref="/en/archives/" />
<PostList {posts} locale="en" titleOverrides={enTitle} perTrack={6} />
<section class="latest" aria-label={t('latest_photos', 'en')}>
<div class="latest-head">
+4 -48
View File
@@ -9,6 +9,7 @@ import Heatmap from '../components/geek/Heatmap.astro';
import { fetchHeartbeat, agoZh } from '../lib/heartbeat';
import { t } from '../i18n/ui';
import { homeTagline } from '../lib/site-content';
import SocialLinks from '../components/SocialLinks.astro';
const posts = (await getCollection('posts', ({ data }) => !data.draft && !data.tags.includes('hidden'))).sort(
(a, b) => b.data.pubDate.getTime() - a.data.pubDate.getTime(),
@@ -23,55 +24,10 @@ const tagline = await homeTagline('zh');
<BaseLayout title="wait4x">
<IdCard>
<p class="tagline">{tagline}</p>
<div class="socials">
<a
class="tap social"
href="https://github.com/wait4xx"
rel="noopener noreferrer"
aria-label="GitHub"
title="GitHub"
>
<svg viewBox="0 0 24 24" width="16" height="16" fill="currentColor" aria-hidden="true">
<path
d="M12 2C6.48 2 2 6.58 2 12.25c0 4.53 2.87 8.37 6.84 9.73.5.1.68-.22.68-.49 0-.24-.01-.88-.01-1.73-2.78.62-3.37-1.37-3.37-1.37-.45-1.18-1.11-1.5-1.11-1.5-.91-.63.07-.62.07-.62 1 .07 1.53 1.06 1.53 1.06.89 1.57 2.34 1.12 2.91.85.09-.66.35-1.11.63-1.37-2.22-.26-4.56-1.14-4.56-5.07 0-1.12.39-2.03 1.03-2.75-.1-.26-.45-1.3.1-2.7 0 0 .84-.28 2.75 1.05a9.3 9.3 0 0 1 5 0c1.91-1.33 2.75-1.05 2.75-1.05.55 1.4.2 2.44.1 2.7.64.72 1.03 1.63 1.03 2.75 0 3.94-2.34 4.8-4.57 5.06.36.32.68.94.68 1.9 0 1.37-.01 2.47-.01 2.81 0 .27.18.6.69.49A10.26 10.26 0 0 0 22 12.25C22 6.58 17.52 2 12 2Z"
></path>
</svg>
</a>
<a class="tap social" href="/rss.xml" aria-label="RSS 订阅" title="RSS 订阅">
<svg
viewBox="0 0 24 24"
width="16"
height="16"
fill="none"
stroke="currentColor"
stroke-width="1.8"
stroke-linecap="round"
aria-hidden="true"
>
<path d="M4 11.5a8.5 8.5 0 0 1 8.5 8.5M4 4.5a15.5 15.5 0 0 1 15.5 15.5"></path>
<circle cx="5.4" cy="18.6" r="1.5" fill="currentColor" stroke="none"></circle>
</svg>
</a>
<a class="tap social" href="mailto:admin@wait4x.online" aria-label="邮件" title="邮件">
<svg
viewBox="0 0 24 24"
width="16"
height="16"
fill="none"
stroke="currentColor"
stroke-width="1.8"
stroke-linecap="round"
stroke-linejoin="round"
aria-hidden="true"
>
<rect x="3" y="5.5" width="18" height="13" rx="2.5"></rect>
<path d="m4 7.5 8 5.5 8-5.5"></path>
</svg>
</a>
</div>
</IdCard>
<SocialLinks />
</IdCard>
<PostList {posts} limit={6} moreHref="/archives/" />
<PostList {posts} perTrack={6} />
<section class="latest" aria-label="最新影像">
<div class="latest-head">