This commit is contained in:
pluv committed 2026-10-08 12:29:59 +08:00
commit 0285b2a5d1
12 files changed
+4243

No files matched your search

+61
View File
@@ -0,0 +1,61 @@
# marp-tectonics
克制、锐利、适于规模作图的科研汇报用 marp 主题, 专为高信息熵、层级突出和印刷品风格设计, 并带有若干排版辅助扩展语法.
## 在其他幻灯片中使用
1. 在 `marp.config.mjs` 里把主题目录注册进来:
```js
export default {
themeSet: ['../tectonics/theme'],
allowLocalFiles: true,
}
```
2. 在 frontmatter 里选中主题、声明画幅:
```yaml
theme: tectonics
size: 16:9 # 或 4:3, 主题两种都适配
```
3. 构建:`marp --html -o deck.html deck.md`
主题的元数据里同时声明了 `@size 16:9 1280px 720px` 和 `@size 4:3 960px 720px`
## 扩展语法
| 语法 | 效果 |
| :--- | :--- |
| `<!-- _class: cover -->` + 四行文字(小字/`##` 主标题/学院+姓名/日期) | 封面: 通栏色带 + 居中三行 |
| `<!-- _class: toc -->` + `## 报告内容` + 有序列表 | 目录页: 左侧大字标题 + 竖线 + 右侧「一、二、…」 |
| `<!-- _class: cols -->` + 用 `<div>` 包住的两栏内容 | 左右两栏, 其余元素整行 |
| `<!-- _class: steps -->` + `## 一、…` + 有序列表 | 章节页: 蓝底白字 01/02/… 编号条 |
| `<!-- header: 章名 -->` | 右上角页眉, 从这页起一直生效(封面/章节页自动不显示) |
| `<p class="point">…</p>` / `<p class="key">…</p>` | 整段红色居中 / 主色蓝居中 |
| `<span class="red">…</span>` / `<span class="blue">…</span>` | 行内改色 |
| `<p class="caption">…</p>` | 图片说明的小灰字 |
| `<div class="tight">…</div>` / `<div class="tighter">…</div>` | 内容偏多时整块缩到 0.85em / 0.78em |
| `<div class="mid">…</div>` / `<div class="bottom">…</div>` | 块内水平居中 / 在正文页里靠底 |
| `<div class="flow">` + `.flow-box`(可加 `is-bad` / `is-good`) + `.flow-arrow` | 纯 CSS 的简易流程图 |
| ` ```mermaid ` 代码块 | 构建时渲染成内联 SVG(需挂 `tools/marp-mermaid-engine.mjs`) |
## 可调参数
- `--tectonics-accent` 主色(默认 `#004e98`, 取自 `design.1.png`), `--tectonics-red` 强调红
- `--tectonics-sans` / `--tectonics-serif` 标题与正文字体
- `--tectonics-title-size` / `--tectonics-title-rule` 页标题字号与下方细线
- `--toc-*`(目录页位置与字号)、`--step-*`(章节编号条尺寸)按画幅各自一组
## 示例与构建
example 目录带有一份示例
```sh
marp --html -o pre.html pre.md # 重新生成示例
```
## 开放源代码协议
该主题在 MIT 协议的约束下开放源代码(vendor 下引用的第三方代码遵循它们自己的协议), 欢迎发起拉取请求并贡献改进.
+5
View File
@@ -0,0 +1,5 @@
export default {
themeSet: ['../theme'],
allowLocalFiles: true,
engine: '../tools/marp-mermaid-engine.mjs',
}
Binary file not shown.

After

Width:  |  Height:  |  Size: 120 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 236 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 268 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 185 KiB

