feat: Mermaid header bar, Code/Preview toggle, Copy SVG, Download PNG, fullscreen header
This commit is contained in:
+292
-79
@@ -83,8 +83,8 @@ export async function renderMermaidBlocks(container) {
|
||||
|
||||
for (var i = 0; i < blocks.length; i++) {
|
||||
var codeBlock = blocks[i];
|
||||
var code = codeBlock.textContent || codeBlock.innerText || '';
|
||||
if (!code.trim()) continue;
|
||||
var originalCode = codeBlock.textContent || codeBlock.innerText || '';
|
||||
if (!originalCode.trim()) continue;
|
||||
|
||||
var wrapper = codeBlock.closest('pre') || codeBlock.parentElement;
|
||||
if (!wrapper) continue;
|
||||
@@ -94,30 +94,53 @@ export async function renderMermaidBlocks(container) {
|
||||
|
||||
try {
|
||||
// Preprocess Obsidian syntax before Mermaid parsing (#24)
|
||||
code = preprocessObsidian(code);
|
||||
var code = preprocessObsidian(originalCode);
|
||||
await mermaid.parse(code);
|
||||
var id = 'mermaid-' + (++_renderCounter) + '-' + Date.now();
|
||||
var result = await mermaid.render(id, code);
|
||||
|
||||
var container_1 = document.createElement('div');
|
||||
container_1.className = 'mermaid-container';
|
||||
container_1.innerHTML = '<div class="mermaid-rendered">' + result.svg + '</div>';
|
||||
// Extract diagram type from first non-comment, non-empty line
|
||||
var diagramType = extractDiagramType(code);
|
||||
|
||||
// Add zoom/pan controls (#27)
|
||||
var controls = document.createElement('div');
|
||||
controls.className = 'mermaid-controls';
|
||||
controls.innerHTML =
|
||||
'<button class="mermaid-btn mermaid-zoom-in" title="Zoom +"><i data-lucide="zoom-in" style="width:14px;height:14px"></i></button>' +
|
||||
'<button class="mermaid-btn mermaid-zoom-out" title="Zoom -"><i data-lucide="zoom-out" style="width:14px;height:14px"></i></button>' +
|
||||
'<button class="mermaid-btn mermaid-reset" title="Reset"><i data-lucide="maximize" style="width:14px;height:14px"></i></button>' +
|
||||
'<button class="mermaid-btn mermaid-fullscreen" title="Plein ecran"><i data-lucide="expand" style="width:14px;height:14px"></i></button>';
|
||||
container_1.appendChild(controls);
|
||||
// Build container with header + body
|
||||
var containerDiv = document.createElement('div');
|
||||
containerDiv.className = 'mermaid-container';
|
||||
|
||||
wrapper.parentNode.replaceChild(container_1, wrapper);
|
||||
setupZoomPan(container_1);
|
||||
// Header bar
|
||||
var header = document.createElement('div');
|
||||
header.className = 'mermaid-header';
|
||||
header.innerHTML =
|
||||
'<span class="mermaid-diagram-type">' + escapeHtml(diagramType) + '</span>' +
|
||||
'<div class="mermaid-header-actions">' +
|
||||
'<button class="mermaid-btn mermaid-zoom-in" title="Zoom +"><i data-lucide="zoom-in" style="width:14px;height:14px"></i></button>' +
|
||||
'<button class="mermaid-btn mermaid-zoom-out" title="Zoom -"><i data-lucide="zoom-out" style="width:14px;height:14px"></i></button>' +
|
||||
'<button class="mermaid-btn mermaid-fullscreen" title="Plein ecran"><i data-lucide="expand" style="width:14px;height:14px"></i></button>' +
|
||||
'<button class="mermaid-btn mermaid-copy" title="Copier SVG"><i data-lucide="copy" style="width:14px;height:14px"></i></button>' +
|
||||
'<button class="mermaid-btn mermaid-download" title="Telecharger PNG"><i data-lucide="download" style="width:14px;height:14px"></i></button>' +
|
||||
'<div class="mermaid-toggle">' +
|
||||
'<button class="mermaid-toggle-btn active" data-mode="preview">Preview</button>' +
|
||||
'<button class="mermaid-toggle-btn" data-mode="code">Code</button>' +
|
||||
'</div>' +
|
||||
'</div>';
|
||||
|
||||
// Body
|
||||
var body = document.createElement('div');
|
||||
body.className = 'mermaid-body';
|
||||
body.innerHTML =
|
||||
'<div class="mermaid-rendered">' + result.svg + '</div>' +
|
||||
'<div class="mermaid-source" style="display:none"><pre><code class="language-mermaid">' + escapeHtml(originalCode) + '</code></pre></div>';
|
||||
|
||||
containerDiv.appendChild(header);
|
||||
containerDiv.appendChild(body);
|
||||
|
||||
wrapper.parentNode.replaceChild(containerDiv, wrapper);
|
||||
|
||||
// Wire up header buttons
|
||||
wireHeaderButtons(containerDiv, originalCode);
|
||||
setupZoomPan(containerDiv);
|
||||
setupCodePreviewToggle(containerDiv);
|
||||
safeCreateIcons();
|
||||
} catch (err) {
|
||||
// Render error block
|
||||
var errorDiv = document.createElement('div');
|
||||
errorDiv.className = 'mermaid-error';
|
||||
errorDiv.innerHTML = '<strong>Erreur Mermaid</strong><br>' + escapeHtml(err.message || String(err));
|
||||
@@ -126,6 +149,86 @@ export async function renderMermaidBlocks(container) {
|
||||
}
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Header button wiring
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
function wireHeaderButtons(container, originalCode) {
|
||||
// Copy SVG
|
||||
var copyBtn = container.querySelector('.mermaid-copy');
|
||||
if (copyBtn) {
|
||||
copyBtn.addEventListener('click', function() {
|
||||
copySvgToClipboard(container);
|
||||
});
|
||||
}
|
||||
|
||||
// Download PNG
|
||||
var downloadBtn = container.querySelector('.mermaid-download');
|
||||
if (downloadBtn) {
|
||||
downloadBtn.addEventListener('click', function() {
|
||||
exportMermaidPNG(container);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Code / Preview toggle
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
function setupCodePreviewToggle(container) {
|
||||
var toggleBtns = container.querySelectorAll('.mermaid-toggle-btn');
|
||||
var rendered = container.querySelector('.mermaid-rendered');
|
||||
var source = container.querySelector('.mermaid-source');
|
||||
var zoomBtns = container.querySelectorAll('.mermaid-zoom-in, .mermaid-zoom-out');
|
||||
var fullscreenBtn = container.querySelector('.mermaid-fullscreen');
|
||||
|
||||
for (var i = 0; i < toggleBtns.length; i++) {
|
||||
toggleBtns[i].addEventListener('click', function() {
|
||||
var mode = this.getAttribute('data-mode');
|
||||
|
||||
// Update active state
|
||||
for (var j = 0; j < toggleBtns.length; j++) {
|
||||
toggleBtns[j].classList.remove('active');
|
||||
}
|
||||
this.classList.add('active');
|
||||
|
||||
if (mode === 'preview') {
|
||||
rendered.style.display = '';
|
||||
source.style.display = 'none';
|
||||
// Show zoom/fullscreen buttons in preview mode
|
||||
for (var k = 0; k < zoomBtns.length; k++) zoomBtns[k].style.display = '';
|
||||
if (fullscreenBtn) fullscreenBtn.style.display = '';
|
||||
} else {
|
||||
rendered.style.display = 'none';
|
||||
source.style.display = '';
|
||||
// Hide zoom/fullscreen in code mode
|
||||
for (var k = 0; k < zoomBtns.length; k++) zoomBtns[k].style.display = 'none';
|
||||
if (fullscreenBtn) fullscreenBtn.style.display = 'none';
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Diagram type extraction
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
function extractDiagramType(code) {
|
||||
var lines = code.trim().split('\n');
|
||||
for (var i = 0; i < lines.length; i++) {
|
||||
var line = lines[i].trim();
|
||||
// Skip comments and empty lines
|
||||
if (!line || line.indexOf('%%') === 0) continue;
|
||||
// Return the first meaningful word(s)
|
||||
var words = line.split(/\s+/);
|
||||
if (words.length >= 2) {
|
||||
return words[0] + ' ' + words[1];
|
||||
}
|
||||
return words[0] || 'mermaid';
|
||||
}
|
||||
return 'mermaid';
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Zoom & Pan (#27)
|
||||
// ---------------------------------------------------------------------------
|
||||
@@ -174,31 +277,44 @@ function setupZoomPan(container) {
|
||||
update();
|
||||
}, { passive: false });
|
||||
|
||||
container.querySelector('.mermaid-zoom-in').addEventListener('click', function() {
|
||||
scale = Math.min(5, scale * 1.3); update();
|
||||
});
|
||||
container.querySelector('.mermaid-zoom-out').addEventListener('click', function() {
|
||||
scale = Math.max(0.2, scale * 0.7); update();
|
||||
});
|
||||
container.querySelector('.mermaid-reset').addEventListener('click', function() {
|
||||
scale = 1; panX = 0; panY = 0; update();
|
||||
});
|
||||
var zoomIn = container.querySelector('.mermaid-zoom-in');
|
||||
var zoomOut = container.querySelector('.mermaid-zoom-out');
|
||||
if (zoomIn) zoomIn.addEventListener('click', function() { scale = Math.min(5, scale * 1.3); update(); });
|
||||
if (zoomOut) zoomOut.addEventListener('click', function() { scale = Math.max(0.2, scale * 0.7); update(); });
|
||||
|
||||
// Fullscreen (#28)
|
||||
container.querySelector('.mermaid-fullscreen').addEventListener('click', function() {
|
||||
openFullscreen(svgWrapper);
|
||||
});
|
||||
var fsBtn = container.querySelector('.mermaid-fullscreen');
|
||||
if (fsBtn) {
|
||||
fsBtn.addEventListener('click', function() {
|
||||
openFullscreen(container);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Fullscreen mode (#28)
|
||||
// Fullscreen mode (#28) — with header bar + full-size diagram
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
function openFullscreen(svgWrapper) {
|
||||
function openFullscreen(container) {
|
||||
var svgWrapper = container.querySelector('.mermaid-rendered');
|
||||
var diagramType = container.querySelector('.mermaid-diagram-type');
|
||||
var typeLabel = diagramType ? diagramType.textContent : 'mermaid';
|
||||
|
||||
var overlay = document.createElement('div');
|
||||
overlay.className = 'mermaid-fullscreen-overlay';
|
||||
|
||||
// Fullscreen header bar
|
||||
overlay.innerHTML =
|
||||
'<button class="mermaid-fullscreen-close" title="Fermer (Echap)"><i data-lucide="x" style="width:18px;height:18px"></i></button>' +
|
||||
'<div class="mermaid-fullscreen-header">' +
|
||||
'<span class="mermaid-diagram-type">' + escapeHtml(typeLabel) + '</span>' +
|
||||
'<div class="mermaid-header-actions">' +
|
||||
'<button class="mermaid-btn mermaid-fs-zoom-in" title="Zoom +"><i data-lucide="zoom-in" style="width:14px;height:14px"></i></button>' +
|
||||
'<button class="mermaid-btn mermaid-fs-zoom-out" title="Zoom -"><i data-lucide="zoom-out" style="width:14px;height:14px"></i></button>' +
|
||||
'<button class="mermaid-btn mermaid-fs-copy" title="Copier SVG"><i data-lucide="copy" style="width:14px;height:14px"></i></button>' +
|
||||
'<button class="mermaid-btn mermaid-fs-download" title="Telecharger PNG"><i data-lucide="download" style="width:14px;height:14px"></i></button>' +
|
||||
'<button class="mermaid-btn mermaid-fs-close" title="Fermer (Echap)"><i data-lucide="x" style="width:14px;height:14px"></i></button>' +
|
||||
'</div>' +
|
||||
'</div>' +
|
||||
'<div class="mermaid-fullscreen-content"></div>';
|
||||
|
||||
var content = overlay.querySelector('.mermaid-fullscreen-content');
|
||||
@@ -209,6 +325,64 @@ function openFullscreen(svgWrapper) {
|
||||
}
|
||||
|
||||
document.body.appendChild(overlay);
|
||||
|
||||
// Fullscreen zoom
|
||||
var fsScale = 1, fsPanX = 0, fsPanY = 0, fsDragging = false, fsStartX, fsStartY;
|
||||
if (svg) {
|
||||
svg.style.transformOrigin = '0 0';
|
||||
function fsUpdate() {
|
||||
svg.style.transform = 'translate(' + fsPanX + 'px, ' + fsPanY + 'px) scale(' + fsScale + ')';
|
||||
}
|
||||
|
||||
svg.addEventListener('mousedown', function(e) {
|
||||
fsDragging = true;
|
||||
fsStartX = e.clientX - fsPanX;
|
||||
fsStartY = e.clientY - fsPanY;
|
||||
svg.style.cursor = 'grabbing';
|
||||
e.preventDefault();
|
||||
});
|
||||
|
||||
document.addEventListener('mousemove', function(e) {
|
||||
if (!fsDragging) return;
|
||||
fsPanX = e.clientX - fsStartX;
|
||||
fsPanY = e.clientY - fsStartY;
|
||||
fsUpdate();
|
||||
});
|
||||
|
||||
document.addEventListener('mouseup', function() {
|
||||
fsDragging = false;
|
||||
if (svg) svg.style.cursor = 'grab';
|
||||
});
|
||||
|
||||
svg.addEventListener('wheel', function(e) {
|
||||
e.preventDefault();
|
||||
var delta = e.deltaY > 0 ? 0.9 : 1.1;
|
||||
fsScale = Math.max(0.2, Math.min(5, fsScale * delta));
|
||||
fsUpdate();
|
||||
}, { passive: false });
|
||||
|
||||
var fsZoomIn = overlay.querySelector('.mermaid-fs-zoom-in');
|
||||
var fsZoomOut = overlay.querySelector('.mermaid-fs-zoom-out');
|
||||
if (fsZoomIn) fsZoomIn.addEventListener('click', function() { fsScale = Math.min(5, fsScale * 1.3); fsUpdate(); });
|
||||
if (fsZoomOut) fsZoomOut.addEventListener('click', function() { fsScale = Math.max(0.2, fsScale * 0.7); fsUpdate(); });
|
||||
}
|
||||
|
||||
// Copy SVG in fullscreen
|
||||
var fsCopy = overlay.querySelector('.mermaid-fs-copy');
|
||||
if (fsCopy) {
|
||||
fsCopy.addEventListener('click', function() {
|
||||
copySvgFromElement(content);
|
||||
});
|
||||
}
|
||||
|
||||
// Download PNG in fullscreen
|
||||
var fsDownload = overlay.querySelector('.mermaid-fs-download');
|
||||
if (fsDownload) {
|
||||
fsDownload.addEventListener('click', function() {
|
||||
exportMermaidPNGFromElement(svg);
|
||||
});
|
||||
}
|
||||
|
||||
safeCreateIcons();
|
||||
|
||||
function close() {
|
||||
@@ -224,7 +398,89 @@ function openFullscreen(svgWrapper) {
|
||||
overlay.addEventListener('click', function(e) {
|
||||
if (e.target === overlay) close();
|
||||
});
|
||||
overlay.querySelector('.mermaid-fullscreen-close').addEventListener('click', close);
|
||||
overlay.querySelector('.mermaid-fs-close').addEventListener('click', close);
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Copy SVG to clipboard
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
function copySvgToClipboard(container) {
|
||||
copySvgFromElement(container.querySelector('.mermaid-rendered'));
|
||||
}
|
||||
|
||||
function copySvgFromElement(el) {
|
||||
if (!el) return;
|
||||
var svg = el.querySelector('svg');
|
||||
if (!svg) return;
|
||||
var data = new XMLSerializer().serializeToString(svg);
|
||||
if (navigator.clipboard && navigator.clipboard.writeText) {
|
||||
navigator.clipboard.writeText(data).then(function() {
|
||||
/* copied */
|
||||
}).catch(function() {
|
||||
fallbackCopy(data);
|
||||
});
|
||||
} else {
|
||||
fallbackCopy(data);
|
||||
}
|
||||
}
|
||||
|
||||
function fallbackCopy(text) {
|
||||
var textarea = document.createElement('textarea');
|
||||
textarea.value = text;
|
||||
textarea.style.position = 'fixed';
|
||||
textarea.style.opacity = '0';
|
||||
document.body.appendChild(textarea);
|
||||
textarea.select();
|
||||
try { document.execCommand('copy'); } catch (e) {}
|
||||
document.body.removeChild(textarea);
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Export SVG/PNG (#24)
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
export function exportMermaidSVG(container) {
|
||||
var svg = container.querySelector('svg');
|
||||
if (!svg) return;
|
||||
var data = new XMLSerializer().serializeToString(svg);
|
||||
var blob = new Blob([data], { type: 'image/svg+xml' });
|
||||
downloadBlob(blob, 'diagram.svg');
|
||||
}
|
||||
|
||||
export function exportMermaidPNG(container) {
|
||||
var svg = container.querySelector('svg');
|
||||
exportMermaidPNGFromElement(svg);
|
||||
}
|
||||
|
||||
function exportMermaidPNGFromElement(svg) {
|
||||
if (!svg) return;
|
||||
var data = new XMLSerializer().serializeToString(svg);
|
||||
var canvas = document.createElement('canvas');
|
||||
var ctx = canvas.getContext('2d');
|
||||
var img = new Image();
|
||||
var blob = new Blob([data], { type: 'image/svg+xml' });
|
||||
var url = URL.createObjectURL(blob);
|
||||
|
||||
img.onload = function() {
|
||||
canvas.width = img.width * 2;
|
||||
canvas.height = img.height * 2;
|
||||
ctx.scale(2, 2);
|
||||
ctx.drawImage(img, 0, 0);
|
||||
URL.revokeObjectURL(url);
|
||||
canvas.toBlob(function(pngBlob) {
|
||||
downloadBlob(pngBlob, 'diagram.png');
|
||||
}, 'image/png');
|
||||
};
|
||||
img.src = url;
|
||||
}
|
||||
|
||||
function downloadBlob(blob, filename) {
|
||||
var a = document.createElement('a');
|
||||
a.href = URL.createObjectURL(blob);
|
||||
a.download = filename;
|
||||
a.click();
|
||||
URL.revokeObjectURL(a.href);
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
@@ -237,8 +493,8 @@ export function setupFocusMode() {
|
||||
document.addEventListener('click', function(e) {
|
||||
var container = e.target.closest('.mermaid-container');
|
||||
if (!container) return;
|
||||
// Don't trigger focus if clicking controls
|
||||
if (e.target.closest('.mermaid-controls') || e.target.closest('button')) return;
|
||||
// Don't trigger focus if clicking header or controls
|
||||
if (e.target.closest('.mermaid-header') || e.target.closest('button')) return;
|
||||
|
||||
var svgWrapper = container.querySelector('.mermaid-rendered');
|
||||
if (!svgWrapper) return;
|
||||
@@ -285,49 +541,6 @@ function updateFocusPanel(svgWrapper) {
|
||||
}
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Export SVG/PNG (#24)
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
export function exportMermaidSVG(container) {
|
||||
var svg = container.querySelector('svg');
|
||||
if (!svg) return;
|
||||
var data = new XMLSerializer().serializeToString(svg);
|
||||
var blob = new Blob([data], { type: 'image/svg+xml' });
|
||||
downloadBlob(blob, 'diagram.svg');
|
||||
}
|
||||
|
||||
export function exportMermaidPNG(container) {
|
||||
var svg = container.querySelector('svg');
|
||||
if (!svg) return;
|
||||
var data = new XMLSerializer().serializeToString(svg);
|
||||
var canvas = document.createElement('canvas');
|
||||
var ctx = canvas.getContext('2d');
|
||||
var img = new Image();
|
||||
var blob = new Blob([data], { type: 'image/svg+xml' });
|
||||
var url = URL.createObjectURL(blob);
|
||||
|
||||
img.onload = function() {
|
||||
canvas.width = img.width * 2;
|
||||
canvas.height = img.height * 2;
|
||||
ctx.scale(2, 2);
|
||||
ctx.drawImage(img, 0, 0);
|
||||
URL.revokeObjectURL(url);
|
||||
canvas.toBlob(function(pngBlob) {
|
||||
downloadBlob(pngBlob, 'diagram.png');
|
||||
}, 'image/png');
|
||||
};
|
||||
img.src = url;
|
||||
}
|
||||
|
||||
function downloadBlob(blob, filename) {
|
||||
var a = document.createElement('a');
|
||||
a.href = URL.createObjectURL(blob);
|
||||
a.download = filename;
|
||||
a.click();
|
||||
URL.revokeObjectURL(a.href);
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Obsidian compatibility pre-processor (#24)
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
+77
-26
@@ -7621,7 +7621,6 @@ body.popup-mode .content-area {
|
||||
========================================================================== */
|
||||
|
||||
.mermaid-container {
|
||||
position: relative;
|
||||
margin: 12px 0;
|
||||
border: 1px solid var(--border);
|
||||
border-radius: 8px;
|
||||
@@ -7629,6 +7628,55 @@ body.popup-mode .content-area {
|
||||
background: var(--bg-secondary);
|
||||
}
|
||||
|
||||
/* ── Header bar ── */
|
||||
.mermaid-header {
|
||||
display: flex; align-items: center; justify-content: space-between;
|
||||
padding: 6px 10px;
|
||||
background: var(--bg-tertiary, #f0f0f5);
|
||||
border-bottom: 1px solid var(--border);
|
||||
min-height: 34px;
|
||||
}
|
||||
.mermaid-diagram-type {
|
||||
font-family: 'SF Mono', 'Fira Code', 'Consolas', monospace;
|
||||
font-size: 0.75rem; font-weight: 600;
|
||||
color: var(--text-secondary);
|
||||
}
|
||||
.mermaid-header-actions {
|
||||
display: flex; align-items: center; gap: 2px;
|
||||
}
|
||||
|
||||
/* ── Buttons ── */
|
||||
.mermaid-btn {
|
||||
width: 28px; height: 28px;
|
||||
border: 1px solid transparent; border-radius: 4px;
|
||||
background: transparent; color: var(--text-secondary);
|
||||
cursor: pointer; display: flex; align-items: center; justify-content: center;
|
||||
transition: background 0.12s, color 0.12s;
|
||||
}
|
||||
.mermaid-btn:hover { background: var(--bg-primary); color: var(--accent); border-color: var(--border); }
|
||||
|
||||
/* ── Code / Preview toggle ── */
|
||||
.mermaid-toggle {
|
||||
display: flex; margin-left: 8px;
|
||||
border: 1px solid var(--border); border-radius: 5px;
|
||||
overflow: hidden;
|
||||
}
|
||||
.mermaid-toggle-btn {
|
||||
padding: 2px 10px; font-size: 0.7rem; font-weight: 500;
|
||||
border: none; background: transparent;
|
||||
color: var(--text-muted, #999); cursor: pointer;
|
||||
transition: background 0.12s, color 0.12s;
|
||||
}
|
||||
.mermaid-toggle-btn.active {
|
||||
background: var(--bg-primary); color: var(--text-primary);
|
||||
box-shadow: 0 0 0 1px var(--border);
|
||||
}
|
||||
.mermaid-toggle-btn:first-child { border-right: 1px solid var(--border); }
|
||||
|
||||
/* ── Body ── */
|
||||
.mermaid-body {
|
||||
position: relative;
|
||||
}
|
||||
.mermaid-rendered {
|
||||
padding: 16px;
|
||||
overflow: hidden;
|
||||
@@ -7636,25 +7684,17 @@ body.popup-mode .content-area {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.mermaid-rendered svg { max-width: 100%; height: auto; }
|
||||
|
||||
.mermaid-controls {
|
||||
position: absolute;
|
||||
top: 6px; right: 6px;
|
||||
display: flex; gap: 2px;
|
||||
opacity: 0; transition: opacity 0.15s;
|
||||
.mermaid-source { padding: 16px; overflow: auto; }
|
||||
.mermaid-source pre {
|
||||
margin: 0; padding: 12px;
|
||||
background: var(--bg-tertiary, #f5f5f5);
|
||||
border-radius: 4px;
|
||||
font-size: 0.78rem; line-height: 1.5;
|
||||
}
|
||||
.mermaid-container:hover .mermaid-controls { opacity: 1; }
|
||||
|
||||
.mermaid-btn {
|
||||
width: 28px; height: 28px;
|
||||
border: 1px solid var(--border); border-radius: 4px;
|
||||
background: var(--bg-primary); color: var(--text-secondary);
|
||||
cursor: pointer; display: flex; align-items: center; justify-content: center;
|
||||
}
|
||||
.mermaid-btn:hover { color: var(--accent); border-color: var(--accent); }
|
||||
|
||||
/* ── Error ── */
|
||||
.mermaid-error {
|
||||
margin: 12px 0; padding: 12px 16px;
|
||||
border: 1px solid rgba(239,68,68,0.3); border-radius: 6px;
|
||||
@@ -7663,22 +7703,33 @@ body.popup-mode .content-area {
|
||||
}
|
||||
.mermaid-error strong { display: block; margin-bottom: 4px; }
|
||||
|
||||
/* ── Fullscreen ── */
|
||||
.mermaid-fullscreen-overlay {
|
||||
position: fixed; top: 0; left: 0; right: 0; bottom: 0;
|
||||
z-index: 10000; background: rgba(0,0,0,0.85);
|
||||
display: flex; align-items: center; justify-content: center;
|
||||
z-index: 10000; background: rgba(0,0,0,0.92);
|
||||
display: flex; flex-direction: column;
|
||||
}
|
||||
.mermaid-fullscreen-close {
|
||||
position: absolute; top: 16px; right: 16px;
|
||||
width: 40px; height: 40px; border: 1px solid rgba(255,255,255,0.2);
|
||||
border-radius: 8px; background: rgba(0,0,0,0.5); color: #fff;
|
||||
cursor: pointer; display: flex; align-items: center; justify-content: center;
|
||||
z-index: 1;
|
||||
.mermaid-fullscreen-header {
|
||||
display: flex; align-items: center; justify-content: space-between;
|
||||
padding: 10px 16px;
|
||||
background: rgba(255,255,255,0.06);
|
||||
border-bottom: 1px solid rgba(255,255,255,0.08);
|
||||
min-height: 46px;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
.mermaid-fullscreen-header .mermaid-diagram-type { color: rgba(255,255,255,0.7); }
|
||||
.mermaid-fullscreen-header .mermaid-btn {
|
||||
color: rgba(255,255,255,0.6);
|
||||
}
|
||||
.mermaid-fullscreen-header .mermaid-btn:hover {
|
||||
background: rgba(255,255,255,0.1);
|
||||
color: #fff;
|
||||
}
|
||||
.mermaid-fullscreen-close:hover { background: rgba(255,255,255,0.1); }
|
||||
.mermaid-fullscreen-content {
|
||||
width: 95vw; height: 95vh;
|
||||
flex: 1;
|
||||
display: flex; align-items: center; justify-content: center;
|
||||
padding: 16px;
|
||||
overflow: hidden;
|
||||
}
|
||||
.mermaid-fullscreen-content svg {
|
||||
width: 100%; height: 100%;
|
||||
|
||||
Reference in New Issue
Block a user