refactor: standardize mermaid diagram styling and improve interactive zoom toolbar UI
This commit is contained in:
@@ -296,7 +296,68 @@
|
||||
display: block;
|
||||
}
|
||||
.mermaid-container.mermaid-active {
|
||||
box-shadow: 0 0 0 2px var(--accent-color, #4f46e5);
|
||||
box-shadow: 0 0 0 2px var(--accent-color, #ea580c);
|
||||
}
|
||||
|
||||
/* Mermaid Orange/Red Brand Theme Styling Overrides */
|
||||
.mermaid svg .task {
|
||||
fill: #ea580c !important;
|
||||
stroke: #c2410c !important;
|
||||
rx: 6px !important;
|
||||
ry: 6px !important;
|
||||
}
|
||||
.mermaid svg .task0, .mermaid svg .task2 {
|
||||
fill: #ea580c !important;
|
||||
stroke: #c2410c !important;
|
||||
}
|
||||
.mermaid svg .task1, .mermaid svg .task3 {
|
||||
fill: #ef4444 !important;
|
||||
stroke: #b91c1c !important;
|
||||
}
|
||||
.mermaid svg .taskText,
|
||||
.mermaid svg .taskTextOutsideRight,
|
||||
.mermaid svg .taskTextOutsideLeft {
|
||||
font-family: 'Inter', sans-serif !important;
|
||||
font-weight: 600 !important;
|
||||
}
|
||||
.mermaid svg .taskText {
|
||||
fill: #ffffff !important;
|
||||
}
|
||||
.mermaid svg .taskTextOutsideRight,
|
||||
.mermaid svg .taskTextOutsideLeft {
|
||||
fill: #1e293b !important;
|
||||
}
|
||||
.dark .mermaid svg .taskTextOutsideRight,
|
||||
.dark .mermaid svg .taskTextOutsideLeft {
|
||||
fill: #f1f5f9 !important;
|
||||
}
|
||||
.mermaid svg .section0,
|
||||
.mermaid svg .section2 {
|
||||
fill: rgba(234, 88, 12, 0.08) !important;
|
||||
}
|
||||
.dark .mermaid svg .section0,
|
||||
.dark .mermaid svg .section2 {
|
||||
fill: rgba(234, 88, 12, 0.18) !important;
|
||||
}
|
||||
.mermaid svg .section1,
|
||||
.mermaid svg .section3 {
|
||||
fill: rgba(239, 68, 68, 0.08) !important;
|
||||
}
|
||||
.dark .mermaid svg .section1,
|
||||
.dark .mermaid svg .section3 {
|
||||
fill: rgba(239, 68, 68, 0.18) !important;
|
||||
}
|
||||
.mermaid svg .today {
|
||||
stroke: #ef4444 !important;
|
||||
stroke-width: 2px !important;
|
||||
}
|
||||
.mermaid svg .titleText {
|
||||
fill: #0f172a !important;
|
||||
font-weight: 700 !important;
|
||||
font-family: 'Outfit', sans-serif !important;
|
||||
}
|
||||
.dark .mermaid svg .titleText {
|
||||
fill: #f8fafc !important;
|
||||
}
|
||||
|
||||
/* Fullscreen overlay */
|
||||
@@ -411,27 +472,27 @@
|
||||
</style>
|
||||
|
||||
@php
|
||||
$accent = $proposal->meta['accent_color'] ?? 'indigo';
|
||||
$accent = $proposal->meta['accent_color'] ?? 'coral';
|
||||
$accentColor = match($accent) {
|
||||
'emerald' => '#059669',
|
||||
'cyberpunk' => '#ec4899',
|
||||
'coral' => '#ea580c',
|
||||
'amber' => '#d97706',
|
||||
default => '#4f46e5',
|
||||
default => '#ea580c',
|
||||
};
|
||||
$accentColorGlow = match($accent) {
|
||||
'emerald' => 'rgba(5, 150, 105, 0.2)',
|
||||
'cyberpunk' => 'rgba(236, 72, 153, 0.2)',
|
||||
'coral' => 'rgba(234, 88, 12, 0.2)',
|
||||
'amber' => 'rgba(217, 119, 6, 0.2)',
|
||||
default => 'rgba(79, 70, 229, 0.2)',
|
||||
default => 'rgba(234, 88, 12, 0.2)',
|
||||
};
|
||||
$themeClass = match($accent) {
|
||||
'emerald' => 'theme-emerald bg-emerald-600 hover:bg-emerald-700 focus:ring-emerald-500 text-emerald-600 dark:text-emerald-400 border-emerald-500/20',
|
||||
'cyberpunk' => 'theme-rose bg-rose-500 hover:bg-rose-600 focus:ring-rose-400 text-rose-500 dark:text-rose-400 border-rose-500/20',
|
||||
'coral' => 'theme-orange bg-orange-600 hover:bg-orange-700 focus:ring-orange-500 text-orange-600 dark:text-orange-400 border-orange-500/20',
|
||||
'amber' => 'theme-amber bg-amber-600 hover:bg-amber-700 focus:ring-amber-500 text-amber-600 dark:text-amber-400 border-amber-500/20',
|
||||
default => 'theme-indigo bg-indigo-600 hover:bg-indigo-700 focus:ring-indigo-500 text-indigo-600 dark:text-indigo-400 border-indigo-500/20',
|
||||
default => 'theme-orange bg-orange-600 hover:bg-orange-700 focus:ring-orange-500 text-orange-600 dark:text-orange-400 border-orange-500/20',
|
||||
};
|
||||
$gradient = match($accent) {
|
||||
'emerald' => 'from-emerald-600 to-teal-600 dark:from-emerald-500 dark:to-teal-500',
|
||||
@@ -966,10 +1027,39 @@
|
||||
const isDark = document.documentElement.classList.contains('dark');
|
||||
mermaid.initialize({
|
||||
startOnLoad: false,
|
||||
theme: isDark ? 'dark' : 'default',
|
||||
theme: 'base',
|
||||
securityLevel: 'loose',
|
||||
themeVariables: {
|
||||
fontFamily: 'Inter, sans-serif'
|
||||
fontFamily: 'Inter, sans-serif',
|
||||
darkMode: isDark,
|
||||
background: isDark ? '#0f172a' : '#ffffff',
|
||||
primaryColor: '#ea580c',
|
||||
primaryTextColor: '#ffffff',
|
||||
primaryBorderColor: '#c2410c',
|
||||
lineColor: '#ea580c',
|
||||
secondaryColor: '#ef4444',
|
||||
secondaryTextColor: '#ffffff',
|
||||
tertiaryColor: isDark ? '#1e293b' : '#fff7ed',
|
||||
tertiaryTextColor: isDark ? '#f8fafc' : '#9a3412',
|
||||
activeTaskBkgColor: '#ea580c',
|
||||
activeTaskBorderColor: '#c2410c',
|
||||
doneTaskBkgColor: '#f97316',
|
||||
doneTaskBorderColor: '#ea580c',
|
||||
critBkgColor: '#ef4444',
|
||||
critBorderColor: '#b91c1c',
|
||||
taskTextLightColor: '#ffffff',
|
||||
taskTextColor: '#ffffff',
|
||||
taskTextDarkColor: '#ffffff',
|
||||
taskTextOutsideColor: isDark ? '#e2e8f0' : '#1e293b',
|
||||
sectionBkgColor: isDark ? 'rgba(234, 88, 12, 0.15)' : 'rgba(234, 88, 12, 0.07)',
|
||||
sectionBkgColor2: isDark ? 'rgba(239, 68, 68, 0.15)' : 'rgba(239, 68, 68, 0.07)',
|
||||
altSectionBkgColor: isDark ? 'rgba(234, 88, 12, 0.10)' : 'rgba(234, 88, 12, 0.04)',
|
||||
gridColor: isDark ? 'rgba(255, 255, 255, 0.1)' : 'rgba(0, 0, 0, 0.08)',
|
||||
todayLineColor: '#ef4444',
|
||||
nodeBorder: '#ea580c',
|
||||
clusterBkg: isDark ? '#1e293b' : '#fff7ed',
|
||||
clusterBorder: '#f97316',
|
||||
titleColor: isDark ? '#f8fafc' : '#0f172a'
|
||||
}
|
||||
});
|
||||
|
||||
@@ -986,20 +1076,18 @@
|
||||
const wrapper = document.getElementById('mermaid-wrapper-' + index);
|
||||
const canvas = document.getElementById('mermaid-canvas-' + index);
|
||||
const pz = mermaidZoomInstances[index];
|
||||
if (!wrapper || !canvas || !pz) return;
|
||||
if (!wrapper || !canvas) return;
|
||||
|
||||
wrapper.classList.add('mermaid-active');
|
||||
canvas.classList.add('mermaid-active');
|
||||
pz.enablePan();
|
||||
if (pz) 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;
|
||||
}
|
||||
|
||||
@@ -1041,25 +1129,19 @@
|
||||
wrapper.id = 'mermaid-wrapper-' + index;
|
||||
wrapper.dataset.mermaidSource = rawMermaid;
|
||||
|
||||
// Zoom Toolbar
|
||||
// Zoom Toolbar (Uzaklaştır [-] | 100% | Yakınlaştır [+] | Sıfırla/Sığdır | Tam Ekran)
|
||||
const toolbar = document.createElement('div');
|
||||
toolbar.className = 'mermaid-toolbar';
|
||||
toolbar.innerHTML = `
|
||||
<span class="mermaid-toolbar-label">Diyagram Görünümü</span>
|
||||
<span class="mermaid-toolbar-hint">Zoom ve kaydırma için tıklayın</span>
|
||||
<span class="mermaid-toolbar-label">DİYAGRAM GÖRÜNÜMÜ</span>
|
||||
<span class="mermaid-toolbar-hint">Zoom ve sürükleme için tıklayın</span>
|
||||
<div class="mermaid-toolbar-controls">
|
||||
<button class="mermaid-zoom-btn" title="Yakınlaştır (Zoom In)" onclick="mermaidZoomIn(${index})">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round"><circle cx="11" cy="11" r="8"/><line x1="21" y1="21" x2="16.65" y2="16.65"/><line x1="11" y1="8" x2="11" y2="14"/><line x1="8" y1="11" x2="14" y2="11"/></svg>
|
||||
</button>
|
||||
<span class="mermaid-zoom-pct" id="mermaid-pct-${index}">100%</span>
|
||||
<button class="mermaid-zoom-btn" title="Uzaklaştır (Zoom Out)" onclick="mermaidZoomOut(${index})">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round"><circle cx="11" cy="11" r="8"/><line x1="21" y1="21" x2="16.65" y2="16.65"/><line x1="8" y1="11" x2="14" y2="11"/></svg>
|
||||
</button>
|
||||
<button class="mermaid-zoom-btn" title="Tam Boyut (1:1)" onclick="mermaidZoomReset(${index})">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round"><path d="M15 3h6v6M9 21H3v-6M21 3l-7 7M3 21l7-7"/></svg>
|
||||
</button>
|
||||
<button class="mermaid-zoom-btn" title="Tam Ekran" onclick="mermaidFullscreen(${index})">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round"><path d="M8 3H5a2 2 0 0 0-2 2v3m18 0V5a2 2 0 0 0-2-2h-3m0 18h3a2 2 0 0 0 2-2v-3M3 16v3a2 2 0 0 0 2 2h3"/></svg>
|
||||
<span class="mermaid-zoom-pct" id="mermaid-pct-${index}">100%</span>
|
||||
<button class="mermaid-zoom-btn" title="Yakınlaştır (Zoom In)" onclick="mermaidZoomIn(${index})">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round"><circle cx="11" cy="11" r="8"/><line x1="21" y1="21" x2="16.65" y2="16.65"/><line x1="11" y1="8" x2="11" y2="14"/><line x1="8" y1="11" x2="14" y2="11"/></svg>
|
||||
</button>
|
||||
</div>
|
||||
`;
|
||||
@@ -1070,7 +1152,7 @@
|
||||
canvas.id = 'mermaid-canvas-' + index;
|
||||
|
||||
const graphDiv = document.createElement('div');
|
||||
graphDiv.className = 'mermaid w-full';
|
||||
graphDiv.className = 'mermaid w-full h-full';
|
||||
graphDiv.id = 'mermaid-graph-' + index;
|
||||
graphDiv.textContent = rawMermaid;
|
||||
|
||||
@@ -1088,19 +1170,21 @@
|
||||
<div class="mermaid-fullscreen-inner" id="mermaid-fs-inner">
|
||||
<div class="mermaid-toolbar" style="border-radius:20px 20px 0 0;">
|
||||
<span class="mermaid-toolbar-label">Tam Ekran Görünüm</span>
|
||||
<button class="mermaid-zoom-btn" title="Yakınlaştır" onclick="mermaidFsZoom('in')">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round"><circle cx="11" cy="11" r="8"/><line x1="21" y1="21" x2="16.65" y2="16.65"/><line x1="11" y1="8" x2="11" y2="14"/><line x1="8" y1="11" x2="14" y2="11"/></svg>
|
||||
</button>
|
||||
<span class="mermaid-zoom-pct" id="mermaid-fs-pct">100%</span>
|
||||
<button class="mermaid-zoom-btn" title="Uzaklaştır" onclick="mermaidFsZoom('out')">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round"><circle cx="11" cy="11" r="8"/><line x1="21" y1="21" x2="16.65" y2="16.65"/><line x1="8" y1="11" x2="14" y2="11"/></svg>
|
||||
</button>
|
||||
<button class="mermaid-zoom-btn" title="1:1 Sıfırla" onclick="mermaidFsZoom('reset')">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round"><path d="M15 3h6v6M9 21H3v-6M21 3l-7 7M3 21l7-7"/></svg>
|
||||
</button>
|
||||
<button class="mermaid-zoom-btn" title="Kapat" onclick="closeMermaidFullscreen()" style="background:#ef4444;border-color:#ef4444;color:#fff;">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round"><line x1="18" y1="6" x2="6" y2="18"/><line x1="6" y1="6" x2="18" y2="18"/></svg>
|
||||
</button>
|
||||
<div class="mermaid-toolbar-controls">
|
||||
<button class="mermaid-zoom-btn" title="Uzaklaştır" onclick="mermaidFsZoom('out')">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round"><circle cx="11" cy="11" r="8"/><line x1="21" y1="21" x2="16.65" y2="16.65"/><line x1="8" y1="11" x2="14" y2="11"/></svg>
|
||||
</button>
|
||||
<span class="mermaid-zoom-pct" id="mermaid-fs-pct">100%</span>
|
||||
<button class="mermaid-zoom-btn" title="Yakınlaştır" onclick="mermaidFsZoom('in')">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round"><circle cx="11" cy="11" r="8"/><line x1="21" y1="21" x2="16.65" y2="16.65"/><line x1="11" y1="8" x2="11" y2="14"/><line x1="8" y1="11" x2="14" y2="11"/></svg>
|
||||
</button>
|
||||
<button class="mermaid-zoom-btn" title="Sığdır / Sıfırla" onclick="mermaidFsZoom('reset')">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round"><path d="M15 3h6v6M9 21H3v-6M21 3l-7 7M3 21l7-7"/></svg>
|
||||
</button>
|
||||
<button class="mermaid-zoom-btn" title="Kapat" onclick="closeMermaidFullscreen()" style="background:#ef4444;border-color:#ef4444;color:#fff;">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round"><line x1="18" y1="6" x2="6" y2="18"/><line x1="6" y1="6" x2="18" y2="18"/></svg>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="mermaid-fullscreen-canvas" id="mermaid-fs-canvas"></div>
|
||||
</div>
|
||||
@@ -1117,10 +1201,7 @@
|
||||
// Run mermaid parser
|
||||
setTimeout(() => {
|
||||
mermaid.run().then(() => {
|
||||
// Re-init lucide icons inside alerts after marked rendering completes
|
||||
lucide.createIcons();
|
||||
|
||||
// Initialize svg-pan-zoom for each mermaid diagram
|
||||
codeElements.forEach((_, index) => {
|
||||
initMermaidZoom(index);
|
||||
});
|
||||
@@ -1136,48 +1217,50 @@
|
||||
const svg = canvas.querySelector('svg');
|
||||
if (!svg) return;
|
||||
|
||||
// Ensure SVG has an ID for svg-pan-zoom
|
||||
if (!svg.id) svg.id = 'mermaid-svg-' + index;
|
||||
|
||||
// Compute a good canvas height from SVG viewBox aspect ratio
|
||||
const canvasW = canvas.clientWidth || canvas.offsetWidth || 800;
|
||||
let canvasH = 520;
|
||||
svg.setAttribute('width', '100%');
|
||||
svg.setAttribute('height', '100%');
|
||||
svg.style.width = '100%';
|
||||
svg.style.height = '100%';
|
||||
|
||||
// Compute canvas height from SVG viewBox aspect ratio
|
||||
let canvasH = 500;
|
||||
const vb = svg.getAttribute('viewBox');
|
||||
if (vb) {
|
||||
const parts = vb.split(/[\s,]+/);
|
||||
if (parts.length >= 4) {
|
||||
const svgW = parseFloat(parts[2]);
|
||||
const svgH = parseFloat(parts[3]);
|
||||
const canvasW = canvas.clientWidth || 800;
|
||||
if (svgW > 0 && svgH > 0) {
|
||||
canvasH = Math.max(400, Math.min(Math.round(svgH * (canvasW / svgW)), 900));
|
||||
canvasH = Math.max(380, Math.min(Math.round(svgH * (canvasW / svgW)), 800));
|
||||
}
|
||||
}
|
||||
}
|
||||
canvas.style.height = canvasH + 'px';
|
||||
|
||||
// svg-pan-zoom needs explicit width/height on the SVG element
|
||||
svg.setAttribute('width', canvasW);
|
||||
svg.setAttribute('height', canvasH);
|
||||
svg.style.width = canvasW + 'px';
|
||||
svg.style.height = canvasH + 'px';
|
||||
|
||||
try {
|
||||
if (mermaidZoomInstances[index]) {
|
||||
try { mermaidZoomInstances[index].destroy(); } catch(e) {}
|
||||
}
|
||||
|
||||
const panZoom = svgPanZoom('#' + svg.id, {
|
||||
zoomEnabled: true,
|
||||
panEnabled: false,
|
||||
panEnabled: true,
|
||||
controlIconsEnabled: false,
|
||||
fit: true,
|
||||
center: true,
|
||||
minZoom: 0.3,
|
||||
maxZoom: 8,
|
||||
zoomScaleSensitivity: 0.3,
|
||||
maxZoom: 10,
|
||||
zoomScaleSensitivity: 0.25,
|
||||
mouseWheelZoomEnabled: false,
|
||||
onZoom: (zoom) => {
|
||||
const pctEl = document.getElementById('mermaid-pct-' + index);
|
||||
if (pctEl) pctEl.textContent = Math.round(zoom * 100) + '%';
|
||||
updatePct(index, zoom);
|
||||
}
|
||||
});
|
||||
mermaidZoomInstances[index] = panZoom;
|
||||
updatePct(index, panZoom.getZoom());
|
||||
setupMermaidActivation(index);
|
||||
} catch(e) {
|
||||
console.warn('svg-pan-zoom init failed for mermaid-' + index, e);
|
||||
@@ -1198,7 +1281,12 @@
|
||||
function mermaidZoomReset(index) {
|
||||
setMermaidActive(index);
|
||||
const pz = mermaidZoomInstances[index];
|
||||
if (pz) { pz.resetZoom(); pz.center(); updatePct(index, pz.getZoom()); }
|
||||
if (pz) {
|
||||
pz.resetZoom();
|
||||
pz.fit();
|
||||
pz.center();
|
||||
updatePct(index, pz.getZoom());
|
||||
}
|
||||
}
|
||||
function updatePct(index, zoom) {
|
||||
const pctEl = document.getElementById('mermaid-pct-' + index);
|
||||
|
||||
Reference in New Issue
Block a user