# Mermaid 图表

在构建期间将 Mermaid 代码块转换成响应式、支持主题切换的 SVG 图表。

import { Callout, Steps, TabItem, Tabs } from '@prosefly/astro-components';

将代码块的语言设为 `mermaid`，Lotus 就会把它转换成静态 SVG。同一套语法可以在
Markdown 和 MDX 中使用，不需要导入组件，也不会向浏览器发送 Mermaid runtime。

## 快速开始

当图表需要指定无障碍名称时，在语言后添加 `title="..."`。省略时，renderer 会
根据图表类型生成名称。

<Tabs>
  <TabItem label="预览">
    ```mermaid title="发布流程"
    flowchart LR
      Markdown --> Astro
      Astro --> SVG
    ```
  </TabItem>
  <TabItem label="源码">
    ````markdown
    ```mermaid title="发布流程"
    flowchart LR
      Markdown --> Astro
      Astro --> SVG
    ```
    ````
  </TabItem>
</Tabs>

转换会在 Astro 构建期间完成。代码块会变成包含 inline SVG 的响应式 `<figure>`，
因此图表能立即显示，并且在 JavaScript 被禁用时仍然可用。

## 支持的图表类型

图表由 [`beautiful-mermaid`](https://github.com/lukilabs/beautiful-mermaid)
渲染，目前支持 Mermaid 的一个明确子集：

| 图表 | 开头声明 | 适合场景 |
| --- | --- | --- |
| 流程图 | `flowchart LR` 或 `graph TD` | 流程、判断和架构 |
| 状态图 | `stateDiagram-v2` | 生命周期和状态转换 |
| 时序图 | `sequenceDiagram` | 请求和交互顺序 |
| 类图 | `classDiagram` | 类型、成员和关系 |
| 实体关系图 | `erDiagram` | 数据模型和基数关系 |
| XY 图表 | `xychart-beta` | 柱状图、折线图和组合图 |

### 流程图

流程图支持从上到下、从左到右、从下到上和从右到左的方向，以及标签和常用节点形状。

<Tabs>
  <TabItem label="预览">
    ```mermaid title="内容发布决策"
    flowchart TD
      Draft[撰写草稿] --> Review{通过审核？}
      Review -->|是| Publish[发布页面]
      Review -->|否| Draft
    ```
  </TabItem>
  <TabItem label="源码">
    ````markdown
    ```mermaid title="内容发布决策"
    flowchart TD
      Draft[撰写草稿] --> Review{通过审核？}
      Review -->|是| Publish[发布页面]
      Review -->|否| Draft
    ```
    ````
  </TabItem>
</Tabs>

### 状态图

当重点在于一个状态如何转变为另一个状态时，可以使用状态图。

<Tabs>
  <TabItem label="预览">
    ```mermaid title="文章生命周期"
    stateDiagram-v2
      [*] --> Draft
      Draft --> Review: 提交
      Review --> Published: 通过
      Review --> Draft: 请求修改
      Published --> [*]
    ```
  </TabItem>
  <TabItem label="源码">
    ````markdown
    ```mermaid title="文章生命周期"
    stateDiagram-v2
      [*] --> Draft
      Draft --> Review: 提交
      Review --> Published: 通过
      Review --> Draft: 请求修改
      Published --> [*]
    ```
    ````
  </TabItem>
</Tabs>

### 时序图

时序图可以直观地展示请求顺序和缓存行为，不需要冗长的过程说明。

<Tabs>
  <TabItem label="预览">
    ```mermaid title="带缓存的 metadata 请求"
    sequenceDiagram
      participant Page as 页面
      participant Cache as 缓存
      participant Provider
      Page->>Cache: 解析 URL
      alt 已缓存
        Cache-->>Page: 返回 metadata
      else 未缓存
        Cache->>Provider: 获取 metadata
        Provider-->>Cache: 返回响应
        Cache-->>Page: 返回 metadata
      end
    ```
  </TabItem>
  <TabItem label="源码">
    ````markdown
    ```mermaid title="带缓存的 metadata 请求"
    sequenceDiagram
      participant Page as 页面
      participant Cache as 缓存
      participant Provider
      Page->>Cache: 解析 URL
      alt 已缓存
        Cache-->>Page: 返回 metadata
      else 未缓存
        Cache->>Provider: 获取 metadata
        Provider-->>Cache: 返回响应
        Cache-->>Page: 返回 metadata
      end
    ```
    ````
  </TabItem>
</Tabs>

### 类图

类图支持成员、方法、annotations、继承、组合、聚合、依赖和关系标签。

<Tabs>
  <TabItem label="预览">
    ```mermaid title="Markdown 渲染类"
    classDiagram
      class MarkdownPage {
        +String title
        +String body
        +render() String
      }
      class Diagram {
        +String source
        +toSVG() String
      }
      MarkdownPage *-- Diagram
    ```
  </TabItem>
  <TabItem label="源码">
    ````markdown
    ```mermaid title="Markdown 渲染类"
    classDiagram
      class MarkdownPage {
        +String title
        +String body
        +render() String
      }
      class Diagram {
        +String source
        +toSVG() String
      }
      MarkdownPage *-- Diagram
    ```
    ````
  </TabItem>
</Tabs>

### 实体关系图

ER 图适合展示实体和基数关系。当关系本身最重要时，可以省略实体字段。

<Tabs>
  <TabItem label="预览">
    ```mermaid title="文档内容模型"
    erDiagram
      SITE ||--o{ PAGE : contains
      PAGE ||--o{ DIAGRAM : renders
      PAGE {
        string slug
        string title
      }
      DIAGRAM {
        string type
        string source
      }
    ```
  </TabItem>
  <TabItem label="源码">
    ````markdown
    ```mermaid title="文档内容模型"
    erDiagram
      SITE ||--o{ PAGE : contains
      PAGE ||--o{ DIAGRAM : renders
      PAGE {
        string slug
        string title
      }
      DIAGRAM {
        string type
        string source
      }
    ```
    ````
  </TabItem>
</Tabs>

### XY 图表

XY 图表支持柱状和折线数据系列。主数据系列使用 accent token，renderer 会据此
计算其他系列的颜色。

<Tabs>
  <TabItem label="预览">
    ```mermaid title="每月文档访问量"
    xychart-beta
      title "文档访问量"
      x-axis [一月, 二月, 三月, 四月, 五月, 六月]
      y-axis "访问量（千）" 0 --> 50
      bar [18, 24, 29, 31, 38, 46]
      line [16, 22, 27, 34, 40, 44]
    ```
  </TabItem>
  <TabItem label="源码">
    ````markdown
    ```mermaid title="每月文档访问量"
    xychart-beta
      title "文档访问量"
      x-axis [一月, 二月, 三月, 四月, 五月, 六月]
      y-axis "访问量（千）" 0 --> 50
      bar [18, 24, 29, 31, 38, 46]
      line [16, 22, 27, 34, 40, 44]
    ```
    ````
  </TabItem>
</Tabs>

<Callout type="note" title="明确支持的 Mermaid 子集">
  目前不支持 Gantt、mindmap、pie chart、user journey 和 C4 diagram。不支持的
  语法会让构建失败，而不是悄悄输出空白或不完整的图表。
</Callout>

## 编写规则

<Steps>

1. **使用准确的 `mermaid` 语言名称。**

   其他语言名称会继续作为普通代码块处理。

2. **添加简短、明确的 title。**

   在代码块起始行写入 `title="请求生命周期"`。它会成为 SVG 的 `<title>`，
   并由 `aria-labelledby` 引用；它不是可见 caption。

3. **只使用受支持的 Mermaid 语法。**

   `beautiful-mermaid` 有意只实现上面列出的六类图表，而不是完整 Mermaid grammar。

4. **将渲染失败视为内容错误。**

   无效和不支持的图表会中止构建。错误信息包含源文件和代码块行号，方便回到原处修复。

</Steps>

## 主题

生成的 SVG 使用与 Lotus 相同的 CSS custom properties，因此无需重新渲染就能
响应站点的明暗模式。

| Token | 图表用途 |
| --- | --- |
| `--pf-background` | 图表背景和颜色计算 |
| `--pf-text` | 主要标签 |
| `--pf-text-muted` | 次要标签和 annotations |
| `--pf-surface` | 节点表面 |
| `--pf-border-subtle` | 节点和分组边框 |
| `--pf-border-muted` | 连接线 |
| `--pf-accent` | 箭头和图表数据系列 |
| `--pf-font-sans` | 标签和标题 |
| `--pf-font-mono` | 等宽图表文字 |

## 配置

Mermaid 默认启用。Lotus 还会安全地将 `mermaid` 添加到已有的
`markdown.syntaxHighlight.excludeLangs`，确保转换收到原始代码块源码。

如果要保留其他 Markdown transforms，但将 Mermaid 渲染成普通代码，可以关闭它：

```ts title="astro.config.ts"
import { defineConfig } from 'astro/config';
import lotus from '@prosefly/astro-theme-lotus';

export default defineConfig({
  integrations: [
    lotus({
      markdown: { mermaid: false },
    }),
  ],
});
```
