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:
1 parent
5be09b6f32
commit
264148f0a6
15 files changed
+346
-12
No files matched your search
@@ -10,8 +10,10 @@ interface Props {
|
||||
/** 展示上限:首页精选 6;/opensource 全量传大数 */
|
||||
limit?: number;
|
||||
locale?: Locale;
|
||||
/** 置顶仓短名(顺序即展示),由 content/site/opensource.yaml 供给 */
|
||||
pinned?: string[];
|
||||
}
|
||||
const { limit = 6, locale = 'zh' } = Astro.props;
|
||||
const { limit = 6, locale = 'zh', pinned } = Astro.props;
|
||||
const title = t('open_source_projects', locale);
|
||||
const LANG_COLORS: Record<string, string> = {
|
||||
Astro: '#ff5a03', TypeScript: '#3178c6', JavaScript: '#f1e05a',
|
||||
@@ -21,7 +23,7 @@ const LANG_COLORS: Record<string, string> = {
|
||||
|
||||
let projects: RepoCard[] = [];
|
||||
try {
|
||||
projects = (await loadProjects()).slice(0, limit);
|
||||
projects = (await loadProjects(pinned)).slice(0, limit);
|
||||
} catch {
|
||||
projects = []; // 兜底已在 lib 内处理,此处再守一层:空墙不破构建
|
||||
}
|
||||
|
||||
@@ -3,17 +3,22 @@ import BaseLayout from '../../layouts/BaseLayout.astro';
|
||||
import IdCard from '../../components/IdCard.astro';
|
||||
import { t } from '../../i18n/ui';
|
||||
import type { Locale } from '../../lib/locale';
|
||||
import { aboutIntro } from '../../lib/site-content';
|
||||
|
||||
// /en/ 侧由 T4 薄页传 locale='en';zh 路由无人传参,默认 zh 零回归
|
||||
interface Props {
|
||||
locale?: Locale;
|
||||
}
|
||||
const { locale = 'zh' } = Astro.props;
|
||||
// 身份陈述段改由 content/site/about.yaml 供给(后台可改),缺值回落默认
|
||||
const intro = await aboutIntro(locale);
|
||||
---
|
||||
|
||||
<BaseLayout title={`${t('about_title', locale)} · wait4x`}>
|
||||
<h1 class="page-title">{t('about_title', locale)}</h1>
|
||||
|
||||
<p class="intro">{intro}</p>
|
||||
|
||||
<IdCard />
|
||||
|
||||
<section class="tracks" aria-label={t('about_tracks_title', locale)}>
|
||||
@@ -72,6 +77,13 @@ const { locale = 'zh' } = Astro.props;
|
||||
margin-top: var(--space-5);
|
||||
text-wrap: balance;
|
||||
}
|
||||
.intro {
|
||||
font-size: 15.5px;
|
||||
line-height: 1.75;
|
||||
color: var(--ink-2);
|
||||
max-width: var(--measure);
|
||||
margin-top: var(--space-3);
|
||||
}
|
||||
.sec-title {
|
||||
font-size: 14px;
|
||||
font-family: var(--font-mono);
|
||||
|
||||
Reference in new issue
Block a user