Callout
- 接入 satteri-callouts(HAST 插件),用 Obsidian 语法:
> [!tip] 标题
> 内容
> [!warning]- 默认折叠
类型名大小写不敏感,支持嵌套、可折叠、标题内联 Markdown。
- 样式没有用它自带的主题 CSS(Obsidian 原版是高饱和蓝/青/紫,还靠
mix-blend-mode 叠底色,在暖纸底上会发脏),改为新建 src/styles/callouts.css,
复用主题已有的 --admonitions-color-* token,与 .admonition(免责声明块)
统一成「3px 左边框 + 彩色标题、无底色」。
- 类型映射:tip/hint→tip,note/info/todo/abstract/summary/tldr→note,
important/example→important,warning/attention/question/help/faq→warning,
caution→caution,success/check/done→(新增的)success,
danger/error/failure/fail/missing/bug→destructive,quote/cite→muted-foreground。
- global.css 补一个 --admonitions-color-success(浅色 oklch(0.62 0.16 150) /
深色 oklch(0.7 0.18 150)),与 tip(180)/note(250)/important(310) 同明度彩度。
脚注中文化
features.gfm.footnotes 设 label「脚注」、backLabel「返回第 {reference} 条」、
backContent「↑」,替换默认的 Footnotes / Back to reference。
正文
- 周末愉快.md:`::: tip 下周计划`(冒号后有空格,从来不是合法指令,
一直渲染成普通段落)改成 `> [!tip] 下周计划`,任务列表一并加 `>` 前缀。
- 关于价值感和归属感的思考.md 的 `> [!tip] Tip` 本来就合法,一行未改,
现在自动变成真 callout。
顺带修
autolink-headings 不再给脚注区那个 sr-only 的「脚注」标题加 # 锚点。
验证
- 两处 callout 均正确渲染;callout 内的图片仍带 data-lightbox-src
(说明 imageLightbox 与 satteriCallouts 的执行顺序没问题)。
- 临时加了一篇带脚注和折叠 callout 的文章验证:脚注文案、返回链接、
折叠态 <details>/<summary> 结构都正确,验证后已删除。
- 整页对比基线:37/41 一致,4 处差异中 2 处是本次有意的 callout 生效,
另 2 处是已知的智能标点引号方向(Sätteri 的结果更正确)。
- pnpm build 41 页 + pagefind 通过。
132 lines
4.8 KiB
JavaScript
132 lines
4.8 KiB
JavaScript
import { defineConfig } from "astro/config"
|
||
import react from "@astrojs/react"
|
||
import sitemap from "@astrojs/sitemap"
|
||
import mdx from "@astrojs/mdx"
|
||
import { pluginCollapsibleSections } from "@expressive-code/plugin-collapsible-sections"
|
||
import { pluginLineNumbers } from "@expressive-code/plugin-line-numbers"
|
||
import expressiveCode from "astro-expressive-code"
|
||
import { pluginLanguageBadge } from "./src/plugins/expressive-code/language-badge"
|
||
import { pluginCustomCopyButton } from "./src/plugins/expressive-code/custom-copy-button"
|
||
import { satteri, satteriHeadingIdsPlugin } from "@astrojs/markdown-satteri"
|
||
import { excerpt } from "./src/plugins/satteri/excerpt.mjs"
|
||
import { readingTime } from "./src/plugins/satteri/reading-time.mjs"
|
||
import { sectionize } from "./src/plugins/satteri/sectionize.mjs"
|
||
import { shiftHeadings } from "./src/plugins/satteri/shift-headings.mjs"
|
||
import { autolinkHeadings } from "./src/plugins/satteri/autolink-headings.mjs"
|
||
import { imageLightbox } from "./src/plugins/satteri/image-lightbox.mjs"
|
||
import { satteriKatex } from "satteri-katex"
|
||
import satteriCallouts from "satteri-callouts"
|
||
import { site } from "./src/data/site"
|
||
|
||
export default defineConfig({
|
||
srcDir: "./src",
|
||
output: "static",
|
||
site: site.url,
|
||
trailingSlash: "always",
|
||
alias: {
|
||
"@": "./src",
|
||
},
|
||
integrations: [
|
||
expressiveCode({
|
||
themes: ["github-dark", "github-light"],
|
||
themeCssSelector: (theme) => {
|
||
// 根据主题名称返回对应的 CSS 选择器
|
||
if (theme.name === "github-light") return ":root:not(.dark)"
|
||
return ".dark"
|
||
},
|
||
plugins: [
|
||
pluginCollapsibleSections(),
|
||
pluginLineNumbers(),
|
||
pluginLanguageBadge(),
|
||
pluginCustomCopyButton(),
|
||
],
|
||
defaultProps: {
|
||
wrap: true,
|
||
overridesByLang: {
|
||
shellsession: {
|
||
showLineNumbers: false,
|
||
},
|
||
},
|
||
},
|
||
styleOverrides: {
|
||
codeBackground: "var(--codeblock-bg)",
|
||
borderRadius: "0.75rem",
|
||
borderColor: "transparent",
|
||
codeFontSize: "0.875rem",
|
||
codeFontFamily: "var(--font-mono), ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, monospace",
|
||
codeLineHeight: "1.625",
|
||
frames: {
|
||
editorBackground: "var(--codeblock-bg)",
|
||
terminalBackground: "var(--codeblock-bg)",
|
||
terminalTitlebarBackground: "var(--codeblock-topbar-bg)",
|
||
editorTabBarBackground: "var(--codeblock-topbar-bg)",
|
||
editorActiveTabBackground: "transparent",
|
||
editorActiveTabIndicatorBottomColor: "var(--primary)",
|
||
editorActiveTabIndicatorTopColor: "transparent",
|
||
editorTabBarBorderBottomColor: "var(--codeblock-topbar-bg)",
|
||
terminalTitlebarBorderBottomColor: "transparent",
|
||
},
|
||
},
|
||
frames: {
|
||
showCopyToClipboardButton: false,
|
||
},
|
||
}),
|
||
react(),
|
||
sitemap(),
|
||
mdx(),
|
||
],
|
||
compressHTML: true,
|
||
markdown: {
|
||
// Astro 7 的 Sätteri 管线。以下插件是 unified 时期 remark/rehype 插件的对应移植,
|
||
// 见 src/plugins/satteri/。
|
||
//
|
||
// 注意:math 只负责「解析」,渲染成 KaTeX 需要额外的 HAST 插件 —— 尚未迁移。
|
||
processor: satteri({
|
||
// dashes: false 是为了和迁移前的输出逐字一致:Astro 的 unified 管线
|
||
// 会把直引号排成弯引号,但不转换 --- (Sätteri 默认会转成破折号)。
|
||
features: {
|
||
math: true,
|
||
smartPunctuation: { dashes: false },
|
||
// 脚注文案中文化(默认是 "Footnotes" / "Back to reference 1")
|
||
gfm: {
|
||
footnotes: {
|
||
label: "脚注",
|
||
backLabel: "返回第 {reference} 条",
|
||
backContent: "↑",
|
||
},
|
||
},
|
||
},
|
||
mdastPlugins: [
|
||
readingTime,
|
||
excerpt,
|
||
shiftHeadings(),
|
||
sectionize(),
|
||
// KaTeX 必须排在 reading-time / excerpt 之后:它把 math 节点换成 KaTeX 的
|
||
// HTML,先换的话 ctx.textContent() 会把 KaTeX 标记也算进字数。
|
||
satteriKatex(),
|
||
],
|
||
hastPlugins: [
|
||
satteriHeadingIdsPlugin(),
|
||
autolinkHeadings,
|
||
imageLightbox,
|
||
// Obsidian 语法的 callout:> [!tip] 标题
|
||
satteriCallouts(),
|
||
],
|
||
}),
|
||
},
|
||
vite: {
|
||
server: {
|
||
watch: {
|
||
/*
|
||
* 项目根目录下的 .pnpm-store 是 pnpm 的内容寻址仓库:5.4 万个文件、672 MB,
|
||
* 而且已经被 .gitignore 忽略。Vite 默认会把项目根整个 watch,加上它以后
|
||
* inotify 直接到顶(max_user_watches = 65536),dev server 一启动就刷屏:
|
||
* ENOSPC: System limit for number of file watchers reached
|
||
* 排除掉即可。node_modules / .git 是 Vite 默认就排除的,不用管。
|
||
*/
|
||
ignored: ["**/.pnpm-store/**"],
|
||
},
|
||
},
|
||
},
|
||
})
|