Skip to content

Commit 596c633

Browse files
committed
style(visualize): polish the mind-map
- colour each connector by its child node's type (was flat white) - rounder nodes with a subtle shadow + hover lift - bigger, glowing, gently-pulsing OpenKB root - on entering the view, scroll so OpenKB is vertically centred with its branches fanning out to the right
1 parent 374d593 commit 596c633

1 file changed

Lines changed: 14 additions & 11 deletions

File tree

openkb/templates/graph.html

Lines changed: 14 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -136,16 +136,18 @@
136136
.mindmap .mm-canvas{position:relative}
137137
.mindmap .mm-links{position:absolute;left:0;top:0;pointer-events:none}
138138
.mindmap .mm-node{
139-
position:absolute;width:184px;height:20px;display:flex;align-items:center;gap:7px;
140-
padding:0 9px;border:1px solid var(--line);border-radius:11px;background:var(--glass);
139+
position:absolute;width:184px;height:22px;display:flex;align-items:center;gap:7px;
140+
padding:0 10px;border:1px solid var(--line);border-radius:13px;background:var(--glass);
141141
font:.72rem var(--mono);color:var(--ink);cursor:pointer;box-sizing:border-box;
142-
transition:filter .12s ease;
142+
box-shadow:0 1px 6px rgba(0,0,0,.3);transition:filter .12s ease,transform .12s ease;
143143
}
144-
.mindmap .mm-node:hover{filter:brightness(1.4)}
144+
.mindmap .mm-node:hover{filter:brightness(1.4);transform:scale(1.04)}
145145
.mindmap .mm-root{
146-
width:86px;justify-content:center;font-weight:700;color:#0a0e14;
147-
background:rgba(232,242,252,.96);border:none;box-shadow:0 0 16px rgba(120,200,255,.6);
146+
width:104px;height:30px;justify-content:center;font-weight:700;font-size:.8rem;letter-spacing:.04em;
147+
color:#08111c;background:linear-gradient(180deg,#eaf4ff,#bfe2ff);border:none;border-radius:16px;
148+
box-shadow:0 0 26px rgba(120,200,255,.75);animation:rootpulse 3.2s ease-in-out infinite;
148149
}
150+
@keyframes rootpulse{0%,100%{box-shadow:0 0 22px rgba(120,200,255,.6)}50%{box-shadow:0 0 34px rgba(120,200,255,.95)}}
149151
.mindmap .mm-dot{width:8px;height:8px;border-radius:50%;flex:none}
150152
.mindmap .mm-label{flex:1;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
151153
.mindmap .mm-caret{
@@ -322,9 +324,9 @@
322324
/* ===================== mind-map: OpenKB → documents → concepts (horizontal tree, DOM) ===================== */
323325
const mmEl = document.getElementById("mindmap");
324326
const mmCollapsed = new Set(); // node ids whose children are hidden
325-
let mmQuery = "";
327+
let mmQuery = "", mmRootY = 0;
326328
const mmResolveSrc = s => { const id = String(s).replace(/\.md$/i, ""); return (byId[id] && byId[id].id.startsWith("summaries/")) ? id : null; };
327-
const ROOT_W = 86, NODE_W = 184, COL = 234, ROW = 27, PADX = 34, PADY = 28, NH = 20;
329+
const ROOT_W = 104, NODE_W = 184, COL = 234, ROW = 31, PADX = 34, PADY = 30, NH = 22;
328330
function buildMindmap(){
329331
const q = mmQuery.toLowerCase();
330332
const keep = n => !q || n.label.toLowerCase().includes(q) || n.id.toLowerCase().includes(q);
@@ -366,12 +368,12 @@
366368
let svg = `<svg class="mm-links" width="${Wpx}" height="${Hpx}">`;
367369
links.forEach(([p, c]) => {
368370
const x1 = p.x + p.w, y1 = p.y + NH/2, x2 = c.x, y2 = c.y + NH/2, mx = (x1 + x2) / 2;
369-
svg += `<path d="M${x1},${y1} C${mx},${y1} ${mx},${y2} ${x2},${y2}" fill="none" stroke="rgba(255,255,255,.15)" stroke-width="1.3"/>`;
371+
svg += `<path d="M${x1},${y1} C${mx},${y1} ${mx},${y2} ${x2},${y2}" fill="none" stroke="rgba(${colorOf(c.type)},.4)" stroke-width="1.5"/>`;
370372
});
371373
svg += `</svg>`;
372374
let html = "";
373375
flat.forEach(it => {
374-
if(it.id === "__openkb__"){ html += `<div class="mm-node mm-root" style="left:${it.x}px;top:${it.y}px">OpenKB</div>`; return; }
376+
if(it.id === "__openkb__"){ html += `<div class="mm-node mm-root" style="left:${it.x}px;top:${it.y - 4}px">OpenKB</div>`; return; }
375377
const col = colorOf(it.type), kn = it.kids.length || (mmCollapsed.has(it.id) ? 1 : 0);
376378
const hasKids = it.id.startsWith("summaries/") && (kidsOf[it.id] || []).length;
377379
html += `<div class="mm-node" data-id="${esc(it.id)}" title="${esc(it.label)}" `
@@ -381,6 +383,7 @@
381383
+ `</div>`;
382384
});
383385
const offY = Math.max(0, (mmEl.clientHeight - Hpx) / 2); // centre vertically when it fits; else scroll
386+
mmRootY = offY + flat.find(it => it.id === "__openkb__").y; // for centring the scroll on OpenKB
384387
mmEl.innerHTML = `<div class="mm-canvas" style="width:${Wpx}px;height:${Hpx}px;margin:${offY}px auto 0">${svg}${html}</div>`;
385388
mmEl.querySelectorAll("[data-tog]").forEach(el => el.onclick = e => {
386389
e.stopPropagation(); const id = el.dataset.tog;
@@ -481,7 +484,7 @@
481484
mmEl.style.display = (m === "mindmap") ? "block" : "none";
482485
spacingCtl.style.display = (m === "mindmap") ? "none" : "flex";
483486
hover = null; closePanel(); panX = 0; panY = 0; autoFit = true;
484-
if(m === "mindmap"){ buildMindmap(); }
487+
if(m === "mindmap"){ buildMindmap(); mmEl.scrollTop = Math.max(0, mmRootY - mmEl.clientHeight / 2); }
485488
else if(m === "radial"){ yaw = 0; pitch = 0; scale = DEF_SCALE; layoutRadial(); alpha = 1; }
486489
else { yaw = DEF_YAW; pitch = DEF_PITCH; scale = DEF_SCALE; seed(); alpha = 1; }
487490
[...modeTabs.children].forEach(b => b.classList.toggle("on", b.dataset.m === m));

0 commit comments

Comments
 (0)