Sonder 把站点级信息集中在根目录的 site.config.toml,而不是散落在组件里。配置结构由 src/config/schema.ts 中的 Zod schema 校验;字段缺失或类型不对时,bun run build 会直接报错。
站点与作者
[config.site]title = "Sonder"description = "Sonder 的个人博客。"pageTitle = "Sonder"url = "https://sonder.liang.one"repository = "https://github.com/lmb666666/Sonder"timeEstablished = "2026-10-04"
[config.profile]name = "Sonder"role = "写博客的人"avatar = "/images/logo.svg"页脚与桌面首页署名读取 profile.name;站点程序名读取 siteInfo.program。
站点信息卡
[config.siteInfo]title = "站点信息"program = "Sonder"uptime = truetotalWords = truelastContentUpdate = truelastUpdated = truebuildPlatform = trueprogram 会显示为「站点程序」一行,也用于页脚的 Powered by;留空时两处一起隐藏。uptime、totalWords、lastContentUpdate、lastUpdated 和 buildPlatform 控制其余信息行。lastUpdated 是构建时间,lastContentUpdate 取文章发布时间与修改时间的最大值。
导航与外观
[config.theme]palette = "orange-soft"lang = "zh-CN"navStyle = "pill"palette:默认色盘,可选green-soft、green-vivid、rose-soft、pink-soft、purple-soft、blue-soft、orange-soft、brown-softlang:zh-CN、zh-TW或ennavStyle:pill胶囊导航或bar通栏工具条
顶部导航由 [[config.topNav.links]] 控制,每项填写 label 与 href。
字体与代码块
[config.fonts]en = "Maple Mono"code = "Monaco"zh = "ChillRoundF"file = "assets/fonts/ChillRoundFRegular.woff2"
[config.code]lineNumbers = truewrap = falsepreserveIndent = truecollapseStyle = "collapsible-auto"languageBadge = truecollapseLines = 15previewLines = 8fonts.file:构建期源字体,仅用于生成public/fonts下的 UI / 内容子集,本身不会部署。code.wrap:桌面端是否自动换行;false时横向滚动,窄屏仍由样式强制换行。code.languageBadge:是否在代码块右上角显示语言徽章。code.collapseLines/previewLines:超过指定行数自动折叠,以及折叠时预览的行数。- 代码块主题固定为纸面主题,token 颜色跟随色盘与深浅色,无需配置主题名。
页面文案
页面标题、kicker 和说明都在 [config.pages] 下:
[config.pages.blog]title = "文章"kicker = "归档"subtitle = "长文与随想的归档。"listLayout = "media"
[config.pages.links]title = "朋友"kicker = "Friends"subtitle = "那些人,那些事。"文章页的 listLayout = "media" 会使用带封面的磨砂卡片;改成 rows 则回到行式列表。postsPerPage 控制每页文章数。
文章页组件
[config.article]share = truenavigation = truemorePosts = trueshare:文章底部分享卡片navigation:上一篇 / 下一篇morePosts:更多文章列表
首页
[config.home.latest]count = 2heatmapWeeks = 20showHeatmapLatest = truecount 控制首页「最新」展示的文章数量。首页引语、介绍和联系方式分别在 [config.home.quote]、[config.home.intro] 与 [[config.home.links]] 中维护。
搜索、评论与朋友圈
[config.search]enabled = trueplaceholder = "搜索文章…"maxResults = 6
[config.comments]enabled = false
[config.friendCircle]feed_src = ""pageSize = 20评论支持 giscus、utterances、Waline、Twikoo 或关闭;具体凭据在对应的 [config.comments.*] 区块中填写。朋友页的 feed_src 可以指向 Friend-Circle-Lite 订阅源,也可以留空使用 public/friend-circle.json 或构建期 RSS 聚合。
友邻(Youlin)
可选接入 友邻:友链和朋友圈改由 Youlin 接口提供,本地数据与 friendCircle 配置保留为回退。
[config.youlin]baseUrl = "https://youlin.example.com"timeoutMs = 8000mode = "build" # build | client
[config.youlin.links]sources = ["youlin", "local"]
[config.youlin.circle]sources = ["youlin", "friendcircle", "public", "rss", "demo"]
[config.youlin.apply]provider = "auto" # auto | youlin | github | none# Youlin 开启 Turnstile 时填写它的公开 site keyturnstileSiteKey = ""
[config.youlin.directives]friendCircle = "auto"friendLinkCard = "auto"baseUrl为空时完全沿用原有本地链路,不会发出任何 Youlin 请求。sources按顺序尝试:只有网络/HTTP/解析失败才继续下一个源;Youlin 返回 200 且 JSON 合法即采用(空结果也有效)。mode = "build"在构建期 SSR,SEO 与 Pagefind 覆盖最好;mode = "client"先渲染构建期回退,浏览器再请求 Youlin 替换 DOM。可在links/circle下单独覆盖。client 刷新只在youlin位于对应sources第一位时生效;把local放前面会退回构建期行为。apply.provider = "auto"时,配了baseUrl就用 Youlin 的/apply接口:表单在当前页面直接 POST,不跳转;开启 Turnstile 时把公开 site key 填到turnstileSiteKey。也可强制github/none。- 浏览器内提交与 client 刷新都要求 Youlin 的
api.corsOrigin允许博客域名;启用 Turnstile 时 site key 也要允许该域名。 - 文章里的
::friend-circle{src="youlin"}与::friend-link-card{src="youlin"}同样可用;不写src时取directives.*的默认值。 - 环境变量是覆盖层:
SONDER_YOULIN_BASE_URL覆盖地址,SONDER_YOULIN_MODE覆盖全局以及links/circle的 mode;无效值会被忽略并回退 TOML。适合 CI 或预览环境。复用本地 Astro 内容缓存时,如果发现文章内指令没有跟随新配置,用bunx astro build --force重建。 - build 模式下数据变化需要重新构建:可以在 Youlin 设置
rebuild.*webhook / GitHub dispatch 触发本站构建,或手动重建。
统计与分析(Umami / 51la)
访问统计是可选的,所有 ID 留空就不会加载任何第三方脚本。
[config.analytics]sendInDev = false
[config.analytics.umami]websiteId = ""scriptUrl = ""hostUrl = ""
[config.analytics.la51]id = ""lingqueMonitorId = ""- Umami:
websiteId和scriptUrl都填写才启用。scriptUrl填 Umami 实例的script.js地址;如果脚本走 CDN 或镜像,hostUrl必须填 Umami 实例地址,否则数据会发到脚本所在域。站点域名填在 Umami 后台即可。 - 最新版 Umami 会自动跟随
ClientRouter的站内换页,不需要手动上报 pageview。 - 51la:填
id启用;再填lingqueMonitorId会额外加载灵雀 perf SDK,启用sendSpaPv与sendSuspicious。灵雀 SDK 失败不影响 51la。灵雀会采集应用异常与可疑行为数据,开启前请确认其隐私说明。 - Umami 和 51la 同时开启会各自统计一份,数字不会一致,通常二选一即可。
sendInDev = false时开发环境不加载统计脚本。Vercel Preview 请在环境变量里设置SONDER_ANALYTICS_DISABLED=1,并且只勾选 Preview,不要影响 Production。- 统计脚本异步加载,被广告拦截器拦截时只影响统计,不影响页面。
Markdown 开关
[config.markdown] 控制数学公式与 Mermaid 图表:
[config.markdown]math = truemathRenderer = "katex" # "katex" | "mathjax"mermaid = true提醒块、外挂指令与响应式表格始终开启——文章内容依赖它们,因此不提供开关。
页面与集合
书影音与朋友页是普通页面加内容集合,动态页读取 Ech0 或 src/data/moments.ts,都不需要注册。删除 src/pages/media/ 与 src/content/media/ 即移除书影音,导航项同步从 site.config.toml 删除。项目卡片直接读取 src/content/projects/,由关于页展示;没有独立项目页。短记录统一使用 /moments。
动态页与特殊内容
[config.pages.moments]title = "动态"kicker = "Moments"subtitle = "记录生活点滴。"note = ""# Ech0 实例地址;留空使用 src/data/moments.ts 的演示数据apiUrl = ""pageSize = 20showPoweredBy = true
[config.music]# ::music 指令与动态页音乐卡共用的 Meting 实例meting_api = "https://api.example.com/meting/?server=:server&type=:type&id=:id&r=:r"apiUrl留空时展示内置演示数据;填写 Ech0 实例地址后,页面在浏览器里请求POST {apiUrl}/api/echo/query,实例需允许当前站点域名跨域。pageSize同时用于静态演示分页和 Ech0 每次请求的条数。- 音乐卡复用
[config.music].meting_api在浏览器解析网易云 / QQ / 酷狗单曲;Meting 或音频不可用时,网易云自动降级为官方外链播放器,其他平台保留原曲链接卡。Meting 实例需允许站点域名跨域(公共实例通常为*)。 - 视频自动识别 B 站、YouTube、抖音、TikTok;位置扩展带
latitude/longitude时生成高德 marker 链接与坐标;GitHub、网站、推文复用文章指令的纸面卡片。 - 图片按 1–9 张自动布局,点击进入 PhotoSwipe 灯箱;Echo 文本会转义,扩展链接只接受无凭据的 http(s) 地址。