feat: enhance Mermaid diagram interaction with improved activation, hint display, and click-to-zoom functionality
This commit is contained in:
@@ -255,11 +255,14 @@
|
|||||||
.mermaid-canvas {
|
.mermaid-canvas {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
height: 520px;
|
height: 520px;
|
||||||
cursor: grab;
|
cursor: pointer;
|
||||||
position: relative;
|
position: relative;
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
}
|
}
|
||||||
.mermaid-canvas:active { cursor: grabbing; }
|
.mermaid-canvas.mermaid-active {
|
||||||
|
cursor: grab;
|
||||||
|
}
|
||||||
|
.mermaid-canvas.mermaid-active:active { cursor: grabbing; }
|
||||||
.mermaid-canvas .mermaid {
|
.mermaid-canvas .mermaid {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
height: 100%;
|
height: 100%;
|
||||||
@@ -267,6 +270,42 @@
|
|||||||
.mermaid-canvas svg {
|
.mermaid-canvas svg {
|
||||||
display: block;
|
display: block;
|
||||||
}
|
}
|
||||||
|
.mermaid-container.mermaid-active {
|
||||||
|
box-shadow: 0 0 0 2px var(--accent-color, #4f46e5);
|
||||||
|
}
|
||||||
|
.mermaid-canvas-hint {
|
||||||
|
position: absolute;
|
||||||
|
inset: 0;
|
||||||
|
z-index: 2;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
pointer-events: none;
|
||||||
|
background: rgba(248, 250, 252, 0.55);
|
||||||
|
backdrop-filter: blur(2px);
|
||||||
|
transition: opacity 0.2s ease;
|
||||||
|
}
|
||||||
|
.dark .mermaid-canvas-hint {
|
||||||
|
background: rgba(15, 23, 42, 0.55);
|
||||||
|
}
|
||||||
|
.mermaid-canvas-hint span {
|
||||||
|
font-size: 0.75rem;
|
||||||
|
font-weight: 600;
|
||||||
|
color: #64748b;
|
||||||
|
background: rgba(255, 255, 255, 0.9);
|
||||||
|
border: 1px solid rgba(0, 0, 0, 0.08);
|
||||||
|
padding: 6px 14px;
|
||||||
|
border-radius: 999px;
|
||||||
|
}
|
||||||
|
.dark .mermaid-canvas-hint span {
|
||||||
|
color: #94a3b8;
|
||||||
|
background: rgba(30, 41, 59, 0.9);
|
||||||
|
border-color: rgba(255, 255, 255, 0.08);
|
||||||
|
}
|
||||||
|
.mermaid-container.mermaid-active .mermaid-canvas-hint {
|
||||||
|
opacity: 0;
|
||||||
|
visibility: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
/* Fullscreen overlay */
|
/* Fullscreen overlay */
|
||||||
.mermaid-fullscreen-overlay {
|
.mermaid-fullscreen-overlay {
|
||||||
@@ -944,6 +983,59 @@
|
|||||||
|
|
||||||
// Mermaid zoom state store
|
// Mermaid zoom state store
|
||||||
const mermaidZoomInstances = {};
|
const mermaidZoomInstances = {};
|
||||||
|
let mermaidActiveIndex = null;
|
||||||
|
|
||||||
|
function setMermaidActive(index) {
|
||||||
|
if (mermaidActiveIndex !== null && mermaidActiveIndex !== index) {
|
||||||
|
deactivateMermaid(mermaidActiveIndex);
|
||||||
|
}
|
||||||
|
mermaidActiveIndex = index;
|
||||||
|
|
||||||
|
const wrapper = document.getElementById('mermaid-wrapper-' + index);
|
||||||
|
const canvas = document.getElementById('mermaid-canvas-' + index);
|
||||||
|
const pz = mermaidZoomInstances[index];
|
||||||
|
if (!wrapper || !canvas || !pz) return;
|
||||||
|
|
||||||
|
wrapper.classList.add('mermaid-active');
|
||||||
|
canvas.classList.add('mermaid-active');
|
||||||
|
pz.enablePan();
|
||||||
|
}
|
||||||
|
|
||||||
|
function deactivateMermaid(index) {
|
||||||
|
const wrapper = document.getElementById('mermaid-wrapper-' + index);
|
||||||
|
const canvas = document.getElementById('mermaid-canvas-' + index);
|
||||||
|
const pz = mermaidZoomInstances[index];
|
||||||
|
if (wrapper) wrapper.classList.remove('mermaid-active');
|
||||||
|
if (canvas) canvas.classList.remove('mermaid-active');
|
||||||
|
if (pz) pz.disablePan();
|
||||||
|
if (mermaidActiveIndex === index) mermaidActiveIndex = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
function deactivateAllMermaid() {
|
||||||
|
if (mermaidActiveIndex !== null) {
|
||||||
|
deactivateMermaid(mermaidActiveIndex);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function setupMermaidActivation(index) {
|
||||||
|
const canvas = document.getElementById('mermaid-canvas-' + index);
|
||||||
|
if (!canvas || canvas.dataset.activationBound) return;
|
||||||
|
canvas.dataset.activationBound = '1';
|
||||||
|
|
||||||
|
canvas.addEventListener('click', function() {
|
||||||
|
setMermaidActive(index);
|
||||||
|
});
|
||||||
|
|
||||||
|
canvas.addEventListener('wheel', function(e) {
|
||||||
|
if (!canvas.classList.contains('mermaid-active')) return;
|
||||||
|
e.preventDefault();
|
||||||
|
const pz = mermaidZoomInstances[index];
|
||||||
|
if (!pz) return;
|
||||||
|
if (e.deltaY < 0) pz.zoomIn();
|
||||||
|
else pz.zoomOut();
|
||||||
|
updatePct(index, pz.getZoom());
|
||||||
|
}, { passive: false });
|
||||||
|
}
|
||||||
|
|
||||||
// Scan code blocks for mermaid and convert them
|
// Scan code blocks for mermaid and convert them
|
||||||
const codeElements = contentDiv.querySelectorAll('pre code.language-mermaid');
|
const codeElements = contentDiv.querySelectorAll('pre code.language-mermaid');
|
||||||
@@ -981,6 +1073,10 @@
|
|||||||
const canvas = document.createElement('div');
|
const canvas = document.createElement('div');
|
||||||
canvas.className = 'mermaid-canvas';
|
canvas.className = 'mermaid-canvas';
|
||||||
canvas.id = 'mermaid-canvas-' + index;
|
canvas.id = 'mermaid-canvas-' + index;
|
||||||
|
|
||||||
|
const hint = document.createElement('div');
|
||||||
|
hint.className = 'mermaid-canvas-hint';
|
||||||
|
hint.innerHTML = '<span>Zoom ve kaydırma için tıklayın</span>';
|
||||||
|
|
||||||
const graphDiv = document.createElement('div');
|
const graphDiv = document.createElement('div');
|
||||||
graphDiv.className = 'mermaid w-full';
|
graphDiv.className = 'mermaid w-full';
|
||||||
@@ -988,6 +1084,7 @@
|
|||||||
graphDiv.textContent = rawMermaid;
|
graphDiv.textContent = rawMermaid;
|
||||||
|
|
||||||
canvas.appendChild(graphDiv);
|
canvas.appendChild(graphDiv);
|
||||||
|
canvas.appendChild(hint);
|
||||||
wrapper.appendChild(toolbar);
|
wrapper.appendChild(toolbar);
|
||||||
wrapper.appendChild(canvas);
|
wrapper.appendChild(canvas);
|
||||||
preContainer.parentNode.replaceChild(wrapper, preContainer);
|
preContainer.parentNode.replaceChild(wrapper, preContainer);
|
||||||
@@ -1021,6 +1118,12 @@
|
|||||||
document.body.appendChild(fsOverlay);
|
document.body.appendChild(fsOverlay);
|
||||||
fsOverlay.addEventListener('click', function(e) { if (e.target === fsOverlay) closeMermaidFullscreen(); });
|
fsOverlay.addEventListener('click', function(e) { if (e.target === fsOverlay) closeMermaidFullscreen(); });
|
||||||
|
|
||||||
|
document.addEventListener('click', function(e) {
|
||||||
|
if (!e.target.closest('.mermaid-container')) {
|
||||||
|
deactivateAllMermaid();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
// Run mermaid parser
|
// Run mermaid parser
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
mermaid.run().then(() => {
|
mermaid.run().then(() => {
|
||||||
@@ -1071,18 +1174,21 @@
|
|||||||
try {
|
try {
|
||||||
const panZoom = svgPanZoom('#' + svg.id, {
|
const panZoom = svgPanZoom('#' + svg.id, {
|
||||||
zoomEnabled: true,
|
zoomEnabled: true,
|
||||||
|
panEnabled: false,
|
||||||
controlIconsEnabled: false,
|
controlIconsEnabled: false,
|
||||||
fit: true,
|
fit: true,
|
||||||
center: true,
|
center: true,
|
||||||
minZoom: 0.3,
|
minZoom: 0.3,
|
||||||
maxZoom: 8,
|
maxZoom: 8,
|
||||||
zoomScaleSensitivity: 0.3,
|
zoomScaleSensitivity: 0.3,
|
||||||
|
mouseWheelZoomEnabled: false,
|
||||||
onZoom: (zoom) => {
|
onZoom: (zoom) => {
|
||||||
const pctEl = document.getElementById('mermaid-pct-' + index);
|
const pctEl = document.getElementById('mermaid-pct-' + index);
|
||||||
if (pctEl) pctEl.textContent = Math.round(zoom * 100) + '%';
|
if (pctEl) pctEl.textContent = Math.round(zoom * 100) + '%';
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
mermaidZoomInstances[index] = panZoom;
|
mermaidZoomInstances[index] = panZoom;
|
||||||
|
setupMermaidActivation(index);
|
||||||
} catch(e) {
|
} catch(e) {
|
||||||
console.warn('svg-pan-zoom init failed for mermaid-' + index, e);
|
console.warn('svg-pan-zoom init failed for mermaid-' + index, e);
|
||||||
}
|
}
|
||||||
@@ -1090,14 +1196,17 @@
|
|||||||
|
|
||||||
// Zoom controls
|
// Zoom controls
|
||||||
function mermaidZoomIn(index) {
|
function mermaidZoomIn(index) {
|
||||||
|
setMermaidActive(index);
|
||||||
const pz = mermaidZoomInstances[index];
|
const pz = mermaidZoomInstances[index];
|
||||||
if (pz) { pz.zoomIn(); updatePct(index, pz.getZoom()); }
|
if (pz) { pz.zoomIn(); updatePct(index, pz.getZoom()); }
|
||||||
}
|
}
|
||||||
function mermaidZoomOut(index) {
|
function mermaidZoomOut(index) {
|
||||||
|
setMermaidActive(index);
|
||||||
const pz = mermaidZoomInstances[index];
|
const pz = mermaidZoomInstances[index];
|
||||||
if (pz) { pz.zoomOut(); updatePct(index, pz.getZoom()); }
|
if (pz) { pz.zoomOut(); updatePct(index, pz.getZoom()); }
|
||||||
}
|
}
|
||||||
function mermaidZoomReset(index) {
|
function mermaidZoomReset(index) {
|
||||||
|
setMermaidActive(index);
|
||||||
const pz = mermaidZoomInstances[index];
|
const pz = mermaidZoomInstances[index];
|
||||||
if (pz) { pz.resetZoom(); pz.center(); updatePct(index, pz.getZoom()); }
|
if (pz) { pz.resetZoom(); pz.center(); updatePct(index, pz.getZoom()); }
|
||||||
}
|
}
|
||||||
@@ -1185,6 +1294,7 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
async function mermaidFullscreen(index) {
|
async function mermaidFullscreen(index) {
|
||||||
|
deactivateAllMermaid();
|
||||||
const wrapper = document.getElementById('mermaid-wrapper-' + index);
|
const wrapper = document.getElementById('mermaid-wrapper-' + index);
|
||||||
if (!wrapper) return;
|
if (!wrapper) return;
|
||||||
const rawMermaid = wrapper.dataset.mermaidSource;
|
const rawMermaid = wrapper.dataset.mermaidSource;
|
||||||
|
|||||||
Reference in New Issue
Block a user