feat: add zoom controls for Mermaid diagrams and improve diagram interaction
This commit is contained in:
@@ -149,14 +149,57 @@
|
||||
|
||||
/* Mermaid diagram styling */
|
||||
.mermaid-diagram-wrapper {
|
||||
position: relative;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
overflow: hidden;
|
||||
cursor: grab;
|
||||
}
|
||||
|
||||
.mermaid-diagram-wrapper:active {
|
||||
cursor: grabbing;
|
||||
}
|
||||
|
||||
.mermaid-diagram-wrapper svg {
|
||||
max-width: 100%;
|
||||
max-width: none;
|
||||
height: auto;
|
||||
}
|
||||
|
||||
.mermaid-zoom-controls {
|
||||
position: absolute;
|
||||
top: 0.5rem;
|
||||
right: 0.5rem;
|
||||
display: flex;
|
||||
gap: 0.25rem;
|
||||
background: white;
|
||||
border-radius: 0.5rem;
|
||||
padding: 0.25rem;
|
||||
box-shadow: 0 2px 4px rgba(0,0,0,0.1);
|
||||
z-index: 10;
|
||||
}
|
||||
|
||||
.mermaid-zoom-btn {
|
||||
padding: 0.375rem;
|
||||
background: white;
|
||||
border: 1px solid #e5e7eb;
|
||||
border-radius: 0.375rem;
|
||||
cursor: pointer;
|
||||
transition: background-color 0.2s;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.mermaid-zoom-btn:hover {
|
||||
background-color: #f3f4f6;
|
||||
}
|
||||
|
||||
.mermaid-zoom-btn svg {
|
||||
width: 1rem;
|
||||
height: 1rem;
|
||||
color: #4b5563;
|
||||
}
|
||||
|
||||
/* Loading Overlay */
|
||||
#auth-loading {
|
||||
@@ -494,6 +537,9 @@
|
||||
|
||||
let panzoomInstance = null;
|
||||
let currentScale = 1;
|
||||
|
||||
// Track mermaid diagram panzoom instances
|
||||
const mermaidPanzoomInstances = new Map();
|
||||
|
||||
// Initialize Mermaid
|
||||
mermaid.initialize({
|
||||
@@ -706,6 +752,63 @@
|
||||
activeLink.classList.remove('text-gray-700');
|
||||
activeLink.classList.add('bg-primary-50', 'border', 'border-primary-200', 'text-primary-700');
|
||||
}
|
||||
|
||||
// Create zoom controls for mermaid diagrams
|
||||
function createMermaidZoomControls(wrapper, svgElement, diagramId) {
|
||||
const controls = document.createElement('div');
|
||||
controls.className = 'mermaid-zoom-controls';
|
||||
controls.innerHTML = `
|
||||
<button class="mermaid-zoom-btn" data-action="zoom-in" title="Zoom In">
|
||||
<svg fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M21 21l-6-6m2-5a7 7 0 11-14 0 7 7 0 0114 0zM10 7v6m3-3H7"></path>
|
||||
</svg>
|
||||
</button>
|
||||
<button class="mermaid-zoom-btn" data-action="zoom-out" title="Zoom Out">
|
||||
<svg fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M21 21l-6-6m2-5a7 7 0 11-14 0 7 7 0 0114 0zM13 10H7"></path>
|
||||
</svg>
|
||||
</button>
|
||||
<button class="mermaid-zoom-btn" data-action="reset" title="Reset View">
|
||||
<svg fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M4 4v5h.582m15.356 2A8.001 8.001 0 004.582 9m0 0H9m11 11v-5h-.581m0 0a8.003 8.003 0 01-15.357-2m15.357 2H15"></path>
|
||||
</svg>
|
||||
</button>
|
||||
`;
|
||||
|
||||
wrapper.appendChild(controls);
|
||||
|
||||
// Wait for next frame to ensure DOM is fully updated before initializing Panzoom
|
||||
requestAnimationFrame(() => {
|
||||
// Initialize panzoom for this mermaid diagram
|
||||
const panzoom = Panzoom(svgElement, {
|
||||
canvas: true,
|
||||
maxScale: 10,
|
||||
minScale: 0.3,
|
||||
startScale: 1
|
||||
});
|
||||
|
||||
mermaidPanzoomInstances.set(diagramId, panzoom);
|
||||
|
||||
// Add event listeners
|
||||
controls.querySelector('[data-action="zoom-in"]').addEventListener('click', (e) => {
|
||||
e.stopPropagation();
|
||||
panzoom.zoomIn();
|
||||
});
|
||||
|
||||
controls.querySelector('[data-action="zoom-out"]').addEventListener('click', (e) => {
|
||||
e.stopPropagation();
|
||||
panzoom.zoomOut();
|
||||
});
|
||||
|
||||
controls.querySelector('[data-action="reset"]').addEventListener('click', (e) => {
|
||||
e.stopPropagation();
|
||||
panzoom.reset();
|
||||
});
|
||||
|
||||
// Add wheel zoom
|
||||
wrapper.addEventListener('wheel', panzoom.zoomWithWheel);
|
||||
});
|
||||
}
|
||||
|
||||
async function showView(viewName, navLink, filePath, title, type = 'svg') {
|
||||
setActiveNav(navLink);
|
||||
@@ -713,6 +816,11 @@
|
||||
panzoomInstance.destroy();
|
||||
panzoomInstance = null;
|
||||
}
|
||||
|
||||
// Clean up mermaid panzoom instances when switching views
|
||||
mermaidPanzoomInstances.forEach(instance => instance.destroy());
|
||||
mermaidPanzoomInstances.clear();
|
||||
|
||||
diagramContainer.innerHTML = '';
|
||||
documentContainer.innerHTML = '';
|
||||
// Reset iframe
|
||||
@@ -841,10 +949,18 @@
|
||||
const pre = block.parentElement;
|
||||
|
||||
try {
|
||||
const { svg } = await mermaid.render(`mermaid-doc-${Date.now()}-${i}`, mermaidCode);
|
||||
const diagramId = `mermaid-doc-${Date.now()}-${i}`;
|
||||
const { svg } = await mermaid.render(diagramId, mermaidCode);
|
||||
const wrapper = document.createElement('div');
|
||||
wrapper.className = 'mermaid-diagram-wrapper bg-white p-4 rounded-lg border border-gray-200 my-4 overflow-x-auto';
|
||||
wrapper.className = 'mermaid-diagram-wrapper bg-white p-4 rounded-lg border border-gray-200 my-4';
|
||||
wrapper.innerHTML = svg;
|
||||
|
||||
const svgElement = wrapper.querySelector('svg');
|
||||
if (svgElement) {
|
||||
// Add zoom controls for this mermaid diagram
|
||||
createMermaidZoomControls(wrapper, svgElement, diagramId);
|
||||
}
|
||||
|
||||
pre.replaceWith(wrapper);
|
||||
} catch (err) {
|
||||
console.error('Mermaid rendering error:', err);
|
||||
|
||||
Reference in New Issue
Block a user