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 styling */
|
||||||
.mermaid-diagram-wrapper {
|
.mermaid-diagram-wrapper {
|
||||||
|
position: relative;
|
||||||
display: flex;
|
display: flex;
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
|
overflow: hidden;
|
||||||
|
cursor: grab;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.mermaid-diagram-wrapper:active {
|
||||||
|
cursor: grabbing;
|
||||||
|
}
|
||||||
|
|
||||||
.mermaid-diagram-wrapper svg {
|
.mermaid-diagram-wrapper svg {
|
||||||
max-width: 100%;
|
max-width: none;
|
||||||
height: auto;
|
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 */
|
/* Loading Overlay */
|
||||||
#auth-loading {
|
#auth-loading {
|
||||||
@@ -494,6 +537,9 @@
|
|||||||
|
|
||||||
let panzoomInstance = null;
|
let panzoomInstance = null;
|
||||||
let currentScale = 1;
|
let currentScale = 1;
|
||||||
|
|
||||||
|
// Track mermaid diagram panzoom instances
|
||||||
|
const mermaidPanzoomInstances = new Map();
|
||||||
|
|
||||||
// Initialize Mermaid
|
// Initialize Mermaid
|
||||||
mermaid.initialize({
|
mermaid.initialize({
|
||||||
@@ -706,6 +752,63 @@
|
|||||||
activeLink.classList.remove('text-gray-700');
|
activeLink.classList.remove('text-gray-700');
|
||||||
activeLink.classList.add('bg-primary-50', 'border', 'border-primary-200', 'text-primary-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') {
|
async function showView(viewName, navLink, filePath, title, type = 'svg') {
|
||||||
setActiveNav(navLink);
|
setActiveNav(navLink);
|
||||||
@@ -713,6 +816,11 @@
|
|||||||
panzoomInstance.destroy();
|
panzoomInstance.destroy();
|
||||||
panzoomInstance = null;
|
panzoomInstance = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Clean up mermaid panzoom instances when switching views
|
||||||
|
mermaidPanzoomInstances.forEach(instance => instance.destroy());
|
||||||
|
mermaidPanzoomInstances.clear();
|
||||||
|
|
||||||
diagramContainer.innerHTML = '';
|
diagramContainer.innerHTML = '';
|
||||||
documentContainer.innerHTML = '';
|
documentContainer.innerHTML = '';
|
||||||
// Reset iframe
|
// Reset iframe
|
||||||
@@ -841,10 +949,18 @@
|
|||||||
const pre = block.parentElement;
|
const pre = block.parentElement;
|
||||||
|
|
||||||
try {
|
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');
|
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;
|
wrapper.innerHTML = svg;
|
||||||
|
|
||||||
|
const svgElement = wrapper.querySelector('svg');
|
||||||
|
if (svgElement) {
|
||||||
|
// Add zoom controls for this mermaid diagram
|
||||||
|
createMermaidZoomControls(wrapper, svgElement, diagramId);
|
||||||
|
}
|
||||||
|
|
||||||
pre.replaceWith(wrapper);
|
pre.replaceWith(wrapper);
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
console.error('Mermaid rendering error:', err);
|
console.error('Mermaid rendering error:', err);
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
.PHONY: launchpad-dev deploy-launchpad-hosting
|
.PHONY: launchpad-dev deploy-launchpad-hosting
|
||||||
|
|
||||||
launchpad-dev: sync-prototypes
|
launchpad-dev:
|
||||||
@echo "--> Starting local Launchpad server using Firebase Hosting emulator..."
|
@echo "--> Starting local Launchpad server using Firebase Hosting emulator..."
|
||||||
@echo " - Generating secure email hashes..."
|
@echo " - Generating secure email hashes..."
|
||||||
@node scripts/generate-allowed-hashes.js
|
@node scripts/generate-allowed-hashes.js
|
||||||
|
|||||||
Reference in New Issue
Block a user