@barzhsieh/nuxt-content-mermaid 2.1.2 → 2.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +162 -1
- package/README.zh-TW.md +166 -2
- package/dist/module.d.mts +83 -1
- package/dist/module.json +1 -1
- package/dist/module.mjs +126 -9
- package/dist/runtime/components/Mermaid.d.vue.ts +6 -4
- package/dist/runtime/components/Mermaid.vue +492 -36
- package/dist/runtime/components/Mermaid.vue.d.ts +6 -4
- package/dist/runtime/components/MermaidExpandOverlay.d.vue.ts +25 -0
- package/dist/runtime/components/MermaidExpandOverlay.vue +140 -0
- package/dist/runtime/components/MermaidExpandOverlay.vue.d.ts +25 -0
- package/dist/runtime/components/MermaidZoomToolbar.d.vue.ts +23 -0
- package/dist/runtime/components/MermaidZoomToolbar.vue +66 -0
- package/dist/runtime/components/MermaidZoomToolbar.vue.d.ts +23 -0
- package/dist/runtime/components/icons/IconClipboard.d.vue.ts +8 -0
- package/dist/runtime/components/icons/IconClipboard.vue +32 -0
- package/dist/runtime/components/icons/IconClipboard.vue.d.ts +8 -0
- package/dist/runtime/components/icons/IconClipboardHover.d.vue.ts +8 -0
- package/dist/runtime/components/icons/IconClipboardHover.vue +33 -0
- package/dist/runtime/components/icons/IconClipboardHover.vue.d.ts +8 -0
- package/dist/runtime/components/icons/IconClipboardSuccess.d.vue.ts +8 -0
- package/dist/runtime/components/icons/IconClipboardSuccess.vue +33 -0
- package/dist/runtime/components/icons/IconClipboardSuccess.vue.d.ts +8 -0
- package/dist/runtime/components/icons/IconCollapse.d.vue.ts +8 -0
- package/dist/runtime/components/icons/IconCollapse.vue +34 -0
- package/dist/runtime/components/icons/IconCollapse.vue.d.ts +8 -0
- package/dist/runtime/components/icons/IconExpand.d.vue.ts +8 -0
- package/dist/runtime/components/icons/IconExpand.vue +34 -0
- package/dist/runtime/components/icons/IconExpand.vue.d.ts +8 -0
- package/dist/runtime/components/icons/IconMinus.d.vue.ts +8 -0
- package/dist/runtime/components/icons/IconMinus.vue +46 -0
- package/dist/runtime/components/icons/IconMinus.vue.d.ts +8 -0
- package/dist/runtime/components/icons/IconPlus.d.vue.ts +8 -0
- package/dist/runtime/components/icons/IconPlus.vue +57 -0
- package/dist/runtime/components/icons/IconPlus.vue.d.ts +8 -0
- package/dist/runtime/components/icons/iconFullScreen.d.vue.ts +8 -0
- package/dist/runtime/components/icons/iconFullScreen.vue +26 -0
- package/dist/runtime/components/icons/iconFullScreen.vue.d.ts +8 -0
- package/dist/runtime/components/icons/iconFullScreenExit.d.vue.ts +8 -0
- package/dist/runtime/components/icons/iconFullScreenExit.vue +26 -0
- package/dist/runtime/components/icons/iconFullScreenExit.vue.d.ts +8 -0
- package/dist/runtime/composables/_configurable.d.ts +27 -0
- package/dist/runtime/composables/_configurable.js +5 -0
- package/dist/runtime/composables/shared/index.d.ts +5 -0
- package/dist/runtime/composables/shared/index.js +5 -0
- package/dist/runtime/composables/shared/tryOnMounted.d.ts +10 -0
- package/dist/runtime/composables/shared/tryOnMounted.js +11 -0
- package/dist/runtime/composables/shared/tryOnScopeDispose.d.ts +7 -0
- package/dist/runtime/composables/shared/tryOnScopeDispose.js +8 -0
- package/dist/runtime/composables/shared/watchImmediate.d.ts +5 -0
- package/dist/runtime/composables/shared/watchImmediate.js +11 -0
- package/dist/runtime/composables/unrefElement.d.ts +12 -0
- package/dist/runtime/composables/unrefElement.js +5 -0
- package/dist/runtime/composables/useEventListener.d.ts +73 -0
- package/dist/runtime/composables/useEventListener.js +40 -0
- package/dist/runtime/composables/useFullscreen.d.ts +25 -0
- package/dist/runtime/composables/useFullscreen.js +122 -0
- package/dist/runtime/composables/useMermaidCursors.d.ts +12 -0
- package/dist/runtime/composables/useMermaidCursors.js +41 -0
- package/dist/runtime/composables/useMermaidExpand.d.ts +45 -0
- package/dist/runtime/composables/useMermaidExpand.js +480 -0
- package/dist/runtime/composables/useMermaidZoom.d.ts +37 -0
- package/dist/runtime/composables/useMermaidZoom.js +261 -0
- package/dist/runtime/composables/useMounted.d.ts +8 -0
- package/dist/runtime/composables/useMounted.js +16 -0
- package/dist/runtime/composables/useSupported.d.ts +2 -0
- package/dist/runtime/composables/useSupported.js +10 -0
- package/dist/runtime/constants.d.ts +4 -0
- package/dist/runtime/constants.js +24 -0
- package/dist/runtime/mermaid-config.d.ts +1 -1
- package/dist/runtime/plugins/mermaid.client.d.ts +2 -2
- package/dist/runtime/styles.css +1 -0
- package/dist/runtime/types/expand.d.ts +48 -0
- package/dist/runtime/types/expand.js +0 -0
- package/dist/runtime/types/utils.d.ts +115 -0
- package/dist/runtime/types/utils.js +0 -0
- package/dist/runtime/utils/index.d.ts +52 -0
- package/dist/runtime/utils/index.js +113 -0
- package/dist/runtime/utils/is.d.ts +15 -0
- package/dist/runtime/utils/is.js +31 -0
- package/dist/runtime/utils/mermaid-transform.d.ts +18 -0
- package/dist/runtime/utils/mermaid-transform.js +345 -0
- package/dist/runtime/utils/vue.d.ts +2 -0
- package/dist/runtime/utils/vue.js +4 -0
- package/package.json +4 -2
- package/dist/runtime/utils.d.ts +0 -1
- package/dist/runtime/utils.js +0 -30
package/README.md
CHANGED
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
[English](./README.md) | [中文](./README.zh-TW.md)
|
|
2
2
|
|
|
3
|
+
[](https://www.npmjs.com/package/@barzhsieh/nuxt-content-mermaid)
|
|
4
|
+
|
|
3
5
|
# nuxt-content-mermaid
|
|
4
6
|
|
|
5
7
|
[![npm version][npm-version-src]][npm-version-href]
|
|
@@ -103,6 +105,30 @@ export default defineNuxtConfig({
|
|
|
103
105
|
spinner: undefined,
|
|
104
106
|
error: undefined,
|
|
105
107
|
},
|
|
108
|
+
toolbar: {
|
|
109
|
+
title: "mermaid",
|
|
110
|
+
fontSize: "14px",
|
|
111
|
+
fullscreenToolbarScale: 1.25,
|
|
112
|
+
buttons: {
|
|
113
|
+
copy: true,
|
|
114
|
+
fullscreen: true,
|
|
115
|
+
expand: true,
|
|
116
|
+
},
|
|
117
|
+
},
|
|
118
|
+
expand: {
|
|
119
|
+
enabled: true,
|
|
120
|
+
margin: 0,
|
|
121
|
+
invokeOpenOn: {
|
|
122
|
+
diagramClick: true,
|
|
123
|
+
},
|
|
124
|
+
invokeCloseOn: {
|
|
125
|
+
esc: true,
|
|
126
|
+
wheel: true,
|
|
127
|
+
swipe: true,
|
|
128
|
+
overlayClick: true,
|
|
129
|
+
closeButtonClick: true,
|
|
130
|
+
},
|
|
131
|
+
},
|
|
106
132
|
},
|
|
107
133
|
});
|
|
108
134
|
```
|
|
@@ -140,8 +166,95 @@ Color mode integration is automatic when `@nuxtjs/color-mode` is installed; manu
|
|
|
140
166
|
| `components.spinner` | `string` | `undefined` | Optional: global loading spinner component name. |
|
|
141
167
|
| `components.error` | `string` | `undefined` | Optional: global error component name when Mermaid rendering fails. |
|
|
142
168
|
|
|
169
|
+
**toolbar**
|
|
170
|
+
|
|
171
|
+
| Option | Type | Default | Description |
|
|
172
|
+
| :------------------------- | :----------------- | :------ | :------------------------------------------ |
|
|
173
|
+
| `toolbar.title` | `string` | `'mermaid'` | Default toolbar title for Mermaid blocks. |
|
|
174
|
+
| `toolbar.fontSize` | `string \| number` | `'14px'` | Default toolbar font size. |
|
|
175
|
+
| `toolbar.fullscreenToolbarScale` | `number` | `1.25` | Scale factor for toolbar font/icon size in fullscreen. |
|
|
176
|
+
| `toolbar.buttons.copy` | `boolean` | `true` | Show copy-source button in the toolbar. |
|
|
177
|
+
| `toolbar.buttons.fullscreen` | `boolean` | `true` | Show fullscreen button in the toolbar. |
|
|
178
|
+
| `toolbar.buttons.expand` | `boolean` | `true` | Show expand button in the toolbar. |
|
|
179
|
+
|
|
180
|
+
**expand**
|
|
181
|
+
|
|
182
|
+
Control SVG expand interactions. You can also set `expand: false` to disable it, or `expand: true` to use defaults.
|
|
183
|
+
|
|
184
|
+
| Option | Type | Default | Description |
|
|
185
|
+
| :------------------------- | :-------- | :------ | :------------------------------------------------------------------------- |
|
|
186
|
+
| `expand.enabled` | `boolean` | `true` | Enable or disable expand features entirely. |
|
|
187
|
+
| `expand.margin` | `number` | `0` | Margin (px) around the expanded SVG within the viewport. |
|
|
188
|
+
| `expand.invokeOpenOn.diagramClick` | `boolean` | `true` | Allow clicking the SVG to open expand overlay. |
|
|
189
|
+
| `expand.invokeCloseOn.esc` | `boolean` | `true` | Allow Escape key to close. |
|
|
190
|
+
| `expand.invokeCloseOn.wheel` | `boolean` | `true` | Allow mouse wheel to close. |
|
|
191
|
+
| `expand.invokeCloseOn.swipe` | `boolean` | `true` | Allow swipe gesture to close. |
|
|
192
|
+
| `expand.invokeCloseOn.overlayClick` | `boolean` | `true` | Allow clicking the overlay background to close. |
|
|
193
|
+
| `expand.invokeCloseOn.closeButtonClick`| `boolean`| `true` | Show the overlay close button. |
|
|
194
|
+
|
|
195
|
+
**Pan & Zoom (Expand Overlay / Fullscreen)**
|
|
196
|
+
|
|
197
|
+
When fullscreen or expand mode is active, users can pan and zoom the diagram:
|
|
198
|
+
|
|
199
|
+
| Interaction | Desktop | Mobile |
|
|
200
|
+
|:---|:---|:---|
|
|
201
|
+
| **Pan** | `Space` + Drag | 1-finger Drag |
|
|
202
|
+
| **Zoom** | `Ctrl/⌘` + Scroll | 2-finger Pinch |
|
|
203
|
+
| **Keyboard** | `+`/`-` to zoom, Arrow keys to pan, `0` to reset | — |
|
|
204
|
+
|
|
205
|
+
A zoom toolbar appears with +/−/Reset buttons and a percentage display.
|
|
206
|
+
|
|
207
|
+
Use `toolbar.fullscreenToolbarScale` to scale the fullscreen toolbar and zoom controls.
|
|
208
|
+
|
|
209
|
+
|
|
143
210
|
> **Note**: All options can be overridden at runtime via `runtimeConfig.public.contentMermaid` (`runtimeConfig.public.mermaidContent` remains supported but deprecated).
|
|
144
211
|
|
|
212
|
+
## Styling (CSS Variables)
|
|
213
|
+
|
|
214
|
+
This module ships global CSS variables (from `runtime/styles.css`) so the Mermaid wrapper and expand overlay share the same palette. You can override them in your app:
|
|
215
|
+
|
|
216
|
+
```css
|
|
217
|
+
:root {
|
|
218
|
+
--ncm-code-bg: #f3f4f6;
|
|
219
|
+
--ncm-code-bg-hover: #e5e7eb;
|
|
220
|
+
--ncm-border: #e5e7eb;
|
|
221
|
+
--ncm-text: #111827;
|
|
222
|
+
--ncm-text-muted: #4b5563;
|
|
223
|
+
--ncm-text-xmuted: #6b7280;
|
|
224
|
+
--ncm-overlay-bg: rgba(255, 255, 255, 0.98);
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
html[data-theme="dark"],
|
|
228
|
+
.dark {
|
|
229
|
+
--ncm-code-bg: #111827;
|
|
230
|
+
--ncm-code-bg-hover: #1f2937;
|
|
231
|
+
--ncm-border: #1f2937;
|
|
232
|
+
--ncm-text: #f9fafb;
|
|
233
|
+
--ncm-text-muted: #9ca3af;
|
|
234
|
+
--ncm-text-xmuted: #6b7280;
|
|
235
|
+
--ncm-overlay-bg: rgba(17, 24, 39, 0.98);
|
|
236
|
+
}
|
|
237
|
+
```
|
|
238
|
+
|
|
239
|
+
Variables:
|
|
240
|
+
- `--ncm-code-bg`: Mermaid block background.
|
|
241
|
+
- `--ncm-code-bg-hover`: Hover background for toolbar buttons.
|
|
242
|
+
- `--ncm-border-color`: Border color for the block and toolbar.
|
|
243
|
+
- `--ncm-border-width`: Border thickness.
|
|
244
|
+
- `--ncm-border-style`: Border style.
|
|
245
|
+
- `--ncm-border`: Composite shorthand (width, style, color) for borders.
|
|
246
|
+
- `--ncm-border-bottom`: Border style applied to the toolbar bottom.
|
|
247
|
+
- `--ncm-text`: Primary text color.
|
|
248
|
+
- `--ncm-text-muted`: Title and secondary text.
|
|
249
|
+
- `--ncm-text-xmuted`: Toolbar icon and subtle UI text.
|
|
250
|
+
- `--ncm-overlay-bg`: Expand overlay background (defaults to `--ncm-code-bg`).
|
|
251
|
+
- `--ncm-expand-target-bg`: Background color shown behind the expanded SVG when `expand.margin` leaves breathing room.
|
|
252
|
+
- `--ncm-overlay-opacity`: Overlay transparency (thinned when `expand.margin` creates breathing room).
|
|
253
|
+
- `--ncm-overlay-backdrop`: `backdrop-filter` applied to the overlay when it becomes visible.
|
|
254
|
+
- `--ncm-hint-bg`: Zoom hint toast background (default: `rgba(0,0,0,0.75)`).
|
|
255
|
+
- `--ncm-hint-text`: Zoom hint toast text color (default: `#fff`).
|
|
256
|
+
- `--ncm-hint-radius`: Zoom hint toast border radius (default: `8px`).
|
|
257
|
+
|
|
145
258
|
## Advanced Usage
|
|
146
259
|
|
|
147
260
|
### Debug mode
|
|
@@ -229,9 +342,57 @@ The actual priority order when settings take effect is as follows:
|
|
|
229
342
|
2. **Frontmatter `config`** — merged on top of the module's `loader.init`.
|
|
230
343
|
3. **Module-level `contentMermaid.loader.init`** — Project default settings.
|
|
231
344
|
|
|
345
|
+
### Mermaid Inline Attributes & YAML Frontmatter
|
|
346
|
+
|
|
347
|
+
You can control Mermaid blocks in three ways: inline attrs, Mermaid YAML frontmatter, and `%%{init}%%` directives.
|
|
348
|
+
|
|
349
|
+
#### Inline attrs (fence info)
|
|
350
|
+
|
|
351
|
+
Use inline attrs on the `mermaid` fence to pass props to the wrapper component or set Mermaid YAML fields (including `toolbar` options like title/fontSize and `toolbar.buttons.*`).
|
|
352
|
+
|
|
353
|
+
````markdown
|
|
354
|
+
```mermaid {title="Diagram A" toolbar='{"title":"My Diagram","fontSize":"14px"}' config='{"theme":"dark"}'}
|
|
355
|
+
graph TD
|
|
356
|
+
A --> B
|
|
357
|
+
```
|
|
358
|
+
````
|
|
359
|
+
|
|
360
|
+
#### Mermaid YAML frontmatter (inside the block)
|
|
361
|
+
|
|
362
|
+
Place Mermaid’s own YAML frontmatter at the top of the code block to affect SVG rendering (e.g. title, displayMode, config), and you can also provide `toolbar` values for the wrapper component (including `toolbar.buttons.copy: true`).
|
|
363
|
+
|
|
364
|
+
````markdown
|
|
365
|
+
```mermaid
|
|
366
|
+
---
|
|
367
|
+
title: Sample Flowchart
|
|
368
|
+
displayMode: compact
|
|
369
|
+
config:
|
|
370
|
+
theme: dark
|
|
371
|
+
toolbar:
|
|
372
|
+
title: "Sample Diagram"
|
|
373
|
+
buttons:
|
|
374
|
+
copy: true
|
|
375
|
+
---
|
|
376
|
+
graph TD
|
|
377
|
+
A --> B
|
|
378
|
+
```
|
|
379
|
+
````
|
|
380
|
+
|
|
381
|
+
#### `%%{init}%%` directive (inside the block)
|
|
382
|
+
|
|
383
|
+
Use Mermaid directives to set render options directly in the diagram definition.
|
|
384
|
+
|
|
385
|
+
````markdown
|
|
386
|
+
```mermaid
|
|
387
|
+
%%{init: { 'theme': 'forest', 'flowchart': { 'curve': 'step' } }}%%
|
|
388
|
+
graph TD
|
|
389
|
+
A --> B
|
|
390
|
+
```
|
|
391
|
+
````
|
|
392
|
+
|
|
232
393
|
### Custom Rendering Component
|
|
233
394
|
|
|
234
|
-
If you want full control over rendering (for example to add a border,
|
|
395
|
+
If you want full control over rendering (for example to add a border, expand controls, or other UI), you can provide a custom component via `components.renderer`.
|
|
235
396
|
|
|
236
397
|
1. Specify the component name in `nuxt.config.ts`:
|
|
237
398
|
|
package/README.zh-TW.md
CHANGED
|
@@ -1,4 +1,6 @@
|
|
|
1
|
-
[
|
|
1
|
+
[中文](./README.zh-TW.md) | [English](./README.md)
|
|
2
|
+
|
|
3
|
+
[](https://www.npmjs.com/package/@barzhsieh/nuxt-content-mermaid)
|
|
2
4
|
|
|
3
5
|
# nuxt-content-mermaid
|
|
4
6
|
|
|
@@ -103,6 +105,30 @@ export default defineNuxtConfig({
|
|
|
103
105
|
spinner: undefined,
|
|
104
106
|
error: undefined,
|
|
105
107
|
},
|
|
108
|
+
toolbar: {
|
|
109
|
+
title: "mermaid",
|
|
110
|
+
fontSize: "14px",
|
|
111
|
+
fullscreenToolbarScale: 1.25,
|
|
112
|
+
buttons: {
|
|
113
|
+
copy: true,
|
|
114
|
+
fullscreen: true,
|
|
115
|
+
expand: true,
|
|
116
|
+
},
|
|
117
|
+
},
|
|
118
|
+
expand: {
|
|
119
|
+
enabled: true,
|
|
120
|
+
margin: 0,
|
|
121
|
+
invokeOpenOn: {
|
|
122
|
+
diagramClick: true,
|
|
123
|
+
},
|
|
124
|
+
invokeCloseOn: {
|
|
125
|
+
esc: true,
|
|
126
|
+
wheel: true,
|
|
127
|
+
swipe: true,
|
|
128
|
+
overlayClick: true,
|
|
129
|
+
closeButtonClick: true,
|
|
130
|
+
},
|
|
131
|
+
},
|
|
106
132
|
},
|
|
107
133
|
});
|
|
108
134
|
```
|
|
@@ -140,8 +166,96 @@ export default defineNuxtConfig({
|
|
|
140
166
|
| `components.spinner` | `string` | `undefined` | 指定全域的 Loading 元件名稱。 |
|
|
141
167
|
| `components.error` | `string` | `undefined` | 指定全域的錯誤顯示元件名稱,渲染失敗時會使用。 |
|
|
142
168
|
|
|
169
|
+
**toolbar**
|
|
170
|
+
|
|
171
|
+
| 參數 | 類型 | 預設值 | 說明 |
|
|
172
|
+
| :---------------------- | :----------------- | :----- | :------------------------------------- |
|
|
173
|
+
| `toolbar.title` | `string` | `'mermaid'` | Mermaid 工具列預設標題。 |
|
|
174
|
+
| `toolbar.fontSize` | `string \| number` | `'14px'` | Mermaid 工具列預設字體大小。 |
|
|
175
|
+
| `toolbar.fullscreenToolbarScale` | `number` | `1.25` | fullscreen 時工具列字體/圖示的放大倍率。 |
|
|
176
|
+
| `toolbar.buttons.copy` | `boolean` | `true` | 顯示工具列複製原始 Mermaid 的按鈕。 |
|
|
177
|
+
| `toolbar.buttons.fullscreen` | `boolean` | `true` | 顯示工具列全螢幕按鈕。 |
|
|
178
|
+
| `toolbar.buttons.expand` | `boolean` | `true` | 顯示工具列放大按鈕。 |
|
|
179
|
+
|
|
180
|
+
**expand**
|
|
181
|
+
|
|
182
|
+
控制 SVG 放大互動行為,也可直接設為 `expand: false` 來停用,或 `expand: true` 使用預設值。
|
|
183
|
+
|
|
184
|
+
| 參數 | 類型 | 預設值 | 說明 |
|
|
185
|
+
| :------------------------ | :-------- | :----- | :------------------------------------------------------- |
|
|
186
|
+
| `expand.enabled` | `boolean` | `true` | 是否啟用放大功能。 |
|
|
187
|
+
| `expand.margin` | `number` | `0` | 放大後 SVG 在視窗內保留的邊距(px)。 |
|
|
188
|
+
| `expand.invokeOpenOn.diagramClick` | `boolean` | `true` | 允許直接點擊 SVG 開啟放大。 |
|
|
189
|
+
| `expand.invokeCloseOn.esc` | `boolean` | `true` | 允許按 ESC 關閉。 |
|
|
190
|
+
| `expand.invokeCloseOn.wheel` | `boolean` | `true` | 允許滑鼠滾輪關閉。 |
|
|
191
|
+
| `expand.invokeCloseOn.swipe` | `boolean` | `true` | 允許滑動手勢關閉。 |
|
|
192
|
+
| `expand.invokeCloseOn.overlayClick` | `boolean` | `true` | 允許點擊 overlay 背景關閉。 |
|
|
193
|
+
| `expand.invokeCloseOn.closeButtonClick`| `boolean` | `true` | 顯示 overlay 關閉按鈕。 |
|
|
194
|
+
|
|
195
|
+
**平移與縮放 (Expand Overlay / Fullscreen)**
|
|
196
|
+
|
|
197
|
+
當放大 Fullscreen 或是 Expand 模式時,使用者可平移與縮放圖表:
|
|
198
|
+
|
|
199
|
+
| 操作 | 桌機 | 行動裝置 |
|
|
200
|
+
|:---|:---|:---|
|
|
201
|
+
| **平移 (Pan)** | `Space` + 拖曳 | 單指拖曳 |
|
|
202
|
+
| **縮放 (Zoom)** | `Ctrl/⌘` + 滾輪 | 雙指捏合 |
|
|
203
|
+
| **鍵盤** | `+`/`-` 縮放、方向鍵平移、`0` 重置 | — |
|
|
204
|
+
|
|
205
|
+
放大介面會顯示縮放工具列,包含 +/−/Reset 按鈕與百分比顯示。
|
|
206
|
+
|
|
207
|
+
可透過 `toolbar.fullscreenToolbarScale` 調整 Fullscreen 工具列與縮放控制的尺寸。
|
|
208
|
+
|
|
209
|
+
|
|
143
210
|
> **Note**: 所有設定皆可透過 `runtimeConfig.public.contentMermaid` 在部署時進行覆寫(`runtimeConfig.public.mermaidContent` 仍支援但已棄用)。
|
|
144
211
|
|
|
212
|
+
## 樣式自訂(CSS 變數)
|
|
213
|
+
|
|
214
|
+
模組會提供全域 CSS 變數(來源為 `runtime/styles.css`),讓 Mermaid 區塊與放大 overlay 使用同一套配色。你可以在專案中覆寫:
|
|
215
|
+
|
|
216
|
+
```css
|
|
217
|
+
:root {
|
|
218
|
+
--ncm-code-bg: #f3f4f6;
|
|
219
|
+
--ncm-code-bg-hover: #e5e7eb;
|
|
220
|
+
--ncm-border: #e5e7eb;
|
|
221
|
+
--ncm-text: #111827;
|
|
222
|
+
--ncm-text-muted: #4b5563;
|
|
223
|
+
--ncm-text-xmuted: #6b7280;
|
|
224
|
+
--ncm-overlay-bg: rgba(255, 255, 255, 0.98);
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
html[data-theme="dark"],
|
|
228
|
+
.dark {
|
|
229
|
+
--ncm-code-bg: #111827;
|
|
230
|
+
--ncm-code-bg-hover: #1f2937;
|
|
231
|
+
--ncm-border: #1f2937;
|
|
232
|
+
--ncm-text: #f9fafb;
|
|
233
|
+
--ncm-text-muted: #9ca3af;
|
|
234
|
+
--ncm-text-xmuted: #6b7280;
|
|
235
|
+
--ncm-overlay-bg: rgba(17, 24, 39, 0.98);
|
|
236
|
+
}
|
|
237
|
+
```
|
|
238
|
+
|
|
239
|
+
可覆寫的變數:
|
|
240
|
+
可覆寫的變數:
|
|
241
|
+
- `--ncm-code-bg`:Mermaid 區塊背景色
|
|
242
|
+
- `--ncm-code-bg-hover`:工具列按鈕 hover 背景
|
|
243
|
+
- `--ncm-border-color`:區塊與工具列的邊框顏色
|
|
244
|
+
- `--ncm-border-width`:邊框厚度
|
|
245
|
+
- `--ncm-border-style`:邊框樣式
|
|
246
|
+
- `--ncm-border`:邊框 shorthand(寬度、樣式、顏色)
|
|
247
|
+
- `--ncm-border-bottom`:工具列底部的邊框
|
|
248
|
+
- `--ncm-text`:主要文字顏色
|
|
249
|
+
- `--ncm-text-muted`:標題與次要文字
|
|
250
|
+
- `--ncm-text-xmuted`:工具列 icon 與更淡的文字
|
|
251
|
+
- `--ncm-overlay-bg`:放大 overlay 背景(預設跟 `--ncm-code-bg` 一致)
|
|
252
|
+
- `--ncm-expand-target-bg`:當 `expand.margin > 0` 時,放大後留白的 SVG 外框背景,可以與 overlay 做出區隔
|
|
253
|
+
- `--ncm-overlay-opacity`:overlay 的透明度(搭配 margin 留白時可微調濃淡)
|
|
254
|
+
- `--ncm-overlay-backdrop`:顯示 overlay 時加上的 `backdrop-filter`,可自訂 blur/效果
|
|
255
|
+
- `--ncm-hint-bg`:縮放提示訊息背景色(預設 `rgba(0,0,0,0.75)`)
|
|
256
|
+
- `--ncm-hint-text`:縮放提示訊息文字顏色(預設 `#fff`)
|
|
257
|
+
- `--ncm-hint-radius`:縮放提示訊息圓角(預設 `8px`)
|
|
258
|
+
|
|
145
259
|
## Advanced Usage
|
|
146
260
|
|
|
147
261
|
### Debug 模式
|
|
@@ -231,9 +345,59 @@ graph TD
|
|
|
231
345
|
2. **frontmatter `config`** —— 深度合併在模組的 `loader.init` 之上。
|
|
232
346
|
3. **模組層級的 `contentMermaid.loader.init`** —— 專案的全域預設。
|
|
233
347
|
|
|
348
|
+
### Mermaid Inline attrs 與 YAML Frontmatter
|
|
349
|
+
|
|
350
|
+
支援三種方式控制 Mermaid Svg 的渲染:inline attrs、Mermaid YAML frontmatter、`%%{init}%%` 指令。
|
|
351
|
+
|
|
352
|
+
#### Inline attrs(fence info)
|
|
353
|
+
|
|
354
|
+
在 `mermaid` fence 上使用 inline attrs,傳遞 wrapper props 或設定 Mermaid 的 YAML 欄位(包含 `toolbar` 的 title/fontSize 與 `toolbar.buttons.*`)。
|
|
355
|
+
|
|
356
|
+
````markdown
|
|
357
|
+
```mermaid {title="Diagram A" toolbar='{"title":"My Diagram","fontSize":"14px"}' config='{"theme":"dark"}'}
|
|
358
|
+
graph TD
|
|
359
|
+
A --> B
|
|
360
|
+
```
|
|
361
|
+
````
|
|
362
|
+
|
|
363
|
+
#### Mermaid YAML frontmatter(block 內)
|
|
364
|
+
|
|
365
|
+
把 Mermaid 的 YAML frontmatter 放在 code block 最前面,用來影響 SVG 輸出(例如 title、displayMode、config),也可以提供 `toolbar` 給 wrapper 元件(包含 `toolbar.buttons.copy: true`)。
|
|
366
|
+
|
|
367
|
+
````markdown
|
|
368
|
+
```mermaid
|
|
369
|
+
---
|
|
370
|
+
title: Sample Flowchart
|
|
371
|
+
displayMode: compact
|
|
372
|
+
config:
|
|
373
|
+
theme: dark
|
|
374
|
+
toolbar:
|
|
375
|
+
title: "Sample Diagram"
|
|
376
|
+
buttons:
|
|
377
|
+
copy: true
|
|
378
|
+
expand: true
|
|
379
|
+
fullscreen: false
|
|
380
|
+
---
|
|
381
|
+
graph TD
|
|
382
|
+
A --> B
|
|
383
|
+
```
|
|
384
|
+
````
|
|
385
|
+
|
|
386
|
+
#### `%%{init}%%` 指令(block 內)
|
|
387
|
+
|
|
388
|
+
使用 Mermaid directive,直接在圖表定義內設定渲染選項。
|
|
389
|
+
|
|
390
|
+
````markdown
|
|
391
|
+
```mermaid
|
|
392
|
+
%%{init: { 'theme': 'forest', 'flowchart': { 'curve': 'step' } }}%%
|
|
393
|
+
graph TD
|
|
394
|
+
A --> B
|
|
395
|
+
```
|
|
396
|
+
````
|
|
397
|
+
|
|
234
398
|
### 自訂渲染元件 (Custom Component)
|
|
235
399
|
|
|
236
|
-
若需完全接管 Mermaid 的渲染行為(例如:加入外框、
|
|
400
|
+
若需完全接管 Mermaid 的渲染行為(例如:加入外框、Expand/Collapse 功能),可指定 `components.renderer`。
|
|
237
401
|
|
|
238
402
|
1. 在 `nuxt.config.ts` 中指定元件名稱:
|
|
239
403
|
|
package/dist/module.d.mts
CHANGED
|
@@ -1,5 +1,76 @@
|
|
|
1
1
|
import * as _nuxt_schema from '@nuxt/schema';
|
|
2
|
-
import { MermaidConfig } from 'mermaid';
|
|
2
|
+
import { Mermaid, MermaidConfig } from 'mermaid';
|
|
3
|
+
import { ExpandOptions } from '../dist/runtime/types/expand.js';
|
|
4
|
+
import { DefineComponent } from 'vue';
|
|
5
|
+
|
|
6
|
+
type MermaidToolbarButtons = {
|
|
7
|
+
copy?: boolean
|
|
8
|
+
fullscreen?: boolean
|
|
9
|
+
expand?: boolean
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
type MermaidToolbarOptions = {
|
|
13
|
+
title?: string
|
|
14
|
+
fontSize?: string | number
|
|
15
|
+
fullscreenToolbarScale?: number
|
|
16
|
+
buttons?: MermaidToolbarButtons
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
declare module '#app' {
|
|
20
|
+
interface NuxtApp {
|
|
21
|
+
$mermaid: () => Promise<Mermaid>
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
declare module 'vue' {
|
|
25
|
+
interface ComponentCustomProperties {
|
|
26
|
+
$mermaid: () => Promise<Mermaid>
|
|
27
|
+
}
|
|
28
|
+
interface GlobalComponents {
|
|
29
|
+
Mermaid: DefineComponent<{
|
|
30
|
+
config?: MermaidConfig
|
|
31
|
+
toolbar?: MermaidToolbarOptions
|
|
32
|
+
code?: string
|
|
33
|
+
}>
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
declare module 'nuxt/schema' {
|
|
38
|
+
interface NuxtConfig {
|
|
39
|
+
contentMermaid?: ModuleOptions
|
|
40
|
+
/**
|
|
41
|
+
* @deprecated Use `contentMermaid`
|
|
42
|
+
*/
|
|
43
|
+
mermaidContent?: ModuleOptions
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
interface NuxtOptions {
|
|
47
|
+
contentMermaid?: ModuleOptions
|
|
48
|
+
/**
|
|
49
|
+
* @deprecated Use `contentMermaid`
|
|
50
|
+
*/
|
|
51
|
+
mermaidContent?: ModuleOptions
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
interface PublicRuntimeConfig {
|
|
55
|
+
contentMermaid?: Partial<ModuleOptions>
|
|
56
|
+
/**
|
|
57
|
+
* @deprecated Use `contentMermaid`
|
|
58
|
+
*/
|
|
59
|
+
mermaidContent?: Partial<ModuleOptions>
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
declare global {
|
|
64
|
+
interface ImportMeta {
|
|
65
|
+
glob<T = unknown>(
|
|
66
|
+
pattern: string,
|
|
67
|
+
options?: {
|
|
68
|
+
eager?: boolean
|
|
69
|
+
import?: string
|
|
70
|
+
},
|
|
71
|
+
): Record<string, () => Promise<T>>
|
|
72
|
+
}
|
|
73
|
+
}
|
|
3
74
|
|
|
4
75
|
interface ModuleOptions {
|
|
5
76
|
/**
|
|
@@ -64,6 +135,17 @@ interface ModuleOptions {
|
|
|
64
135
|
*/
|
|
65
136
|
error?: string;
|
|
66
137
|
};
|
|
138
|
+
/**
|
|
139
|
+
* Options related to SVG expand (lightbox) interactions
|
|
140
|
+
*/
|
|
141
|
+
/**
|
|
142
|
+
* Expand configuration. `false` disables expand, `true` uses defaults.
|
|
143
|
+
*/
|
|
144
|
+
expand?: ExpandOptions | boolean;
|
|
145
|
+
/**
|
|
146
|
+
* Default toolbar settings for Mermaid component
|
|
147
|
+
*/
|
|
148
|
+
toolbar?: MermaidToolbarOptions;
|
|
67
149
|
}
|
|
68
150
|
declare const _default: _nuxt_schema.NuxtModule<ModuleOptions, ModuleOptions, false>;
|
|
69
151
|
|
package/dist/module.json
CHANGED
package/dist/module.mjs
CHANGED
|
@@ -1,9 +1,11 @@
|
|
|
1
1
|
import { defineNuxtModule, useLogger, createResolver, addVitePlugin, addPlugin, addComponent, addImports, addTypeTemplate } from '@nuxt/kit';
|
|
2
2
|
import { defu } from 'defu';
|
|
3
|
-
import { DEFAULT_MERMAID_CONFIG, DEFAULT_DARK_THEME, DEFAULT_LIGHT_THEME, DEFAULT_FRONTMATTER_CONFIG_KEY } from '../dist/runtime/constants.js';
|
|
3
|
+
import { DEFAULT_MERMAID_CONFIG, DEFAULT_TOOLBAR_OPTIONS, DEFAULT_EXPAND_OPTIONS, DEFAULT_DARK_THEME, DEFAULT_LIGHT_THEME, DEFAULT_FRONTMATTER_CONFIG_KEY } from '../dist/runtime/constants.js';
|
|
4
|
+
import { parseInlineAttrs, parseMermaidFrontmatter, extractMermaidInlineOverrides, applyMermaidFrontmatterOverrides, mergeToolbarProps, extractToolbarProps } from '../dist/runtime/utils/mermaid-transform.js';
|
|
5
|
+
import { isNonEmptyRecord, stringifyInlineValue } from '../dist/runtime/utils/index.js';
|
|
4
6
|
|
|
5
|
-
const MERMAID_BLOCK = /```mermaid([\s\S]*?)```/gi;
|
|
6
7
|
const SANITIZE_URL_PACKAGE = "@braintree/sanitize-url";
|
|
8
|
+
const MERMAID_FENCE_RE = /^[ \t]*(?:`{3,}|~{3,})[ \t]*mermaid(?:$|[ \t{[])/im;
|
|
7
9
|
const DEFAULTS = {
|
|
8
10
|
enabled: true,
|
|
9
11
|
loader: {
|
|
@@ -18,7 +20,9 @@ const DEFAULTS = {
|
|
|
18
20
|
renderer: void 0,
|
|
19
21
|
spinner: void 0,
|
|
20
22
|
error: void 0
|
|
21
|
-
}
|
|
23
|
+
},
|
|
24
|
+
expand: DEFAULT_EXPAND_OPTIONS,
|
|
25
|
+
toolbar: DEFAULT_TOOLBAR_OPTIONS
|
|
22
26
|
};
|
|
23
27
|
const module$1 = defineNuxtModule({
|
|
24
28
|
meta: {
|
|
@@ -46,6 +50,8 @@ const module$1 = defineNuxtModule({
|
|
|
46
50
|
);
|
|
47
51
|
const resolver = createResolver(import.meta.url);
|
|
48
52
|
const runtimeDir = resolver.resolve("./runtime");
|
|
53
|
+
nuxt.options.css ||= [];
|
|
54
|
+
nuxt.options.css.push(resolver.resolve("./runtime/styles.css"));
|
|
49
55
|
const publicRuntimeConfig = nuxt.options.runtimeConfig.public;
|
|
50
56
|
const runtimeOverrides = publicRuntimeConfig.contentMermaid || publicRuntimeConfig.mermaidContent || {};
|
|
51
57
|
if (!publicRuntimeConfig.contentMermaid && publicRuntimeConfig.mermaidContent)
|
|
@@ -106,7 +112,7 @@ export {}
|
|
|
106
112
|
nuxt.hook("content:file:beforeParse", (ctx) => {
|
|
107
113
|
const { file } = ctx;
|
|
108
114
|
if (!file.id?.endsWith(".md")) return;
|
|
109
|
-
if (!file.body
|
|
115
|
+
if (!MERMAID_FENCE_RE.test(file.body)) return;
|
|
110
116
|
file.body = transformMermaidCodeBlocks(
|
|
111
117
|
file.body,
|
|
112
118
|
baseMermaidComponentName
|
|
@@ -115,12 +121,123 @@ export {}
|
|
|
115
121
|
}
|
|
116
122
|
});
|
|
117
123
|
function transformMermaidCodeBlocks(body, componentName, frontmatterConfigKey = DEFAULT_FRONTMATTER_CONFIG_KEY) {
|
|
118
|
-
|
|
124
|
+
const newline = body.includes("\r\n") ? "\r\n" : "\n";
|
|
125
|
+
const lines = body.split(newline);
|
|
126
|
+
const output = [];
|
|
127
|
+
let inFence = false;
|
|
128
|
+
let fenceChar = null;
|
|
129
|
+
let fenceLength = 0;
|
|
130
|
+
const isClosingFence = (line) => {
|
|
131
|
+
if (!fenceChar) return false;
|
|
132
|
+
const trimmed = line.trim();
|
|
133
|
+
if (trimmed.length < fenceLength) return false;
|
|
134
|
+
for (const char of trimmed) {
|
|
135
|
+
if (char !== fenceChar) return false;
|
|
136
|
+
}
|
|
137
|
+
return true;
|
|
138
|
+
};
|
|
139
|
+
const isFenceMarkerChar = (char) => char === "`" || char === "~";
|
|
140
|
+
const parseFence = (line) => {
|
|
141
|
+
let index = 0;
|
|
142
|
+
while (index < line.length && (line[index] === " " || line[index] === " "))
|
|
143
|
+
index++;
|
|
144
|
+
const indent = line.slice(0, index);
|
|
145
|
+
const markerChar = line[index];
|
|
146
|
+
if (!isFenceMarkerChar(markerChar))
|
|
147
|
+
return null;
|
|
148
|
+
let markerEnd = index;
|
|
149
|
+
while (markerEnd < line.length && line[markerEnd] === markerChar)
|
|
150
|
+
markerEnd++;
|
|
151
|
+
const markerLength = markerEnd - index;
|
|
152
|
+
if (markerLength < 3)
|
|
153
|
+
return null;
|
|
154
|
+
return {
|
|
155
|
+
indent,
|
|
156
|
+
markerChar,
|
|
157
|
+
markerLength,
|
|
158
|
+
info: line.slice(markerEnd).trim()
|
|
159
|
+
};
|
|
160
|
+
};
|
|
161
|
+
const isMermaidFence = (info) => {
|
|
162
|
+
if (!info) return false;
|
|
163
|
+
const lower = info.toLowerCase();
|
|
164
|
+
if (!lower.startsWith("mermaid")) return false;
|
|
165
|
+
const next = lower.slice("mermaid".length, "mermaid".length + 1);
|
|
166
|
+
return next === "" || /\s/.test(next) || next === "{" || next === "[";
|
|
167
|
+
};
|
|
168
|
+
const buildComponentTag = (encoded, toolbar) => {
|
|
169
|
+
const attrs = [
|
|
170
|
+
`:config="${frontmatterConfigKey}"`
|
|
171
|
+
];
|
|
172
|
+
if (toolbar && isNonEmptyRecord(toolbar)) {
|
|
173
|
+
attrs.push(`:toolbar='${stringifyInlineValue(toolbar)}'`);
|
|
174
|
+
}
|
|
175
|
+
attrs.push(`code="${encoded}"`);
|
|
176
|
+
return `<${componentName} ${attrs.join(" ")}></${componentName}>`;
|
|
177
|
+
};
|
|
178
|
+
for (let index = 0; index < lines.length; index++) {
|
|
179
|
+
const line = lines[index];
|
|
180
|
+
if (inFence) {
|
|
181
|
+
output.push(line);
|
|
182
|
+
if (isClosingFence(line)) {
|
|
183
|
+
inFence = false;
|
|
184
|
+
fenceChar = null;
|
|
185
|
+
fenceLength = 0;
|
|
186
|
+
}
|
|
187
|
+
continue;
|
|
188
|
+
}
|
|
189
|
+
const fence = parseFence(line);
|
|
190
|
+
if (!fence) {
|
|
191
|
+
output.push(line);
|
|
192
|
+
continue;
|
|
193
|
+
}
|
|
194
|
+
if (!isMermaidFence(fence.info)) {
|
|
195
|
+
inFence = true;
|
|
196
|
+
fenceChar = fence.markerChar;
|
|
197
|
+
fenceLength = fence.markerLength;
|
|
198
|
+
output.push(line);
|
|
199
|
+
continue;
|
|
200
|
+
}
|
|
201
|
+
let closingIndex = -1;
|
|
202
|
+
for (let j = index + 1; j < lines.length; j++) {
|
|
203
|
+
const trimmed = lines[j].trim();
|
|
204
|
+
if (trimmed.length < fence.markerLength) continue;
|
|
205
|
+
let isFence = true;
|
|
206
|
+
for (const char of trimmed) {
|
|
207
|
+
if (char !== fence.markerChar) {
|
|
208
|
+
isFence = false;
|
|
209
|
+
break;
|
|
210
|
+
}
|
|
211
|
+
}
|
|
212
|
+
if (isFence) {
|
|
213
|
+
closingIndex = j;
|
|
214
|
+
break;
|
|
215
|
+
}
|
|
216
|
+
}
|
|
217
|
+
if (closingIndex === -1) {
|
|
218
|
+
output.push(line);
|
|
219
|
+
continue;
|
|
220
|
+
}
|
|
221
|
+
const rawCode = lines.slice(index + 1, closingIndex).join(newline);
|
|
119
222
|
const code = rawCode.trim();
|
|
120
|
-
if (!code)
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
223
|
+
if (!code) {
|
|
224
|
+
output.push(...lines.slice(index, closingIndex + 1));
|
|
225
|
+
index = closingIndex;
|
|
226
|
+
continue;
|
|
227
|
+
}
|
|
228
|
+
const inlineAttrs = parseInlineAttrs(fence.info);
|
|
229
|
+
const frontmatterInfo = parseMermaidFrontmatter(rawCode, newline);
|
|
230
|
+
const inlineOverrides = extractMermaidInlineOverrides(inlineAttrs);
|
|
231
|
+
const mergedCode = inlineOverrides ? applyMermaidFrontmatterOverrides(rawCode, newline, frontmatterInfo, inlineOverrides, fence.indent) : rawCode;
|
|
232
|
+
const toolbarProps = mergeToolbarProps(
|
|
233
|
+
extractToolbarProps(frontmatterInfo?.data),
|
|
234
|
+
extractToolbarProps(inlineAttrs)
|
|
235
|
+
);
|
|
236
|
+
const encoded = encodeURIComponent(mergedCode.trim());
|
|
237
|
+
output.push(`${fence.indent}${buildComponentTag(encoded, toolbarProps)}`);
|
|
238
|
+
index = closingIndex;
|
|
239
|
+
}
|
|
240
|
+
return output.join(newline);
|
|
124
241
|
}
|
|
125
242
|
|
|
126
243
|
export { module$1 as default, transformMermaidCodeBlocks };
|
|
@@ -1,9 +1,11 @@
|
|
|
1
1
|
import type { MermaidConfig } from 'mermaid';
|
|
2
|
+
import type { MermaidToolbarOptions } from '~/src/types/mermaid';
|
|
2
3
|
type __VLS_Props = {
|
|
3
4
|
config?: MermaidConfig | string | unknown;
|
|
5
|
+
toolbar?: MermaidToolbarOptions;
|
|
4
6
|
code?: string;
|
|
5
7
|
};
|
|
6
|
-
declare var __VLS_1: {}, __VLS_9: {},
|
|
8
|
+
declare var __VLS_1: {}, __VLS_9: {}, __VLS_52: {}, __VLS_54: {}, __VLS_62: {
|
|
7
9
|
error: unknown;
|
|
8
10
|
source: string;
|
|
9
11
|
};
|
|
@@ -12,11 +14,11 @@ type __VLS_Slots = {} & {
|
|
|
12
14
|
} & {
|
|
13
15
|
default?: (props: typeof __VLS_9) => any;
|
|
14
16
|
} & {
|
|
15
|
-
default?: (props: typeof
|
|
17
|
+
default?: (props: typeof __VLS_52) => any;
|
|
16
18
|
} & {
|
|
17
|
-
loading?: (props: typeof
|
|
19
|
+
loading?: (props: typeof __VLS_54) => any;
|
|
18
20
|
} & {
|
|
19
|
-
error?: (props: typeof
|
|
21
|
+
error?: (props: typeof __VLS_62) => any;
|
|
20
22
|
};
|
|
21
23
|
declare const __VLS_base: import("vue").DefineComponent<__VLS_Props, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {}, string, import("vue").PublicProps, Readonly<__VLS_Props> & Readonly<{}>, {}, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
|
|
22
24
|
declare const __VLS_export: __VLS_WithSlots<typeof __VLS_base, __VLS_Slots>;
|