Last active
March 3, 2025 03:38
-
-
Save engalar/415b1399aa4bce71626dba161d795d38 to your computer and use it in GitHub Desktop.
tampermonkey UserScript for mermaid
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// ==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