+122
View File
@@ -0,0 +1,122 @@
6202 级研究生毕业答辩
高活泼性 *Felis catus* 系猫科动物及可爱性质应用研究
地球猫咪及资源学院 哈基人
2026 年 9 月 28 日
(原稿这里还有 "报告人: zhiyu3826" 和 "指导教师: zhiyu3826", 按 design.1 改版时去掉了, 需要就加回)
---
报告内容
1. 选题背景与意义
2. 研究内容与进展
3. 工作总结及未来展望
4. 致谢
---
一、选题背景与意义
(本页小节用编号条样式: 蓝底白字 01-05 + 灰底条, 对应 design.4)
1. 研究背景
2. 研究现状
3. 存在问题
4. 研究思路
5. 技术路线
---
1.1 研究背景
(页眉: 选题背景与意义, 从这一页起后续各页右上角都显示)
**家猫**凭借着响应快, 尺寸小, 成本低, 高活泼型等优点而得到广泛关注(关键的介绍话语, 高度凝练)
(左图) pre.assets/结构.png 说明: 家猫结构示意图
(右图) pre.assets/多种家猫.png 说明: 多种家猫示意图, 家猫陪伴应用
(蓝色居中) 高活泼性的家猫性格是提供高质量, 持久, 可靠的陪伴体验的关键所在
---
1.1 研究背景
人群对家猫性质要求
[] 相近的良好性格
[] 较长的陪伴周期
[] 较高的对象智商
[] 优异的活泼可爱性
[] 高液态灵活性
(右图) pre.assets/镜子实验.png 说明: 家猫镜子实验示意图
---
1.1 研究背景
三花猫优势
[v] 寿命较高
[v] 性格稳定
[v] 不闯祸
[v] 亲近人类
(右图) pre.assets/三花猫与人类玩耍.jpg 说明: 三花猫与人类玩耍示意图, 引用出处: 哔哩哔哩猫猫频道
---
1.2 研究现状
家养猫科动物研究现状
| 体系 | 应激易度(单位: 哈) | 寿命长度(单位: a) | Reference |
| :--- | ---: | ---: | :--- |
| 美国短毛猫 | 520 | 15 | 猫科陪伴协会年报 |
| 西伯利亚森林猫 | 505 | 14 | 家猫行为观察报告 |
| 阿比西尼亚猫 | 610 | 12 | 猫科陪伴协会年报 |
| 日本短尾猫 | 540 | 14 | 哔哩哔哩猫猫频道 |
| 巴厘猫 | 570 | 16 | 家猫行为观察报告 |
| 中国狸花猫 | 460 | 17 | 本实验室实测 |
(红色居中) 国际主要研究的家猫应激易度在 500 哈以上, 无法满足高玩极端环境下应用
---
1.3 存在问题
**使用强度与应激易度无法满足极端玩耍环境**
**传统训猫工艺造成猫猫缺陷风险高, 耗时耗力**
(下方流程图, 原生 mermaid)
```mermaid
graph LR
A["✗ 训猫、玩耍分开进行"] --> B["✓ 匹配共训"]
```
(红色居中) 如何实现活泼与难应激性质匹配共存?
---
1.4 研究思路
用视觉模型从高速摄像里量化「活泼度」:
```python
import cv2, numpy as np
from ultralytics import YOLO
model = YOLO("yolov8n.pt") # COCO 类别 15 = cat
cap = cv2.VideoCapture("cat.mp4") # 96 fps 高速摄像
shift, prev = [], None
for _ in range(600):
boxes = model.predict(cap.read()[1], classes=[15], verbose=False)
box = boxes[0].boxes.xyxy[0] # 取第一只猫
center = np.array([(box[0] + box[2]) / 2, (box[1] + box[3]) / 2])
shift.append(np.linalg.norm(center - prev) if prev is not None else 0)
prev = center
print(f"平均活泼度 {np.mean(shift[1:]) / 3.2:.0f} 哈")
```
(蓝色居中) 活泼度达标才谈得上陪伴, 应激易度达标才算得上安全
+474
View File
@@ -0,0 +1,474 @@
/*!
* Tectonics — 答辩模板主题
*
* @theme tectonics
* @author zhiyu3826
* @size 16:9 1280px 720px
* @size 4:3 960px 720px
* @auto-scaling fittingHeader
*/
/* 以 Marp Core 内置 default 主题为底, 这里只覆盖版式 */
@import-theme "default";
/* ===== 可调参数 ===== */
section {
--tectonics-accent: #004e98; /* 主色: 取自 design.1.png 的色带 */
--tectonics-fg: #393939; /* 封面的深灰文字色 */
--tectonics-sans: "Noto Sans CJK SC", "Source Han Sans SC", "PingFang SC",
"Microsoft YaHei", sans-serif;
--tectonics-serif: "Source Han Serif CN VF", "Source Han Serif CN",
"Noto Serif CJK SC", "Songti SC", SimSun, serif;
--tectonics-header-color: #555; /* 右上角章节名的灰 */
--tectonics-title-size: 34px;
--tectonics-title-rule: 2px;
width: 1280px;
height: 720px;
padding: 48px 64px 44px;
}
/* ===== 正文页: 标题钉在左上角, 内容自上而下 ===== */
section:not(.cover) {
display: flex;
flex-flow: column nowrap;
align-content: flex-start;
justify-content: flex-start;
}
/* 「本页第一个标题」的两种情形:
* 没有页眉时, 标题是 section 的第一个子元素 (:first-child)
* 有页眉时, 框架会把 <header> 插成第一个子元素, 标题紧跟其后
* 所以每条标题规则都要写这两个选择器, 否则加了页眉的页会掉样式。
*/
section:not(.cover):not(.toc) > :is(h1, h2, h3):first-child,
section:not(.cover):not(.toc) > header:first-child + :is(h1, h2, h3) {
flex: none;
margin: 0 0 28px;
padding: 0 0 12px;
border-bottom: var(--tectonics-title-rule) solid var(--tectonics-accent);
font-size: var(--tectonics-title-size);
line-height: 1.25;
}
/* ===== 封面 (对应 design.1.png) =====
* 三行文字 + 一条通栏色带, 位置按设计稿比例量出来的, 单位是 1280x720 画布上的 px
*/
section.cover {
display: flex;
flex-flow: column nowrap;
justify-content: flex-start;
padding: 0; /* 让色带通栏 */
text-align: center;
color: var(--tectonics-fg);
}
section.cover > p {
margin: 0;
line-height: 1;
font-family: var(--tectonics-sans);
font-weight: 700;
font-size: 42px;
}
/* 第一行: 顶部小字 */
section.cover > p:first-of-type {
padding-top: 63px;
}
/* 第二行: 通栏色带里的主标题 */
section.cover > :is(h1, h2):first-of-type {
margin: 60px 0 0;
padding: 21px 64px 15px;
background: var(--tectonics-accent);
color: #fff;
font-family: var(--tectonics-serif);
font-size: 70px;
font-weight: 700;
line-height: 1.45;
text-align: center;
}
/* 第三行: 学院 + 姓名 */
section.cover > p:nth-of-type(2) {
margin-top: 30px;
font-size: 37px;
}
/* 第四行: 日期 */
section.cover > p:nth-of-type(3) {
margin-top: 164px;
font-size: 28px;
font-weight: 400;
}
/* ===== 左右两栏: 用 div 包住的内容各占一栏, 其余元素整行 ===== */
section.cols {
display: grid;
grid-template-columns: 1fr 1fr;
gap: 1rem 2rem;
align-content: start;
}
section.cols > :is(h1, h2, h3):first-child,
section.cols > header:first-child + :is(h1, h2, h3),
section.cols > p,
section.cols > ul,
section.cols > ol,
section.cols > blockquote {
grid-column: 1 / -1;
}
section.cols > div {
min-width: 0;
}
/* ===== 块级小工具 =====
* markdown 里用 div 包住段落 (div 标签与文字之间留空行, 段内公式/加粗才会被解析):
* <div class="mid"> … </div> 水平居中
* <div class="bottom"> … </div> 靠底 (正文页是 flex 列, 把该块推到底部)
*/
section .mid {
text-align: center;
}
section .bottom {
margin-top: auto;
}
/* ===== 目录页 (对应 design.2.png) =====
* 左侧大字标题 + 竖直分隔线 + 右侧条目, 位置按设计稿比例量出来的 (1280x720 画布上的 px)
*/
section.toc {
--toc-line-x: 411px; /* 竖线左沿 */
--toc-line-y: 114px; /* 竖线顶端 */
--toc-line-h: 519px; /* 竖线高度 */
--toc-line-w: 4px;
--toc-title-left: 59px; /* 大字标题左沿 (相对版心) */
--toc-title-width: 260px; /* 限制宽度, 让"报告内容"自然折成两行 */
--toc-title-size: 91px;
--toc-title-line: 1.15;
--toc-list-left: 269px; /* 列表相对大字标题右沿的缩进 */
--toc-item-size: 51px;
--toc-item-line: 1.77;
display: flex;
flex-flow: row nowrap;
align-items: center;
padding: 48px 64px 88px;
}
/* 竖直分隔线
* 注意: 不能用 section::after —— 框架把页码也画在 section::after 上, 且它的规则带 id
* 选择器, 优先级压过主题, content 会被换成页码。所以借内容的 ::before 来画
* (它是 static 定位, 绝对定位的包含块仍然是 section)
* 目录条目既可以写成列表 (ul/ol), 也可以写成纯文本行 (p), 两种都挂竖线。
*/
section.toc > :is(ul, ol, p)::before {
content: '';
position: absolute;
top: var(--toc-line-y);
left: var(--toc-line-x);
width: var(--toc-line-w);
height: var(--toc-line-h);
background: var(--tectonics-accent); /* = #004e98 */
}
/* 左侧大字标题 */
section.toc > :is(h1, h2, h3):first-child,
section.toc > header:first-child + :is(h1, h2, h3) {
flex: none;
width: var(--toc-title-width);
margin: 0 0 0 var(--toc-title-left);
padding: 0;
border: none;
font-size: var(--toc-title-size);
font-weight: 700;
line-height: var(--toc-title-line);
text-align: left;
}
/* 右侧条目
* 两种写法都支持:
* 有序列表 —— 序号由主题生成成「一、二、…」(cjk-ideographic)
* list-style-position: outside 时序号挂在左侧空白里, 条目文字的左沿保持在设计稿位置
* 纯文本行 —— 写成连续几行, 渲染成一个 <p>, 条目自带「一、二、…」
*/
section.toc > :is(ul, ol, p) {
margin: 9px 0 0 var(--toc-list-left);
padding: 0;
font-size: var(--toc-item-size);
line-height: var(--toc-item-line);
}
section.toc > ul {
list-style: none;
}
section.toc > ol {
list-style-type: cjk-ideographic;
list-style-position: outside;
}
section.toc > :is(ul, ol) > li {
margin: 0;
}
/* ===== 4:3 (960x720) 下重新量一遍目录页 =====
* 主题元数据里的 @size 已声明 16:9 与 4:3 两种尺寸, Marp 会给每个 section
* 打上 data-size 属性, 所以尺寸适配写在主题里就够 —— markdown 不必再写 <style> 覆盖。
*/
section[data-size='4:3'].toc {
--toc-line-x: 300px; /* 竖线左沿: 紧贴大字标题右沿 */
--toc-line-y: 26%;
--toc-line-h: 42%;
--toc-title-left: 44px;
--toc-title-width: 190px;
--toc-title-size: 68px;
--toc-list-left: 120px; /* 列表相对大字标题右沿的缩进, 由 269 压到 120 */
--toc-item-size: 34px;
}
/* 960px 宽放不下 16:9 的字号, 条目一律不折行 */
section[data-size='4:3'].toc > :is(ul, ol) > li,
section[data-size='4:3'].toc > p {
white-space: nowrap;
}
/* ===== 图片说明/脚注 =====
* markdown 里写成 <p class="caption">…</p>
*/
section p.caption {
margin: 8px 0 0;
color: #666;
font-size: 0.55em;
line-height: 1.4;
}
/* 只放图片的栏: 图片与说明居中 */
section.cols > div.pic {
text-align: center;
}
/* ===== 页眉: 右上角显示当前章节名 (对应 design.3.png) =====
* markdown 里用局部指令设置, 从该页起往后都生效:
* <!-- header: 选题背景与意义 -->
* 位置与左上角的页标题同一水平线, 字号字重也与页标题一致
*/
section header {
position: absolute;
top: 48px;
right: 64px;
left: auto;
margin: 0;
font-size: var(--tectonics-title-size);
font-weight: 600;
line-height: 1.25;
text-align: right;
color: var(--tectonics-header-color);
}
/* 章节分隔页与封面页不显示页眉:
* 页眉是全局指令, 会从设置它的那页一直生效到下次设置为止,
* 若不屏蔽, 章节页会顶着上一章的章节名, 结束页也会继承最后一章的章节名。
*/
section.steps > header,
section.cover > header {
display: none;
}
/* ===== 简易流程图 (纯 CSS 画, 不依赖 mermaid) =====
* markdown 里:
* <div class="flow">
* <div class="flow-box is-bad">…</div>
* <div class="flow-arrow">→</div>
* <div class="flow-box is-good">…</div>
* </div>
*/
section .flow {
display: flex;
flex-flow: row nowrap;
align-items: stretch;
gap: 0.6rem;
margin: 1.6rem 0 1rem;
}
section .flow-box {
flex: 1 1 0;
min-width: 0;
display: flex;
flex-flow: column nowrap;
justify-content: center;
padding: 0.7rem 0.9rem;
border: var(--tectonics-title-rule) solid var(--tectonics-accent);
border-radius: 8px;
background: #f2f7fc;
color: #1a1a1a;
font-size: 0.85em;
line-height: 1.35;
text-align: center;
}
section .flow-box.is-bad {
border-color: #9aa3ad;
background: #f5f6f7;
color: #6b7280;
}
section .flow-arrow {
flex: none;
display: flex;
align-items: center;
color: var(--tectonics-accent);
font-size: 1.3em;
font-weight: 700;
}
/* ===== mermaid 图 =====
* 由 tools/marp-mermaid-engine.mjs 在构建时把 ```mermaid 渲染成内联 SVG
*/
section .mermaid-diagram {
margin: 1.6rem 0 1rem;
}
section .mermaid-diagram svg {
display: block;
height: auto;
margin: 0 auto;
}
/* ===== 章节页的小节列表 (对应 design.4.png) =====
* 用法: 本页第一行加 _class 指令 steps, 正文写成有序列表:
* <!-- _class: steps -->
* ## 一、选题背景与意义
* 1. 研究背景
* 2. 研究现状
* 序号由主题生成成 01 02 03..., 呈蓝底白字的方块 + 灰底条
*/
section.steps {
--step-row-w: 600px; /* 整条宽度 (居中) */
--step-row-h: 56px; /* 每条高度 */
--step-gap: 54px; /* 条与条的间距 */
--step-badge-w: 172px; /* 左侧蓝块宽度 */
--step-badge-size: 26px; /* 蓝块里的数字字号 */
--step-label-size: 32px; /* 右侧文字字号 */
--step-label-pad: 32px; /* 文字距蓝块的间距 */
--step-bar-color: #e0e0e0; /* 灰底 */
--step-bar-color-label: #333333; /* 文字色 */
}
section.steps > ol {
width: var(--step-row-w); /* 整条宽度, 居中 */
margin: 24px auto 0;
padding: 0;
list-style: none;
counter-reset: step;
}
section.steps > ol > li {
position: relative;
display: flex;
align-items: center;
min-height: var(--step-row-h);
margin: 0 0 var(--step-gap);
padding: 0 var(--step-label-pad) 0 calc(var(--step-badge-w) + var(--step-label-pad));
background: var(--step-bar-color);
color: var(--step-bar-color-label);
font-size: var(--step-label-size);
font-weight: 400;
line-height: 1.2;
}
section.steps > ol > li:last-child {
margin-bottom: 0;
}
section.steps > ol > li::before {
counter-increment: step;
content: counter(step, decimal-leading-zero);
position: absolute;
top: 0;
bottom: 0;
left: 0;
width: var(--step-badge-w);
display: flex;
align-items: center;
justify-content: center;
background: var(--tectonics-accent);
color: #fff;
font-size: var(--step-badge-size);
font-weight: 700;
letter-spacing: 0.06em;
}
/* ===== 强调文字 =====
* markdown 里写成:
* <p class="point">…</p> 整段: 红色 + 居中 (问题 / 风险 / 需要强调的结论)
* <p class="key">…</p> 整段: 主色蓝 + 居中 (关键论点)
* <span class="red">…</span> 行内: 红色
* <span class="blue">…</span> 行内: 主色蓝
*/
section {
--tectonics-red: #c00000;
}
section p.point,
section p.key {
margin: 0.9rem 0 0;
font-size: 1.06em;
font-weight: 700;
line-height: 1.35;
text-align: center;
}
section p.point {
color: var(--tectonics-red);
}
section p.key {
color: var(--tectonics-accent);
}
section .red {
color: var(--tectonics-red);
}
section .blue {
color: var(--tectonics-accent);
}
/* ===== 密集内容: 表格/栏目内容偏多时, 整体缩一档字号 =====
* 用法: 用 div 包住要缩放的内容 (不要在 markdown 里写内联 style)
* <div class="tight"> …表格… </div> 缩到 0.85em
* <div class="tighter"> …表格… </div> 缩到 0.78em
*/
section div.tight {
font-size: 0.85em;
}
section div.tighter {
font-size: 0.78em;
}
/* ===== 代码块 =====
* 字号 60%, 无圆角, 打开自动折行, 字体用系统里的 Cascadia Code (Nerd Font 版)
* 注意: 主题元数据里 @auto-scaling 只保留 fittingHeader, 关掉了代码块的自动缩放 ——
* 否则内容会被放进 SVG 里按 max-content 排版, 长行只会被整体缩小而不折行。
*/
section :is(pre, marp-pre) {
font-family: "CaskaydiaCove Nerd Font Mono", "CaskaydiaCove Nerd Font",
"CaskaydiaMono Nerd Font Mono", var(--fontStack-monospace, monospace);
font-size: 60%;
line-height: 1.15;
padding: 20px 24px;
border-radius: 0;
white-space: pre-wrap;
overflow-wrap: anywhere;
}
section :is(pre, marp-pre) > code {
white-space: pre-wrap;
overflow-wrap: anywhere;
}
+125
View File
@@ -0,0 +1,125 @@
/**
* marp-mermaid-engine —— 让这套 deck 离线也能渲染「原生 mermaid」
*
* 背景:本机装的 marp-cli 4.5.1 自带的 marp-core 4.4.0 里没有 mermaid(二进制里搜不到这个词),
* 而 marp-core v5 的 mermaid 插件需要联网装 beautiful-mermaid。为了在离线环境也能用原生
* mermaid 语法,这里把 marp-core 的 fence 渲染规则换掉:遇到 ```mermaid 代码块时,
* 调用 vendor/mermaid 里那份 mermaid + Chromium 无头渲染成内联 <svg>。
* markdown 里保持原生 mermaid 写法和 fence,输出里是真的 mermaid 图。
*
* 用法(marp.config.mjs):
* export default { engine: './tools/marp-mermaid-engine.mjs', ... }
*
* 可调环境变量:
* MARP_MERMAID_DIR mermaid dist 目录(默认 vendor/mermaid)
* MARP_MERMAID_CHROMIUM 浏览器可执行文件(默认 /usr/bin/chromium)
*
* 如果以后装了 marp-core v5 的 mermaid 插件,把这个 engine 配置删掉即可切回官方渲染。
*/
import { execFileSync } from 'node:child_process'
import fs from 'node:fs'
import os from 'node:os'
import path from 'node:path'
import { fileURLToPath, pathToFileURL } from 'node:url'
const here = path.dirname(fileURLToPath(import.meta.url))
const CHROMIUM = process.env.MARP_MERMAID_CHROMIUM || '/usr/bin/chromium'
const MERMAID_DIR =
process.env.MARP_MERMAID_DIR || path.join(here, '..', 'vendor', 'mermaid')
const MERMAID_JS = path.join(MERMAID_DIR, 'mermaid.min.js')
/** 图的外观,跟主题主色对齐 */
const MERMAID_CONFIG = {
startOnLoad: false,
theme: 'base',
themeVariables: {
primaryColor: '#e8f1fa',
primaryBorderColor: '#004e98',
primaryTextColor: '#1a1a1a',
lineColor: '#004e98',
fontFamily: '"Noto Sans CJK SC", "Source Han Sans SC", sans-serif',
fontSize: '24px',
},
// wrappingWidth 给够, 免得节点里的中文被折成两行
flowchart: { curve: 'basis', wrappingWidth: 360, padding: 14, nodeSpacing: 60 },
}
let seq = 0
/** 同步渲染(markdown-it 的渲染函数必须是同步的,所以用 execFileSync 调 Chromium) */
const renderMermaid = (code) => {
const id = `marp-mermaid-${++seq}`
const dir = fs.mkdtempSync(path.join(os.tmpdir(), 'marp-mermaid-'))
const mermaidJs = pathToFileURL(MERMAID_JS).href
fs.writeFileSync(
path.join(dir, 'index.html'),
`<!DOCTYPE html><html><body><div id="result"></div>
<script src="${mermaidJs}"></script>
<script>
mermaid.initialize(${JSON.stringify(MERMAID_CONFIG)});
mermaid.render(${JSON.stringify(id)}, ${JSON.stringify(code)})
.then(function (r) { document.getElementById('result').innerHTML = r.svg; })
.catch(function (e) { document.getElementById('result').dataset.error = String(e); });
</script></body></html>`,
)
const dom = execFileSync(
CHROMIUM,
[
'--headless',
'--no-sandbox',
'--disable-gpu',
'--hide-scrollbars',
'--virtual-time-budget=10000',
'--dump-dom',
pathToFileURL(path.join(dir, 'index.html')).href,
],
{ encoding: 'utf8', maxBuffer: 128 * 1024 * 1024 },
)
const start = dom.indexOf('<svg')
const end = dom.lastIndexOf('</svg>')
if (start < 0 || end < 0)
throw new Error(
`mermaid 渲染失败: ${dom.match(/data-error="([^"]*)"/)?.[1] || '没有拿到 svg'}`,
)
return dom.slice(start, end + '</svg>'.length)
}
/**
* marp-cli 的「函数式 engine」
*
* 两个注意点(读 marp-cli 源码得出的结论):
* 1. 必须是箭头函数 —— CLI 用 isClass() 判断,普通函数带 prototype 会被当成类去 new;
* 2. 参数里的 marp 是 CLI 自带 marp-core 的一个**实例**(不是类)。改完它的 markdown
* 渲染规则后,把这个实例返回即可。
*/
const marpMermaidEngine = ({ marp }) => {
const md = marp.markdown
const originalFence = md.renderer.rules.fence
md.renderer.rules.fence = (tokens, idx, mdOpts, env, self) => {
const token = tokens[idx]
const info = (token.info || '').trim().toLowerCase()
if (info === 'mermaid' || info.startsWith('mermaid ')) {
try {
return `<div class="mermaid-diagram">${renderMermaid(token.content)}</div>\n`
} catch (e) {
process.stderr.write(`[marp-mermaid] ${e.message}\n`)
process.stderr.write('[marp-mermaid] 已回退成普通代码块\n')
}
}
return originalFence(tokens, idx, mdOpts, env, self)
}
return marp
}
export default marpMermaidEngine
+21
View File
@@ -0,0 +1,21 @@
The MIT License (MIT)
Copyright (c) 2014 - 2022 Knut Sveidqvist
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
+30
View File
@@ -0,0 +1,30 @@
# vendor/mermaid
这里放的是 **mermaid 11.15.0** 的浏览器构建,供 `tools/marp-mermaid-engine.mjs` 在构建时
把 Markdown 里的 ```` ```mermaid ```` 代码块渲染成内联 SVG 用(详见该文件的说明)。
- 文件:`mermaid.min.js`(UMD 单文件构建,自包含,不依赖同目录其它分片)
- 来源:本机 npm 包 `mermaid@11.15.0` 的 `dist/mermaid.min.js`
(具体是从 `~/.local/src/llama.cpp/tools/ui/node_modules/mermaid/dist/` 复制过来的)
- 许可:MIT,原许可证见同目录 `LICENSE`
- 大小:约 3.2 MB
## 为什么单独复制一份
原来插件直接引用了 llama.cpp 那份 node_modules 里的路径。复制到这里之后,这个 deck
就是自包含的:换机器、删掉 llama.cpp 都不影响构建。
## 想升级 mermaid
从任意来源拿到新版本的 `dist/mermaid.min.js`,覆盖这个文件即可:
```bash
npm pack mermaid@<version> # 或 npm i mermaid@<version> 后从 node_modules 取
cp mermaid/dist/mermaid.min.js vendor/mermaid/mermaid.min.js
```
如果用别处的文件,也可以不改本目录,改用环境变量指定:
```bash
MARP_MERMAID_DIR=/path/to/mermaid/dist marp example.marp.md -o pre.html
```
+3405
View File
File diff suppressed because it is too large. Load diff