init
This commit is contained in:
commit
0285b2a5d1
12 files changed
+4243
No files matched your search
@@ -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 下引用的第三方代码遵循它们自己的协议), 欢迎发起拉取请求并贡献改进.
|
||||
@@ -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
@@ -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} 哈")
|
||||
```
|
||||
|
||||
(蓝色居中) 活泼度达标才谈得上陪伴, 应激易度达标才算得上安全
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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
|
||||
|
||||
Vendored
+21
@@ -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.
|
||||
Vendored
+30
@@ -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
|
||||
```
|
||||
Vendored
+3405
File diff suppressed because it is too large.
Load diff
Reference in new issue
Block a user