|
136 | 136 | .mindmap .mm-canvas{position:relative} |
137 | 137 | .mindmap .mm-links{position:absolute;left:0;top:0;pointer-events:none} |
138 | 138 | .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); |
141 | 141 | 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; |
143 | 143 | } |
144 | | -.mindmap .mm-node:hover{filter:brightness(1.4)} |
| 144 | +.mindmap .mm-node:hover{filter:brightness(1.4);transform:scale(1.04)} |
145 | 145 | .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; |
148 | 149 | } |
| 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)}} |
149 | 151 | .mindmap .mm-dot{width:8px;height:8px;border-radius:50%;flex:none} |
150 | 152 | .mindmap .mm-label{flex:1;overflow:hidden;text-overflow:ellipsis;white-space:nowrap} |
151 | 153 | .mindmap .mm-caret{ |
|
322 | 324 | /* ===================== mind-map: OpenKB → documents → concepts (horizontal tree, DOM) ===================== */ |
323 | 325 | const mmEl = document.getElementById("mindmap"); |
324 | 326 | const mmCollapsed = new Set(); // node ids whose children are hidden |
325 | | -let mmQuery = ""; |
| 327 | +let mmQuery = "", mmRootY = 0; |
326 | 328 | 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; |
328 | 330 | function buildMindmap(){ |
329 | 331 | const q = mmQuery.toLowerCase(); |
330 | 332 | const keep = n => !q || n.label.toLowerCase().includes(q) || n.id.toLowerCase().includes(q); |
|
366 | 368 | let svg = `<svg class="mm-links" width="${Wpx}" height="${Hpx}">`; |
367 | 369 | links.forEach(([p, c]) => { |
368 | 370 | 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"/>`; |
370 | 372 | }); |
371 | 373 | svg += `</svg>`; |
372 | 374 | let html = ""; |
373 | 375 | 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; } |
375 | 377 | const col = colorOf(it.type), kn = it.kids.length || (mmCollapsed.has(it.id) ? 1 : 0); |
376 | 378 | const hasKids = it.id.startsWith("summaries/") && (kidsOf[it.id] || []).length; |
377 | 379 | html += `<div class="mm-node" data-id="${esc(it.id)}" title="${esc(it.label)}" ` |
|
381 | 383 | + `</div>`; |
382 | 384 | }); |
383 | 385 | 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 |
384 | 387 | mmEl.innerHTML = `<div class="mm-canvas" style="width:${Wpx}px;height:${Hpx}px;margin:${offY}px auto 0">${svg}${html}</div>`; |
385 | 388 | mmEl.querySelectorAll("[data-tog]").forEach(el => el.onclick = e => { |
386 | 389 | e.stopPropagation(); const id = el.dataset.tog; |
|
481 | 484 | mmEl.style.display = (m === "mindmap") ? "block" : "none"; |
482 | 485 | spacingCtl.style.display = (m === "mindmap") ? "none" : "flex"; |
483 | 486 | 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); } |
485 | 488 | else if(m === "radial"){ yaw = 0; pitch = 0; scale = DEF_SCALE; layoutRadial(); alpha = 1; } |
486 | 489 | else { yaw = DEF_YAW; pitch = DEF_PITCH; scale = DEF_SCALE; seed(); alpha = 1; } |
487 | 490 | [...modeTabs.children].forEach(b => b.classList.toggle("on", b.dataset.m === m)); |
|
0 commit comments