一套可移植、有主张的 Quarto 书籍脚手架 —— 适合教材、讲义和长篇技术写作。
本模板从一个真实的中文教材项目抽象而来,让下一本书可以直接接续上一本的成果 —— 现成可用的 Lua filter、合理的 callout 样式、两套渲染 profile,以及一条命令即可克隆的章节脚手架。
- 📚 Quarto book + website 双形态 —— 一次渲染即可得到可导航的 HTML 站点(如有需要也可输出 PDF)。
- 🎨 基于 Lua filter 的语义代码块 ——
```bash、```opencode、```agent、```skill由styles.css统一上色。 - 💬 Callout 风格指南 ——
note、tip、warning、important、caution五类的使用约定。 - 🔀 两套渲染 profile ——
_quarto-full.yml(完整版)与_quarto-selection.yml(精选子集,例如工作坊用)。 - 🧱 章节脚手架 ——
chapters/chapter-template/内置index.md、各小节与小结,复制即可起新章。 - 🖼️ Mermaid 图表 —— 开箱即用,原生支持。
- 🇨🇳 中文优先的默认设置 ——
lang: zh与中文友好的排版细节,也很容易切到英文或其他语言。 - 💬 可选的 AI 问询浮窗 —— 自带"问问 AI"浮动按钮 + SSE 流式回答(默认关闭);填一个你自己后端的 URL 即可启用,详见
docs/ai-ask-widget.md与下文「AI 问询浮窗」。
- 拷贝模板到目标位置作为新书目录:
cp -R quarto-book-template my-book && cd my-book
- 个性化
_quarto.yml—— 运行交互式初始化脚本(推荐):脚本会依次询问标题、副标题、作者、侧栏短标题、GitHub 地址和语言代码,然后就地改写./scripts/init-book.sh
_quarto.yml(同时保存一份_quarto.yml.bak备份)。也可以传旗标用于自动化:./scripts/init-book.sh --title "我的书" --author "我" \ --github "https://github.com/me/my-book" --lang zh
- 替换封面与 logo —— 把自己的
images/book-logo.png与images/cover.png放到对应位置。 - 新建章节 —— 复制
chapters/chapter-template/(或使用辅助脚本):./scripts/new-chapter.sh 1 "引言" - 接入 profile —— 把章节登记到
_quarto-full.yml与_quarto-selection.yml。(scripts/new-chapter.sh会直接打印好可粘贴的 YAML 片段。) - 写作与构建:
quarto preview # 写作时实时预览 ./scripts/render.sh full # 渲染完整版到 _book/ ./scripts/render.sh selection # 渲染精选子集
quarto-book-template/
├── _quarto.yml # 基础配置(标题、作者、侧栏、主题)
├── _quarto-full.yml # Profile:完整版书籍
├── _quarto-selection.yml # Profile:精选子集
├── _quarto-pdf.yml # Profile:PDF 输出(LaTeX/LuaLaTeX)
├── styles.css # 语义代码块与 callout 样式
├── opencode-prompt.lua # 语义代码块的 Lua filter
├── index.md # 首页
├── images/
│ ├── README.md # 封面 / logo 的尺寸建议
│ ├── book-logo.png
│ └── cover.png
├── chapters/
│ └── chapter-template/ # 每写一章就复制一份
│ ├── index.md
│ ├── section-1.md
│ ├── section-2.md
│ ├── summary.md
│ └── images/
├── assets/ # 可选 AI 问询浮窗的前端资源
│ ├── js/ai-ask.js
│ ├── css/ai-ask.css
│ └── partials/ai-ask.html
├── docs/
│ ├── quarto-quickstart.md
│ ├── semantic-code-blocks.md
│ ├── css-class-reference.md
│ ├── ai-ask-widget.md
│ └── style-guides/
│ ├── callout-style-guide.md
│ └── content-module-guide.md
├── scripts/
│ ├── init-book.sh # 个性化 _quarto.yml(拷贝模板后跑一次)
│ ├── new-chapter.sh # 新建一章的脚手架
│ └── render.sh # 用指定 profile 渲染
├── LICENSE # MIT —— 覆盖代码、配置、脚本、样式
├── LICENSE-CONTENT # CC-BY 4.0 —— 覆盖书稿正文 / 章节内容
└── README.md
模板鼓励用语义化的代码块类名替代笼统的 ```python:```bash(终端会话)、```opencode(写给编程 agent CLI 的自然语言提示词)、```agent(agent 定义文件)、```skill(skill 定义文件)。Lua filter(opencode-prompt.lua)与 CSS(styles.css)配合,把每类代码块渲染成截然不同的视觉风格,读者一眼就能分辨它们各自的角色。
完整目录与示例见 docs/semantic-code-blocks.md。
Quarto 的 profile 机制允许同一份源码渲染出多本书:
_quarto-full.yml—— 完整版,所有章节都包含。用于成稿教材。_quarto-selection.yml—— 精选子集,例如 4 章的工作坊读本,或对外宣传的"试读版"。_quarto-pdf.yml—— PDF 输出(基于 LaTeX,使用 LuaLaTeX 引擎,已配置好 CJK 支持)。所需工具与字体见docs/quarto-quickstart.md。
切换 profile 用 quarto render --profile full、--profile selection、--profile pdf(render.sh 是这条命令的封装)。
模板自带一个"问问 AI"的浮动入口(默认右下角),让读者能用自然语言提问、得到针对当前页面源文档的 SSE 流式回答。默认关闭,三步开启:
-
指向你的后端。编辑
assets/partials/ai-ask.html,把ai-ask-endpoint的content改成你的 SSE 接口:<meta name="ai-ask-endpoint" content="https://api.example.com/ask">
留空 → widget 静默不挂载(默认状态)。
-
重新渲染:
./scripts/render.sh full。每页右下角就会出现"问问 AI"按钮(⌘ / Ctrl + J 也能开关)。 -
后端实现 SSE 契约。最小载荷
{question, page_url, page_title, history},响应Content-Type: text/event-stream,发四类事件source / delta / meta / done(见docs/ai-ask-widget.md§3 完整契约 + 一份 130 行 FastAPI 参考实现)。本仓库附带scripts/_test_ai_server.py作为本地联调用的"开箱即用"参考后端(接 OpenAI 兼容 API,把当前页.md全文塞进 system prompt)。
特性一览:
- SSE 流式输出:逐 token 显示,配闪烁光标
▍;Stop 按钮可中途取消。 - 多轮上下文:自动把历史轮次附在请求里(
history数组,可由ai-ask-history-capmeta 调整上限);sessionStorage 持久化 24h,刷新可恢复。 - Quarto callouts 原生渲染:LLM 回答里若出现
::: {.callout-tip}等 Pandoc fenced div,会渲染成带颜色边的卡片(5 类全支持)。 - 多代码块、表格、Markdown 完整保真:基于 marked.js v15 GFM。
- 截断显式提示:若 LLM 因
max_tokens截断(finish_reason = "length"),气泡末尾追加灰色斜体提示,避免"无声中断"。 - 移动端友好:使用
100dvh视口单位,≤600px 自动全屏化,输入框始终可达。 - 隐私最小化:默认仅发送当前页 URL + 标题 + 用户问题。如需 RAG,由后端按 URL 拉取/索引源文档。
调试旋钮(都是 assets/partials/ai-ask.html 里的可选 <meta>):
| meta | 默认 | 用途 |
|---|---|---|
ai-ask-trigger-label |
问问 AI |
按钮文字 |
ai-ask-shortcut |
j |
⌘/Ctrl + 此键开关 |
ai-ask-book |
由 <title> 推断 |
sessionStorage 命名空间 |
ai-ask-history-cap |
20 |
历史轮数上限(clamp 1–100) |
ai-ask-debug |
空 | 设为 1 暴露 window.__aiAsk 调试 API |
完整契约、后端示例、调试 API 详见 docs/ai-ask-widget.md。
- 📘
docs/quarto-quickstart.md—— 极简的 Quarto 入门复习 - 🎨
docs/semantic-code-blocks.md—— 语义代码块系统详解 - 🧾
docs/css-class-reference.md—— 模板自带的所有 CSS 类速查 - 💬
docs/style-guides/callout-style-guide.md—— 五类 callout 的选用指南 - 🧩
docs/style-guides/content-module-guide.md—— 章节结构与内容模块的写作主张 - 💬
docs/ai-ask-widget.md—— AI 问询浮窗:完整 SSE 契约、FastAPI 后端示例、调试 API
- 改语言。 把
_quarto.yml里的lang: zh改成en(或其他语言代码),Quarto 会处理后续。同时记得改侧栏标签和章节模板里的中文文案。 - 换主题。 默认是
cosmo。可以试flatly、cerulean、darkly,或 Bootswatch 上任何主题 —— 改_quarto.yml中的theme:字段即可。 - 不要 Lua filter。 如果用不到语义代码块,从
_quarto.yml删掉filters:项,再删掉opencode-prompt.lua。普通的 fenced code block 仍然可用。 - 加 PDF 目标。 在
_quarto.yml的format:下加pdf:项;若没有 TeX 环境,运行quarto install tinytex装一份 TinyTeX。 - 定制 callout。 调整
styles.css里的.callout-*规则,或在_quarto.yml里覆盖 Quarto 默认的callout-icon/callout-appearance。 - 重组章节。 章节文件夹名只是约定 —— 真正起作用的是你登记到
_quarto-full.yml/_quarto-selection.yml里的列表。
本模板采用双协议:
- 代码、配置、脚本与样式资源(
*.yml、*.css、*.lua、*.sh、scripts/、docs/)—— 采用 MIT 协议。见LICENSE。 - 书稿正文 / 章节内容(
chapters/下的.md文件以及任何作者撰写的稿件材料)—— 采用 CC-BY 4.0 协议。见LICENSE-CONTENT。
开始写作后,请把这两份协议替换成你自己选择的协议与署名。
本模板抽象自一个关于 AI agent 的真实中文教材项目。这里编码的诸多约定(语义代码块、callout 纪律、双 profile)都是写那本书时打磨出来的,并已沉淀在 docs/ 中,让下一本书直接受益。
用 ❤️ 与 Quarto 构建。