feat(cms): 文章页标题下说明后台可编辑 + 文章数 {n} 占位符随数量变化
后台「页面文案」新增「文章页说明」(中/英 markdown,与瞬间/书架同构的
压平结构);{n} 在构建期替换为当前可见文章数。顺修默认文案错字
(月分分组→按月分组),en 文章页补齐标题与说明行(此前只有裸列表)。
验证: pnpm astro build exit 0;dist 断言「共 10 篇」动态计数与 en 侧文案;config-check 通过;E2E 61/61
Spec: none (页面文案体系的小增量,随 5l/5m 后续直落)
Co-authored-by: GLM-5.3
This commit is contained in:
1 parent
9b11070dd4
commit
d37fe581c0
6 files changed
+44
-3
No files matched your search
@@ -9,3 +9,7 @@ moments:
|
|||||||
books:
|
books:
|
||||||
note_zh: 点一行展开封面与简介 · 置顶的书默认展开
|
note_zh: 点一行展开封面与简介 · 置顶的书默认展开
|
||||||
note_en: 'Tap a row for the cover and blurb · pinned books start open'
|
note_en: 'Tap a row for the cover and blurb · pinned books start open'
|
||||||
|
|
||||||
|
archives:
|
||||||
|
note_zh: 按年份折叠 · 按月分组 · 共 {n} 篇
|
||||||
|
note_en: 'Folded by year · grouped by month · {n} posts in total'
|
||||||
@@ -170,6 +170,13 @@ collections:
|
|||||||
fields:
|
fields:
|
||||||
- { label: 中文, name: note_zh, widget: markdown, required: false, hint: '一行小字;排版(字体/颜色)选中文字 → Insert ▸ 排版' }
|
- { label: 中文, name: note_zh, widget: markdown, required: false, hint: '一行小字;排版(字体/颜色)选中文字 → Insert ▸ 排版' }
|
||||||
- { label: English, name: note_en, widget: markdown, required: false }
|
- { label: English, name: note_en, widget: markdown, required: false }
|
||||||
|
- label: 文章页说明
|
||||||
|
name: archives
|
||||||
|
widget: object
|
||||||
|
required: false
|
||||||
|
fields:
|
||||||
|
- { label: 中文, name: note_zh, widget: markdown, required: false, hint: '一行小字;{n} 会替换为当前可见文章数(构建期);排版用 Insert ▸ 排版' }
|
||||||
|
- { label: English, name: note_en, widget: markdown, required: false }
|
||||||
- name: home
|
- name: home
|
||||||
label: 主页设置
|
label: 主页设置
|
||||||
file: content/site/home.yaml
|
file: content/site/home.yaml
|
||||||
|
|||||||
@@ -246,6 +246,7 @@ export const collections = {
|
|||||||
schema: z.object({
|
schema: z.object({
|
||||||
moments: pageNoteSchema.optional(),
|
moments: pageNoteSchema.optional(),
|
||||||
books: pageNoteSchema.optional(),
|
books: pageNoteSchema.optional(),
|
||||||
|
archives: pageNoteSchema.optional(),
|
||||||
}),
|
}),
|
||||||
}),
|
}),
|
||||||
siteTheme: defineCollection({
|
siteTheme: defineCollection({
|
||||||
|
|||||||
@@ -181,6 +181,10 @@ const PAGE_NOTE_DEFAULTS = {
|
|||||||
zh: '点一行展开封面与简介 · 置顶的书默认展开',
|
zh: '点一行展开封面与简介 · 置顶的书默认展开',
|
||||||
en: 'Tap a row for the cover and blurb · pinned books start open',
|
en: 'Tap a row for the cover and blurb · pinned books start open',
|
||||||
},
|
},
|
||||||
|
archives: {
|
||||||
|
zh: '按年份折叠 · 按月分组 · 共 {n} 篇',
|
||||||
|
en: 'Folded by year · grouped by month · {n} posts in total',
|
||||||
|
},
|
||||||
} as const;
|
} as const;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -191,13 +195,16 @@ const PAGE_NOTE_DEFAULTS = {
|
|||||||
* 「可选对象嵌可选对象不渲染子编辑器」的缺陷结构(#446/#654)。
|
* 「可选对象嵌可选对象不渲染子编辑器」的缺陷结构(#446/#654)。
|
||||||
*/
|
*/
|
||||||
export async function pageNote(
|
export async function pageNote(
|
||||||
page: 'moments' | 'books',
|
page: 'moments' | 'books' | 'archives',
|
||||||
locale: Locale,
|
locale: Locale,
|
||||||
|
/** 占位符替换(在 markdown 渲染前做):文章页用 {n}=可见文章数 */
|
||||||
|
vars?: Record<string, string | number>,
|
||||||
): Promise<PageNote> {
|
): Promise<PageNote> {
|
||||||
const entry = await getEntry('sitePages', 'pages');
|
const entry = await getEntry('sitePages', 'pages');
|
||||||
const data = entry?.data?.[page];
|
const data = entry?.data?.[page];
|
||||||
const fallback = PAGE_NOTE_DEFAULTS[page];
|
const fallback = PAGE_NOTE_DEFAULTS[page];
|
||||||
const text = (locale === 'en' ? data?.note_en : data?.note_zh) || fallback[locale];
|
let text = (locale === 'en' ? data?.note_en : data?.note_zh) || fallback[locale];
|
||||||
|
if (vars) for (const [k, v] of Object.entries(vars)) text = text.replaceAll(`{${k}}`, String(v));
|
||||||
const html = await renderRich(text, { inline: true });
|
const html = await renderRich(text, { inline: true });
|
||||||
return { html, className: 'page-note' };
|
return { html, className: 'page-note' };
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,16 +5,19 @@ import { isVisiblePost } from '../../lib/post-visibility';
|
|||||||
import BaseLayout from '../../layouts/BaseLayout.astro';
|
import BaseLayout from '../../layouts/BaseLayout.astro';
|
||||||
import PostList from '../../components/PostList.astro';
|
import PostList from '../../components/PostList.astro';
|
||||||
import { sortPosts } from '../../lib/post-order';
|
import { sortPosts } from '../../lib/post-order';
|
||||||
|
import { pageNote } from '../../lib/site-content';
|
||||||
|
|
||||||
// 置顶优先 → 时间倒序(sortPosts 契约见 src/lib/post-order.ts)
|
// 置顶优先 → 时间倒序(sortPosts 契约见 src/lib/post-order.ts)
|
||||||
const posts = sortPosts(
|
const posts = sortPosts(
|
||||||
await getCollection('posts', ({ data }) => isVisiblePost(data)),
|
await getCollection('posts', ({ data }) => isVisiblePost(data)),
|
||||||
);
|
);
|
||||||
|
// 标题下说明:后台「页面文案 → 文章页说明」可改;{n} 占位符=可见文章数(构建期替换)
|
||||||
|
const note = await pageNote('archives', 'zh', { n: posts.length });
|
||||||
---
|
---
|
||||||
|
|
||||||
<BaseLayout title="文章 · wait4x">
|
<BaseLayout title="文章 · wait4x">
|
||||||
<h1 class="page-title">文章</h1>
|
<h1 class="page-title">文章</h1>
|
||||||
<p class="page-note">按年份折叠 · 月分分组 · 共 {posts.length} 篇</p>
|
<p class="page-note" set:html={note.html} />
|
||||||
<PostList {posts} fold />
|
<PostList {posts} fold />
|
||||||
</BaseLayout>
|
</BaseLayout>
|
||||||
|
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ import { isVisiblePost } from '../../../lib/post-visibility';
|
|||||||
import BaseLayout from '../../../layouts/BaseLayout.astro';
|
import BaseLayout from '../../../layouts/BaseLayout.astro';
|
||||||
import PostList from '../../../components/PostList.astro';
|
import PostList from '../../../components/PostList.astro';
|
||||||
import { sortPosts } from '../../../lib/post-order';
|
import { sortPosts } from '../../../lib/post-order';
|
||||||
|
import { pageNote } from '../../../lib/site-content';
|
||||||
|
|
||||||
const posts = sortPosts(
|
const posts = sortPosts(
|
||||||
await getCollection('posts', ({ data }) => isVisiblePost(data)),
|
await getCollection('posts', ({ data }) => isVisiblePost(data)),
|
||||||
@@ -12,8 +13,26 @@ const posts = sortPosts(
|
|||||||
const enTitle = Object.fromEntries(
|
const enTitle = Object.fromEntries(
|
||||||
(await getCollection('postsEn')).map((e) => [e.id, e.data.title]),
|
(await getCollection('postsEn')).map((e) => [e.id, e.data.title]),
|
||||||
);
|
);
|
||||||
|
const note = await pageNote('archives', 'en', { n: posts.length });
|
||||||
---
|
---
|
||||||
|
|
||||||
<BaseLayout title="Posts · wait4x" description="All posts">
|
<BaseLayout title="Posts · wait4x" description="All posts">
|
||||||
|
<h1 class="page-title">Posts</h1>
|
||||||
|
<p class="page-note" set:html={note.html} />
|
||||||
<PostList {posts} locale="en" titleOverrides={enTitle} fold />
|
<PostList {posts} locale="en" titleOverrides={enTitle} fold />
|
||||||
</BaseLayout>
|
</BaseLayout>
|
||||||
|
|
||||||
|
<style>
|
||||||
|
.page-title {
|
||||||
|
font-size: var(--text-h1);
|
||||||
|
line-height: var(--leading-heading);
|
||||||
|
color: var(--ink-1);
|
||||||
|
margin-top: var(--space-5);
|
||||||
|
text-wrap: balance;
|
||||||
|
}
|
||||||
|
.page-note {
|
||||||
|
font-size: 13px;
|
||||||
|
color: var(--ink-4);
|
||||||
|
margin-block: var(--space-1) var(--space-4);
|
||||||
|
}
|
||||||
|
</style>
|
||||||
Reference in new issue
Block a user