backpack-viewer 0.3.0 → 0.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +29 -8
- package/bin/serve.js +116 -3
- package/dist/app/assets/index-DBZCyAjY.js +34 -0
- package/dist/app/assets/{index-CvkozBSE.css → index-DlVz8Lz7.css} +1 -1
- package/dist/app/index.html +2 -2
- package/dist/main.js +57 -0
- package/dist/sidebar.d.ts +11 -0
- package/dist/sidebar.js +136 -0
- package/dist/style.css +126 -0
- package/package.json +2 -2
- package/dist/app/assets/index-CBjy2b6N.js +0 -34
|
@@ -1,34 +0,0 @@
|
|
|
1
|
-
var bn=Object.defineProperty;var wn=(t,e,s)=>e in t?bn(t,e,{enumerable:!0,configurable:!0,writable:!0,value:s}):t[e]=s;var ut=(t,e,s)=>wn(t,typeof e!="symbol"?e+"":e,s);(function(){const e=document.createElement("link").relList;if(e&&e.supports&&e.supports("modulepreload"))return;for(const l of document.querySelectorAll('link[rel="modulepreload"]'))r(l);new MutationObserver(l=>{for(const f of l)if(f.type==="childList")for(const b of f.addedNodes)b.tagName==="LINK"&&b.rel==="modulepreload"&&r(b)}).observe(document,{childList:!0,subtree:!0});function s(l){const f={};return l.integrity&&(f.integrity=l.integrity),l.referrerPolicy&&(f.referrerPolicy=l.referrerPolicy),l.crossOrigin==="use-credentials"?f.credentials="include":l.crossOrigin==="anonymous"?f.credentials="omit":f.credentials="same-origin",f}function r(l){if(l.ep)return;l.ep=!0;const f=s(l);fetch(l.href,f)}})();async function mt(){const t=await fetch("/api/ontologies");return t.ok?t.json():[]}async function ht(t){const e=await fetch(`/api/ontologies/${encodeURIComponent(t)}`);if(!e.ok)throw new Error(`Failed to load ontology: ${t}`);return e.json()}async function kn(){const t=await fetch("/api/remotes");return t.ok?t.json():[]}async function Sn(t){const e=await fetch(`/api/remotes/${encodeURIComponent(t)}`);if(!e.ok)throw new Error(`Failed to load remote graph: ${t}`);return e.json()}async function wt(t,e){if(!(await fetch(`/api/ontologies/${encodeURIComponent(t)}`,{method:"PUT",headers:{"Content-Type":"application/json"},body:JSON.stringify(e)})).ok)throw new Error(`Failed to save ontology: ${t}`)}async function Nn(t,e){if(!(await fetch(`/api/ontologies/${encodeURIComponent(t)}/rename`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({name:e})})).ok)throw new Error(`Failed to rename ontology: ${t}`)}async function Ln(t){const e=await fetch(`/api/graphs/${encodeURIComponent(t)}/branches`);return e.ok?e.json():[]}async function qt(t,e,s){const r=await fetch(`/api/graphs/${encodeURIComponent(t)}/branches`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({name:e,from:s})});if(!r.ok){const l=await r.json().catch(()=>({}));throw new Error(l.error||"Failed to create branch")}}async function Yt(t,e){const s=await fetch(`/api/graphs/${encodeURIComponent(t)}/branches/switch`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({name:e})});if(!s.ok){const r=await s.json().catch(()=>({}));throw new Error(r.error||"Failed to switch branch")}}async function In(t,e){const s=await fetch(`/api/graphs/${encodeURIComponent(t)}/branches/${encodeURIComponent(e)}`,{method:"DELETE"});if(!s.ok){const r=await s.json().catch(()=>({}));throw new Error(r.error||"Failed to delete branch")}}async function Mn(t){const e=await fetch(`/api/graphs/${encodeURIComponent(t)}/snapshots`);return e.ok?e.json():[]}async function Tn(t,e){const s=await fetch(`/api/graphs/${encodeURIComponent(t)}/snapshots`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({label:e})});if(!s.ok){const r=await s.json().catch(()=>({}));throw new Error(r.error||"Failed to create snapshot")}}async function An(t,e){const s=await fetch(`/api/graphs/${encodeURIComponent(t)}/rollback`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({version:e})});if(!s.ok){const r=await s.json().catch(()=>({}));throw new Error(r.error||"Failed to rollback")}}async function Rn(t){const e=await fetch(`/api/graphs/${encodeURIComponent(t)}/snippets`);return e.ok?e.json():[]}async function Xt(t,e,s,r,l){const f=await fetch(`/api/graphs/${encodeURIComponent(t)}/snippets`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({label:e,description:l,nodeIds:s,edgeIds:r})});if(!f.ok)throw new Error("Failed to save snippet");return(await f.json()).id}async function Bn(t,e){const s=await fetch(`/api/graphs/${encodeURIComponent(t)}/snippets/${encodeURIComponent(e)}`);if(!s.ok)throw new Error("Snippet not found");return s.json()}async function Fn(t,e){if(!(await fetch(`/api/graphs/${encodeURIComponent(t)}/snippets/${encodeURIComponent(e)}`,{method:"DELETE"})).ok)throw new Error("Failed to delete snippet")}const _t="bp-dialog-overlay";function pn(){var e;(e=document.querySelector(`.${_t}`))==null||e.remove();const t=document.createElement("div");return t.className=_t,document.body.appendChild(t),t}function un(t,e){const s=document.createElement("div");s.className="bp-dialog";const r=document.createElement("h4");return r.className="bp-dialog-title",r.textContent=e,s.appendChild(r),t.appendChild(s),t.addEventListener("click",l=>{l.target===t&&t.remove()}),s}function mn(t,e){const s=document.createElement("div");s.className="bp-dialog-buttons";for(const r of e){const l=document.createElement("button");l.className="bp-dialog-btn",r.accent&&l.classList.add("bp-dialog-btn-accent"),r.danger&&l.classList.add("bp-dialog-btn-danger"),l.textContent=r.label,l.addEventListener("click",r.onClick),s.appendChild(l)}t.appendChild(s)}function hn(t,e){return new Promise(s=>{var b;const r=pn(),l=un(r,t),f=document.createElement("p");f.className="bp-dialog-message",f.textContent=e,l.appendChild(f),mn(l,[{label:"Cancel",onClick:()=>{r.remove(),s(!1)}},{label:"Confirm",accent:!0,onClick:()=>{r.remove(),s(!0)}}]),(b=l.querySelector(".bp-dialog-btn-accent"))==null||b.focus()})}function gt(t,e,s){return new Promise(r=>{const l=pn(),f=un(l,t),b=document.createElement("input");b.type="text",b.className="bp-dialog-input",b.placeholder=e??"",b.value="",f.appendChild(b);const i=()=>{const o=b.value.trim();l.remove(),r(o||null)};b.addEventListener("keydown",o=>{o.key==="Enter"&&i(),o.key==="Escape"&&(l.remove(),r(null))}),mn(f,[{label:"Cancel",onClick:()=>{l.remove(),r(null)}},{label:"OK",accent:!0,onClick:i}]),b.focus(),b.select()})}function Gt(t){return t>=1e3?`${(t/1e3).toFixed(1)}k tokens`:`${t} tokens`}function Vt(t,e){return t*50+e*25+50}function Pn(t,e){const s=typeof e=="function"?{onSelect:e}:e,r=document.createElement("h2");r.textContent="Backpack Viewer";const l=document.createElement("input");l.type="text",l.placeholder="Filter...",l.id="filter";const f=document.createElement("ul");f.id="ontology-list";const b=document.createElement("h3");b.className="sidebar-section-heading",b.textContent="REMOTE GRAPHS",b.hidden=!0;const i=document.createElement("ul");i.id="remote-list",i.className="remote-list",i.hidden=!0;const o=document.createElement("div");o.className="sidebar-footer",o.innerHTML='<a href="mailto:support@backpackontology.com">support@backpackontology.com</a><span>Feedback & support</span><span class="sidebar-version">v0.3.0</span>';const F=document.createElement("button");F.className="sidebar-collapse-btn",F.title="Toggle sidebar (Tab)",F.innerHTML='<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><polyline points="11 17 6 12 11 7"/><polyline points="18 17 13 12 18 7"/></svg>';let c=!1;function a(){c=!c,t.classList.toggle("sidebar-collapsed",c),D.classList.toggle("hidden",!c)}F.addEventListener("click",a);const I=document.createElement("div");I.className="sidebar-heading-row",I.appendChild(r),I.appendChild(F),t.appendChild(I);const D=document.createElement("button");D.className="tools-pane-toggle hidden",D.title="Show sidebar (Tab)",D.innerHTML='<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><polyline points="13 7 18 12 13 17"/><polyline points="6 7 11 12 6 17"/></svg>',D.addEventListener("click",a),t.appendChild(l),t.appendChild(f),t.appendChild(b),t.appendChild(i),t.appendChild(o);let E=[],K=[],J="";return l.addEventListener("input",()=>{const R=l.value.toLowerCase();for(const _ of E){const T=_.dataset.name??"";_.style.display=T.includes(R)?"":"none"}for(const _ of K){const T=_.dataset.name??"";_.style.display=T.includes(R)?"":"none"}}),{setSummaries(R){f.innerHTML="";const _=fetch("/api/locks").then(T=>T.json()).catch(()=>({}));E=R.map(T=>{const C=document.createElement("li");C.className="ontology-item",C.dataset.name=T.name;const O=document.createElement("span");O.className="name",O.textContent=T.name;const q=document.createElement("span");q.className="stats";const z=Vt(T.nodeCount,T.edgeCount);q.textContent=`${T.nodeCount} nodes, ${T.edgeCount} edges · ~${Gt(z)}`;const j=document.createElement("span");j.className="sidebar-branch",j.dataset.graph=T.name;const Z=document.createElement("span");if(Z.className="sidebar-lock-badge",Z.dataset.graph=T.name,_.then(H=>{if(!Z.isConnected)return;const ce=H[T.name];ce&&typeof ce=="object"&&ce.author&&(Z.textContent=`editing: ${ce.author}`,Z.title=`Last activity: ${ce.lastActivity??""}`,Z.classList.add("active"))}),C.appendChild(O),C.appendChild(q),C.appendChild(Z),C.appendChild(j),s.onRename){const H=document.createElement("button");H.className="sidebar-edit-btn",H.textContent="✎",H.title="Rename";const ce=s.onRename;H.addEventListener("click",ve=>{ve.stopPropagation();const pe=document.createElement("input");pe.type="text",pe.className="sidebar-rename-input",pe.value=T.name,O.textContent="",O.appendChild(pe),H.style.display="none",pe.focus(),pe.select();const re=()=>{const ge=pe.value.trim();ge&&ge!==T.name?ce(T.name,ge):(O.textContent=T.name,H.style.display="")};pe.addEventListener("blur",re),pe.addEventListener("keydown",ge=>{ge.key==="Enter"&&pe.blur(),ge.key==="Escape"&&(pe.value=T.name,pe.blur())})}),C.appendChild(H)}return C.addEventListener("click",()=>s.onSelect(T.name)),f.appendChild(C),C}),J&&this.setActive(J)},setActive(R){J=R;for(const _ of E)_.classList.toggle("active",_.dataset.name===R);for(const _ of K)_.classList.toggle("active",_.dataset.name===R)},setRemotes(R){i.replaceChildren(),K=R.map(T=>{const C=document.createElement("li");C.className="ontology-item ontology-item-remote",C.dataset.name=T.name;const O=document.createElement("div");O.className="remote-name-row";const q=document.createElement("span");q.className="name",q.textContent=T.name;const z=document.createElement("span");z.className="remote-badge",z.textContent=T.pinned?"remote · pinned":"remote",z.title=`Source: ${T.source??T.url}`,O.appendChild(q),O.appendChild(z);const j=document.createElement("span");j.className="stats";const Z=Vt(T.nodeCount,T.edgeCount);j.textContent=`${T.nodeCount} nodes, ${T.edgeCount} edges · ~${Gt(Z)}`;const H=document.createElement("span");return H.className="remote-source",H.textContent=T.source??new URL(T.url).hostname,H.title=T.url,C.appendChild(O),C.appendChild(j),C.appendChild(H),C.addEventListener("click",()=>s.onSelect(T.name)),i.appendChild(C),C});const _=R.length>0;b.hidden=!_,i.hidden=!_,J&&this.setActive(J)},setActiveBranch(R,_,T){const C=f.querySelectorAll(`.sidebar-branch[data-graph="${R}"]`);for(const O of C){O.textContent=`/ ${_}`,O.title="Click to switch branch",O.style.cursor="pointer";const q=O.cloneNode(!0);O.replaceWith(q),q.addEventListener("click",z=>{z.stopPropagation(),ae(R,q,T??[])})}},setSnippets(R,_){var O;const T=E.find(q=>q.dataset.name===R);if(!T||((O=T.querySelector(".sidebar-snippets"))==null||O.remove(),_.length===0))return;const C=document.createElement("div");C.className="sidebar-snippets";for(const q of _){const z=document.createElement("div");z.className="sidebar-snippet";const j=document.createElement("span");j.className="sidebar-snippet-label",j.textContent=`◆ ${q.label}`,j.title=`${q.nodeCount} nodes — click to load`;const Z=document.createElement("button");Z.className="sidebar-snippet-delete",Z.textContent="×",Z.title="Delete snippet",Z.addEventListener("click",H=>{var ce;H.stopPropagation(),(ce=s.onSnippetDelete)==null||ce.call(s,R,q.id)}),z.appendChild(j),z.appendChild(Z),z.addEventListener("click",H=>{var ce;H.stopPropagation(),(ce=s.onSnippetLoad)==null||ce.call(s,R,q.id)}),C.appendChild(z)}T.appendChild(C)},toggle:a,expandBtn:D};function ae(R,_,T){const C=t.querySelector(".branch-picker");C&&C.remove();const O=document.createElement("div");O.className="branch-picker";for(const z of T){const j=document.createElement("div");j.className="branch-picker-item",z.active&&j.classList.add("branch-picker-active");const Z=document.createElement("span");if(Z.textContent=z.name,j.appendChild(Z),!z.active&&s.onBranchDelete){const H=document.createElement("button");H.className="branch-picker-delete",H.textContent="×",H.title=`Delete ${z.name}`,H.addEventListener("click",ce=>{ce.stopPropagation(),hn("Delete branch",`Delete branch "${z.name}"?`).then(ve=>{ve&&(s.onBranchDelete(R,z.name),O.remove())})}),j.appendChild(H)}z.active||j.addEventListener("click",()=>{var H;(H=s.onBranchSwitch)==null||H.call(s,R,z.name),O.remove()}),O.appendChild(j)}if(s.onBranchCreate){const z=document.createElement("div");z.className="branch-picker-item branch-picker-create",z.textContent="+ New branch",z.addEventListener("click",()=>{gt("New branch","Branch name").then(j=>{j&&(s.onBranchCreate(R,j),O.remove())})}),O.appendChild(z)}_.after(O);const q=z=>{O.contains(z.target)||(O.remove(),document.removeEventListener("click",q))};setTimeout(()=>document.addEventListener("click",q),0)}}function Tt(t,e,s,r){return{x0:t,y0:e,x1:s,y1:r,cx:0,cy:0,mass:0,children:[null,null,null,null],body:null}}function Kt(t,e,s){const r=(t.x0+t.x1)/2,l=(t.y0+t.y1)/2;return(e<r?0:1)+(s<l?0:2)}function Jt(t,e){const s=(t.x0+t.x1)/2,r=(t.y0+t.y1)/2;switch(e){case 0:return[t.x0,t.y0,s,r];case 1:return[s,t.y0,t.x1,r];case 2:return[t.x0,r,s,t.y1];default:return[s,r,t.x1,t.y1]}}function At(t,e){if(t.mass===0&&t.body===null){t.body=e,t.cx=e.x,t.cy=e.y,t.mass=1;return}if(t.body!==null){const l=t.body;t.body=null,l.x===e.x&&l.y===e.y&&(e.x+=(Math.random()-.5)*.1,e.y+=(Math.random()-.5)*.1);const f=Kt(t,l.x,l.y);if(t.children[f]===null){const[b,i,o,F]=Jt(t,f);t.children[f]=Tt(b,i,o,F)}At(t.children[f],l)}const s=Kt(t,e.x,e.y);if(t.children[s]===null){const[l,f,b,i]=Jt(t,s);t.children[s]=Tt(l,f,b,i)}At(t.children[s],e);const r=t.mass+1;t.cx=(t.cx*t.mass+e.x)/r,t.cy=(t.cy*t.mass+e.y)/r,t.mass=r}function $n(t){if(t.length===0)return null;let e=1/0,s=1/0,r=-1/0,l=-1/0;for(const c of t)c.x<e&&(e=c.x),c.y<s&&(s=c.y),c.x>r&&(r=c.x),c.y>l&&(l=c.y);const f=Math.max(r-e,l-s)*.1+50,b=(e+r)/2,i=(s+l)/2,o=Math.max(r-e,l-s)/2+f,F=Tt(b-o,i-o,b+o,i+o);for(const c of t)At(F,c);return F}function Dn(t,e,s,r,l,f){fn(t,e,s,r,l,f)}function fn(t,e,s,r,l,f){if(t.mass===0)return;const b=t.cx-e.x,i=t.cy-e.y,o=b*b+i*i;if(t.body!==null){if(t.body!==e){let c=Math.sqrt(o);c<f&&(c=f);const a=r*l/(c*c),I=b/c*a,D=i/c*a;e.vx-=I,e.vy-=D}return}const F=t.x1-t.x0;if(F*F/o<s*s){let c=Math.sqrt(o);c<f&&(c=f);const a=r*t.mass*l/(c*c),I=b/c*a,D=i/c*a;e.vx-=I,e.vy-=D;return}for(let c=0;c<4;c++)t.children[c]!==null&&fn(t.children[c],e,s,r,l,f)}const gn={clusterStrength:.08,spacing:1.5},Zt=6e3,On=12e3,Wn=.004,yn=140,Cn=350,Qt=.9,en=.01,at=30,kt=50;let Ye={...gn};function Ze(t){t.clusterStrength!==void 0&&(Ye.clusterStrength=t.clusterStrength),t.spacing!==void 0&&(Ye.spacing=t.spacing)}function lt(){return{...Ye}}function Hn(t){if(t<=30)return{...gn};const e=Math.log2(t/30);return{clusterStrength:Math.min(.5,.08+.06*e),spacing:Math.min(15,1.5+1.2*e)}}function zn(t,e){for(const s of Object.values(t))if(typeof s=="string")return s;return e}function tn(t,e,s){const r=new Set(e);let l=new Set(e);for(let f=0;f<s;f++){const b=new Set;for(const i of t.edges)l.has(i.sourceId)&&!r.has(i.targetId)&&b.add(i.targetId),l.has(i.targetId)&&!r.has(i.sourceId)&&b.add(i.sourceId);for(const i of b)r.add(i);if(l=b,b.size===0)break}return{nodes:t.nodes.filter(f=>r.has(f.id)),edges:t.edges.filter(f=>r.has(f.sourceId)&&r.has(f.targetId)),metadata:t.metadata}}function St(t){const e=new Map,s=[...new Set(t.nodes.map(o=>o.type))],r=Math.sqrt(s.length)*Cn*.6*Math.max(1,Ye.spacing),l=new Map,f=new Map;for(const o of t.nodes)f.set(o.type,(f.get(o.type)??0)+1);const b=t.nodes.map(o=>{const F=s.indexOf(o.type),c=2*Math.PI*F/Math.max(s.length,1),a=Math.cos(c)*r,I=Math.sin(c)*r,D=l.get(o.type)??0;l.set(o.type,D+1);const E=f.get(o.type)??1,K=2*Math.PI*D/E,J=yn*.6,ae={id:o.id,x:a+Math.cos(K)*J,y:I+Math.sin(K)*J,vx:0,vy:0,label:zn(o.properties,o.id),type:o.type};return e.set(o.id,ae),ae}),i=t.edges.map(o=>({sourceId:o.sourceId,targetId:o.targetId,type:o.type}));return{nodes:b,edges:i,nodeMap:e}}const jn=.7,Un=80;function qn(t,e){const{nodes:s,edges:r,nodeMap:l}=t,f=On*Ye.spacing;if(s.length>=Un){const i=$n(s);if(i)for(const F of s)Dn(i,F,jn,f,e,at);const o=f-Zt;if(o>0){const F=new Map;for(const c of s){let a=F.get(c.type);a||(a=[],F.set(c.type,a)),a.push(c)}for(const c of F.values())for(let a=0;a<c.length;a++)for(let I=a+1;I<c.length;I++){const D=c[a],E=c[I];let K=E.x-D.x,J=E.y-D.y,ae=Math.sqrt(K*K+J*J);ae<at&&(ae=at);const R=o*e/(ae*ae),_=K/ae*R,T=J/ae*R;D.vx+=_,D.vy+=T,E.vx-=_,E.vy-=T}}}else for(let i=0;i<s.length;i++)for(let o=i+1;o<s.length;o++){const F=s[i],c=s[o];let a=c.x-F.x,I=c.y-F.y,D=Math.sqrt(a*a+I*I);D<at&&(D=at);const K=(F.type===c.type?Zt:f)*e/(D*D),J=a/D*K,ae=I/D*K;F.vx-=J,F.vy-=ae,c.vx+=J,c.vy+=ae}for(const i of r){const o=l.get(i.sourceId),F=l.get(i.targetId);if(!o||!F)continue;const c=F.x-o.x,a=F.y-o.y,I=Math.sqrt(c*c+a*a);if(I===0)continue;const D=o.type===F.type?yn*Ye.spacing:Cn*Ye.spacing,E=Wn*(I-D)*e,K=c/I*E,J=a/I*E;o.vx+=K,o.vy+=J,F.vx-=K,F.vy-=J}for(const i of s)i.vx-=i.x*en*e,i.vy-=i.y*en*e;const b=new Map;for(const i of s){const o=b.get(i.type)??{x:0,y:0,count:0};o.x+=i.x,o.y+=i.y,o.count++,b.set(i.type,o)}for(const i of b.values())i.x/=i.count,i.y/=i.count;for(const i of s){const o=b.get(i.type);i.vx+=(o.x-i.x)*Ye.clusterStrength*e,i.vy+=(o.y-i.y)*Ye.clusterStrength*e}for(const i of s){i.vx*=Qt,i.vy*=Qt;const o=Math.sqrt(i.vx*i.vx+i.vy*i.vy);o>kt&&(i.vx=i.vx/o*kt,i.vy=i.vy/o*kt),i.x+=i.vx,i.y+=i.vy}return e*.995}const nn=["#d4a27f","#c17856","#b07a5e","#d4956b","#a67c5a","#cc9e7c","#c4866a","#cb8e6c","#b8956e","#a88a70","#d9b08c","#c4a882","#e8b898","#b5927a","#a8886e","#d1a990"],on=new Map;function ke(t){const e=on.get(t);if(e)return e;let s=0;for(let l=0;l<t.length;l++)s=(s<<5)-s+t.charCodeAt(l)|0;const r=nn[Math.abs(s)%nn.length];return on.set(t,r),r}class Yn{constructor(e){ut(this,"cells",new Map);ut(this,"cellSize");ut(this,"invCell");this.cellSize=e,this.invCell=1/e}key(e,s){const r=e+32768|0,l=s+32768|0;return r*73856093^l*19349663}clear(){this.cells.clear()}insert(e){const s=Math.floor(e.x*this.invCell),r=Math.floor(e.y*this.invCell),l=this.key(s,r),f=this.cells.get(l);f?f.push(e):this.cells.set(l,[e])}rebuild(e){this.cells.clear();for(const s of e)this.insert(s)}query(e,s,r){const l=r*r,f=Math.floor((e-r)*this.invCell),b=Math.floor((e+r)*this.invCell),i=Math.floor((s-r)*this.invCell),o=Math.floor((s+r)*this.invCell);let F=null,c=l;for(let a=f;a<=b;a++)for(let I=i;I<=o;I++){const D=this.cells.get(this.key(a,I));if(D)for(const E of D){const K=E.x-e,J=E.y-s,ae=K*K+J*J;ae<=c&&(c=ae,F=E)}}return F}}const Qe=new Map,Xn=2e3;function _n(t,e,s){return`${t}|${e}|${s}`}const Gn=new OffscreenCanvas(1,1),sn=Gn.getContext("2d");function Vn(t,e,s){sn.font=e;const r=sn.measureText(t),l=Math.ceil(r.width)+2,f=Math.ceil(r.actualBoundingBoxAscent+r.actualBoundingBoxDescent)+4,b=new OffscreenCanvas(l,f),i=b.getContext("2d");return i.font=e,i.fillStyle=s,i.textAlign="left",i.textBaseline="top",i.fillText(t,1,1),{canvas:b,width:l,height:f}}function an(t,e,s,r,l,f,b){const i=_n(e,l,f);let o=Qe.get(i);if(!o){if(Qe.size>=Xn){const a=Qe.keys().next().value;a!==void 0&&Qe.delete(a)}o=Vn(e,l,f),Qe.set(i,o)}const F=s-o.width/2,c=b==="top"?r:r-o.height;t.drawImage(o.canvas,F,c)}function Kn(){Qe.clear()}function ye(t){return getComputedStyle(document.documentElement).getPropertyValue(t).trim()}const Fe=20,Nt=.001,Jn={hideBadges:.4,hideLabels:.25,hideEdgeLabels:.35,smallNodes:.2,hideArrows:.15,dotNodes:.1,hullsOnly:.05},Zn={zoomFactor:1.3,zoomMin:.05,zoomMax:10,panAnimationMs:300};function ft(t,e,s,r,l,f=100){const b=(t-s.x)*s.scale,i=(e-s.y)*s.scale;return b>=-f&&b<=r+f&&i>=-f&&i<=l+f}function Qn(t,e,s,r){const l={...Jn,...(r==null?void 0:r.lod)??{}},f={...Zn,...(r==null?void 0:r.navigation)??{}},b={pulseSpeed:.02,...(r==null?void 0:r.walk)??{}},i=t.querySelector("canvas"),o=i.getContext("2d"),F=window.devicePixelRatio||1;let c={x:0,y:0,scale:1},a=null,I=1,D=0,E=new Set,K=null,J=!0,ae=!0,R=!0,_=!0,T=null,C=null,O=1,q=null,z=null,j=null,Z=!1,H=[],ce=0,ve=0;const pe=400,re=new Yn(Fe*2);let ge=0;function Y(){P(),ge||(ge=requestAnimationFrame(()=>{ge=0,h()}))}const m=150;let y=null,S=!1;function L(){if(!y)try{y=new Worker(new URL("/assets/layout-worker-BZXiBoiC.js",import.meta.url),{type:"module"}),y.onmessage=B,y.onerror=()=>{S=!1,y=null,$e()}}catch{return S=!1,null}return y}function B(d){const v=d.data;if(v.type==="tick"&&a){const M=v.positions,$=a.nodes;for(let U=0;U<$.length;U++)$[U].x=M[U*4],$[U].y=M[U*4+1],$[U].vx=M[U*4+2],$[U].vy=M[U*4+3];I=v.alpha,re.rebuild($),h()}v.type==="settled"&&(I=0,Z&&H.length>0&&!ie&&(ie=requestAnimationFrame(Se)))}let g=null,N=null,A=!0;function P(){A=!0}let W=null,k=null;const p=f.panAnimationMs;function x(){i.width=i.clientWidth*F,i.height=i.clientHeight*F,P(),Y()}const Q=new ResizeObserver(x);Q.observe(t),x();function te(d,v){return[d/c.scale+c.x,v/c.scale+c.y]}function n(d,v){if(!a)return null;const[M,$]=te(d,v);return re.query(M,$,Fe)}function u(){if(!a)return;ce+=b.pulseSpeed;const d=new Set(H);o.save(),o.setTransform(F,0,0,F,0,0),g&&(o.clearRect(0,0,i.clientWidth,i.clientHeight),o.drawImage(g,0,0,i.clientWidth,i.clientHeight)),o.save(),o.translate(-c.x*c.scale,-c.y*c.scale),o.scale(c.scale,c.scale);const v=ye("--canvas-walk-edge")||"#1a1a1a",M=[];for(const V of a.edges){if(!d.has(V.sourceId)||!d.has(V.targetId)||V.sourceId===V.targetId)continue;const X=a.nodeMap.get(V.sourceId),ee=a.nodeMap.get(V.targetId);!X||!ee||M.push(X.x,X.y,ee.x,ee.y)}if(M.length>0){o.beginPath();for(let V=0;V<M.length;V+=4)o.moveTo(M[V],M[V+1]),o.lineTo(M[V+2],M[V+3]);o.strokeStyle=v,o.lineWidth=3,o.globalAlpha=.5+.5*Math.sin(ce),o.stroke(),o.globalAlpha=1}const $=c.scale<l.smallNodes?Fe*.5:Fe,U=ye("--accent")||"#d4a27f";for(const V of H){const X=a.nodeMap.get(V);if(!X||!ft(X.x,X.y,c,i.clientWidth,i.clientHeight))continue;const ee=V===H[H.length-1],le=.5+.5*Math.sin(ce);o.strokeStyle=U,o.lineWidth=ee?3:2,o.globalAlpha=ee?.5+.5*le:.3+.4*le,o.beginPath(),o.arc(X.x,X.y,$+(ee?6:4),0,Math.PI*2),o.stroke()}o.globalAlpha=1,o.restore(),_&&a.nodes.length>1&&G(),o.restore()}function h(){var Ot;if(!a){o.clearRect(0,0,i.width,i.height);return}if(!A&&g&&Z&&H.length>0&&I<Nt){u();return}const d=I<Nt&&Z&&H.length>0;Z&&H.length>0&&(ce+=b.pulseSpeed);const v=Z&&!d?new Set(H):null,M=ye("--canvas-edge"),$=ye("--canvas-edge-highlight"),U=ye("--canvas-edge-dim"),V=ye("--canvas-edge-label"),X=ye("--canvas-edge-label-highlight"),ee=ye("--canvas-edge-label-dim"),le=ye("--canvas-arrow"),he=ye("--canvas-arrow-highlight"),fe=ye("--canvas-node-label"),xe=ye("--canvas-node-label-dim"),Oe=ye("--canvas-type-badge"),Ie=ye("--canvas-type-badge-dim"),Le=ye("--canvas-selection-border"),ze=ye("--canvas-node-border");if(o.save(),o.setTransform(F,0,0,F,0,0),o.clearRect(0,0,i.clientWidth,i.clientHeight),o.save(),o.translate(-c.x*c.scale,-c.y*c.scale),o.scale(c.scale,c.scale),R&&c.scale>=l.smallNodes){const ne=new Map;for(const Ne of a.nodes){if(K!==null&&!K.has(Ne.id))continue;const Ae=ne.get(Ne.type)??[];Ae.push(Ne),ne.set(Ne.type,Ae)}for(const[Ne,Ae]of ne){if(Ae.length<2)continue;const Ge=ke(Ne),Xe=Fe*2.5;let We=1/0,He=1/0,Re=-1/0,qe=-1/0;for(const Be of Ae)Be.x<We&&(We=Be.x),Be.y<He&&(He=Be.y),Be.x>Re&&(Re=Be.x),Be.y>qe&&(qe=Be.y);o.beginPath();const oe=(Re-We)/2+Xe,be=(qe-He)/2+Xe,Ce=(We+Re)/2,Pe=(He+qe)/2;o.ellipse(Ce,Pe,oe,be,0,0,Math.PI*2),o.fillStyle=Ge,o.globalAlpha=.05,o.fill(),o.strokeStyle=Ge,o.globalAlpha=.12,o.lineWidth=1,o.setLineDash([4,4]),o.stroke(),o.setLineDash([]),o.globalAlpha=1}}let Me=null;if(E.size>0){Me=new Set;for(const ne of a.edges)E.has(ne.sourceId)&&Me.add(ne.targetId),E.has(ne.targetId)&&Me.add(ne.sourceId)}const vt=ye("--accent")||"#d4a27f",xt=ye("--canvas-walk-edge")||"#1a1a1a",Je=c.scale>=l.hideArrows,dt=ae&&c.scale>=l.hideEdgeLabels;if(J){const ne=[],Ne=[],Ae=[],Ge=[],Xe=[],We=[];for(const oe of a.edges){const be=a.nodeMap.get(oe.sourceId),Ce=a.nodeMap.get(oe.targetId);if(!be||!Ce||!ft(be.x,be.y,c,i.clientWidth,i.clientHeight,200)&&!ft(Ce.x,Ce.y,c,i.clientWidth,i.clientHeight,200))continue;const Pe=K===null||K.has(oe.sourceId),Be=K===null||K.has(oe.targetId),Wt=Pe&&Be;if(K!==null&&!Pe&&!Be)continue;const bt=E.size>0&&(E.has(oe.sourceId)||E.has(oe.targetId))||K!==null&&Wt,Ht=K!==null&&!Wt,zt=v!==null&&v.has(oe.sourceId)&&v.has(oe.targetId),jt=j?T==null?void 0:T.edges.find(pt=>pt.sourceId===oe.sourceId&&pt.targetId===oe.targetId||pt.targetId===oe.sourceId&&pt.sourceId===oe.targetId):null,Ut=!!(j&&jt&&j.edgeIds.has(jt.id));if(oe.sourceId===oe.targetId){me(be,oe.type,bt,M,$,V,X);continue}(Ut?Xe:zt?Ge:bt?Ne:Ht?Ae:ne).push(be.x,be.y,Ce.x,Ce.y),(Je||dt)&&We.push({sx:be.x,sy:be.y,tx:Ce.x,ty:Ce.y,type:oe.type,highlighted:bt,edgeDimmed:Ht,isPathEdge:Ut,isWalkEdge:zt})}const He=Je?1.5:1,qe=[{lines:ne,color:M,width:He,alpha:1},{lines:Ae,color:U,width:He,alpha:1},{lines:Ne,color:$,width:Je?2.5:1,alpha:1},{lines:Xe,color:vt,width:3,alpha:1},{lines:Ge,color:xt,width:3,alpha:.5+.5*Math.sin(ce)}];for(const oe of qe)if(oe.lines.length!==0){o.beginPath();for(let be=0;be<oe.lines.length;be+=4)o.moveTo(oe.lines[be],oe.lines[be+1]),o.lineTo(oe.lines[be+2],oe.lines[be+3]);o.strokeStyle=oe.color,o.lineWidth=oe.width,o.globalAlpha=oe.alpha,o.stroke()}o.globalAlpha=1;for(const oe of We)if(Je&&se(oe.sx,oe.sy,oe.tx,oe.ty,oe.highlighted||oe.isPathEdge,le,he),dt){const be=(oe.sx+oe.tx)/2,Ce=(oe.sy+oe.ty)/2;o.fillStyle=oe.highlighted?X:oe.edgeDimmed?ee:V,o.font="9px system-ui, sans-serif",o.textAlign="center",o.textBaseline="bottom",o.fillText(oe.type,be,Ce-4)}}const Et=performance.now()-ve,Ee=Math.min(1,Et/pe),je=1-(1-Ee)*(1-Ee),Ue=Ee<1,Dt=c.scale<l.hullsOnly,En=!Dt&&c.scale<l.dotNodes;if(!Dt)for(const ne of a.nodes){if(!ft(ne.x,ne.y,c,i.clientWidth,i.clientHeight))continue;const Ne=ke(ne.type);if(En){const Ce=K!==null&&!K.has(ne.id);o.fillStyle=Ne;const Pe=Ce?.1:.8;o.globalAlpha=Ue?Pe*je:Pe,o.fillRect(ne.x-2,ne.y-2,4,4);continue}const Ae=E.has(ne.id),Ge=Me!==null&&Me.has(ne.id),Xe=K!==null&&!K.has(ne.id),We=Xe||E.size>0&&!Ae&&!Ge,He=c.scale<l.smallNodes?Fe*.5:Fe,Re=Ue?He*je:He;if(v!=null&&v.has(ne.id)){const Ce=H[H.length-1]===ne.id,Pe=.5+.5*Math.sin(ce),Be=ye("--accent")||"#d4a27f";o.save(),o.strokeStyle=Be,o.lineWidth=Ce?3:2,o.globalAlpha=Ce?.5+.5*Pe:.3+.4*Pe,o.beginPath(),o.arc(ne.x,ne.y,Re+(Ce?6:4),0,Math.PI*2),o.stroke(),o.restore()}Ae&&(o.save(),o.shadowColor=Ne,o.shadowBlur=20,o.beginPath(),o.arc(ne.x,ne.y,Re+3,0,Math.PI*2),o.fillStyle=Ne,o.globalAlpha=.3,o.fill(),o.restore()),o.beginPath(),o.arc(ne.x,ne.y,Re,0,Math.PI*2),o.fillStyle=Ne;const qe=Xe?.1:We?.3:1;o.globalAlpha=Ue?qe*je:qe,o.fill(),o.strokeStyle=Ae?Le:ze,o.lineWidth=Ae?3:1.5,o.stroke(),o.globalAlpha=1,j&&j.nodeIds.has(ne.id)&&!Ae&&(o.save(),o.shadowColor=ye("--accent")||"#d4a27f",o.shadowBlur=15,o.beginPath(),o.arc(ne.x,ne.y,Re+2,0,Math.PI*2),o.strokeStyle=ye("--accent")||"#d4a27f",o.globalAlpha=.5,o.lineWidth=2,o.stroke(),o.restore());const oe=T==null?void 0:T.nodes.find(Ce=>Ce.id===ne.id);if(((Ot=oe==null?void 0:oe.properties)==null?void 0:Ot._starred)===!0&&(o.fillStyle="#ffd700",o.font="10px system-ui, sans-serif",o.textAlign="left",o.textBaseline="bottom",o.fillText("★",ne.x+Re-2,ne.y-Re+2)),c.scale>=l.hideLabels){const Ce=ne.label.length>24?ne.label.slice(0,22)+"...":ne.label,Pe=We?xe:fe;an(o,Ce,ne.x,ne.y+Re+4,"11px system-ui, sans-serif",Pe,"top")}if(c.scale>=l.hideBadges){const Ce=We?Ie:Oe;an(o,ne.type,ne.x,ne.y-Re-3,"9px system-ui, sans-serif",Ce,"bottom")}o.globalAlpha=1}if(o.restore(),o.restore(),d){const ne=i.width,Ne=i.height;(!g||g.width!==ne||g.height!==Ne)&&(g=new OffscreenCanvas(ne,Ne),N=g.getContext("2d")),N&&(N.clearRect(0,0,ne,Ne),N.drawImage(i,0,0),A=!1),u();return}_&&a.nodes.length>1&&G()}function G(){if(!a)return;const d=140,v=100,M=8,$=i.clientWidth-d-16,U=i.clientHeight-v-16;let V=1/0,X=1/0,ee=-1/0,le=-1/0;for(const Ee of a.nodes)Ee.x<V&&(V=Ee.x),Ee.y<X&&(X=Ee.y),Ee.x>ee&&(ee=Ee.x),Ee.y>le&&(le=Ee.y);const he=ee-V||1,fe=le-X||1,xe=Math.min((d-M*2)/he,(v-M*2)/fe),Oe=$+M+(d-M*2-he*xe)/2,Ie=U+M+(v-M*2-fe*xe)/2;o.save(),o.setTransform(F,0,0,F,0,0),o.fillStyle=ye("--bg-surface")||"#1a1a1a",o.globalAlpha=.85,o.beginPath(),o.roundRect($,U,d,v,8),o.fill(),o.strokeStyle=ye("--border")||"#2a2a2a",o.globalAlpha=1,o.lineWidth=1,o.stroke(),o.globalAlpha=.15,o.strokeStyle=ye("--canvas-edge")||"#555",o.lineWidth=.5;for(const Ee of a.edges){const je=a.nodeMap.get(Ee.sourceId),Ue=a.nodeMap.get(Ee.targetId);!je||!Ue||Ee.sourceId===Ee.targetId||(o.beginPath(),o.moveTo(Oe+(je.x-V)*xe,Ie+(je.y-X)*xe),o.lineTo(Oe+(Ue.x-V)*xe,Ie+(Ue.y-X)*xe),o.stroke())}o.globalAlpha=.8;for(const Ee of a.nodes){const je=Oe+(Ee.x-V)*xe,Ue=Ie+(Ee.y-X)*xe;o.beginPath(),o.arc(je,Ue,2,0,Math.PI*2),o.fillStyle=ke(Ee.type),o.fill()}const Le=c.x,ze=c.y,Me=c.x+i.clientWidth/c.scale,vt=c.y+i.clientHeight/c.scale,xt=Oe+(Le-V)*xe,Je=Ie+(ze-X)*xe,dt=(Me-Le)*xe,Et=(vt-ze)*xe;o.globalAlpha=.3,o.strokeStyle=ye("--accent")||"#d4a27f",o.lineWidth=1.5,o.strokeRect(Math.max($,Math.min(xt,$+d)),Math.max(U,Math.min(Je,U+v)),Math.min(dt,d),Math.min(Et,v)),o.globalAlpha=1,o.restore()}function se(d,v,M,$,U,V,X){const ee=Math.atan2($-v,M-d),le=M-Math.cos(ee)*Fe,he=$-Math.sin(ee)*Fe,fe=8;o.beginPath(),o.moveTo(le,he),o.lineTo(le-fe*Math.cos(ee-.4),he-fe*Math.sin(ee-.4)),o.lineTo(le-fe*Math.cos(ee+.4),he-fe*Math.sin(ee+.4)),o.closePath(),o.fillStyle=U?X:V,o.fill()}function me(d,v,M,$,U,V,X){const ee=d.x+Fe+15,le=d.y-Fe-15;o.beginPath(),o.arc(ee,le,15,0,Math.PI*2),o.strokeStyle=M?U:$,o.lineWidth=M?2.5:1.5,o.stroke(),ae&&(o.fillStyle=M?X:V,o.font="9px system-ui, sans-serif",o.textAlign="center",o.fillText(v,ee,le-18))}function ue(){if(!W||!k)return;const d=performance.now()-k.time,v=Math.min(d/p,1),M=1-Math.pow(1-v,3);c.x=k.x+(W.x-k.x)*M,c.y=k.y+(W.y-k.y)*M,P(),h(),v<1?requestAnimationFrame(ue):(W=null,k=null)}let ie=0;function Se(){if(!Z||H.length===0){ie=0;return}h(),ie=requestAnimationFrame(Se)}function we(){if(!a||a.nodes.length===0)return;let d=1/0,v=1/0,M=-1/0,$=-1/0;for(const he of a.nodes)he.x<d&&(d=he.x),he.y<v&&(v=he.y),he.x>M&&(M=he.x),he.y>$&&($=he.y);const U=Fe*4,V=M-d+U*2,X=$-v+U*2,ee=i.clientWidth/Math.max(V,1),le=i.clientHeight/Math.max(X,1);c.scale=Math.min(ee,le,2),c.x=(d+M)/2-i.clientWidth/(2*c.scale),c.y=(v+$)/2-i.clientHeight/(2*c.scale),Y()}function $e(){if(!a||I<Nt){Z&&H.length>0&&!ie&&(ie=requestAnimationFrame(Se));return}I=qn(a,I),re.rebuild(a.nodes),h(),D=requestAnimationFrame($e)}let et=!1,yt=!1,Ve=0,Ke=0;i.addEventListener("mousedown",d=>{et=!0,yt=!1,Ve=d.clientX,Ke=d.clientY}),i.addEventListener("mousemove",d=>{if(!et)return;const v=d.clientX-Ve,M=d.clientY-Ke;(Math.abs(v)>5||Math.abs(M)>5)&&(yt=!0),c.x-=v/c.scale,c.y-=M/c.scale,Ve=d.clientX,Ke=d.clientY,Y()}),i.addEventListener("mouseup",d=>{if(et=!1,yt)return;const v=i.getBoundingClientRect(),M=d.clientX-v.left,$=d.clientY-v.top,U=n(M,$),V=d.ctrlKey||d.metaKey;if(Z&&C&&U&&a){const X=H.length>0?H[H.length-1]:C[0],ee=new Set([X]),le=[{id:X,path:[X]}];let he=null;for(;le.length>0;){const{id:Ie,path:Le}=le.shift();if(Ie===U.id){he=Le;break}for(const ze of a.edges){let Me=null;ze.sourceId===Ie?Me=ze.targetId:ze.targetId===Ie&&(Me=ze.sourceId),Me&&!ee.has(Me)&&(ee.add(Me),le.push({id:Me,path:[...Le,Me]}))}}if(!he)return;for(const Ie of he.slice(1))H.includes(Ie)||H.push(Ie);C=[U.id];const fe=Math.max(1,O);O=fe;const xe=tn(T,[U.id],fe);cancelAnimationFrame(D),y&&y.postMessage({type:"stop"}),a=St(xe),re.rebuild(a.nodes),I=1,E=new Set([U.id]),K=null,c={x:0,y:0,scale:1},S=xe.nodes.length>=m;const Oe=S?L():null;Oe?Oe.postMessage({type:"start",data:xe}):(S=!1,$e()),setTimeout(()=>{a&&we()},300),s==null||s({seedNodeIds:[U.id],hops:fe,totalNodes:xe.nodes.length}),e==null||e([U.id]);return}if(U){V?E.has(U.id)?E.delete(U.id):E.add(U.id):E.size===1&&E.has(U.id)?E.clear():(E.clear(),E.add(U.id));const X=[...E];e==null||e(X.length>0?X:null)}else E.clear(),e==null||e(null);Y()}),i.addEventListener("mouseleave",()=>{et=!1}),i.addEventListener("wheel",d=>{d.preventDefault();const v=i.getBoundingClientRect(),M=d.clientX-v.left,$=d.clientY-v.top,[U,V]=te(M,$),X=d.ctrlKey?1-d.deltaY*.01:d.deltaY>0?.9:1.1;c.scale=Math.max(f.zoomMin,Math.min(f.zoomMax,c.scale*X)),c.x=U-M/c.scale,c.y=V-$/c.scale,Y()},{passive:!1});let De=[],Rt=0,Bt=1,Ft=0,Pt=0,Ct=!1;i.addEventListener("touchstart",d=>{d.preventDefault(),De=Array.from(d.touches),De.length===2?(Rt=$t(De[0],De[1]),Bt=c.scale):De.length===1&&(Ve=De[0].clientX,Ke=De[0].clientY,Ft=De[0].clientX,Pt=De[0].clientY,Ct=!1)},{passive:!1}),i.addEventListener("touchmove",d=>{d.preventDefault();const v=Array.from(d.touches);if(v.length===2&&De.length===2){const $=$t(v[0],v[1])/Rt;c.scale=Math.max(f.zoomMin,Math.min(f.zoomMax,Bt*$)),Y()}else if(v.length===1){const M=v[0].clientX-Ve,$=v[0].clientY-Ke;(Math.abs(v[0].clientX-Ft)>10||Math.abs(v[0].clientY-Pt)>10)&&(Ct=!0),c.x-=M/c.scale,c.y-=$/c.scale,Ve=v[0].clientX,Ke=v[0].clientY,Y()}De=v},{passive:!1}),i.addEventListener("touchend",d=>{if(d.preventDefault(),Ct||d.changedTouches.length!==1)return;const v=d.changedTouches[0],M=i.getBoundingClientRect(),$=v.clientX-M.left,U=v.clientY-M.top,V=n($,U);if(V){E.size===1&&E.has(V.id)?E.clear():(E.clear(),E.add(V.id));const X=[...E];e==null||e(X.length>0?X:null)}else E.clear(),e==null||e(null);Y()},{passive:!1}),i.addEventListener("gesturestart",d=>d.preventDefault()),i.addEventListener("gesturechange",d=>d.preventDefault());function $t(d,v){const M=d.clientX-v.clientX,$=d.clientY-v.clientY;return Math.sqrt(M*M+$*$)}const tt=document.createElement("div");tt.className="zoom-controls";const nt=document.createElement("button");nt.className="zoom-btn",nt.textContent="+",nt.title="Zoom in",nt.addEventListener("click",()=>{const d=i.clientWidth/2,v=i.clientHeight/2,[M,$]=te(d,v);c.scale=Math.min(f.zoomMax,c.scale*f.zoomFactor),c.x=M-d/c.scale,c.y=$-v/c.scale,Y()});const ot=document.createElement("button");ot.className="zoom-btn",ot.textContent="−",ot.title="Zoom out",ot.addEventListener("click",()=>{const d=i.clientWidth/2,v=i.clientHeight/2,[M,$]=te(d,v);c.scale=Math.max(f.zoomMin,c.scale/f.zoomFactor),c.x=M-d/c.scale,c.y=$-v/c.scale,Y()});const st=document.createElement("button");st.className="zoom-btn",st.textContent="○",st.title="Reset zoom",st.addEventListener("click",()=>{if(a){if(c={x:0,y:0,scale:1},a.nodes.length>0){let d=1/0,v=1/0,M=-1/0,$=-1/0;for(const X of a.nodes)X.x<d&&(d=X.x),X.y<v&&(v=X.y),X.x>M&&(M=X.x),X.y>$&&($=X.y);const U=(d+M)/2,V=(v+$)/2;c.x=U-i.clientWidth/2,c.y=V-i.clientHeight/2}Y()}}),tt.appendChild(nt),tt.appendChild(st),tt.appendChild(ot),t.appendChild(tt);const Te=document.createElement("div");Te.className="node-tooltip",Te.style.display="none",t.appendChild(Te);let rt=null,_e=null;return i.addEventListener("mousemove",d=>{if(et){Te.style.display!=="none"&&(Te.style.display="none",rt=null);return}const v=i.getBoundingClientRect(),M=d.clientX-v.left,$=d.clientY-v.top,U=n(M,$),V=(U==null?void 0:U.id)??null;V!==rt?(rt=V,Te.style.display="none",_e&&clearTimeout(_e),_e=null,V&&U&&(_e=setTimeout(()=>{if(!a||!T)return;const X=a.edges.filter(ee=>ee.sourceId===V||ee.targetId===V).length;Te.textContent=`${U.label} · ${U.type} · ${X} edge${X!==1?"s":""}`,Te.style.left=`${d.clientX-v.left+12}px`,Te.style.top=`${d.clientY-v.top-8}px`,Te.style.display="block"},200))):V&&Te.style.display==="block"&&(Te.style.left=`${d.clientX-v.left+12}px`,Te.style.top=`${d.clientY-v.top-8}px`)}),i.addEventListener("mouseleave",()=>{Te.style.display="none",rt=null,_e&&clearTimeout(_e),_e=null}),{loadGraph(d){if(cancelAnimationFrame(D),y&&y.postMessage({type:"stop"}),Kn(),T=d,C=null,q=null,z=null,ve=performance.now(),a=St(d),re.rebuild(a.nodes),I=1,E=new Set,K=null,c={x:0,y:0,scale:1},a.nodes.length>0){let M=1/0,$=1/0,U=-1/0,V=-1/0;for(const fe of a.nodes)fe.x<M&&(M=fe.x),fe.y<$&&($=fe.y),fe.x>U&&(U=fe.x),fe.y>V&&(V=fe.y);const X=(M+U)/2,ee=($+V)/2,le=i.clientWidth,he=i.clientHeight;c.x=X-le/2,c.y=ee-he/2}S=d.nodes.length>=m;const v=S?L():null;v?v.postMessage({type:"start",data:d}):(S=!1,$e())},setFilteredNodeIds(d){K=d,Y()},panToNode(d){this.panToNodes([d])},panToNodes(d){if(!a||d.length===0)return;const v=d.map(U=>a.nodeMap.get(U)).filter(Boolean);if(v.length===0)return;E=new Set(d),e==null||e(d);const M=i.clientWidth,$=i.clientHeight;if(v.length===1)k={x:c.x,y:c.y,time:performance.now()},W={x:v[0].x-M/(2*c.scale),y:v[0].y-$/(2*c.scale)};else{let U=1/0,V=1/0,X=-1/0,ee=-1/0;for(const Le of v)Le.x<U&&(U=Le.x),Le.y<V&&(V=Le.y),Le.x>X&&(X=Le.x),Le.y>ee&&(ee=Le.y);const le=Fe*4,he=X-U+le*2,fe=ee-V+le*2,xe=Math.min(M/he,$/fe,c.scale);c.scale=xe;const Oe=(U+X)/2,Ie=(V+ee)/2;k={x:c.x,y:c.y,time:performance.now()},W={x:Oe-M/(2*c.scale),y:Ie-$/(2*c.scale)}}ue()},setEdges(d){J=d,Y()},setEdgeLabels(d){ae=d,Y()},setTypeHulls(d){R=d,Y()},setMinimap(d){_=d,Y()},centerView(){we()},panBy(d,v){c.x+=d/c.scale,c.y+=v/c.scale,Y()},zoomBy(d){const v=i.clientWidth/2,M=i.clientHeight/2,[$,U]=te(v,M);c.scale=Math.max(f.zoomMin,Math.min(f.zoomMax,c.scale*d)),c.x=$-v/c.scale,c.y=U-M/c.scale,Y()},reheat(){S&&y?y.postMessage({type:"params",params:lt()}):(I=.5,cancelAnimationFrame(D),$e())},exportImage(d){if(!a)return"";const v=i.width,M=i.height;if(d==="png"){const X=document.createElement("canvas");X.width=v,X.height=M;const ee=X.getContext("2d");return ee.fillStyle=ye("--bg")||"#141414",ee.fillRect(0,0,v,M),ee.drawImage(i,0,0),xn(ee,v,M),X.toDataURL("image/png")}const $=i.toDataURL("image/png"),U=Math.max(16,Math.round(v/80)),V=`<svg xmlns="http://www.w3.org/2000/svg" width="${v}" height="${M}">
|
|
2
|
-
<image href="${$}" width="${v}" height="${M}"/>
|
|
3
|
-
<text x="${v-20}" y="${M-16}" text-anchor="end" font-family="system-ui, sans-serif" font-size="${U}" fill="#ffffff" opacity="0.4">backpackontology.com</text>
|
|
4
|
-
</svg>`;return"data:image/svg+xml;charset=utf-8,"+encodeURIComponent(V)},enterFocus(d,v){if(!T||!a)return;C||(q=a,z={...c}),C=d,O=v;const M=tn(T,d,v);cancelAnimationFrame(D),y&&y.postMessage({type:"stop"}),a=St(M),re.rebuild(a.nodes),I=1,E=new Set(d),K=null,c={x:0,y:0,scale:1},S=M.nodes.length>=m;const $=S?L():null;$?$.postMessage({type:"start",data:M}):(S=!1,$e()),setTimeout(()=>{!a||!C||we()},300),s==null||s({seedNodeIds:d,hops:v,totalNodes:M.nodes.length})},exitFocus(){!C||!q||(cancelAnimationFrame(D),y&&y.postMessage({type:"stop"}),a=q,re.rebuild(a.nodes),c=z??{x:0,y:0,scale:1},C=null,q=null,z=null,E=new Set,K=null,Y(),s==null||s(null))},isFocused(){return C!==null},getFocusInfo(){return!C||!a?null:{seedNodeIds:C,hops:O,totalNodes:a.nodes.length}},findPath(d,v){if(!a)return null;const M=new Set([d]),$=[{nodeId:d,path:[d],edges:[]}];for(;$.length>0;){const{nodeId:U,path:V,edges:X}=$.shift();if(U===v)return{nodeIds:V,edgeIds:X};for(const ee of a.edges){let le=null;if(ee.sourceId===U?le=ee.targetId:ee.targetId===U&&(le=ee.sourceId),le&&!M.has(le)){M.add(le);const he=T==null?void 0:T.edges.find(fe=>fe.sourceId===ee.sourceId&&fe.targetId===ee.targetId||fe.targetId===ee.sourceId&&fe.sourceId===ee.targetId);$.push({nodeId:le,path:[...V,le],edges:[...X,(he==null?void 0:he.id)??""]})}}}return null},setHighlightedPath(d,v){d&&v?j={nodeIds:new Set(d),edgeIds:new Set(v)}:j=null,Y()},clearHighlightedPath(){j=null,Y()},setWalkMode(d){Z=d,d?(H=C?[...C]:[...E],ie||(ie=requestAnimationFrame(Se))):(H=[],ie&&(cancelAnimationFrame(ie),ie=0)),Y()},getWalkMode(){return Z},getWalkTrail(){return[...H]},getFilteredNodeIds(){return K},removeFromWalkTrail(d){H=H.filter(v=>v!==d),Y()},nodeAtScreen(d,v){return n(d,v)},getNodeIds(){if(!a)return[];if(C){const d=new Set(C),v=a.nodes.filter($=>d.has($.id)).map($=>$.id),M=a.nodes.filter($=>!d.has($.id)).map($=>$.id);return[...v,...M]}return a.nodes.map(d=>d.id)},destroy(){cancelAnimationFrame(D),ge&&(cancelAnimationFrame(ge),ge=0),ie&&(cancelAnimationFrame(ie),ie=0),y&&(y.terminate(),y=null),g=null,N=null,Q.disconnect()}};function xn(d,v,M){const $=Math.max(16,Math.round(v/80));d.save(),d.font=`${$}px system-ui, sans-serif`,d.fillStyle="rgba(255, 255, 255, 0.4)",d.textAlign="right",d.textBaseline="bottom",d.fillText("backpackontology.com",v-20,M-16),d.restore()}}function it(t){for(const e of Object.values(t.properties))if(typeof e=="string")return e;return t.id}const eo="✎";function to(t,e,s,r){const l=document.createElement("div");l.id="info-panel",l.className="info-panel hidden",t.appendChild(l);let f=!1,b=[],i=-1,o=!1,F=null,c=[],a=!1,I=[],D=-1;function E(){l.classList.add("hidden"),l.classList.remove("info-panel-maximized"),l.innerHTML="",f=!1,b=[],i=-1}function K(C){!F||!s||(i<b.length-1&&(b=b.slice(0,i+1)),b.push(C),i=b.length-1,o=!0,s(C),o=!1)}function J(){if(i<=0||!F)return;i--,o=!0;const C=b[i];s==null||s(C),_(C,F),o=!1}function ae(){if(i>=b.length-1||!F)return;i++,o=!0;const C=b[i];s==null||s(C),_(C,F),o=!1}function R(){const C=document.createElement("div");C.className="info-panel-toolbar";const O=document.createElement("button");O.className="info-toolbar-btn",O.textContent="←",O.title="Back",O.disabled=i<=0,O.addEventListener("click",J),C.appendChild(O);const q=document.createElement("button");if(q.className="info-toolbar-btn",q.textContent="→",q.title="Forward",q.disabled=i>=b.length-1,q.addEventListener("click",ae),C.appendChild(q),r&&c.length>0){const Z=document.createElement("button");Z.className="info-toolbar-btn info-focus-btn",Z.textContent="◎",Z.title="Focus on neighborhood (F)",Z.disabled=a,a&&(Z.style.opacity="0.3"),Z.addEventListener("click",()=>{a||r(c)}),C.appendChild(Z)}const z=document.createElement("button");z.className="info-toolbar-btn",z.textContent=f?"⎘":"⛶",z.title=f?"Restore":"Maximize",z.addEventListener("click",()=>{f=!f,l.classList.toggle("info-panel-maximized",f),z.textContent=f?"⎘":"⛶",z.title=f?"Restore":"Maximize"}),C.appendChild(z);const j=document.createElement("button");return j.className="info-toolbar-btn info-close-btn",j.textContent="×",j.title="Close",j.addEventListener("click",E),C.appendChild(j),C}function _(C,O){const q=O.nodes.find(g=>g.id===C);if(!q)return;const z=O.edges.filter(g=>g.sourceId===C||g.targetId===C);I=z.map(g=>g.sourceId===C?g.targetId:g.sourceId),D=-1,l.innerHTML="",l.classList.remove("hidden"),f&&l.classList.add("info-panel-maximized");const j=document.createElement("div");j.className="info-panel-header",j.appendChild(R());const Z=document.createElement("div");Z.className="info-header";const H=document.createElement("span");if(H.className="info-type-badge",H.textContent=q.type,H.style.backgroundColor=ke(q.type),e){H.classList.add("info-editable");const g=document.createElement("button");g.className="info-inline-edit",g.textContent=eo,g.addEventListener("click",N=>{N.stopPropagation();const A=document.createElement("input");A.type="text",A.className="info-edit-inline-input",A.value=q.type,H.textContent="",H.appendChild(A),A.focus(),A.select();const P=()=>{const W=A.value.trim();W&&W!==q.type?e.onChangeNodeType(C,W):(H.textContent=q.type,H.appendChild(g))};A.addEventListener("blur",P),A.addEventListener("keydown",W=>{W.key==="Enter"&&A.blur(),W.key==="Escape"&&(A.value=q.type,A.blur())})}),H.appendChild(g)}const ce=document.createElement("h3");ce.className="info-label",ce.textContent=it(q);const ve=document.createElement("span");ve.className="info-id",ve.textContent=q.id,Z.appendChild(H),Z.appendChild(ce),Z.appendChild(ve),j.appendChild(Z),l.appendChild(j);const pe=document.createElement("div");pe.className="info-panel-body";const re=Object.keys(q.properties),ge=ct("Properties");if(re.length>0){const g=document.createElement("dl");g.className="info-props";for(const N of re){const A=document.createElement("dt");A.textContent=N;const P=document.createElement("dd");if(e){const W=Lt(q.properties[N]),k=document.createElement("textarea");k.className="info-edit-input",k.value=W,k.rows=1,k.addEventListener("input",()=>cn(k)),k.addEventListener("keydown",x=>{x.key==="Enter"&&!x.shiftKey&&(x.preventDefault(),k.blur())}),k.addEventListener("blur",()=>{const x=k.value;x!==W&&e.onUpdateNode(C,{[N]:oo(x)})}),P.appendChild(k),requestAnimationFrame(()=>cn(k));const p=document.createElement("button");p.className="info-delete-prop",p.textContent="×",p.title=`Remove ${N}`,p.addEventListener("click",()=>{const x={...q.properties};delete x[N],e.onUpdateNode(C,x)}),P.appendChild(p)}else P.appendChild(no(q.properties[N]));g.appendChild(A),g.appendChild(P)}ge.appendChild(g)}if(e){const g=document.createElement("button");g.className="info-add-btn",g.textContent="+ Add property",g.addEventListener("click",()=>{const N=document.createElement("div");N.className="info-add-row";const A=document.createElement("input");A.type="text",A.className="info-edit-input",A.placeholder="key";const P=document.createElement("input");P.type="text",P.className="info-edit-input",P.placeholder="value";const W=document.createElement("button");W.className="info-add-save",W.textContent="Add",W.addEventListener("click",()=>{A.value&&e.onAddProperty(C,A.value,P.value)}),N.appendChild(A),N.appendChild(P),N.appendChild(W),ge.appendChild(N),A.focus()}),ge.appendChild(g)}if(pe.appendChild(ge),z.length>0){const g=ct(`Connections (${z.length})`),N=document.createElement("ul");N.className="info-connections";for(const A of z){const P=A.sourceId===C,W=P?A.targetId:A.sourceId,k=O.nodes.find(h=>h.id===W),p=k?it(k):W,x=document.createElement("li");if(x.className="info-connection",s&&k&&(x.classList.add("info-connection-link"),x.addEventListener("click",h=>{h.target.closest(".info-delete-edge")||K(W)})),k){const h=document.createElement("span");h.className="info-target-dot",h.style.backgroundColor=ke(k.type),x.appendChild(h)}const Q=document.createElement("span");Q.className="info-arrow",Q.textContent=P?"→":"←";const te=document.createElement("span");te.className="info-edge-type",te.textContent=A.type;const n=document.createElement("span");n.className="info-target",n.textContent=p,x.appendChild(Q),x.appendChild(te),x.appendChild(n);const u=Object.keys(A.properties);if(u.length>0){const h=document.createElement("div");h.className="info-edge-props";for(const G of u){const se=document.createElement("span");se.className="info-edge-prop",se.textContent=`${G}: ${Lt(A.properties[G])}`,h.appendChild(se)}x.appendChild(h)}if(e){const h=document.createElement("button");h.className="info-delete-edge",h.textContent="×",h.title="Remove connection",h.addEventListener("click",G=>{G.stopPropagation(),e.onDeleteEdge(A.id)}),x.appendChild(h)}N.appendChild(x)}g.appendChild(N),pe.appendChild(g)}const Y=ct("Timestamps"),m=document.createElement("dl");m.className="info-props";const y=document.createElement("dt");y.textContent="created";const S=document.createElement("dd");S.textContent=ln(q.createdAt);const L=document.createElement("dt");L.textContent="updated";const B=document.createElement("dd");if(B.textContent=ln(q.updatedAt),m.appendChild(y),m.appendChild(S),m.appendChild(L),m.appendChild(B),Y.appendChild(m),pe.appendChild(Y),e){const g=document.createElement("div");g.className="info-section info-danger";const N=document.createElement("button");N.className="info-delete-node",N.textContent="Delete node",N.addEventListener("click",()=>{e.onDeleteNode(C),E()}),g.appendChild(N),pe.appendChild(g)}l.appendChild(pe)}function T(C,O){const q=new Set(C),z=O.nodes.filter(Y=>q.has(Y.id));if(z.length===0)return;const j=O.edges.filter(Y=>q.has(Y.sourceId)&&q.has(Y.targetId));l.innerHTML="",l.classList.remove("hidden"),f&&l.classList.add("info-panel-maximized"),l.appendChild(R());const Z=document.createElement("div");Z.className="info-header";const H=document.createElement("h3");H.className="info-label",H.textContent=`${z.length} nodes selected`,Z.appendChild(H);const ce=document.createElement("div");ce.className="info-badge-row";const ve=new Map;for(const Y of z)ve.set(Y.type,(ve.get(Y.type)??0)+1);for(const[Y,m]of ve){const y=document.createElement("span");y.className="info-type-badge",y.style.backgroundColor=ke(Y),y.textContent=m>1?`${Y} (${m})`:Y,ce.appendChild(y)}Z.appendChild(ce),l.appendChild(Z);const pe=ct("Selected Nodes"),re=document.createElement("ul");re.className="info-connections";for(const Y of z){const m=document.createElement("li");m.className="info-connection",s&&(m.classList.add("info-connection-link"),m.addEventListener("click",()=>{K(Y.id)}));const y=document.createElement("span");y.className="info-target-dot",y.style.backgroundColor=ke(Y.type);const S=document.createElement("span");S.className="info-target",S.textContent=it(Y);const L=document.createElement("span");L.className="info-edge-type",L.textContent=Y.type,m.appendChild(y),m.appendChild(S),m.appendChild(L),re.appendChild(m)}pe.appendChild(re),l.appendChild(pe);const ge=ct(j.length>0?`Connections Between Selected (${j.length})`:"Connections Between Selected");if(j.length===0){const Y=document.createElement("p");Y.className="info-empty-message",Y.textContent="No direct connections between selected nodes",ge.appendChild(Y)}else{const Y=document.createElement("ul");Y.className="info-connections";for(const m of j){const y=O.nodes.find(x=>x.id===m.sourceId),S=O.nodes.find(x=>x.id===m.targetId),L=y?it(y):m.sourceId,B=S?it(S):m.targetId,g=document.createElement("li");if(g.className="info-connection",y){const x=document.createElement("span");x.className="info-target-dot",x.style.backgroundColor=ke(y.type),g.appendChild(x)}const N=document.createElement("span");N.className="info-target",N.textContent=L;const A=document.createElement("span");A.className="info-arrow",A.textContent="→";const P=document.createElement("span");P.className="info-edge-type",P.textContent=m.type;const W=document.createElement("span");if(W.className="info-arrow",W.textContent="→",g.appendChild(N),g.appendChild(A),g.appendChild(P),g.appendChild(W),S){const x=document.createElement("span");x.className="info-target-dot",x.style.backgroundColor=ke(S.type),g.appendChild(x)}const k=document.createElement("span");k.className="info-target",k.textContent=B,g.appendChild(k);const p=Object.keys(m.properties);if(p.length>0){const x=document.createElement("div");x.className="info-edge-props";for(const Q of p){const te=document.createElement("span");te.className="info-edge-prop",te.textContent=`${Q}: ${Lt(m.properties[Q])}`,x.appendChild(te)}g.appendChild(x)}Y.appendChild(g)}ge.appendChild(Y)}l.appendChild(ge)}return{show(C,O){if(F=O,c=C,C.length===1&&!o){const q=C[0];b[i]!==q&&(i<b.length-1&&(b=b.slice(0,i+1)),b.push(q),i=b.length-1)}C.length===1?_(C[0],O):C.length>1&&T(C,O)},hide:E,goBack:J,goForward:ae,cycleConnection(C){if(I.length===0)return null;D===-1?D=C===1?0:I.length-1:(D+=C,D>=I.length&&(D=0),D<0&&(D=I.length-1));const O=l.querySelectorAll(".info-connection");return O.forEach((q,z)=>{q.classList.toggle("info-connection-active",z===D)}),D>=0&&O[D]&&O[D].scrollIntoView({block:"nearest"}),I[D]??null},setFocusDisabled(C){a=C;const O=l.querySelector(".info-focus-btn");O&&(O.disabled=C,O.style.opacity=C?"0.3":"")},get visible(){return!l.classList.contains("hidden")}}}function ct(t){const e=document.createElement("div");e.className="info-section";const s=document.createElement("h4");return s.className="info-section-title",s.textContent=t,e.appendChild(s),e}function no(t){if(Array.isArray(t)){const s=document.createElement("div");s.className="info-array";for(const r of t){const l=document.createElement("span");l.className="info-tag",l.textContent=String(r),s.appendChild(l)}return s}if(t!==null&&typeof t=="object"){const s=document.createElement("pre");return s.className="info-json",s.textContent=JSON.stringify(t,null,2),s}const e=document.createElement("span");return e.className="info-value",e.textContent=String(t??""),e}function Lt(t){return Array.isArray(t)?t.map(String).join(", "):t!==null&&typeof t=="object"?JSON.stringify(t):String(t??"")}function oo(t){const e=t.trim();if(e==="true")return!0;if(e==="false")return!1;if(e!==""&&!isNaN(Number(e)))return Number(e);if(e.startsWith("[")&&e.endsWith("]")||e.startsWith("{")&&e.endsWith("}"))try{return JSON.parse(e)}catch{return t}return t}function cn(t){t.style.height="auto",t.style.height=t.scrollHeight+"px"}function ln(t){try{return new Date(t).toLocaleString()}catch{return t}}function vn(t){for(const e of Object.values(t.properties))if(typeof e=="string")return e;return t.id}function rn(t,e){const s=e.toLowerCase();if(vn(t).toLowerCase().includes(s)||t.type.toLowerCase().includes(s))return!0;for(const r of Object.values(t.properties))if(typeof r=="string"&&r.toLowerCase().includes(s))return!0;return!1}function so(t,e){const s=(e==null?void 0:e.maxResults)??8,r=(e==null?void 0:e.debounceMs)??150;let l=null,f=null,b=null,i=null;const o=document.createElement("div");o.className="search-overlay hidden";const F=document.createElement("div");F.className="search-input-wrap";const c=document.createElement("input");c.className="search-input",c.type="text",c.placeholder="Search nodes...",c.setAttribute("autocomplete","off"),c.setAttribute("spellcheck","false");const a=document.createElement("kbd");a.className="search-kbd",a.textContent="/",F.appendChild(c),F.appendChild(a);const I=document.createElement("ul");I.className="search-results hidden",o.appendChild(F),o.appendChild(I),t.appendChild(o);function D(){if(!l)return null;const R=c.value.trim();if(R.length===0)return null;const _=new Set;for(const T of l.nodes)rn(T,R)&&_.add(T.id);return _}function E(){const R=D();f==null||f(R),K()}function K(){I.innerHTML="",J=-1;const R=c.value.trim();if(!l||R.length===0){I.classList.add("hidden");return}const _=[];for(const T of l.nodes)if(rn(T,R)&&(_.push(T),_.length>=s))break;if(_.length===0){I.classList.add("hidden");return}for(const T of _){const C=document.createElement("li");C.className="search-result-item";const O=document.createElement("span");O.className="search-result-dot",O.style.backgroundColor=ke(T.type);const q=document.createElement("span");q.className="search-result-label";const z=vn(T);q.textContent=z.length>36?z.slice(0,34)+"...":z;const j=document.createElement("span");j.className="search-result-type",j.textContent=T.type,C.appendChild(O),C.appendChild(q),C.appendChild(j),C.addEventListener("click",()=>{b==null||b(T.id),c.value="",I.classList.add("hidden"),E()}),I.appendChild(C)}I.classList.remove("hidden")}c.addEventListener("input",()=>{i&&clearTimeout(i),i=setTimeout(E,r)});let J=-1;function ae(){const R=I.querySelectorAll(".search-result-item");R.forEach((_,T)=>{_.classList.toggle("search-result-active",T===J)}),J>=0&&R[J]&&R[J].scrollIntoView({block:"nearest"})}return c.addEventListener("keydown",R=>{const _=I.querySelectorAll(".search-result-item");R.key==="ArrowDown"?(R.preventDefault(),_.length>0&&(J=Math.min(J+1,_.length-1),ae())):R.key==="ArrowUp"?(R.preventDefault(),_.length>0&&(J=Math.max(J-1,0),ae())):R.key==="Enter"?(R.preventDefault(),J>=0&&_[J]?_[J].click():_.length>0&&_[0].click(),c.blur()):R.key==="Escape"&&(c.value="",c.blur(),I.classList.add("hidden"),J=-1,E())}),document.addEventListener("click",R=>{o.contains(R.target)||I.classList.add("hidden")}),c.addEventListener("focus",()=>a.classList.add("hidden")),c.addEventListener("blur",()=>{c.value.length===0&&a.classList.remove("hidden")}),{setLearningGraphData(R){l=R,c.value="",I.classList.add("hidden"),l&&l.nodes.length>0?o.classList.remove("hidden"):o.classList.add("hidden")},onFilterChange(R){f=R},onNodeSelect(R){b=R},clear(){c.value="",I.classList.add("hidden"),f==null||f(null)},focus(){c.focus()}}}function ao(t,e){let s=null,r=null,l=!0,f=null,b=!0,i=!0,o=!0,F="types",c="",a="",I=[],D=[];const E={types:new Set,nodeIds:new Set};function K(){if(!s)return[];const m=new Set;for(const y of s.nodes)E.types.has(y.type)&&m.add(y.id);for(const y of E.nodeIds)m.add(y);return[...m]}function J(m){if(E.nodeIds.has(m))return!0;const y=s==null?void 0:s.nodes.find(S=>S.id===m);return y?E.types.has(y.type):!1}function ae(){return E.types.size===0&&E.nodeIds.size===0}function R(){const m=K();e.onFocusChange(m.length>0?m:null)}const _=document.createElement("button");_.className="tools-pane-toggle hidden",_.title="Graph Inspector",_.innerHTML='<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M4 7h16"/><path d="M4 12h16"/><path d="M4 17h10"/></svg>';const T=document.createElement("div");T.className="tools-pane-content hidden",t.appendChild(_),t.appendChild(T),_.addEventListener("click",()=>{var m;l=!l,T.classList.toggle("hidden",l),_.classList.toggle("active",!l),l||(m=e.onOpen)==null||m.call(e)});function C(){if(T.innerHTML="",!r)return;const m=document.createElement("div");if(m.className="tools-pane-summary",m.innerHTML=`<span>${r.nodeCount} nodes</span><span class="tools-pane-sep">·</span><span>${r.edgeCount} edges</span><span class="tools-pane-sep">·</span><span>${r.types.length} types</span>`,T.appendChild(m),s&&r.nodeCount>0){const B=Math.ceil(JSON.stringify(s).length/4),g=Math.round(B/r.nodeCount),N=Math.max(10,Math.round(g*.3)*Math.min(5,r.nodeCount)),A=B>N?Math.round((1-N/B)*100):0,P=document.createElement("div");P.className="tools-pane-token-card";const W=Math.min(100,A),k=document.createElement("div");k.className="token-card-label",k.textContent="Token Efficiency",P.appendChild(k);const p=document.createElement("div");p.className="token-card-stat",p.textContent=`~${B.toLocaleString()} tokens stored`,P.appendChild(p);const x=document.createElement("div");x.className="token-card-bar";const Q=document.createElement("div");Q.className="token-card-bar-fill",Q.style.width=`${W}%`,x.appendChild(Q),P.appendChild(x);const te=document.createElement("div");te.className="token-card-stat",te.textContent=`A search returns ~${N} tokens instead of ~${B.toLocaleString()} (${A}% reduction)`,P.appendChild(te),T.appendChild(P)}const y=document.createElement("div");y.className="tools-pane-tabs";const S=[{id:"types",label:"Types"},{id:"insights",label:"Insights"},{id:"controls",label:"Controls"}];for(const B of S){const g=document.createElement("button");g.className="tools-pane-tab",F===B.id&&g.classList.add("tools-pane-tab-active"),g.textContent=B.label,g.addEventListener("click",()=>{F=B.id,C()}),y.appendChild(g)}T.appendChild(y),ae()||z(),D.length>0&&q(),F==="types"&&r.types.length>5?T.appendChild(Z("Filter types...",c,B=>{c=B,O()})):F==="insights"&&r.orphans.length+r.singletons.length+r.emptyNodes.length>5&&T.appendChild(Z("Filter issues...",a,g=>{a=g,O()}));const L=document.createElement("div");L.className="tools-pane-tab-content",T.appendChild(L),O()}function O(){const m=T.querySelector(".tools-pane-tab-content");m&&(m.innerHTML="",F==="types"?H(m):F==="insights"?ce(m):F==="controls"&&ve(m))}function q(){T.appendChild(re(`Walk Trail (${D.length})`,m=>{for(let S=0;S<D.length;S++){const L=D[S],B=S===D.length-1;if(L.edgeType){const p=document.createElement("div");p.className="walk-trail-edge",p.textContent=`↓ ${L.edgeType}`,m.appendChild(p)}const g=document.createElement("div");g.className="tools-pane-row tools-pane-clickable",B&&(g.style.fontWeight="600");const N=document.createElement("span");N.className="tools-pane-count",N.style.minWidth="18px",N.textContent=`${S+1}`;const A=document.createElement("span");A.className="tools-pane-dot",A.style.backgroundColor=ke(L.type);const P=document.createElement("span");P.className="tools-pane-name",P.textContent=L.label;const W=document.createElement("span");W.className="tools-pane-count",W.textContent=L.type;const k=document.createElement("button");k.className="tools-pane-edit",k.style.opacity="1",k.textContent="×",k.title="Remove from trail",k.addEventListener("click",p=>{var x;p.stopPropagation(),(x=e.onWalkTrailRemove)==null||x.call(e,L.id)}),g.appendChild(N),g.appendChild(A),g.appendChild(P),g.appendChild(W),g.appendChild(k),g.addEventListener("click",()=>{e.onNavigateToNode(L.id)}),m.appendChild(g)}const y=document.createElement("div");if(y.className="tools-pane-export-row",e.onWalkIsolate){const S=document.createElement("button");S.className="tools-pane-export-btn",S.textContent="Isolate (I)",S.addEventListener("click",()=>e.onWalkIsolate()),y.appendChild(S)}if(e.onWalkSaveSnippet&&D.length>=2){const S=document.createElement("button");S.className="tools-pane-export-btn",S.textContent="Save snippet",S.addEventListener("click",()=>{gt("Save snippet","Name for this snippet").then(L=>{L&&e.onWalkSaveSnippet(L)})}),y.appendChild(S)}m.appendChild(y)}))}function z(){if(!r||!s)return;const m=K();T.appendChild(re("Focused",y=>{for(const g of E.types){const N=r.types.find(x=>x.name===g);if(!N)continue;const A=document.createElement("div");A.className="tools-pane-row tools-pane-clickable";const P=document.createElement("span");P.className="tools-pane-dot",P.style.backgroundColor=ke(N.name);const W=document.createElement("span");W.className="tools-pane-name",W.textContent=N.name;const k=document.createElement("span");k.className="tools-pane-count",k.textContent=`${N.count} nodes`;const p=document.createElement("button");p.className="tools-pane-edit tools-pane-focus-active",p.style.opacity="1",p.textContent="×",p.title=`Remove ${N.name} from focus`,A.appendChild(P),A.appendChild(W),A.appendChild(k),A.appendChild(p),p.addEventListener("click",x=>{x.stopPropagation(),E.types.delete(N.name),R(),C()}),y.appendChild(A)}for(const g of E.nodeIds){const N=s.nodes.find(Q=>Q.id===g);if(!N)continue;const A=dn(N.properties)??N.id,P=document.createElement("div");P.className="tools-pane-row tools-pane-clickable";const W=document.createElement("span");W.className="tools-pane-dot",W.style.backgroundColor=ke(N.type);const k=document.createElement("span");k.className="tools-pane-name",k.textContent=A;const p=document.createElement("span");p.className="tools-pane-count",p.textContent=N.type;const x=document.createElement("button");x.className="tools-pane-edit tools-pane-focus-active",x.style.opacity="1",x.textContent="×",x.title=`Remove ${A} from focus`,P.appendChild(W),P.appendChild(k),P.appendChild(p),P.appendChild(x),P.addEventListener("click",Q=>{Q.target.closest(".tools-pane-edit")||e.onNavigateToNode(g)}),x.addEventListener("click",Q=>{Q.stopPropagation(),E.nodeIds.delete(g),R(),C()}),y.appendChild(P)}const S=document.createElement("div");S.className="tools-pane-row tools-pane-clickable tools-pane-focus-clear";const L=document.createElement("span");L.className="tools-pane-name",L.style.color="var(--accent)",L.textContent=`${m.length} total`;const B=document.createElement("span");B.className="tools-pane-badge",B.textContent="clear all",S.appendChild(L),S.appendChild(B),S.addEventListener("click",()=>{E.types.clear(),E.nodeIds.clear(),R(),C()}),y.appendChild(S)}))}function j(m){const y=document.createElement("div");y.className="tools-pane-row tools-pane-clickable",f===m.name&&y.classList.add("active");const S=document.createElement("span");S.className="tools-pane-dot",S.style.backgroundColor=ke(m.name);const L=document.createElement("span");L.className="tools-pane-name",L.textContent=m.name;const B=document.createElement("span");B.className="tools-pane-count",B.textContent=String(m.count);const g=document.createElement("button");g.className="tools-pane-edit tools-pane-focus-toggle",E.types.has(m.name)&&g.classList.add("tools-pane-focus-active"),g.textContent="◎",g.title=E.types.has(m.name)?`Remove ${m.name} from focus`:`Add ${m.name} to focus`;const N=document.createElement("button");return N.className="tools-pane-edit",N.textContent="✎",N.title=`Rename all ${m.name} nodes`,y.appendChild(S),y.appendChild(L),y.appendChild(B),y.appendChild(g),y.appendChild(N),y.addEventListener("click",A=>{A.target.closest(".tools-pane-edit")||(f===m.name?(f=null,e.onFilterByType(null)):(f=m.name,e.onFilterByType(m.name)),C())}),g.addEventListener("click",A=>{A.stopPropagation(),E.types.has(m.name)?E.types.delete(m.name):E.types.add(m.name),R(),C()}),N.addEventListener("click",A=>{A.stopPropagation(),ge(y,m.name,P=>{P&&P!==m.name&&e.onRenameNodeType(m.name,P)})}),y}function Z(m,y,S){const L=document.createElement("input");return L.type="text",L.className="tools-pane-search",L.placeholder=m,L.value=y,L.addEventListener("input",()=>S(L.value)),L}function H(m){if(!r)return;const y=c.toLowerCase();if(r.types.length){const L=r.types.filter(B=>!E.types.has(B.name)).filter(B=>!y||B.name.toLowerCase().includes(y));L.length>0&&m.appendChild(re("Node Types",B=>{for(const g of L)B.appendChild(j(g))}))}const S=r.edgeTypes.filter(L=>!y||L.name.toLowerCase().includes(y));S.length&&m.appendChild(re("Edge Types",L=>{for(const B of S){const g=document.createElement("div");g.className="tools-pane-row tools-pane-clickable";const N=document.createElement("span");N.className="tools-pane-name",N.textContent=B.name;const A=document.createElement("span");A.className="tools-pane-count",A.textContent=String(B.count);const P=document.createElement("button");P.className="tools-pane-edit",P.textContent="✎",P.title=`Rename all ${B.name} edges`,g.appendChild(N),g.appendChild(A),g.appendChild(P),P.addEventListener("click",W=>{W.stopPropagation(),ge(g,B.name,k=>{k&&k!==B.name&&e.onRenameEdgeType(B.name,k)})}),L.appendChild(g)}}))}function ce(m){if(!r)return;const y=a.toLowerCase(),S=r.starred.filter(k=>!y||k.label.toLowerCase().includes(y)||k.type.toLowerCase().includes(y));S.length&&m.appendChild(re("★ Starred",k=>{for(const Q of S){const te=document.createElement("div");te.className="tools-pane-row tools-pane-clickable";const n=document.createElement("span");n.className="tools-pane-dot",n.style.backgroundColor=ke(Q.type);const u=document.createElement("span");u.className="tools-pane-name",u.textContent=Q.label;const h=document.createElement("button");h.className="tools-pane-edit tools-pane-focus-toggle",J(Q.id)&&h.classList.add("tools-pane-focus-active"),h.textContent="◎",h.title=J(Q.id)?`Remove ${Q.label} from focus`:`Add ${Q.label} to focus`,te.appendChild(n),te.appendChild(u),te.appendChild(h),te.addEventListener("click",G=>{G.target.closest(".tools-pane-edit")||e.onNavigateToNode(Q.id)}),h.addEventListener("click",G=>{G.stopPropagation(),E.nodeIds.has(Q.id)?E.nodeIds.delete(Q.id):E.nodeIds.add(Q.id),R(),C()}),k.appendChild(te)}const p=document.createElement("div");p.className="tools-pane-row tools-pane-actions";const x=document.createElement("button");if(x.className="tools-pane-action-btn",x.textContent="Focus all",x.title="Enter focus mode with all starred nodes",x.addEventListener("click",()=>{E.nodeIds.clear(),E.types.clear();for(const Q of r.starred)E.nodeIds.add(Q.id);R(),C()}),p.appendChild(x),e.onStarredSaveSnippet){const Q=document.createElement("button");Q.className="tools-pane-action-btn",Q.textContent="Save as snippet",Q.title="Save starred nodes as a reusable snippet",Q.addEventListener("click",async()=>{const te=await gt("Snippet name","starred");te&&e.onStarredSaveSnippet(te,r.starred.map(n=>n.id))}),p.appendChild(Q)}k.appendChild(p)}));const L=r.mostConnected.filter(k=>!y||k.label.toLowerCase().includes(y)||k.type.toLowerCase().includes(y));L.length&&m.appendChild(re("Most Connected",k=>{for(const p of L){const x=document.createElement("div");x.className="tools-pane-row tools-pane-clickable";const Q=document.createElement("span");Q.className="tools-pane-dot",Q.style.backgroundColor=ke(p.type);const te=document.createElement("span");te.className="tools-pane-name",te.textContent=p.label;const n=document.createElement("span");n.className="tools-pane-count",n.textContent=`${p.connections}`;const u=document.createElement("button");u.className="tools-pane-edit tools-pane-focus-toggle",J(p.id)&&u.classList.add("tools-pane-focus-active"),u.textContent="◎",u.title=J(p.id)?`Remove ${p.label} from focus`:`Add ${p.label} to focus`,x.appendChild(Q),x.appendChild(te),x.appendChild(n),x.appendChild(u),x.addEventListener("click",h=>{h.target.closest(".tools-pane-edit")||e.onNavigateToNode(p.id)}),u.addEventListener("click",h=>{h.stopPropagation(),E.nodeIds.has(p.id)?E.nodeIds.delete(p.id):E.nodeIds.add(p.id),R(),C()}),k.appendChild(x)}}));const B=r.orphans.filter(k=>!y||k.label.toLowerCase().includes(y)||k.type.toLowerCase().includes(y)),g=r.singletons.filter(k=>!y||k.name.toLowerCase().includes(y)),N=r.emptyNodes.filter(k=>!y||k.label.toLowerCase().includes(y)||k.type.toLowerCase().includes(y)),A=B.length>0,P=g.length>0,W=N.length>0;if(!A&&!P&&!W){const k=document.createElement("div");k.className="tools-pane-empty-msg",k.textContent="No issues found",m.appendChild(k);return}A&&m.appendChild(re("Orphans",k=>{for(const p of B.slice(0,5)){const x=document.createElement("div");x.className="tools-pane-row tools-pane-clickable tools-pane-issue";const Q=document.createElement("span");Q.className="tools-pane-dot",Q.style.backgroundColor=ke(p.type);const te=document.createElement("span");te.className="tools-pane-name",te.textContent=p.label;const n=document.createElement("span");n.className="tools-pane-badge",n.textContent="orphan";const u=document.createElement("button");u.className="tools-pane-edit tools-pane-focus-toggle",J(p.id)&&u.classList.add("tools-pane-focus-active"),u.textContent="◎",u.title=J(p.id)?`Remove ${p.label} from focus`:`Add ${p.label} to focus`,x.appendChild(Q),x.appendChild(te),x.appendChild(n),x.appendChild(u),x.addEventListener("click",h=>{h.target.closest(".tools-pane-edit")||e.onNavigateToNode(p.id)}),u.addEventListener("click",h=>{h.stopPropagation(),E.nodeIds.has(p.id)?E.nodeIds.delete(p.id):E.nodeIds.add(p.id),R(),C()}),k.appendChild(x)}if(B.length>5){const p=document.createElement("div");p.className="tools-pane-more",p.textContent=`+ ${B.length-5} more orphans`,k.appendChild(p)}})),P&&m.appendChild(re("Singletons",k=>{for(const p of g.slice(0,5)){const x=document.createElement("div");x.className="tools-pane-row tools-pane-issue";const Q=document.createElement("span");Q.className="tools-pane-dot",Q.style.backgroundColor=ke(p.name);const te=document.createElement("span");te.className="tools-pane-name",te.textContent=p.name;const n=document.createElement("span");n.className="tools-pane-badge",n.textContent="1 node",x.appendChild(Q),x.appendChild(te),x.appendChild(n),k.appendChild(x)}})),W&&m.appendChild(re("Empty Nodes",k=>{for(const p of N.slice(0,5)){const x=document.createElement("div");x.className="tools-pane-row tools-pane-issue";const Q=document.createElement("span");Q.className="tools-pane-dot",Q.style.backgroundColor=ke(p.type);const te=document.createElement("span");te.className="tools-pane-name",te.textContent=p.label;const n=document.createElement("span");n.className="tools-pane-badge",n.textContent="empty",x.appendChild(Q),x.appendChild(te),x.appendChild(n),k.appendChild(x)}if(r.emptyNodes.length>5){const p=document.createElement("div");p.className="tools-pane-more",p.textContent=`+ ${r.emptyNodes.length-5} more empty nodes`,k.appendChild(p)}}))}function ve(m){m.appendChild(re("Display",y=>{const S=document.createElement("div");S.className="tools-pane-row tools-pane-clickable";const L=document.createElement("input");L.type="checkbox",L.checked=b,L.className="tools-pane-checkbox";const B=document.createElement("span");B.className="tools-pane-name",B.textContent="Edge labels",S.appendChild(L),S.appendChild(B),S.addEventListener("click",p=>{p.target!==L&&(L.checked=!L.checked),b=L.checked,e.onToggleEdgeLabels(b)}),y.appendChild(S);const g=document.createElement("div");g.className="tools-pane-row tools-pane-clickable";const N=document.createElement("input");N.type="checkbox",N.checked=i,N.className="tools-pane-checkbox";const A=document.createElement("span");A.className="tools-pane-name",A.textContent="Type regions",g.appendChild(N),g.appendChild(A),g.addEventListener("click",p=>{p.target!==N&&(N.checked=!N.checked),i=N.checked,e.onToggleTypeHulls(i)}),y.appendChild(g);const P=document.createElement("div");P.className="tools-pane-row tools-pane-clickable";const W=document.createElement("input");W.type="checkbox",W.checked=o,W.className="tools-pane-checkbox";const k=document.createElement("span");k.className="tools-pane-name",k.textContent="Minimap",P.appendChild(W),P.appendChild(k),P.addEventListener("click",p=>{p.target!==W&&(W.checked=!W.checked),o=W.checked,e.onToggleMinimap(o)}),y.appendChild(P)})),m.appendChild(re("Layout",y=>{y.appendChild(pe("Clustering",0,1,.02,.08,S=>{e.onLayoutChange("clusterStrength",S)})),y.appendChild(pe("Spacing",.5,20,.5,1.5,S=>{e.onLayoutChange("spacing",S)})),y.appendChild(pe("Pan speed",20,200,10,60,S=>{e.onPanSpeedChange(S)}))})),m.appendChild(re("Export",y=>{const S=document.createElement("div");S.className="tools-pane-export-row";const L=document.createElement("button");L.className="tools-pane-export-btn",L.textContent="Export PNG",L.addEventListener("click",()=>e.onExport("png"));const B=document.createElement("button");B.className="tools-pane-export-btn",B.textContent="Export SVG",B.addEventListener("click",()=>e.onExport("svg")),S.appendChild(L),S.appendChild(B),y.appendChild(S)})),(e.onSnapshot||e.onRollback)&&m.appendChild(re("Versions",y=>{const S=document.createElement("div");S.className="tools-pane-export-row";const L=document.createElement("button");if(L.className="tools-pane-export-btn",L.textContent="Save snapshot",L.addEventListener("click",()=>{gt("Save snapshot","Label (optional)").then(B=>{var g;(g=e.onSnapshot)==null||g.call(e,B||void 0)})}),S.appendChild(L),y.appendChild(S),I.length>0)for(const B of I){const g=document.createElement("div");g.className="tools-pane-row";const N=document.createElement("span");N.className="tools-pane-name";const A=io(B.timestamp);N.textContent=B.label?`#${B.version} ${B.label}`:`#${B.version}`,N.title=`${A} — ${B.nodeCount} nodes, ${B.edgeCount} edges`;const P=document.createElement("span");P.className="tools-pane-count",P.textContent=A;const W=document.createElement("button");W.className="tools-pane-edit",W.style.opacity="1",W.textContent="↩",W.title="Restore this snapshot",W.addEventListener("click",()=>{hn("Restore snapshot",`Restore snapshot #${B.version}? Current state will be lost unless you save a snapshot first.`).then(k=>{var p;k&&((p=e.onRollback)==null||p.call(e,B.version))})}),g.appendChild(N),g.appendChild(P),g.appendChild(W),y.appendChild(g)}else{const B=document.createElement("div");B.className="tools-pane-empty-msg",B.textContent="No snapshots yet",y.appendChild(B)}}))}function pe(m,y,S,L,B,g){const N=document.createElement("div");N.className="tools-pane-slider-row";const A=document.createElement("span");A.className="tools-pane-slider-label",A.textContent=m;const P=document.createElement("input");P.type="range",P.className="tools-pane-slider",P.min=String(y),P.max=String(S),P.step=String(L),P.value=String(B);const W=document.createElement("span");return W.className="tools-pane-slider-value",W.textContent=String(B),P.addEventListener("input",()=>{const k=parseFloat(P.value);W.textContent=k%1===0?String(k):k.toFixed(2),g(k)}),N.appendChild(A),N.appendChild(P),N.appendChild(W),N}function re(m,y){const S=document.createElement("div");S.className="tools-pane-section";const L=document.createElement("div");return L.className="tools-pane-heading",L.textContent=m,S.appendChild(L),y(S),S}function ge(m,y,S){const L=document.createElement("input");L.className="tools-pane-inline-input",L.value=y,L.type="text";const B=m.innerHTML;m.innerHTML="",m.classList.add("tools-pane-editing"),m.appendChild(L),L.focus(),L.select();function g(){const N=L.value.trim();m.classList.remove("tools-pane-editing"),N&&N!==y?S(N):m.innerHTML=B}L.addEventListener("keydown",N=>{N.key==="Enter"&&(N.preventDefault(),g()),N.key==="Escape"&&(m.innerHTML=B,m.classList.remove("tools-pane-editing"))}),L.addEventListener("blur",g)}function Y(m){const y=new Map,S=new Map,L=new Map,B=new Set;for(const p of m.nodes)y.set(p.type,(y.get(p.type)??0)+1);for(const p of m.edges)S.set(p.type,(S.get(p.type)??0)+1),L.set(p.sourceId,(L.get(p.sourceId)??0)+1),L.set(p.targetId,(L.get(p.targetId)??0)+1),B.add(p.sourceId),B.add(p.targetId);const g=p=>dn(p.properties)??p.id,N=m.nodes.filter(p=>p.properties._starred===!0).map(p=>({id:p.id,label:g(p),type:p.type})),A=m.nodes.filter(p=>!B.has(p.id)).map(p=>({id:p.id,label:g(p),type:p.type})),P=[...y.entries()].filter(([,p])=>p===1).map(([p])=>({name:p})),W=m.nodes.filter(p=>Object.keys(p.properties).length===0).map(p=>({id:p.id,label:p.id,type:p.type})),k=m.nodes.map(p=>({id:p.id,label:g(p),type:p.type,connections:L.get(p.id)??0})).filter(p=>p.connections>0).sort((p,x)=>x.connections-p.connections).slice(0,5);return{nodeCount:m.nodes.length,edgeCount:m.edges.length,types:[...y.entries()].sort((p,x)=>x[1]-p[1]).map(([p,x])=>({name:p,count:x})),edgeTypes:[...S.entries()].sort((p,x)=>x[1]-p[1]).map(([p,x])=>({name:p,count:x})),starred:N,orphans:A,singletons:P,emptyNodes:W,mostConnected:k}}return{collapse(){l=!0,T.classList.add("hidden"),_.classList.remove("active")},addToFocusSet(m){for(const y of m)E.nodeIds.add(y);R(),C()},clearFocusSet(){E.types.clear(),E.nodeIds.clear(),R(),C()},setData(m){s=m,f=null,E.types.clear(),E.nodeIds.clear(),s&&s.nodes.length>0?(r=Y(s),_.classList.remove("hidden"),C()):(r=null,_.classList.add("hidden"),T.classList.add("hidden"))},setSnapshots(m){I=m,F==="controls"&&O()},setWalkTrail(m){D=m,C()}}}function io(t){const e=Date.now()-new Date(t).getTime(),s=Math.floor(e/6e4);if(s<1)return"just now";if(s<60)return`${s}m ago`;const r=Math.floor(s/60);return r<24?`${r}h ago`:`${Math.floor(r/24)}d ago`}function dn(t){for(const e of Object.values(t))if(typeof e=="string")return e;return null}function co(t,e){const s=e.split("+"),r=s.pop(),l=s.map(o=>o.toLowerCase()),f=l.includes("ctrl")||l.includes("cmd")||l.includes("meta"),b=l.includes("shift"),i=l.includes("alt");return f!==(t.ctrlKey||t.metaKey)||!f&&(t.ctrlKey||t.metaKey)||b&&!t.shiftKey||i!==t.altKey?!1:r.toLowerCase()==="escape"?t.key==="Escape":r.toLowerCase()==="tab"?t.key==="Tab":l.length>0?t.key.toLowerCase()===r.toLowerCase():t.key===r}function lo(){return{search:"Focus search",searchAlt:"Focus search (alt)",undo:"Undo",redo:"Redo",help:"Toggle help",escape:"Exit focus / close panel",focus:"Focus on selected / exit focus",toggleEdges:"Toggle edges on/off",center:"Center view on graph",nextNode:"Next node in view",prevNode:"Previous node in view",nextConnection:"Next connection",prevConnection:"Previous connection",historyBack:"Node history back",historyForward:"Node history forward",hopsIncrease:"Increase hops",hopsDecrease:"Decrease hops",panLeft:"Pan left",panDown:"Pan down",panUp:"Pan up",panRight:"Pan right",panFastLeft:"Pan fast left",zoomOut:"Zoom out",zoomIn:"Zoom in",panFastRight:"Pan fast right",spacingDecrease:"Decrease spacing",spacingIncrease:"Increase spacing",clusteringDecrease:"Decrease clustering",clusteringIncrease:"Increase clustering",toggleSidebar:"Toggle sidebar",walkMode:"Toggle walk mode (in focus)",walkIsolate:"Isolate walk trail nodes"}}const ro=[{key:"Click",description:"Select node"},{key:"Ctrl+Click",description:"Multi-select nodes"},{key:"Drag",description:"Pan canvas"},{key:"Scroll",description:"Zoom in/out"}],po=["search","searchAlt","undo","redo","help","focus","toggleEdges","center","nextNode","prevNode","nextConnection","prevConnection","historyBack","historyForward","hopsIncrease","hopsDecrease","panLeft","panDown","panUp","panRight","panFastLeft","panFastRight","zoomIn","zoomOut","spacingDecrease","spacingIncrease","clusteringDecrease","clusteringIncrease","toggleSidebar","walkMode","walkIsolate","escape"];function uo(t){return t.split("+").map(e=>e.charAt(0).toUpperCase()+e.slice(1)).join("+")}function mo(t,e){const s=lo(),r=document.createElement("div");r.className="shortcuts-overlay hidden";const l=document.createElement("div");l.className="shortcuts-modal";const f=document.createElement("h3");f.className="shortcuts-title",f.textContent="Keyboard Shortcuts";const b=document.createElement("div");b.className="shortcuts-list";for(const a of po){const I=e[a];if(!I)continue;const D=document.createElement("div");D.className="shortcuts-row";const E=document.createElement("div");E.className="shortcuts-keys";const K=document.createElement("kbd");K.textContent=uo(I),E.appendChild(K);const J=document.createElement("span");J.className="shortcuts-desc",J.textContent=s[a],D.appendChild(E),D.appendChild(J),b.appendChild(D)}for(const a of ro){const I=document.createElement("div");I.className="shortcuts-row";const D=document.createElement("div");D.className="shortcuts-keys";const E=document.createElement("kbd");E.textContent=a.key,D.appendChild(E);const K=document.createElement("span");K.className="shortcuts-desc",K.textContent=a.description,I.appendChild(D),I.appendChild(K),b.appendChild(I)}const i=document.createElement("button");i.className="shortcuts-close",i.textContent="×",l.appendChild(i),l.appendChild(f),l.appendChild(b),r.appendChild(l),t.appendChild(r);function o(){r.classList.remove("hidden")}function F(){r.classList.add("hidden")}function c(){r.classList.toggle("hidden")}return i.addEventListener("click",F),r.addEventListener("click",a=>{a.target===r&&F()}),{show:o,hide:F,toggle:c}}function ho(t){const e=document.createElement("div");return e.className="empty-state",e.innerHTML=`
|
|
5
|
-
<div class="empty-state-bg">
|
|
6
|
-
<div class="empty-state-circle c1"></div>
|
|
7
|
-
<div class="empty-state-circle c2"></div>
|
|
8
|
-
<div class="empty-state-circle c3"></div>
|
|
9
|
-
<div class="empty-state-circle c4"></div>
|
|
10
|
-
<div class="empty-state-circle c5"></div>
|
|
11
|
-
<svg class="empty-state-lines" viewBox="0 0 400 300" preserveAspectRatio="xMidYMid slice">
|
|
12
|
-
<line x1="80" y1="60" x2="220" y2="140" stroke="currentColor" stroke-width="0.5" opacity="0.15"/>
|
|
13
|
-
<line x1="220" y1="140" x2="320" y2="80" stroke="currentColor" stroke-width="0.5" opacity="0.15"/>
|
|
14
|
-
<line x1="220" y1="140" x2="160" y2="240" stroke="currentColor" stroke-width="0.5" opacity="0.15"/>
|
|
15
|
-
<line x1="160" y1="240" x2="300" y2="220" stroke="currentColor" stroke-width="0.5" opacity="0.15"/>
|
|
16
|
-
</svg>
|
|
17
|
-
</div>
|
|
18
|
-
<div class="empty-state-content">
|
|
19
|
-
<div class="empty-state-icon">
|
|
20
|
-
<svg width="48" height="48" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round">
|
|
21
|
-
<path d="M21 16V8a2 2 0 00-1-1.73l-7-4a2 2 0 00-2 0l-7 4A2 2 0 002 8v8a2 2 0 001 1.73l7 4a2 2 0 002 0l7-4A2 2 0 0022 16z"/>
|
|
22
|
-
<polyline points="3.27 6.96 12 12.01 20.73 6.96"/>
|
|
23
|
-
<line x1="12" y1="22.08" x2="12" y2="12"/>
|
|
24
|
-
</svg>
|
|
25
|
-
</div>
|
|
26
|
-
<h2 class="empty-state-title">No learning graphs yet</h2>
|
|
27
|
-
<p class="empty-state-desc">Connect Backpack to Claude, then start a conversation. Claude will build your first learning graph automatically.</p>
|
|
28
|
-
<div class="empty-state-setup">
|
|
29
|
-
<div class="empty-state-label">Add Backpack to Claude Code:</div>
|
|
30
|
-
<code class="empty-state-code">claude mcp add backpack-local -s user -- npx backpack-ontology@latest</code>
|
|
31
|
-
</div>
|
|
32
|
-
<p class="empty-state-hint">Press <kbd>?</kbd> for keyboard shortcuts</p>
|
|
33
|
-
</div>
|
|
34
|
-
`,t.appendChild(e),{show(){e.classList.remove("hidden")},hide(){e.classList.add("hidden")}}}const fo=30;function go(){let t=[],e=[];return{push(s){t.push(JSON.stringify(s)),t.length>fo&&t.shift(),e=[]},undo(s){return t.length===0?null:(e.push(JSON.stringify(s)),JSON.parse(t.pop()))},redo(s){return e.length===0?null:(t.push(JSON.stringify(s)),JSON.parse(e.pop()))},canUndo(){return t.length>0},canRedo(){return e.length>0},clear(){t=[],e=[]}}}function yo(t,e){let s=null;function r(b,i,o,F,c){l(),s=document.createElement("div"),s.className="context-menu",s.style.left=`${F}px`,s.style.top=`${c}px`;const a=[{label:o?"★ Unstar":"☆ Star",action:()=>e.onStar(b),premium:!1},{label:"◎ Focus on node",action:()=>e.onFocusNode(b),premium:!1},{label:"⑂ Explore in branch",action:()=>e.onExploreInBranch(b),premium:!1},{label:"⎘ Copy ID",action:()=>e.onCopyId(b),premium:!1}];e.onExpand&&a.push({label:"⊕ Expand node",action:()=>e.onExpand(b),premium:!0}),e.onExplainPath&&a.push({label:"↔ Explain path to…",action:()=>e.onExplainPath(b),premium:!0}),e.onEnrich&&a.push({label:"≡ Enrich from web",action:()=>e.onEnrich(b),premium:!0});let I=!1;for(const E of a){if(!I&&E.premium){const J=document.createElement("div");J.className="context-menu-separator",s.appendChild(J),I=!0}const K=document.createElement("div");K.className="context-menu-item",K.textContent=E.label,K.addEventListener("click",()=>{E.action(),l()}),s.appendChild(K)}t.appendChild(s);const D=s.getBoundingClientRect();D.right>window.innerWidth&&(s.style.left=`${F-D.width}px`),D.bottom>window.innerHeight&&(s.style.top=`${c-D.height}px`),setTimeout(()=>document.addEventListener("click",l),0),document.addEventListener("keydown",f)}function l(){s&&(s.remove(),s=null),document.removeEventListener("click",l),document.removeEventListener("keydown",f)}function f(b){b.key==="Escape"&&l()}return{show:r,hide:l}}const Co={search:"/",searchAlt:"ctrl+k",undo:"ctrl+z",redo:"ctrl+shift+z",help:"?",escape:"Escape",focus:"f",toggleEdges:"e",center:"c",nextNode:".",prevNode:",",nextConnection:">",prevConnection:"<",historyBack:"(",historyForward:")",hopsIncrease:"=",hopsDecrease:"-",panLeft:"h",panDown:"j",panUp:"k",panRight:"l",panFastLeft:"H",zoomOut:"J",zoomIn:"K",panFastRight:"L",spacingDecrease:"[",spacingIncrease:"]",clusteringDecrease:"{",clusteringIncrease:"}",toggleSidebar:"Tab",walkMode:"w",walkIsolate:"i"},vo={edges:!0,edgeLabels:!0,typeHulls:!0,minimap:!0,theme:"system"},xo={spacing:1.5,clustering:.08},Eo={panSpeed:60,panFastMultiplier:3,zoomFactor:1.3,zoomMin:.05,zoomMax:10,panAnimationMs:300},bo={hideBadges:.4,hideLabels:.25,hideEdgeLabels:.35,smallNodes:.2,hideArrows:.15},wo={pulseSpeed:.02},ko={maxSearchResults:8,maxQualityItems:5,maxMostConnected:5,searchDebounceMs:150},So={keybindings:Co,display:vo,layout:xo,navigation:Eo,lod:bo,walk:wo,limits:ko};let de="",w=null,It=new Set,Mt=!1;async function No(){const t=document.getElementById("canvas-container"),e={...So};try{const n=await fetch("/api/config");if(n.ok){const u=await n.json();Object.assign(e.keybindings,u.keybindings??{}),Object.assign(e.display,u.display??{}),Object.assign(e.layout,u.layout??{}),Object.assign(e.navigation,u.navigation??{}),Object.assign(e.lod,u.lod??{}),Object.assign(e.limits,u.limits??{})}}catch{}const s=e.keybindings,r=window.matchMedia("(prefers-color-scheme: dark)"),l=e.display.theme==="system"?r.matches?"dark":"light":e.display.theme,b=localStorage.getItem("backpack-theme")??l;document.documentElement.setAttribute("data-theme",b);const i=document.createElement("button");i.className="theme-toggle",i.textContent=b==="light"?"☾":"☼",i.title="Toggle light/dark mode",i.addEventListener("click",()=>{const u=document.documentElement.getAttribute("data-theme")==="light"?"dark":"light";document.documentElement.setAttribute("data-theme",u),localStorage.setItem("backpack-theme",u),i.textContent=u==="light"?"☾":"☼"}),t.appendChild(i);const o=go();async function F(){if(!de||!w)return;w.metadata.updatedAt=new Date().toISOString(),await wt(de,w),a.loadGraph(w),z.setLearningGraphData(w),j.setData(w);const n=await mt();Y.setSummaries(n)}async function c(n){w=n,await wt(de,w),a.loadGraph(w),z.setLearningGraphData(w),j.setData(w);const u=await mt();Y.setSummaries(u)}let a;const I=to(t,{onUpdateNode(n,u){if(!w)return;o.push(w);const h=w.nodes.find(G=>G.id===n);h&&(h.properties={...h.properties,...u},h.updatedAt=new Date().toISOString(),F().then(()=>I.show([n],w)))},onChangeNodeType(n,u){if(!w)return;o.push(w);const h=w.nodes.find(G=>G.id===n);h&&(h.type=u,h.updatedAt=new Date().toISOString(),F().then(()=>I.show([n],w)))},onDeleteNode(n){w&&(o.push(w),w.nodes=w.nodes.filter(u=>u.id!==n),w.edges=w.edges.filter(u=>u.sourceId!==n&&u.targetId!==n),F())},onDeleteEdge(n){var h;if(!w)return;o.push(w);const u=(h=w.edges.find(G=>G.id===n))==null?void 0:h.sourceId;w.edges=w.edges.filter(G=>G.id!==n),F().then(()=>{u&&w&&I.show([u],w)})},onAddProperty(n,u,h){if(!w)return;o.push(w);const G=w.nodes.find(se=>se.id===n);G&&(G.properties[u]=h,G.updatedAt=new Date().toISOString(),F().then(()=>I.show([n],w)))}},n=>{a.panToNode(n)},n=>{j.addToFocusSet(n)}),D=window.matchMedia("(max-width: 768px)");let E=[],K=e.display.edges,J=e.navigation.panSpeed,ae=-1,R=null;function _(n){R&&R.remove(),R=document.createElement("div"),R.className="focus-indicator";const u=document.createElement("span");u.className="focus-indicator-label",u.textContent=`Focused: ${n.totalNodes} nodes`;const h=document.createElement("span");h.className="focus-indicator-hops",h.textContent=`${n.hops}`;const G=document.createElement("button");G.className="focus-indicator-btn",G.textContent="−",G.title="Fewer hops",G.disabled=n.hops===0,G.addEventListener("click",()=>{a.enterFocus(n.seedNodeIds,Math.max(0,n.hops-1))});const se=document.createElement("button");se.className="focus-indicator-btn",se.textContent="+",se.title="More hops",se.disabled=!1,se.addEventListener("click",()=>{a.enterFocus(n.seedNodeIds,n.hops+1)});const me=document.createElement("button");me.className="focus-indicator-btn focus-indicator-exit",me.textContent="×",me.title="Exit focus (Esc)",me.addEventListener("click",()=>j.clearFocusSet());const ue=document.createElement("button");ue.className="walk-indicator",a.getWalkMode()&&ue.classList.add("active"),ue.textContent="Walk",ue.title="Toggle walk mode (W) — click nodes to traverse",ue.addEventListener("click",()=>{a.setWalkMode(!a.getWalkMode()),ue.classList.toggle("active",a.getWalkMode())}),R.appendChild(u),R.appendChild(G),R.appendChild(h),R.appendChild(se),R.appendChild(ue),R.appendChild(me)}function T(){R&&(R.remove(),R=null)}const C=document.createElement("div");C.className="path-bar hidden",t.appendChild(C);function O(n){if(C.innerHTML="",!w)return;for(let h=0;h<n.nodeIds.length;h++){const G=n.nodeIds[h],se=w.nodes.find(ie=>ie.id===G);if(!se)continue;const me=Object.values(se.properties).find(ie=>typeof ie=="string")??se.id;if(h>0){const ie=n.edgeIds[h-1],Se=w.edges.find($e=>$e.id===ie),we=document.createElement("span");we.className="path-bar-edge",we.textContent=Se?`→ ${Se.type} →`:"→",C.appendChild(we)}const ue=document.createElement("span");ue.className="path-bar-node",ue.textContent=me,ue.addEventListener("click",()=>a.panToNode(G)),C.appendChild(ue)}const u=document.createElement("button");u.className="path-bar-close",u.textContent="×",u.addEventListener("click",q),C.appendChild(u),C.classList.remove("hidden")}function q(){C.classList.add("hidden"),C.innerHTML="",a.clearHighlightedPath()}a=Qn(t,n=>{if(E=n??[],!a.getWalkMode())if(n&&n.length===2){const u=a.findPath(n[0],n[1]);u&&u.nodeIds.length>0?(a.setHighlightedPath(u.nodeIds,u.edgeIds),O(u)):q()}else q();n&&n.length>0&&w?(I.show(n,w),D.matches&&j.collapse(),A(de,n)):(I.hide(),de&&A(de))},n=>{if(n){_(n);const u=t.querySelector(".canvas-top-left");u&&R&&u.appendChild(R),A(de,n.seedNodeIds),I.setFocusDisabled(n.hops===0),m()}else T(),I.setFocusDisabled(!1),de&&A(de),m()},{lod:e.lod,navigation:e.navigation,walk:e.walk});const z=so(t,{maxResults:e.limits.maxSearchResults,debounceMs:e.limits.searchDebounceMs}),j=ao(t,{onFilterByType(n){if(w)if(n===null)a.setFilteredNodeIds(null);else{const u=new Set(((w==null?void 0:w.nodes)??[]).filter(h=>h.type===n).map(h=>h.id));a.setFilteredNodeIds(u)}},onNavigateToNode(n){a.panToNode(n),w&&I.show([n],w)},onWalkTrailRemove(n){a.removeFromWalkTrail(n),m()},onWalkIsolate(){if(!w)return;const n=a.getWalkTrail();n.length!==0&&a.enterFocus(n,0)},async onWalkSaveSnippet(n){if(!de||!w)return;const u=a.getWalkTrail();if(u.length<2)return;const h=new Set(u),G=w.edges.filter(se=>h.has(se.sourceId)&&h.has(se.targetId)).map(se=>se.id);await Xt(de,n,u,G),await L(de)},async onStarredSaveSnippet(n,u){if(!de||!w)return;const h=new Set(u),G=w.edges.filter(se=>h.has(se.sourceId)&&h.has(se.targetId)).map(se=>se.id);await Xt(de,n,u,G),await L(de)},onFocusChange(n){n&&n.length>0?a.enterFocus(n,0):a.isFocused()&&a.exitFocus()},onRenameNodeType(n,u){if(w){o.push(w);for(const h of w.nodes)h.type===n&&(h.type=u,h.updatedAt=new Date().toISOString());F()}},onRenameEdgeType(n,u){if(w){o.push(w);for(const h of w.edges)h.type===n&&(h.type=u);F()}},onToggleEdgeLabels(n){a.setEdgeLabels(n)},onToggleTypeHulls(n){a.setTypeHulls(n)},onToggleMinimap(n){a.setMinimap(n)},onLayoutChange(n,u){Ze({[n]:u}),a.reheat()},onPanSpeedChange(n){J=n},onExport(n){const u=a.exportImage(n);if(!u)return;const h=document.createElement("a");h.download=`${de||"graph"}.${n}`,h.href=u,h.click()},onSnapshot:async n=>{de&&(await Tn(de,n),await S(de))},onRollback:async n=>{de&&(await An(de,n),w=await ht(de),a.loadGraph(w),z.setLearningGraphData(w),j.setData(w),await S(de))},onOpen(){D.matches&&I.hide()}}),Z=document.createElement("div");Z.className="canvas-top-bar";const H=document.createElement("div");H.className="canvas-top-left";const ce=document.createElement("div");ce.className="canvas-top-center";const ve=document.createElement("div");ve.className="canvas-top-right";const pe=t.querySelector(".tools-pane-toggle");pe&&H.appendChild(pe);const re=t.querySelector(".search-overlay");re&&ce.appendChild(re);const ge=t.querySelector(".zoom-controls");ge&&ve.appendChild(ge),ve.appendChild(i),Z.appendChild(H),Z.appendChild(ce),Z.appendChild(ve),t.appendChild(Z),z.onFilterChange(n=>{a.setFilteredNodeIds(n)}),z.onNodeSelect(n=>{a.isFocused()&&j.clearFocusSet(),a.panToNode(n),w&&I.show([n],w)});const Y=Pn(document.getElementById("sidebar"),{onSelect:n=>W(n),onRename:async(n,u)=>{await Nn(n,u),de===n&&(de=u);const h=await mt();Y.setSummaries(h),Y.setActive(de),de===u&&(w=await ht(u),a.loadGraph(w),z.setLearningGraphData(w),j.setData(w))},onBranchSwitch:async(n,u)=>{await Yt(n,u),await y(n),w=await ht(n),a.loadGraph(w),z.setLearningGraphData(w),j.setData(w),await S(n)},onBranchCreate:async(n,u)=>{await qt(n,u),await y(n)},onBranchDelete:async(n,u)=>{await In(n,u),await y(n)},onSnippetLoad:async(n,u)=>{var G;const h=await Bn(n,u);((G=h==null?void 0:h.nodeIds)==null?void 0:G.length)>0&&a.enterFocus(h.nodeIds,0)},onSnippetDelete:async(n,u)=>{await Fn(n,u),await L(n)}});function m(){const n=a.getWalkTrail();if(!w||n.length===0){j.setWalkTrail([]),q();return}const u=[],h=n.map((G,se)=>{const me=w.nodes.find(ie=>ie.id===G);let ue;if(se>0){const ie=n[se-1],Se=w.edges.find(we=>we.sourceId===ie&&we.targetId===G||we.targetId===ie&&we.sourceId===G);ue=Se==null?void 0:Se.type,Se&&u.push(Se.id)}return{id:G,label:me?Object.values(me.properties).find(ie=>typeof ie=="string")??me.id:G,type:(me==null?void 0:me.type)??"?",edgeType:ue}});j.setWalkTrail(h),n.length>=2?(a.setHighlightedPath(n,u),O({nodeIds:n,edgeIds:u})):q()}async function y(n){const u=await Ln(n),h=u.find(G=>G.active);h&&Y.setActiveBranch(n,h.name,u)}async function S(n){const u=await Mn(n);j.setSnapshots(u)}async function L(n){const u=await Rn(n);Y.setSnippets(n,u)}H.insertBefore(Y.expandBtn,H.firstChild);const B=mo(t,s),g=ho(t),N=yo(t,{onStar(n){if(!w)return;const u=w.nodes.find(G=>G.id===n);if(!u)return;const h=u.properties._starred===!0;u.properties._starred=!h,wt(de,w),a.loadGraph(w)},onFocusNode(n){j.addToFocusSet([n])},onExploreInBranch(n){if(de){const u=`explore-${n.slice(0,8)}`;qt(de,u).then(()=>{Yt(de,u).then(()=>{a.enterFocus([n],1)})})}},onCopyId(n){navigator.clipboard.writeText(n)}});t.addEventListener("contextmenu",n=>{n.preventDefault();const u=t.querySelector("canvas");if(!u||!w)return;const h=u.getBoundingClientRect(),G=n.clientX-h.left,se=n.clientY-h.top,me=a.nodeAtScreen(G,se);if(!me)return;const ue=w.nodes.find(we=>we.id===me.id);if(!ue)return;const ie=Object.values(ue.properties).find(we=>typeof we=="string")??ue.id,Se=ue.properties._starred===!0;N.show(ue.id,ie,Se,n.clientX-h.left,n.clientY-h.top)}),e.display.edges||a.setEdges(!1),e.display.edgeLabels||a.setEdgeLabels(!1),e.display.typeHulls||a.setTypeHulls(!1),e.display.minimap||a.setMinimap(!1);function A(n,u){const h=[];u!=null&&u.length&&h.push("node="+u.map(encodeURIComponent).join(","));const G=a.getFocusInfo();G&&(h.push("focus="+G.seedNodeIds.map(encodeURIComponent).join(",")),h.push("hops="+G.hops));const se="#"+encodeURIComponent(n)+(h.length?"?"+h.join("&"):"");history.replaceState(null,"",se)}function P(){const n=window.location.hash.slice(1);if(!n)return{graph:null,nodes:[],focus:[],hops:1};const[u,h]=n.split("?"),G=u?decodeURIComponent(u):null;let se=[],me=[],ue=1;if(h){const ie=new URLSearchParams(h),Se=ie.get("node");Se&&(se=Se.split(",").map(decodeURIComponent));const we=ie.get("focus");we&&(me=we.split(",").map(decodeURIComponent));const $e=ie.get("hops");$e&&(ue=Math.max(0,parseInt($e,10)||1))}return{graph:G,nodes:se,focus:me,hops:ue}}async function W(n,u,h,G){de=n,Mt=It.has(n),Y.setActive(n),I.hide(),T(),z.clear(),o.clear(),w=Mt?await Sn(n):await ht(n);const se=Hn(w.nodes.length);if(Ze({spacing:Math.max(e.layout.spacing,se.spacing),clusterStrength:Math.max(e.layout.clustering,se.clusterStrength)}),a.loadGraph(w),z.setLearningGraphData(w),j.setData(w),g.hide(),A(n),Mt||(await y(n),await S(n),await L(n)),h!=null&&h.length&&w){const me=h.filter(ue=>w.nodes.some(ie=>ie.id===ue));if(me.length){setTimeout(()=>{a.enterFocus(me,G??1)},500);return}}if(u!=null&&u.length&&w){const me=u.filter(ue=>w.nodes.some(ie=>ie.id===ue));me.length&&setTimeout(()=>{a.panToNodes(me),w&&I.show(me,w),A(n,me)},500)}}const[k,p]=await Promise.all([mt(),kn().catch(()=>[])]);Y.setSummaries(k),Y.setRemotes(p),It=new Set(p.map(n=>n.name));const x=P(),Q=x.graph&&k.some(n=>n.name===x.graph)||x.graph&&It.has(x.graph)?x.graph:k.length>0?k[0].name:p.length>0?p[0].name:null;Q?await W(Q,x.nodes.length?x.nodes:void 0,x.focus.length?x.focus:void 0,x.hops):g.show();const te={search(){z.focus()},searchAlt(){z.focus()},undo(){if(w){const n=o.undo(w);n&&c(n)}},redo(){if(w){const n=o.redo(w);n&&c(n)}},focus(){a.isFocused()?j.clearFocusSet():E.length>0&&j.addToFocusSet(E)},hopsDecrease(){const n=a.getFocusInfo();n&&n.hops>0&&a.enterFocus(n.seedNodeIds,n.hops-1)},hopsIncrease(){const n=a.getFocusInfo();n&&a.enterFocus(n.seedNodeIds,n.hops+1)},nextNode(){const n=a.getNodeIds();n.length>0&&(ae=(ae+1)%n.length,a.panToNode(n[ae]),w&&I.show([n[ae]],w))},prevNode(){const n=a.getNodeIds();n.length>0&&(ae=ae<=0?n.length-1:ae-1,a.panToNode(n[ae]),w&&I.show([n[ae]],w))},nextConnection(){const n=I.cycleConnection(1);n&&a.panToNode(n)},prevConnection(){const n=I.cycleConnection(-1);n&&a.panToNode(n)},historyBack(){I.goBack()},historyForward(){I.goForward()},center(){a.centerView()},toggleEdges(){K=!K,a.setEdges(K)},panLeft(){a.panBy(-J,0)},panDown(){a.panBy(0,J)},panUp(){a.panBy(0,-J)},panRight(){a.panBy(J,0)},panFastLeft(){a.panBy(-J*e.navigation.panFastMultiplier,0)},zoomOut(){a.zoomBy(1/e.navigation.zoomFactor)},zoomIn(){a.zoomBy(e.navigation.zoomFactor)},panFastRight(){a.panBy(J*e.navigation.panFastMultiplier,0)},spacingDecrease(){const n=lt();Ze({spacing:Math.max(.5,n.spacing-.5)}),a.reheat()},spacingIncrease(){const n=lt();Ze({spacing:Math.min(20,n.spacing+.5)}),a.reheat()},clusteringDecrease(){const n=lt();Ze({clusterStrength:Math.max(0,n.clusterStrength-.03)}),a.reheat()},clusteringIncrease(){const n=lt();Ze({clusterStrength:Math.min(1,n.clusterStrength+.03)}),a.reheat()},help(){B.toggle()},toggleSidebar(){Y.toggle()},walkIsolate(){if(!w)return;const n=a.getWalkTrail();n.length!==0&&a.enterFocus(n,0)},walkMode(){!a.isFocused()&&E.length>0&&j.addToFocusSet(E),a.setWalkMode(!a.getWalkMode());const n=t.querySelector(".walk-indicator");n&&n.classList.toggle("active",a.getWalkMode()),m()},escape(){a.isFocused()?j.clearFocusSet():B.hide()}};document.addEventListener("keydown",n=>{var u;if(!(n.target instanceof HTMLInputElement||n.target instanceof HTMLTextAreaElement)){for(const[h,G]of Object.entries(s))if(co(n,G)){(h==="search"||h==="searchAlt"||h==="undo"||h==="redo"||h==="toggleSidebar")&&n.preventDefault(),(u=te[h])==null||u.call(te);return}}}),window.addEventListener("hashchange",()=>{const n=P();if(n.graph&&n.graph!==de)W(n.graph,n.nodes.length?n.nodes:void 0,n.focus.length?n.focus:void 0,n.hops);else if(n.graph&&n.focus.length&&w)a.enterFocus(n.focus,n.hops);else if(n.graph&&n.nodes.length&&w){a.isFocused()&&a.exitFocus();const u=n.nodes.filter(h=>w.nodes.some(G=>G.id===h));u.length&&(a.panToNodes(u),I.show(u,w))}})}No();
|