Skip to content

Instantly share code, notes, and snippets.

@engalar
Last active March 3, 2025 03:38
Show Gist options
  • Save engalar/415b1399aa4bce71626dba161d795d38 to your computer and use it in GitHub Desktop.
Save engalar/415b1399aa4bce71626dba161d795d38 to your computer and use it in GitHub Desktop.
tampermonkey UserScript for mermaid
// ==UserScript==
// @name Mermaid代码可视化
// @namespace http://tampermonkey.net/
// @version 1.0.0
// @description 将网页中的Mermaid代码块转换为可视化图表,每2秒自动检测
// @author You
// @match http://localhost:5678/webhook/*
// @icon data:image/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==
// @grant GM_addStyle
// @grant GM_notification
// @grant GM_log
// @grant GM_getResourceText
// @grant GM_addElement
// @require https://cdnjs.cloudflare.com/ajax/libs/mermaid/10.6.1/mermaid.min.js
// @require https://gist.githubusercontent.com/engalar/50f742215c2e96efb54ab4e2d177181e/raw/util.js
// @resource sweetalert2_css https://cdn.jsdelivr.net/npm/sweetalert2@11/dist/sweetalert2.min.css
// @resource sweetalert2_js https://cdn.jsdelivr.net/npm/sweetalert2@11/dist/sweetalert2.min.js
// @downloadURL https://gist.githubusercontent.com/engalar/415b1399aa4bce71626dba161d795d38/raw/mermaid.user.js
// @updateURL https://gist.githubusercontent.com/engalar/415b1399aa4bce71626dba161d795d38/raw/mermaid.user.js
// ==/UserScript==
(function() {
'use strict';
// 配置常量
const CODE_BLOCK_SELECTOR = 'code.language-mermaid';
const BUTTON_TEXT = '渲染图表';
const NOTIFICATION_TIMEOUT = 2000;
const AUTO_SCAN_INTERVAL = 2000; // 自动扫描间隔设为2秒
// 加载SweetAlert2资源
GM_addElement('script', {
textContent: GM_getResourceText('sweetalert2_js')
});
GM_addStyle(GM_getResourceText('sweetalert2_css'));
// 添加自定义样式
GM_addStyle(`
.mermaid-chart {
width: 100%;
margin: 10px 0;
background-color: #f9f9f9;
border-radius: 4px;
padding: 10px;
box-shadow: 0 2px 5px rgba(0,0,0,0.1);
}
.mermaid-render-button {
user-select: none;
transition: background 120ms ease-in;
cursor: pointer;
display: inline-flex;
align-items: center;
white-space: nowrap;
height: 24px;
border-radius: 4px;
font-size: 12px;
line-height: 1.2;
padding: 0 8px;
background-color: #4CAF50;
color: white;
border: none;
margin: 5px 0;
}
.mermaid-render-button:hover {
background-color: #3e8e41;
}
.mermaid-toggle-button {
position: fixed;
bottom: 20px;
right: 20px;
z-index: 9999;
padding: 8px 12px;
background-color: #4CAF50;
color: white;
border: none;
border-radius: 4px;
cursor: pointer;
box-shadow: 0 2px 5px rgba(0,0,0,0.2);
font-size: 14px;
}
.mermaid-toggle-button:hover {
background-color: #3e8e41;
}
`);
// 初始化mermaid
mermaid.initialize({
startOnLoad: false,
theme: 'default',
securityLevel: 'loose'
});
// 工具函数
function showNotification(message, type = 'success') {
GM_notification({
text: message,
timeout: NOTIFICATION_TIMEOUT
});
}
function createButton(text, clickHandler) {
const button = document.createElement('button');
button.className = 'mermaid-render-button';
button.textContent = text;
button.addEventListener('click', clickHandler);
return button;
}
// 内容处理函数
function extractMermaidCode(codeElement) {
return codeElement.textContent.trim();
}
async function renderMermaidCode(codeElement, chartDiv, index) {
const mermaidCode = extractMermaidCode(codeElement);
try {
const result = await mermaid.render(`mermaid-${index}`, mermaidCode);
chartDiv.innerHTML = result.svg;
return true;
} catch (error) {
console.error('Mermaid渲染错误:', error);
chartDiv.innerHTML = `<div style="color: red; border: 1px solid red; padding: 10px;">
Mermaid渲染错误: ${error.message}
</div>`;
return false;
}
}
function showGraph(svgContent) {
Swal.fire({
title: 'Mermaid图表',
html: `<div class="mermaid-fullscreen">${svgContent}</div>`,
width: '80%',
padding: '1em',
backdrop: `rgba(0,0,0,0.4)`,
showConfirmButton: false,
showCloseButton: true
});
}
// 处理单个Mermaid代码块
async function processMermaidBlock(codeElement, index) {
if (codeElement.__mermaid_processed) {
return;
}
// 创建容器
const chartContainer = document.createElement('div');
chartContainer.className = 'mermaid-chart-container';
// 创建图表div
const chartDiv = document.createElement('div');
chartDiv.className = 'mermaid-chart';
chartDiv.id = `mermaid-chart-${index}`;
chartContainer.appendChild(chartDiv);
// 创建按钮容器
const buttonContainer = document.createElement('div');
buttonContainer.style.textAlign = 'right';
// 创建显示/隐藏代码按钮
const toggleCodeButton = createButton('显示代码', () => {
const isHidden = codeElement.style.display === 'none';
codeElement.style.display = isHidden ? 'block' : 'none';
toggleCodeButton.textContent = isHidden ? '隐藏代码' : '显示代码';
});
buttonContainer.appendChild(toggleCodeButton);
// 创建重新渲染按钮
const rerenderButton = createButton('重新渲染', () => {
renderMermaidCode(codeElement, chartDiv, index)
.then(success => {
if (success) {
showNotification('重新渲染成功');
} else {
showNotification('渲染失败,请检查语法', 'error');
}
});
});
buttonContainer.appendChild(rerenderButton);
// 创建查看大图按钮
const fullscreenButton = createButton('查看大图', () => {
if (chartDiv.innerHTML) {
showGraph(chartDiv.innerHTML);
}
});
buttonContainer.appendChild(fullscreenButton);
chartContainer.appendChild(buttonContainer);
// 插入到代码块后面
codeElement.parentNode.insertBefore(chartContainer, codeElement.nextSibling);
// 渲染图表
await renderMermaidCode(codeElement, chartDiv, index);
// 默认隐藏代码
codeElement.style.display = 'none';
toggleCodeButton.textContent = '显示代码';
// 标记为已处理
codeElement.__mermaid_processed = true;
}
// 处理页面上所有Mermaid代码块
async function processAllMermaidBlocks() {
const codeElements = document.querySelectorAll(CODE_BLOCK_SELECTOR);
if (codeElements.length === 0) {
// 没有找到代码块,不显示通知
return;
}
let newElementsCount = 0;
for (let i = 0; i < codeElements.length; i++) {
if (!codeElements[i].__mermaid_processed) {
newElementsCount++;
await processMermaidBlock(codeElements[i], i);
}
}
if (newElementsCount > 0) {
showNotification(`处理了${newElementsCount}个新的Mermaid代码块`);
}
}
// 定时扫描页面上的Mermaid代码块
function startAutoScan() {
// 初始扫描
processAllMermaidBlocks();
// 设置定时器每2秒扫描一次
setInterval(processAllMermaidBlocks, AUTO_SCAN_INTERVAL);
}
// 主流程
function init() {
// 等待页面加载完成
window.addEventListener('load', function() {
// 开始自动扫描
setTimeout(startAutoScan, 1000);
});
}
// 开始执行
init();
})();
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment