Files
ttrpg-tools/docs/markdown.md
T

664 lines
15 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# Markdown 编写说明
本文档介绍 TTRPG Tools 支持的 Markdown 扩展语法和组件用法。
## 基础语法
使用标准 Markdown 语法,支持以下扩展:
- [GFM](https://github.github.com/gfm/) - GitHub Flavored Markdown
- [marked-alert](https://github.com/Insidify/marked-alert) - 警告/提示块
- [marked-gfm-heading-id](https://github.com/markedjs/marked-gfm-heading-id) - 标题 ID
- [marked-directive](https://github.com/fengzilong/marked-directive) - 指令语法
### 代码块围栏
代码块围栏可使用反引号或波浪号(`~~~`)书写;闭合围栏必须与开启围栏使用相同字符,且不短于开启围栏。声明 `role=` 的代码块同理。
## 指令语法
通过 `marked-directive` 支持自定义组件插入:
```markdown
:component-name[content]{key="value" another="test"}
```
### 语法说明
| 部分 | 说明 | 示例 |
|------|------|------|
| `:name` | 组件名称 | `:dice` |
| `[content]` | 内容参数 | `[2d6+d8]` |
| `{attrs}` | 属性对象 | `{key="attack"}` |
支持多个嵌套指令:
```markdown
::: container
这里是容器内容
:dice[1d20]
:::
```
## 分栏布局
使用简单的分隔符语法创建多栏布局:
```markdown
|---
左侧栏内容
-|-
右侧栏内容
---
```
**语法说明:**
| 分隔符 | 说明 |
|--------|------|
| `\|---` | 开始分栏容器 |
| `-|-` | 分隔各栏 |
| `---` | 结束分栏容器 |
**多栏示例:**
```markdown
|---
第一栏
-|-
第二栏
-|--
第三栏(更宽)
---
```
`-|--` 中的额外 `-` 会添加 `-N` 后缀到 CSS 类名(如 `col-2`),可用于自定义宽度。
## 图标语法
使用简单的 `:[icon-name]` 语法插入图标:
```markdown
:[attack] :[defense] :[potion] :[sword]
```
图标会渲染为 `<icon class="icon-attack"></icon>` 形式。
### 支持多种图片格式
默认情况下,`:[icon-name]` 会查找 `.png` 文件。你也可以显式指定其他支持的格式:
```markdown
:[attack] <!-- 查找 attack.png -->
:[attack.svg] <!-- 查找 attack.svg -->
:[shield.gif] <!-- 查找 shield.gif -->
:[photo.jpg] <!-- 查找 photo.jpg -->
:[icon.webp] <!-- 查找 icon.webp -->
```
**支持的扩展名:** `.svg`、`.png`、`.gif`、`.jpg`、`.jpeg`、`.webp`
**注意:** CSS class 名称始终使用不带扩展名的图标名称(如 `icon-attack`),方便统一样式控制。
### 图标查找路径
图标没有单独的配置项。`:[name]` 会从当前文档所在目录开始,逐级向上查找 `assets/` 目录,
直到内容目录根:
```text
rules/combat.md 中的 :[attack]
→ rules/assets/attack.png
→ assets/attack.png
```
因此把图标放在内容目录(或其子目录)的 `assets/` 下即可。`tttk check` 会用同样的规则
校验图标是否存在(诊断 `TTTK-A001`)。
## 组件库
### 🎲 骰子组件 (md-dice)
```markdown
:md-dice[2d6+d8]
:md-dice[1d20+5]{key="attack"}
```
**功能:**
- 点击文本执行掷骰
- 点击骰子图标重置为公式
- `key` 属性将结果记录到 URL 参数中 (`?dice-attack=15`)
- 骰子数量可省略,`d20` 等价于 `1d20`
**属性:**
| 属性 | 类型 | 说明 |
|------|------|------|
| `key` | string | 用于 URL 参数记录的标识 |
**示例:**
```markdown
攻击检定 :md-dice[1d20+5]{key="attack"}
伤害掷骰 :md-dice[2d6+3]{key="damage"}
```
### 🔗 链接组件 (md-link)
```markdown
:md-link[./other-page.md]
:md-link[./rules.md#combat-section]
```
**功能:**
- 点击链接在当前页面内展开显示目标文章内容
- 支持 `#section` 语法显示特定章节
- 支持相对路径引用
**属性:**
| 属性 | 类型 | 说明 |
|------|------|------|
| (无) | - | 内容即为链接目标路径 |
**示例:**
```markdown
查看完整规则 :md-link[./rules.md]
查看战斗章节 :md-link[./rules.md#combat]
```
### 🖼️ 背景组件 (md-bg)
```markdown
:md-bg[./images/background.jpg]
:md-bg[./images/pattern.png]{fit="contain"}
:md-bg[#ff00dd]
:md-bg[rgb(100,200,50)]
```
**功能:**
- 将图片设置为当前文章卡片的背景
- 支持纯色背景(CSS 颜色值)
- 自动覆盖整个卡片区域
**属性:**
| 属性 | 类型 | 默认值 | 说明 |
|------|------|--------|------|
| `fit` | `cover` \| `contain` \| `fill` \| `none` \| `scale-down` | `cover` | 背景适配方式(仅图片时生效) |
**示例:**
```markdown
:md-bg[./images/dungeon-bg.jpg]{fit="cover"}
# 地牢探险
这里是地牢的描述内容...
:md-bg[#2a1a3a]
# 暗紫色背景
:md-bg[rgb(200,50,50)]
# 红色背景
```
### 🔤 字体组件 (md-font)
```markdown
:md-font[Noto Sans SC]{source="google" weight="700" color="#ff00dd"}
:md-font[LXGW WenKai]{source="emfont"}
:md-font[Arial]{source="local"}
```
**功能:**
- 设置当前文章卡片的字体
- 支持从 Google Fonts、emfont 或本地加载字体
- 支持设置字体颜色
**属性:**
| 属性 | 类型 | 默认值 | 说明 |
|------|------|--------|------|
| `source` | `google` \| `emfont` \| `local` | `local` | 字体来源 |
| `weight` | string | `400` | 字体粗细 |
| `color` | string | - | 字体颜色(CSS 颜色值,如 `#ff00dd`、`rgb(255,0,0)`) |
**示例:**
```markdown
:md-font[Noto Sans SC]{source="google" weight="400"}
# 标题文本
这里是正文内容,使用 Noto Sans SC 字体。
:md-font[Noto Sans SC]{source="google" weight="400" color="#1a1a2e"}
# 深色文字
:md-font[Noto Sans SC]{source="google" weight="700" color="crimson"}
# 红色粗体标题
```
### 📍 标记组件 (md-pins)
```markdown
:md-pins[./images/map.png]{pins="A:30,40 B:10,30" fixed}
:md-pins[./images/city-map.png]
:md-pins[./images/dungeon.png]{labelStart="1"}
:md-pins[./images/quest.png]{labelStart="C"}
```
**功能:**
- 在图片上显示标记点(A-Z, AA-ZZ, AAA-ZZZ... 或数字)
- `fixed` 模式:仅显示标记,不可编辑
- 非 fixed 模式:点击图片添加标记,点击标记删除
- 提供复制按钮生成标记代码
- 支持自定义标签起始值(字母或数字)
**属性:**
| 属性 | 类型 | 默认值 | 说明 |
|------|------|--------|------|
| `pins` | string | `""` | 标记列表,格式 `"A:30,40 B:10,30"` (标签:x,y) |
| `fixed` | boolean | `false` | 是否为固定模式(只读) |
| `labelStart` | string | `"A"` | 标签起始值,支持字母(如 `"A"`, `"C"`)或数字(如 `"1"`, `"7"`) |
**标签生成规则:**
| 起始值类型 | 说明 | 示例 |
|------|------|------|
| 字母(默认) | 从起始字母开始,按 A-Z, AA-ZZ, AAA-ZZZ 顺序 | `A` → A, B, C...; `C` → C, D, E... |
| 数字 | 从起始数字开始递增 | `1` → 1, 2, 3...; `7` → 7, 8, 9... |
**字母标签序列(从 A 开始):**
- 0-25: A-Z
- 26-51: AA-ZZ
- 52-77: AAA-ZZZ
**示例:**
```markdown
<!-- 固定标记模式 - 字母标签(默认从 A 开始) -->
:md-pins[./images/battle-map.png]{pins="A:25,50 B:75,30 C:50,80" fixed}
<!-- 可编辑模式 - 点击添加标记 - 从 A 开始 -->
:md-pins[./images/blank-map.png]
<!-- 数字标签 - 从 1 开始 -->
:md-pins[./images/dungeon.png]{labelStart="1"}
<!-- 数字标签 - 从 7 开始 -->
:md-pins[./images/cave.png]{labelStart="7"}
<!-- 字母标签 - 从 C 开始 -->
:md-pins[./images/quest-map.png]{labelStart="C"}
<!-- 自定义标签 + 预设标记 -->
:md-pins[./images/map.png]{pins="5:30,40 6:75,30" labelStart="5" fixed}
<!-- 复制生成的格式 -->
:md-pins[./images/map.png]{pins="A:30,40 B:10,30" fixed}
```
### 📊 表格组件 (md-table)
```markdown
:md-table[./data.csv]
:md-table[./data.csv]{roll=true}
:md-table[./data.csv]{roll=true remix=true}
```
**CSV 格式要求:**
```csv
label,body,group
第一页,这是**第一页**的内容,group1
第二页,这是*第二页*的内容,group1
第三页,这是第三页的内容,group2
```
- 使用英文逗号分隔
- 支持 `#` 开头的注释行
- 包含逗号或 `#` 的字段用双引号包裹
**特殊列:**
| 列名 | 说明 |
|------|------|
| `label` | 标签页名称 |
| `body` | 标签页内容(支持 Markdown) |
| `group` | 分组标识(可选) |
**属性:**
| 属性 | 类型 | 说明 |
|------|------|------|
| `roll` | boolean | 添加随机切换按钮 |
| `remix` | boolean | `{{prop}}` 引用随机行内容 |
**变量引用语法:**
在 `body` 列中可使用 `{{prop}}` 引用同行其他列:
```csv
label,name,description,body
战士,约翰,勇敢的战士,{{name}}是一位{{description}}。
```
**Front Matter 支持:**
CSV 可包含 YAML front matter,所有行会继承这些属性:
```csv
---
source: 玩家手册
version: 1.0
---
label,name,description
1,战士,近战专家
2,法师,奥术施法者
```
**示例:**
```markdown
<!-- 基础表格 -->
:md-table[./npcs.csv]
<!-- 带随机切换 -->
:md-table[./encounters.csv]{roll=true}
<!-- 随机引用变量 -->
:md-table[./quests.csv]{roll=true remix=true}
```
**内联表格(显式声明):**
Markdown 表格不会自动转换。如需内联表格,用代码块并声明 `role=spark-table`(首列需为骰子公式,如 `d6`):
````markdown
```markdown role=spark-table
| d6 | 结果 |
|----|------|
| 1 | 遭遇强盗 |
| 2 | 平安无事 |
```
````
扫描时转换为 CSV 并渲染为 `md-table` 组件。CSV 格式的内联表格用 `csv` 语言:
````markdown
```csv role=spark-table
d6,结果
1,遭遇强盗
2,平安无事
```
````
普通 Markdown 表格(无 role 声明)始终按标准 GFM 表格渲染,不做任何转换。
### 🃏 卡牌组件 (md-deck)
```markdown
:md-deck[./cards.csv]{grid="5x8" layers="title:1,1-5,1f8 body:1,5-5,8f3"}
```
**CSV 格式:**
```csv
label,title,body
1,卡牌名称,这张卡牌的**效果**描述
2,另一张牌,更多效果
```
**属性:**
| 属性 | 类型 | 说明 |
|------|------|------|
| `grid` | string | 卡牌布局(行 x 列) |
| `layers` | string | 图层定义 |
**图层语法:**
```
layers="字段:起始行,起始列 - 结束列,字体大小"
```
示例:`title:1,1-5,1f8` 表示 title 字段从第 1 行开始,占据 1-5 列,8mm字体。
**结构化配置(yaml 代码块):**
推荐使用 ```yaml role=tag 代码块(`yaml` 语言可被语法高亮),通过 `body` 指定 CSV 路径,`data-config` 提供结构化配置(图层可以是字段或模板):
````markdown
```yaml role=tag
tag: md-deck
body: ./cards.csv
data-config:
size: 63x88
grid: 5x5
layers:
- prop: title
pos: 1,1-5,1
font: 12
- template: |
**{{name}}** — {{type}}
{{description}}
pos: 1,3-5,8
font: 3
align: l
```
````
每个图层通过 `prop`(读取 CSV 字段)或 `template`(渲染带 `{{变量}}` 替换的 markdown 模板)定义,`pos` 为网格位置 `x1,y1-x2,y2`(1-based,与紧凑 layers 字符串同格式),支持 `font`、`orientation`、`align`(水平 `l`/`c`/`r`,可加垂直前缀 `t`/`b` 组成 `tl`/`tc`/`tr`/`bl`/`bc`/`br`,如 `align: tl` 表示左上对齐)。`back_layers` 用于背面图层。
### 🖨️ 打印版式组件 (md-print)
将 Markdown 文档排版为可打印的 A4 横版页面:每张 A4 放两个 A5 页面,每个 A5 页面再分成多列。
```markdown
:md-print[./rules.md]
:md-print[./rules.md]{columns="2" margin="10" gap="5" font="3"}
```
**功能:**
- 自动分页:内容按块级元素流入 A5 页面,段落、列表和表格可在分页处拆分
- 每张 A4 横版放两个 A5 页面,每个 A5 页面默认两列
- 预览中可直接打印或另存为 PDF
- 支持页眉标题、页码、导出时间戳和中缝裁切线
**属性:**
| 属性 | 类型 | 默认值 | 说明 |
|------|------|--------|------|
| `columns` | number | `2` | 每个 A5 页面的列数(1–4) |
| `margin` | number | `10` | 页面边距(毫米) |
| `gap` | number | `5` | 列间距(毫米) |
| `font` | number | `3` | 正文字号(毫米) |
| `title` | string | - | 页眉标题 |
| `pageNumbers` | boolean | `true` | 是否在页面外侧角落显示页码 |
| `timestamp` | boolean | `false` | 是否在页码旁边显示导出时间 |
| `cutMarks` | boolean | `true` | 是否显示 A4 中缝裁切线 |
**YAML 写法:**
```yaml
tag: md-print
body: ./rules.md
columns: 2
margin: 10
gap: 5
font: 3
title: 规则书
timestamp: true
```
**导出时间戳:**
```markdown
:md-print[./rules.md]{timestamp=true}
```
开启后页脚会显示类似 `3 / 12 · 2026-10-23 14:05` 的内容。页码位于页面外侧底角:左侧 A5 在左下角,右侧 A5 在右下角。
**打印设置:** 在浏览器打印对话框中选择 A4、横向、无边距、100% 缩放。
### 🧶 叙事线组件 (md-yarn-spinner)
用于展示分支叙事结构,支持 Yarn Spinner 格式文件。
```markdown
:md-yarn-spinner[./story.yarn]
```
## YAML 标签
使用 ```yaml role=tag 代码块创建自定义标签(`yaml` 语言可被语法高亮):
````markdown
```yaml role=tag
tag: tag-name
class: custom-class
id: my-id
body: 标签内容
```
````
`tag`、`id` 等简单属性也可以直接写在 fence 行上(fence 行属性优先于 YAML 内容):
````markdown
```yaml role=tag tag=tag-name id=my-id
class: custom-class
body: 标签内容
```
````
渲染为:
```html
<tag-name id="my-id" class="custom-class">标签内容</tag-name>
```
## Mermaid 图表
支持 mermaid 流程图:
````markdown
```mermaid
graph TD
A[开始] --> B{选择}
B -->|选项 1| C[结果 1]
B -->|选项 2| D[结果 2]
```
````
支持的图表类型:
- flowchart - 流程图
- sequenceDiagram - 时序图
- classDiagram - 类图
- stateDiagram - 状态图
- erDiagram - ER 图
- pie - 饼图
## 警告/提示块
```markdown
> [!NOTE]
> 这是一条备注
> [!TIP]
> 这是一条提示
> [!IMPORTANT]
> 这是重要信息
> [!WARNING]
> 这是警告信息
> [!CAUTION]
> 这是危险警告
```
## 文件引用
### 相对路径
```markdown
<!-- 引用同目录文件 -->
:md-table[./data.csv]
<!-- 引用子目录文件 -->
:md-deck[./cards/deck.csv]
<!-- 引用上级目录文件 -->
:md-table[../shared/npcs.csv]
<!-- 引用图片 -->
![地图](./images/map.png)
```
### 路径解析规则
- 所有路径相对于当前 Markdown 文件
- 支持 `.` 和 `..` 导航
- 自动处理 URL 编码
## 样式定制
### 使用 Tailwind 类
组件支持 Tailwind CSS 类:
```markdown
:md-dice[1d20]{class="text-red-500"}
```
### 自定义 CSS
```css
/* 在 styles.css 中添加 */
.md-dice {
@apply text-blue-600 hover:text-blue-800;
}
```
## 最佳实践
### 内容组织
```markdown
# 章节标题
这里是章节内容。
## 子章节
### 规则说明
:md-dice[2d6] 掷骰决定结果。
:md-table[./options.csv]{roll=true}
> [!TIP]
> 这是一个有用的提示。
```
### 性能优化
- 大型 CSV 文件使用 `group` 列分组
- 图片使用适当分辨率
- 避免过多嵌套组件
### 可访问性
- 为图片添加 `alt` 文本
- 使用语义化标题层级
- 确保颜色对比度