跨环(TransCircle Project)官方博客:记录项目进展、社群知识与跨性别议题。
在线地址:blog.transcircle.org
博客文章存放在 src/content/posts/ 目录下,以 Markdown 文件形式管理。
- 文章文件:
src/content/posts/文章标题.md - 图片资源:
public/images/ - 无需编写代码:只需要编辑 Markdown 文件
- 进入
src/content/posts/目录 - 新建一个
.md文件,文件名建议使用英文(如weekly-report-01.md) - 在文件开头填写文章信息(Frontmatter):
---
title: '文章标题'
description: '文章简介,会显示在列表中'
pubDate: 2026-05-21
author: '作者名称' # 想让署名可点,写成 { name: '...', link: 'https://...' }
category: '开发进度'
tags: ['标签1', '标签2']
---
## 正文标题
正文内容支持 Markdown 格式:
- **粗体文字**
- *斜体文字*
- [链接文字](https://example.com)
- `行内代码`
### 代码块
```typescript
const example = "代码会自动高亮";
4. 保存文件,提交到 Git 仓库即可
### 方式二:复制模板
1. 复制 `src/content/posts/project-kickoff.md`
2. 修改文件名和内容
3. 保存并提交
---
## 修改文章
1. 找到 `src/content/posts/` 下对应的文章文件
2. 修改内容
3. 如需更新发布时间,修改 `pubDate` 字段,或添加 `updatedDate` 字段:
```markdown
---
title: '原标题'
pubDate: 2026-05-20
updatedDate: 2026-05-21 # 添加这行表示更新时间
---
| 字段 | 必填 | 说明 | 示例 |
|---|---|---|---|
title |
✅ | 文章标题 | '项目启动报告' |
description |
可选 | 文章简介,显示在列表中 | '本周完成的工作内容' |
pubDate |
✅ | 发布日期 | 2026-05-21 |
updatedDate |
可选 | 更新日期 | 2026-05-22 |
author |
可选 | 作者署名(默认:TransCircle 项目组),写法见下节 | '张三' |
editor |
可选 | 编辑署名,不写就不显示,写法见下节 | '李四' |
category |
可选 | 分类(默认:general) | '开发进度' 或 '团队报告' |
tags |
可选 | 标签数组 | ['前端', 'astro'] |
cover |
可选 | 封面图路径 | '/images/cover.png' |
draft |
可选 | 草稿标记(默认:false) | true 或 false |
contentLicense |
可选 | 正文的内容协议(默认:CC-BY-SA-4.0) | 'CC-BY-SA-4.0' |
codeLicense |
可选 | 正文代码块的协议,没有代码就别写,写法见下节 | 'MIT' |
两个字段的写法完全一样,支持三种形式,可以混着用:
---
# 1. 只写名字:不带链接,署名显示为纯文本,点不了
author: 'TransCircle 文案组'
# 2. 名字 + 链接:署名可点,在新标签页打开
author: { name: '翅膀', link: 'https://x.com/axzameyzed' }
# 3. 多个人:写成列表,带不带链接可以混排
author:
- { name: '羽莉', link: 'https://x.com/liwanmiaohy' }
- { name: 'Oakley Huang', link: 'https://x.com/YangyanH5' }
- 'TransCircle 文案组' # 这一位没有链接,就是纯文本
---几条规则:
- 不写
link就是没有链接,署名保持纯文本、不做跳转,也不会被"顺手"指向主站。 - 不写
editor就是没有编辑,文章页、分享图、结构化数据里都不会出现「编辑」这一行; 不会自动署上团队名。 author不写时才回退到TransCircle 项目组。link只接受http(s)链接,其它协议(如javascript:)会在构建时直接报错。- 多人署名用顿号(、)连接;点击带链接的署名会先弹出外链确认框。
开发进度- 开发进展报告团队报告- 团队周报/月报技术分享- 技术文章general- 其他
一篇文章可能同时装着两类作品:正文(文字、论述、表格)是创作性作品,代码块是软件。 两者的授权方式不一样——Creative Commons 官方就不建议拿 CC 协议去授权软件——所以拆成两个字段。
内容协议(contentLicense)——管正文,每篇文章都会显示,不写就用默认值:
CC-BY-SA-4.0(默认)- 知识共享 署名-相同方式共享 4.0CC-BY-4.0- 知识共享 署名 4.0CC0-1.0- 公共领域Proprietary- 保留所有权利
代码协议(codeLicense)——只管正文里的代码块,不写就不显示,没有默认值:
AGPL-3.0- GNU Affero General Public License v3.0MIT- MIT LicenseApache-2.0- Apache License 2.0BSD-3-Clause- BSD 3-Clause LicenseProprietary- 保留所有权利
几条规则:
- 文章里一行代码都没有,就别写
codeLicense。 给不存在的代码挂协议是空转, 还会让读者误以为正文、甚至整站源码受它约束。 - 写了
codeLicense,页脚才多出「代码」那枚徽章;打印版、Markdown 导出、llms-full.txt里的代码协议行同样只在写了的时候才输出。 - 它约束的只是别人把你文章里那段代码抄进自己项目时该遵守什么, 和本站自己的源码无关——站点源码由仓库根目录的 LICENSE(AGPL-3.0)统一约束。
- 只有
contentLicense会写进搜索引擎读的结构化数据;codeLicense仅作页面展示。
示例——一篇纯文字的文章:
---
title: '文章标题'
contentLicense: 'CC-BY-4.0'
# 没有代码,就不写 codeLicense
---一篇带代码示例的技术文章:
---
title: '文章标题'
contentLicense: 'CC-BY-SA-4.0'
codeLicense: 'MIT'
---# 一级标题
## 二级标题
### 三级标题
**粗体文字**
*斜体文字*
~~删除线~~
- 无序列表项
- 无序列表项
1. 有序列表项
2. 有序列表项
[链接文字](https://example.com)

> 引用文字
| 表格 | 表头 |
|------|------|
| 内容 | 内容 |需要让某段内容「跳出来」——比如用药风险、医疗免责声明、操作提醒——就用提示框。写法沿用 GitHub 的告示语法:在引用块(>)的第一行写 [!类型],正文照常写在后面的行里。
> [!WARNING]
> 请**定期进行血检**以确定药物的实际作用;若出现身体不适或血检结果异常,请及时停药并就医。上面会渲染成一个带图标与「警告」标题的琥珀色框。一共有五种类型:
| 标记 | 默认标题 | 颜色 | 适用场景 |
|---|---|---|---|
[!NOTE] |
备注 | 蓝 | 中性的补充信息 |
[!TIP] |
提示 | 绿 | 操作建议、小窍门 |
[!IMPORTANT] |
重要 | 粉 | 必须知道、但不涉及危险的关键点 |
[!WARNING] |
警告 | 琥珀 | 需要留意、可能有风险 |
[!CAUTION] |
危险 | 红 | 严重后果或强烈禁止 |
自定义标题:类型标记后面、同一行内还能写自己的标题,覆盖默认字样:
> [!NOTE] 医疗免责声明
> 本文仅供信息参考,不构成任何医疗建议。几条要点:
- 正文可以有多段,也能包含加粗、列表、链接、脚注等任意 Markdown。
- 类型不区分大小写,
[!warning]与[!WARNING]等价。 - 只有第一行是
[!类型]的引用块才会变成提示框;普通引用块(如放名言、放整段说明的> …)保持原样,不受影响。
每篇文章在构建时自动生成一张 1200×630 的社交分享图(OG Image),无需手动制作。 分享到微信 / X / Telegram / Slack 等平台时,预览图会呈现一张仿 GitHub 仓库卡片风格、 符合站点粉色设计系统的卡片,包含:
- 文章标题与简介
- 发布日期、更新日期(若有)、作者、预计阅读时长
- 标签与分类徽标
卡片由 src/lib/og/render.ts(satori 排版 → resvg 栅格化)绘制,端点为
src/pages/og/[...slug].png.ts,产物路径为 /og/<slug>.png,已自动写入文章页的
og:image / twitter:image。frontmatter 里的 cover 仅作页内题图,不再用作分享图。
首页、标签页等非文章页面共用一张站点默认封面 /og-cover.png,由
src/pages/og-cover.png.ts 在构建时生成(与文章卡同一套画布与品牌横幅),
无需手工维护图片文件。
卡片中文使用裁剪过的 Noto Sans SC 子集(仅含文章中出现过的字形,约 90 KB/字重,
位于 src/assets/og/fonts/)。仅当新文章的标题 / 简介 / 标签 / 作者里用到了
此前从未出现过的生僻字、且卡片上显示为「□」时,才需要重新生成:
pnpm run og:fonts # 重新裁剪字体子集,随后提交更新后的 .woff 文件绝大多数常用汉字已被现有文章覆盖,通常无需关心这一步。
每篇文章文末都有一个「下载 PDF」链接,读者点一下即可下载一份文字型 PDF (可选中、可搜索、链接可点、矢量高清、白底、每页顶部带站点标识),适合离线阅读与打印。
这些 PDF 在构建时自动生成,无需手动制作:
astro build先产出每篇文章的「打印视图」dist/print/<slug>/index.html(由src/pages/print/[...slug].astro渲染——一份只含 logo、文章头、正文、脚注、协议的 干净文档,去掉了导航 / 页脚 / 主题切换等站点 UI)。这些 HTML 只是 PDF 的渲染源。scripts/generate-pdfs.mjs再用无头 Chrome 打开这些页面,以浏览器打印引擎输出dist/print/<slug>.pdf(/print/<slug>.pdf),并随即删除对应的 HTML 目录—— 最终dist/print/下只保留干净的.pdf,不把中间产物部署上线。
二者已合并进 pnpm run build(即 astro build && node scripts/generate-pdfs.mjs),
因此 Cloudflare Pages 现有的构建流程会自动产出 PDF,无需改动。
本地开发:
pnpm run dev不生成 PDF(那是构建产物)。因此文末「下载 PDF」在 dev 下 改为指向可实时渲染的打印视图页(用于预览排版);pnpm run build/ 线上部署时才是真正的pnpm run build后打开dist/print/*.pdf。
几个要点:
- 中文字体:CF 构建环境没有中文系统字体,脚本会从已渲染的 HTML 收集全部用到的 字形(连 callout 标签、脚注「注释」等由插件生成、Markdown 源里没有的文字也一并覆盖), 据此把 Noto Sans SC 子集化后内嵌进 PDF——既不缺字、体积又小,且未来新增的组件文字会自动纳入。
- 正文样式复用
.article-content,所以任何未来新增、影响正文的全局样式都会自动出现在 PDF 里。 - 每页顶部 logo 由打印引擎的每页页眉渲染(读取
src/assets/brand/transcircle-horizontal.svg)。 - 失败不阻断部署:在 Cloudflare 构建中若无头浏览器不可用,脚本会跳过并以 0 退出
(沿用
indexnow的约定),部署照常,只是这次没有更新 PDF。
pnpm run build # 构建站点并生成全部文章 PDF(CF 用这个)
pnpm run build:site # 只构建站点、不生成 PDF(本地快速预览产物时用)
pnpm run pdf # 站点已构建(dist/ 存在)时,单独重跑 PDF 生成依赖说明:PDF 生成依赖
puppeteer。package.json里的pnpm.onlyBuiltDependencies已放行它的安装脚本,pnpm install会自动下载配套的 Chromium(约 150 MB,含在 pnpm 缓存中)。首次生成若本地无字体源,会从 notofonts/noto-cjk 下载完整 Noto Sans SC 到.cache/(与og:fonts共用缓存)。
站点图标只有一个源文件,全部产物都由它生成:
| 文件 | 用途 |
|---|---|
src/assets/brand/transcircle-mark.svg |
纯图标(环形标),图标唯一源文件 |
src/assets/brand/transcircle-horizontal.svg |
横幅 Logo(图标 + 字标),用于 OG 卡片页眉与封面 |
更换品牌标志时,替换上面两个 SVG,然后运行:
pnpm run icons # 重新生成 public/ 下的全部图标,随后一并提交脚本 scripts/generate-icons.mjs 会写出:logo-mark.svg(矢量图标,供页头 / 页脚与
现代浏览器的 rel="icon" 使用)、favicon.ico(16/32/48)、favicon.png、
icon-192.png、icon-512.png、icon-maskable.png(Android 需要的安全区留白 + 白底)、
apple-touch-icon.png(iOS 不支持透明,故补白底)。
OG 卡片的品牌横幅直接读取 transcircle-horizontal.svg,因此改完图标重新构建即可,
不需要额外操作。
- Node.js >= 24
- pnpm(包管理器)
pnpm installpnpm run dev访问 http://localhost:4321 预览
pnpm run build构建结果输出到 dist/ 目录
博客已连接 Cloudflare Pages,推送代码后自动部署。
-
编辑/添加文章
# 修改或添加 src/content/posts/ 下的文件 -
本地预览(可选)
pnpm run dev
-
提交更改
git add src/content/posts/新文章.md git commit -m ":memo: docs(posts): add weekly development report" git push -
自动部署
- 代码推送到 main 分支后
- Cloudflare Pages 会自动构建并部署
- 约 1-2 分钟后可在 blog.transcircle.org 看到更新
使用以下格式提交:
:memo: docs(posts): 添加文章标题或简要描述
常用前缀:
:memo:- 添加/修改文章:bug:- 修正文章错误:fire:- 删除文章
blog/
├── src/
│ ├── content/posts/ # 文章目录(你主要操作这里)
│ ├── components/ # UI 组件
│ ├── layouts/ # 页面布局
│ ├── pages/ # 页面路由
│ ├── assets/
│ │ ├── brand/ # 品牌 SVG(图标 / 横幅 Logo 的源文件)
│ │ └── og/fonts/ # OG 卡片用的 Noto Sans SC 子集字体
│ ├── lib/og/ # OG 卡片绘制
│ ├── lib/markdown/ # Markdown 扩展(提示 / 警告框等 rehype 插件)
│ └── styles/ # 样式文件
├── scripts/ # 构建期工具(图标生成、字体子集、IndexNow)
├── public/ # 静态资源(图片、图标等,图标由脚本生成)
├── dist/ # 构建输出(自动生成)
├── LICENSE # 仓库代码的许可证(AGPL-3.0)
└── ...配置文件
A: 图片放在 public/images/ 目录下,文章中引用路径为 /images/图片名.png
A: pubDate 为过去的日期会立即显示;未来日期的文章会等到日期到达后自动显示
A: 在 Frontmatter 中设置 draft: true,该文章不会出现在网站上
A: 直接删除 src/content/posts/ 下的对应文件并提交即可
A: 分类是文章的大类(如"开发进度"),标签是更细粒度的关键词(如"astro", "前端")。一篇文章只有一个分类,可以有多个标签
本项目遵循 TransCircle 全局设计系统(../docs/DESIGN.md),落地方式与博客特有的偏离记录在
DESIGN.md:
- 两套主题:浅色 / 深色(高对比度模式已按全局规范移除,对比度由令牌自身色值保证)
- 所有颜色 / 圆角 / 字号 / 动效走 CSS 变量,组件里不写死数值
- 外壳宽 1280px、正文宽 960px;所有交互支持键盘导航与屏幕阅读器
- Astro - 静态站点生成器
- TypeScript - 类型安全
- Markdown - 文章格式
- Shiki - 代码语法高亮
- Fuse.js - 搜索功能
本站针对传统搜索引擎(SEO)与生成式引擎 / AI 检索(GEO)做了系统优化。以下产物在每次 pnpm run build 时自动生成,无需手动维护,永不过期:
| 产物 | 路径 | 说明 |
|---|---|---|
| 站点地图 | /sitemap-index.xml |
含每篇文章真实的 lastmod、changefreq、priority;自动排除搜索页 |
| 结构化数据 | 各页 <head> 内 JSON-LD |
Organization / WebSite(含站内搜索框)/ Blog / BlogPosting / FAQPage / BreadcrumbList / CollectionPage |
| AI 索引 | /llms.txt |
遵循 llmstxt.org 约定:实体消歧 + 自动文章清单 |
| AI 全文快照 | /llms-full.txt |
内联全部文章正文,供 LLM / RAG 一次性摄取 |
| 文章 Markdown 原文 | /posts/<slug>.md |
每篇文章的纯 Markdown 版本,便于 AI 抓取 |
| 搜索索引 | /search-index.json |
客户端全文搜索数据 |
| RSS | /rss.xml |
文章订阅源 |
| 爬虫规则 | /robots.txt、/ai.txt |
显式欢迎主流搜索引擎与 AI 爬虫 |
注意:
llms.txt/llms-full.txt/search-index.json现由src/pages/*.ts端点在构建时生成,不再提交到public/,因此不会随内容更新而出现陈旧副本。
这些步骤需要账号或在部署后执行,无法纯靠代码完成:
-
Google Search Console(https://search.google.com/search-console):添加资源
blog.transcircle.org→ 提交站点地图sitemap-index.xml。如需站点验证,可在文章 frontmatter 之外,于Layout.astro的<head>加一行<meta name="google-site-verification" content="...">。 -
Bing Webmaster Tools(https://www.bing.com/webmasters):添加站点并提交 sitemap(可直接从 GSC 导入)。Bing 验证后即自动支持 IndexNow。
-
IndexNow 主动推送(让 Bing / Yandex / Seznam 等即时收录)。IndexNow 只是「通知 URL 变更」的一次 HTTP 请求,提交的是绝对 URL,在哪里运行都可以,不需要跑在生产服务器上。本项目部署在 Cloudflare Pages,按偏好三选一:
- 方式 A · Cloudflare Crawler Hints(推荐,零维护):登录 Cloudflare → 选择
transcircle.org域名 → Caching / 缓存 → Configuration → Crawler Hints 开启即可。之后 Cloudflare 会在内容变化时自动通过 IndexNow 推送,无需本脚本。要求该域名通过 Cloudflare 代理(Pages 自定义域名默认满足)。 - 方式 B · 嵌入 Pages 构建命令(全自动、可控):在 Cloudflare Pages 项目设置里,把「构建命令」改为:
脚本已做适配:仅在生产分支(默认
pnpm run build && pnpm run indexnowmain)提交,且在 Cloudflare 构建环境中即使提交失败也不会让部署失败。生产分支名不同可设环境变量INDEXNOW_PRODUCTION_BRANCH。 - 方式 C · 本地手动(最简单):每次发文部署后,在本地跑一次:
因为提交的是线上绝对 URL,本地运行同样生效。
pnpm run build && pnpm run indexnow
密钥文件
public/b1ba2832c93fda19d24eb2a7b7e91ca3.txt部署后可通过https://blog.transcircle.org/b1ba2832c93fda19d24eb2a7b7e91ca3.txt访问,用于所有权校验,请勿删除或改名。 - 方式 A · Cloudflare Crawler Hints(推荐,零维护):登录 Cloudflare → 选择
-
首次或大更新后:在 GSC 用「网址检查 → 请求编入索引」对首页与新文章手动催收,通常最快。
仓库代码:AGPL-3.0。本站是通过网络提供服务的程序, AGPL 第 13 条要求:任何修改后部署的版本,都必须向其使用者提供对应的完整源码。
文章内容:逐篇声明,默认 CC-BY-SA-4.0,见许可协议。
文章 frontmatter 里的 contentLicense / codeLicense 只约束该篇文章本身,
不影响仓库代码的授权。
