feat(cms): 内容管理闭环——站点单例三件套+文章视频字段

- A 站点文案单例:content/site/{home,about,opensource}.yaml +
  src/lib/site-content.ts 访问层(字段级回落默认,默认值=原文案逐字
  一致,零回归);接线主页 tagline(en 首页新增该块)、关于页 intro、
  开源页叙述三段 + PINNED 参数化(projects.ts: loadProjects(pinned)
  /orderPinned,PINNED_DEFAULT 仅缺省兜底)
- loader 语义修正(返工如实入档):Astro 7 的 file() 把 YAML 顶层对象
  按 Object.entries 拆成多条目(id=key、data=value),单例字段必炸
  schema;改 glob 精确到单文件 = 真单例语义,data 即文件根对象,
  Sveltia 可编辑根字段零嵌套(比包 main: 层的方案后台体验更好)
- B 文章媒体:posts +video/+poster;Sveltia file 字段
  (media_folder=public/media、public_folder=/media、hint ≤50MB);
  正文后渲染 video controls preload=metadata playsinline,无则不渲染;
  图片链路核对本已一致(./assets 走 Astro 管线);链接 markdown 原生
- docs/写作指南.md 补「后台上传」节(三类媒体 + 三单例操作 + 体积纪律)

Sveltia 集合:posts / moments / photos / site_pages(三单例)

车道:op-gitea(实测 tagline 改 yaml 产物联动、置空回落默认、pinned
改名排序变、视频临时件渲染全对、构建绿 + lint 45 页 0/0/0);收编
复验:构建 44 页 + E2E 37/37 + 三 yaml 扁平键就位

验证: pnpm astro build 44 页 exit 0;E2E 37/37 PASS;content-lint
      0/0/0;播放器/单例/置顶 playwright 实测全过

Spec: none (内容管理闭环,车道级交付)

Co-authored-by: GLM-5.3
This commit is contained in:
wait4xandGLM-5.3 committed 2026-11-02 12:42:10 +08:00
1 parent 5be09b6f32
commit 264148f0a6
15 files changed
+346 -12

No files matched your search

+21
View File
@@ -2,6 +2,7 @@
// /en/archives/{slug}:英文版文章页——postsEn 优先;缺译回退 zh 正文 + 醒目标注
import type { CollectionEntry } from 'astro:content';
import { getCollection, render } from 'astro:content';
import LinkCardStyles from '../../../components/geek/LinkCardStyles.astro';
import PhotoZoom from '../../../components/geek/PhotoZoom.astro';
import BaseLayout from '../../../layouts/BaseLayout.astro';
import ArtalkComments from '../../../components/ArtalkComments.astro';
@@ -61,6 +62,14 @@ const minutes = Math.max(1, Math.ceil(words / 220));
<AiTranslatedBadge />
<div class={isReading ? 'prose-reading' : 'prose-tech'}>
<Content />
{entry.data.video && (
<figure class="post-video">
<video controls preload="metadata" playsinline poster={entry.data.poster}>
<source src={entry.data.video} />
Your browser cannot play embedded video — <a href={entry.data.video}>download it instead</a>.
</video>
</figure>
)}
</div>
<nav class="pn">
{prev && <a class="pn-item" href={`/en/archives/${prev.id}/`}>← {t('prev_post', 'en')} · {prev.data.title}</a>}
@@ -68,6 +77,7 @@ const minutes = Math.max(1, Math.ceil(words / 220));
</nav>
<ArtalkComments pageKey={`/archives/${entry.id}/`} pageTitle={entry.data.title} />
</article>
<LinkCardStyles />
<PhotoZoom />
</BaseLayout>
@@ -116,6 +126,17 @@ const minutes = Math.max(1, Math.ceil(words / 220));
}
/* ---- T6 reading paper card (§6-2) ---- */
/* 文章附视频:与 zh 版同构(cms 车道 B) */
.post-video {
margin: var(--space-4) 0 0;
}
.post-video video {
width: 100%;
height: auto;
border-radius: 10px;
background: #000;
display: block;
}
.prose-reading {
border: 1px solid var(--paper-line);
border-radius: 12px;