用户实测:「有的文章同时选择了置顶和隐藏,还会显示并置顶」。
根因:后台「隐藏」开关(hiddenTag)是个假开关——它只写 `hiddenTag: true` 这个
没人读的字段,而全站过滤只认 `tags` 里的 `hidden`。于是隐藏从未生效;
叠加置顶后,这篇还在列表最前面。
- 新增 src/lib/post-visibility.ts:可见性契约单一事实源——`!draft && !hidden &&
!tags.includes('hidden')`(两条通道都认,历史写法兼容)
- postsSchema 增真字段 `hidden`;七处消费点(首页双轨/归档 zh/en/书架/RSS zh/en/
文章页导航)统一走 isVisiblePost
- 后台假开关 hiddenTag 换成真开关 hidden,hint 写清语义:不进列表/RSS/sitemap,
页面本身仍生成(链接可分享);与置顶同时打开时以隐藏为准
- sitemap 过滤隐藏文章(astro.config 配置期扫 frontmatter,两种写法都认;
内容目录不可读时宁可不排除也不炸构建)
贡献数据去重(5j T2,回答用户「连续贡献是否实时」):
- 连续贡献不再构建期抓取 streak.svg 快照(不实时、暗色需滤镜、与热力图同源重复),
改为热力图同一份 GraphQL 日历本地计算(src/lib/heatmap.ts streakStats):
当前连续(以最后有贡献日为终点)/ 最长 / 总贡献,界面上标注「数据更新于 X」
- 贡献蛇块与自托管 snake/streak SVG 删除,fetch 脚本 ASSETS 清空,
build.sh 守卫改为退役说明;开源页数据板整块并入热力图区
验证: 构建 51 页 exit 0;content-lint 52 页 0/0/0;E2E 56/56;
临时两篇「置顶+隐藏」(新字段/旧 tags 各一)实测——首页/归档/书架/
双语首页/RSS 双语/sitemap 全部零命中,页面本身仍生成;
清理后归档首条恢复 writing-template(普通置顶不受影响);
开源页 snake/streak 资产零残留、连续统计条与更新时间标注就位
Spec: 2026-11-03_blog-5j-content-refine (T2 + 隐藏 bug 修复)
Co-authored-by: GLM-5.3
72 lines
3.0 KiB
JavaScript
72 lines
3.0 KiB
JavaScript
// @ts-check
|
||
import { defineConfig } from 'astro/config';
|
||
import pagefind from 'astro-pagefind';
|
||
import sitemap from '@astrojs/sitemap';
|
||
import { execSync } from 'node:child_process';
|
||
import { readdirSync, readFileSync } from 'node:fs';
|
||
import rehypeLinkCards, { linkCardsReport } from './src/lib/rehype-link-cards';
|
||
import rehypeClassWhitelist from './src/lib/rehype-class-whitelist';
|
||
import rehypeRaw from 'rehype-raw';
|
||
|
||
// 构建透明(T7):commit/时间经 vite.define 注入,页脚与 /about 引用。
|
||
// 四重回退:CI 环境变量优先(GITEA_ACTIONS/GITHUB_SHA)→ 本地 git → dev 占位。
|
||
const sha =
|
||
process.env.GITEA_COMMIT_SHA ||
|
||
process.env.GITHUB_SHA ||
|
||
(() => { try { return execSync('git rev-parse HEAD').toString().trim(); } catch { return 'dev'; } })();
|
||
const date =
|
||
process.env.GITEA_COMMIT_DATE ||
|
||
process.env.GITHUB_COMMIT_DATE ||
|
||
(() => { try { return execSync('git log -1 --format=%cI').toString().trim(); } catch { return new Date().toISOString(); } })();
|
||
|
||
// 隐藏文章不进 sitemap(内容侧契约见 src/lib/post-visibility.ts)。
|
||
// 这里在配置期直接扫 frontmatter:Astro 的 content collections 在配置上下文不可用,
|
||
// 而 sitemap 的 filter 只拿到 URL。判定两条通道:`hidden: true` 与 tags 里的 hidden。
|
||
const hiddenSlugs = (() => {
|
||
const set = new Set();
|
||
try {
|
||
const dir = 'content/posts';
|
||
for (const file of readdirSync(dir)) {
|
||
if (!file.endsWith('.md')) continue;
|
||
const raw = readFileSync(`${dir}/${file}`, 'utf8');
|
||
const head = (raw.split('\n---\n')[0] ?? '').replace(/^---\n/, '');
|
||
if (/^hidden:\s*true\s*$/m.test(head)) { set.add(file.replace(/\.md$/, '')); continue; }
|
||
// tags 可能是行内数组,也可能是多行列表:抓出 tags 段再找 hidden 词
|
||
const m = /^tags:[ \t]*([\s\S]*?)(?=^\w|\s*$)/m.exec(head);
|
||
const tagBlock = m ? m[1] : '';
|
||
if (/\bhidden\b/.test(tagBlock)) set.add(file.replace(/\.md$/, ''));
|
||
}
|
||
} catch {
|
||
/* 内容目录不可读时宁可不排除,也不让构建挂掉 */
|
||
}
|
||
return [...set];
|
||
})();
|
||
|
||
export default defineConfig({
|
||
site: 'https://wait4x.online',
|
||
integrations: [
|
||
pagefind(),
|
||
sitemap({
|
||
filter: (page) => !hiddenSlugs.some((slug) => page.includes(`/archives/${slug}/`)),
|
||
}),
|
||
linkCardsReport(),
|
||
],
|
||
markdown: {
|
||
// 独立成段的裸链接 → OG 预览卡(构建期抓取,失败回落普通链接;见 src/lib/rehype-link-cards.ts)
|
||
// 顺序:rehypeRaw 先把 markdown 里的 raw HTML 解析成 hast element(否则白名单看不到 span),
|
||
// 再白名单净化(剥 style/on*/非白名单类),最后链接卡片(节点由插件自建,不经净化)
|
||
rehypePlugins: [rehypeRaw, rehypeClassWhitelist, rehypeLinkCards],
|
||
},
|
||
i18n: {
|
||
defaultLocale: 'zh',
|
||
locales: ['zh', 'en'],
|
||
routing: { prefixDefaultLocale: false },
|
||
},
|
||
vite: {
|
||
define: {
|
||
'import.meta.env.GIT_COMMIT_SHA': JSON.stringify(sha),
|
||
'import.meta.env.GIT_COMMIT_DATE': JSON.stringify(date),
|
||
},
|
||
},
|
||
});
|