astro-mermaid 1.0.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 +95 -0
- package/astro-mermaid-integration.d.ts +41 -0
- package/astro-mermaid-integration.js +255 -0
- package/package.json +53 -0
package/README.md
ADDED
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
# astro-mermaid
|
|
2
|
+
|
|
3
|
+
An Astro integration for rendering Mermaid diagrams with automatic theme switching and client-side rendering.
|
|
4
|
+
|
|
5
|
+
## Features
|
|
6
|
+
|
|
7
|
+
- 🎨 Automatic theme switching based on your site's theme
|
|
8
|
+
- 🚀 Client-side rendering for optimal performance
|
|
9
|
+
- 📝 Simple markdown syntax using code blocks
|
|
10
|
+
- ⚡ Vite optimization for fast development
|
|
11
|
+
- 🔧 Customizable mermaid configuration
|
|
12
|
+
- 🎯 TypeScript support
|
|
13
|
+
|
|
14
|
+
## Installation
|
|
15
|
+
|
|
16
|
+
```bash
|
|
17
|
+
npm install astro-mermaid mermaid
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
## Usage
|
|
21
|
+
|
|
22
|
+
Add the integration to your `astro.config.mjs`:
|
|
23
|
+
|
|
24
|
+
```js
|
|
25
|
+
import { defineConfig } from 'astro/config';
|
|
26
|
+
import mermaid from 'astro-mermaid';
|
|
27
|
+
|
|
28
|
+
export default defineConfig({
|
|
29
|
+
integrations: [
|
|
30
|
+
mermaid()
|
|
31
|
+
]
|
|
32
|
+
});
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
Then use mermaid code blocks in your markdown files:
|
|
36
|
+
|
|
37
|
+
````markdown
|
|
38
|
+
```mermaid
|
|
39
|
+
graph TD
|
|
40
|
+
A[Start] --> B{Is it working?}
|
|
41
|
+
B -->|Yes| C[Great!]
|
|
42
|
+
B -->|No| D[Debug]
|
|
43
|
+
D --> A
|
|
44
|
+
```
|
|
45
|
+
````
|
|
46
|
+
|
|
47
|
+
## Configuration
|
|
48
|
+
|
|
49
|
+
```js
|
|
50
|
+
mermaid({
|
|
51
|
+
// Default theme: 'default', 'dark', 'forest', 'neutral', 'base'
|
|
52
|
+
theme: 'forest',
|
|
53
|
+
|
|
54
|
+
// Enable automatic theme switching based on data-theme attribute
|
|
55
|
+
autoTheme: true,
|
|
56
|
+
|
|
57
|
+
// Additional mermaid configuration
|
|
58
|
+
mermaidConfig: {
|
|
59
|
+
flowchart: {
|
|
60
|
+
curve: 'basis'
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
})
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
## Theme Switching
|
|
67
|
+
|
|
68
|
+
If `autoTheme` is enabled (default), the integration will automatically switch between themes based on your site's `data-theme` attribute:
|
|
69
|
+
|
|
70
|
+
- `data-theme="light"` → uses 'default' mermaid theme
|
|
71
|
+
- `data-theme="dark"` → uses 'dark' mermaid theme
|
|
72
|
+
|
|
73
|
+
## Supported Diagrams
|
|
74
|
+
|
|
75
|
+
All mermaid diagram types are supported:
|
|
76
|
+
|
|
77
|
+
- Flowcharts
|
|
78
|
+
- Sequence diagrams
|
|
79
|
+
- Gantt charts
|
|
80
|
+
- Class diagrams
|
|
81
|
+
- State diagrams
|
|
82
|
+
- Entity Relationship diagrams
|
|
83
|
+
- User Journey diagrams
|
|
84
|
+
- Git graphs
|
|
85
|
+
- Pie charts
|
|
86
|
+
- Requirement diagrams
|
|
87
|
+
- C4 diagrams
|
|
88
|
+
- Mindmaps
|
|
89
|
+
- Timeline diagrams
|
|
90
|
+
- Quadrant charts
|
|
91
|
+
- And more!
|
|
92
|
+
|
|
93
|
+
## License
|
|
94
|
+
|
|
95
|
+
MIT
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import type { AstroIntegration } from 'astro';
|
|
2
|
+
|
|
3
|
+
export interface AstroMermaidOptions {
|
|
4
|
+
/**
|
|
5
|
+
* Default mermaid theme
|
|
6
|
+
* @default 'default'
|
|
7
|
+
*/
|
|
8
|
+
theme?: 'default' | 'dark' | 'forest' | 'neutral' | 'base';
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* Enable automatic theme switching based on data-theme attribute
|
|
12
|
+
* @default true
|
|
13
|
+
*/
|
|
14
|
+
autoTheme?: boolean;
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* Additional mermaid configuration options
|
|
18
|
+
* @see https://mermaid.js.org/config/setup/modules/mermaidAPI.html#mermaidapi-configuration-defaults
|
|
19
|
+
*/
|
|
20
|
+
mermaidConfig?: Record<string, any>;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* Astro integration for rendering Mermaid diagrams
|
|
25
|
+
*
|
|
26
|
+
* @example
|
|
27
|
+
* ```js
|
|
28
|
+
* import { defineConfig } from 'astro/config';
|
|
29
|
+
* import mermaid from 'astro-mermaid';
|
|
30
|
+
*
|
|
31
|
+
* export default defineConfig({
|
|
32
|
+
* integrations: [
|
|
33
|
+
* mermaid({
|
|
34
|
+
* theme: 'forest',
|
|
35
|
+
* autoTheme: true
|
|
36
|
+
* })
|
|
37
|
+
* ]
|
|
38
|
+
* });
|
|
39
|
+
* ```
|
|
40
|
+
*/
|
|
41
|
+
export default function astroMermaid(options?: AstroMermaidOptions): AstroIntegration;
|
|
@@ -0,0 +1,255 @@
|
|
|
1
|
+
import { fileURLToPath } from 'node:url';
|
|
2
|
+
import path from 'node:path';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Rehype plugin to transform mermaid code blocks
|
|
6
|
+
* Converts ```mermaid code blocks to <pre class="mermaid">
|
|
7
|
+
*/
|
|
8
|
+
function rehypeMermaidPlugin(options = {}) {
|
|
9
|
+
return async function transformer(tree, file) {
|
|
10
|
+
const { visit } = await import('unist-util-visit');
|
|
11
|
+
const { toString } = await import('mdast-util-to-string');
|
|
12
|
+
|
|
13
|
+
let mermaidCount = 0;
|
|
14
|
+
|
|
15
|
+
visit(tree, 'element', (node, index, parent) => {
|
|
16
|
+
// Look for <pre><code class="language-mermaid">
|
|
17
|
+
if (
|
|
18
|
+
node.tagName === 'pre' &&
|
|
19
|
+
node.children?.length === 1 &&
|
|
20
|
+
node.children[0].tagName === 'code'
|
|
21
|
+
) {
|
|
22
|
+
const codeNode = node.children[0];
|
|
23
|
+
const className = codeNode.properties?.className;
|
|
24
|
+
|
|
25
|
+
if (Array.isArray(className) && className.includes('language-mermaid')) {
|
|
26
|
+
mermaidCount++;
|
|
27
|
+
// Get the mermaid diagram content
|
|
28
|
+
const diagramContent = toString(codeNode);
|
|
29
|
+
|
|
30
|
+
// Transform to <pre class="mermaid">
|
|
31
|
+
node.properties = {
|
|
32
|
+
...node.properties,
|
|
33
|
+
className: ['mermaid']
|
|
34
|
+
};
|
|
35
|
+
|
|
36
|
+
node.children = [{
|
|
37
|
+
type: 'text',
|
|
38
|
+
value: diagramContent
|
|
39
|
+
}];
|
|
40
|
+
|
|
41
|
+
if (options.logger) {
|
|
42
|
+
options.logger.info(`Transformed mermaid block #${mermaidCount} in ${file.path || 'unknown file'}`);
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
});
|
|
47
|
+
|
|
48
|
+
if (mermaidCount > 0 && options.logger) {
|
|
49
|
+
options.logger.info(`Total mermaid blocks transformed: ${mermaidCount}`);
|
|
50
|
+
}
|
|
51
|
+
};
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
/**
|
|
55
|
+
* Astro integration for rendering Mermaid diagrams
|
|
56
|
+
* Supports automatic theme switching and client-side rendering
|
|
57
|
+
*
|
|
58
|
+
* @param {Object} options - Configuration options
|
|
59
|
+
* @param {string} [options.theme='default'] - Default theme ('default', 'dark', 'forest', 'neutral')
|
|
60
|
+
* @param {boolean} [options.autoTheme=true] - Enable automatic theme switching based on data-theme attribute
|
|
61
|
+
* @param {Object} [options.mermaidConfig={}] - Additional mermaid configuration options
|
|
62
|
+
* @returns {import('astro').AstroIntegration}
|
|
63
|
+
*/
|
|
64
|
+
export default function astroMermaid(options = {}) {
|
|
65
|
+
const {
|
|
66
|
+
theme = 'default',
|
|
67
|
+
autoTheme = true,
|
|
68
|
+
mermaidConfig = {}
|
|
69
|
+
} = options;
|
|
70
|
+
|
|
71
|
+
return {
|
|
72
|
+
name: 'astro-mermaid',
|
|
73
|
+
hooks: {
|
|
74
|
+
'astro:config:setup': async ({ config, updateConfig, addWatchFile, injectScript, logger, command }) => {
|
|
75
|
+
logger.info('Setting up Mermaid integration');
|
|
76
|
+
|
|
77
|
+
// Log existing rehype plugins
|
|
78
|
+
logger.info('Existing rehype plugins:', config.markdown?.rehypePlugins?.length || 0);
|
|
79
|
+
|
|
80
|
+
// Update markdown config to use our rehype plugin
|
|
81
|
+
updateConfig({
|
|
82
|
+
markdown: {
|
|
83
|
+
rehypePlugins: [
|
|
84
|
+
...(config.markdown?.rehypePlugins || []),
|
|
85
|
+
[rehypeMermaidPlugin, { logger }]
|
|
86
|
+
]
|
|
87
|
+
},
|
|
88
|
+
vite: {
|
|
89
|
+
optimizeDeps: {
|
|
90
|
+
include: ['mermaid']
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
});
|
|
94
|
+
|
|
95
|
+
// Inject client-side mermaid script
|
|
96
|
+
const mermaidScriptContent = `
|
|
97
|
+
import mermaid from 'mermaid';
|
|
98
|
+
|
|
99
|
+
// Mermaid configuration
|
|
100
|
+
const defaultConfig = ${JSON.stringify({
|
|
101
|
+
startOnLoad: false,
|
|
102
|
+
theme: theme,
|
|
103
|
+
...mermaidConfig
|
|
104
|
+
})};
|
|
105
|
+
|
|
106
|
+
// Theme mapping for auto-theme switching
|
|
107
|
+
const themeMap = {
|
|
108
|
+
'light': 'default',
|
|
109
|
+
'dark': 'dark'
|
|
110
|
+
};
|
|
111
|
+
|
|
112
|
+
// Initialize all mermaid diagrams
|
|
113
|
+
async function initMermaid() {
|
|
114
|
+
console.log('[astro-mermaid] Initializing mermaid diagrams...');
|
|
115
|
+
const diagrams = document.querySelectorAll('pre.mermaid');
|
|
116
|
+
|
|
117
|
+
console.log('[astro-mermaid] Found', diagrams.length, 'mermaid diagrams');
|
|
118
|
+
|
|
119
|
+
if (diagrams.length === 0) {
|
|
120
|
+
console.log('[astro-mermaid] No mermaid diagrams found. Looking for code blocks...');
|
|
121
|
+
const codeBlocks = document.querySelectorAll('pre code.language-mermaid');
|
|
122
|
+
console.log('[astro-mermaid] Found', codeBlocks.length, 'mermaid code blocks');
|
|
123
|
+
return;
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
// Get current theme
|
|
127
|
+
let currentTheme = defaultConfig.theme;
|
|
128
|
+
|
|
129
|
+
if (${autoTheme}) {
|
|
130
|
+
const dataTheme = document.documentElement.getAttribute('data-theme');
|
|
131
|
+
currentTheme = themeMap[dataTheme] || defaultConfig.theme;
|
|
132
|
+
console.log('[astro-mermaid] Using theme:', currentTheme);
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
// Configure mermaid
|
|
136
|
+
mermaid.initialize({
|
|
137
|
+
...defaultConfig,
|
|
138
|
+
theme: currentTheme
|
|
139
|
+
});
|
|
140
|
+
|
|
141
|
+
// Render each diagram
|
|
142
|
+
for (const diagram of diagrams) {
|
|
143
|
+
// Skip if already processed
|
|
144
|
+
if (diagram.hasAttribute('data-processed')) continue;
|
|
145
|
+
|
|
146
|
+
// Store original content
|
|
147
|
+
if (!diagram.hasAttribute('data-diagram')) {
|
|
148
|
+
diagram.setAttribute('data-diagram', diagram.textContent || '');
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
const diagramDefinition = diagram.getAttribute('data-diagram') || '';
|
|
152
|
+
const id = 'mermaid-' + Math.random().toString(36).slice(2, 11);
|
|
153
|
+
|
|
154
|
+
console.log('[astro-mermaid] Rendering diagram:', id);
|
|
155
|
+
|
|
156
|
+
try {
|
|
157
|
+
const { svg } = await mermaid.render(id, diagramDefinition);
|
|
158
|
+
diagram.innerHTML = svg;
|
|
159
|
+
diagram.setAttribute('data-processed', 'true');
|
|
160
|
+
console.log('[astro-mermaid] Successfully rendered diagram:', id);
|
|
161
|
+
} catch (error) {
|
|
162
|
+
console.error('[astro-mermaid] Mermaid rendering error:', error);
|
|
163
|
+
diagram.innerHTML = '<div style="color: red;">Error rendering diagram</div>';
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
// Initialize on DOM ready
|
|
169
|
+
if (document.readyState === 'loading') {
|
|
170
|
+
document.addEventListener('DOMContentLoaded', initMermaid);
|
|
171
|
+
} else {
|
|
172
|
+
initMermaid();
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
// Re-render on theme change if auto-theme is enabled
|
|
176
|
+
if (${autoTheme}) {
|
|
177
|
+
const observer = new MutationObserver((mutations) => {
|
|
178
|
+
for (const mutation of mutations) {
|
|
179
|
+
if (mutation.type === 'attributes' && mutation.attributeName === 'data-theme') {
|
|
180
|
+
// Reset processed state and re-render
|
|
181
|
+
document.querySelectorAll('pre.mermaid[data-processed]').forEach(diagram => {
|
|
182
|
+
diagram.removeAttribute('data-processed');
|
|
183
|
+
});
|
|
184
|
+
initMermaid();
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
});
|
|
188
|
+
|
|
189
|
+
observer.observe(document.documentElement, {
|
|
190
|
+
attributes: true,
|
|
191
|
+
attributeFilter: ['data-theme']
|
|
192
|
+
});
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
// Handle view transitions (for Astro View Transitions API)
|
|
196
|
+
document.addEventListener('astro:after-swap', initMermaid);
|
|
197
|
+
`;
|
|
198
|
+
|
|
199
|
+
injectScript('page', mermaidScriptContent);
|
|
200
|
+
|
|
201
|
+
// Add CSS to the page
|
|
202
|
+
injectScript('page', `
|
|
203
|
+
// Add CSS for mermaid diagrams
|
|
204
|
+
const style = document.createElement('style');
|
|
205
|
+
style.textContent = \`
|
|
206
|
+
/* Hide diagrams until processed to prevent flash of unstyled content */
|
|
207
|
+
pre.mermaid:not([data-processed]) {
|
|
208
|
+
opacity: 0;
|
|
209
|
+
transition: opacity 0.3s ease-in-out;
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
/* Show processed diagrams */
|
|
213
|
+
pre.mermaid[data-processed] {
|
|
214
|
+
opacity: 1;
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
/* Center mermaid diagrams and add spacing */
|
|
218
|
+
pre.mermaid {
|
|
219
|
+
display: flex;
|
|
220
|
+
justify-content: center;
|
|
221
|
+
align-items: center;
|
|
222
|
+
margin: 2rem 0;
|
|
223
|
+
padding: 1rem;
|
|
224
|
+
background-color: transparent;
|
|
225
|
+
border: none;
|
|
226
|
+
overflow: auto;
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
/* Ensure responsive sizing for mermaid SVGs */
|
|
230
|
+
pre.mermaid svg {
|
|
231
|
+
max-width: 100%;
|
|
232
|
+
height: auto;
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
/* Optional: Add subtle background for better visibility */
|
|
236
|
+
@media (prefers-color-scheme: dark) {
|
|
237
|
+
pre.mermaid {
|
|
238
|
+
background-color: rgba(255, 255, 255, 0.02);
|
|
239
|
+
border-radius: 0.5rem;
|
|
240
|
+
}
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
@media (prefers-color-scheme: light) {
|
|
244
|
+
pre.mermaid {
|
|
245
|
+
background-color: rgba(0, 0, 0, 0.02);
|
|
246
|
+
border-radius: 0.5rem;
|
|
247
|
+
}
|
|
248
|
+
}
|
|
249
|
+
\`;
|
|
250
|
+
document.head.appendChild(style);
|
|
251
|
+
`);
|
|
252
|
+
}
|
|
253
|
+
}
|
|
254
|
+
};
|
|
255
|
+
}
|
package/package.json
ADDED
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "astro-mermaid",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"description": "An Astro integration for rendering Mermaid diagrams with automatic theme switching and client-side rendering",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"main": "./astro-mermaid-integration.js",
|
|
7
|
+
"types": "./astro-mermaid-integration.d.ts",
|
|
8
|
+
"exports": {
|
|
9
|
+
".": {
|
|
10
|
+
"import": "./astro-mermaid-integration.js",
|
|
11
|
+
"types": "./astro-mermaid-integration.d.ts"
|
|
12
|
+
}
|
|
13
|
+
},
|
|
14
|
+
"files": [
|
|
15
|
+
"astro-mermaid-integration.js",
|
|
16
|
+
"astro-mermaid-integration.d.ts",
|
|
17
|
+
"README.md"
|
|
18
|
+
],
|
|
19
|
+
"keywords": [
|
|
20
|
+
"astro",
|
|
21
|
+
"astro-integration",
|
|
22
|
+
"mermaid",
|
|
23
|
+
"diagrams",
|
|
24
|
+
"markdown",
|
|
25
|
+
"flowchart",
|
|
26
|
+
"gantt",
|
|
27
|
+
"sequence-diagram"
|
|
28
|
+
],
|
|
29
|
+
"author": "Jose Sebastian",
|
|
30
|
+
"license": "MIT",
|
|
31
|
+
"peerDependencies": {
|
|
32
|
+
"astro": "^4.0.0 || ^5.0.0",
|
|
33
|
+
"mermaid": "^10.0.0 || ^11.0.0"
|
|
34
|
+
},
|
|
35
|
+
"dependencies": {
|
|
36
|
+
"mdast-util-to-string": "^4.0.0",
|
|
37
|
+
"unist-util-visit": "^5.0.0"
|
|
38
|
+
},
|
|
39
|
+
"devDependencies": {
|
|
40
|
+
"@types/hast": "^3.0.4",
|
|
41
|
+
"astro": "^5.0.0",
|
|
42
|
+
"mermaid": "^11.0.0",
|
|
43
|
+
"typescript": "^5.0.0"
|
|
44
|
+
},
|
|
45
|
+
"repository": {
|
|
46
|
+
"type": "git",
|
|
47
|
+
"url": "https://github.com/joesaby/astro-mermaid.git"
|
|
48
|
+
},
|
|
49
|
+
"homepage": "https://github.com/joesaby/astro-mermaid#readme",
|
|
50
|
+
"bugs": {
|
|
51
|
+
"url": "https://github.com/joesaby/astro-mermaid/issues"
|
|
52
|
+
}
|
|
53
|
+
}
|