viteboard 0.1.7 → 0.1.8
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.
|
@@ -1,40 +1,40 @@
|
|
|
1
|
-
var Cs=Object.defineProperty;var ks=(i,t,e)=>t in i?Cs(i,t,{enumerable:!0,configurable:!0,writable:!0,value:e}):i[t]=e;var u=(i,t,e)=>ks(i,typeof t!="symbol"?t+"":t,e);(function(){const t=document.createElement("link").relList;if(t&&t.supports&&t.supports("modulepreload"))return;for(const s of document.querySelectorAll('link[rel="modulepreload"]'))n(s);new MutationObserver(s=>{for(const o of s)if(o.type==="childList")for(const a of o.addedNodes)a.tagName==="LINK"&&a.rel==="modulepreload"&&n(a)}).observe(document,{childList:!0,subtree:!0});function e(s){const o={};return s.integrity&&(o.integrity=s.integrity),s.referrerPolicy&&(o.referrerPolicy=s.referrerPolicy),s.crossOrigin==="use-credentials"?o.credentials="include":s.crossOrigin==="anonymous"?o.credentials="omit":o.credentials="same-origin",o}function n(s){if(s.ep)return;s.ep=!0;const o=e(s);fetch(s.href,o)}})();const $="/__api";class se extends Error{constructor(e,n){super(e);u(this,"currentRevision");this.name="RevisionConflictError",this.currentRevision=n}}async function D(i){var t;if(!i.ok){let e="";try{e=((t=await i.json())==null?void 0:t.error)??""}catch{}throw new Error(`${i.status} ${i.statusText}${e?` — ${e}`:""}`)}return i.json()}function A(i={}){return i}const k={async getWorkspace(){return D(await fetch(`${$}/workspace`,A()))},async removeProject(i){await D(await fetch(`${$}/workspace/project?id=${encodeURIComponent(i)}`,A({method:"DELETE"})))},async pickAndAddProject(){return D(await fetch(`${$}/workspace/pick-project`,A({method:"POST"})))},async ensureProjectDocsRoot(i){return(await D(await fetch(`${$}/workspace/project/docs-root`,A({method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({projectId:i})})))).root},async getTree(i){return(await D(await fetch(`${$}/tree?rootId=${encodeURIComponent(i)}`,A()))).tree},async getProjectTree(i){return(await D(await fetch(`${$}/project-tree?projectId=${encodeURIComponent(i)}`,A()))).tree},async createDocsFolder(i,t){await D(await fetch(`${$}/workspace/project/create-docs-folder`,A({method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({projectId:i,parentPath:t})})))},async readFile(i,t){return(await D(await fetch(`${$}/file?rootId=${encodeURIComponent(i)}&path=${encodeURIComponent(t)}`,A()))).content},async readFileWithRevision(i,t){return D(await fetch(`${$}/file?rootId=${encodeURIComponent(i)}&path=${encodeURIComponent(t)}`,A()))},async writeFile(i,t,e,n){const s=await fetch(`${$}/file`,A({method:"PUT",headers:{"Content-Type":"application/json"},body:JSON.stringify({rootId:i,path:t,content:e,expectedRevision:n})}));if(s.status===409){const a=await s.json();throw new se(a.error??"File changed on disk",a.currentRevision??null)}return(await D(s)).revision},async createDirectory(i,t){await D(await fetch(`${$}/directory`,A({method:"PUT",headers:{"Content-Type":"application/json"},body:JSON.stringify({rootId:i,path:t})})))},async getBoard(i,t){const e=await fetch(`${$}/board?rootId=${encodeURIComponent(i)}&id=${encodeURIComponent(t)}`,A());return e.status===404?null:(await D(e)).doc},async getBoardWithRevision(i,t){const e=await fetch(`${$}/board?rootId=${encodeURIComponent(i)}&id=${encodeURIComponent(t)}`,A());return e.status===404?null:D(e)},async saveBoard(i,t,e,n){const s=await fetch(`${$}/board`,A({method:"PUT",headers:{"Content-Type":"application/json"},body:JSON.stringify({rootId:i,id:t,doc:e,expectedRevision:n})}));if(s.status===409){const a=await s.json();throw new se(a.error??"Board changed on disk",a.currentRevision??null)}return(await D(s)).revision},async deleteFile(i,t){await D(await fetch(`${$}/file?rootId=${encodeURIComponent(i)}&path=${encodeURIComponent(t)}`,A({method:"DELETE"})))},async renameFile(i,t,e,n=!1){await D(await fetch(`${$}/file`,A({method:"PATCH",headers:{"Content-Type":"application/json"},body:JSON.stringify({rootId:i,oldPath:t,newPath:e,ignoreMissing:n})})))},async deleteBoard(i,t){await D(await fetch(`${$}/board?rootId=${encodeURIComponent(i)}&id=${encodeURIComponent(t)}`,A({method:"DELETE"})))},assetUrl(i,t){return`${$}/asset?rootId=${encodeURIComponent(i)}&path=${encodeURIComponent(t)}`},async uploadAsset(i,t,e,n){return(await D(await fetch(`${$}/asset`,A({method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({rootId:i,name:t,base64:e,mimeType:n})})))).path},async cleanupManagedAssets(i,t=[]){return(await D(await fetch(`${$}/asset/cleanup`,A({method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({rootId:i,preservePaths:t})})))).removed}};function Es(i,t){const e=i.find(o=>o.type==="dir"&&o.name===t);if(!e||e.type!=="dir")return[];const n=[],s=o=>{for(const a of o)a.type==="file"?n.push(a):s(a.children)};return s(e.children),n}function Ue(i){for(const t of i){if(t.type==="file"&&t.name.endsWith(".md"))return t.path;if(t.type==="dir"){const e=Ue(t.children);if(e)return e}}return null}function wt(i){const t=[];for(const e of i.replace(/\\/g,"/").split("/")){const n=e.trim();if(!(!n||n===".")){if(n===".."){t.length>0&&t.pop();continue}t.push(n)}}return t.join("/")}function qn(i){const t=wt(i),e=t.lastIndexOf("/");return e===-1?"":t.slice(0,e)}function Ss(i,t){if(/^(https?:|mailto:|tel:|#|data:)/.test(t))return t;if(t.startsWith("/"))return wt(t);const e=qn(i);return wt(e?`${e}/${t}`:t)}function Ye(i,t){const e=qn(i),n=e?e.split("/").filter(Boolean):[],s=wt(t).split("/").filter(Boolean);let o=0;for(;o<n.length&&o<s.length&&n[o]===s[o];)o++;const a=n.slice(o).map(()=>".."),r=s.slice(o);return[...a,...r].join("/")||s[s.length-1]||""}const Ts=["sticky","task","rectangle","ellipse","text","line","arrow","connector","image","screenshot","frame","templateGroup"];function ce(i){const t=new Set;for(const e of i.elements){const n=e.data.assetId;typeof n=="string"&&t.add(n)}return{...i.schemaUrl?{$schema:i.schemaUrl}:{},version:1,id:i.boardId,title:i.title,createdAt:i.createdAt,updatedAt:Date.now(),viewport:{...i.viewport},theme:i.theme,elements:i.elements,assetIds:[...t]}}function Y(i){return typeof i=="number"&&Number.isFinite(i)}function Yn(i){if(typeof i!="object"||i===null)return null;const t=i;return typeof t.id!="string"||typeof t.type!="string"||!Ts.includes(t.type)||!Y(t.x)||!Y(t.y)||!Y(t.width)||!Y(t.height)?null:{id:t.id,type:t.type,x:t.x,y:t.y,width:t.width,height:t.height,rotation:Y(t.rotation)?t.rotation:0,zIndex:Y(t.zIndex)?t.zIndex:0,locked:t.locked===!0,hidden:t.hidden===!0,createdAt:Y(t.createdAt)?t.createdAt:Date.now(),updatedAt:Y(t.updatedAt)?t.updatedAt:Date.now(),style:typeof t.style=="object"&&t.style!==null?t.style:{},data:typeof t.data=="object"&&t.data!==null?t.data:{}}}function we(i){if(typeof i!="object"||i===null)return null;const t=i;if(t.version!==1||typeof t.id!="string"||!Array.isArray(t.elements))return null;const e=[];for(const s of t.elements){const o=Yn(s);o&&e.push(o)}const n=t.viewport??{};return{...typeof t.$schema=="string"?{$schema:t.$schema}:{},version:1,id:t.id,title:typeof t.title=="string"?t.title.slice(0,200):"Imported Board",createdAt:Y(t.createdAt)?t.createdAt:Date.now(),updatedAt:Y(t.updatedAt)?t.updatedAt:Date.now(),viewport:{offsetX:Y(n.offsetX)?n.offsetX:0,offsetY:Y(n.offsetY)?n.offsetY:0,scale:Y(n.scale)&&n.scale>.01&&n.scale<=40?n.scale:1},theme:t.theme==="dark"?"dark":"light",elements:e,assetIds:Array.isArray(t.assetIds)?t.assetIds.filter(s=>typeof s=="string"):[]}}const Bs="/board-v1.schema.json",Ms=".board.json";function G(i){return i.replace(/\.board\.json$/,"")}function Is(i){return i.trim().replace(/^\/+/,"").replace(/\.board\.json$/,"")}function Rs(i,t){return re(i,t)[0]??""}function re(i,t){const e=i.trim(),n=Is(i);if(!n)return[];if(e.startsWith("./")||e.startsWith("../")){const r=t.lastIndexOf("/"),c=r===-1?"":t.slice(0,r);return[wt(c?`${c}/${n}`:n)]}if(e.startsWith("/")){const r=t.lastIndexOf("/"),c=r===-1?"":t.slice(0,r),l=wt(c?`${c}/${n}`:n),d=[n];if(l&&l!==n&&d.push(l),c){const h=c.includes("/")?c.slice(0,c.lastIndexOf("/")):"",p=wt(h?`${h}/${n}`:n);p&&!d.includes(p)&&d.push(p)}return d}const s=t.lastIndexOf("/"),o=s===-1?"":t.slice(0,s),a=wt(o?`${o}/${n}`:n);return a&&a!==n?[a,n]:[n]}function en(i){return i.toLowerCase().replace(/[^\w\s-]/g,"").trim().replace(/\s+/g,"-").slice(0,48)||"board"}function Ls(i){return new Promise((t,e)=>{const n=new FileReader;n.onload=()=>{const s=n.result;t(s.slice(s.indexOf(",")+1))},n.onerror=()=>e(n.error),n.readAsDataURL(i)})}const J={async listIds(i){const t=await k.getTree(i);return $s(t).map(e=>G(e.path))},async list(i){const t=await this.listIds(i),e=[];for(const n of t){const s=await this.load(i,n);s&&e.push({id:n,title:s.title,elementCount:s.elements.length,updatedAt:s.updatedAt,filePath:`${n}.board.json`})}return e.sort((n,s)=>s.updatedAt-n.updatedAt),e},async load(i,t){const e=await k.getBoard(i,t);if(e)return we(e)??void 0},async save(i,t){await k.saveBoard(i,t.id,t)},async delete(i,t){await k.deleteBoard(i,t)},async move(i,t,e){const n=await this.load(i,t);if(!n)throw new Error("Board not found");const s=t.split("/").pop()??t,o=e.replace(/^\/+|\/+$/g,""),a=o?`${o}/${s}`:s;if(a===t)return t;if(new Set(await this.listIds(i)).has(a))throw new Error("A board already exists there");const c=Date.now();return await k.saveBoard(i,a,{...n,id:a,updatedAt:c}),await k.deleteBoard(i,t),a},async rename(i,t,e){const n=await this.load(i,t);if(!n)throw new Error("Board not found");const s=t.includes("/")?t.slice(0,t.lastIndexOf("/")):"",o=en(e),a=s?`${s}/${o}`:o,r=Date.now();if(a===t)return await k.saveBoard(i,t,{...n,title:e.trim()||n.title,updatedAt:r}),t;if(new Set(await this.listIds(i)).has(a))throw new Error("A board already exists with that name");return await k.saveBoard(i,a,{...n,id:a,title:e.trim()||n.title,updatedAt:r}),await k.deleteBoard(i,t),a},async create(i,t,e,n=""){const s=new Set(await this.listIds(i)),o=en(t);let r=`${n?`${n.replace(/^\/+|\/+$/g,"")}/`:""}${o}`;s.has(r)&&(r=`${r}-${Date.now().toString(36)}`);const c=Date.now(),l={$schema:Bs,version:1,id:r,title:t.trim()||"Untitled Board",createdAt:c,updatedAt:c,viewport:{offsetX:0,offsetY:0,scale:1},theme:e,elements:[],assetIds:[]};return await k.saveBoard(i,r,l),r},async uploadImage(i,t,e){const n=await Ls(t);return k.uploadAsset(i,e??"image.png",n,t.type)},async cleanupUnusedAssets(i,t=[]){return k.cleanupManagedAssets(i,t)}};function $s(i){const t=[],e=n=>{for(const s of n)s.type==="file"?s.name.endsWith(Ms)&&t.push(s):e(s.children)};return e(i),t}const Ps=new Set(["capabilities","assets"]);class Ds{constructor(t,e){u(this,"element");u(this,"header");u(this,"nav");u(this,"footer");u(this,"links",new Map);u(this,"collapsibles",new Map);u(this,"collapsedState",new Map);u(this,"callbacks");u(this,"contextMenu");u(this,"draggedItem");u(this,"dropExpandTimer");u(this,"dropExpandTarget");u(this,"lastWorkspace",{projects:[]});u(this,"lastTreesByRoot",new Map);u(this,"lastTreesByProject",new Map);u(this,"rawModeProjects",new Set);u(this,"lastActiveHash","");u(this,"forceNextActiveSync",!0);this.callbacks=e,this.element=document.createElement("aside"),this.element.className="sidebar",this.header=document.createElement("div"),this.header.className="sidebar-header";const n=document.createElement("a");n.className="sidebar-brand",n.href="#/",n.textContent="ViteBoard",this.header.appendChild(n),this.nav=document.createElement("nav"),this.nav.className="sidebar-nav",this.footer=document.createElement("div"),this.footer.className="sidebar-footer";const s=document.createElement("button");s.className="sidebar-add-repo",s.type="button",s.textContent="Add Repo",s.title="Add a local project root",s.addEventListener("click",()=>this.callbacks.onAddRepo()),this.footer.appendChild(s),this.element.append(this.header,this.nav,this.footer),t.appendChild(this.element),document.addEventListener("pointerdown",o=>{this.contextMenu&&(this.contextMenu.contains(o.target)||this.closeContextMenu())},!0)}refresh(t,e,n){this.lastWorkspace=t,this.lastTreesByRoot=e,n&&(this.lastTreesByProject=n),this.render()}render(){const t=this.lastWorkspace,e=this.lastTreesByRoot;if(this.lastTreesByProject,this.nav.replaceChildren(),this.links.clear(),this.collapsibles.clear(),t.projects.length===0){const s=document.createElement("div");s.className="nav-group",s.appendChild(this.groupLabel("Workspace"));const o=document.createElement("div");o.className="nav-label nav-empty-copy",o.textContent="Add a project root to discover docs folders.",s.appendChild(o),this.nav.appendChild(s)}else for(const s of t.projects)this.nav.appendChild(this.projectSection(s,e));const n=document.createElement("div");n.className="nav-group",n.appendChild(this.groupLabel("System")),n.appendChild(this.link("#/tokens","Tokens","tokens-root")),this.nav.appendChild(n),this.setActive(location.hash,{forceSyncAncestors:this.forceNextActiveSync}),this.forceNextActiveSync=!1}setActive(t,e={}){var s,o;for(const a of new Set(this.links.values()))a.classList.remove("active");const n=this.links.get(t);if(n)n.classList.add("active");else if(t.startsWith("#/root/")){const a=t.match(/^#\/root\/([^/]+)\/(boards|capabilities|docs)(?:\/(.+))?$/);if(a){const[,r,c]=a,l=decodeURIComponent(r);c==="boards"?(s=this.links.get(Hs(l)))==null||s.classList.add("active"):c==="capabilities"&&((o=this.links.get(Fs(l)))==null||o.classList.add("active"))}}(e.forceSyncAncestors||t!==this.lastActiveHash)&&this.syncCollapsed(t),this.lastActiveHash=t}toggleRawMode(t){this.rawModeProjects.has(t)?this.rawModeProjects.delete(t):this.rawModeProjects.add(t),this.forceNextActiveSync=!0,this.render()}syncCollapsed(t){const e=this.ancestorKeys(t);for(const n of e)this.applyCollapsed(n,!1)}ancestorKeys(t){const e=new Set,n=t.match(/^#\/project\/([^/]+)(?:\/boards)?$/);if(n)return e.add(decodeURIComponent(n[1])),e;const s=t.match(/^#\/root\/([^/]+)\/(docs|boards|capabilities)(?:\/(.+))?$/);if(!s)return e;const o=decodeURIComponent(s[1]),a=s[2],r=s[3]?decodeURIComponent(s[3]):"";let c,l;for(const p of this.lastWorkspace.projects){const m=p.docsRoots.find(g=>g.id===o);if(m){c=p.id,l=m.displayPath;break}}if(!c||!l)return e;e.add(c),e.add(o);const d=l.split("/").filter(Boolean).slice(0,-1);let h="";for(const p of d){h=h?`${h}/${p}`:p;const m=`folder:${c}:${h}`;this.collapsibles.has(m)&&e.add(m)}if((a==="docs"||a==="capabilities")&&r){const m=(a==="capabilities"?`capabilities/${r}`:r).split("/");for(let g=1;g<m.length;g++){const y=m.slice(0,g).join("/"),b=`doc:${o}:${y}`;this.collapsibles.has(b)&&e.add(b)}}return e}projectSection(t,e){const{id:n,label:s,docsRoots:o}=t,a=this.rawModeProjects.has(n),r=document.createElement("div");r.className="nav-repo-body";const c=document.createElement("div");c.className="nav-group nav-repo-group";const l=document.createElement("div");l.className="nav-repo-header-row";const d=document.createElement("button");d.className="nav-repo-header",d.type="button";const h=document.createElement("span");h.className="nav-repo-chevron",h.textContent="›";const p=document.createElement("span");p.className="nav-repo-label-text",p.textContent=s;const m=!a&&o.find(v=>xt(v.displayPath)==="docs"),g=document.createElement("span");g.className="nav-tree-badge",g.textContent="DOCS",g.hidden=!m;const y=document.createElement("button");y.className="nav-repo-more",y.type="button",y.title="Project options",y.innerHTML='<svg viewBox="0 0 16 16" width="14" height="14" fill="currentColor"><circle cx="8" cy="3" r="1.3"/><circle cx="8" cy="8" r="1.3"/><circle cx="8" cy="13" r="1.3"/></svg>',y.addEventListener("click",v=>{v.stopPropagation();const S=y.getBoundingClientRect();this.showContextMenu(S.right+4,S.top,s,[{icon:a?Et:At,iconClass:a?"nav-ctx-doc":"nav-ctx-dir",label:a?"View: Docs":"View: Raw",action:()=>this.toggleRawMode(n)},{icon:$e,iconClass:"nav-ctx-edit",label:"Wiki",action:()=>{location.hash=`#/project/${encodeURIComponent(n)}`}},{kind:"divider"},{icon:Et,iconClass:"nav-ctx-doc",label:"New Doc",action:()=>this.callbacks.onCreateProjectDoc(n)},{icon:Dt,iconClass:"nav-ctx-board",label:"New Board",action:()=>this.callbacks.onCreateProjectBoard(n)},{icon:At,iconClass:"nav-ctx-dir",label:"New Directory",action:()=>this.callbacks.onCreateProjectDirectory(n)},{kind:"divider"},{icon:Vt,iconClass:"nav-ctx-delete",label:"Remove from workspace",action:()=>this.callbacks.onRemoveProject(n,s),danger:!0}])}),d.append(h,p,g),l.append(d,y),this.registerCollapsible(n,r,c,d,!0),d.addEventListener("click",()=>this.toggleCollapsible(n)),l.addEventListener("contextmenu",v=>{v.preventDefault(),v.stopPropagation(),y.click()});const b=Os(t,this.lastTreesByProject.get(n)??[],e),x=a?b:_e(ve(b));if(x.length===0){const v=document.createElement("div");v.className="nav-label nav-empty-copy",v.textContent="No folders found.",r.appendChild(v)}else r.appendChild(this.renderCanonicalNodes(t,x,0,a));return c.append(l,r),c}renderCanonicalNodes(t,e,n,s){const o=document.createElement("div");for(const a of Us(e)){if(a.kind==="doc"||a.kind==="board"||a.kind==="capability"||a.kind==="file"){o.appendChild(this.renderCanonicalFile(a,n));continue}const r=document.createElement("div");r.className="nav-tree-group",r.style.setProperty("--tree-depth",String(n));const c=document.createElement("div");c.className="nav-tree-children";const l=document.createElement("button");l.className="nav-tree-row nav-tree-folder"+(a.kind==="docsRoot"?" nav-tree-docs-root":"")+(a.docsContainerRoot?" nav-tree-docs-container":"")+(a.root?"":" nav-tree-scaffold"),l.type="button",l.style.setProperty("--tree-depth",String(n));const d=document.createElement("span");d.className="nav-repo-chevron",d.textContent="›";const h=_s(a);h&&l.classList.add("nav-tree-capability-folder");const p=document.createElement("span");if(p.textContent=a.name,l.appendChild(d),h&&l.insertAdjacentHTML("beforeend",Re),l.appendChild(p),a.kind==="docsRoot"||a.docsContainerRoot){const g=document.createElement("span");g.className="nav-tree-badge",g.textContent="DOCS",l.appendChild(g)}const m=a.kind==="docsRoot"||a.docsContainerRoot?(a.docsContainerRoot??a.root).id:a.root?`doc:${a.root.id}:${a.contentPath??""}`:`folder:${t.id}:${a.projectPath}`;if(this.registerCollapsible(m,c,r,l,!0),l.addEventListener("click",()=>this.toggleCollapsible(m)),a.kind==="docsRoot"||a.docsContainerRoot){const g=a.docsContainerRoot??a.root;l.addEventListener("contextmenu",y=>{y.preventDefault(),y.stopPropagation(),this.openDirContextMenu(y.clientX,y.clientY,g,"")}),this.enableDirectoryDropTarget(r,g.id,"")}else if(a.root){const g=a.root,y=a.contentPath??"";this.enableDragSource(l,{kind:"dir",rootId:g.id,path:y}),this.enableDirectoryDropTarget(r,g.id,y),r.addEventListener("contextmenu",b=>{b.preventDefault(),b.stopPropagation(),this.openDirContextMenu(b.clientX,b.clientY,g,y)})}else l.addEventListener("contextmenu",g=>{g.preventDefault(),g.stopPropagation(),this.showContextMenu(g.clientX,g.clientY,a.name,[{icon:At,iconClass:"nav-ctx-dir",label:"Create docs folder here",action:()=>this.callbacks.onCreateDocsFolder(t.id,a.projectPath)}])});c.appendChild(this.renderCanonicalNodes(t,a.children,n+1,s)),r.append(l,c),o.appendChild(r)}return o}renderCanonicalFile(t,e){if(t.kind==="file"){if(t.root&&t.contentPath&&ie(t.contentPath)){const l=document.createElement("button");return l.className="nav-link nav-tree-row nav-tree-file nav-tree-capability-file",l.type="button",l.style.setProperty("--tree-depth",String(e)),l.insertAdjacentHTML("afterbegin",Le),l.appendChild(document.createTextNode(t.name)),l.addEventListener("click",d=>{d.preventDefault(),this.callbacks.onOpenTextFile(t.root.id,t.contentPath)}),l.addEventListener("contextmenu",d=>{d.preventDefault(),d.stopPropagation(),this.openTextFileContextMenu(d.clientX,d.clientY,t.root,t.contentPath)}),l}const c=document.createElement("div");return c.className="nav-tree-row nav-tree-file",c.style.setProperty("--tree-depth",String(e)),c.textContent=t.name,c}const n=t.root,s=t.contentPath,o=t.kind==="doc"?nn(n.id,s):t.kind==="board"?sn(n.id,G(s)):js(n.id,s),a=t.kind==="doc"&&t.name==="index.md"?"Overview":Nt(t.kind==="board"?G(t.name):t.name),r=this.link(o,a,`${t.kind}:${n.id}:${s}`);return r.classList.add("nav-tree-row",`nav-tree-${t.kind}`),r.style.setProperty("--tree-depth",String(e)),r.insertAdjacentHTML("afterbegin",t.kind==="board"?Dt:t.kind==="capability"?Re:Et),this.enableDragSource(r,t.kind==="board"?{kind:"board",rootId:n.id,boardId:G(s)}:t.kind==="capability"?{kind:"capability",rootId:n.id,path:s}:{kind:"doc",rootId:n.id,path:s}),r.addEventListener("contextmenu",c=>{c.preventDefault(),c.stopPropagation(),t.kind==="board"?this.openBoardContextMenu(c.clientX,c.clientY,n,G(s)):t.kind==="doc"&&this.openDocContextMenu(c.clientX,c.clientY,n,s)}),r}renderBrowseNode(t,e,n){if(e.type==="file"){const p=document.createElement("div");return p.className="nav-browse-file",p.textContent=e.name,p}if(e.name==="docs"){const p=t.docsRoots.find(m=>m.displayPath===e.path||m.displayPath.endsWith("/"+e.path));if(p){const m=n.get(p.id)??[];return this.docsRootSection(p,m)}}const o=Gn(e),a=`browse:${t.id}:${e.path}`,r=document.createElement("div");r.className=o?"nav-subgroup nav-collapsible-dir":"nav-subgroup nav-browse-dir";const c=document.createElement("div");c.className="nav-dir-body";const l=document.createElement("button");l.className=o?"nav-dir-toggle nav-dir-project":"nav-browse-dir-toggle",l.type="button";const d=document.createElement("span");d.className="nav-repo-chevron",d.textContent="›";const h=document.createElement("span");if(h.textContent=e.name,l.append(d,h),l.addEventListener("click",()=>this.toggleCollapsible(a)),o){const p=t.docsRoots.find(m=>m.displayPath.startsWith(e.path+"/")||m.displayPath===e.path);p&&l.addEventListener("contextmenu",m=>{m.preventDefault(),m.stopPropagation(),this.openDirContextMenu(m.clientX,m.clientY,p,"")})}else l.addEventListener("contextmenu",p=>{p.preventDefault(),p.stopPropagation(),this.showContextMenu(p.clientX,p.clientY,e.name,[{icon:At,iconClass:"nav-ctx-dir",label:"Create /docs/",action:()=>this.callbacks.onCreateDocsFolder(t.id,e.path)}])});for(const p of e.children)p.type==="dir"&&c.appendChild(this.renderBrowseNode(t,p,n));return this.registerCollapsible(a,c,r,l,!0),r.append(l,c),r}renderPathNodes(t,e,n,s=""){const o=document.createElement("div");for(const a of t)if(a.kind==="root")o.appendChild(this.docsRootSection(a.root,e.get(a.root.id)??[]));else{const r=s?`${s}/${a.segment}`:a.segment,c=`pathseg:${n}:${r}`,l=this.renderPathNodes(a.children,e,n,r);l.classList.add("nav-dir-body");const d=document.createElement("div");d.className="nav-subgroup nav-collapsible-dir";const h=Zn(a),{row:p,toggle:m}=this.createDirectoryRow(a.segment,`#/project/${encodeURIComponent(n)}`,`${a.segment} wiki`,()=>this.toggleCollapsible(c),!0);h&&d.addEventListener("contextmenu",g=>{g.preventDefault(),g.stopPropagation(),this.openDirContextMenu(g.clientX,g.clientY,h,"")}),this.registerCollapsible(c,l,d,m,!0),d.append(p,l),o.appendChild(d)}return o}docsRootSection(t,e){const n=document.createElement("div");n.className="nav-subgroup nav-docs-root";const s=t.displayPath.split("/").pop()??t.displayPath;if(s.toLowerCase()!=="docs"){const a=document.createElement("div");a.className="nav-root-path-label",a.textContent=s,n.appendChild(a),a.addEventListener("contextmenu",r=>{r.preventDefault(),r.stopPropagation(),this.openDirContextMenu(r.clientX,r.clientY,t,"")})}return n.addEventListener("contextmenu",a=>{var r;(r=a.target)!=null&&r.closest(".nav-link, .nav-dir-toggle")||(a.preventDefault(),a.stopPropagation(),this.openDirContextMenu(a.clientX,a.clientY,t,""))}),this.enableDirectoryDropTarget(n,t.id,""),n.appendChild(this.docsNodes(t,As(e),"",e)),n}createDirectoryRow(t,e,n,s,o=!1){const a=document.createElement("div");a.className="nav-dir-header-row";const r=document.createElement("button");r.className=o?"nav-dir-toggle nav-dir-project":"nav-dir-toggle nav-dir-docs",r.type="button";const c=document.createElement("span");c.className="nav-repo-chevron",c.innerHTML='<svg viewBox="0 0 16 16" width="10" height="10" fill="currentColor"><path d="M6 4l4 4-4 4"/></svg>';const l=document.createElement("span");l.textContent=t,r.append(c,l),r.addEventListener("click",s);const d=document.createElement("a");return d.className="nav-repo-wiki-link nav-dir-wiki-link",d.href=e,d.title=n,d.innerHTML='<svg viewBox="0 0 14 14" fill="none" stroke="currentColor" stroke-width="1.6" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><rect x="2" y="2" width="10" height="10" rx="2"/><path d="M5 5h4M5 7h4M5 9h2"/></svg>',d.addEventListener("click",h=>h.stopPropagation()),this.links.set(e,d),a.append(r,d),{row:a,toggle:r}}docsNodes(t,e,n,s){const o=document.createElement("div"),a=Kn(e),r=Ns(s,n),c=[...a.map(l=>({kind:l.type==="file"&&ie(l.path)?"file":"doc",node:l})),...r.map(l=>({kind:"board",name:Nt(G(l.path).split("/").pop()??G(l.path)),boardId:G(l.path)}))].sort((l,d)=>{const h=l.kind==="doc"&&l.node.type==="file"&&l.node.name==="index.md",p=d.kind==="doc"&&d.node.type==="file"&&d.node.name==="index.md";if(h!==p)return h?-1:1;const m=(l.kind==="doc"||l.kind==="file")&&l.node.type==="file"&&on(l.node.name),g=(d.kind==="doc"||d.kind==="file")&&d.node.type==="file"&&on(d.node.name);if(m!==g)return m?-1:1;const y=(l.kind==="doc"||l.kind==="file")&&l.node.type==="dir",b=(d.kind==="doc"||d.kind==="file")&&d.node.type==="dir";if(y!==b)return y?-1:1;const x=l.kind==="board"?l.name:l.node.name,v=d.kind==="board"?d.name:d.node.name;return x.localeCompare(v)});for(const l of c)if(l.kind==="board"){const d=document.createElement("a");d.className="nav-link nav-link-board",d.href=sn(t.id,l.boardId),d.insertAdjacentHTML("afterbegin",Dt),d.appendChild(document.createTextNode(l.name));const h=`board:${t.id}:${l.boardId}`;this.links.set(h,d),this.links.set(d.href,d),this.enableDragSource(d,{kind:"board",rootId:t.id,boardId:l.boardId}),d.addEventListener("contextmenu",p=>{p.preventDefault(),p.stopPropagation(),this.openBoardContextMenu(p.clientX,p.clientY,t,l.boardId)}),o.appendChild(d)}else{const{node:d}=l;if(d.type==="file"){if(l.kind==="file"){const m=document.createElement("button");m.className="nav-link nav-tree-file nav-tree-capability-file",m.type="button",m.insertAdjacentHTML("afterbegin",Le),m.appendChild(document.createTextNode(d.name)),m.addEventListener("click",()=>this.callbacks.onOpenTextFile(t.id,d.path)),m.addEventListener("contextmenu",g=>{g.preventDefault(),g.stopPropagation(),this.openTextFileContextMenu(g.clientX,g.clientY,t,d.path)}),o.appendChild(m);continue}if(!d.name.endsWith(".md"))continue;const h=d.name==="index.md"?"Overview":Nt(d.name),p=this.link(nn(t.id,d.path),h,`doc:${t.id}:${d.path}`);p.insertAdjacentHTML("afterbegin",Et),this.enableDragSource(p,{kind:"doc",rootId:t.id,path:d.path}),p.addEventListener("contextmenu",m=>{m.preventDefault(),m.stopPropagation(),this.openDocContextMenu(m.clientX,m.clientY,t,d.path)}),o.appendChild(p)}else{const h=`doc:${t.id}:${d.path}`,p=this.docsNodes(t,d.children,d.path,s);p.classList.add("nav-dir-body");const m=document.createElement("div");m.className="nav-subgroup nav-collapsible-dir";const{row:g,toggle:y}=this.createDirectoryRow(Nt(d.name),`#/root/${encodeURIComponent(t.id)}/directory/${encodeURIComponent(d.path)}`,`${d.name} wiki`,b=>{b.button===0&&this.toggleCollapsible(h)},!1);this.enableDragSource(y,{kind:"dir",rootId:t.id,path:d.path}),m.addEventListener("contextmenu",b=>{b.preventDefault(),b.stopPropagation(),this.openDirContextMenu(b.clientX,b.clientY,t,d.path)}),this.enableDirectoryDropTarget(m,t.id,d.path),this.registerCollapsible(h,p,m,y,!0),m.append(g,p),o.appendChild(m)}}return o}enableDragSource(t,e){t.draggable=!0,t.addEventListener("dragstart",n=>{var s,o;this.closeContextMenu(),this.draggedItem=e,t.classList.add("nav-dragging"),(s=n.dataTransfer)==null||s.setData("application/x-docs-nav-item",JSON.stringify(e)),(o=n.dataTransfer)==null||o.setData("text/plain",Xs(e)),n.dataTransfer&&(n.dataTransfer.effectAllowed="move")}),t.addEventListener("dragend",()=>{t.classList.remove("nav-dragging"),this.draggedItem=void 0,this.clearDropTargets()})}enableDirectoryDropTarget(t,e,n){t.addEventListener("dragover",s=>{const o=this.currentDragItem(s);!o||!this.canDropItem(o,e,n)||(s.preventDefault(),s.stopPropagation(),s.dataTransfer&&(s.dataTransfer.dropEffect="move"),t.classList.add("nav-drop-target"),this.scheduleDropExpand(t))}),t.addEventListener("dragleave",s=>{t.contains(s.relatedTarget)||(t.classList.remove("nav-drop-target"),this.clearDropExpand(t))}),t.addEventListener("drop",s=>{const o=this.currentDragItem(s);!o||!this.canDropItem(o,e,n)||(s.preventDefault(),s.stopPropagation(),this.clearDropExpand(t),this.clearDropTargets(),this.moveDraggedItem(o,n))})}scheduleDropExpand(t){this.dropExpandTarget===t||!t.dataset.collapsibleKey||(this.clearDropExpand(),this.dropExpandTarget=t,this.dropExpandTimer=window.setTimeout(()=>{const e=t.dataset.collapsibleKey;e&&this.applyCollapsed(e,!1),t.classList.add("nav-drop-auto-expanded"),this.dropExpandTimer=void 0},650))}clearDropExpand(t){var e;t&&this.dropExpandTarget!==t||(this.dropExpandTimer!==void 0&&window.clearTimeout(this.dropExpandTimer),this.dropExpandTimer=void 0,(e=this.dropExpandTarget)==null||e.classList.remove("nav-drop-auto-expanded"),this.dropExpandTarget=void 0)}currentDragItem(t){var n;if(this.draggedItem)return this.draggedItem;const e=(n=t.dataTransfer)==null?void 0:n.getData("application/x-docs-nav-item");if(e)try{const s=JSON.parse(e);if(s&&(s.kind==="doc"||s.kind==="capability"||s.kind==="board"||s.kind==="dir")&&typeof s.rootId=="string")return s}catch{}}canDropItem(t,e,n){if(t.rootId!==e)return!1;const s=xt(n);if(t.kind==="doc")return Ct(t.path)!==s;if(t.kind==="capability")return s==="capabilities"||s.startsWith("capabilities/")&&Ct(t.path)!==s;if(t.kind==="board")return Ct(t.boardId)!==s;const o=xt(t.path);return!o||o===s||Ct(o)===s?!1:!s.startsWith(`${o}/`)}moveDraggedItem(t,e){const n=xt(e);t.kind==="doc"||t.kind==="capability"?this.callbacks.onMoveDoc(t.rootId,t.path,n):t.kind==="board"?this.callbacks.onMoveBoard(t.rootId,t.boardId,n):this.callbacks.onMoveDirectory(t.rootId,t.path,n)}clearDropTargets(){this.clearDropExpand(),this.element.querySelectorAll(".nav-drop-target").forEach(t=>{t.classList.remove("nav-drop-target")})}startInlineRename(t,e,n){const s=document.createElement("input");s.className="nav-inline-input",s.value=e.replace(/\.md$/,"");const o=t.parentElement;if(!o)return;t.style.display="none",o.insertBefore(s,t.nextSibling),s.focus(),s.select();let a=!1;const r=c=>{if(!a&&(a=!0,s.remove(),t.style.display="",c)){const l=s.value.trim();l&&l!==e.replace(/\.md$/,"")&&n(l)}};s.addEventListener("keydown",c=>{c.stopPropagation(),c.key==="Enter"&&(c.preventDefault(),r(!0)),c.key==="Escape"&&(c.preventDefault(),r(!1))}),s.addEventListener("blur",()=>r(!0))}startInlineCreate(t,e,n){const s=document.createElement("input");s.className="nav-inline-input",s.placeholder=e,t.insertBefore(s,t.firstChild),s.focus();let o=!1;const a=r=>{if(!o&&(o=!0,s.remove(),r)){const c=s.value.trim();c&&n(c)}};s.addEventListener("keydown",r=>{r.stopPropagation(),r.key==="Enter"&&(r.preventDefault(),a(!0)),r.key==="Escape"&&(r.preventDefault(),a(!1))}),s.addEventListener("blur",()=>a(!0))}registerCollapsible(t,e,n,s,o){this.collapsibles.set(t,{body:e,group:n,btn:s}),n.dataset.collapsibleKey=t,this.applyCollapsed(t,this.collapsedState.get(t)??o)}applyCollapsed(t,e){const n=this.collapsibles.get(t);n&&(this.collapsedState.set(t,e),n.body.hidden=e,n.group.classList.toggle("collapsed",e),n.btn.setAttribute("aria-expanded",String(!e)))}toggleCollapsible(t){const e=this.collapsibles.get(t);e&&this.applyCollapsed(t,!e.body.hidden)}openDirContextMenu(t,e,n,s){const o=s?Nt(s.split("/").pop()??s):n.displayPath.split("/").pop()??n.displayPath,a=[{icon:At,iconClass:"nav-ctx-dir",label:"New Directory",action:()=>this.callbacks.onCreateDirectory(n.id,s)},{icon:Dt,iconClass:"nav-ctx-board",label:"New Board",action:()=>this.callbacks.onCreateBoard(n.id,s)},{icon:Et,iconClass:"nav-ctx-doc",label:"New Doc",action:()=>this.callbacks.onCreateDoc(n.id,s)},{icon:Re,iconClass:"nav-ctx-cap",label:"New Capability",action:()=>this.callbacks.onCreateCapability(n.id,s)}];s&&a.push({icon:le,iconClass:"nav-ctx-rename",label:"Rename",action:()=>this.callbacks.onRenameDirectory(n.id,s)},{icon:Vt,iconClass:"nav-ctx-delete",label:"Delete",action:()=>this.callbacks.onDeleteDirectory(n.id,s)}),this.showContextMenu(t,e,o,a)}openEmptyProjectContextMenu(t,e,n,s){this.showContextMenu(t,e,s,[{icon:At,iconClass:"nav-ctx-dir",label:"New Directory",action:()=>this.callbacks.onCreateProjectDirectory(n)},{icon:Dt,iconClass:"nav-ctx-board",label:"New Board",action:()=>this.callbacks.onCreateProjectBoard(n)},{icon:Et,iconClass:"nav-ctx-doc",label:"New Doc",action:()=>this.callbacks.onCreateProjectDoc(n)}])}openDocContextMenu(t,e,n,s){const o=s.split("/").pop()??s;this.showContextMenu(t,e,o,[{icon:Et,iconClass:"nav-ctx-doc",label:"Open",action:()=>this.callbacks.onOpenDoc(n.id,s)},{icon:$e,iconClass:"nav-ctx-edit",label:"Edit",action:()=>this.callbacks.onEditDoc(n.id,s)},{kind:"divider"},{icon:le,iconClass:"nav-ctx-rename",label:"Rename",action:()=>this.callbacks.onRenameDoc(n.id,s)},{icon:Vt,iconClass:"nav-ctx-delete",label:"Delete",action:()=>this.callbacks.onDeleteDoc(n.id,s),danger:!0}])}openTextFileContextMenu(t,e,n,s){const o=s.split("/").pop()??s;this.showContextMenu(t,e,o,[{icon:Le,iconClass:"nav-ctx-doc",label:"Open",action:()=>this.callbacks.onOpenTextFile(n.id,s)},{icon:$e,iconClass:"nav-ctx-edit",label:"Edit",action:()=>this.callbacks.onOpenTextFile(n.id,s)},{kind:"divider"},{icon:le,iconClass:"nav-ctx-rename",label:"Rename",action:()=>this.callbacks.onRenameDoc(n.id,s)},{icon:Vt,iconClass:"nav-ctx-delete",label:"Delete",action:()=>this.callbacks.onDeleteDoc(n.id,s),danger:!0}])}openBoardContextMenu(t,e,n,s){const o=Nt(s.split("/").pop()??s);this.showContextMenu(t,e,o,[{icon:Dt,iconClass:"nav-ctx-board",label:"Open",action:()=>this.callbacks.onOpenBoard(n.id,s)},{kind:"divider"},{icon:le,iconClass:"nav-ctx-rename",label:"Rename",action:()=>this.callbacks.onRenameBoard(n.id,s)},{icon:Vt,iconClass:"nav-ctx-delete",label:"Delete",action:()=>this.callbacks.onDeleteBoard(n.id,s),danger:!0}])}showContextMenu(t,e,n,s){this.closeContextMenu();const o=document.createElement("div");o.className="nav-context-menu",o.addEventListener("pointerdown",c=>c.stopPropagation());const a=document.createElement("div");a.className="nav-context-label",a.textContent=n,o.appendChild(a);const r=document.createElement("div");r.className="nav-context-divider",o.appendChild(r);for(const c of s){if(c.kind==="divider"){const p=document.createElement("div");p.className="nav-context-divider",o.appendChild(p);continue}const l=document.createElement("button");l.className="nav-context-item"+(c.danger?" nav-context-item-danger":""),l.type="button";const d=document.createElement("span");d.className=`nav-ctx-icon ${c.iconClass}`,d.innerHTML=c.icon;const h=document.createElement("span");h.textContent=c.label,l.append(d,h),l.addEventListener("click",()=>{this.closeContextMenu(),c.action()}),o.appendChild(l)}o.style.position="fixed",o.style.left=`${t}px`,o.style.top=`${e}px`,document.body.appendChild(o),this.contextMenu=o,requestAnimationFrame(()=>{if(!this.contextMenu)return;const c=o.getBoundingClientRect();c.right>window.innerWidth&&(o.style.left=`${Math.max(0,t-c.width)}px`),c.bottom>window.innerHeight&&(o.style.top=`${Math.max(0,e-c.height)}px`)})}closeContextMenu(){var t;(t=this.contextMenu)==null||t.remove(),this.contextMenu=void 0}groupLabel(t){const e=document.createElement("div");return e.className="nav-label",e.textContent=t,e}link(t,e,n){const s=document.createElement("a");return s.className="nav-link",s.href=t,s.textContent=e,this.links.set(n,s),this.links.set(t,s),s}}const Dt='<svg class="nav-node-icon nav-node-icon-board" viewBox="0 0 16 16" aria-hidden="true"><rect x="1" y="1" width="6" height="6" rx="1"/><rect x="9" y="1" width="6" height="6" rx="1"/><rect x="1" y="9" width="6" height="6" rx="1"/><rect x="9" y="9" width="6" height="6" rx="1"/></svg>',Re='<svg class="nav-node-icon nav-node-icon-capability" viewBox="0 0 16 16" aria-hidden="true"><path d="M8 1l2 4.5 4.5 0.7-3.3 3.1 0.8 4.7-4-2.1-4 2.1 0.8-4.7L1.5 6.2l4.5-0.7z"/></svg>',Et='<svg class="nav-node-icon nav-node-icon-doc" viewBox="0 0 16 16" aria-hidden="true"><path d="M3 1.5h6.5l3 3V14.5H3z"/><path d="M9.5 1.5V4.5h3" stroke="none"/><line x1="5" y1="7" x2="11" y2="7" stroke="var(--bg-canvas)" stroke-width="0.8"/><line x1="5" y1="9.5" x2="11" y2="9.5" stroke="var(--bg-canvas)" stroke-width="0.8"/><line x1="5" y1="12" x2="9" y2="12" stroke="var(--bg-canvas)" stroke-width="0.8"/></svg>',Le='<svg class="nav-node-icon nav-node-icon-doc" viewBox="0 0 16 16" aria-hidden="true"><path d="M3 1.5h6.5l3 3V14.5H3z"/><path d="M9.5 1.5V4.5h3" stroke="none"/><line x1="5" y1="7" x2="11" y2="7" stroke="var(--bg-canvas)" stroke-width="0.8"/><line x1="5" y1="9.5" x2="11" y2="9.5" stroke="var(--bg-canvas)" stroke-width="0.8"/></svg>',At='<svg class="nav-ctx-svg" viewBox="0 0 16 16" aria-hidden="true" fill="none" stroke="currentColor" stroke-width="1.45" stroke-linecap="round" stroke-linejoin="round"><path d="M2 4.5h4l1.4 1.6H14v6.4a1 1 0 0 1-1 1H3a1 1 0 0 1-1-1z"/><path d="M2 4.5v-1a1 1 0 0 1 1-1h3l1.4 2"/></svg>',$e='<svg class="nav-ctx-svg" viewBox="0 0 16 16" aria-hidden="true" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><path d="M11 2l3 3-8 8H3v-3z"/></svg>',le='<svg class="nav-ctx-svg" viewBox="0 0 16 16" aria-hidden="true" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><path d="M2 12h12M8 3v9M5 6l3-3 3 3"/></svg>',Vt='<svg class="nav-ctx-svg" viewBox="0 0 16 16" aria-hidden="true" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><path d="M2 4h12M5 4V2h6v2M6 7v5M10 7v5M3 4l1 9a1 1 0 001 1h6a1 1 0 001-1l1-9"/></svg>';function Kn(i){return i.filter(t=>t.type==="file"?t.name.endsWith(".md")||ie(t.path):!Ps.has(t.name)).map(t=>t.type==="file"?t:{...t,children:Kn(t.children)})}function As(i){const t=i.find(e=>e.type==="dir"&&e.name.toLowerCase()==="docs");return!t||t.type!=="dir"?i:i.filter(e=>e!==t).concat(t.children)}function Ns(i,t){const e=t?`${t}/`:"";return zs(i).filter(n=>e?n.path.startsWith(e)?!n.path.slice(e.length).includes("/"):!1:!n.path.includes("/"))}function zs(i){const t=[],e=n=>{for(const s of n)s.type==="file"?s.name.endsWith(".board.json")&&t.push(s):e(s.children)};return e(i),t}function nn(i,t){return`#/root/${encodeURIComponent(i)}/docs/${encodeURIComponent(t)}`}function Hs(i){return`#/root/${encodeURIComponent(i)}/boards`}function sn(i,t){return`#/root/${encodeURIComponent(i)}/boards/${encodeURIComponent(t)}`}function Fs(i){return`#/root/${encodeURIComponent(i)}/capabilities`}function js(i,t){return`#/root/${encodeURIComponent(i)}/capabilities/${encodeURIComponent(Ws(t))}`}function Ws(i){return i.replace(/^capabilities\//,"")}function Os(i,t,e){const n=new Map,s=[],o=c=>{const l=xt(c),d=n.get(l);if(d)return d;const h=Ct(l),p={id:`folder:${i.id}:${l}`,kind:"folder",name:l.split("/").pop()??i.label,projectPath:l,children:[]};return n.set(l,p),l&&h?o(h).children.push(p):s.push(p),p},a=c=>{for(const l of c)if(l.type==="dir")o(l.path),a(l.children);else{const d={id:`file:${i.id}:${l.path}`,kind:"file",name:l.name,projectPath:l.path,children:[]};n.set(l.path,d);const h=Ct(l.path);h?o(h).children.push(d):s.push(d)}};a(t);for(const c of i.docsRoots){const l=xt(c.displayPath),d=o(l);d.kind="docsRoot",d.id=`root:${c.id}`,d.root=c,d.contentPath="";const h=p=>{for(const m of p){const g=[l,m.path].filter(Boolean).join("/");if(m.type==="dir"){const E=o(g);E.kind!=="docsRoot"&&(E.root=c,E.contentPath=m.path),h(m.children);continue}const y=m.name.endsWith(".board.json"),b=Vn(m.path),x=ie(m.path);if(!m.name.endsWith(".md")&&!y&&!x)continue;const v=Ct(g),S=n.get(g),w=S??{id:"",kind:"file",name:m.name,projectPath:g,children:[]};w.id=`${y?"board":b?"capability":x?"file":"doc"}:${c.id}:${m.path}`,w.kind=y?"board":b?"capability":x?"file":"doc",w.root=c,w.contentPath=m.path,S||(n.set(g,w),v?o(v).children.push(w):s.push(w))}};h(e.get(c.id)??[])}const r=(c,l)=>{const d=c.kind==="docsRoot"?c.root:c.root??l;if(d&&(c.kind==="folder"||c.kind==="file")&&!c.contentPath){c.root=d;const h=xt(d.displayPath);c.contentPath=c.projectPath.slice(h.length).replace(/^\//,"")}for(const h of c.children)r(h,d)};for(const c of s)r(c);return s}function Us(i){return[...i].sort((t,e)=>{const n=s=>s.kind==="doc"&&s.name==="index.md"?0:s.kind==="doc"?1:s.kind==="capability"?2:s.kind==="board"?3:s.kind==="folder"?4:(s.kind==="docsRoot",5);return n(t)-n(e)||t.name.localeCompare(e.name,void 0,{sensitivity:"accent"})})}function on(i){return/^readme\.(md|txt)$/i.test(i)}function ve(i,t,e=!1){const n=[];for(const s of i){if(s.kind==="docsRoot"){n.push({...s,children:ve(s.children,!1,!0)});continue}if(e){if(s.kind==="file"){ie(s.contentPath??"")&&n.push(s);continue}if(s.kind==="folder"){const o=ve(s.children,!1,!0);(s.name!=="assets"||o.length>0)&&n.push({...s,children:o})}else n.push(s);continue}if(s.kind==="folder"){const o=ve(s.children);o.length>0&&n.push({...s,children:o})}}return n}function _e(i){var e;const t=[];for(const n of i){if(n.kind==="docsRoot"){t.push(..._e(n.children));continue}if(n.kind!=="folder"){t.push(n);continue}const s=(e=n.children.find(o=>o.kind==="docsRoot"))==null?void 0:e.root;t.push({...n,docsContainerRoot:s,children:_e(n.children)})}return t}function Nt(i){const t=i.replace(/\.md$/,"").replace(/[-_]/g," ");return t.charAt(0).toUpperCase()+t.slice(1)}function Vn(i){if(!i.startsWith("capabilities/")||!i.endsWith(".md"))return!1;const t=i.slice(13);return t.includes("/")?t.endsWith("/index.md"):!0}function ie(i){return!i.startsWith("capabilities/")||i.endsWith(".board.json")?!1:!Vn(i)}function _s(i){var t;return i.kind!=="folder"||!((t=i.contentPath)!=null&&t.startsWith("capabilities/"))?null:i.children.find(e=>e.kind==="capability"&&Ct(e.contentPath??"")===i.contentPath)??null}function Gn(i){if(i.type==="file")return!1;for(const t of i.children)if(t.type==="dir"&&t.name==="docs"||t.type==="dir"&&Gn(t))return!0;return!1}function xt(i){return i.replace(/^\/+|\/+$/g,"")}function Ct(i){const t=xt(i),e=t.lastIndexOf("/");return e===-1?"":t.slice(0,e)}function Xs(i){return i.kind==="doc"||i.kind==="capability"?i.path:i.kind==="board"?i.boardId:i.path}function Zn(i){if(i.kind==="root")return i.root;for(const t of i.children){const e=Zn(t);if(e)return e}return null}function ne(i,t={}){const{frontmatter:e,body:n}=qs(i);try{const s=Jn(n.split(`
|
|
1
|
+
var Cs=Object.defineProperty;var ks=(i,t,e)=>t in i?Cs(i,t,{enumerable:!0,configurable:!0,writable:!0,value:e}):i[t]=e;var u=(i,t,e)=>ks(i,typeof t!="symbol"?t+"":t,e);(function(){const t=document.createElement("link").relList;if(t&&t.supports&&t.supports("modulepreload"))return;for(const s of document.querySelectorAll('link[rel="modulepreload"]'))n(s);new MutationObserver(s=>{for(const o of s)if(o.type==="childList")for(const a of o.addedNodes)a.tagName==="LINK"&&a.rel==="modulepreload"&&n(a)}).observe(document,{childList:!0,subtree:!0});function e(s){const o={};return s.integrity&&(o.integrity=s.integrity),s.referrerPolicy&&(o.referrerPolicy=s.referrerPolicy),s.crossOrigin==="use-credentials"?o.credentials="include":s.crossOrigin==="anonymous"?o.credentials="omit":o.credentials="same-origin",o}function n(s){if(s.ep)return;s.ep=!0;const o=e(s);fetch(s.href,o)}})();const $="/__api";class se extends Error{constructor(e,n){super(e);u(this,"currentRevision");this.name="RevisionConflictError",this.currentRevision=n}}async function P(i){var t;if(!i.ok){let e="";try{e=((t=await i.json())==null?void 0:t.error)??""}catch{}throw new Error(`${i.status} ${i.statusText}${e?` — ${e}`:""}`)}return i.json()}function D(i={}){return i}const k={async getWorkspace(){return P(await fetch(`${$}/workspace`,D()))},async removeProject(i){await P(await fetch(`${$}/workspace/project?id=${encodeURIComponent(i)}`,D({method:"DELETE"})))},async pickAndAddProject(){return P(await fetch(`${$}/workspace/pick-project`,D({method:"POST"})))},async addProject(i,t){return P(await fetch(`${$}/workspace/project`,D({method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({rootPath:i,label:t})})))},async ensureProjectDocsRoot(i){return(await P(await fetch(`${$}/workspace/project/docs-root`,D({method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({projectId:i})})))).root},async getTree(i){return(await P(await fetch(`${$}/tree?rootId=${encodeURIComponent(i)}`,D()))).tree},async getProjectTree(i){return(await P(await fetch(`${$}/project-tree?projectId=${encodeURIComponent(i)}`,D()))).tree},async createDocsFolder(i,t){await P(await fetch(`${$}/workspace/project/create-docs-folder`,D({method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({projectId:i,parentPath:t})})))},async readFile(i,t){return(await P(await fetch(`${$}/file?rootId=${encodeURIComponent(i)}&path=${encodeURIComponent(t)}`,D()))).content},async readFileWithRevision(i,t){return P(await fetch(`${$}/file?rootId=${encodeURIComponent(i)}&path=${encodeURIComponent(t)}`,D()))},async writeFile(i,t,e,n){const s=await fetch(`${$}/file`,D({method:"PUT",headers:{"Content-Type":"application/json"},body:JSON.stringify({rootId:i,path:t,content:e,expectedRevision:n})}));if(s.status===409){const a=await s.json();throw new se(a.error??"File changed on disk",a.currentRevision??null)}return(await P(s)).revision},async createDirectory(i,t){await P(await fetch(`${$}/directory`,D({method:"PUT",headers:{"Content-Type":"application/json"},body:JSON.stringify({rootId:i,path:t})})))},async getBoard(i,t){const e=await fetch(`${$}/board?rootId=${encodeURIComponent(i)}&id=${encodeURIComponent(t)}`,D());return e.status===404?null:(await P(e)).doc},async getBoardWithRevision(i,t){const e=await fetch(`${$}/board?rootId=${encodeURIComponent(i)}&id=${encodeURIComponent(t)}`,D());return e.status===404?null:P(e)},async saveBoard(i,t,e,n){const s=await fetch(`${$}/board`,D({method:"PUT",headers:{"Content-Type":"application/json"},body:JSON.stringify({rootId:i,id:t,doc:e,expectedRevision:n})}));if(s.status===409){const a=await s.json();throw new se(a.error??"Board changed on disk",a.currentRevision??null)}return(await P(s)).revision},async deleteFile(i,t){await P(await fetch(`${$}/file?rootId=${encodeURIComponent(i)}&path=${encodeURIComponent(t)}`,D({method:"DELETE"})))},async renameFile(i,t,e,n=!1){await P(await fetch(`${$}/file`,D({method:"PATCH",headers:{"Content-Type":"application/json"},body:JSON.stringify({rootId:i,oldPath:t,newPath:e,ignoreMissing:n})})))},async deleteBoard(i,t){await P(await fetch(`${$}/board?rootId=${encodeURIComponent(i)}&id=${encodeURIComponent(t)}`,D({method:"DELETE"})))},assetUrl(i,t){return`${$}/asset?rootId=${encodeURIComponent(i)}&path=${encodeURIComponent(t)}`},async uploadAsset(i,t,e,n){return(await P(await fetch(`${$}/asset`,D({method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({rootId:i,name:t,base64:e,mimeType:n})})))).path},async cleanupManagedAssets(i,t=[]){return(await P(await fetch(`${$}/asset/cleanup`,D({method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({rootId:i,preservePaths:t})})))).removed}};function Es(i,t){const e=i.find(o=>o.type==="dir"&&o.name===t);if(!e||e.type!=="dir")return[];const n=[],s=o=>{for(const a of o)a.type==="file"?n.push(a):s(a.children)};return s(e.children),n}function Ue(i){for(const t of i){if(t.type==="file"&&t.name.endsWith(".md"))return t.path;if(t.type==="dir"){const e=Ue(t.children);if(e)return e}}return null}function wt(i){const t=[];for(const e of i.replace(/\\/g,"/").split("/")){const n=e.trim();if(!(!n||n===".")){if(n===".."){t.length>0&&t.pop();continue}t.push(n)}}return t.join("/")}function qn(i){const t=wt(i),e=t.lastIndexOf("/");return e===-1?"":t.slice(0,e)}function Ss(i,t){if(/^(https?:|mailto:|tel:|#|data:)/.test(t))return t;if(t.startsWith("/"))return wt(t);const e=qn(i);return wt(e?`${e}/${t}`:t)}function Ke(i,t){const e=qn(i),n=e?e.split("/").filter(Boolean):[],s=wt(t).split("/").filter(Boolean);let o=0;for(;o<n.length&&o<s.length&&n[o]===s[o];)o++;const a=n.slice(o).map(()=>".."),r=s.slice(o);return[...a,...r].join("/")||s[s.length-1]||""}const Ts=["sticky","task","rectangle","ellipse","text","line","arrow","connector","image","screenshot","frame","templateGroup"];function ce(i){const t=new Set;for(const e of i.elements){const n=e.data.assetId;typeof n=="string"&&t.add(n)}return{...i.schemaUrl?{$schema:i.schemaUrl}:{},version:1,id:i.boardId,title:i.title,createdAt:i.createdAt,updatedAt:Date.now(),viewport:{...i.viewport},theme:i.theme,elements:i.elements,assetIds:[...t]}}function Y(i){return typeof i=="number"&&Number.isFinite(i)}function Yn(i){if(typeof i!="object"||i===null)return null;const t=i;return typeof t.id!="string"||typeof t.type!="string"||!Ts.includes(t.type)||!Y(t.x)||!Y(t.y)||!Y(t.width)||!Y(t.height)?null:{id:t.id,type:t.type,x:t.x,y:t.y,width:t.width,height:t.height,rotation:Y(t.rotation)?t.rotation:0,zIndex:Y(t.zIndex)?t.zIndex:0,locked:t.locked===!0,hidden:t.hidden===!0,createdAt:Y(t.createdAt)?t.createdAt:Date.now(),updatedAt:Y(t.updatedAt)?t.updatedAt:Date.now(),style:typeof t.style=="object"&&t.style!==null?t.style:{},data:typeof t.data=="object"&&t.data!==null?t.data:{}}}function we(i){if(typeof i!="object"||i===null)return null;const t=i;if(t.version!==1||typeof t.id!="string"||!Array.isArray(t.elements))return null;const e=[];for(const s of t.elements){const o=Yn(s);o&&e.push(o)}const n=t.viewport??{};return{...typeof t.$schema=="string"?{$schema:t.$schema}:{},version:1,id:t.id,title:typeof t.title=="string"?t.title.slice(0,200):"Imported Board",createdAt:Y(t.createdAt)?t.createdAt:Date.now(),updatedAt:Y(t.updatedAt)?t.updatedAt:Date.now(),viewport:{offsetX:Y(n.offsetX)?n.offsetX:0,offsetY:Y(n.offsetY)?n.offsetY:0,scale:Y(n.scale)&&n.scale>.01&&n.scale<=40?n.scale:1},theme:t.theme==="dark"?"dark":"light",elements:e,assetIds:Array.isArray(t.assetIds)?t.assetIds.filter(s=>typeof s=="string"):[]}}const Bs="/board-v1.schema.json",Ms=".board.json";function G(i){return i.replace(/\.board\.json$/,"")}function Is(i){return i.trim().replace(/^\/+/,"").replace(/\.board\.json$/,"")}function Rs(i,t){return re(i,t)[0]??""}function re(i,t){const e=i.trim(),n=Is(i);if(!n)return[];if(e.startsWith("./")||e.startsWith("../")){const r=t.lastIndexOf("/"),c=r===-1?"":t.slice(0,r);return[wt(c?`${c}/${n}`:n)]}if(e.startsWith("/")){const r=t.lastIndexOf("/"),c=r===-1?"":t.slice(0,r),l=wt(c?`${c}/${n}`:n),d=[n];if(l&&l!==n&&d.push(l),c){const h=c.includes("/")?c.slice(0,c.lastIndexOf("/")):"",p=wt(h?`${h}/${n}`:n);p&&!d.includes(p)&&d.push(p)}return d}const s=t.lastIndexOf("/"),o=s===-1?"":t.slice(0,s),a=wt(o?`${o}/${n}`:n);return a&&a!==n?[a,n]:[n]}function nn(i){return i.toLowerCase().replace(/[^\w\s-]/g,"").trim().replace(/\s+/g,"-").slice(0,48)||"board"}function Ls(i){return new Promise((t,e)=>{const n=new FileReader;n.onload=()=>{const s=n.result;t(s.slice(s.indexOf(",")+1))},n.onerror=()=>e(n.error),n.readAsDataURL(i)})}const J={async listIds(i){const t=await k.getTree(i);return $s(t).map(e=>G(e.path))},async list(i){const t=await this.listIds(i),e=[];for(const n of t){const s=await this.load(i,n);s&&e.push({id:n,title:s.title,elementCount:s.elements.length,updatedAt:s.updatedAt,filePath:`${n}.board.json`})}return e.sort((n,s)=>s.updatedAt-n.updatedAt),e},async load(i,t){const e=await k.getBoard(i,t);if(e)return we(e)??void 0},async save(i,t){await k.saveBoard(i,t.id,t)},async delete(i,t){await k.deleteBoard(i,t)},async move(i,t,e){const n=await this.load(i,t);if(!n)throw new Error("Board not found");const s=t.split("/").pop()??t,o=e.replace(/^\/+|\/+$/g,""),a=o?`${o}/${s}`:s;if(a===t)return t;if(new Set(await this.listIds(i)).has(a))throw new Error("A board already exists there");const c=Date.now();return await k.saveBoard(i,a,{...n,id:a,updatedAt:c}),await k.deleteBoard(i,t),a},async rename(i,t,e){const n=await this.load(i,t);if(!n)throw new Error("Board not found");const s=t.includes("/")?t.slice(0,t.lastIndexOf("/")):"",o=nn(e),a=s?`${s}/${o}`:o,r=Date.now();if(a===t)return await k.saveBoard(i,t,{...n,title:e.trim()||n.title,updatedAt:r}),t;if(new Set(await this.listIds(i)).has(a))throw new Error("A board already exists with that name");return await k.saveBoard(i,a,{...n,id:a,title:e.trim()||n.title,updatedAt:r}),await k.deleteBoard(i,t),a},async create(i,t,e,n=""){const s=new Set(await this.listIds(i)),o=nn(t);let r=`${n?`${n.replace(/^\/+|\/+$/g,"")}/`:""}${o}`;s.has(r)&&(r=`${r}-${Date.now().toString(36)}`);const c=Date.now(),l={$schema:Bs,version:1,id:r,title:t.trim()||"Untitled Board",createdAt:c,updatedAt:c,viewport:{offsetX:0,offsetY:0,scale:1},theme:e,elements:[],assetIds:[]};return await k.saveBoard(i,r,l),r},async uploadImage(i,t,e){const n=await Ls(t);return k.uploadAsset(i,e??"image.png",n,t.type)},async cleanupUnusedAssets(i,t=[]){return k.cleanupManagedAssets(i,t)}};function $s(i){const t=[],e=n=>{for(const s of n)s.type==="file"?s.name.endsWith(Ms)&&t.push(s):e(s.children)};return e(i),t}const Ps=new Set(["capabilities","assets"]);class Ds{constructor(t,e){u(this,"element");u(this,"header");u(this,"nav");u(this,"footer");u(this,"links",new Map);u(this,"collapsibles",new Map);u(this,"collapsedState",new Map);u(this,"callbacks");u(this,"contextMenu");u(this,"draggedItem");u(this,"dropExpandTimer");u(this,"dropExpandTarget");u(this,"lastWorkspace",{projects:[]});u(this,"lastTreesByRoot",new Map);u(this,"lastTreesByProject",new Map);u(this,"rawModeProjects",new Set);u(this,"lastActiveHash","");u(this,"forceNextActiveSync",!0);this.callbacks=e,this.element=document.createElement("aside"),this.element.className="sidebar",this.header=document.createElement("div"),this.header.className="sidebar-header";const n=document.createElement("a");n.className="sidebar-brand",n.href="#/",n.textContent="ViteBoard",this.header.appendChild(n),this.nav=document.createElement("nav"),this.nav.className="sidebar-nav",this.footer=document.createElement("div"),this.footer.className="sidebar-footer";const s=document.createElement("button");s.className="sidebar-add-repo",s.type="button",s.textContent="Add Repo",s.title="Add a local project root",s.addEventListener("click",()=>this.callbacks.onAddRepo()),this.footer.appendChild(s),this.element.append(this.header,this.nav,this.footer),t.appendChild(this.element),document.addEventListener("pointerdown",o=>{this.contextMenu&&(this.contextMenu.contains(o.target)||this.closeContextMenu())},!0)}refresh(t,e,n){this.lastWorkspace=t,this.lastTreesByRoot=e,n&&(this.lastTreesByProject=n),this.render()}render(){const t=this.lastWorkspace,e=this.lastTreesByRoot;if(this.lastTreesByProject,this.nav.replaceChildren(),this.links.clear(),this.collapsibles.clear(),t.projects.length===0){const s=document.createElement("div");s.className="nav-group",s.appendChild(this.groupLabel("Workspace"));const o=document.createElement("div");o.className="nav-label nav-empty-copy",o.textContent="Add a project root to discover docs folders.",s.appendChild(o),this.nav.appendChild(s)}else for(const s of t.projects)this.nav.appendChild(this.projectSection(s,e));const n=document.createElement("div");n.className="nav-group",n.appendChild(this.groupLabel("System")),n.appendChild(this.link("#/tokens","Tokens","tokens-root")),this.nav.appendChild(n),this.setActive(location.hash,{forceSyncAncestors:this.forceNextActiveSync}),this.forceNextActiveSync=!1}setActive(t,e={}){var s,o;for(const a of new Set(this.links.values()))a.classList.remove("active");const n=this.links.get(t);if(n)n.classList.add("active");else if(t.startsWith("#/root/")){const a=t.match(/^#\/root\/([^/]+)\/(boards|capabilities|docs)(?:\/(.+))?$/);if(a){const[,r,c]=a,l=decodeURIComponent(r);c==="boards"?(s=this.links.get(Hs(l)))==null||s.classList.add("active"):c==="capabilities"&&((o=this.links.get(Fs(l)))==null||o.classList.add("active"))}}(e.forceSyncAncestors||t!==this.lastActiveHash)&&this.syncCollapsed(t),this.lastActiveHash=t}toggleRawMode(t){this.rawModeProjects.has(t)?this.rawModeProjects.delete(t):this.rawModeProjects.add(t),this.forceNextActiveSync=!0,this.render()}syncCollapsed(t){const e=this.ancestorKeys(t);for(const n of e)this.applyCollapsed(n,!1)}ancestorKeys(t){const e=new Set,n=t.match(/^#\/project\/([^/]+)(?:\/boards)?$/);if(n)return e.add(decodeURIComponent(n[1])),e;const s=t.match(/^#\/root\/([^/]+)\/(docs|boards|capabilities)(?:\/(.+))?$/);if(!s)return e;const o=decodeURIComponent(s[1]),a=s[2],r=s[3]?decodeURIComponent(s[3]):"";let c,l;for(const p of this.lastWorkspace.projects){const m=p.docsRoots.find(g=>g.id===o);if(m){c=p.id,l=m.displayPath;break}}if(!c||!l)return e;e.add(c),e.add(o);const d=l.split("/").filter(Boolean).slice(0,-1);let h="";for(const p of d){h=h?`${h}/${p}`:p;const m=`folder:${c}:${h}`;this.collapsibles.has(m)&&e.add(m)}if((a==="docs"||a==="capabilities")&&r){const m=(a==="capabilities"?`capabilities/${r}`:r).split("/");for(let g=1;g<m.length;g++){const y=m.slice(0,g).join("/"),b=`doc:${o}:${y}`;this.collapsibles.has(b)&&e.add(b)}}return e}projectSection(t,e){const{id:n,label:s,docsRoots:o}=t,a=this.rawModeProjects.has(n),r=document.createElement("div");r.className="nav-repo-body";const c=document.createElement("div");c.className="nav-group nav-repo-group";const l=document.createElement("div");l.className="nav-repo-header-row";const d=document.createElement("button");d.className="nav-repo-header",d.type="button";const h=document.createElement("span");h.className="nav-repo-chevron",h.textContent="›";const p=document.createElement("span");p.className="nav-repo-label-text",p.textContent=s;const m=!a&&o.find(v=>xt(v.displayPath)==="docs"),g=document.createElement("span");g.className="nav-tree-badge",g.textContent="DOCS",g.hidden=!m;const y=document.createElement("button");y.className="nav-repo-more",y.type="button",y.title="Project options",y.innerHTML='<svg viewBox="0 0 16 16" width="14" height="14" fill="currentColor"><circle cx="8" cy="3" r="1.3"/><circle cx="8" cy="8" r="1.3"/><circle cx="8" cy="13" r="1.3"/></svg>',y.addEventListener("click",v=>{v.stopPropagation();const S=y.getBoundingClientRect();this.showContextMenu(S.right+4,S.top,s,[{icon:a?Et:At,iconClass:a?"nav-ctx-doc":"nav-ctx-dir",label:a?"View: Docs":"View: Raw",action:()=>this.toggleRawMode(n)},{icon:$e,iconClass:"nav-ctx-edit",label:"Wiki",action:()=>{location.hash=`#/project/${encodeURIComponent(n)}`}},{kind:"divider"},{icon:Et,iconClass:"nav-ctx-doc",label:"New Doc",action:()=>this.callbacks.onCreateProjectDoc(n)},{icon:Dt,iconClass:"nav-ctx-board",label:"New Board",action:()=>this.callbacks.onCreateProjectBoard(n)},{icon:At,iconClass:"nav-ctx-dir",label:"New Directory",action:()=>this.callbacks.onCreateProjectDirectory(n)},{kind:"divider"},{icon:Vt,iconClass:"nav-ctx-delete",label:"Remove from workspace",action:()=>this.callbacks.onRemoveProject(n,s),danger:!0}])}),d.append(h,p,g),l.append(d,y),this.registerCollapsible(n,r,c,d,!0),d.addEventListener("click",()=>this.toggleCollapsible(n)),l.addEventListener("contextmenu",v=>{v.preventDefault(),v.stopPropagation(),y.click()});const b=Os(t,this.lastTreesByProject.get(n)??[],e),x=a?b:Xe(ve(b));if(x.length===0){const v=document.createElement("div");v.className="nav-label nav-empty-copy",v.textContent="No folders found.",r.appendChild(v)}else r.appendChild(this.renderCanonicalNodes(t,x,0,a));return c.append(l,r),c}renderCanonicalNodes(t,e,n,s){const o=document.createElement("div");for(const a of Us(e)){if(a.kind==="doc"||a.kind==="board"||a.kind==="capability"||a.kind==="file"){o.appendChild(this.renderCanonicalFile(a,n));continue}const r=document.createElement("div");r.className="nav-tree-group",r.style.setProperty("--tree-depth",String(n));const c=document.createElement("div");c.className="nav-tree-children";const l=document.createElement("button");l.className="nav-tree-row nav-tree-folder"+(a.kind==="docsRoot"?" nav-tree-docs-root":"")+(a.docsContainerRoot?" nav-tree-docs-container":"")+(a.root?"":" nav-tree-scaffold"),l.type="button",l.style.setProperty("--tree-depth",String(n));const d=document.createElement("span");d.className="nav-repo-chevron",d.textContent="›";const h=_s(a);h&&l.classList.add("nav-tree-capability-folder");const p=document.createElement("span");if(p.textContent=a.name,l.appendChild(d),h&&l.insertAdjacentHTML("beforeend",Re),l.appendChild(p),a.kind==="docsRoot"||a.docsContainerRoot){const g=document.createElement("span");g.className="nav-tree-badge",g.textContent="DOCS",l.appendChild(g)}const m=a.kind==="docsRoot"||a.docsContainerRoot?(a.docsContainerRoot??a.root).id:a.root?`doc:${a.root.id}:${a.contentPath??""}`:`folder:${t.id}:${a.projectPath}`;if(this.registerCollapsible(m,c,r,l,!0),l.addEventListener("click",()=>this.toggleCollapsible(m)),a.kind==="docsRoot"||a.docsContainerRoot){const g=a.docsContainerRoot??a.root;l.addEventListener("contextmenu",y=>{y.preventDefault(),y.stopPropagation(),this.openDirContextMenu(y.clientX,y.clientY,g,"")}),this.enableDirectoryDropTarget(r,g.id,"")}else if(a.root){const g=a.root,y=a.contentPath??"";this.enableDragSource(l,{kind:"dir",rootId:g.id,path:y}),this.enableDirectoryDropTarget(r,g.id,y),r.addEventListener("contextmenu",b=>{b.preventDefault(),b.stopPropagation(),this.openDirContextMenu(b.clientX,b.clientY,g,y)})}else l.addEventListener("contextmenu",g=>{g.preventDefault(),g.stopPropagation(),this.showContextMenu(g.clientX,g.clientY,a.name,[{icon:At,iconClass:"nav-ctx-dir",label:"Create docs folder here",action:()=>this.callbacks.onCreateDocsFolder(t.id,a.projectPath)}])});c.appendChild(this.renderCanonicalNodes(t,a.children,n+1,s)),r.append(l,c),o.appendChild(r)}return o}renderCanonicalFile(t,e){if(t.kind==="file"){if(t.root&&t.contentPath&&ie(t.contentPath)){const l=document.createElement("button");return l.className="nav-link nav-tree-row nav-tree-file nav-tree-capability-file",l.type="button",l.style.setProperty("--tree-depth",String(e)),l.insertAdjacentHTML("afterbegin",Le),l.appendChild(document.createTextNode(t.name)),l.addEventListener("click",d=>{d.preventDefault(),this.callbacks.onOpenTextFile(t.root.id,t.contentPath)}),l.addEventListener("contextmenu",d=>{d.preventDefault(),d.stopPropagation(),this.openTextFileContextMenu(d.clientX,d.clientY,t.root,t.contentPath)}),l}const c=document.createElement("div");return c.className="nav-tree-row nav-tree-file",c.style.setProperty("--tree-depth",String(e)),c.textContent=t.name,c}const n=t.root,s=t.contentPath,o=t.kind==="doc"?sn(n.id,s):t.kind==="board"?on(n.id,G(s)):js(n.id,s),a=t.kind==="doc"&&t.name==="index.md"?"Overview":Nt(t.kind==="board"?G(t.name):t.name),r=this.link(o,a,`${t.kind}:${n.id}:${s}`);return r.classList.add("nav-tree-row",`nav-tree-${t.kind}`),r.style.setProperty("--tree-depth",String(e)),r.insertAdjacentHTML("afterbegin",t.kind==="board"?Dt:t.kind==="capability"?Re:Et),this.enableDragSource(r,t.kind==="board"?{kind:"board",rootId:n.id,boardId:G(s)}:t.kind==="capability"?{kind:"capability",rootId:n.id,path:s}:{kind:"doc",rootId:n.id,path:s}),r.addEventListener("contextmenu",c=>{c.preventDefault(),c.stopPropagation(),t.kind==="board"?this.openBoardContextMenu(c.clientX,c.clientY,n,G(s)):t.kind==="doc"&&this.openDocContextMenu(c.clientX,c.clientY,n,s)}),r}renderBrowseNode(t,e,n){if(e.type==="file"){const p=document.createElement("div");return p.className="nav-browse-file",p.textContent=e.name,p}if(e.name==="docs"){const p=t.docsRoots.find(m=>m.displayPath===e.path||m.displayPath.endsWith("/"+e.path));if(p){const m=n.get(p.id)??[];return this.docsRootSection(p,m)}}const o=Gn(e),a=`browse:${t.id}:${e.path}`,r=document.createElement("div");r.className=o?"nav-subgroup nav-collapsible-dir":"nav-subgroup nav-browse-dir";const c=document.createElement("div");c.className="nav-dir-body";const l=document.createElement("button");l.className=o?"nav-dir-toggle nav-dir-project":"nav-browse-dir-toggle",l.type="button";const d=document.createElement("span");d.className="nav-repo-chevron",d.textContent="›";const h=document.createElement("span");if(h.textContent=e.name,l.append(d,h),l.addEventListener("click",()=>this.toggleCollapsible(a)),o){const p=t.docsRoots.find(m=>m.displayPath.startsWith(e.path+"/")||m.displayPath===e.path);p&&l.addEventListener("contextmenu",m=>{m.preventDefault(),m.stopPropagation(),this.openDirContextMenu(m.clientX,m.clientY,p,"")})}else l.addEventListener("contextmenu",p=>{p.preventDefault(),p.stopPropagation(),this.showContextMenu(p.clientX,p.clientY,e.name,[{icon:At,iconClass:"nav-ctx-dir",label:"Create /docs/",action:()=>this.callbacks.onCreateDocsFolder(t.id,e.path)}])});for(const p of e.children)p.type==="dir"&&c.appendChild(this.renderBrowseNode(t,p,n));return this.registerCollapsible(a,c,r,l,!0),r.append(l,c),r}renderPathNodes(t,e,n,s=""){const o=document.createElement("div");for(const a of t)if(a.kind==="root")o.appendChild(this.docsRootSection(a.root,e.get(a.root.id)??[]));else{const r=s?`${s}/${a.segment}`:a.segment,c=`pathseg:${n}:${r}`,l=this.renderPathNodes(a.children,e,n,r);l.classList.add("nav-dir-body");const d=document.createElement("div");d.className="nav-subgroup nav-collapsible-dir";const h=Zn(a),{row:p,toggle:m}=this.createDirectoryRow(a.segment,`#/project/${encodeURIComponent(n)}`,`${a.segment} wiki`,()=>this.toggleCollapsible(c),!0);h&&d.addEventListener("contextmenu",g=>{g.preventDefault(),g.stopPropagation(),this.openDirContextMenu(g.clientX,g.clientY,h,"")}),this.registerCollapsible(c,l,d,m,!0),d.append(p,l),o.appendChild(d)}return o}docsRootSection(t,e){const n=document.createElement("div");n.className="nav-subgroup nav-docs-root";const s=t.displayPath.split("/").pop()??t.displayPath;if(s.toLowerCase()!=="docs"){const a=document.createElement("div");a.className="nav-root-path-label",a.textContent=s,n.appendChild(a),a.addEventListener("contextmenu",r=>{r.preventDefault(),r.stopPropagation(),this.openDirContextMenu(r.clientX,r.clientY,t,"")})}return n.addEventListener("contextmenu",a=>{var r;(r=a.target)!=null&&r.closest(".nav-link, .nav-dir-toggle")||(a.preventDefault(),a.stopPropagation(),this.openDirContextMenu(a.clientX,a.clientY,t,""))}),this.enableDirectoryDropTarget(n,t.id,""),n.appendChild(this.docsNodes(t,As(e),"",e)),n}createDirectoryRow(t,e,n,s,o=!1){const a=document.createElement("div");a.className="nav-dir-header-row";const r=document.createElement("button");r.className=o?"nav-dir-toggle nav-dir-project":"nav-dir-toggle nav-dir-docs",r.type="button";const c=document.createElement("span");c.className="nav-repo-chevron",c.innerHTML='<svg viewBox="0 0 16 16" width="10" height="10" fill="currentColor"><path d="M6 4l4 4-4 4"/></svg>';const l=document.createElement("span");l.textContent=t,r.append(c,l),r.addEventListener("click",s);const d=document.createElement("a");return d.className="nav-repo-wiki-link nav-dir-wiki-link",d.href=e,d.title=n,d.innerHTML='<svg viewBox="0 0 14 14" fill="none" stroke="currentColor" stroke-width="1.6" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><rect x="2" y="2" width="10" height="10" rx="2"/><path d="M5 5h4M5 7h4M5 9h2"/></svg>',d.addEventListener("click",h=>h.stopPropagation()),this.links.set(e,d),a.append(r,d),{row:a,toggle:r}}docsNodes(t,e,n,s){const o=document.createElement("div"),a=Kn(e),r=Ns(s,n),c=[...a.map(l=>({kind:l.type==="file"&&ie(l.path)?"file":"doc",node:l})),...r.map(l=>({kind:"board",name:Nt(G(l.path).split("/").pop()??G(l.path)),boardId:G(l.path)}))].sort((l,d)=>{const h=l.kind==="doc"&&l.node.type==="file"&&l.node.name==="index.md",p=d.kind==="doc"&&d.node.type==="file"&&d.node.name==="index.md";if(h!==p)return h?-1:1;const m=(l.kind==="doc"||l.kind==="file")&&l.node.type==="file"&&_e(l.node.name),g=(d.kind==="doc"||d.kind==="file")&&d.node.type==="file"&&_e(d.node.name);if(m!==g)return m?-1:1;const y=(l.kind==="doc"||l.kind==="file")&&l.node.type==="dir",b=(d.kind==="doc"||d.kind==="file")&&d.node.type==="dir";if(y!==b)return y?-1:1;const x=l.kind==="board"?l.name:l.node.name,v=d.kind==="board"?d.name:d.node.name;return x.localeCompare(v)});for(const l of c)if(l.kind==="board"){const d=document.createElement("a");d.className="nav-link nav-link-board",d.href=on(t.id,l.boardId),d.insertAdjacentHTML("afterbegin",Dt),d.appendChild(document.createTextNode(l.name));const h=`board:${t.id}:${l.boardId}`;this.links.set(h,d),this.links.set(d.href,d),this.enableDragSource(d,{kind:"board",rootId:t.id,boardId:l.boardId}),d.addEventListener("contextmenu",p=>{p.preventDefault(),p.stopPropagation(),this.openBoardContextMenu(p.clientX,p.clientY,t,l.boardId)}),o.appendChild(d)}else{const{node:d}=l;if(d.type==="file"){if(l.kind==="file"){const m=document.createElement("button");m.className="nav-link nav-tree-file nav-tree-capability-file",m.type="button",m.insertAdjacentHTML("afterbegin",Le),m.appendChild(document.createTextNode(d.name)),m.addEventListener("click",()=>this.callbacks.onOpenTextFile(t.id,d.path)),m.addEventListener("contextmenu",g=>{g.preventDefault(),g.stopPropagation(),this.openTextFileContextMenu(g.clientX,g.clientY,t,d.path)}),o.appendChild(m);continue}if(!d.name.endsWith(".md"))continue;const h=d.name==="index.md"?"Overview":Nt(d.name),p=this.link(sn(t.id,d.path),h,`doc:${t.id}:${d.path}`);p.insertAdjacentHTML("afterbegin",Et),this.enableDragSource(p,{kind:"doc",rootId:t.id,path:d.path}),p.addEventListener("contextmenu",m=>{m.preventDefault(),m.stopPropagation(),this.openDocContextMenu(m.clientX,m.clientY,t,d.path)}),o.appendChild(p)}else{const h=`doc:${t.id}:${d.path}`,p=this.docsNodes(t,d.children,d.path,s);p.classList.add("nav-dir-body");const m=document.createElement("div");m.className="nav-subgroup nav-collapsible-dir";const{row:g,toggle:y}=this.createDirectoryRow(Nt(d.name),`#/root/${encodeURIComponent(t.id)}/directory/${encodeURIComponent(d.path)}`,`${d.name} wiki`,b=>{b.button===0&&this.toggleCollapsible(h)},!1);this.enableDragSource(y,{kind:"dir",rootId:t.id,path:d.path}),m.addEventListener("contextmenu",b=>{b.preventDefault(),b.stopPropagation(),this.openDirContextMenu(b.clientX,b.clientY,t,d.path)}),this.enableDirectoryDropTarget(m,t.id,d.path),this.registerCollapsible(h,p,m,y,!0),m.append(g,p),o.appendChild(m)}}return o}enableDragSource(t,e){t.draggable=!0,t.addEventListener("dragstart",n=>{var s,o;this.closeContextMenu(),this.draggedItem=e,t.classList.add("nav-dragging"),(s=n.dataTransfer)==null||s.setData("application/x-docs-nav-item",JSON.stringify(e)),(o=n.dataTransfer)==null||o.setData("text/plain",Xs(e)),n.dataTransfer&&(n.dataTransfer.effectAllowed="move")}),t.addEventListener("dragend",()=>{t.classList.remove("nav-dragging"),this.draggedItem=void 0,this.clearDropTargets()})}enableDirectoryDropTarget(t,e,n){t.addEventListener("dragover",s=>{const o=this.currentDragItem(s);!o||!this.canDropItem(o,e,n)||(s.preventDefault(),s.stopPropagation(),s.dataTransfer&&(s.dataTransfer.dropEffect="move"),t.classList.add("nav-drop-target"),this.scheduleDropExpand(t))}),t.addEventListener("dragleave",s=>{t.contains(s.relatedTarget)||(t.classList.remove("nav-drop-target"),this.clearDropExpand(t))}),t.addEventListener("drop",s=>{const o=this.currentDragItem(s);!o||!this.canDropItem(o,e,n)||(s.preventDefault(),s.stopPropagation(),this.clearDropExpand(t),this.clearDropTargets(),this.moveDraggedItem(o,n))})}scheduleDropExpand(t){this.dropExpandTarget===t||!t.dataset.collapsibleKey||(this.clearDropExpand(),this.dropExpandTarget=t,this.dropExpandTimer=window.setTimeout(()=>{const e=t.dataset.collapsibleKey;e&&this.applyCollapsed(e,!1),t.classList.add("nav-drop-auto-expanded"),this.dropExpandTimer=void 0},650))}clearDropExpand(t){var e;t&&this.dropExpandTarget!==t||(this.dropExpandTimer!==void 0&&window.clearTimeout(this.dropExpandTimer),this.dropExpandTimer=void 0,(e=this.dropExpandTarget)==null||e.classList.remove("nav-drop-auto-expanded"),this.dropExpandTarget=void 0)}currentDragItem(t){var n;if(this.draggedItem)return this.draggedItem;const e=(n=t.dataTransfer)==null?void 0:n.getData("application/x-docs-nav-item");if(e)try{const s=JSON.parse(e);if(s&&(s.kind==="doc"||s.kind==="capability"||s.kind==="board"||s.kind==="dir")&&typeof s.rootId=="string")return s}catch{}}canDropItem(t,e,n){if(t.rootId!==e)return!1;const s=xt(n);if(t.kind==="doc")return Ct(t.path)!==s;if(t.kind==="capability")return s==="capabilities"||s.startsWith("capabilities/")&&Ct(t.path)!==s;if(t.kind==="board")return Ct(t.boardId)!==s;const o=xt(t.path);return!o||o===s||Ct(o)===s?!1:!s.startsWith(`${o}/`)}moveDraggedItem(t,e){const n=xt(e);t.kind==="doc"||t.kind==="capability"?this.callbacks.onMoveDoc(t.rootId,t.path,n):t.kind==="board"?this.callbacks.onMoveBoard(t.rootId,t.boardId,n):this.callbacks.onMoveDirectory(t.rootId,t.path,n)}clearDropTargets(){this.clearDropExpand(),this.element.querySelectorAll(".nav-drop-target").forEach(t=>{t.classList.remove("nav-drop-target")})}startInlineRename(t,e,n){const s=document.createElement("input");s.className="nav-inline-input",s.value=e.replace(/\.md$/,"");const o=t.parentElement;if(!o)return;t.style.display="none",o.insertBefore(s,t.nextSibling),s.focus(),s.select();let a=!1;const r=c=>{if(!a&&(a=!0,s.remove(),t.style.display="",c)){const l=s.value.trim();l&&l!==e.replace(/\.md$/,"")&&n(l)}};s.addEventListener("keydown",c=>{c.stopPropagation(),c.key==="Enter"&&(c.preventDefault(),r(!0)),c.key==="Escape"&&(c.preventDefault(),r(!1))}),s.addEventListener("blur",()=>r(!0))}startInlineCreate(t,e,n){const s=document.createElement("input");s.className="nav-inline-input",s.placeholder=e,t.insertBefore(s,t.firstChild),s.focus();let o=!1;const a=r=>{if(!o&&(o=!0,s.remove(),r)){const c=s.value.trim();c&&n(c)}};s.addEventListener("keydown",r=>{r.stopPropagation(),r.key==="Enter"&&(r.preventDefault(),a(!0)),r.key==="Escape"&&(r.preventDefault(),a(!1))}),s.addEventListener("blur",()=>a(!0))}registerCollapsible(t,e,n,s,o){this.collapsibles.set(t,{body:e,group:n,btn:s}),n.dataset.collapsibleKey=t,this.applyCollapsed(t,this.collapsedState.get(t)??o)}applyCollapsed(t,e){const n=this.collapsibles.get(t);n&&(this.collapsedState.set(t,e),n.body.hidden=e,n.group.classList.toggle("collapsed",e),n.btn.setAttribute("aria-expanded",String(!e)))}toggleCollapsible(t){const e=this.collapsibles.get(t);e&&this.applyCollapsed(t,!e.body.hidden)}openDirContextMenu(t,e,n,s){const o=s?Nt(s.split("/").pop()??s):n.displayPath.split("/").pop()??n.displayPath,a=[{icon:At,iconClass:"nav-ctx-dir",label:"New Directory",action:()=>this.callbacks.onCreateDirectory(n.id,s)},{icon:Dt,iconClass:"nav-ctx-board",label:"New Board",action:()=>this.callbacks.onCreateBoard(n.id,s)},{icon:Et,iconClass:"nav-ctx-doc",label:"New Doc",action:()=>this.callbacks.onCreateDoc(n.id,s)},{icon:Re,iconClass:"nav-ctx-cap",label:"New Capability",action:()=>this.callbacks.onCreateCapability(n.id,s)}];s&&a.push({icon:le,iconClass:"nav-ctx-rename",label:"Rename",action:()=>this.callbacks.onRenameDirectory(n.id,s)},{icon:Vt,iconClass:"nav-ctx-delete",label:"Delete",action:()=>this.callbacks.onDeleteDirectory(n.id,s)}),this.showContextMenu(t,e,o,a)}openEmptyProjectContextMenu(t,e,n,s){this.showContextMenu(t,e,s,[{icon:At,iconClass:"nav-ctx-dir",label:"New Directory",action:()=>this.callbacks.onCreateProjectDirectory(n)},{icon:Dt,iconClass:"nav-ctx-board",label:"New Board",action:()=>this.callbacks.onCreateProjectBoard(n)},{icon:Et,iconClass:"nav-ctx-doc",label:"New Doc",action:()=>this.callbacks.onCreateProjectDoc(n)}])}openDocContextMenu(t,e,n,s){const o=s.split("/").pop()??s;this.showContextMenu(t,e,o,[{icon:Et,iconClass:"nav-ctx-doc",label:"Open",action:()=>this.callbacks.onOpenDoc(n.id,s)},{icon:$e,iconClass:"nav-ctx-edit",label:"Edit",action:()=>this.callbacks.onEditDoc(n.id,s)},{kind:"divider"},{icon:le,iconClass:"nav-ctx-rename",label:"Rename",action:()=>this.callbacks.onRenameDoc(n.id,s)},{icon:Vt,iconClass:"nav-ctx-delete",label:"Delete",action:()=>this.callbacks.onDeleteDoc(n.id,s),danger:!0}])}openTextFileContextMenu(t,e,n,s){const o=s.split("/").pop()??s;this.showContextMenu(t,e,o,[{icon:Le,iconClass:"nav-ctx-doc",label:"Open",action:()=>this.callbacks.onOpenTextFile(n.id,s)},{icon:$e,iconClass:"nav-ctx-edit",label:"Edit",action:()=>this.callbacks.onOpenTextFile(n.id,s)},{kind:"divider"},{icon:le,iconClass:"nav-ctx-rename",label:"Rename",action:()=>this.callbacks.onRenameDoc(n.id,s)},{icon:Vt,iconClass:"nav-ctx-delete",label:"Delete",action:()=>this.callbacks.onDeleteDoc(n.id,s),danger:!0}])}openBoardContextMenu(t,e,n,s){const o=Nt(s.split("/").pop()??s);this.showContextMenu(t,e,o,[{icon:Dt,iconClass:"nav-ctx-board",label:"Open",action:()=>this.callbacks.onOpenBoard(n.id,s)},{kind:"divider"},{icon:le,iconClass:"nav-ctx-rename",label:"Rename",action:()=>this.callbacks.onRenameBoard(n.id,s)},{icon:Vt,iconClass:"nav-ctx-delete",label:"Delete",action:()=>this.callbacks.onDeleteBoard(n.id,s),danger:!0}])}showContextMenu(t,e,n,s){this.closeContextMenu();const o=document.createElement("div");o.className="nav-context-menu",o.addEventListener("pointerdown",c=>c.stopPropagation());const a=document.createElement("div");a.className="nav-context-label",a.textContent=n,o.appendChild(a);const r=document.createElement("div");r.className="nav-context-divider",o.appendChild(r);for(const c of s){if(c.kind==="divider"){const p=document.createElement("div");p.className="nav-context-divider",o.appendChild(p);continue}const l=document.createElement("button");l.className="nav-context-item"+(c.danger?" nav-context-item-danger":""),l.type="button";const d=document.createElement("span");d.className=`nav-ctx-icon ${c.iconClass}`,d.innerHTML=c.icon;const h=document.createElement("span");h.textContent=c.label,l.append(d,h),l.addEventListener("click",()=>{this.closeContextMenu(),c.action()}),o.appendChild(l)}o.style.position="fixed",o.style.left=`${t}px`,o.style.top=`${e}px`,document.body.appendChild(o),this.contextMenu=o,requestAnimationFrame(()=>{if(!this.contextMenu)return;const c=o.getBoundingClientRect();c.right>window.innerWidth&&(o.style.left=`${Math.max(0,t-c.width)}px`),c.bottom>window.innerHeight&&(o.style.top=`${Math.max(0,e-c.height)}px`)})}closeContextMenu(){var t;(t=this.contextMenu)==null||t.remove(),this.contextMenu=void 0}groupLabel(t){const e=document.createElement("div");return e.className="nav-label",e.textContent=t,e}link(t,e,n){const s=document.createElement("a");return s.className="nav-link",s.href=t,s.textContent=e,this.links.set(n,s),this.links.set(t,s),s}}const Dt='<svg class="nav-node-icon nav-node-icon-board" viewBox="0 0 16 16" aria-hidden="true"><rect x="1" y="1" width="6" height="6" rx="1"/><rect x="9" y="1" width="6" height="6" rx="1"/><rect x="1" y="9" width="6" height="6" rx="1"/><rect x="9" y="9" width="6" height="6" rx="1"/></svg>',Re='<svg class="nav-node-icon nav-node-icon-capability" viewBox="0 0 16 16" aria-hidden="true"><path d="M8 1l2 4.5 4.5 0.7-3.3 3.1 0.8 4.7-4-2.1-4 2.1 0.8-4.7L1.5 6.2l4.5-0.7z"/></svg>',Et='<svg class="nav-node-icon nav-node-icon-doc" viewBox="0 0 16 16" aria-hidden="true"><path d="M3 1.5h6.5l3 3V14.5H3z"/><path d="M9.5 1.5V4.5h3" stroke="none"/><line x1="5" y1="7" x2="11" y2="7" stroke="var(--bg-canvas)" stroke-width="0.8"/><line x1="5" y1="9.5" x2="11" y2="9.5" stroke="var(--bg-canvas)" stroke-width="0.8"/><line x1="5" y1="12" x2="9" y2="12" stroke="var(--bg-canvas)" stroke-width="0.8"/></svg>',Le='<svg class="nav-node-icon nav-node-icon-doc" viewBox="0 0 16 16" aria-hidden="true"><path d="M3 1.5h6.5l3 3V14.5H3z"/><path d="M9.5 1.5V4.5h3" stroke="none"/><line x1="5" y1="7" x2="11" y2="7" stroke="var(--bg-canvas)" stroke-width="0.8"/><line x1="5" y1="9.5" x2="11" y2="9.5" stroke="var(--bg-canvas)" stroke-width="0.8"/></svg>',At='<svg class="nav-ctx-svg" viewBox="0 0 16 16" aria-hidden="true" fill="none" stroke="currentColor" stroke-width="1.45" stroke-linecap="round" stroke-linejoin="round"><path d="M2 4.5h4l1.4 1.6H14v6.4a1 1 0 0 1-1 1H3a1 1 0 0 1-1-1z"/><path d="M2 4.5v-1a1 1 0 0 1 1-1h3l1.4 2"/></svg>',$e='<svg class="nav-ctx-svg" viewBox="0 0 16 16" aria-hidden="true" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><path d="M11 2l3 3-8 8H3v-3z"/></svg>',le='<svg class="nav-ctx-svg" viewBox="0 0 16 16" aria-hidden="true" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><path d="M2 12h12M8 3v9M5 6l3-3 3 3"/></svg>',Vt='<svg class="nav-ctx-svg" viewBox="0 0 16 16" aria-hidden="true" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><path d="M2 4h12M5 4V2h6v2M6 7v5M10 7v5M3 4l1 9a1 1 0 001 1h6a1 1 0 001-1l1-9"/></svg>';function Kn(i){return i.filter(t=>t.type==="file"?t.name.endsWith(".md")||ie(t.path):!Ps.has(t.name)).map(t=>t.type==="file"?t:{...t,children:Kn(t.children)})}function As(i){const t=i.find(e=>e.type==="dir"&&e.name.toLowerCase()==="docs");return!t||t.type!=="dir"?i:i.filter(e=>e!==t).concat(t.children)}function Ns(i,t){const e=t?`${t}/`:"";return zs(i).filter(n=>e?n.path.startsWith(e)?!n.path.slice(e.length).includes("/"):!1:!n.path.includes("/"))}function zs(i){const t=[],e=n=>{for(const s of n)s.type==="file"?s.name.endsWith(".board.json")&&t.push(s):e(s.children)};return e(i),t}function sn(i,t){return`#/root/${encodeURIComponent(i)}/docs/${encodeURIComponent(t)}`}function Hs(i){return`#/root/${encodeURIComponent(i)}/boards`}function on(i,t){return`#/root/${encodeURIComponent(i)}/boards/${encodeURIComponent(t)}`}function Fs(i){return`#/root/${encodeURIComponent(i)}/capabilities`}function js(i,t){return`#/root/${encodeURIComponent(i)}/capabilities/${encodeURIComponent(Ws(t))}`}function Ws(i){return i.replace(/^capabilities\//,"")}function Os(i,t,e){const n=new Map,s=[],o=c=>{const l=xt(c),d=n.get(l);if(d)return d;const h=Ct(l),p={id:`folder:${i.id}:${l}`,kind:"folder",name:l.split("/").pop()??i.label,projectPath:l,children:[]};return n.set(l,p),l&&h?o(h).children.push(p):s.push(p),p},a=c=>{for(const l of c)if(l.type==="dir")o(l.path),a(l.children);else{const d={id:`file:${i.id}:${l.path}`,kind:"file",name:l.name,projectPath:l.path,children:[]};n.set(l.path,d);const h=Ct(l.path);h?o(h).children.push(d):s.push(d)}};a(t);for(const c of i.docsRoots){const l=xt(c.displayPath),d=o(l);d.kind="docsRoot",d.id=`root:${c.id}`,d.root=c,d.contentPath="";const h=p=>{for(const m of p){const g=[l,m.path].filter(Boolean).join("/");if(m.type==="dir"){const E=o(g);E.kind!=="docsRoot"&&(E.root=c,E.contentPath=m.path),h(m.children);continue}const y=m.name.endsWith(".board.json"),b=Vn(m.path),x=ie(m.path);if(!m.name.endsWith(".md")&&!y&&!x)continue;const v=Ct(g),S=n.get(g),w=S??{id:"",kind:"file",name:m.name,projectPath:g,children:[]};w.id=`${y?"board":b?"capability":x?"file":"doc"}:${c.id}:${m.path}`,w.kind=y?"board":b?"capability":x?"file":"doc",w.root=c,w.contentPath=m.path,S||(n.set(g,w),v?o(v).children.push(w):s.push(w))}};h(e.get(c.id)??[])}const r=(c,l)=>{const d=c.kind==="docsRoot"?c.root:c.root??l;if(d&&(c.kind==="folder"||c.kind==="file")&&!c.contentPath){c.root=d;const h=xt(d.displayPath);c.contentPath=c.projectPath.slice(h.length).replace(/^\//,"")}for(const h of c.children)r(h,d)};for(const c of s)r(c);return s}function Us(i){return[...i].sort((t,e)=>{const n=s=>s.kind==="doc"&&s.name==="index.md"?0:(s.kind==="doc"||s.kind==="file")&&_e(s.name)?1:s.kind==="doc"?2:s.kind==="capability"?3:s.kind==="board"?4:s.kind==="folder"&&s.root&&!s.docsContainerRoot?5:s.kind==="folder"&&s.docsContainerRoot?6:s.kind==="folder"&&!s.root?7:s.kind==="docsRoot"?8:9;return n(t)-n(e)||t.name.localeCompare(e.name,void 0,{sensitivity:"accent"})})}function _e(i){return/^readme\.(md|txt)$/i.test(i)}function ve(i,t,e=!1){const n=[];for(const s of i){if(s.kind==="docsRoot"){n.push({...s,children:ve(s.children,!1,!0)});continue}if(e){if(s.kind==="file"){ie(s.contentPath??"")&&n.push(s);continue}if(s.kind==="folder"){const o=ve(s.children,!1,!0);(s.name!=="assets"||o.length>0)&&n.push({...s,children:o})}else n.push(s);continue}if(s.kind==="folder"){const o=ve(s.children);o.length>0&&n.push({...s,children:o})}}return n}function Xe(i){var e;const t=[];for(const n of i){if(n.kind==="docsRoot"){t.push(...Xe(n.children));continue}if(n.kind!=="folder"){t.push(n);continue}const s=(e=n.children.find(o=>o.kind==="docsRoot"))==null?void 0:e.root;t.push({...n,docsContainerRoot:s,children:Xe(n.children)})}return t}function Nt(i){const t=i.replace(/\.md$/,"").replace(/[-_]/g," ");return t.charAt(0).toUpperCase()+t.slice(1)}function Vn(i){if(!i.startsWith("capabilities/")||!i.endsWith(".md"))return!1;const t=i.slice(13);return t.includes("/")?t.endsWith("/index.md"):!0}function ie(i){return!i.startsWith("capabilities/")||i.endsWith(".board.json")?!1:!Vn(i)}function _s(i){var t;return i.kind!=="folder"||!((t=i.contentPath)!=null&&t.startsWith("capabilities/"))?null:i.children.find(e=>e.kind==="capability"&&Ct(e.contentPath??"")===i.contentPath)??null}function Gn(i){if(i.type==="file")return!1;for(const t of i.children)if(t.type==="dir"&&t.name==="docs"||t.type==="dir"&&Gn(t))return!0;return!1}function xt(i){return i.replace(/^\/+|\/+$/g,"")}function Ct(i){const t=xt(i),e=t.lastIndexOf("/");return e===-1?"":t.slice(0,e)}function Xs(i){return i.kind==="doc"||i.kind==="capability"?i.path:i.kind==="board"?i.boardId:i.path}function Zn(i){if(i.kind==="root")return i.root;for(const t of i.children){const e=Zn(t);if(e)return e}return null}function ne(i,t={}){const{frontmatter:e,body:n}=qs(i);try{const s=Jn(n.split(`
|
|
2
2
|
`),t);return{frontmatter:e,html:s}}catch(s){return console.error("Markdown render failed",s),{frontmatter:e,html:`<div class="md-error"><strong>Could not render this document.</strong><pre>${Ut(String(s))}</pre></div>`}}}function qs(i){const t={};if(!i.startsWith("---"))return{frontmatter:t,body:i};const e=i.indexOf(`
|
|
3
3
|
---`,3);if(e===-1)return{frontmatter:t,body:i};const n=i.slice(3,e).trim();for(const o of n.split(`
|
|
4
4
|
`)){const a=o.indexOf(":");a!==-1&&(t[o.slice(0,a).trim()]=o.slice(a+1).trim())}const s=i.slice(e+4).replace(/^\n+/,"");return{frontmatter:t,body:s}}function Jn(i,t){const e=[];let n=0,s=0;const o=i.length*4+1e3;for(;n<i.length;){if(++s>o)throw new Error(`renderBlocks exceeded ${o} iterations at line ${n} — aborting to avoid an infinite loop`);const a=i[n];if(a.trim()===""){n++;continue}const r=a.match(/^(`{3,})\s*(\w+)?\s*$/);if(r){const d=r[1].length,h=(r[2]??"").toLowerCase(),p=new RegExp("^`{"+d+",}\\s*$"),m=[];for(n++;n<i.length&&!p.test(i[n]);)m.push(i[n]),n++;n++,h==="board"?e.push(Vs(ts(m.join(`
|
|
5
5
|
`)))):e.push(`<pre class="code-block"><code${h?` class="language-${h}"`:""}>${Ut(m.join(`
|
|
6
6
|
`))}</code></pre>`);continue}const c=a.match(/^(#{1,6})\s+(.*)$/);if(c){const d=c[1].length,h=Lt(c[2].trim(),t),p=Js(c[2]);e.push(`<h${d} id="${p}">${h}</h${d}>`),n++;continue}if(/^(-{3,}|\*{3,}|_{3,})\s*$/.test(a)){e.push("<hr />"),n++;continue}if(/^>\s?/.test(a)){const d=[];for(;n<i.length&&/^>\s?/.test(i[n]);)d.push(i[n].replace(/^>\s?/,"")),n++;e.push(`<blockquote>${Jn(d,t)}</blockquote>`);continue}if(a.includes("|")&&n+1<i.length&&Ys(i[n+1])){const d=[];for(;n<i.length&&i[n].includes("|")&&i[n].trim()!=="";)d.push(i[n]),n++;e.push(Ks(d,t));continue}if(Wt(a)){const d=[];for(;n<i.length&&(Wt(i[n])||/^\s+\S/.test(i[n])||i[n].trim()==="");){if(i[n].trim()===""){const h=i[n+1];if(h===void 0||!Wt(h)&&!/^\s+\S/.test(h))break}d.push(i[n]),n++}e.push(Qn(d,t));continue}const l=[i[n]];for(n++;n<i.length&&i[n].trim()!==""&&!/^`{3,}/.test(i[n])&&!/^#{1,6}\s/.test(i[n])&&!/^>\s?/.test(i[n])&&!Wt(i[n])&&!/^(-{3,}|\*{3,}|_{3,})\s*$/.test(i[n]);)l.push(i[n]),n++;e.push(`<p>${Lt(l.join(" ").trim(),t)}</p>`)}return e.join(`
|
|
7
7
|
`)}function Wt(i){return/^\s*([-*+]|\d+\.)\s+/.test(i)}function Qn(i,t){const e=i.filter(l=>Wt(l)).map(l=>l.match(/^\s*/)[0].length);if(e.length===0)return Lt(i.join(" ").trim(),t);const n=Math.min(...e),s=[];let o=!1,a=null;for(const l of i){const d=l.match(/^\s*/)[0].length,h=l.match(/^\s*([-*+]|\d+\.)\s+(.*)$/);if(h&&d===n){o=/\d+\./.test(h[1]);let p=h[2],m=null;const g=p.match(/^\[([ xX])\]\s+(.*)$/);g&&(m=g[1].toLowerCase()==="x",p=g[2]),a={ordered:o,content:[p],checked:m},s.push(a)}else a&&a.content.push(l.slice(n))}const r=o?"ol":"ul",c=s.map(l=>{const d=l.content[0],h=l.content.slice(1);let p=Lt(d,t);const m=h.filter(g=>g.trim()!=="");return m.some(g=>Wt(g))?p+=Qn(h,t):m.length&&(p+=" "+Lt(m.join(" ").trim(),t)),l.checked!==null?`<li class="task">${`<input type="checkbox" disabled${l.checked?" checked":""} /> `}${p}</li>`:`<li>${p}</li>`}).join("");return`<${r}>${c}</${r}>`}function Ys(i){return/^\s*\|?\s*:?-{1,}:?\s*(\|\s*:?-{1,}:?\s*)*\|?\s*$/.test(i)}function Pe(i){return i.trim().replace(/^\|/,"").replace(/\|$/,"").split("|").map(t=>t.trim())}function Ks(i,t){const e=Pe(i[0]),n=Pe(i[1]).map(r=>{const c=r.startsWith(":"),l=r.endsWith(":");return c&&l?"center":l?"right":c?"left":""}),s=i.slice(2).map(Pe),o=e.map((r,c)=>`<th${n[c]?` style="text-align:${n[c]}"`:""}>${Lt(r,t)}</th>`).join(""),a=s.map(r=>`<tr>${r.map((c,l)=>`<td${n[l]?` style="text-align:${n[l]}"`:""}>${Lt(c,t)}</td>`).join("")}</tr>`).join("");return`<div class="markdown-table-scroll"><table><thead><tr>${o}</tr></thead><tbody>${a}</tbody></table></div>`}function ts(i){const t={};for(const n of i.split(`
|
|
8
|
-
`)){const s=n.replace(/#.*$/,"").trim();if(!s)continue;const o=s.indexOf(":");o!==-1&&(t[s.slice(0,o).trim()]=s.slice(o+1).trim())}let e=null;if(t.region){const n=t.region.split(",").map(s=>parseFloat(s.trim()));n.length===4&&n.every(s=>Number.isFinite(s))&&(e=[n[0],n[1],n[2],n[3]])}return{src:t.src??"",region:e,height:t.height?Math.max(120,parseInt(t.height,10)||360):360,title:t.title??null}}function Vs(i){const t=i.region?i.region.join(","):"";return`<figure class="board-embed" data-src="${Mt(i.src)}" data-region="${t}" data-height="${i.height}" data-title="${Mt(i.title??"")}"></figure>`}function Lt(i,t){let e=i;const n=[];e=e.replace(/\\([\\`*_{}\[\]()#+\-.!|])/g,(a,r)=>(n.push(r),`${n.length-1}`));const s=[];e=e.replace(/`([^`]+)`/g,(a,r)=>(s.push(`<code>${Ut(de(r,n))}</code>`),`\0${s.length-1}\0`));const o=[];return e=e.replace(/!\[([^\]]*)\]\(([^)\s]+)\)/g,(a,r,c)=>{const l=de(c,n),d=
|
|
9
|
-
`)){if(a===""){o.push("");continue}const r=a.split(" ");let c="";for(const l of r){const d=c===""?l:c+" "+l;i.measureText(d).width>n&&c!==""?(o.push(c),c=l):c=d}o.push(c)}return Ot.size>ii&&Ot.clear(),Ot.set(t,o),o}function _t(i,t,e,n,s,o){const a=Math.min(o,n/2,s/2);i.beginPath(),i.moveTo(t+a,e),i.arcTo(t+n,e,t+n,e+s,a),i.arcTo(t+n,e+s,t,e+s,a),i.arcTo(t,e+s,t,e,a),i.arcTo(t,e,t+n,e,a),i.closePath()}function xe(i,t){const{ctx:e,lod:n}=t;if(e.save(),e.globalAlpha=i.style.opacity??1,n===0){ai(i,t),e.restore();return}switch(i.type){case"sticky":ri(i,t);break;case"task":ci(i,t);break;case"rectangle":case"frame":rn(i,t);break;case"ellipse":fi(i,t);break;case"text":gi(i,t);break;case"line":case"arrow":case"connector":vi(i,t);break;case"image":case"screenshot":wi(i,t);break;default:rn(i,t)}e.restore()}function ai(i,t){const{ctx:e}=t;if(i.type==="line"||i.type==="arrow"||i.type==="connector"){e.strokeStyle=i.style.stroke??(t.theme==="dark"?"#888":"#999"),e.lineWidth=Math.max(1/t.scale,i.style.strokeWidth??2),e.beginPath(),e.moveTo(i.x,i.y),e.lineTo(i.x+i.width,i.y+i.height),e.stroke();return}e.fillStyle=i.style.fill??(t.theme==="dark"?"#3a3d42":"#d8d8d4"),e.fillRect(i.x,i.y,i.width,i.height)}function Be(i,t){i.style.shadow&&t.lod===2&&(t.ctx.shadowColor=t.theme==="dark"?"rgba(0,0,0,0.5)":"rgba(0,0,0,0.14)",t.ctx.shadowBlur=8*t.scale,t.ctx.shadowOffsetY=2*t.scale)}function Me(i){i.ctx.shadowColor="transparent",i.ctx.shadowBlur=0,i.ctx.shadowOffsetY=0}function ri(i,t){const{ctx:e,lod:n}=t,s=i.style.fill??"#fef08a";if(Be(i,t),_t(e,i.x,i.y,i.width,i.height,i.style.borderRadius??12),e.fillStyle=s,e.fill(),Me(t),n===2){const o=i.data.text??"";o&&
|
|
10
|
-
`)});continue}const a=o.match(/^(#{1,3})\s+(.*)$/);if(a){e.push({kind:"heading",level:a[1].length,text:a[2]});continue}const r=o.match(/^>\s?(.*)$/);if(r){e.push({kind:"quote",text:r[1]});continue}const c=o.match(/^([-*+]|\d+\.)\s+(.*)$/);if(c){e.push({kind:"list",text:c[2]});continue}e.push({kind:"paragraph",text:s})}return e}function It(i){if(i.type!=="text")return;const t=String(i.data.text??""),e=ns(t),n=Te(i);let s=0;for(const o of e){if(o.kind==="code"){s+=Math.max(1,o.text.split(/\r?\n/).length)+1;continue}const a=Math.max(1,Math.floor(Math.max(120,i.width)/Math.max(6,n*.6))),r=o.text.replace(/[*_`#>-]/g,"");s+=Math.max(1,Math.ceil(Math.max(1,r.length)/a))}i.height=Math.max(n*1.45,s*n*1.35+8)}function bi(i){const t=[];let e=0;for(;e<i.length;){if(i.startsWith("**",e)){const s=i.indexOf("**",e+2);if(s!==-1){t.push({text:i.slice(e+2,s),bold:!0}),e=s+2;continue}}if(i.startsWith("*",e)){const s=i.indexOf("*",e+1);if(s!==-1){t.push({text:i.slice(e+1,s),italic:!0}),e=s+1;continue}}if(i.startsWith("`",e)){const s=i.indexOf("`",e+1);if(s!==-1){t.push({text:i.slice(e+1,s),code:!0}),e=s+1;continue}}let n=i.length;for(const s of["**","*","`"]){const o=i.indexOf(s,e+1);o!==-1&&o<n&&(n=o)}t.push({text:i.slice(e,n)}),e=n}return t.filter(n=>n.text.length>0)}function cn(i,t,e,n,s){const o=[[]];let a=0;for(const r of t){const c=r.text.split(/(\s+)/);for(const l of c){if(!l)continue;const d={...r,text:l};Xe(i,d,n,s);const h=i.measureText(l).width;a>0&&a+h>e&&l.trim()&&(o.push([]),a=0),o[o.length-1].push(d),a+=h}}return o}function Xe(i,t,e,n){const s=t.bold?"700":"400",o=t.italic?"italic ":"",a=t.code?'"SF Mono", ui-monospace, Menlo, monospace':n;i.font=`${o}${s} ${e}px ${a}`}function Ve(i,t,e,n,s="center",o="middle"){const{ctx:a}=t,r=i.data.shapeKind==="chevron",c=Te(i),l=i.style.fontFamily??'-apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif',d=r?"750":i.style.fontWeight??"400";a.font=`${d} ${c}px ${l}`,a.fillStyle=i.style.textColor??(t.theme==="dark"&&i.type==="text"?"#f2f2f2":"#1f2933");const h=Math.max(10,i.width-n*2),p=`${i.id}|${i.updatedAt}|${c}|${h.toFixed(0)}`,m=oi(a,p,e,h),g=c*1.35,y=m.length*g;let b;o==="middle"?b=i.y+i.height/2-y/2+g/2:b=i.y+n+g/2,a.textBaseline="middle",a.textAlign=s;const x=s==="center"?i.x+i.width/2:i.x+n;a.save(),a.beginPath(),a.rect(i.x,i.y,i.width,i.height),a.clip();for(let v=0;v<m.length;v++)a.fillText(m[v],x,b+v*g);a.restore()}function vi(i,t){const{ctx:e,lod:n}=t,s=i.x,o=i.y,a=i.x+i.width,r=i.y+i.height,c=i.style.stroke??(t.theme==="dark"?"#d1d5db":"#374151"),l=i.style.strokeWidth??2;if(e.strokeStyle=c,e.fillStyle=c,e.lineWidth=l,e.setLineDash(i.style.strokeDash??[]),e.beginPath(),e.moveTo(s,o),e.lineTo(a,r),e.stroke(),e.setLineDash([]),n>=1){const d=Math.atan2(r-o,a-s),h=Math.max(11,l*5.5);(i.style.arrowEnd??i.type==="arrow")&&ln(e,a,r,d,h),i.style.arrowStart&&ln(e,s,o,d+Math.PI,h);const p=typeof i.data.text=="string"?i.data.text.trim():"";if(p)if(i.data.labelPosition==="sides"){const[m,g]=p.split("|").map(y=>y.trim());m&&De(e,m,s,o,a,r,t,.24),g&&De(e,g,s,o,a,r,t,.76)}else De(e,p,s,o,a,r,t)}}function De(i,t,e,n,s,o,a,r=.5){i.font='600 13px -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif';const h=i.measureText(t).width+7*2,p=21,m=e+(s-e)*r-h/2,g=n+(o-n)*r-p/2;i.fillStyle=a.theme==="dark"?"#202328":"#ffffff",_t(i,m,g,h,p,4),i.fill(),i.strokeStyle=a.theme==="dark"?"#4a4d52":"#d8dade",i.lineWidth=1,i.stroke(),i.fillStyle=a.theme==="dark"?"#f2f2f2":"#1f2933",i.textAlign="center",i.textBaseline="middle",i.fillText(t,m+h/2,g+p/2)}function ln(i,t,e,n,s){i.beginPath(),i.moveTo(t,e),i.lineTo(t-s*Math.cos(n-Math.PI/6),e-s*Math.sin(n-Math.PI/6)),i.lineTo(t-s*Math.cos(n+Math.PI/6),e-s*Math.sin(n+Math.PI/6)),i.closePath(),i.fill()}function wi(i,t){const{ctx:e,imageCache:n}=t,s=i.data.src,o=i.data.assetId,a=s?n.getBySrc(s):o?n.get(o):null;if(a){if(t.lod===1&&t.scale<.15){e.fillStyle=t.theme==="dark"?"#3a3d42":"#d8d8d4",e.fillRect(i.x,i.y,i.width,i.height);return}e.drawImage(a,i.x,i.y,i.width,i.height)}else if(e.fillStyle=t.theme==="dark"?"#2a2d31":"#ececea",e.fillRect(i.x,i.y,i.width,i.height),e.strokeStyle=t.theme==="dark"?"#4a4d52":"#c9c9c5",e.lineWidth=1/t.scale,e.strokeRect(i.x,i.y,i.width,i.height),t.lod===2){const c=(s?n.isMissingSrc(s):o?n.isMissing(o):!1)?"Missing image":"Loading…";e.font="12px -apple-system, sans-serif",e.fillStyle=t.theme==="dark"?"#9ca3af":"#6b7280",e.textAlign="center",e.textBaseline="middle",e.fillText(c,i.x+i.width/2,i.y+i.height/2)}}class xi{constructor(t,e){u(this,"element");u(this,"canvas");u(this,"ctx");u(this,"imageCache");u(this,"doc",null);u(this,"region",[0,0,100,100]);u(this,"opts");u(this,"openLink");u(this,"ro");this.opts=e,this.element=t,t.classList.add("board-embed"),t.textContent="";const n=document.createElement("div");n.className="board-embed-frame",n.style.height=e.height+"px",this.canvas=document.createElement("canvas"),this.ctx=this.canvas.getContext("2d"),n.appendChild(this.canvas),t.appendChild(n);const s=document.createElement("a");s.className="board-embed-open";const o=e.region?`?region=${encodeURIComponent(e.region.join(","))}`:"";if(s.href=`#/root/${encodeURIComponent(e.rootId)}/boards/${encodeURIComponent(e.src)}${o}`,s.textContent="Open board →",this.openLink=s,n.appendChild(s),e.title){const a=document.createElement("figcaption");a.textContent=e.title,t.appendChild(a)}this.imageCache=new es(it,()=>this.render(),a=>k.assetUrl(this.opts.rootId,a)),this.ro=new ResizeObserver(()=>this.render()),this.ro.observe(n),this.load()}async load(){var t;try{const e=(t=this.opts.srcCandidates)!=null&&t.length?this.opts.srcCandidates:[this.opts.src];let n=null,s=this.opts.src;for(const a of e){const r=await k.getBoard(this.opts.rootId,a);if(n=r?we(r):null,n){s=a;break}}if(!n)return this.renderError(`Board "${this.opts.src}" not found`);this.opts.src=s;const o=this.opts.region?`?region=${encodeURIComponent(this.opts.region.join(","))}`:"";this.openLink.href=`#/root/${encodeURIComponent(this.opts.rootId)}/boards/${encodeURIComponent(s)}${o}`,this.doc=n,this.region=this.opts.region??Ci(n.elements),this.render()}catch{this.renderError("Failed to load board")}}renderError(t){var n;(n=this.element.querySelector(".board-embed-frame"))==null||n.classList.add("error");const e=this.element.querySelector(".board-embed-frame");if(e){e.innerHTML="";const s=document.createElement("span");s.className="board-embed-msg",s.textContent=t,e.appendChild(s)}}render(){if(!this.doc)return;const t=this.canvas.parentElement,e=Math.max(1,t.clientWidth),n=Math.max(1,t.clientHeight),s=Math.max(1,window.devicePixelRatio||1);this.canvas.width=Math.round(e*s),this.canvas.height=Math.round(n*s),this.canvas.style.width=e+"px",this.canvas.style.height=n+"px";const o=this.ctx;o.setTransform(s,0,0,s,0,0),o.clearRect(0,0,e,n),o.fillStyle=this.opts.theme==="dark"?"#111315":"#f3f2f1",o.fillRect(0,0,e,n);const[a,r,c,l]=this.region;if(c<=0||l<=0)return;const d=Math.min(e/c,n/l),h=(e-c*d)/2-a*d,p=(n-l*d)/2-r*d;o.save(),o.translate(h,p),o.scale(d,d);const m={ctx:o,scale:d,lod:2,theme:this.opts.theme,imageCache:this.imageCache},g=Math.max(c,l)*.1;for(const y of[...this.doc.elements].sort((b,x)=>b.zIndex-x.zIndex))y.hidden||y.x+y.width<a-g||y.x>a+c+g||y.y+y.height<r-g||y.y>r+l+g||xe(y,m);o.restore()}setTheme(t){this.opts.theme!==t&&(this.opts.theme=t,this.render())}destroy(){this.ro.disconnect(),this.imageCache.clear()}}function Ci(i){if(i.length===0)return[0,0,800,600];let t=1/0,e=1/0,n=-1/0,s=-1/0;for(const a of i)t=Math.min(t,a.x,a.x+a.width),e=Math.min(e,a.y,a.y+a.height),n=Math.max(n,a.x,a.x+a.width),s=Math.max(s,a.y,a.y+a.height);const o=40;return[t-o,e-o,n-t+o*2,s-e+o*2]}function ee(){return document.documentElement.getAttribute("data-theme")==="dark"?"dark":"light"}function dn(i,t,e){const{html:n,frontmatter:s}=ne(t,e),o=document.createElement("article");o.className="markdown-body",o.innerHTML=n,i.replaceChildren(o),o.querySelectorAll("pre.code-block").forEach(r=>{var h;const c=r.querySelector("code"),l=(h=c==null?void 0:c.textContent)==null?void 0:h.trimEnd();if(!l)return;const d=document.createElement("button");d.className="code-copy-btn",d.type="button",d.textContent="Copy",d.addEventListener("click",async()=>{try{await navigator.clipboard.writeText(l),d.textContent="Copied"}catch{d.textContent="Failed"}window.setTimeout(()=>{d.textContent="Copy"},1200)}),r.appendChild(d)});const a=[];return o.querySelectorAll("figure.board-embed").forEach(r=>{const c=r.dataset.src??"";if(!c)return;const l=re(c,e.docPath),d=l[0]??"",h=r.dataset.region??"",p=h?h.split(",").map(Number):[],m=p.length===4&&p.every(b=>Number.isFinite(b))?[p[0],p[1],p[2],p[3]]:null,g=parseInt(r.dataset.height??"360",10)||360,y=r.dataset.title||null;try{a.push(new xi(r,{rootId:e.rootId,src:d,srcCandidates:l,region:m,height:g,title:y,theme:ee()}))}catch(b){console.error("Board embed failed to mount",c,b),r.textContent=`Could not load board "${c}".`}}),{frontmatter:s,destroy:()=>{for(const r of a)r.destroy()},setTheme:r=>{for(const c of a)c.setTheme(r)}}}const ki=.05,Ei=40,ss=1;function L(i,t,e){return{x:(i-e.offsetX)/e.scale,y:(t-e.offsetY)/e.scale}}function Rt(i,t,e){return{x:i*e.scale+e.offsetX,y:t*e.scale+e.offsetY}}function is(i){return Math.min(Ei,Math.max(ki,i))}function oe(i,t,e,n){const s=is(n),o={x:(t-i.offsetX)/i.scale,y:(e-i.offsetY)/i.scale};i.scale=s,i.offsetX=t-o.x*i.scale,i.offsetY=e-o.y*i.scale}function Si(i,t,e){const n=L(0,0,i),s=L(t,e,i);return{left:n.x,top:n.y,right:s.x,bottom:s.y}}class Ti{constructor(){u(this,"schemaUrl");u(this,"boardId","default-board");u(this,"title","Untitled Board");u(this,"createdAt",Date.now());u(this,"viewport",{offsetX:0,offsetY:0,scale:ss});u(this,"theme","light");u(this,"elements",[]);u(this,"elementsById",new Map);u(this,"selectedIds",new Set);u(this,"hoveredId",null);u(this,"sortedCache",null);u(this,"changeListeners",[]);u(this,"renderListeners",[])}onChange(t){this.changeListeners.push(t)}onRenderNeeded(t){this.renderListeners.push(t)}emitChange(){this.sortedCache=null;for(const t of this.changeListeners)t();this.requestRender()}requestRender(){for(const t of this.renderListeners)t()}addElement(t){this.elements.push(t),this.elementsById.set(t.id,t),this.sortedCache=null}removeElement(t){const e=this.elementsById.get(t);if(!e)return;this.elementsById.delete(t);const n=this.elements.indexOf(e);return n>=0&&this.elements.splice(n,1),this.selectedIds.delete(t),this.sortedCache=null,e}getSorted(){return this.sortedCache||(this.sortedCache=[...this.elements].sort((t,e)=>t.zIndex-e.zIndex)),this.sortedCache}invalidateSort(){this.sortedCache=null}maxZIndex(){let t=0;for(const e of this.elements)e.zIndex>t&&(t=e.zIndex);return t}minZIndex(){let t=0;for(const e of this.elements)e.zIndex<t&&(t=e.zIndex);return t}getSelected(){const t=[];for(const e of this.selectedIds){const n=this.elementsById.get(e);n&&t.push(n)}return t}clearSelection(){this.selectedIds.clear()}getVisibleElements(t){const e=[];for(const n of this.getSorted())n.hidden||Bi(n,t)&&e.push(n);return e}}function Bi(i,t){const e=Math.min(i.x,i.x+i.width),n=Math.max(i.x,i.x+i.width),s=Math.min(i.y,i.y+i.height),o=Math.max(i.y,i.y+i.height);return!(n<t.left||e>t.right||o<t.top||s>t.bottom)}let Ae=0;function ae(){return Ae=(Ae+1)%65535,Date.now().toString(36)+"-"+Ae.toString(36)+"-"+Math.random().toString(36).slice(2,8)}function H(i,t={}){const e=Date.now();return{id:ae(),type:i,x:0,y:0,width:100,height:100,rotation:0,zIndex:0,locked:!1,hidden:!1,createdAt:e,updatedAt:e,style:{},data:{},...t}}const hn=200;class Mi{constructor(){u(this,"undoStack",[]);u(this,"redoStack",[])}execute(t,e,n){const s={id:ae(),type:t,timestamp:Date.now(),do:e,undo:n};s.do(),this.undoStack.push(s),this.undoStack.length>hn&&this.undoStack.shift(),this.redoStack.length=0}push(t,e,n){const s={id:ae(),type:t,timestamp:Date.now(),do:e,undo:n};this.undoStack.push(s),this.undoStack.length>hn&&this.undoStack.shift(),this.redoStack.length=0}undo(){const t=this.undoStack.pop();return t?(t.undo(),this.redoStack.push(t),!0):!1}redo(){const t=this.redoStack.pop();return t?(t.do(),this.undoStack.push(t),!0):!1}clear(){this.undoStack.length=0,this.redoStack.length=0}}class Ii{constructor(t,e){u(this,"state");u(this,"commands");this.state=t,this.commands=e}deleteSelection(){const t=this.state.getSelected().filter(s=>!s.locked);if(t.length===0)return;const e=this.state,n=t.map(s=>s);this.commands.execute("delete",()=>{for(const s of n)e.removeElement(s.id);e.emitChange()},()=>{for(const s of n)e.elementsById.has(s.id)||e.addElement(s);e.emitChange()})}duplicateSelection(t=24){const e=this.state.getSelected();if(e.length===0)return[];const n=e.map(s=>this.cloneElement(s,t));this.insertElements(n,"duplicate"),this.state.clearSelection();for(const s of n)this.state.selectedIds.add(s.id);return this.state.requestRender(),n}cloneElement(t,e){const n=Date.now();return{...t,id:ae(),x:t.x+e,y:t.y+e,zIndex:this.state.maxZIndex()+1,createdAt:n,updatedAt:n,style:{...t.style},data:{...t.data}}}insertElements(t,e){const n=this.state;this.commands.execute(e,()=>{for(const s of t)n.elementsById.has(s.id)||n.addElement(s);n.emitChange()},()=>{for(const s of t)n.removeElement(s.id);n.emitChange()})}nudgeSelection(t,e){const n=this.state.getSelected().filter(c=>!c.locked);if(n.length===0)return;const s=this.state,o=n.map(c=>({id:c.id,x:c.x,y:c.y,updatedAt:c.updatedAt})),a=n.map(c=>({id:c.id,x:c.x+t,y:c.y+e,updatedAt:Date.now()})),r=c=>{for(const l of c){const d=s.elementsById.get(l.id);d&&(d.x=l.x,d.y=l.y,d.updatedAt=l.updatedAt)}s.emitChange()};this.commands.execute("nudge",()=>r(a),()=>r(o))}applyZChange(t){const e=this.state.getSelected();if(e.length===0)return;const n=this.state,s=e.map(r=>({id:r.id,z:r.zIndex}));for(const r of e)t(r);n.invalidateSort();const o=e.map(r=>({id:r.id,z:r.zIndex})),a=r=>{for(const c of r){const l=n.elementsById.get(c.id);l&&(l.zIndex=c.z)}n.invalidateSort(),n.emitChange()};this.commands.push("layer",()=>a(o),()=>a(s)),n.emitChange()}bringForward(){this.applyZChange(t=>t.zIndex+=1)}sendBackward(){this.applyZChange(t=>t.zIndex-=1)}bringToFront(){let t=this.state.maxZIndex();this.applyZChange(e=>e.zIndex=++t)}sendToBack(){let t=this.state.minZIndex();this.applyZChange(e=>e.zIndex=--t)}}const Ri=["image/png","image/jpeg","image/webp","image/gif"],Li=5*1024*1024;class $i{constructor(t,e,n,s,o){u(this,"state");u(this,"commands");u(this,"imageCache");u(this,"notify");u(this,"uploadImage");u(this,"uploadedImageByHash",new Map);this.state=t,this.commands=e,this.imageCache=n,this.notify=s,this.uploadImage=o}async insertBlob(t,e,n,s){if(!Ri.includes(t.type)){this.notify("Unsupported image type");return}t.size>Li&&this.notify("Large image added — consider optimizing it for git");let o=0,a=0,r=null;try{r=await createImageBitmap(t),o=r.width,a=r.height}catch{this.notify("Could not decode image");return}const c={originalWidth:o,originalHeight:a,alt:s};if(this.uploadImage)try{const b=await this.uploadOrReuseImage(t,s);c.src=b,r&&this.imageCache.setBySrc(b,r)}catch(b){this.notify("Failed to save image to disk"),console.error("Image upload failed",b);return}else try{const b=await it.createFromBlob(t,s);c.assetId=b.id,r&&this.imageCache.set(b.id,r)}catch(b){this.notify("Failed to store image (storage quota?)"),console.error("Asset store failed",b);return}const l=L(e,n,this.state.viewport),d=480/Math.min(1,this.state.viewport.scale);let h=o,p=a;const m=Math.max(h,p);if(m>d){const b=d/m;h*=b,p*=b}const g=H("image",{x:l.x-h/2,y:l.y-p/2,width:h,height:p,zIndex:this.state.maxZIndex()+1,data:c}),y=this.state;this.commands.execute("insert-image",()=>{y.elementsById.has(g.id)||y.addElement(g),y.emitChange()},()=>{y.removeElement(g.id),y.emitChange()}),y.clearSelection(),y.selectedIds.add(g.id),y.requestRender()}async insertFiles(t,e,n){let s=0;for(const o of Array.from(t))o.type.startsWith("image/")&&(await this.insertBlob(o,e+s,n+s,o.name),s+=24)}async uploadOrReuseImage(t,e){if(!this.uploadImage)throw new Error("Missing uploadImage");const n=await Pi(t),s=this.uploadedImageByHash.get(n);if(s)return s;const o=await this.uploadImage(t,e);return this.uploadedImageByHash.set(n,o),o}}async function Pi(i){const t=await crypto.subtle.digest("SHA-256",await i.arrayBuffer());return Array.from(new Uint8Array(t),e=>e.toString(16).padStart(2,"0")).join("")}const pn="application/x-viteboard-elements";class Di{constructor(t,e,n,s){u(this,"state");u(this,"actions");u(this,"imageInsert");u(this,"internalClipboard",[]);u(this,"internalClipboardToken","");u(this,"lastPointer",{x:window.innerWidth/2,y:window.innerHeight/2});this.state=t,this.actions=e,this.imageInsert=n,window.addEventListener("pointermove",o=>{this.lastPointer={x:o.clientX,y:o.clientY}},{signal:s}),window.addEventListener("paste",o=>{this.isEditingText(o.target)||this.handlePaste(o)},{signal:s}),window.addEventListener("copy",o=>{this.isEditingText(o.target)||this.copySelection(o.clipboardData)&&o.preventDefault()},{signal:s}),window.addEventListener("cut",o=>{this.isEditingText(o.target)||this.copySelection(o.clipboardData)&&(this.actions.deleteSelection(),o.preventDefault())},{signal:s})}isEditingText(t){const e=t;return!!e&&(e.tagName==="TEXTAREA"||e.tagName==="INPUT"||e.isContentEditable)}copySelection(t){const e=this.state.getSelected();return e.length===0?!1:(this.internalClipboard=e.map(n=>({...n,style:{...n.style},data:{...n.data}})),this.internalClipboardToken=Date.now().toString(36)+"-"+Math.random().toString(36).slice(2,8),t&&this.writeClipboardPayload(t,e),!0)}async handlePaste(t){const e=t.clipboardData,n=e==null?void 0:e.items,s=e==null?void 0:e.getData("text/plain").trim();if(e&&this.isInternalClipboardPaste(e)){t.preventDefault(),this.pasteInternal();return}if(n){for(const o of n)if(o.type.startsWith("image/")){const a=o.getAsFile();if(a&&!s){t.preventDefault(),await this.imageInsert.insertBlob(a,this.lastPointer.x,this.lastPointer.y,"Pasted screenshot");return}}}if(!e&&this.internalClipboard.length>0){t.preventDefault(),this.pasteInternal();return}s&&(t.preventDefault(),this.pasteText(s))}writeClipboardPayload(t,e){try{t.clearData(),t.setData(pn,this.internalClipboardToken),t.setData("text/plain",this.selectionText(e))}catch{}}isInternalClipboardPaste(t){const e=t.getData(pn).trim();return!!e&&e===this.internalClipboardToken&&this.internalClipboard.length>0}selectionText(t){return t.map(n=>typeof n.data.text=="string"?n.data.text.trim():"").filter(Boolean).join(`
|
|
8
|
+
`)){const s=n.replace(/#.*$/,"").trim();if(!s)continue;const o=s.indexOf(":");o!==-1&&(t[s.slice(0,o).trim()]=s.slice(o+1).trim())}let e=null;if(t.region){const n=t.region.split(",").map(s=>parseFloat(s.trim()));n.length===4&&n.every(s=>Number.isFinite(s))&&(e=[n[0],n[1],n[2],n[3]])}return{src:t.src??"",region:e,height:t.height?Math.max(120,parseInt(t.height,10)||360):360,title:t.title??null}}function Vs(i){const t=i.region?i.region.join(","):"";return`<figure class="board-embed" data-src="${Mt(i.src)}" data-region="${t}" data-height="${i.height}" data-title="${Mt(i.title??"")}"></figure>`}function Lt(i,t){let e=i;const n=[];e=e.replace(/\\([\\`*_{}\[\]()#+\-.!|])/g,(a,r)=>(n.push(r),`${n.length-1}`));const s=[];e=e.replace(/`([^`]+)`/g,(a,r)=>(s.push(`<code>${Ut(de(r,n))}</code>`),`\0${s.length-1}\0`));const o=[];return e=e.replace(/!\[([^\]]*)\]\(([^)\s]+)\)/g,(a,r,c)=>{const l=de(c,n),d=Ve(l,t),h=Gs(l,t),p=de(r,n),m=d===l?"":` data-md-src="${Mt(l)}"`;return o.push(`<img src="${Mt(h)}" alt="${Mt(p)}" loading="lazy"${m} />`),`${o.length-1}`}),e=e.replace(/\[([^\]]+)\]\(([^)\s]+)\)/g,(a,r,c)=>{const l=de(c,n),d=Zs(l,t),p=/^(https?:|mailto:|tel:)/.test(l)?' target="_blank" rel="noopener noreferrer"':"",m=d===l?"":` data-md-href="${Mt(l)}"`;return o.push(`<a href="${Mt(d)}"${p}${m}>${an(r,n,s)}</a>`),`${o.length-1}`}),e=an(e,n,s),e=e.replace(/\u0002(\d+)\u0002/g,(a,r)=>o[Number(r)]??""),e}function an(i,t,e){let n=Ut(i);return n=n.replace(/\*\*([\s\S]+?)\*\*/g,"<strong>$1</strong>"),n=n.replace(/__([\s\S]+?)__/g,"<strong>$1</strong>"),n=n.replace(/(^|[^*])\*([^*\s][^*]*)\*/g,"$1<em>$2</em>"),n=n.replace(/(^|[^_])_([^_\s][^_]*)_/g,"$1<em>$2</em>"),n=n.replace(/\u0000(\d+)\u0000/g,(s,o)=>e[Number(o)]??""),n=n.replace(/\u0001(\d+)\u0001/g,(s,o)=>Ut(t[Number(o)]??"")),n}function de(i,t){return i.replace(/\u0001(\d+)\u0001/g,(e,n)=>t[Number(n)]??"")}function Gs(i,t){if(/^(https?:|data:)/.test(i)||!t.rootId||!t.docPath)return i;const e=Ve(i,t);return e?k.assetUrl(t.rootId,e):i}function Zs(i,t){if(/^(https?:|mailto:|tel:|#|data:)/.test(i)||!t.rootId||!t.docPath)return i;const e=Ve(i,t);return e?e.endsWith(".md")?`#/root/${encodeURIComponent(t.rootId)}/docs/${encodeURIComponent(e)}`:k.assetUrl(t.rootId,e):i}function Ve(i,t){return t.docPath?Ss(t.docPath,i):i}function Ut(i){return i.replace(/&/g,"&").replace(/</g,"<").replace(/>/g,">")}function Mt(i){return Ut(i).replace(/"/g,""")}function Js(i){return i.toLowerCase().replace(/[^\w\s-]/g,"").trim().replace(/\s+/g,"-")}class es{constructor(t,e,n){u(this,"cache",new Map);u(this,"loading",new Set);u(this,"missing",new Set);u(this,"assetStore");u(this,"onLoaded");u(this,"resolveSrcUrl");this.assetStore=t,this.onLoaded=e,this.resolveSrcUrl=n}get(t){const e=this.cache.get(t);return e||(!this.loading.has(t)&&!this.missing.has(t)&&this.load(t),null)}isMissing(t){return this.missing.has(t)}srcToUrl(t){return this.resolveSrcUrl?this.resolveSrcUrl(t):/^(https?:)?\/\//.test(t)||t.startsWith("/")||t.startsWith("data:")?t:`/__api/asset?path=${encodeURIComponent(t)}`}keyForSrc(t){return this.srcToUrl(t)}getBySrc(t){const e=this.srcToUrl(t),n=this.cache.get(e);return n||(!this.loading.has(e)&&!this.missing.has(e)&&this.loadUrl(e),null)}isMissingSrc(t){return this.missing.has(this.srcToUrl(t))}async loadUrl(t){this.loading.add(t);try{const e=await fetch(t);if(!e.ok){this.missing.add(t);return}const n=await e.blob(),s=await createImageBitmap(n);this.cache.set(t,s),this.onLoaded()}catch{this.missing.add(t)}finally{this.loading.delete(t)}}set(t,e){this.cache.set(t,e),this.missing.delete(t)}setBySrc(t,e){this.set(this.srcToUrl(t),e)}async load(t){this.loading.add(t);try{const e=await this.assetStore.get(t);if(!e){this.missing.add(t);return}const n=await createImageBitmap(e.blob);this.cache.set(t,n),this.onLoaded()}catch{this.missing.add(t)}finally{this.loading.delete(t)}}evict(t){const e=this.cache.get(t);e&&e.close(),this.cache.delete(t),this.missing.delete(t)}clear(){for(const t of this.cache.values())t.close();this.cache.clear(),this.missing.clear()}get size(){return this.cache.size}}const Qs="viteboard",ti=1;class ei{constructor(){u(this,"dbPromise",null)}open(){return this.dbPromise?this.dbPromise:(this.dbPromise=new Promise((t,e)=>{const n=indexedDB.open(Qs,ti);n.onupgradeneeded=()=>{const s=n.result;s.objectStoreNames.contains("boards")||s.createObjectStore("boards",{keyPath:"id"}),s.objectStoreNames.contains("assets")||s.createObjectStore("assets",{keyPath:"id"})},n.onsuccess=()=>t(n.result),n.onerror=()=>e(n.error??new Error("IndexedDB open failed")),n.onblocked=()=>e(new Error("IndexedDB blocked"))}),this.dbPromise)}async put(t,e){const n=await this.open();return new Promise((s,o)=>{const a=n.transaction(t,"readwrite");a.objectStore(t).put(e),a.oncomplete=()=>s(),a.onerror=()=>o(a.error??new Error("IndexedDB write failed"))})}async get(t,e){const n=await this.open();return new Promise((s,o)=>{const r=n.transaction(t,"readonly").objectStore(t).get(e);r.onsuccess=()=>s(r.result),r.onerror=()=>o(r.error??new Error("IndexedDB read failed"))})}async delete(t,e){const n=await this.open();return new Promise((s,o)=>{const a=n.transaction(t,"readwrite");a.objectStore(t).delete(e),a.oncomplete=()=>s(),a.onerror=()=>o(a.error??new Error("IndexedDB delete failed"))})}async getAllKeys(t){const e=await this.open();return new Promise((n,s)=>{const a=e.transaction(t,"readonly").objectStore(t).getAllKeys();a.onsuccess=()=>n(a.result),a.onerror=()=>s(a.error??new Error("IndexedDB keys failed"))})}async getAll(t){const e=await this.open();return new Promise((n,s)=>{const a=e.transaction(t,"readonly").objectStore(t).getAll();a.onsuccess=()=>n(a.result),a.onerror=()=>s(a.error??new Error("IndexedDB read failed"))})}async clearStore(t){const e=await this.open();return new Promise((n,s)=>{const o=e.transaction(t,"readwrite");o.objectStore(t).clear(),o.oncomplete=()=>n(),o.onerror=()=>s(o.error??new Error("IndexedDB clear failed"))})}}const K=new ei;class ni{async get(t){try{return await K.get("assets",t)}catch{return}}async createFromBlob(t,e){const n=await si(t),s=await this.get(n);if(s)return s;const o=await createImageBitmap(t),a=Date.now(),r={id:n,type:"image",mimeType:t.type||"image/png",blob:t,width:o.width,height:o.height,sizeBytes:t.size,createdAt:a,updatedAt:a,name:e};return o.close(),await K.put("assets",r),r}async put(t){await K.put("assets",t)}async delete(t){await K.delete("assets",t)}async getAllKeys(){try{return await K.getAllKeys("assets")}catch{return[]}}async getAll(){try{return await K.getAll("assets")}catch{return[]}}async totalSizeBytes(){return(await this.getAll()).reduce((e,n)=>e+n.sizeBytes,0)}async clearUnused(t){const e=await this.getAllKeys();let n=0;for(const s of e)t.has(s)||(await K.delete("assets",s),n++);return n}async clearAll(){await K.clearStore("assets")}}const it=new ni;async function si(i){const t=await crypto.subtle.digest("SHA-256",await i.arrayBuffer());return Array.from(new Uint8Array(t),e=>e.toString(16).padStart(2,"0")).join("")}const Ot=new Map,ii=2e3;function X(i){for(const t of Ot.keys())t.startsWith(i+"|")&&Ot.delete(t)}function Te(i){if(i.data.shapeKind==="chevron"){if(typeof i.style.fontSize=="number"&&Number.isFinite(i.style.fontSize))return i.style.fontSize;const t=Math.abs(i.height)*.34,e=Math.abs(i.width)*.18;return Math.round(Math.max(13,Math.min(48,t,e)))}return i.style.fontSize??14}function oi(i,t,e,n){const s=Ot.get(t);if(s)return s;const o=[];for(const a of e.split(`
|
|
9
|
+
`)){if(a===""){o.push("");continue}const r=a.split(" ");let c="";for(const l of r){const d=c===""?l:c+" "+l;i.measureText(d).width>n&&c!==""?(o.push(c),c=l):c=d}o.push(c)}return Ot.size>ii&&Ot.clear(),Ot.set(t,o),o}function _t(i,t,e,n,s,o){const a=Math.min(o,n/2,s/2);i.beginPath(),i.moveTo(t+a,e),i.arcTo(t+n,e,t+n,e+s,a),i.arcTo(t+n,e+s,t,e+s,a),i.arcTo(t,e+s,t,e,a),i.arcTo(t,e,t+n,e,a),i.closePath()}function xe(i,t){const{ctx:e,lod:n}=t;if(e.save(),e.globalAlpha=i.style.opacity??1,n===0){ai(i,t),e.restore();return}switch(i.type){case"sticky":ri(i,t);break;case"task":ci(i,t);break;case"rectangle":case"frame":rn(i,t);break;case"ellipse":fi(i,t);break;case"text":gi(i,t);break;case"line":case"arrow":case"connector":vi(i,t);break;case"image":case"screenshot":wi(i,t);break;default:rn(i,t)}e.restore()}function ai(i,t){const{ctx:e}=t;if(i.type==="line"||i.type==="arrow"||i.type==="connector"){e.strokeStyle=i.style.stroke??(t.theme==="dark"?"#888":"#999"),e.lineWidth=Math.max(1/t.scale,i.style.strokeWidth??2),e.beginPath(),e.moveTo(i.x,i.y),e.lineTo(i.x+i.width,i.y+i.height),e.stroke();return}e.fillStyle=i.style.fill??(t.theme==="dark"?"#3a3d42":"#d8d8d4"),e.fillRect(i.x,i.y,i.width,i.height)}function Be(i,t){i.style.shadow&&t.lod===2&&(t.ctx.shadowColor=t.theme==="dark"?"rgba(0,0,0,0.5)":"rgba(0,0,0,0.14)",t.ctx.shadowBlur=8*t.scale,t.ctx.shadowOffsetY=2*t.scale)}function Me(i){i.ctx.shadowColor="transparent",i.ctx.shadowBlur=0,i.ctx.shadowOffsetY=0}function ri(i,t){const{ctx:e,lod:n}=t,s=i.style.fill??"#fef08a";if(Be(i,t),_t(e,i.x,i.y,i.width,i.height,i.style.borderRadius??12),e.fillStyle=s,e.fill(),Me(t),n===2){const o=i.data.text??"";o&&Ge(i,t,o,14)}}function ci(i,t){const{ctx:e,lod:n}=t,s=i.data.checked===!0,o=t.theme==="dark",a=i.style.borderRadius??14;if(Be(i,t),_t(e,i.x,i.y,i.width,i.height,a),e.fillStyle=i.style.fill??(o?"#17191b":"#ffffff"),e.fill(),Me(t),e.strokeStyle=i.style.stroke??(o?"rgba(255,255,255,0.12)":"rgba(0,0,0,0.09)"),e.lineWidth=i.style.strokeWidth??1,e.stroke(),n<2)return;const r=Math.min(22,Math.max(16,i.height*.38)),c=i.x+16,l=i.y+i.height/2-r/2;_t(e,c,l,r,r,6),e.fillStyle=s?"#0078d4":o?"#111314":"#f3f2f1",e.fill(),e.strokeStyle=s?"#0078d4":o?"rgba(255,255,255,0.18)":"rgba(0,0,0,0.13)",e.lineWidth=1.4,e.stroke(),s&&(e.strokeStyle="#ffffff",e.lineWidth=2.1,e.lineCap="round",e.lineJoin="round",e.beginPath(),e.moveTo(c+r*.26,l+r*.52),e.lineTo(c+r*.43,l+r*.68),e.lineTo(c+r*.75,l+r*.32),e.stroke());const d=i.data.text??"";if(!d)return;const h=50,p=16,m=i.style.fontSize??15,g=i.style.fontFamily??'-apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif';if(e.font=`${i.style.fontWeight??"650"} ${m}px ${g}`,e.fillStyle=s?o?"#a7aaa8":"#777777":i.style.textColor??(o?"#f6f6f3":"#252829"),e.textAlign="left",e.textBaseline="middle",e.save(),e.beginPath(),e.rect(i.x+h,i.y,Math.max(10,i.width-h-p),i.height),e.clip(),e.fillText(d,i.x+h,i.y+i.height/2),s){const y=e.measureText(d),b=i.y+i.height/2+1;e.strokeStyle=o?"rgba(167,170,168,0.58)":"rgba(119,119,119,0.48)",e.lineWidth=1.3,e.beginPath(),e.moveTo(i.x+h,b),e.lineTo(i.x+h+Math.min(y.width,i.width-h-p),b),e.stroke()}e.restore()}function rn(i,t){const{ctx:e,lod:n}=t,s=i.data.shapeKind??"rectangle",o=i.style.borderRadius??0;if(Be(i,t),s==="diamond"?li(e,i):s==="triangle"?di(e,i):s==="chevron"?hi(e,i):s==="parallelogram"?pi(e,i):s==="hexagon"?ui(e,i):s==="cylinder"?mi(e,i):s==="pill"?_t(e,i.x,i.y,i.width,i.height,Math.min(Math.abs(i.height)/2,Math.abs(i.width)/2)):o>0?_t(e,i.x,i.y,i.width,i.height,o):(e.beginPath(),e.rect(i.x,i.y,i.width,i.height)),i.style.fill&&i.style.fill!=="transparent"&&(e.fillStyle=i.style.fill,e.fill()),Me(t),i.style.stroke&&(i.style.strokeWidth??0)>0&&(e.strokeStyle=i.style.stroke,e.lineWidth=i.style.strokeWidth??1,e.stroke(),s==="cylinder")){const a=Math.abs(i.width)/2,r=Math.min(Math.abs(i.height)*.18,18);e.beginPath(),e.ellipse(i.x+i.width/2,i.y+r,a,r,0,0,Math.PI*2),e.stroke()}if(n===2){const a=i.data.text??"";if(a){const r=s==="chevron"?Math.min(Math.abs(i.width)*.18,Math.abs(i.height)*.55)+8:10;Ge(i,t,a,r)}}}function li(i,t){const e=t.x,n=t.y,s=t.width,o=t.height;i.beginPath(),i.moveTo(e+s/2,n),i.lineTo(e+s,n+o/2),i.lineTo(e+s/2,n+o),i.lineTo(e,n+o/2),i.closePath()}function di(i,t){const e=t.x,n=t.y,s=t.width,o=t.height;i.beginPath(),i.moveTo(e+s/2,n),i.lineTo(e+s,n+o),i.lineTo(e,n+o),i.closePath()}function hi(i,t){const e=t.x,n=t.y,s=t.width,o=t.height,a=Math.min(Math.abs(s)*.22,Math.abs(o)*.62);i.beginPath(),i.moveTo(e,n),i.lineTo(e+s-a,n),i.lineTo(e+s,n+o/2),i.lineTo(e+s-a,n+o),i.lineTo(e,n+o),i.lineTo(e+a,n+o/2),i.closePath()}function pi(i,t){const e=Math.min(Math.abs(t.width)*.2,Math.abs(t.height)*.55);i.beginPath(),i.moveTo(t.x+e,t.y),i.lineTo(t.x+t.width,t.y),i.lineTo(t.x+t.width-e,t.y+t.height),i.lineTo(t.x,t.y+t.height),i.closePath()}function ui(i,t){const e=Math.min(Math.abs(t.width)*.22,Math.abs(t.height)*.5);i.beginPath(),i.moveTo(t.x+e,t.y),i.lineTo(t.x+t.width-e,t.y),i.lineTo(t.x+t.width,t.y+t.height/2),i.lineTo(t.x+t.width-e,t.y+t.height),i.lineTo(t.x+e,t.y+t.height),i.lineTo(t.x,t.y+t.height/2),i.closePath()}function mi(i,t){const e=Math.abs(t.width)/2,n=Math.min(Math.abs(t.height)*.18,18),s=t.x+t.width/2;i.beginPath(),i.ellipse(s,t.y+n,e,n,0,Math.PI,Math.PI*2),i.lineTo(t.x+t.width,t.y+t.height-n),i.ellipse(s,t.y+t.height-n,e,n,0,0,Math.PI),i.lineTo(t.x,t.y+n),i.closePath()}function fi(i,t){const{ctx:e,lod:n}=t;if(Be(i,t),e.beginPath(),e.ellipse(i.x+i.width/2,i.y+i.height/2,Math.abs(i.width/2),Math.abs(i.height/2),0,0,Math.PI*2),i.style.fill&&i.style.fill!=="transparent"&&(e.fillStyle=i.style.fill,e.fill()),Me(t),i.style.stroke&&(i.style.strokeWidth??0)>0&&(e.strokeStyle=i.style.stroke,e.lineWidth=i.style.strokeWidth??1,e.stroke()),n===2){const s=i.data.text??"";s&&Ge(i,t,s,10)}}function gi(i,t){if(t.lod<2){t.ctx.fillStyle=t.theme==="dark"?"#55585e":"#c5c5c0",t.ctx.fillRect(i.x,i.y,i.width,Math.min(i.height,6/t.scale));return}const e=i.data.text??"";yi(i,t,e)}function yi(i,t,e){const{ctx:n}=t,s=Te(i),o=i.style.fontFamily??'-apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif',a=i.style.textColor??(t.theme==="dark"?"#f2f2f2":"#1f2933"),r=Math.max(10,i.width),c=ns(e),l=s*1.35;let d=i.y+l/2;n.save(),n.beginPath(),n.rect(i.x,i.y,i.width,i.height),n.clip(),n.textBaseline="middle",n.textAlign="left";for(const h of c){if(d>i.y+i.height)break;let p=h.text,m=i.x,g=s,y=a;if(h.kind==="heading"?g=h.level===1?s*1.35:h.level===2?s*1.18:s*1.08:h.kind==="quote"?(m+=14,y=t.theme==="dark"?"#cbd5e1":"#475569",n.fillStyle=t.theme==="dark"?"#334155":"#cbd5e1",n.fillRect(i.x+2,d-l/2+2,3,Math.max(l-4,10))):h.kind==="list"&&(m+=16,n.fillStyle=y,n.beginPath(),n.arc(i.x+6,d,2.2,0,Math.PI*2),n.fill()),h.kind==="code"){const v=p.split(/\r?\n/),S=g*1.45,w=v.length*S+12;n.fillStyle=t.theme==="dark"?"#111827":"#eef2f7",n.fillRect(i.x,d-l/2,Math.max(80,i.width),w);for(const E of v){if(d>i.y+i.height)break;const B=cn(n,[{text:E,code:!0}],r-12,g,o);for(const T of B){let R=i.x+8;for(const A of T)qe(n,A,g,o),n.fillStyle=y,n.fillText(A.text,R,d+6),R+=n.measureText(A.text).width;d+=S}}d+=8;continue}const b=bi(p),x=cn(n,b,r-(m-i.x),g,o);for(const v of x){if(d>i.y+i.height)break;let S=m;for(const w of v){if(qe(n,w,g,o),w.code){const E=n.measureText(w.text).width;n.fillStyle=t.theme==="dark"?"#1f2937":"#eef2f7",n.fillRect(S-2,d-g*.48,E+4,g*.96),n.fillStyle=y}else n.fillStyle=y;n.fillText(w.text,S,d),S+=n.measureText(w.text).width}d+=l}}n.restore()}function ns(i){const t=i.split(/\r?\n/),e=[];for(let n=0;n<t.length;n++){const s=t[n],o=s.trimStart();if(!o){e.push({kind:"paragraph",text:""});continue}if(/^```/.test(o)){const l=[];for(n++;n<t.length&&!/^```/.test(t[n].trimStart());)l.push(t[n]),n++;e.push({kind:"code",text:l.join(`
|
|
10
|
+
`)});continue}const a=o.match(/^(#{1,3})\s+(.*)$/);if(a){e.push({kind:"heading",level:a[1].length,text:a[2]});continue}const r=o.match(/^>\s?(.*)$/);if(r){e.push({kind:"quote",text:r[1]});continue}const c=o.match(/^([-*+]|\d+\.)\s+(.*)$/);if(c){e.push({kind:"list",text:c[2]});continue}e.push({kind:"paragraph",text:s})}return e}function It(i){if(i.type!=="text")return;const t=String(i.data.text??""),e=ns(t),n=Te(i);let s=0;for(const o of e){if(o.kind==="code"){s+=Math.max(1,o.text.split(/\r?\n/).length)+1;continue}const a=Math.max(1,Math.floor(Math.max(120,i.width)/Math.max(6,n*.6))),r=o.text.replace(/[*_`#>-]/g,"");s+=Math.max(1,Math.ceil(Math.max(1,r.length)/a))}i.height=Math.max(n*1.45,s*n*1.35+8)}function bi(i){const t=[];let e=0;for(;e<i.length;){if(i.startsWith("**",e)){const s=i.indexOf("**",e+2);if(s!==-1){t.push({text:i.slice(e+2,s),bold:!0}),e=s+2;continue}}if(i.startsWith("*",e)){const s=i.indexOf("*",e+1);if(s!==-1){t.push({text:i.slice(e+1,s),italic:!0}),e=s+1;continue}}if(i.startsWith("`",e)){const s=i.indexOf("`",e+1);if(s!==-1){t.push({text:i.slice(e+1,s),code:!0}),e=s+1;continue}}let n=i.length;for(const s of["**","*","`"]){const o=i.indexOf(s,e+1);o!==-1&&o<n&&(n=o)}t.push({text:i.slice(e,n)}),e=n}return t.filter(n=>n.text.length>0)}function cn(i,t,e,n,s){const o=[[]];let a=0;for(const r of t){const c=r.text.split(/(\s+)/);for(const l of c){if(!l)continue;const d={...r,text:l};qe(i,d,n,s);const h=i.measureText(l).width;a>0&&a+h>e&&l.trim()&&(o.push([]),a=0),o[o.length-1].push(d),a+=h}}return o}function qe(i,t,e,n){const s=t.bold?"700":"400",o=t.italic?"italic ":"",a=t.code?'"SF Mono", ui-monospace, Menlo, monospace':n;i.font=`${o}${s} ${e}px ${a}`}function Ge(i,t,e,n,s="center",o="middle"){const{ctx:a}=t,r=i.data.shapeKind==="chevron",c=Te(i),l=i.style.fontFamily??'-apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif',d=r?"750":i.style.fontWeight??"400";a.font=`${d} ${c}px ${l}`,a.fillStyle=i.style.textColor??(t.theme==="dark"&&i.type==="text"?"#f2f2f2":"#1f2933");const h=Math.max(10,i.width-n*2),p=`${i.id}|${i.updatedAt}|${c}|${h.toFixed(0)}`,m=oi(a,p,e,h),g=c*1.35,y=m.length*g;let b;o==="middle"?b=i.y+i.height/2-y/2+g/2:b=i.y+n+g/2,a.textBaseline="middle",a.textAlign=s;const x=s==="center"?i.x+i.width/2:i.x+n;a.save(),a.beginPath(),a.rect(i.x,i.y,i.width,i.height),a.clip();for(let v=0;v<m.length;v++)a.fillText(m[v],x,b+v*g);a.restore()}function vi(i,t){const{ctx:e,lod:n}=t,s=i.x,o=i.y,a=i.x+i.width,r=i.y+i.height,c=i.style.stroke??(t.theme==="dark"?"#d1d5db":"#374151"),l=i.style.strokeWidth??2;if(e.strokeStyle=c,e.fillStyle=c,e.lineWidth=l,e.setLineDash(i.style.strokeDash??[]),e.beginPath(),e.moveTo(s,o),e.lineTo(a,r),e.stroke(),e.setLineDash([]),n>=1){const d=Math.atan2(r-o,a-s),h=Math.max(11,l*5.5);(i.style.arrowEnd??i.type==="arrow")&&ln(e,a,r,d,h),i.style.arrowStart&&ln(e,s,o,d+Math.PI,h);const p=typeof i.data.text=="string"?i.data.text.trim():"";if(p)if(i.data.labelPosition==="sides"){const[m,g]=p.split("|").map(y=>y.trim());m&&De(e,m,s,o,a,r,t,.24),g&&De(e,g,s,o,a,r,t,.76)}else De(e,p,s,o,a,r,t)}}function De(i,t,e,n,s,o,a,r=.5){i.font='600 13px -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif';const h=i.measureText(t).width+7*2,p=21,m=e+(s-e)*r-h/2,g=n+(o-n)*r-p/2;i.fillStyle=a.theme==="dark"?"#202328":"#ffffff",_t(i,m,g,h,p,4),i.fill(),i.strokeStyle=a.theme==="dark"?"#4a4d52":"#d8dade",i.lineWidth=1,i.stroke(),i.fillStyle=a.theme==="dark"?"#f2f2f2":"#1f2933",i.textAlign="center",i.textBaseline="middle",i.fillText(t,m+h/2,g+p/2)}function ln(i,t,e,n,s){i.beginPath(),i.moveTo(t,e),i.lineTo(t-s*Math.cos(n-Math.PI/6),e-s*Math.sin(n-Math.PI/6)),i.lineTo(t-s*Math.cos(n+Math.PI/6),e-s*Math.sin(n+Math.PI/6)),i.closePath(),i.fill()}function wi(i,t){const{ctx:e,imageCache:n}=t,s=i.data.src,o=i.data.assetId,a=s?n.getBySrc(s):o?n.get(o):null;if(a){if(t.lod===1&&t.scale<.15){e.fillStyle=t.theme==="dark"?"#3a3d42":"#d8d8d4",e.fillRect(i.x,i.y,i.width,i.height);return}e.drawImage(a,i.x,i.y,i.width,i.height)}else if(e.fillStyle=t.theme==="dark"?"#2a2d31":"#ececea",e.fillRect(i.x,i.y,i.width,i.height),e.strokeStyle=t.theme==="dark"?"#4a4d52":"#c9c9c5",e.lineWidth=1/t.scale,e.strokeRect(i.x,i.y,i.width,i.height),t.lod===2){const c=(s?n.isMissingSrc(s):o?n.isMissing(o):!1)?"Missing image":"Loading…";e.font="12px -apple-system, sans-serif",e.fillStyle=t.theme==="dark"?"#9ca3af":"#6b7280",e.textAlign="center",e.textBaseline="middle",e.fillText(c,i.x+i.width/2,i.y+i.height/2)}}class xi{constructor(t,e){u(this,"element");u(this,"canvas");u(this,"ctx");u(this,"imageCache");u(this,"doc",null);u(this,"region",[0,0,100,100]);u(this,"opts");u(this,"openLink");u(this,"ro");this.opts=e,this.element=t,t.classList.add("board-embed"),t.textContent="";const n=document.createElement("div");n.className="board-embed-frame",n.style.height=e.height+"px",this.canvas=document.createElement("canvas"),this.ctx=this.canvas.getContext("2d"),n.appendChild(this.canvas),t.appendChild(n);const s=document.createElement("a");s.className="board-embed-open";const o=e.region?`?region=${encodeURIComponent(e.region.join(","))}`:"";if(s.href=`#/root/${encodeURIComponent(e.rootId)}/boards/${encodeURIComponent(e.src)}${o}`,s.textContent="Open board →",this.openLink=s,n.appendChild(s),e.title){const a=document.createElement("figcaption");a.textContent=e.title,t.appendChild(a)}this.imageCache=new es(it,()=>this.render(),a=>k.assetUrl(this.opts.rootId,a)),this.ro=new ResizeObserver(()=>this.render()),this.ro.observe(n),this.load()}async load(){var t;try{const e=(t=this.opts.srcCandidates)!=null&&t.length?this.opts.srcCandidates:[this.opts.src];let n=null,s=this.opts.src;for(const a of e){const r=await k.getBoard(this.opts.rootId,a);if(n=r?we(r):null,n){s=a;break}}if(!n)return this.renderError(`Board "${this.opts.src}" not found`);this.opts.src=s;const o=this.opts.region?`?region=${encodeURIComponent(this.opts.region.join(","))}`:"";this.openLink.href=`#/root/${encodeURIComponent(this.opts.rootId)}/boards/${encodeURIComponent(s)}${o}`,this.doc=n,this.region=this.opts.region??Ci(n.elements),this.render()}catch{this.renderError("Failed to load board")}}renderError(t){var n;(n=this.element.querySelector(".board-embed-frame"))==null||n.classList.add("error");const e=this.element.querySelector(".board-embed-frame");if(e){e.innerHTML="";const s=document.createElement("span");s.className="board-embed-msg",s.textContent=t,e.appendChild(s)}}render(){if(!this.doc)return;const t=this.canvas.parentElement,e=Math.max(1,t.clientWidth),n=Math.max(1,t.clientHeight),s=Math.max(1,window.devicePixelRatio||1);this.canvas.width=Math.round(e*s),this.canvas.height=Math.round(n*s),this.canvas.style.width=e+"px",this.canvas.style.height=n+"px";const o=this.ctx;o.setTransform(s,0,0,s,0,0),o.clearRect(0,0,e,n),o.fillStyle=this.opts.theme==="dark"?"#111315":"#f3f2f1",o.fillRect(0,0,e,n);const[a,r,c,l]=this.region;if(c<=0||l<=0)return;const d=Math.min(e/c,n/l),h=(e-c*d)/2-a*d,p=(n-l*d)/2-r*d;o.save(),o.translate(h,p),o.scale(d,d);const m={ctx:o,scale:d,lod:2,theme:this.opts.theme,imageCache:this.imageCache},g=Math.max(c,l)*.1;for(const y of[...this.doc.elements].sort((b,x)=>b.zIndex-x.zIndex))y.hidden||y.x+y.width<a-g||y.x>a+c+g||y.y+y.height<r-g||y.y>r+l+g||xe(y,m);o.restore()}setTheme(t){this.opts.theme!==t&&(this.opts.theme=t,this.render())}destroy(){this.ro.disconnect(),this.imageCache.clear()}}function Ci(i){if(i.length===0)return[0,0,800,600];let t=1/0,e=1/0,n=-1/0,s=-1/0;for(const a of i)t=Math.min(t,a.x,a.x+a.width),e=Math.min(e,a.y,a.y+a.height),n=Math.max(n,a.x,a.x+a.width),s=Math.max(s,a.y,a.y+a.height);const o=40;return[t-o,e-o,n-t+o*2,s-e+o*2]}function ee(){return document.documentElement.getAttribute("data-theme")==="dark"?"dark":"light"}function dn(i,t,e){const{html:n,frontmatter:s}=ne(t,e),o=document.createElement("article");o.className="markdown-body",o.innerHTML=n,i.replaceChildren(o),o.querySelectorAll("pre.code-block").forEach(r=>{var h;const c=r.querySelector("code"),l=(h=c==null?void 0:c.textContent)==null?void 0:h.trimEnd();if(!l)return;const d=document.createElement("button");d.className="code-copy-btn",d.type="button",d.textContent="Copy",d.addEventListener("click",async()=>{try{await navigator.clipboard.writeText(l),d.textContent="Copied"}catch{d.textContent="Failed"}window.setTimeout(()=>{d.textContent="Copy"},1200)}),r.appendChild(d)});const a=[];return o.querySelectorAll("figure.board-embed").forEach(r=>{const c=r.dataset.src??"";if(!c)return;const l=re(c,e.docPath),d=l[0]??"",h=r.dataset.region??"",p=h?h.split(",").map(Number):[],m=p.length===4&&p.every(b=>Number.isFinite(b))?[p[0],p[1],p[2],p[3]]:null,g=parseInt(r.dataset.height??"360",10)||360,y=r.dataset.title||null;try{a.push(new xi(r,{rootId:e.rootId,src:d,srcCandidates:l,region:m,height:g,title:y,theme:ee()}))}catch(b){console.error("Board embed failed to mount",c,b),r.textContent=`Could not load board "${c}".`}}),{frontmatter:s,destroy:()=>{for(const r of a)r.destroy()},setTheme:r=>{for(const c of a)c.setTheme(r)}}}const ki=.05,Ei=40,ss=1;function L(i,t,e){return{x:(i-e.offsetX)/e.scale,y:(t-e.offsetY)/e.scale}}function Rt(i,t,e){return{x:i*e.scale+e.offsetX,y:t*e.scale+e.offsetY}}function is(i){return Math.min(Ei,Math.max(ki,i))}function oe(i,t,e,n){const s=is(n),o={x:(t-i.offsetX)/i.scale,y:(e-i.offsetY)/i.scale};i.scale=s,i.offsetX=t-o.x*i.scale,i.offsetY=e-o.y*i.scale}function Si(i,t,e){const n=L(0,0,i),s=L(t,e,i);return{left:n.x,top:n.y,right:s.x,bottom:s.y}}class Ti{constructor(){u(this,"schemaUrl");u(this,"boardId","default-board");u(this,"title","Untitled Board");u(this,"createdAt",Date.now());u(this,"viewport",{offsetX:0,offsetY:0,scale:ss});u(this,"theme","light");u(this,"elements",[]);u(this,"elementsById",new Map);u(this,"selectedIds",new Set);u(this,"hoveredId",null);u(this,"sortedCache",null);u(this,"changeListeners",[]);u(this,"renderListeners",[])}onChange(t){this.changeListeners.push(t)}onRenderNeeded(t){this.renderListeners.push(t)}emitChange(){this.sortedCache=null;for(const t of this.changeListeners)t();this.requestRender()}requestRender(){for(const t of this.renderListeners)t()}addElement(t){this.elements.push(t),this.elementsById.set(t.id,t),this.sortedCache=null}removeElement(t){const e=this.elementsById.get(t);if(!e)return;this.elementsById.delete(t);const n=this.elements.indexOf(e);return n>=0&&this.elements.splice(n,1),this.selectedIds.delete(t),this.sortedCache=null,e}getSorted(){return this.sortedCache||(this.sortedCache=[...this.elements].sort((t,e)=>t.zIndex-e.zIndex)),this.sortedCache}invalidateSort(){this.sortedCache=null}maxZIndex(){let t=0;for(const e of this.elements)e.zIndex>t&&(t=e.zIndex);return t}minZIndex(){let t=0;for(const e of this.elements)e.zIndex<t&&(t=e.zIndex);return t}getSelected(){const t=[];for(const e of this.selectedIds){const n=this.elementsById.get(e);n&&t.push(n)}return t}clearSelection(){this.selectedIds.clear()}getVisibleElements(t){const e=[];for(const n of this.getSorted())n.hidden||Bi(n,t)&&e.push(n);return e}}function Bi(i,t){const e=Math.min(i.x,i.x+i.width),n=Math.max(i.x,i.x+i.width),s=Math.min(i.y,i.y+i.height),o=Math.max(i.y,i.y+i.height);return!(n<t.left||e>t.right||o<t.top||s>t.bottom)}let Ae=0;function ae(){return Ae=(Ae+1)%65535,Date.now().toString(36)+"-"+Ae.toString(36)+"-"+Math.random().toString(36).slice(2,8)}function H(i,t={}){const e=Date.now();return{id:ae(),type:i,x:0,y:0,width:100,height:100,rotation:0,zIndex:0,locked:!1,hidden:!1,createdAt:e,updatedAt:e,style:{},data:{},...t}}const hn=200;class Mi{constructor(){u(this,"undoStack",[]);u(this,"redoStack",[])}execute(t,e,n){const s={id:ae(),type:t,timestamp:Date.now(),do:e,undo:n};s.do(),this.undoStack.push(s),this.undoStack.length>hn&&this.undoStack.shift(),this.redoStack.length=0}push(t,e,n){const s={id:ae(),type:t,timestamp:Date.now(),do:e,undo:n};this.undoStack.push(s),this.undoStack.length>hn&&this.undoStack.shift(),this.redoStack.length=0}undo(){const t=this.undoStack.pop();return t?(t.undo(),this.redoStack.push(t),!0):!1}redo(){const t=this.redoStack.pop();return t?(t.do(),this.undoStack.push(t),!0):!1}clear(){this.undoStack.length=0,this.redoStack.length=0}}class Ii{constructor(t,e){u(this,"state");u(this,"commands");this.state=t,this.commands=e}deleteSelection(){const t=this.state.getSelected().filter(s=>!s.locked);if(t.length===0)return;const e=this.state,n=t.map(s=>s);this.commands.execute("delete",()=>{for(const s of n)e.removeElement(s.id);e.emitChange()},()=>{for(const s of n)e.elementsById.has(s.id)||e.addElement(s);e.emitChange()})}duplicateSelection(t=24){const e=this.state.getSelected();if(e.length===0)return[];const n=e.map(s=>this.cloneElement(s,t));this.insertElements(n,"duplicate"),this.state.clearSelection();for(const s of n)this.state.selectedIds.add(s.id);return this.state.requestRender(),n}cloneElement(t,e){const n=Date.now();return{...t,id:ae(),x:t.x+e,y:t.y+e,zIndex:this.state.maxZIndex()+1,createdAt:n,updatedAt:n,style:{...t.style},data:{...t.data}}}insertElements(t,e){const n=this.state;this.commands.execute(e,()=>{for(const s of t)n.elementsById.has(s.id)||n.addElement(s);n.emitChange()},()=>{for(const s of t)n.removeElement(s.id);n.emitChange()})}nudgeSelection(t,e){const n=this.state.getSelected().filter(c=>!c.locked);if(n.length===0)return;const s=this.state,o=n.map(c=>({id:c.id,x:c.x,y:c.y,updatedAt:c.updatedAt})),a=n.map(c=>({id:c.id,x:c.x+t,y:c.y+e,updatedAt:Date.now()})),r=c=>{for(const l of c){const d=s.elementsById.get(l.id);d&&(d.x=l.x,d.y=l.y,d.updatedAt=l.updatedAt)}s.emitChange()};this.commands.execute("nudge",()=>r(a),()=>r(o))}applyZChange(t){const e=this.state.getSelected();if(e.length===0)return;const n=this.state,s=e.map(r=>({id:r.id,z:r.zIndex}));for(const r of e)t(r);n.invalidateSort();const o=e.map(r=>({id:r.id,z:r.zIndex})),a=r=>{for(const c of r){const l=n.elementsById.get(c.id);l&&(l.zIndex=c.z)}n.invalidateSort(),n.emitChange()};this.commands.push("layer",()=>a(o),()=>a(s)),n.emitChange()}bringForward(){this.applyZChange(t=>t.zIndex+=1)}sendBackward(){this.applyZChange(t=>t.zIndex-=1)}bringToFront(){let t=this.state.maxZIndex();this.applyZChange(e=>e.zIndex=++t)}sendToBack(){let t=this.state.minZIndex();this.applyZChange(e=>e.zIndex=--t)}}const Ri=["image/png","image/jpeg","image/webp","image/gif"],Li=5*1024*1024;class $i{constructor(t,e,n,s,o){u(this,"state");u(this,"commands");u(this,"imageCache");u(this,"notify");u(this,"uploadImage");u(this,"uploadedImageByHash",new Map);this.state=t,this.commands=e,this.imageCache=n,this.notify=s,this.uploadImage=o}async insertBlob(t,e,n,s){if(!Ri.includes(t.type)){this.notify("Unsupported image type");return}t.size>Li&&this.notify("Large image added — consider optimizing it for git");let o=0,a=0,r=null;try{r=await createImageBitmap(t),o=r.width,a=r.height}catch{this.notify("Could not decode image");return}const c={originalWidth:o,originalHeight:a,alt:s};if(this.uploadImage)try{const b=await this.uploadOrReuseImage(t,s);c.src=b,r&&this.imageCache.setBySrc(b,r)}catch(b){this.notify("Failed to save image to disk"),console.error("Image upload failed",b);return}else try{const b=await it.createFromBlob(t,s);c.assetId=b.id,r&&this.imageCache.set(b.id,r)}catch(b){this.notify("Failed to store image (storage quota?)"),console.error("Asset store failed",b);return}const l=L(e,n,this.state.viewport),d=480/Math.min(1,this.state.viewport.scale);let h=o,p=a;const m=Math.max(h,p);if(m>d){const b=d/m;h*=b,p*=b}const g=H("image",{x:l.x-h/2,y:l.y-p/2,width:h,height:p,zIndex:this.state.maxZIndex()+1,data:c}),y=this.state;this.commands.execute("insert-image",()=>{y.elementsById.has(g.id)||y.addElement(g),y.emitChange()},()=>{y.removeElement(g.id),y.emitChange()}),y.clearSelection(),y.selectedIds.add(g.id),y.requestRender()}async insertFiles(t,e,n){let s=0;for(const o of Array.from(t))o.type.startsWith("image/")&&(await this.insertBlob(o,e+s,n+s,o.name),s+=24)}async uploadOrReuseImage(t,e){if(!this.uploadImage)throw new Error("Missing uploadImage");const n=await Pi(t),s=this.uploadedImageByHash.get(n);if(s)return s;const o=await this.uploadImage(t,e);return this.uploadedImageByHash.set(n,o),o}}async function Pi(i){const t=await crypto.subtle.digest("SHA-256",await i.arrayBuffer());return Array.from(new Uint8Array(t),e=>e.toString(16).padStart(2,"0")).join("")}const pn="application/x-viteboard-elements";class Di{constructor(t,e,n,s){u(this,"state");u(this,"actions");u(this,"imageInsert");u(this,"internalClipboard",[]);u(this,"internalClipboardToken","");u(this,"lastPointer",{x:window.innerWidth/2,y:window.innerHeight/2});this.state=t,this.actions=e,this.imageInsert=n,window.addEventListener("pointermove",o=>{this.lastPointer={x:o.clientX,y:o.clientY}},{signal:s}),window.addEventListener("paste",o=>{this.isEditingText(o.target)||this.handlePaste(o)},{signal:s}),window.addEventListener("copy",o=>{this.isEditingText(o.target)||this.copySelection(o.clipboardData)&&o.preventDefault()},{signal:s}),window.addEventListener("cut",o=>{this.isEditingText(o.target)||this.copySelection(o.clipboardData)&&(this.actions.deleteSelection(),o.preventDefault())},{signal:s})}isEditingText(t){const e=t;return!!e&&(e.tagName==="TEXTAREA"||e.tagName==="INPUT"||e.isContentEditable)}copySelection(t){const e=this.state.getSelected();return e.length===0?!1:(this.internalClipboard=e.map(n=>({...n,style:{...n.style},data:{...n.data}})),this.internalClipboardToken=Date.now().toString(36)+"-"+Math.random().toString(36).slice(2,8),t&&this.writeClipboardPayload(t,e),!0)}async handlePaste(t){const e=t.clipboardData,n=e==null?void 0:e.items,s=e==null?void 0:e.getData("text/plain").trim();if(e&&this.isInternalClipboardPaste(e)){t.preventDefault(),this.pasteInternal();return}if(n){for(const o of n)if(o.type.startsWith("image/")){const a=o.getAsFile();if(a&&!s){t.preventDefault(),await this.imageInsert.insertBlob(a,this.lastPointer.x,this.lastPointer.y,"Pasted screenshot");return}}}if(!e&&this.internalClipboard.length>0){t.preventDefault(),this.pasteInternal();return}s&&(t.preventDefault(),this.pasteText(s))}writeClipboardPayload(t,e){try{t.clearData(),t.setData(pn,this.internalClipboardToken),t.setData("text/plain",this.selectionText(e))}catch{}}isInternalClipboardPaste(t){const e=t.getData(pn).trim();return!!e&&e===this.internalClipboardToken&&this.internalClipboard.length>0}selectionText(t){return t.map(n=>typeof n.data.text=="string"?n.data.text.trim():"").filter(Boolean).join(`
|
|
11
11
|
|
|
12
|
-
`)}pasteInternal(){const t=L(this.lastPointer.x,this.lastPointer.y,this.state.viewport);let e=1/0,n=1/0,s=-1/0,o=-1/0;for(const d of this.internalClipboard)e=Math.min(e,Math.min(d.x,d.x+d.width)),n=Math.min(n,Math.min(d.y,d.y+d.height)),s=Math.max(s,Math.max(d.x,d.x+d.width)),o=Math.max(o,Math.max(d.y,d.y+d.height));const a=(e+s)/2,r=(n+o)/2;let c=this.state.maxZIndex();const l=[];for(const d of this.internalClipboard){const h=Yn(d);if(!h)continue;const p=this.actions.cloneElement(h,0);p.x=h.x+(t.x-a),p.y=h.y+(t.y-r),p.zIndex=++c,l.push(p)}if(l.length!==0){this.actions.insertElements(l,"paste"),this.state.clearSelection();for(const d of l)this.state.selectedIds.add(d.id);this.state.requestRender()}}pasteText(t){const e=L(this.lastPointer.x,this.lastPointer.y,this.state.viewport),n=H("text",{x:e.x,y:e.y,width:Math.min(420,Math.max(160,t.length*8)),height:28,zIndex:this.state.maxZIndex()+1,style:{fontSize:16,textColor:this.state.theme==="dark"?"#f2f2f2":"#1f2933"},data:{text:t.slice(0,5e3)}});It(n),this.actions.insertElements([n],"paste-text"),this.state.clearSelection(),this.state.selectedIds.add(n.id),this.state.requestRender()}}function Ai(i,t){const{state:e,commands:n,actions:s,toolController:o}=i;window.addEventListener("keydown",a=>{const r=a.target;if(r&&(r.tagName==="TEXTAREA"||r.tagName==="INPUT"||r.isContentEditable))return;const c=a.metaKey||a.ctrlKey,l=a.shiftKey?10:1;if(!c)switch(a.key){case"ArrowLeft":a.preventDefault(),s.nudgeSelection(-l,0);return;case"ArrowRight":a.preventDefault(),s.nudgeSelection(l,0);return;case"ArrowUp":a.preventDefault(),s.nudgeSelection(0,-l);return;case"ArrowDown":a.preventDefault(),s.nudgeSelection(0,l);return}if(c){switch(a.key.toLowerCase()){case"d":a.preventDefault(),s.duplicateSelection();return;case"z":a.preventDefault(),a.shiftKey?n.redo():n.undo();return;case"]":a.preventDefault(),a.shiftKey?s.bringToFront():s.bringForward();return;case"[":a.preventDefault(),a.shiftKey?s.sendToBack():s.sendBackward();return;case"=":case"+":a.preventDefault(),oe(e.viewport,window.innerWidth/2,window.innerHeight/2,e.viewport.scale*1.2),e.requestRender();return;case"-":a.preventDefault(),oe(e.viewport,window.innerWidth/2,window.innerHeight/2,e.viewport.scale/1.2),e.requestRender();return;case"0":a.preventDefault(),i.resetView();return;case"a":a.preventDefault(),e.clearSelection();for(const d of e.elements)!d.locked&&!d.hidden&&e.selectedIds.add(d.id);e.requestRender();return}return}switch(a.key){case"Delete":case"Backspace":a.preventDefault(),s.deleteSelection();return;case"Escape":o.cancel(),o.setTool("select");return}switch(a.key.toLowerCase()){case"v":o.setTool("select");return;case"h":o.setTool("hand");return;case"s":o.setTool("sticky");return;case"r":o.setTool("rectangle");return;case"o":o.setTool("ellipse");return;case"t":o.setTool(a.shiftKey?"task":"text");return;case"a":o.setTool("arrow");return;case"i":o.setTool("image");return}},{signal:t})}function Ni(i){if(i.elements.length===0)return null;let t=1/0,e=1/0,n=-1/0,s=-1/0;for(const a of i.elements)a.hidden||(t=Math.min(t,Math.min(a.x,a.x+a.width)),e=Math.min(e,Math.min(a.y,a.y+a.height)),n=Math.max(n,Math.max(a.x,a.x+a.width)),s=Math.max(s,Math.max(a.y,a.y+a.height)));if(!Number.isFinite(t))return null;const o=48;return{x:t-o,y:e-o,w:n-t+o*2,h:s-e+o*2}}function os(i,t,e,n){let o=Math.round(e.w*n),a=Math.round(e.h*n);if(o>8192||a>8192){const h=8192/Math.max(o,a);n*=h,o=Math.round(e.w*n),a=Math.round(e.h*n)}const r=document.createElement("canvas");r.width=Math.max(1,o),r.height=Math.max(1,a);const c=r.getContext("2d"),l=i.theme==="dark"?"#111315":"#f3f2f1";c.fillStyle=l,c.fillRect(0,0,r.width,r.height),c.scale(n,n),c.translate(-e.x,-e.y);const d=i.getSorted();for(const h of d)h.hidden||Math.max(h.x,h.x+h.width)<e.x||Math.min(h.x,h.x+h.width)>e.x+e.w||Math.max(h.y,h.y+h.height)<e.y||Math.min(h.y,h.y+h.height)>e.y+e.h||xe(h,{ctx:c,scale:n,lod:2,theme:i.theme,imageCache:t});return r}function as(i){return new Promise((t,e)=>{i.toBlob(n=>{n?t(n):e(new Error("PNG encode failed"))},"image/png")})}async function zi(i,t,e,n){const s=i.viewport,o={x:-s.offsetX/s.scale,y:-s.offsetY/s.scale,w:e/s.scale,h:n/s.scale},a=os(i,t,o,s.scale);return as(a)}async function Hi(i,t){const e=Ni(i);if(!e)return null;const n=os(i,t,e,1);return as(n)}function un(i,t){const e=URL.createObjectURL(i),n=document.createElement("a");n.href=e,n.download=t,n.click(),URL.revokeObjectURL(e)}class Ge{constructor(t,e){u(this,"overlay");u(this,"rectEl");u(this,"abort",new AbortController);u(this,"start",null);u(this,"onComplete");u(this,"done",!1);this.onComplete=e,this.overlay=document.createElement("div"),this.overlay.className="embed-select-overlay";const n=document.createElement("div");n.className="embed-select-hint",n.textContent="Drag to select the area to embed · Esc to cancel",this.overlay.appendChild(n),this.rectEl=document.createElement("div"),this.rectEl.className="embed-select-rect",this.rectEl.style.display="none",this.overlay.appendChild(this.rectEl),t.appendChild(this.overlay);const s=this.abort.signal;this.overlay.addEventListener("pointerdown",o=>this.onDown(o),{signal:s}),this.overlay.addEventListener("pointermove",o=>this.onMove(o),{signal:s}),this.overlay.addEventListener("pointerup",o=>this.onUp(o),{signal:s}),window.addEventListener("keydown",o=>{o.key==="Escape"&&(o.preventDefault(),this.finish(null))},{signal:s})}static begin(t,e){new Ge(t,e)}onDown(t){t.preventDefault(),this.start={x:t.clientX,y:t.clientY},this.rectEl.style.display="block",this.draw(t.clientX,t.clientY),this.overlay.setPointerCapture(t.pointerId)}onMove(t){this.start&&this.draw(t.clientX,t.clientY)}onUp(t){if(!this.start)return;const e=this.rectFrom(t.clientX,t.clientY);if(e.w<8||e.h<8){this.finish(null);return}this.finish(e)}rectFrom(t,e){const n=this.start;return{x:Math.min(n.x,t),y:Math.min(n.y,e),w:Math.abs(t-n.x),h:Math.abs(e-n.y)}}draw(t,e){const n=this.rectFrom(t,e);this.rectEl.style.left=`${n.x}px`,this.rectEl.style.top=`${n.y}px`,this.rectEl.style.width=`${n.w}px`,this.rectEl.style.height=`${n.h}px`}finish(t){this.done||(this.done=!0,this.abort.abort(),this.overlay.remove(),this.onComplete(t))}}class Fi{constructor(t,e=3,n){u(this,"container");u(this,"layers",[]);u(this,"contexts",[]);u(this,"width",0);u(this,"height",0);u(this,"dpr",1);u(this,"resizeListeners",[]);this.container=document.createElement("div"),this.container.className="canvas-stack",t.appendChild(this.container);for(let s=0;s<e;s++){const o=document.createElement("canvas"),a=o.getContext("2d",{alpha:s!==0});this.container.appendChild(o),this.layers.push(o),this.contexts.push(a)}this.resize(),window.addEventListener("resize",()=>{this.resize();for(const s of this.resizeListeners)s()},{signal:n})}get interactionLayer(){return this.layers[this.layers.length-1]}onResize(t){this.resizeListeners.push(t)}resize(){this.dpr=Math.max(1,window.devicePixelRatio||1),this.width=window.innerWidth,this.height=window.innerHeight;for(const t of this.layers)t.width=Math.round(this.width*this.dpr),t.height=Math.round(this.height*this.dpr),t.style.width=this.width+"px",t.style.height=this.height+"px"}beginLayer(t){const e=this.contexts[t];return e.setTransform(this.dpr,0,0,this.dpr,0,0),e.clearRect(0,0,this.width,this.height),e}}class ji{constructor(t,e,n){u(this,"surface");u(this,"state");u(this,"imageCache");u(this,"overlay",{marquee:null,preview:null});u(this,"lastRenderMs",0);u(this,"visibleCount",0);u(this,"cullingEnabled",!0);u(this,"lodEnabled",!0);this.surface=t,this.state=e,this.imageCache=n}getLod(){if(!this.lodEnabled)return 2;const t=this.state.viewport.scale;return t<.1?0:t<.25?1:2}render(){const t=performance.now();this.renderGrid(),this.renderObjects(),this.renderOverlay(),this.lastRenderMs=performance.now()-t}renderGrid(){const{surface:t,state:e}=this,n=t.beginLayer(0),s=e.viewport,o=getComputedStyle(document.documentElement).getPropertyValue("--bg-canvas").trim(),a=getComputedStyle(document.documentElement).getPropertyValue("--grid-dot").trim();n.fillStyle=o||"#f3f2f1",n.fillRect(0,0,t.width,t.height);let c=32*s.scale;if(!Number.isFinite(c)||c<=0)return;for(;c<16;)c*=2;for(;c>64;)c/=2;if(c<4)return;const l=(s.offsetX%c+c)%c,d=(s.offsetY%c+c)%c,h=Math.min(1.5,Math.max(.75,s.scale*.9));n.fillStyle=a||"rgba(0,0,0,0.14)",n.beginPath();for(let p=l;p<t.width;p+=c)for(let m=d;m<t.height;m+=c)n.moveTo(p+h,m),n.arc(p,m,h,0,Math.PI*2);n.fill()}renderObjects(){const{surface:t,state:e}=this,n=t.beginLayer(1),s=e.viewport;n.translate(s.offsetX,s.offsetY),n.scale(s.scale,s.scale);const o=Si(s,t.width,t.height),a=this.cullingEnabled?e.getVisibleElements(o):e.getSorted().filter(c=>!c.hidden);this.visibleCount=a.length;const r={ctx:n,scale:s.scale,lod:this.getLod(),theme:e.theme,imageCache:this.imageCache};for(const c of a)xe(c,r)}renderOverlay(){const{surface:t,state:e}=this,n=t.beginLayer(2),s=e.viewport,o=getComputedStyle(document.documentElement).getPropertyValue("--selection").trim()||"#6e6e6e";if(e.hoveredId&&!e.selectedIds.has(e.hoveredId)){const r=e.elementsById.get(e.hoveredId);if(r){const c=this.elementScreenBBox(r);n.strokeStyle=o,n.globalAlpha=.45,n.lineWidth=1.5,n.strokeRect(c.x,c.y,c.w,c.h),n.globalAlpha=1}}const a=e.getSelected();if(a.length>0){n.strokeStyle=o,n.lineWidth=1.5;let r=1/0,c=1/0,l=-1/0,d=-1/0;for(const p of a){const m=this.elementScreenBBox(p);n.strokeRect(m.x,m.y,m.w,m.h),r=Math.min(r,m.x),c=Math.min(c,m.y),l=Math.max(l,m.x+m.w),d=Math.max(d,m.y+m.h)}a.length>1&&(n.setLineDash([4,4]),n.strokeRect(r-4,c-4,l-r+8,d-c+8),n.setLineDash([]));const h=a.length===1?this.elementScreenBBox(a[0]):{x:r,y:c,w:l-r,h:d-c};this.drawHandles(n,h,o)}if(this.overlay.marquee){const r=this.overlay.marquee;n.fillStyle=o+"22",n.strokeStyle=o,n.lineWidth=1,n.fillRect(r.x,r.y,r.w,r.h),n.strokeRect(r.x,r.y,r.w,r.h)}this.overlay.preview&&(n.save(),n.translate(s.offsetX,s.offsetY),n.scale(s.scale,s.scale),n.globalAlpha=.8,xe(this.overlay.preview,{ctx:n,scale:s.scale,lod:2,theme:e.theme,imageCache:this.imageCache}),n.restore())}elementScreenBBox(t){const e=this.state.viewport,n=Math.min(t.x,t.x+t.width),s=Math.min(t.y,t.y+t.height),o=Math.max(t.x,t.x+t.width),a=Math.max(t.y,t.y+t.height),r=Rt(n,s,e),c=Rt(o,a,e);return{x:r.x,y:r.y,w:c.x-r.x,h:c.y-r.y}}drawHandles(t,e,n){const a=rs(e);t.fillStyle=getComputedStyle(document.documentElement).getPropertyValue("--bg-panel").trim()||"#fff",t.strokeStyle=n,t.lineWidth=1.5;for(const r of a)t.beginPath(),t.rect(r.x-4,r.y-4,8,8),t.fill(),t.stroke()}}function rs(i){const{x:t,y:e,w:n,h:s}=i;return[{id:"nw",x:t,y:e},{id:"n",x:t+n/2,y:e},{id:"ne",x:t+n,y:e},{id:"e",x:t+n,y:e+s/2},{id:"se",x:t+n,y:e+s},{id:"s",x:t+n/2,y:e+s},{id:"sw",x:t,y:e+s},{id:"w",x:t,y:e+s/2}]}class Wi{constructor(t){u(this,"rafId",null);u(this,"renderFn");this.renderFn=t}requestRender(){this.rafId===null&&(this.rafId=requestAnimationFrame(()=>{this.rafId=null,this.renderFn()}))}cancel(){this.rafId!==null&&(cancelAnimationFrame(this.rafId),this.rafId=null)}}function Oi(i,t,e,n,s,o){const a=s-e,r=o-n,c=a*a+r*r;if(c===0)return Math.hypot(i-e,t-n);let l=((i-e)*a+(t-n)*r)/c;return l=Math.max(0,Math.min(1,l)),Math.hypot(i-(e+l*a),t-(n+l*r))}class Ui{constructor(t){u(this,"state");u(this,"lastHitTestMs",0);this.state=t}hitTest(t,e,n){const s=performance.now(),o=this.state.getSorted(),a=6/n;let r=null;for(let c=o.length-1;c>=0;c--){const l=o[c];if(!(l.hidden||l.locked)&&this.hitsElement(l,t,e,a)){r=l;break}}return this.lastHitTestMs=performance.now()-s,r}hitsElement(t,e,n,s){if(t.type==="line"||t.type==="arrow"||t.type==="connector")return Oi(e,n,t.x,t.y,t.x+t.width,t.y+t.height)<=Math.max(s,(t.style.strokeWidth??2)/2+s);const o=Math.min(t.x,t.x+t.width),a=Math.max(t.x,t.x+t.width),r=Math.min(t.y,t.y+t.height),c=Math.max(t.y,t.y+t.height);if(e<o||e>a||n<r||n>c)return!1;if(t.type==="ellipse"){const l=(o+a)/2,d=(r+c)/2,h=(a-o)/2,p=(c-r)/2;if(h===0||p===0)return!1;const m=(e-l)/h,g=(n-d)/p;return m*m+g*g<=1}return!0}elementsInRect(t,e,n,s){const o=Math.min(t,t+n),a=Math.max(t,t+n),r=Math.min(e,e+s),c=Math.max(e,e+s),l=[];for(const d of this.state.elements){if(d.hidden||d.locked)continue;const h=Math.min(d.x,d.x+d.width),p=Math.max(d.x,d.x+d.width),m=Math.min(d.y,d.y+d.height),g=Math.max(d.y,d.y+d.height);h>=o&&p<=a&&m>=r&&g<=c&&l.push(d)}return l}}class _i{constructor(){u(this,"fps",0);u(this,"frameCount",0);u(this,"lastSample",performance.now());u(this,"running",!1)}start(){if(this.running)return;this.running=!0;const t=()=>{if(!this.running)return;this.frameCount++;const e=performance.now(),n=e-this.lastSample;n>=1e3&&(this.fps=Math.round(this.frameCount*1e3/n),this.frameCount=0,this.lastSample=e),requestAnimationFrame(t)};requestAnimationFrame(t)}stop(){this.running=!1}}const Xi=16,qi=720,mn=120,Yi=.0032;class Ki{constructor(t,e,n,s){u(this,"tools",new Map);u(this,"active");u(this,"ctx");u(this,"target");u(this,"spaceDown",!1);u(this,"tempPanning",!1);u(this,"panLast",{x:0,y:0});u(this,"toolChangeListeners",[]);u(this,"signal");this.target=t,this.ctx=e,this.signal=s;for(const o of n)this.tools.set(o.name,o);this.active=this.tools.get("select"),this.bindEvents()}get activeName(){return this.active.name}onToolChange(t){this.toolChangeListeners.push(t)}setTool(t){var n,s,o,a,r;if(this.active.name===t){(s=(n=this.active).onActivate)==null||s.call(n,this.ctx);return}(a=(o=this.active).onDeactivate)==null||a.call(o,this.ctx);const e=this.tools.get(t);if(e){this.active=e,this.ctx.setCursor(e.cursor),(r=e.onActivate)==null||r.call(e,this.ctx);for(const c of this.toolChangeListeners)c(t)}}cancel(){var t,e;(e=(t=this.active).onCancel)==null||e.call(t,this.ctx)}bindEvents(){const t=this.target;t.addEventListener("pointerdown",e=>{if(e.button===1||e.button===2||this.spaceDown){e.preventDefault(),this.tempPanning=!0,this.panLast={x:e.clientX,y:e.clientY},this.ctx.setCursor("grabbing"),t.setPointerCapture(e.pointerId);return}e.button===0&&(t.setPointerCapture(e.pointerId),this.active.onPointerDown(e,this.ctx))}),t.addEventListener("pointermove",e=>{if(this.tempPanning){const n=this.ctx.state.viewport;n.offsetX+=e.clientX-this.panLast.x,n.offsetY+=e.clientY-this.panLast.y,this.panLast={x:e.clientX,y:e.clientY},this.ctx.state.requestRender();return}this.active.onPointerMove(e,this.ctx)}),t.addEventListener("pointerup",e=>{if(this.tempPanning){this.tempPanning=!1,this.ctx.setCursor(this.spaceDown?"grab":this.active.cursor);return}this.active.onPointerUp(e,this.ctx)}),t.addEventListener("pointercancel",()=>{this.tempPanning&&(this.tempPanning=!1,this.ctx.setCursor(this.spaceDown?"grab":this.active.cursor))}),t.addEventListener("dblclick",e=>{var n,s;(s=(n=this.active).onDoubleClick)==null||s.call(n,e,this.ctx)}),t.addEventListener("wheel",e=>{e.preventDefault();const n=this.ctx.state.viewport,s=fn(e.deltaX,e.deltaMode,this.ctx.state.viewport.scale),o=fn(e.deltaY,e.deltaMode,this.ctx.state.viewport.scale);if(e.ctrlKey||e.metaKey){const a=Math.exp(-Vi(o)*Yi);oe(n,e.clientX,e.clientY,n.scale*a)}else e.shiftKey&&Math.abs(s)<Math.abs(o)?n.offsetX-=o:(n.offsetX-=s,n.offsetY-=o);this.ctx.state.requestRender()},{passive:!1}),window.addEventListener("keydown",e=>{e.code==="Space"&&!this.isEditingText(e)&&(this.spaceDown||(this.spaceDown=!0,this.tempPanning||this.ctx.setCursor("grab")),e.preventDefault())},{signal:this.signal}),window.addEventListener("keyup",e=>{e.code==="Space"&&(this.spaceDown=!1,this.tempPanning||this.ctx.setCursor(this.active.cursor))},{signal:this.signal}),t.addEventListener("contextmenu",e=>e.preventDefault())}isEditingText(t){const e=t.target;return!!e&&(e.tagName==="TEXTAREA"||e.tagName==="INPUT"||e.isContentEditable)}}function fn(i,t,e){const s=i*(t===1?Xi:t===2?qi:1),o=e<.5?.8:e>2?1.08:1;return s*o}function Vi(i){return Math.max(-mn,Math.min(mn,i))}const he=7,Gi={nw:"nwse-resize",n:"ns-resize",ne:"nesw-resize",e:"ew-resize",se:"nwse-resize",s:"ns-resize",sw:"nesw-resize",w:"ew-resize"};class Zi{constructor(){u(this,"name","select");u(this,"cursor","default");u(this,"mode","none");u(this,"startScreen",{x:0,y:0});u(this,"startWorld",{x:0,y:0});u(this,"snapshots",[]);u(this,"activeHandle",null);u(this,"endpointIsStart",!1);u(this,"moved",!1);u(this,"pointerDownHitId",null)}onPointerDown(t,e){const{state:n,hitTester:s,renderer:o}=e;this.startScreen={x:t.clientX,y:t.clientY},this.startWorld=L(t.clientX,t.clientY,n.viewport),this.moved=!1;const a=this.hitHandle(t,e);if(a){this.mode="resize",this.activeHandle=a,this.takeSnapshots(n.getSelected());return}const r=n.getSelected();if(r.length===1&&this.isLinear(r[0])){const l=this.hitEndpoint(t,r[0],e);if(l!==null){this.mode="endpoint",this.endpointIsStart=l,this.takeSnapshots(r);return}}const c=s.hitTest(this.startWorld.x,this.startWorld.y,n.viewport.scale);if(c){this.pointerDownHitId=c.id,t.shiftKey?n.selectedIds.has(c.id)?n.selectedIds.delete(c.id):n.selectedIds.add(c.id):n.selectedIds.has(c.id)||(n.clearSelection(),n.selectedIds.add(c.id)),this.mode="move",this.takeSnapshots(n.getSelected()),n.requestRender();return}t.shiftKey||n.clearSelection(),this.mode="marquee",o.overlay.marquee={x:t.clientX,y:t.clientY,w:0,h:0},n.requestRender()}onPointerMove(t,e){const{state:n,renderer:s,hitTester:o}=e;if(this.mode==="none"){const d=this.hitHandle(t,e);if(d){e.setCursor(Gi[d]);return}const h=L(t.clientX,t.clientY,n.viewport),p=o.hitTest(h.x,h.y,n.viewport.scale),m=p?p.id:null;e.setCursor(p?"move":"default"),m!==n.hoveredId&&(n.hoveredId=m,n.requestRender());return}const a=t.clientX-this.startScreen.x,r=t.clientY-this.startScreen.y;Math.abs(a)+Math.abs(r)>2&&(this.moved=!0);const c=a/n.viewport.scale,l=r/n.viewport.scale;if(this.mode==="move"){for(const d of this.snapshots){const h=n.elementsById.get(d.id);!h||h.locked||(h.x=d.x+c,h.y=d.y+l)}n.requestRender()}else if(this.mode==="marquee")s.overlay.marquee={x:this.startScreen.x,y:this.startScreen.y,w:a,h:r},n.requestRender();else if(this.mode==="resize"&&this.activeHandle)this.applyResize(c,l,t.shiftKey,e),n.requestRender();else if(this.mode==="endpoint"){const d=this.snapshots[0],h=n.elementsById.get(d.id);h&&(this.endpointIsStart?(h.x=d.x+c,h.y=d.y+l,h.width=d.width-c,h.height=d.height-l):(h.width=d.width+c,h.height=d.height+l)),n.requestRender()}}onPointerUp(t,e){const{state:n,renderer:s,hitTester:o,commands:a}=e;if(this.mode==="marquee"){const r=s.overlay.marquee;if(s.overlay.marquee=null,r&&(Math.abs(r.w)>3||Math.abs(r.h)>3)){const c=L(r.x,r.y,n.viewport),l=L(r.x+r.w,r.y+r.h,n.viewport),d=o.elementsInRect(c.x,c.y,l.x-c.x,l.y-c.y);for(const h of d)n.selectedIds.add(h.id)}n.requestRender()}else if((this.mode==="move"||this.mode==="resize"||this.mode==="endpoint")&&this.moved){const r=this.snapshots,c=r.map(d=>{const h=n.elementsById.get(d.id);return{id:d.id,x:h.x,y:h.y,width:h.width,height:h.height}}),l=d=>{for(const h of d){const p=n.elementsById.get(h.id);p&&(p.x=h.x,p.y=h.y,p.width=h.width,p.height=h.height,p.updatedAt=Date.now(),X(p.id))}n.emitChange()};for(const d of c){const h=n.elementsById.get(d.id);h&&(h.updatedAt=Date.now(),X(h.id))}a.push(this.mode,()=>l(c),()=>l(r)),n.emitChange()}else this.mode==="move"&&!this.moved&&this.toggleTaskIfCheckboxClick(t,e);this.mode="none",this.activeHandle=null,this.snapshots=[],this.pointerDownHitId=null}onDoubleClick(t,e){const{state:n,hitTester:s}=e,o=L(t.clientX,t.clientY,n.viewport),a=s.hitTest(o.x,o.y,n.viewport.scale);a&&(a.type==="sticky"||a.type==="task"||a.type==="text"||a.type==="rectangle"||a.type==="ellipse"||a.type==="frame"||a.type==="arrow"||a.type==="line"||a.type==="connector")&&e.openTextEditor(a)}onCancel(t){if(this.mode!=="none"&&this.snapshots.length>0)for(const e of this.snapshots){const n=t.state.elementsById.get(e.id);n&&(n.x=e.x,n.y=e.y,n.width=e.width,n.height=e.height)}t.renderer.overlay.marquee=null,this.mode="none",t.state.clearSelection(),t.state.requestRender()}isLinear(t){return t.type==="line"||t.type==="arrow"||t.type==="connector"}takeSnapshots(t){this.snapshots=t.map(e=>({id:e.id,x:e.x,y:e.y,width:e.width,height:e.height}))}toggleTaskIfCheckboxClick(t,e){const{state:n,hitTester:s,commands:o}=e,a=L(t.clientX,t.clientY,n.viewport),r=s.hitTest(a.x,a.y,n.viewport.scale);if(!r||r.id!==this.pointerDownHitId||r.type!=="task"||!this.hitTaskCheckbox(a.x,a.y,r))return;const c=r.data.checked===!0,l=!c,d=r.id,h=p=>{const m=n.elementsById.get(d);m&&(m.data.checked=p,m.updatedAt=Date.now(),n.emitChange())};o.execute("toggle-task",()=>h(l),()=>h(c))}hitTaskCheckbox(t,e,n){const s=Math.min(22,Math.max(16,n.height*.38)),o=n.x+16,a=n.y+n.height/2-s/2,r=8;return t>=o-r&&t<=o+s+r&&e>=a-r&&e<=a+s+r}hitHandle(t,e){const{state:n,renderer:s}=e,o=n.getSelected();if(o.length===0||o.length===1&&this.isLinear(o[0]))return null;let a;if(o.length===1)a=s.elementScreenBBox(o[0]);else{let r=1/0,c=1/0,l=-1/0,d=-1/0;for(const h of o){const p=s.elementScreenBBox(h);r=Math.min(r,p.x),c=Math.min(c,p.y),l=Math.max(l,p.x+p.w),d=Math.max(d,p.y+p.h)}a={x:r,y:c,w:l-r,h:d-c}}for(const r of rs(a))if(Math.abs(t.clientX-r.x)<=he&&Math.abs(t.clientY-r.y)<=he)return r.id;return null}hitEndpoint(t,e,n){const s=n.state.viewport,o=e.x*s.scale+s.offsetX,a=e.y*s.scale+s.offsetY,r=(e.x+e.width)*s.scale+s.offsetX,c=(e.y+e.height)*s.scale+s.offsetY;return Math.hypot(t.clientX-o,t.clientY-a)<=he+2?!0:Math.hypot(t.clientX-r,t.clientY-c)<=he+2?!1:null}applyResize(t,e,n,s){const{state:o}=s,a=this.activeHandle;let r=1/0,c=1/0,l=-1/0,d=-1/0;for(const w of this.snapshots)r=Math.min(r,Math.min(w.x,w.x+w.width)),c=Math.min(c,Math.min(w.y,w.y+w.height)),l=Math.max(l,Math.max(w.x,w.x+w.width)),d=Math.max(d,Math.max(w.y,w.y+w.height));const h=l-r,p=d-c;if(h===0||p===0)return;let m=r,g=c,y=h,b=p;if(a.includes("e")&&(y=h+t),a.includes("w")&&(m=r+t,y=h-t),a.includes("s")&&(b=p+e),a.includes("n")&&(g=c+e,b=p-e),n&&(a==="nw"||a==="ne"||a==="se"||a==="sw")){const w=h/p;if(Math.abs(y/h)>Math.abs(b/p)){const E=y/w;a.includes("n")&&(g=g+(b-E)),b=E}else{const E=b*w;a.includes("w")&&(m=m+(y-E)),y=E}}const x=4;if(Math.abs(y)<x||Math.abs(b)<x)return;const v=y/h,S=b/p;for(const w of this.snapshots){const E=o.elementsById.get(w.id);!E||E.locked||(E.x=m+(w.x-r)*v,E.y=g+(w.y-c)*S,E.width=w.width*v,E.height=w.height*S,E.updatedAt=Date.now(),X(E.id))}}}class Ji{constructor(){u(this,"name","hand");u(this,"cursor","grab");u(this,"panning",!1);u(this,"last",{x:0,y:0})}onPointerDown(t,e){this.panning=!0,this.last={x:t.clientX,y:t.clientY},e.setCursor("grabbing")}onPointerMove(t,e){if(!this.panning)return;const n=e.state.viewport;n.offsetX+=t.clientX-this.last.x,n.offsetY+=t.clientY-this.last.y,this.last={x:t.clientX,y:t.clientY},e.state.requestRender()}onPointerUp(t,e){this.panning=!1,e.setCursor("grab")}onCancel(t){this.panning=!1,t.setCursor("grab")}}const Ce=["#fef08a","#fdba74","#fca5a5","#f9a8d4","#d8b4fe","#a5b4fc","#93c5fd","#86efac"];let cs=Ce[0];function Qi(){return cs}function to(i){cs=i}class eo{constructor(){u(this,"name","sticky");u(this,"cursor","crosshair")}onPointerDown(t,e){const{state:n,commands:s}=e,o=L(t.clientX,t.clientY,n.viewport),a=H("sticky",{x:o.x-110,y:o.y-80,width:220,height:160,zIndex:n.maxZIndex()+1,style:{fill:Qi(),borderRadius:12,shadow:!0,fontSize:15,textColor:"#1f2933"},data:{text:""}});s.execute("create-sticky",()=>{n.elementsById.has(a.id)||n.addElement(a),n.emitChange()},()=>{n.removeElement(a.id),n.emitChange()}),n.clearSelection(),n.selectedIds.add(a.id),e.setTool("select"),e.openTextEditor(a)}onPointerMove(t,e){}onPointerUp(t,e){}}class no{constructor(){u(this,"name","task");u(this,"cursor","crosshair")}onPointerDown(t,e){const{state:n,commands:s}=e,o=L(t.clientX,t.clientY,n.viewport),a=n.theme==="dark",r=H("task",{x:o.x-140,y:o.y-28,width:280,height:56,zIndex:n.maxZIndex()+1,style:{fill:a?"#17191b":"#ffffff",stroke:a?"rgba(255,255,255,0.12)":"rgba(0,0,0,0.09)",strokeWidth:1,borderRadius:14,shadow:!0,fontSize:15,fontWeight:"650",textColor:a?"#f6f6f3":"#252829"},data:{text:"Task title",checked:!1}});s.execute("create-task",()=>{n.elementsById.has(r.id)||n.addElement(r),n.emitChange()},()=>{n.removeElement(r.id),n.emitChange()}),n.clearSelection(),n.selectedIds.add(r.id),e.setTool("select"),e.openTextEditor(r)}onPointerMove(t,e){}onPointerUp(t,e){}}class ct{constructor(t){u(this,"name");u(this,"cursor","crosshair");u(this,"shapeType");u(this,"shapeKind");u(this,"drawing",!1);u(this,"startWorld",{x:0,y:0});u(this,"preview",null);this.name=t,this.shapeKind=t,this.shapeType=t==="ellipse"?"ellipse":"rectangle"}onPointerDown(t,e){const{state:n}=e;this.drawing=!0,this.startWorld=L(t.clientX,t.clientY,n.viewport);const s=n.theme==="dark",o=!["rectangle","ellipse","pill","cylinder"].includes(this.shapeKind);this.preview=H(this.shapeType,{x:this.startWorld.x,y:this.startWorld.y,width:0,height:0,zIndex:n.maxZIndex()+1,style:{fill:o?"#0078d4":s?"#2a2d33":"#ffffff",stroke:o?"#495057":s?"#9ca3af":"#374151",strokeWidth:o?0:1.5,borderRadius:this.shapeKind==="pill"?999:this.shapeKind==="rectangle"?8:0,fontSize:14,textColor:o?"#ffffff":s?"#f2f2f2":"#1f2933"},data:{text:"",shapeKind:this.shapeKind}}),e.renderer.overlay.preview=this.preview}onPointerMove(t,e){if(!this.drawing||!this.preview)return;const n=L(t.clientX,t.clientY,e.state.viewport);let s=n.x-this.startWorld.x,o=n.y-this.startWorld.y;if(t.shiftKey){const a=Math.max(Math.abs(s),Math.abs(o));s=Math.sign(s||1)*a,o=Math.sign(o||1)*a}this.preview.x=Math.min(this.startWorld.x,this.startWorld.x+s),this.preview.y=Math.min(this.startWorld.y,this.startWorld.y+o),this.preview.width=Math.abs(s),this.preview.height=Math.abs(o),e.state.requestRender()}onPointerUp(t,e){const{state:n,commands:s}=e;if(!this.drawing||!this.preview)return;this.drawing=!1,e.renderer.overlay.preview=null;const o=this.preview;this.preview=null,(o.width<4||o.height<4)&&(o.width=this.shapeKind==="chevron"?210:160,o.height=this.shapeKind==="chevron"?76:100,o.x-=o.width/2,o.y-=o.height/2),s.execute("create-shape",()=>{n.elementsById.has(o.id)||n.addElement(o),n.emitChange()},()=>{n.removeElement(o.id),n.emitChange()}),n.clearSelection(),n.selectedIds.add(o.id),e.setTool("select")}onCancel(t){this.drawing=!1,this.preview=null,t.renderer.overlay.preview=null,t.state.requestRender()}}class so{constructor(){u(this,"name","text");u(this,"cursor","text")}onPointerDown(t,e){const{state:n,commands:s}=e,o=L(t.clientX,t.clientY,n.viewport),a=H("text",{x:o.x,y:o.y-12,width:240,height:28,zIndex:n.maxZIndex()+1,style:{fontSize:16,textColor:n.theme==="dark"?"#f2f2f2":"#1f2933"},data:{text:""}});It(a),s.execute("create-text",()=>{n.elementsById.has(a.id)||n.addElement(a),n.emitChange()},()=>{n.removeElement(a.id),n.emitChange()}),n.clearSelection(),n.selectedIds.add(a.id),e.setTool("select"),e.openTextEditor(a)}onPointerMove(t,e){}onPointerUp(t,e){}}class Gt{constructor(t="arrow"){u(this,"name");u(this,"cursor","crosshair");u(this,"drawing",!1);u(this,"startWorld",{x:0,y:0});u(this,"preview",null);this.name=t}onPointerDown(t,e){const{state:n}=e;this.drawing=!0,this.startWorld=L(t.clientX,t.clientY,n.viewport),this.preview=H("arrow",{x:this.startWorld.x,y:this.startWorld.y,width:0,height:0,zIndex:n.maxZIndex()+1,style:{stroke:n.theme==="dark"?"#d1d5db":"#374151",strokeWidth:2,arrowEnd:!0,arrowStart:this.name==="twoWayArrow",strokeDash:this.name==="dashedArrow"||t.altKey?[8,6]:void 0},data:{text:"",labelPosition:this.name==="sidedLabelArrow"?"sides":"center"}}),e.renderer.overlay.preview=this.preview}onPointerMove(t,e){if(!this.drawing||!this.preview)return;const n=L(t.clientX,t.clientY,e.state.viewport);let s=n.x-this.startWorld.x,o=n.y-this.startWorld.y;if(t.shiftKey){const a=Math.atan2(o,s),r=Math.round(a/(Math.PI/4))*(Math.PI/4),c=Math.hypot(s,o);s=Math.cos(r)*c,o=Math.sin(r)*c}this.preview.width=s,this.preview.height=o,e.state.requestRender()}onPointerUp(t,e){const{state:n,commands:s}=e;if(!this.drawing||!this.preview)return;this.drawing=!1,e.renderer.overlay.preview=null;const o=this.preview;if(this.preview=null,Math.hypot(o.width,o.height)<8){n.requestRender();return}s.execute("create-arrow",()=>{n.elementsById.has(o.id)||n.addElement(o),n.emitChange()},()=>{n.removeElement(o.id),n.emitChange()}),n.clearSelection(),n.selectedIds.add(o.id),e.setTool("select"),(this.name==="labeledArrow"||this.name==="sidedLabelArrow")&&e.openTextEditor(o)}onCancel(t){this.drawing=!1,this.preview=null,t.renderer.overlay.preview=null,t.state.requestRender()}}class io{constructor(t){u(this,"name","image");u(this,"cursor","default");u(this,"onInsert");this.onInsert=t}onActivate(t){const e=document.createElement("input");e.type="file",e.accept="image/png,image/jpeg,image/webp,image/gif",e.multiple=!0,e.onchange=()=>{e.files&&e.files.length>0&&this.onInsert(e.files,window.innerWidth/2,window.innerHeight/2),t.setTool("select")},e.oncancel=()=>t.setTool("select"),e.click()}onPointerDown(t,e){}onPointerMove(t,e){}onPointerUp(t,e){}}const pe="psc:";class oo{constructor(){u(this,"lastSaveMs",0)}async saveBoard(t){const e=performance.now();try{await K.put("boards",t),this.lastSaveMs=performance.now()-e,this.setPref("lastBoardId",t.id),this.setPref("recovery",JSON.stringify({id:t.id,title:t.title,updatedAt:t.updatedAt,elementCount:t.elements.length}))}catch(n){throw console.error("Board save failed",n),n}}async loadBoard(t){try{return await K.get("boards",t)}catch(e){console.error("Board load failed",e);return}}async deleteBoard(t){await K.delete("boards",t)}async clearAllBoards(){await K.clearStore("boards")}async getAllBoards(){try{return await K.getAll("boards")}catch{return[]}}setPref(t,e){try{localStorage.setItem(pe+t,e)}catch{}}getPref(t){try{return localStorage.getItem(pe+t)}catch{return null}}removePref(t){try{localStorage.removeItem(pe+t)}catch{}}clearPrefs(){try{const t=[];for(let e=0;e<localStorage.length;e++){const n=localStorage.key(e);n&&n.startsWith(pe)&&t.push(n)}for(const e of t)localStorage.removeItem(e)}catch{}}async estimateStorage(){try{if(navigator.storage&&navigator.storage.estimate){const t=await navigator.storage.estimate();return{usage:t.usage??0,quota:t.quota??0}}}catch{}return{usage:0,quota:0}}}const tt=new oo;function ao(i){return new Promise((t,e)=>{const n=new FileReader;n.onload=()=>{const s=n.result;t(s.slice(s.indexOf(",")+1))},n.onerror=()=>e(n.error),n.readAsDataURL(i)})}function ro(i,t){const e=atob(i),n=new Uint8Array(e.length);for(let s=0;s<e.length;s++)n[s]=e.charCodeAt(s);return new Blob([n],{type:t})}function gn(i,t){const e=new Blob([JSON.stringify(t)],{type:"application/json"}),n=URL.createObjectURL(e),s=document.createElement("a");s.href=n,s.download=i,s.click(),URL.revokeObjectURL(n)}function yn(i){return i.replace(/[^a-z0-9-_ ]/gi,"").trim().slice(0,60)||"board"}class co{exportBoardJson(t){gn(`${yn(t.title)}.json`,t)}async exportFullBundle(t){const e=[];for(const s of t.assetIds){const o=await it.get(s);o&&e.push({id:o.id,mimeType:o.mimeType,width:o.width,height:o.height,name:o.name,base64:await ao(o.blob)})}const n={bundleVersion:1,board:t,assets:e};gn(`${yn(t.title)}-bundle.json`,n)}async importFromFile(t){let e;try{e=JSON.parse(await t.text())}catch{return null}if(typeof e!="object"||e===null)return null;const n=e;if(n.bundleVersion===1&&Array.isArray(n.assets)){const s=we(n.board);if(!s)return null;const o=new Map;for(const a of n.assets){const r=await this.importAsset(a);r&&o.set(r.originalId,r.asset.id)}for(const a of s.elements){const r=a.data.assetId;typeof r=="string"&&o.has(r)&&(a.data.assetId=o.get(r))}return s.assetIds=[...o.values()],s}return we(e)}async importAsset(t){if(typeof t!="object"||t===null)return null;const e=t;if(typeof e.id!="string"||typeof e.base64!="string"||typeof e.mimeType!="string"||!e.mimeType.startsWith("image/"))return null;try{const n=ro(e.base64,e.mimeType),s=Date.now(),o={id:ae(),type:"image",mimeType:e.mimeType,blob:n,width:typeof e.width=="number"?e.width:0,height:typeof e.height=="number"?e.height:0,sizeBytes:n.size,createdAt:s,updatedAt:s,name:typeof e.name=="string"?e.name.slice(0,100):void 0};return await it.put(o),{originalId:e.id,asset:o}}catch{return null}}}const Ne=new co,V={select:'<svg viewBox="0 0 24 24"><path d="M4 3l7 18 2.5-7.5L21 11z"/></svg>',hand:'<svg viewBox="0 0 24 24"><path d="M18 11V6.5a1.5 1.5 0 0 0-3 0V11m0-1V4.5a1.5 1.5 0 0 0-3 0V10m0 .5v-5a1.5 1.5 0 0 0-3 0V12m9-1v1.5a1.5 1.5 0 0 1 3 0V14c0 4-2.5 7-6.5 7S8 18.5 6 15l-1.8-3.2a1.4 1.4 0 0 1 2.3-1.5L8 12V7"/></svg>',sticky:'<svg viewBox="0 0 24 24"><path d="M5 4h14a1 1 0 0 1 1 1v9l-6 6H5a1 1 0 0 1-1-1V5a1 1 0 0 1 1-1z"/><path d="M14 20v-5a1 1 0 0 1 1-1h5"/></svg>',task:'<svg viewBox="0 0 24 24"><rect x="4" y="5" width="16" height="14" rx="3"/><path d="M8 12l2.3 2.3L16 8.8"/></svg>',rectangle:'<svg viewBox="0 0 24 24"><rect x="4" y="5" width="16" height="14" rx="2"/></svg>',ellipse:'<svg viewBox="0 0 24 24"><ellipse cx="12" cy="12" rx="8.5" ry="7"/></svg>',diamond:'<svg viewBox="0 0 24 24"><path d="M12 3l8 9-8 9-8-9z"/></svg>',triangle:'<svg viewBox="0 0 24 24"><path d="M12 4l9 16H3z"/></svg>',pill:'<svg viewBox="0 0 24 24"><rect x="3.5" y="7" width="17" height="10" rx="5"/></svg>',chevron:'<svg viewBox="0 0 24 24"><path d="M4 6h12l5 6-5 6H4l5-6z"/></svg>',parallelogram:'<svg viewBox="0 0 24 24"><path d="M7 5h13l-3 14H4z"/></svg>',hexagon:'<svg viewBox="0 0 24 24"><path d="M8 4h8l5 8-5 8H8l-5-8z"/></svg>',cylinder:'<svg viewBox="0 0 24 24"><ellipse cx="12" cy="6" rx="7" ry="3"/><path d="M5 6v11c0 1.7 3.1 3 7 3s7-1.3 7-3V6"/></svg>',arrowDashed:'<svg viewBox="0 0 24 24"><path stroke-dasharray="4 3" d="M4 12h14m0 0l-5-5m5 5l-5 5"/></svg>',arrowBoth:'<svg viewBox="0 0 24 24"><path d="M4 12h16m-16 0l5-5m-5 5l5 5m11-5l-5-5m5 5l-5 5"/></svg>',arrowLabel:'<svg viewBox="0 0 24 24"><path d="M3 17L17 7m0 0h-6m6 0v6"/><rect x="7" y="9" width="10" height="6" rx="1"/></svg>',text:'<svg viewBox="0 0 24 24"><path d="M5 6V4h14v2M12 4v16m-3 0h6"/></svg>',arrow:'<svg viewBox="0 0 24 24"><path d="M5 19L19 5m0 0h-7m7 0v7"/></svg>',image:'<svg viewBox="0 0 24 24"><rect x="3" y="4" width="18" height="16" rx="2"/><circle cx="9" cy="10" r="1.6"/><path d="M21 16l-5-5-9 9"/></svg>',templates:'<svg viewBox="0 0 24 24"><rect x="3" y="3" width="8" height="8" rx="1.5"/><rect x="13" y="3" width="8" height="8" rx="1.5"/><rect x="3" y="13" width="8" height="8" rx="1.5"/><rect x="13" y="13" width="8" height="8" rx="1.5"/></svg>',shapes:'<svg viewBox="0 0 24 24"><rect x="4" y="5" width="7" height="7" rx="1.5"/><circle cx="16.5" cy="8.5" r="3.5"/><path d="M7.5 14l3.8 6H3.7z"/><path d="M15 14h4l2 3-2 3h-4l2-3z"/></svg>',sun:'<svg viewBox="0 0 24 24"><circle cx="12" cy="12" r="4"/><path d="M12 2v2m0 16v2M4.9 4.9l1.4 1.4m11.4 11.4l1.4 1.4M2 12h2m16 0h2M4.9 19.1l1.4-1.4m11.4-11.4l1.4-1.4"/></svg>',moon:'<svg viewBox="0 0 24 24"><path d="M21 12.8A9 9 0 1 1 11.2 3 7 7 0 0 0 21 12.8z"/></svg>',export:'<svg viewBox="0 0 24 24"><path d="M12 15V3m0 0L7 8m5-5l5 5M4 17v2a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2v-2"/></svg>',import:'<svg viewBox="0 0 24 24"><path d="M12 3v12m0 0l-5-5m5 5l5-5M4 17v2a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2v-2"/></svg>',gauge:'<svg viewBox="0 0 24 24"><path d="M12 14l4-4M3.3 14a9 9 0 1 1 17.4 0"/></svg>',storage:'<svg viewBox="0 0 24 24"><ellipse cx="12" cy="5.5" rx="8" ry="2.5"/><path d="M4 5.5V12c0 1.4 3.6 2.5 8 2.5s8-1.1 8-2.5V5.5M4 12v6.5C4 19.9 7.6 21 12 21s8-1.1 8-2.5V12"/></svg>',flask:'<svg viewBox="0 0 24 24"><path d="M9 3h6M10 3v6L4.5 18a2 2 0 0 0 1.8 3h11.4a2 2 0 0 0 1.8-3L14 9V3"/><path d="M7 15h10"/></svg>',reset:'<svg viewBox="0 0 24 24"><path d="M3 12a9 9 0 1 0 2.6-6.3M3 4v5h5"/></svg>',camera:'<svg viewBox="0 0 24 24"><path d="M3 8a2 2 0 0 1 2-2h2l2-2h6l2 2h2a2 2 0 0 1 2 2v10a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2z"/><circle cx="12" cy="13" r="3.5"/></svg>',trash:'<svg viewBox="0 0 24 24"><path d="M4 7h16M10 11v6m4-6v6M6 7l1 13a1 1 0 0 0 1 1h8a1 1 0 0 0 1-1l1-13M9 7V4a1 1 0 0 1 1-1h4a1 1 0 0 1 1 1v3"/></svg>',embed:'<svg viewBox="0 0 24 24"><rect x="3" y="5" width="18" height="14" rx="2" stroke-dasharray="3 3"/><path d="M9 10l-2 2 2 2m6-4l2 2-2 2"/></svg>',arrowLeft:'<svg viewBox="0 0 24 24"><path d="M19 12H5m0 0l6-6m-6 6l6 6"/></svg>',search:'<svg viewBox="0 0 24 24"><circle cx="11" cy="11" r="7"/><path d="M20 20l-4-4"/></svg>',panelLeft:'<svg viewBox="0 0 24 24"><rect x="4" y="4" width="16" height="16" rx="2"/><path d="M10 4v16"/></svg>',edit:'<svg viewBox="0 0 24 24"><path d="M12 20h9"/><path d="M16.5 3.5a2.1 2.1 0 0 1 3 3L7 19l-4 1 1-4z"/></svg>',copy:'<svg viewBox="0 0 24 24"><rect x="8" y="8" width="11" height="11" rx="2"/><path d="M5 15H4a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h8a2 2 0 0 1 2 2v1"/></svg>',folder:'<svg viewBox="0 0 24 24"><path d="M4 7a2 2 0 0 1 2-2h4l2 2h6a2 2 0 0 1 2 2v7a2 2 0 0 1-2 2H6a2 2 0 0 1-2-2z"/></svg>',folderOpen:'<svg viewBox="0 0 24 24"><path d="M4 7a2 2 0 0 1 2-2h4l2 2h6a2 2 0 0 1 2 2v1M4 8l1.5 9c.1.6.6 1 1.2 1h10.6c.6 0 1.1-.4 1.2-1L20 8z"/></svg>',file:'<svg viewBox="0 0 24 24"><path d="M13 3H6a2 2 0 0 0-2 2v14a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V10z"/><path d="M13 3v7h7"/></svg>',fileText:'<svg viewBox="0 0 24 24"><path d="M13 3H6a2 2 0 0 0-2 2v14a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V10z"/><path d="M13 3v7h7M10 13h4m-4 4h4"/></svg>',board:'<svg viewBox="0 0 24 24"><rect x="3" y="3" width="7" height="7" rx="1"/><rect x="12" y="3" width="9" height="7" rx="1"/><rect x="3" y="12" width="9" height="9" rx="1"/><rect x="14" y="12" width="7" height="9" rx="1"/></svg>',doc:'<svg viewBox="0 0 24 24"><path d="M14 3H6a2 2 0 0 0-2 2v14a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V9z"/><path d="M14 3v6h6M10 13h4m-4 4h4m-4-8h1"/></svg>',skill:'<svg viewBox="0 0 24 24"><path d="M12 2l3.1 6.3 6.9 1-5 4.9 1.2 6.8-6.2-3.3-6.2 3.3 1.2-6.8-5-4.9 6.9-1z"/></svg>',plus:'<svg viewBox="0 0 24 24"><path d="M12 5v14m-7-7h14"/></svg>',moreVertical:'<svg viewBox="0 0 24 24"><circle cx="12" cy="12" r="1"/><circle cx="12" cy="5" r="1"/><circle cx="12" cy="19" r="1"/></svg>',chevronRight:'<svg viewBox="0 0 24 24"><path d="M9 18l6-6-6-6"/></svg>',chevronDown:'<svg viewBox="0 0 24 24"><path d="M6 9l6 6 6-6"/></svg>',wiki:'<svg viewBox="0 0 24 24"><path d="M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z"/><path d="M14 2v6h6M8 13h2m-2 4h6m-6-8h1"/></svg>',list:'<svg viewBox="0 0 24 24"><line x1="8" y1="6" x2="21" y2="6"/><line x1="8" y1="12" x2="21" y2="12"/><line x1="8" y1="18" x2="21" y2="18"/><circle cx="4" cy="6" r="1"/><circle cx="4" cy="12" r="1"/><circle cx="4" cy="18" r="1"/></svg>'},lo=[{tool:"select",icon:"select",label:"Select",key:"V"},{tool:"hand",icon:"hand",label:"Hand",key:"H"},{tool:"sticky",icon:"sticky",label:"Sticky note",key:"S"},{tool:"task",icon:"task",label:"Task",key:""},{tool:"text",icon:"text",label:"Text",key:"T"},{tool:"image",icon:"image",label:"Image",key:"I"}],ls=[{tool:"rectangle",icon:"rectangle",label:"Rectangle",key:"R"},{tool:"ellipse",icon:"ellipse",label:"Ellipse",key:"O"},{tool:"diamond",icon:"diamond",label:"Diamond",key:""},{tool:"triangle",icon:"triangle",label:"Triangle",key:""},{tool:"pill",icon:"pill",label:"Pill",key:""},{tool:"chevron",icon:"chevron",label:"Chevron",key:""},{tool:"parallelogram",icon:"parallelogram",label:"Parallelogram",key:""},{tool:"hexagon",icon:"hexagon",label:"Hexagon",key:""},{tool:"cylinder",icon:"cylinder",label:"Cylinder",key:""}],ho=[{tool:"arrow",icon:"arrow",label:"Arrow (hold Shift to snap)",key:"A"},{tool:"dashedArrow",icon:"arrowDashed",label:"Dashed arrow",key:""},{tool:"twoWayArrow",icon:"arrowBoth",label:"Two-way arrow",key:""},{tool:"labeledArrow",icon:"arrowLabel",label:"Centered label arrow",key:""},{tool:"sidedLabelArrow",icon:"arrowLabel",label:"Left and right labels",key:""}],po=new Set(ls.map(i=>i.tool));class uo{constructor(t,e){u(this,"element");u(this,"toolButtons",new Map);u(this,"shapeButtons",new Map);u(this,"shapeBtn");u(this,"shapeGroup");u(this,"arrowGroup");u(this,"themeBtn");this.element=document.createElement("div"),this.element.className="toolbar";for(const a of lo){const r=this.makeButton(a.icon,a.label,a.key);r.addEventListener("click",()=>e.setTool(a.tool)),this.toolButtons.set(a.tool,r),this.element.appendChild(r),a.tool==="sticky"&&this.element.appendChild(this.makeShapePicker(e)),a.tool==="text"&&this.element.appendChild(this.makeArrowPicker(e))}this.element.appendChild(this.divider());const n=this.makeButton("templates","Templates","");n.addEventListener("click",e.openTemplates),this.element.appendChild(n),this.element.appendChild(this.divider()),this.themeBtn=this.makeButton("moon","Toggle theme",""),this.themeBtn.addEventListener("click",e.toggleTheme),this.element.appendChild(this.themeBtn);const s=this.makeButton("export","Export / Import","");s.addEventListener("click",e.openExportMenu),this.element.appendChild(s);const o=this.makeButton("flask","Stress test","");if(o.addEventListener("click",e.toggleStressPanel),this.element.appendChild(o),e.copyEmbed){this.element.appendChild(this.divider());const a=this.makeButton("embed","Copy embed of a region","");a.addEventListener("click",e.copyEmbed),this.element.appendChild(a)}t.appendChild(this.element)}makeButton(t,e,n){const s=document.createElement("button");s.className="tool-btn",s.setAttribute("aria-label",e),s.innerHTML=V[t]??"";const o=document.createElement("span");if(o.className="tooltip",o.textContent=e,n){const a=document.createElement("kbd");a.textContent=n,o.appendChild(a)}return s.appendChild(o),s}makeShapePicker(t){this.shapeGroup=document.createElement("div"),this.shapeGroup.className="shape-tool-group",this.shapeBtn=this.makeButton("shapes","Shapes",""),this.shapeBtn.classList.add("shape-tool-trigger"),this.shapeBtn.addEventListener("click",n=>{n.stopPropagation(),this.shapeGroup.classList.toggle("open")});const e=document.createElement("div");e.className="shape-tool-popover";for(const n of ls){const s=this.makeButton(n.icon,n.label,n.key);s.classList.add("shape-option-btn"),s.addEventListener("click",o=>{o.stopPropagation(),t.setTool(n.tool),this.shapeGroup.classList.remove("open")}),this.shapeButtons.set(n.tool,s),e.appendChild(s)}return this.shapeGroup.append(this.shapeBtn,e),this.shapeGroup}makeArrowPicker(t){this.arrowGroup=document.createElement("div"),this.arrowGroup.className="shape-tool-group";const e=this.makeButton("arrow","Arrow types","");e.classList.add("shape-tool-trigger"),e.addEventListener("click",s=>{s.stopPropagation(),this.arrowGroup.classList.toggle("open")});const n=document.createElement("div");n.className="shape-tool-popover";for(const s of ho){const o=this.makeButton(s.icon,s.label,s.key);o.classList.add("shape-option-btn"),o.addEventListener("click",a=>{a.stopPropagation(),t.setTool(s.tool),this.arrowGroup.classList.remove("open")}),this.toolButtons.set(s.tool,o),n.appendChild(o)}return this.arrowGroup.append(e,n),this.arrowGroup}divider(){const t=document.createElement("div");return t.className="toolbar-divider",t}setActiveTool(t){var e;for(const[n,s]of this.toolButtons)s.classList.toggle("active",n===t);for(const[n,s]of this.shapeButtons)s.classList.toggle("active",n===t);(e=this.shapeBtn)==null||e.classList.toggle("active",po.has(t))}setTheme(t){const e=this.themeBtn.querySelector(".tooltip");this.themeBtn.innerHTML=V[t==="dark"?"sun":"moon"],e&&this.themeBtn.appendChild(e)}}class mo{constructor(t,e,n){u(this,"zoomLabel");u(this,"titleInput");u(this,"titleMeasure");u(this,"statusEl");u(this,"statusTextEl");u(this,"statusActionBtn");const s=document.createElement("div");if(s.className="top-left",e.onExit){const m=document.createElement("button");m.className="control-btn back-btn",m.innerHTML=`${V.arrowLeft}<span>ViteBoard</span>`,m.title="Save and back to ViteBoard",m.setAttribute("aria-label","Back to ViteBoard"),m.addEventListener("click",e.onExit),s.appendChild(m)}this.titleInput=document.createElement("input"),this.titleInput.className="board-title",this.titleInput.value=n,this.titleInput.maxLength=120,this.titleInput.setAttribute("aria-label","Board title"),this.titleInput.addEventListener("change",()=>e.onTitleChange(this.titleInput.value.trim()||"Untitled Board")),this.titleInput.addEventListener("input",()=>this.resizeTitleInput()),this.titleInput.addEventListener("keydown",m=>{m.stopPropagation(),m.key==="Enter"&&this.titleInput.blur()}),this.titleMeasure=document.createElement("span"),this.titleMeasure.className="board-title-measure",s.appendChild(this.titleInput),s.appendChild(this.titleMeasure),t.appendChild(s),this.resizeTitleInput();const o=document.createElement("div");o.className="top-right";const a=document.createElement("div");a.className="control-group";const r=this.btn("−","Zoom out (Ctrl/Cmd + wheel or Ctrl/Cmd + -)");r.addEventListener("click",e.zoomOut),a.appendChild(r),this.zoomLabel=this.btn("100%","Reset zoom to 100% (Ctrl/Cmd + 0)"),this.zoomLabel.classList.add("zoom-label"),this.zoomLabel.addEventListener("click",e.resetView),a.appendChild(this.zoomLabel);const c=this.btn("+","Zoom in (Ctrl/Cmd + wheel or Ctrl/Cmd + +)");c.addEventListener("click",e.zoomIn),a.appendChild(c),o.appendChild(a);const l=document.createElement("div");l.className="control-group";const d=this.iconBtn("reset","Reset view");d.addEventListener("click",e.resetView),l.appendChild(d);const h=this.iconBtn("storage","Storage manager");h.addEventListener("click",e.openStorageManager),l.appendChild(h);const p=this.iconBtn("gauge","Performance overlay");if(p.addEventListener("click",e.togglePerfOverlay),l.appendChild(p),e.deleteBoard){const m=this.iconBtn("trash","Delete board");m.classList.add("danger-control"),m.addEventListener("click",e.deleteBoard),l.appendChild(m)}o.appendChild(l),this.statusEl=document.createElement("div"),this.statusEl.className="board-live-status",this.statusEl.hidden=!0,this.statusTextEl=document.createElement("span"),this.statusActionBtn=document.createElement("button"),this.statusActionBtn.className="status-action-btn",this.statusActionBtn.hidden=!0,this.statusEl.append(this.statusTextEl,this.statusActionBtn),o.appendChild(this.statusEl),t.appendChild(o)}btn(t,e){const n=document.createElement("button");return n.className="control-btn",n.textContent=t,n.title=e,n.setAttribute("aria-label",e),n}iconBtn(t,e){const n=document.createElement("button");return n.className="control-btn",n.innerHTML=V[t]??"",n.title=e,n.setAttribute("aria-label",e),n}setZoom(t){this.zoomLabel.textContent=Math.round(t*100)+"%"}setTitle(t){this.titleInput.value=t,this.resizeTitleInput()}setStatus(t,e,n){this.statusEl.hidden=!t,this.statusTextEl.textContent=t,this.statusEl.dataset.state=e,this.statusActionBtn.hidden=!n,this.statusActionBtn.textContent=(n==null?void 0:n.label)??"",this.statusActionBtn.onclick=(n==null?void 0:n.onClick)??null}resizeTitleInput(){if(!this.titleMeasure||!this.titleInput)return;this.titleMeasure.textContent=this.titleInput.value||"Untitled Board";const t=Math.ceil(this.titleMeasure.getBoundingClientRect().width+22),e=Math.max(180,window.innerWidth-460);this.titleInput.style.width=Math.min(Math.max(90,t),e)+"px"}}class fo{constructor(t,e){u(this,"state");u(this,"commands");u(this,"textareas",[]);u(this,"editingId",null);this.state=t,this.commands=e}get isEditing(){return this.editingId!==null}open(t){if(this.close(),this.editingId=t.id,t.data.labelPosition==="sides"){this.openSideEditors(t);return}const e=document.createElement("textarea");e.className="text-editor",e.value=t.data.text??"",t.data.labelPosition==="sides"&&(e.placeholder="left label | right label"),this.position(e,t),document.body.appendChild(e),this.textareas=[e],e.focus(),e.select();const n=t.data.text??"";t.data.text="",t.updatedAt=Date.now(),X(t.id),this.state.requestRender();const s=()=>{const o=e.value;if(t.data.text=o,It(t),t.updatedAt=Date.now(),X(t.id),o!==n){const a=t.id,r=this.state;this.commands.push("edit-text",()=>{const c=r.elementsById.get(a);c&&(c.data.text=o,It(c),c.updatedAt=Date.now(),X(a),r.emitChange())},()=>{const c=r.elementsById.get(a);c&&(c.data.text=n,It(c),c.updatedAt=Date.now(),X(a),r.emitChange())})}this.state.emitChange(),this.close()};e.addEventListener("blur",s),e.addEventListener("keydown",o=>{o.stopPropagation(),o.key==="Escape"?(t.data.text=n,X(t.id),this.close(),this.state.requestRender()):o.key==="Enter"&&(o.metaKey||o.ctrlKey)&&e.blur()})}openSideEditors(t){const e=String(t.data.text??""),[n="",s=""]=e.split("|",2).map(d=>d.trim()),o=this.makeSideEditor("Left label",n),a=this.makeSideEditor("Right label",s);this.positionSideEditors(o,a,t),document.body.append(o,a),this.textareas=[o,a],o.focus(),o.select(),t.data.text="",t.updatedAt=Date.now(),X(t.id),this.state.requestRender();let r=!1;const c=()=>{if(r)return;r=!0;const d=`${o.value.trim()} | ${a.value.trim()}`;t.data.text=d,t.updatedAt=Date.now(),X(t.id),d!==e&&this.pushTextCommand(t.id,e,d),this.state.emitChange(),this.close()},l=()=>{r||(r=!0,t.data.text=e,X(t.id),this.close(),this.state.requestRender())};for(const d of[o,a])d.addEventListener("keydown",h=>{h.stopPropagation(),h.key==="Escape"?l():h.key==="Enter"&&(h.metaKey||h.ctrlKey)&&c()}),d.addEventListener("blur",()=>{window.setTimeout(()=>{this.textareas.includes(document.activeElement)||c()},0)})}makeSideEditor(t,e){const n=document.createElement("textarea");return n.className="text-editor text-editor-side",n.placeholder=t,n.value=e,n.style.fontFamily='-apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif',n.style.fontWeight="600",n.style.textAlign="center",n.style.lineHeight="1.35",n.style.color=this.state.theme==="dark"?"#f2f2f2":"#1f2933",n}positionSideEditors(t,e,n){const s=this.state.viewport,o=Rt(n.x,n.y,s),a=Rt(n.x+n.width,n.y+n.height,s),r=13*s.scale,c=Math.max(82,Math.min(150,Math.hypot(a.x-o.x,a.y-o.y)*.34)),l=Math.max(24,r*1.35+4);for(const[d,h]of[[t,.24],[e,.76]])d.style.left=o.x+(a.x-o.x)*h-c/2+"px",d.style.top=o.y+(a.y-o.y)*h-l/2+"px",d.style.width=c+"px",d.style.height=l+"px",d.style.fontSize=r+"px"}pushTextCommand(t,e,n){const s=this.state;this.commands.push("edit-text",()=>{const o=s.elementsById.get(t);o&&(o.data.text=n,It(o),o.updatedAt=Date.now(),X(t),s.emitChange())},()=>{const o=s.elementsById.get(t);o&&(o.data.text=e,It(o),o.updatedAt=Date.now(),X(t),s.emitChange())})}position(t,e){const n=this.state.viewport;if(e.type==="arrow"||e.type==="line"||e.type==="connector"){const b=Rt(e.x,e.y,n),x=Rt(e.x+e.width,e.y+e.height,n),v=13*n.scale,S=Math.max(100,Math.min(240,Math.hypot(x.x-b.x,x.y-b.y)-16)),w=Math.max(24,v*1.35+4);t.style.left=(b.x+x.x)/2-S/2+"px",t.style.top=(b.y+x.y)/2-w/2+"px",t.style.width=S+"px",t.style.height=w+"px",t.style.fontSize=v+"px",t.style.lineHeight="1.35",t.style.fontFamily='-apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif',t.style.fontWeight="600",t.style.color=this.state.theme==="dark"?"#f2f2f2":"#1f2933",t.style.textAlign="center";return}const s=Rt(e.x,e.y,n),o=e.data.shapeKind==="chevron",a=Te(e)*n.scale,r=o?Math.min(Math.abs(e.width)*.18,Math.abs(e.height)*.55)+8:10,c=(e.type==="sticky"?14:e.type==="task"?50:e.type==="text"?0:r)*n.scale,l=e.type!=="text"&&e.type!=="task",d=o?e.height*n.scale:e.height*n.scale-(e.type==="sticky"?28:l?r*2:0)*n.scale,h=Math.max(1,String(e.data.text??"").split(/\r?\n/).length),p=Math.max(24,a*(o?1.18:1.35)*h+4),m=l?Math.min(Math.max(24,d),p):Math.max(24,d),g=l?Math.max(0,(e.height*n.scale-m)/2):e.type==="sticky"?14*n.scale:0,y=(e.type==="task"?16:e.type==="sticky"?14:e.type==="text"?0:r)*n.scale;t.style.left=s.x+c+"px",t.style.top=s.y+g+"px",t.style.width=Math.max(40,e.width*n.scale-c-y)+"px",t.style.height=m+"px",t.style.fontSize=a+"px",t.style.lineHeight=o?"1.18":"1.35",t.style.fontFamily=e.style.fontFamily??'-apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif',t.style.fontWeight=o?"750":e.style.fontWeight??"400",t.style.color=e.style.textColor??(this.state.theme==="dark"?"#f2f2f2":"#1f2933"),t.style.textAlign=e.type==="text"||e.type==="task"?"left":"center"}close(){if(this.textareas.length){const t=this.textareas;this.textareas=[],this.editingId=null;for(const e of t)e.remove()}}}function _(i,t){const e=document.createElement("div");e.className="modal-backdrop";const n=document.createElement("div");n.className="modal",n.setAttribute("role","dialog"),n.setAttribute("aria-label",i);const s=document.createElement("button");s.className="modal-close",s.textContent="✕",s.setAttribute("aria-label","Close");const o=document.createElement("h2");o.textContent=i;const a=document.createElement("div"),r=()=>e.remove();s.addEventListener("click",r),e.addEventListener("click",c=>{c.target===e&&r()}),e.addEventListener("keydown",c=>{c.stopPropagation(),c.key==="Escape"&&r()}),n.appendChild(s),n.appendChild(o),n.appendChild(a),e.appendChild(n),document.body.appendChild(e),t(a,r),s.focus()}let lt=null,ze=null;function C(i){lt||(lt=document.createElement("div"),lt.className="toast",document.body.appendChild(lt)),lt.textContent=i,lt.classList.add("visible"),ze!==null&&clearTimeout(ze),ze=window.setTimeout(()=>{lt==null||lt.classList.remove("visible")},2600)}function gt(i){return i==="dark"?{card:"#1e2126",cardStroke:"#3a3f46",heading:"#f2f2f2",text:"#c8cdd4",accent:"#4dabf7",sticky:"#fef08a",zone:"#22262c"}:{card:"#ffffff",cardStroke:"#d8dade",heading:"#1f2933",text:"#4b5563",accent:"#6e6e6e",sticky:"#fef08a",zone:"#f0f0ed"}}let Yt=0;function yt(i){Yt=i}function N(i,t,e,n,s,o=""){return H("rectangle",{x:i,y:t,width:e,height:n,zIndex:++Yt,style:{borderRadius:10,...s},data:{text:o}})}function I(i,t,e,n,s,o,a="600"){return H("text",{x:i,y:t,width:e,height:s*1.6,zIndex:++Yt,style:{fontSize:s,textColor:o,fontWeight:a},data:{text:n}})}function W(i,t,e,n,s=180,o=120){return H("sticky",{x:i,y:t,width:s,height:o,zIndex:++Yt,style:{fill:n,borderRadius:12,shadow:!0,fontSize:13,textColor:"#1f2933"},data:{text:e}})}function z(i,t,e,n,s,o={}){return H("arrow",{x:i,y:t,width:e-i,height:n-t,zIndex:++Yt,style:{stroke:s,strokeWidth:2,arrowEnd:!0,arrowStart:o.arrowStart,strokeDash:o.dashed?[8,6]:void 0},data:{text:o.label??"",labelPosition:o.sides?"sides":"center"}})}function go(i,t,e,n,s,o=""){return H("ellipse",{x:i,y:t,width:e,height:n,zIndex:++Yt,style:s,data:{text:o}})}function yo(i,t,e,n){const s=gt(e);yt(n);const o=[];return o.push(N(i,t,760,560,{fill:s.card,stroke:s.cardStroke,strokeWidth:1.5,borderRadius:16,shadow:!0})),o.push(I(i+28,t+22,400,"User Persona",22,s.heading,"700")),o.push(I(i+28,t+60,300,"Name",13,s.accent)),o.push(W(i+28,t+86,"Jordan Lee",s.sticky,200,64)),o.push(I(i+260,t+60,300,"Role",13,s.accent)),o.push(W(i+260,t+86,"Senior Product Manager","#a5b4fc",220,64)),o.push(I(i+510,t+60,300,"Buying trigger",13,s.accent)),o.push(W(i+510,t+86,"Team scaling pains","#fdba74",220,64)),[["Goals","Ship the right features faster","#86efac"],["Pain points","Scattered docs, unclear priorities","#fca5a5"],["Jobs to be done","Align team on what to build next","#93c5fd"],["Current workaround","Spreadsheets + slide decks","#d8b4fe"],["Success criteria","Stakeholders aligned in 1 meeting","#f9a8d4"],["Key quote",'"I need clarity, not more tools."',"#fef08a"]].forEach(([r,c,l],d)=>{const h=d%3,p=Math.floor(d/3),m=i+28+h*242,g=t+188+p*178;o.push(I(m,g,230,r,13,s.accent)),o.push(W(m,g+26,c,l,220,124))}),o}const He=["Awareness","Discovery","Evaluation","Onboarding","Activation","Retention"],bo=["#93c5fd","#a5b4fc","#d8b4fe","#f9a8d4","#fdba74","#86efac"];function vo(i,t,e,n){const s=gt(e);yt(n);const o=[],a=230,r=He.length*a+56;return o.push(N(i,t,r,640,{fill:s.card,stroke:s.cardStroke,strokeWidth:1.5,borderRadius:16,shadow:!0})),o.push(I(i+28,t+22,500,"User Journey Map",22,s.heading,"700")),He.forEach((c,l)=>{const d=i+28+l*a,h=t+70;o.push(N(d,h,a-16,48,{fill:bo[l],borderRadius:10},c)),l<He.length-1&&o.push(z(d+a-14,h+24,d+a-2,h+24,s.heading)),o.push(N(d,h+64,a-16,150,{fill:s.zone,borderRadius:10},"")),o.push(I(d+10,h+70,a-36,"Actions",12,s.accent)),o.push(W(d+14,h+96,"","#fef08a",a-44,100)),o.push(N(d,h+226,a-16,150,{fill:s.zone,borderRadius:10},"")),o.push(I(d+10,h+232,a-36,"Pain points",12,s.accent)),o.push(W(d+14,h+258,"","#fca5a5",a-44,100)),o.push(N(d,h+388,a-16,150,{fill:s.zone,borderRadius:10},"")),o.push(I(d+10,h+394,a-36,"Opportunities",12,s.accent)),o.push(W(d+14,h+420,"","#86efac",a-44,100))}),o}function wo(i,t,e,n){const s=gt(e);yt(n);const o=[],a=680;o.push(N(i,t,a+120,a+130,{fill:s.card,stroke:s.cardStroke,strokeWidth:1.5,borderRadius:16,shadow:!0})),o.push(I(i+28,t+22,500,"Feature Prioritization Matrix",22,s.heading,"700"));const r=i+80,c=t+80,l=a/2;return o.push(N(r,c,l,l,{fill:"#86efac55",borderRadius:8})),o.push(N(r+l,c,l,l,{fill:"#93c5fd55",borderRadius:8})),o.push(N(r,c+l,l,l,{fill:"#fef08a55",borderRadius:8})),o.push(N(r+l,c+l,l,l,{fill:"#fca5a555",borderRadius:8})),o.push(I(r+16,c+12,300,"Quick wins",16,s.heading,"700")),o.push(I(r+l+16,c+12,300,"Strategic bets",16,s.heading,"700")),o.push(I(r+16,c+l+12,300,"Fill-ins",16,s.heading,"700")),o.push(I(r+l+16,c+l+12,300,"Avoid",16,s.heading,"700")),o.push(z(r-24,c+a,r-24,c,s.heading)),o.push(I(r-64,c+l-12,60,"Impact",14,s.text,"600")),o.push(z(r,c+a+24,r+a,c+a+24,s.heading)),o.push(I(r+l-30,c+a+34,80,"Effort",14,s.text,"600")),o.push(W(r+40,c+60,"Feature idea","#fef08a",150,90)),o.push(W(r+l+40,c+60,"Big bet","#a5b4fc",150,90)),o}const bn=[["Problem","#fca5a5"],["User","#93c5fd"],["Context","#d8b4fe"],["Current workflow","#fdba74"],["Proposed solution","#86efac"],["Edge cases","#f9a8d4"],["Acceptance criteria","#a5b4fc"],["Dependencies","#fef08a"],["Risks","#fca5a5"]];function xo(i,t,e,n){const s=gt(e);yt(n);const o=[],a=3,r=280,c=210,l=a*r+56,h=Math.ceil(bn.length/a)*c+100;return o.push(N(i,t,l,h,{fill:s.card,stroke:s.cardStroke,strokeWidth:1.5,borderRadius:16,shadow:!0})),o.push(I(i+28,t+22,500,"Product Requirements Flow",22,s.heading,"700")),bn.forEach(([p,m],g)=>{const y=g%a,b=Math.floor(g/a),x=i+28+y*r,v=t+72+b*c;o.push(I(x,v,r-30,`${g+1}. ${p}`,14,s.accent)),o.push(W(x,v+30,"",m,r-28,c-60))}),o}function Co(i,t,e,n){const s=gt(e);yt(n);const o=[];o.push(I(i,t-40,400,"System Diagram",22,s.heading,"700"));const a=(r,c,l,d,h,p)=>N(r,c,l,d,{fill:h,stroke:s.cardStroke,strokeWidth:1.5,borderRadius:12,shadow:!0,fontSize:15,fontWeight:"600",textColor:"#1f2933"},p);return o.push(go(i,t+130,110,110,{fill:"#f9a8d4",stroke:s.cardStroke,strokeWidth:1.5,fontSize:14,fontWeight:"600",textColor:"#1f2933"},"User")),o.push(a(i+200,t+140,180,90,"#93c5fd","Frontend")),o.push(a(i+470,t+140,180,90,"#a5b4fc","API / Server")),o.push(a(i+740,t+60,180,90,"#86efac","Database")),o.push(a(i+740,t+200,180,90,"#fdba74","External Service")),o.push(a(i+470,t+330,180,90,"#fef08a","Notification Service")),o.push(z(i+115,t+185,i+195,t+185,s.heading,{label:"uses"})),o.push(z(i+385,t+185,i+465,t+185,s.heading,{label:"request | response",sides:!0,arrowStart:!0})),o.push(z(i+655,t+165,i+735,t+110,s.heading,{label:"read"})),o.push(z(i+655,t+205,i+735,t+240,s.heading,{label:"webhook",dashed:!0})),o.push(z(i+560,t+235,i+560,t+325,s.heading,{label:"event",dashed:!0})),o.push(z(i+470,t+375,i+80,t+245,s.heading,{label:"notify",dashed:!0})),o}function ko(i,t,e,n){const s=gt(e);yt(n);const o=[];o.push(I(i+280,t-40,500,"Opportunity Solution Tree",22,s.heading,"700")),o.push(N(i+300,t,280,80,{fill:"#a5b4fc",borderRadius:12,shadow:!0,fontSize:15,fontWeight:"600",textColor:"#1f2933"},"Desired outcome"));const a=t+160,r=[i,i+300,i+600];for(const d of r)o.push(W(d,a,"Opportunity","#93c5fd",220,100)),o.push(z(i+440,t+85,d+110,a-5,s.heading));const c=a+180;for(const d of r)o.push(W(d,c,"Solution","#86efac",220,100)),o.push(z(d+110,a+105,d+110,c-5,s.heading));const l=c+180;for(const d of r)o.push(W(d,l,"Experiment","#fdba74",220,90)),o.push(z(d+110,c+105,d+110,l-5,s.heading));return o.push(I(i,l+120,400,"Signals / metrics",14,s.accent)),o.push(W(i,l+150,"What signal tells us this is working?","#fef08a",380,100)),o}function Eo(i,t,e,n){const s=gt(e);yt(n);const o=[];o.push(N(i,t,1060,620,{fill:s.card,stroke:s.cardStroke,strokeWidth:1.5,borderRadius:16,shadow:!0})),o.push(I(i+28,t+22,500,"Screenshot Review",22,s.heading,"700")),o.push(I(i+28,t+64,300,"Screenshot",13,s.accent));const a=H("frame",{x:i+28,y:t+92,width:480,height:360,zIndex:n+100,style:{fill:s.zone,stroke:s.cardStroke,strokeWidth:1.5,borderRadius:12,fontSize:13,textColor:s.text},data:{text:"Paste a screenshot here (Cmd/Ctrl+V)"}});return o.push(a),[["Observations","#93c5fd"],["Problems","#fca5a5"],["UX notes","#d8b4fe"],["Requirements","#86efac"]].forEach(([c,l],d)=>{const h=d%2,p=Math.floor(d/2),m=i+540+h*250,g=t+64+p*200;o.push(I(m,g,230,c,13,s.accent)),o.push(W(m,g+28,"",l,230,140))}),o.push(I(i+28,t+470,300,"Follow-up tasks",13,s.accent)),o.push(W(i+28,t+498,"","#fef08a",480,96)),o.push(I(i+540,t+470,300,"Decision",13,s.accent)),o.push(W(i+540,t+498,"","#fdba74",480,96)),o}function So(i,t,e,n){const s=gt(e);yt(n);const o=[];o.push(I(i,t,880,"Workflow map",26,s.heading,"700"));const a=[["Request","#dbeafe"],["Review","#fef3c7"],["Deliver","#dcfce7"]];for(let r=0;r<a.length;r++){const c=i+r*280;o.push(N(c,t+130,180,96,{fill:a[r][1],stroke:s.cardStroke,strokeWidth:1.5,borderRadius:12,fontSize:16,fontWeight:"650",textColor:"#1f2933",shadow:!0},a[r][0]))}return o.push(z(i+180,t+178,i+280,t+178,s.accent,{label:"approve"})),o.push(z(i+460,t+178,i+560,t+178,s.accent,{label:"ship"})),o.push(z(i+650,t+226,i+370,t+310,"#9ca3af",{label:"feedback",dashed:!0})),o.push(N(i+280,t+300,180,72,{fill:s.zone,stroke:s.cardStroke,strokeWidth:1.5,borderRadius:10,fontSize:14,textColor:s.text},"Learn and iterate")),o}function To(i,t,e,n){const s=gt(e);yt(n);const o=[];return o.push(I(i,t,800,"Handoff map",26,s.heading,"700")),[["Explore","#dbeafe"],["Decide","#fef3c7"],["Act","#dcfce7"]].forEach(([r,c],l)=>{o.push(N(i+l*270,t+150,170,92,{fill:c,stroke:s.cardStroke,strokeWidth:1.5,borderRadius:12,shadow:!0,fontSize:16,fontWeight:"650",textColor:"#1f2933"},r))}),o.push(z(i+170,t+196,i+270,t+196,s.accent,{label:"proposal"})),o.push(z(i+440,t+196,i+540,t+196,s.accent,{label:"owner | outcome",sides:!0,arrowStart:!0})),o.push(z(i+625,t+245,i+355,t+330,"#9ca3af",{label:"feedback",dashed:!0})),o.push(N(i+265,t+320,180,70,{fill:s.zone,stroke:s.cardStroke,strokeWidth:1.5,borderRadius:10,fontSize:14,textColor:s.text},"Review signal")),o}const Bo=[{id:"persona",name:"User Persona Card",description:"Name, role, goals, pain points, JTBD, success criteria.",build:yo},{id:"journey",name:"User Journey Map",description:"Awareness → Retention stages with sticky note areas.",build:vo},{id:"matrix",name:"Prioritization Matrix",description:"Impact vs effort: quick wins, strategic bets, fill-ins, avoid.",build:wo},{id:"requirements",name:"Requirements Flow",description:"Problem, user, context, solution, edge cases, risks.",build:xo},{id:"system",name:"System Diagram Starter",description:"User, frontend, API, database, external services + arrows.",build:Co},{id:"ost",name:"Opportunity Solution Tree",description:"Outcome, opportunities, solutions, experiments, signals.",build:ko},{id:"screenshot-review",name:"Screenshot Review Board",description:"Screenshot zone with observations, problems, UX notes.",build:Eo},{id:"workflow",name:"Workflow Map",description:"Labeled handoffs, a dashed feedback loop, and editable steps.",build:So},{id:"handoff",name:"Handoff Map",description:"A shared decision flow with ownership, outcomes, and feedback.",build:To}];function Mo(i,t){_("Insert a template",(e,n)=>{const s=document.createElement("div");s.className="template-grid";for(const o of Bo){const a=document.createElement("button");a.className="template-card";const r=document.createElement("span");r.className="t-name",r.textContent=o.name;const c=document.createElement("span");c.className="t-desc",c.textContent=o.description,a.appendChild(r),a.appendChild(c),a.addEventListener("click",()=>{Io(i,t,o.build),n()}),s.appendChild(a)}e.appendChild(s)})}function Io(i,t,e){const n=L(window.innerWidth/2,window.innerHeight/2,i.viewport),s=e(n.x-380,n.y-280,i.theme,i.maxZIndex());t.execute("insert-template",()=>{for(const o of s)i.elementsById.has(o.id)||i.addElement(o);i.emitChange()},()=>{for(const o of s)i.removeElement(o.id);i.emitChange()}),i.clearSelection();for(const o of s)i.selectedIds.add(o.id);i.requestRender()}function ue(i){return i<1024?i+" B":i<1024*1024?(i/1024).toFixed(1)+" KB":(i/(1024*1024)).toFixed(1)+" MB"}function Ro(i,t,e,n){_(n?"Storage":"Local storage",async(s,o)=>{const a=document.createElement("div");s.appendChild(a);const r=(g,y)=>{const b=document.createElement("div");b.className="storage-row";const x=document.createElement("span");x.textContent=g;const v=document.createElement("span");v.textContent=y,b.appendChild(x),b.appendChild(v),a.appendChild(b)};r("Elements on board",String(i.elements.length));const c=JSON.stringify(i.elements);if(r("Board data size",ue(c.length)),n)r("Workspace assets","Stored on disk under docs/assets");else{const g=await it.getAllKeys();r("Image assets",String(g.length));const y=await it.totalSizeBytes();r("Image asset size",ue(y))}const l=await tt.estimateStorage();!n&&l.quota>0&&r("Browser storage",`${ue(l.usage)} of ${ue(l.quota)}`);const d=document.createElement("div");d.className="modal-actions";const h=document.createElement("button");h.className="btn",h.textContent=n?"Clean unused managed assets":"Clear unused assets",h.addEventListener("click",async()=>{if(n){const x=i.elements.map(v=>typeof v.data.src=="string"?v.data.src:"").filter(Boolean);try{const v=await n(x);C(`Removed ${v} unused managed asset${v===1?"":"s"}`),o()}catch{C("Could not clean workspace assets")}return}const g=new Set,y=await tt.getAllBoards();for(const x of y)for(const v of x.elements){const S=v.data.assetId;typeof S=="string"&&g.add(S)}const b=await it.clearUnused(g);C(`Removed ${b} unused asset${b===1?"":"s"}`),o()}),d.appendChild(h);const p=document.createElement("button");p.className="btn danger",p.textContent="Clear board",p.addEventListener("click",()=>{confirm("Remove all elements from this board?")&&(t(),o())}),d.appendChild(p);const m=document.createElement("button");m.className="btn danger",m.textContent=n?"Reset local-only data":"Reset all local data",m.addEventListener("click",()=>{confirm("Delete ALL local boards, assets and preferences? This cannot be undone.")&&(e(),o())}),d.appendChild(m),s.appendChild(d)})}class Lo{constructor(t,e,n,s,o,a){u(this,"element");u(this,"visible",!1);u(this,"state");u(this,"renderer");u(this,"hitTester");u(this,"monitor");u(this,"imageCache");u(this,"timer",null);u(this,"storageEstimate","–");this.state=e,this.renderer=n,this.hitTester=s,this.monitor=o,this.imageCache=a,this.element=document.createElement("div"),this.element.className="perf-overlay",t.appendChild(this.element)}toggle(){this.visible=!this.visible,this.element.classList.toggle("visible",this.visible),this.visible?(this.monitor.start(),this.update(),this.timer=window.setInterval(()=>this.update(),500),this.refreshStorage()):this.timer!==null&&(clearInterval(this.timer),this.timer=null)}async refreshStorage(){const t=await it.totalSizeBytes();this.storageEstimate=(t/(1024*1024)).toFixed(1)+"MB"}update(){const t=this.state.viewport,e=[`FPS: ${this.monitor.fps}`,`Total elements: ${this.state.elements.length.toLocaleString()}`,`Visible elements: ${this.renderer.visibleCount.toLocaleString()}`,`Render time: ${this.renderer.lastRenderMs.toFixed(1)}ms`,`Hit-test time: ${this.hitTester.lastHitTestMs.toFixed(2)}ms`,`Save time: ${tt.lastSaveMs.toFixed(0)}ms`,`Image cache: ${this.imageCache.size}`,`Estimated storage: ${this.storageEstimate}`,`Zoom: ${Math.round(t.scale*100)}%`,`Viewport: x: ${Math.round(-t.offsetX/t.scale)}, y: ${Math.round(-t.offsetY/t.scale)}`,`Culling: ${this.renderer.cullingEnabled?"on":"off"} LOD: ${this.renderer.lodEnabled?"on":"off"}`];this.element.textContent=e.join(`
|
|
13
|
-
`)}}const me=["#93c5fd","#a5b4fc","#86efac","#fdba74","#fca5a5","#d8b4fe","#f9a8d4","#fef08a","#ffffff","#e5e7eb"],vn=["Onboarding","Checkout","Retention","Activation","Churn risk","API gateway","User insight","Edge case","Quick win","Tech debt","Experiment","Metric","Persona","Journey","Feature flag"];function Q(i,t){return i+Math.random()*(t-i)}function dt(i){return i[Math.floor(Math.random()*i.length)]}const ht="stress";class $o{constructor(t){u(this,"state");u(this,"lastGenerateMs",0);this.state=t}generate(t){const e=performance.now(),n=Math.sqrt(t)*280,s=["sticky","rectangle","ellipse","text","arrow"];let o=this.state.maxZIndex();const a=[];for(let r=0;r<t;r++){const c=dt(s),l=Q(-n/2,n/2),d=Q(-n/2,n/2);let h;c==="sticky"?h=H("sticky",{x:l,y:d,width:220,height:160,zIndex:++o,style:{fill:dt(Ce),borderRadius:12,shadow:!0,fontSize:14,textColor:"#1f2933"},data:{text:dt(vn),[ht]:!0}}):c==="rectangle"||c==="ellipse"?h=H(c,{x:l,y:d,width:Q(80,300),height:Q(60,200),zIndex:++o,style:{fill:dt(me),stroke:"#37415188",strokeWidth:1.5,borderRadius:c==="rectangle"?8:0},data:{[ht]:!0}}):c==="text"?h=H("text",{x:l,y:d,width:200,height:28,zIndex:++o,style:{fontSize:16,textColor:this.state.theme==="dark"?"#f2f2f2":"#1f2933"},data:{text:dt(vn),[ht]:!0}}):h=H("arrow",{x:l,y:d,width:Q(-250,250),height:Q(-250,250),zIndex:++o,style:{stroke:dt(me),strokeWidth:2,arrowEnd:!0},data:{[ht]:!0}}),a.push(h)}for(const r of a)this.state.addElement(r);this.lastGenerateMs=performance.now()-e,this.state.emitChange()}generateImagePlaceholders(t){const e=Math.sqrt(t)*420;let n=this.state.maxZIndex();for(let s=0;s<t;s++){const o=H("image",{x:Q(-e/2,e/2),y:Q(-e/2,e/2),width:320,height:220,zIndex:++n,data:{assetId:"stress-placeholder-"+s,[ht]:!0}});this.state.addElement(o)}this.state.emitChange()}generateMixedPmBoard(){this.generate(300)}randomizePositions(){const t=Math.sqrt(this.state.elements.length)*280;for(const e of this.state.elements)e.data[ht]&&(e.x=Q(-t/2,t/2),e.y=Q(-t/2,t/2));this.state.emitChange()}randomizeColors(){for(const t of this.state.elements)t.data[ht]&&(t.type==="sticky"?t.style.fill=dt(Ce):t.type==="rectangle"||t.type==="ellipse"?t.style.fill=dt(me):t.type==="arrow"&&(t.style.stroke=dt(me)));this.state.emitChange()}randomizeZIndex(){for(const t of this.state.elements)t.data[ht]&&(t.zIndex=Math.floor(Q(0,this.state.elements.length)));this.state.invalidateSort(),this.state.emitChange()}clearGenerated(){const t=this.state.elements.filter(e=>e.data[ht]);for(const e of t)this.state.removeElement(e.id);this.state.emitChange()}}class Po{constructor(t,e,n){u(this,"element");u(this,"visible",!1);this.element=document.createElement("div"),this.element.className="stress-panel";const s=(a,r,c=!1)=>{const l=document.createElement("button");l.className="btn"+(c?" danger":""),l.textContent=a,l.addEventListener("click",r),this.element.appendChild(l)},o=a=>()=>{e.generate(a),C(`Generated ${a.toLocaleString()} elements in ${e.lastGenerateMs.toFixed(0)}ms`)};s("+100",o(100)),s("+1,000",o(1e3)),s("+5,000",o(5e3)),s("+10,000",o(1e4)),s("+20,000",o(2e4)),s("+100 images",()=>{e.generateImagePlaceholders(100),C("Generated 100 image placeholders")}),s("Mixed PM board",()=>{e.generateMixedPmBoard(),C("Generated mixed PM board")}),s("Shuffle positions",()=>e.randomizePositions()),s("Shuffle colors",()=>e.randomizeColors()),s("Shuffle z-index",()=>e.randomizeZIndex()),s("Toggle culling",()=>{n.cullingEnabled=!n.cullingEnabled,C(`Viewport culling ${n.cullingEnabled?"enabled":"disabled"}`),n.state.requestRender()}),s("Toggle LOD",()=>{n.lodEnabled=!n.lodEnabled,C(`Simplified rendering ${n.lodEnabled?"enabled":"disabled"}`),n.state.requestRender()}),s("Clear generated",()=>{e.clearGenerated(),C("Cleared generated elements")},!0),t.appendChild(this.element)}toggle(){this.visible=!this.visible,this.element.classList.toggle("visible",this.visible)}}const Do=300,Ao=1e3,wn=[{label:"Small",shortLabel:"S",fontSize:13,fontWeight:"400"},{label:"Body",shortLabel:"Body",fontSize:16,fontWeight:"400"},{label:"H3",shortLabel:"H3",fontSize:18,fontWeight:"650"},{label:"H2",shortLabel:"H2",fontSize:24,fontWeight:"700"},{label:"H1",shortLabel:"H1",fontSize:32,fontWeight:"750"}],No=new Set(["text"]),zo=new Set(["rectangle","ellipse","frame"]),Ho=["#0078d4","#4dabf7","#6e6e6e","#ffffff","#0f0f0f","#fef08a","#93c5fd","#fca5a5"],Fo=[{label:"Black text",value:"#1f2933"},{label:"White text",value:"#ffffff"}];class jo{constructor(t,e={}){u(this,"state",new Ti);u(this,"commands",new Mi);u(this,"surface");u(this,"renderer");u(this,"scheduler");u(this,"hitTester");u(this,"imageCache");u(this,"monitor",new _i);u(this,"actions");u(this,"imageInsert");u(this,"toolController");u(this,"textEditor");u(this,"toolbar");u(this,"topControls");u(this,"perfOverlay");u(this,"stressPanel");u(this,"boardSaveTimer",null);u(this,"viewportSaveTimer",null);u(this,"saveInFlight",null);u(this,"saveQueued",!1);u(this,"suppressPersistence",!1);u(this,"options");u(this,"listenerAbort",new AbortController);u(this,"root");u(this,"revision",null);u(this,"stale",!1);u(this,"bottomToolCluster",null);u(this,"stickyColorPopover",null);u(this,"textSizePopover",null);u(this,"shapeStylePopover",null);u(this,"layerMenu",null);this.root=t,this.options=e,e.boardId&&(this.state.boardId=e.boardId);const n=this.listenerAbort.signal;this.surface=new Fi(t,3,n),this.imageCache=new es(it,()=>this.state.requestRender(),e.resolveAssetUrl),this.renderer=new ji(this.surface,this.state,this.imageCache),this.scheduler=new Wi(()=>this.renderer.render()),this.hitTester=new Ui(this.state),this.actions=new Ii(this.state,this.commands),this.textEditor=new fo(this.state,this.commands),this.imageInsert=new $i(this.state,this.commands,this.imageCache,C,e.uploadImage),this.state.onRenderNeeded(()=>{var s;this.scheduler.requestRender(),(s=this.topControls)==null||s.setZoom(this.state.viewport.scale),this.suppressPersistence||this.scheduleViewportSave(),this.updateContextualToolPanels()}),this.state.onChange(()=>{this.suppressPersistence||this.scheduleBoardSave()}),this.surface.onResize(()=>this.state.requestRender()),this.setupTools(t,n),this.setupUi(t),this.setupSelectionOverlays(t,n),this.setupDragDrop(t),new Di(this.state,this.actions,this.imageInsert,n),Ai({state:this.state,commands:this.commands,actions:this.actions,toolController:this.toolController,resetView:()=>this.resetView()},n),this.loadInitialState()}destroy(){this.boardSaveTimer!==null&&clearTimeout(this.boardSaveTimer),this.viewportSaveTimer!==null&&clearTimeout(this.viewportSaveTimer),this.listenerAbort.abort(),this.imageCache.clear()}setupTools(t,e){const n={state:this.state,renderer:this.renderer,surface:this.surface,hitTester:this.hitTester,commands:this.commands,setTool:s=>this.toolController.setTool(s),setCursor:s=>{this.surface.container.style.cursor=s},openTextEditor:s=>this.textEditor.open(s)};this.toolController=new Ki(this.surface.container,n,[new Zi,new Ji,new eo,new no,new ct("rectangle"),new ct("ellipse"),new ct("diamond"),new ct("triangle"),new ct("pill"),new ct("chevron"),new ct("parallelogram"),new ct("hexagon"),new ct("cylinder"),new so,new Gt,new Gt("dashedArrow"),new Gt("twoWayArrow"),new Gt("labeledArrow"),new Gt("sidedLabelArrow"),new io((s,o,a)=>void this.imageInsert.insertFiles(s,o,a))],e),this.toolController.onToolChange(s=>{var o;(o=this.toolbar)==null||o.setActiveTool(s)})}setupUi(t){this.toolbar=new uo(t,{setTool:n=>this.toolController.setTool(n),openTemplates:()=>Mo(this.state,this.commands),toggleTheme:()=>this.toggleTheme(),openExportMenu:()=>this.openExportMenu(),toggleStressPanel:()=>this.stressPanel.toggle(),copyEmbed:this.options.onExit?()=>this.startEmbedSelection():void 0}),this.toolbar.setActiveTool("select"),this.topControls=new mo(t,{onExit:this.options.onExit?()=>this.exitToDocs():void 0,resetView:()=>this.resetView(),zoomIn:()=>{oe(this.state.viewport,window.innerWidth/2,window.innerHeight/2,this.state.viewport.scale*1.2),this.state.requestRender()},zoomOut:()=>{oe(this.state.viewport,window.innerWidth/2,window.innerHeight/2,this.state.viewport.scale/1.2),this.state.requestRender()},openStorageManager:()=>Ro(this.state,()=>this.clearBoard(),()=>void this.resetAllLocalData(),this.options.cleanupUnusedAssets),togglePerfOverlay:()=>this.perfOverlay.toggle(),deleteBoard:this.options.deleteBoard?()=>this.confirmDeleteBoard():void 0,onTitleChange:n=>{this.state.title=n,this.state.emitChange()}},this.state.title),this.perfOverlay=new Lo(t,this.state,this.renderer,this.hitTester,this.monitor,this.imageCache);const e=new $o(this.state);this.stressPanel=new Po(t,e,this.renderer)}setupSelectionOverlays(t,e){this.bottomToolCluster=document.createElement("div"),this.bottomToolCluster.className="bottom-tool-cluster",t.appendChild(this.bottomToolCluster),this.bottomToolCluster.appendChild(this.toolbar.element),this.stickyColorPopover=document.createElement("div"),this.stickyColorPopover.className="context-tool-popover sticky-color-popover",this.stickyColorPopover.setAttribute("aria-hidden","true");for(const s of Ce){const o=document.createElement("button");o.type="button",o.className="sticky-color-btn",o.title="Set sticky color",o.setAttribute("aria-label",`Set sticky color ${s}`),o.style.setProperty("--swatch",s),o.addEventListener("click",()=>this.setSelectedStickyColor(s)),this.stickyColorPopover.appendChild(o)}this.bottomToolCluster.appendChild(this.stickyColorPopover),this.textSizePopover=document.createElement("div"),this.textSizePopover.className="context-tool-popover text-size-popover",this.textSizePopover.setAttribute("aria-hidden","true");for(const s of wn){const o=document.createElement("button");o.type="button",o.className="text-size-btn",o.textContent=s.shortLabel,o.setAttribute("aria-label",`Set text size ${s.label}`),o.addEventListener("click",()=>this.setSelectedTextSize(s)),this.textSizePopover.appendChild(o)}this.bottomToolCluster.appendChild(this.textSizePopover),this.shapeStylePopover=document.createElement("div"),this.shapeStylePopover.className="context-tool-popover shape-style-popover",this.shapeStylePopover.setAttribute("aria-hidden","true");for(const s of Ho){const o=document.createElement("button");o.type="button",o.className="shape-fill-btn",o.title="Set shape color",o.setAttribute("aria-label",`Set shape color ${s}`),o.style.setProperty("--swatch",s),o.addEventListener("click",()=>this.setSelectedShapeFill(s)),this.shapeStylePopover.appendChild(o)}const n=document.createElement("div");n.className="context-tool-divider",this.shapeStylePopover.appendChild(n);for(const s of Fo){const o=document.createElement("button");o.type="button",o.className="shape-text-color-btn",o.textContent=s.value==="#ffffff"?"W":"B",o.setAttribute("aria-label",s.label),o.addEventListener("click",()=>this.setSelectedShapeTextColor(s.value)),this.shapeStylePopover.appendChild(o)}this.bottomToolCluster.appendChild(this.shapeStylePopover),this.surface.interactionLayer.addEventListener("contextmenu",s=>this.openLayerMenu(s),{signal:e,capture:!0}),document.addEventListener("pointerdown",s=>{this.layerMenu&&!this.layerMenu.contains(s.target)&&this.closeLayerMenu()},{signal:e}),document.addEventListener("keydown",s=>{s.key==="Escape"&&this.closeLayerMenu()},{signal:e})}updateContextualToolPanels(){this.updateStickyColorPopover(),this.updateTextSizePopover(),this.updateShapeStylePopover()}setContextPanelVisible(t,e){t&&(t.classList.toggle("is-visible",e),t.setAttribute("aria-hidden",String(!e)))}updateStickyColorPopover(){var o;const t=this.stickyColorPopover;if(!t)return;const e=this.state.getSelected().filter(a=>a.type==="sticky"),n=e.length>0&&!this.textEditor.isEditing;if(this.setContextPanelVisible(t,n),!n)return;const s=(o=e[0])==null?void 0:o.style.fill;for(const a of t.children){const r=a,c=r.style.getPropertyValue("--swatch")===s;r.classList.toggle("active",c),r.setAttribute("aria-pressed",String(c))}}setSelectedStickyColor(t){to(t);const e=this.state.getSelected().filter(r=>r.type==="sticky"&&!r.locked);if(e.length===0)return;const n=this.state,s=e.map(r=>({id:r.id,fill:r.style.fill,textColor:r.style.textColor,updatedAt:r.updatedAt})),o=e.map(r=>({id:r.id,fill:t,textColor:"#1f2933",updatedAt:Date.now()})),a=r=>{for(const c of r){const l=n.elementsById.get(c.id);l&&(l.style.fill=c.fill,l.style.textColor=c.textColor,l.updatedAt=c.updatedAt)}n.emitChange()};this.commands.execute("sticky-color",()=>a(o),()=>a(s))}updateTextSizePopover(){var o,a;const t=this.textSizePopover;if(!t)return;const e=this.selectedTextTargets(),n=e.length>0&&!this.textEditor.isEditing;if(this.setContextPanelVisible(t,n),!n)return;const s=((o=e[0])==null?void 0:o.style.fontSize)??(((a=e[0])==null?void 0:a.type)==="sticky"?15:16);for(const r of t.children){const c=r,l=wn.find(h=>h.shortLabel===c.textContent),d=(l==null?void 0:l.fontSize)===s;c.classList.toggle("active",d),c.setAttribute("aria-pressed",String(d))}}selectedTextTargets(){return this.state.getSelected().filter(t=>No.has(t.type)&&!t.locked)}setSelectedTextSize(t){const e=this.selectedTextTargets();if(e.length===0)return;const n=this.state,s=e.map(r=>({id:r.id,fontSize:r.style.fontSize,fontWeight:r.style.fontWeight,height:r.height,updatedAt:r.updatedAt})),o=e.map(r=>({id:r.id,fontSize:t.fontSize,fontWeight:t.fontWeight,height:r.type==="text"?Math.max(r.height,Math.ceil(t.fontSize*1.45)):r.height,updatedAt:Date.now()})),a=r=>{for(const c of r){const l=n.elementsById.get(c.id);l&&(l.style.fontSize=c.fontSize,l.style.fontWeight=c.fontWeight,l.height=c.height,l.updatedAt=c.updatedAt,X(l.id))}n.emitChange()};this.commands.execute("text-size",()=>a(o),()=>a(s))}updateShapeStylePopover(){var a,r;const t=this.shapeStylePopover;if(!t)return;const e=this.selectedShapeTargets(),n=e.length>0&&!this.textEditor.isEditing;if(this.setContextPanelVisible(t,n),!n)return;const s=(a=e[0])==null?void 0:a.style.fill,o=((r=e[0])==null?void 0:r.style.textColor)??"#1f2933";for(const c of t.children){const l=c;if(l.classList.contains("shape-fill-btn")){const d=l.style.getPropertyValue("--swatch")===s;l.classList.toggle("active",d),l.setAttribute("aria-pressed",String(d))}if(l.classList.contains("shape-text-color-btn")){const h=l.textContent==="W"?o==="#ffffff":o!=="#ffffff";l.classList.toggle("active",h),l.setAttribute("aria-pressed",String(h))}}}selectedShapeTargets(){return this.state.getSelected().filter(t=>zo.has(t.type)&&!t.locked)}setSelectedShapeFill(t){const e=this.selectedShapeTargets();if(e.length===0)return;const n=this.state,s=e.map(r=>({id:r.id,fill:r.style.fill,updatedAt:r.updatedAt})),o=e.map(r=>({id:r.id,fill:t,updatedAt:Date.now()})),a=r=>{for(const c of r){const l=n.elementsById.get(c.id);l&&(l.style.fill=c.fill,l.updatedAt=c.updatedAt)}n.emitChange()};this.commands.execute("shape-fill",()=>a(o),()=>a(s))}setSelectedShapeTextColor(t){const e=this.selectedShapeTargets();if(e.length===0)return;const n=this.state,s=e.map(r=>({id:r.id,textColor:r.style.textColor,updatedAt:r.updatedAt})),o=e.map(r=>({id:r.id,textColor:t,updatedAt:Date.now()})),a=r=>{for(const c of r){const l=n.elementsById.get(c.id);l&&(l.style.textColor=c.textColor,l.updatedAt=c.updatedAt,X(l.id))}n.emitChange()};this.commands.execute("shape-text-color",()=>a(o),()=>a(s))}openLayerMenu(t){if(t.preventDefault(),t.stopPropagation(),this.textEditor.isEditing)return;const e=L(t.clientX,t.clientY,this.state.viewport),n=this.hitTester.hitTest(e.x,e.y,this.state.viewport.scale);n&&!this.state.selectedIds.has(n.id)&&(this.state.clearSelection(),this.state.selectedIds.add(n.id),this.state.requestRender());const s=this.state.getSelected();if(s.length===0){this.closeLayerMenu();return}this.closeLayerMenu();const o=document.createElement("div");o.className="layer-menu",o.setAttribute("role","menu");const a=document.createElement("div");a.className="layer-menu-label",a.textContent=s.length===1?"Layer":`${s.length} layers`,o.appendChild(a);const r=(l,d)=>{const h=document.createElement("button");h.type="button",h.setAttribute("role","menuitem"),h.textContent=l,h.addEventListener("click",()=>{d(),this.closeLayerMenu()}),o.appendChild(h)},c=()=>{const l=document.createElement("div");l.className="layer-menu-divider",o.appendChild(l)};r("Bring forward",()=>this.actions.bringForward()),r("Send backward",()=>this.actions.sendBackward()),c(),r("Bring to front",()=>this.actions.bringToFront()),r("Send to back",()=>this.actions.sendToBack()),this.root.appendChild(o),this.layerMenu=o,this.positionLayerMenu(o,t.clientX,t.clientY)}positionLayerMenu(t,e,n){t.style.left="0px",t.style.top="0px",requestAnimationFrame(()=>{const o=t.getBoundingClientRect(),a=Math.min(Math.max(12,e),window.innerWidth-o.width-12),r=Math.min(Math.max(12,n),window.innerHeight-o.height-12);t.style.left=`${a}px`,t.style.top=`${r}px`})}closeLayerMenu(){var t;(t=this.layerMenu)==null||t.remove(),this.layerMenu=null}exitToDocs(){this.boardSaveTimer!==null&&(clearTimeout(this.boardSaveTimer),this.boardSaveTimer=null),this.saveBoard().then(t=>{var e,n;t&&((n=(e=this.options).onExit)==null||n.call(e))})}startEmbedSelection(){Ge.begin(this.root,t=>{t&&this.copyEmbedSnippet(t)})}async copyEmbedSnippet(t){const e=this.state.viewport,n=L(t.x,t.y,e),s=L(t.x+t.w,t.y+t.h,e),o=Math.round(n.x),a=Math.round(n.y),r=Math.round(s.x-n.x),c=Math.round(s.y-n.y),l=`\`\`\`board
|
|
12
|
+
`)}pasteInternal(){const t=L(this.lastPointer.x,this.lastPointer.y,this.state.viewport);let e=1/0,n=1/0,s=-1/0,o=-1/0;for(const d of this.internalClipboard)e=Math.min(e,Math.min(d.x,d.x+d.width)),n=Math.min(n,Math.min(d.y,d.y+d.height)),s=Math.max(s,Math.max(d.x,d.x+d.width)),o=Math.max(o,Math.max(d.y,d.y+d.height));const a=(e+s)/2,r=(n+o)/2;let c=this.state.maxZIndex();const l=[];for(const d of this.internalClipboard){const h=Yn(d);if(!h)continue;const p=this.actions.cloneElement(h,0);p.x=h.x+(t.x-a),p.y=h.y+(t.y-r),p.zIndex=++c,l.push(p)}if(l.length!==0){this.actions.insertElements(l,"paste"),this.state.clearSelection();for(const d of l)this.state.selectedIds.add(d.id);this.state.requestRender()}}pasteText(t){const e=L(this.lastPointer.x,this.lastPointer.y,this.state.viewport),n=H("text",{x:e.x,y:e.y,width:Math.min(420,Math.max(160,t.length*8)),height:28,zIndex:this.state.maxZIndex()+1,style:{fontSize:16,textColor:this.state.theme==="dark"?"#f2f2f2":"#1f2933"},data:{text:t.slice(0,5e3)}});It(n),this.actions.insertElements([n],"paste-text"),this.state.clearSelection(),this.state.selectedIds.add(n.id),this.state.requestRender()}}function Ai(i,t){const{state:e,commands:n,actions:s,toolController:o}=i;window.addEventListener("keydown",a=>{const r=a.target;if(r&&(r.tagName==="TEXTAREA"||r.tagName==="INPUT"||r.isContentEditable))return;const c=a.metaKey||a.ctrlKey,l=a.shiftKey?10:1;if(!c)switch(a.key){case"ArrowLeft":a.preventDefault(),s.nudgeSelection(-l,0);return;case"ArrowRight":a.preventDefault(),s.nudgeSelection(l,0);return;case"ArrowUp":a.preventDefault(),s.nudgeSelection(0,-l);return;case"ArrowDown":a.preventDefault(),s.nudgeSelection(0,l);return}if(c){switch(a.key.toLowerCase()){case"d":a.preventDefault(),s.duplicateSelection();return;case"z":a.preventDefault(),a.shiftKey?n.redo():n.undo();return;case"]":a.preventDefault(),a.shiftKey?s.bringToFront():s.bringForward();return;case"[":a.preventDefault(),a.shiftKey?s.sendToBack():s.sendBackward();return;case"=":case"+":a.preventDefault(),oe(e.viewport,window.innerWidth/2,window.innerHeight/2,e.viewport.scale*1.2),e.requestRender();return;case"-":a.preventDefault(),oe(e.viewport,window.innerWidth/2,window.innerHeight/2,e.viewport.scale/1.2),e.requestRender();return;case"0":a.preventDefault(),i.resetView();return;case"a":a.preventDefault(),e.clearSelection();for(const d of e.elements)!d.locked&&!d.hidden&&e.selectedIds.add(d.id);e.requestRender();return}return}switch(a.key){case"Delete":case"Backspace":a.preventDefault(),s.deleteSelection();return;case"Escape":o.cancel(),o.setTool("select");return}switch(a.key.toLowerCase()){case"v":o.setTool("select");return;case"h":o.setTool("hand");return;case"s":o.setTool("sticky");return;case"r":o.setTool("rectangle");return;case"o":o.setTool("ellipse");return;case"t":o.setTool(a.shiftKey?"task":"text");return;case"a":o.setTool("arrow");return;case"i":o.setTool("image");return}},{signal:t})}function Ni(i){if(i.elements.length===0)return null;let t=1/0,e=1/0,n=-1/0,s=-1/0;for(const a of i.elements)a.hidden||(t=Math.min(t,Math.min(a.x,a.x+a.width)),e=Math.min(e,Math.min(a.y,a.y+a.height)),n=Math.max(n,Math.max(a.x,a.x+a.width)),s=Math.max(s,Math.max(a.y,a.y+a.height)));if(!Number.isFinite(t))return null;const o=48;return{x:t-o,y:e-o,w:n-t+o*2,h:s-e+o*2}}function os(i,t,e,n){let o=Math.round(e.w*n),a=Math.round(e.h*n);if(o>8192||a>8192){const h=8192/Math.max(o,a);n*=h,o=Math.round(e.w*n),a=Math.round(e.h*n)}const r=document.createElement("canvas");r.width=Math.max(1,o),r.height=Math.max(1,a);const c=r.getContext("2d"),l=i.theme==="dark"?"#111315":"#f3f2f1";c.fillStyle=l,c.fillRect(0,0,r.width,r.height),c.scale(n,n),c.translate(-e.x,-e.y);const d=i.getSorted();for(const h of d)h.hidden||Math.max(h.x,h.x+h.width)<e.x||Math.min(h.x,h.x+h.width)>e.x+e.w||Math.max(h.y,h.y+h.height)<e.y||Math.min(h.y,h.y+h.height)>e.y+e.h||xe(h,{ctx:c,scale:n,lod:2,theme:i.theme,imageCache:t});return r}function as(i){return new Promise((t,e)=>{i.toBlob(n=>{n?t(n):e(new Error("PNG encode failed"))},"image/png")})}async function zi(i,t,e,n){const s=i.viewport,o={x:-s.offsetX/s.scale,y:-s.offsetY/s.scale,w:e/s.scale,h:n/s.scale},a=os(i,t,o,s.scale);return as(a)}async function Hi(i,t){const e=Ni(i);if(!e)return null;const n=os(i,t,e,1);return as(n)}function un(i,t){const e=URL.createObjectURL(i),n=document.createElement("a");n.href=e,n.download=t,n.click(),URL.revokeObjectURL(e)}class Ze{constructor(t,e){u(this,"overlay");u(this,"rectEl");u(this,"abort",new AbortController);u(this,"start",null);u(this,"onComplete");u(this,"done",!1);this.onComplete=e,this.overlay=document.createElement("div"),this.overlay.className="embed-select-overlay";const n=document.createElement("div");n.className="embed-select-hint",n.textContent="Drag to select the area to embed · Esc to cancel",this.overlay.appendChild(n),this.rectEl=document.createElement("div"),this.rectEl.className="embed-select-rect",this.rectEl.style.display="none",this.overlay.appendChild(this.rectEl),t.appendChild(this.overlay);const s=this.abort.signal;this.overlay.addEventListener("pointerdown",o=>this.onDown(o),{signal:s}),this.overlay.addEventListener("pointermove",o=>this.onMove(o),{signal:s}),this.overlay.addEventListener("pointerup",o=>this.onUp(o),{signal:s}),window.addEventListener("keydown",o=>{o.key==="Escape"&&(o.preventDefault(),this.finish(null))},{signal:s})}static begin(t,e){new Ze(t,e)}onDown(t){t.preventDefault(),this.start={x:t.clientX,y:t.clientY},this.rectEl.style.display="block",this.draw(t.clientX,t.clientY),this.overlay.setPointerCapture(t.pointerId)}onMove(t){this.start&&this.draw(t.clientX,t.clientY)}onUp(t){if(!this.start)return;const e=this.rectFrom(t.clientX,t.clientY);if(e.w<8||e.h<8){this.finish(null);return}this.finish(e)}rectFrom(t,e){const n=this.start;return{x:Math.min(n.x,t),y:Math.min(n.y,e),w:Math.abs(t-n.x),h:Math.abs(e-n.y)}}draw(t,e){const n=this.rectFrom(t,e);this.rectEl.style.left=`${n.x}px`,this.rectEl.style.top=`${n.y}px`,this.rectEl.style.width=`${n.w}px`,this.rectEl.style.height=`${n.h}px`}finish(t){this.done||(this.done=!0,this.abort.abort(),this.overlay.remove(),this.onComplete(t))}}class Fi{constructor(t,e=3,n){u(this,"container");u(this,"layers",[]);u(this,"contexts",[]);u(this,"width",0);u(this,"height",0);u(this,"dpr",1);u(this,"resizeListeners",[]);this.container=document.createElement("div"),this.container.className="canvas-stack",t.appendChild(this.container);for(let s=0;s<e;s++){const o=document.createElement("canvas"),a=o.getContext("2d",{alpha:s!==0});this.container.appendChild(o),this.layers.push(o),this.contexts.push(a)}this.resize(),window.addEventListener("resize",()=>{this.resize();for(const s of this.resizeListeners)s()},{signal:n})}get interactionLayer(){return this.layers[this.layers.length-1]}onResize(t){this.resizeListeners.push(t)}resize(){this.dpr=Math.max(1,window.devicePixelRatio||1),this.width=window.innerWidth,this.height=window.innerHeight;for(const t of this.layers)t.width=Math.round(this.width*this.dpr),t.height=Math.round(this.height*this.dpr),t.style.width=this.width+"px",t.style.height=this.height+"px"}beginLayer(t){const e=this.contexts[t];return e.setTransform(this.dpr,0,0,this.dpr,0,0),e.clearRect(0,0,this.width,this.height),e}}class ji{constructor(t,e,n){u(this,"surface");u(this,"state");u(this,"imageCache");u(this,"overlay",{marquee:null,preview:null});u(this,"lastRenderMs",0);u(this,"visibleCount",0);u(this,"cullingEnabled",!0);u(this,"lodEnabled",!0);this.surface=t,this.state=e,this.imageCache=n}getLod(){if(!this.lodEnabled)return 2;const t=this.state.viewport.scale;return t<.1?0:t<.25?1:2}render(){const t=performance.now();this.renderGrid(),this.renderObjects(),this.renderOverlay(),this.lastRenderMs=performance.now()-t}renderGrid(){const{surface:t,state:e}=this,n=t.beginLayer(0),s=e.viewport,o=getComputedStyle(document.documentElement).getPropertyValue("--bg-canvas").trim(),a=getComputedStyle(document.documentElement).getPropertyValue("--grid-dot").trim();n.fillStyle=o||"#f3f2f1",n.fillRect(0,0,t.width,t.height);let c=32*s.scale;if(!Number.isFinite(c)||c<=0)return;for(;c<16;)c*=2;for(;c>64;)c/=2;if(c<4)return;const l=(s.offsetX%c+c)%c,d=(s.offsetY%c+c)%c,h=Math.min(1.5,Math.max(.75,s.scale*.9));n.fillStyle=a||"rgba(0,0,0,0.14)",n.beginPath();for(let p=l;p<t.width;p+=c)for(let m=d;m<t.height;m+=c)n.moveTo(p+h,m),n.arc(p,m,h,0,Math.PI*2);n.fill()}renderObjects(){const{surface:t,state:e}=this,n=t.beginLayer(1),s=e.viewport;n.translate(s.offsetX,s.offsetY),n.scale(s.scale,s.scale);const o=Si(s,t.width,t.height),a=this.cullingEnabled?e.getVisibleElements(o):e.getSorted().filter(c=>!c.hidden);this.visibleCount=a.length;const r={ctx:n,scale:s.scale,lod:this.getLod(),theme:e.theme,imageCache:this.imageCache};for(const c of a)xe(c,r)}renderOverlay(){const{surface:t,state:e}=this,n=t.beginLayer(2),s=e.viewport,o=getComputedStyle(document.documentElement).getPropertyValue("--selection").trim()||"#6e6e6e";if(e.hoveredId&&!e.selectedIds.has(e.hoveredId)){const r=e.elementsById.get(e.hoveredId);if(r){const c=this.elementScreenBBox(r);n.strokeStyle=o,n.globalAlpha=.45,n.lineWidth=1.5,n.strokeRect(c.x,c.y,c.w,c.h),n.globalAlpha=1}}const a=e.getSelected();if(a.length>0){n.strokeStyle=o,n.lineWidth=1.5;let r=1/0,c=1/0,l=-1/0,d=-1/0;for(const p of a){const m=this.elementScreenBBox(p);n.strokeRect(m.x,m.y,m.w,m.h),r=Math.min(r,m.x),c=Math.min(c,m.y),l=Math.max(l,m.x+m.w),d=Math.max(d,m.y+m.h)}a.length>1&&(n.setLineDash([4,4]),n.strokeRect(r-4,c-4,l-r+8,d-c+8),n.setLineDash([]));const h=a.length===1?this.elementScreenBBox(a[0]):{x:r,y:c,w:l-r,h:d-c};this.drawHandles(n,h,o)}if(this.overlay.marquee){const r=this.overlay.marquee;n.fillStyle=o+"22",n.strokeStyle=o,n.lineWidth=1,n.fillRect(r.x,r.y,r.w,r.h),n.strokeRect(r.x,r.y,r.w,r.h)}this.overlay.preview&&(n.save(),n.translate(s.offsetX,s.offsetY),n.scale(s.scale,s.scale),n.globalAlpha=.8,xe(this.overlay.preview,{ctx:n,scale:s.scale,lod:2,theme:e.theme,imageCache:this.imageCache}),n.restore())}elementScreenBBox(t){const e=this.state.viewport,n=Math.min(t.x,t.x+t.width),s=Math.min(t.y,t.y+t.height),o=Math.max(t.x,t.x+t.width),a=Math.max(t.y,t.y+t.height),r=Rt(n,s,e),c=Rt(o,a,e);return{x:r.x,y:r.y,w:c.x-r.x,h:c.y-r.y}}drawHandles(t,e,n){const a=rs(e);t.fillStyle=getComputedStyle(document.documentElement).getPropertyValue("--bg-panel").trim()||"#fff",t.strokeStyle=n,t.lineWidth=1.5;for(const r of a)t.beginPath(),t.rect(r.x-4,r.y-4,8,8),t.fill(),t.stroke()}}function rs(i){const{x:t,y:e,w:n,h:s}=i;return[{id:"nw",x:t,y:e},{id:"n",x:t+n/2,y:e},{id:"ne",x:t+n,y:e},{id:"e",x:t+n,y:e+s/2},{id:"se",x:t+n,y:e+s},{id:"s",x:t+n/2,y:e+s},{id:"sw",x:t,y:e+s},{id:"w",x:t,y:e+s/2}]}class Wi{constructor(t){u(this,"rafId",null);u(this,"renderFn");this.renderFn=t}requestRender(){this.rafId===null&&(this.rafId=requestAnimationFrame(()=>{this.rafId=null,this.renderFn()}))}cancel(){this.rafId!==null&&(cancelAnimationFrame(this.rafId),this.rafId=null)}}function Oi(i,t,e,n,s,o){const a=s-e,r=o-n,c=a*a+r*r;if(c===0)return Math.hypot(i-e,t-n);let l=((i-e)*a+(t-n)*r)/c;return l=Math.max(0,Math.min(1,l)),Math.hypot(i-(e+l*a),t-(n+l*r))}class Ui{constructor(t){u(this,"state");u(this,"lastHitTestMs",0);this.state=t}hitTest(t,e,n){const s=performance.now(),o=this.state.getSorted(),a=6/n;let r=null;for(let c=o.length-1;c>=0;c--){const l=o[c];if(!(l.hidden||l.locked)&&this.hitsElement(l,t,e,a)){r=l;break}}return this.lastHitTestMs=performance.now()-s,r}hitsElement(t,e,n,s){if(t.type==="line"||t.type==="arrow"||t.type==="connector")return Oi(e,n,t.x,t.y,t.x+t.width,t.y+t.height)<=Math.max(s,(t.style.strokeWidth??2)/2+s);const o=Math.min(t.x,t.x+t.width),a=Math.max(t.x,t.x+t.width),r=Math.min(t.y,t.y+t.height),c=Math.max(t.y,t.y+t.height);if(e<o||e>a||n<r||n>c)return!1;if(t.type==="ellipse"){const l=(o+a)/2,d=(r+c)/2,h=(a-o)/2,p=(c-r)/2;if(h===0||p===0)return!1;const m=(e-l)/h,g=(n-d)/p;return m*m+g*g<=1}return!0}elementsInRect(t,e,n,s){const o=Math.min(t,t+n),a=Math.max(t,t+n),r=Math.min(e,e+s),c=Math.max(e,e+s),l=[];for(const d of this.state.elements){if(d.hidden||d.locked)continue;const h=Math.min(d.x,d.x+d.width),p=Math.max(d.x,d.x+d.width),m=Math.min(d.y,d.y+d.height),g=Math.max(d.y,d.y+d.height);h>=o&&p<=a&&m>=r&&g<=c&&l.push(d)}return l}}class _i{constructor(){u(this,"fps",0);u(this,"frameCount",0);u(this,"lastSample",performance.now());u(this,"running",!1)}start(){if(this.running)return;this.running=!0;const t=()=>{if(!this.running)return;this.frameCount++;const e=performance.now(),n=e-this.lastSample;n>=1e3&&(this.fps=Math.round(this.frameCount*1e3/n),this.frameCount=0,this.lastSample=e),requestAnimationFrame(t)};requestAnimationFrame(t)}stop(){this.running=!1}}const Xi=16,qi=720,mn=120,Yi=.0032;class Ki{constructor(t,e,n,s){u(this,"tools",new Map);u(this,"active");u(this,"ctx");u(this,"target");u(this,"spaceDown",!1);u(this,"tempPanning",!1);u(this,"panLast",{x:0,y:0});u(this,"toolChangeListeners",[]);u(this,"signal");this.target=t,this.ctx=e,this.signal=s;for(const o of n)this.tools.set(o.name,o);this.active=this.tools.get("select"),this.bindEvents()}get activeName(){return this.active.name}onToolChange(t){this.toolChangeListeners.push(t)}setTool(t){var n,s,o,a,r;if(this.active.name===t){(s=(n=this.active).onActivate)==null||s.call(n,this.ctx);return}(a=(o=this.active).onDeactivate)==null||a.call(o,this.ctx);const e=this.tools.get(t);if(e){this.active=e,this.ctx.setCursor(e.cursor),(r=e.onActivate)==null||r.call(e,this.ctx);for(const c of this.toolChangeListeners)c(t)}}cancel(){var t,e;(e=(t=this.active).onCancel)==null||e.call(t,this.ctx)}bindEvents(){const t=this.target;t.addEventListener("pointerdown",e=>{if(e.button===1||e.button===2||this.spaceDown){e.preventDefault(),this.tempPanning=!0,this.panLast={x:e.clientX,y:e.clientY},this.ctx.setCursor("grabbing"),t.setPointerCapture(e.pointerId);return}e.button===0&&(t.setPointerCapture(e.pointerId),this.active.onPointerDown(e,this.ctx))}),t.addEventListener("pointermove",e=>{if(this.tempPanning){const n=this.ctx.state.viewport;n.offsetX+=e.clientX-this.panLast.x,n.offsetY+=e.clientY-this.panLast.y,this.panLast={x:e.clientX,y:e.clientY},this.ctx.state.requestRender();return}this.active.onPointerMove(e,this.ctx)}),t.addEventListener("pointerup",e=>{if(this.tempPanning){this.tempPanning=!1,this.ctx.setCursor(this.spaceDown?"grab":this.active.cursor);return}this.active.onPointerUp(e,this.ctx)}),t.addEventListener("pointercancel",()=>{this.tempPanning&&(this.tempPanning=!1,this.ctx.setCursor(this.spaceDown?"grab":this.active.cursor))}),t.addEventListener("dblclick",e=>{var n,s;(s=(n=this.active).onDoubleClick)==null||s.call(n,e,this.ctx)}),t.addEventListener("wheel",e=>{e.preventDefault();const n=this.ctx.state.viewport,s=fn(e.deltaX,e.deltaMode,this.ctx.state.viewport.scale),o=fn(e.deltaY,e.deltaMode,this.ctx.state.viewport.scale);if(e.ctrlKey||e.metaKey){const a=Math.exp(-Vi(o)*Yi);oe(n,e.clientX,e.clientY,n.scale*a)}else e.shiftKey&&Math.abs(s)<Math.abs(o)?n.offsetX-=o:(n.offsetX-=s,n.offsetY-=o);this.ctx.state.requestRender()},{passive:!1}),window.addEventListener("keydown",e=>{e.code==="Space"&&!this.isEditingText(e)&&(this.spaceDown||(this.spaceDown=!0,this.tempPanning||this.ctx.setCursor("grab")),e.preventDefault())},{signal:this.signal}),window.addEventListener("keyup",e=>{e.code==="Space"&&(this.spaceDown=!1,this.tempPanning||this.ctx.setCursor(this.active.cursor))},{signal:this.signal}),t.addEventListener("contextmenu",e=>e.preventDefault())}isEditingText(t){const e=t.target;return!!e&&(e.tagName==="TEXTAREA"||e.tagName==="INPUT"||e.isContentEditable)}}function fn(i,t,e){const s=i*(t===1?Xi:t===2?qi:1),o=e<.5?.8:e>2?1.08:1;return s*o}function Vi(i){return Math.max(-mn,Math.min(mn,i))}const he=7,Gi={nw:"nwse-resize",n:"ns-resize",ne:"nesw-resize",e:"ew-resize",se:"nwse-resize",s:"ns-resize",sw:"nesw-resize",w:"ew-resize"};class Zi{constructor(){u(this,"name","select");u(this,"cursor","default");u(this,"mode","none");u(this,"startScreen",{x:0,y:0});u(this,"startWorld",{x:0,y:0});u(this,"snapshots",[]);u(this,"activeHandle",null);u(this,"endpointIsStart",!1);u(this,"moved",!1);u(this,"pointerDownHitId",null)}onPointerDown(t,e){const{state:n,hitTester:s,renderer:o}=e;this.startScreen={x:t.clientX,y:t.clientY},this.startWorld=L(t.clientX,t.clientY,n.viewport),this.moved=!1;const a=this.hitHandle(t,e);if(a){this.mode="resize",this.activeHandle=a,this.takeSnapshots(n.getSelected());return}const r=n.getSelected();if(r.length===1&&this.isLinear(r[0])){const l=this.hitEndpoint(t,r[0],e);if(l!==null){this.mode="endpoint",this.endpointIsStart=l,this.takeSnapshots(r);return}}const c=s.hitTest(this.startWorld.x,this.startWorld.y,n.viewport.scale);if(c){this.pointerDownHitId=c.id,t.shiftKey?n.selectedIds.has(c.id)?n.selectedIds.delete(c.id):n.selectedIds.add(c.id):n.selectedIds.has(c.id)||(n.clearSelection(),n.selectedIds.add(c.id)),this.mode="move",this.takeSnapshots(n.getSelected()),n.requestRender();return}t.shiftKey||n.clearSelection(),this.mode="marquee",o.overlay.marquee={x:t.clientX,y:t.clientY,w:0,h:0},n.requestRender()}onPointerMove(t,e){const{state:n,renderer:s,hitTester:o}=e;if(this.mode==="none"){const d=this.hitHandle(t,e);if(d){e.setCursor(Gi[d]);return}const h=L(t.clientX,t.clientY,n.viewport),p=o.hitTest(h.x,h.y,n.viewport.scale),m=p?p.id:null;e.setCursor(p?"move":"default"),m!==n.hoveredId&&(n.hoveredId=m,n.requestRender());return}const a=t.clientX-this.startScreen.x,r=t.clientY-this.startScreen.y;Math.abs(a)+Math.abs(r)>2&&(this.moved=!0);const c=a/n.viewport.scale,l=r/n.viewport.scale;if(this.mode==="move"){for(const d of this.snapshots){const h=n.elementsById.get(d.id);!h||h.locked||(h.x=d.x+c,h.y=d.y+l)}n.requestRender()}else if(this.mode==="marquee")s.overlay.marquee={x:this.startScreen.x,y:this.startScreen.y,w:a,h:r},n.requestRender();else if(this.mode==="resize"&&this.activeHandle)this.applyResize(c,l,t.shiftKey,e),n.requestRender();else if(this.mode==="endpoint"){const d=this.snapshots[0],h=n.elementsById.get(d.id);h&&(this.endpointIsStart?(h.x=d.x+c,h.y=d.y+l,h.width=d.width-c,h.height=d.height-l):(h.width=d.width+c,h.height=d.height+l)),n.requestRender()}}onPointerUp(t,e){const{state:n,renderer:s,hitTester:o,commands:a}=e;if(this.mode==="marquee"){const r=s.overlay.marquee;if(s.overlay.marquee=null,r&&(Math.abs(r.w)>3||Math.abs(r.h)>3)){const c=L(r.x,r.y,n.viewport),l=L(r.x+r.w,r.y+r.h,n.viewport),d=o.elementsInRect(c.x,c.y,l.x-c.x,l.y-c.y);for(const h of d)n.selectedIds.add(h.id)}n.requestRender()}else if((this.mode==="move"||this.mode==="resize"||this.mode==="endpoint")&&this.moved){const r=this.snapshots,c=r.map(d=>{const h=n.elementsById.get(d.id);return{id:d.id,x:h.x,y:h.y,width:h.width,height:h.height}}),l=d=>{for(const h of d){const p=n.elementsById.get(h.id);p&&(p.x=h.x,p.y=h.y,p.width=h.width,p.height=h.height,p.updatedAt=Date.now(),X(p.id))}n.emitChange()};for(const d of c){const h=n.elementsById.get(d.id);h&&(h.updatedAt=Date.now(),X(h.id))}a.push(this.mode,()=>l(c),()=>l(r)),n.emitChange()}else this.mode==="move"&&!this.moved&&this.toggleTaskIfCheckboxClick(t,e);this.mode="none",this.activeHandle=null,this.snapshots=[],this.pointerDownHitId=null}onDoubleClick(t,e){const{state:n,hitTester:s}=e,o=L(t.clientX,t.clientY,n.viewport),a=s.hitTest(o.x,o.y,n.viewport.scale);a&&(a.type==="sticky"||a.type==="task"||a.type==="text"||a.type==="rectangle"||a.type==="ellipse"||a.type==="frame"||a.type==="arrow"||a.type==="line"||a.type==="connector")&&e.openTextEditor(a)}onCancel(t){if(this.mode!=="none"&&this.snapshots.length>0)for(const e of this.snapshots){const n=t.state.elementsById.get(e.id);n&&(n.x=e.x,n.y=e.y,n.width=e.width,n.height=e.height)}t.renderer.overlay.marquee=null,this.mode="none",t.state.clearSelection(),t.state.requestRender()}isLinear(t){return t.type==="line"||t.type==="arrow"||t.type==="connector"}takeSnapshots(t){this.snapshots=t.map(e=>({id:e.id,x:e.x,y:e.y,width:e.width,height:e.height}))}toggleTaskIfCheckboxClick(t,e){const{state:n,hitTester:s,commands:o}=e,a=L(t.clientX,t.clientY,n.viewport),r=s.hitTest(a.x,a.y,n.viewport.scale);if(!r||r.id!==this.pointerDownHitId||r.type!=="task"||!this.hitTaskCheckbox(a.x,a.y,r))return;const c=r.data.checked===!0,l=!c,d=r.id,h=p=>{const m=n.elementsById.get(d);m&&(m.data.checked=p,m.updatedAt=Date.now(),n.emitChange())};o.execute("toggle-task",()=>h(l),()=>h(c))}hitTaskCheckbox(t,e,n){const s=Math.min(22,Math.max(16,n.height*.38)),o=n.x+16,a=n.y+n.height/2-s/2,r=8;return t>=o-r&&t<=o+s+r&&e>=a-r&&e<=a+s+r}hitHandle(t,e){const{state:n,renderer:s}=e,o=n.getSelected();if(o.length===0||o.length===1&&this.isLinear(o[0]))return null;let a;if(o.length===1)a=s.elementScreenBBox(o[0]);else{let r=1/0,c=1/0,l=-1/0,d=-1/0;for(const h of o){const p=s.elementScreenBBox(h);r=Math.min(r,p.x),c=Math.min(c,p.y),l=Math.max(l,p.x+p.w),d=Math.max(d,p.y+p.h)}a={x:r,y:c,w:l-r,h:d-c}}for(const r of rs(a))if(Math.abs(t.clientX-r.x)<=he&&Math.abs(t.clientY-r.y)<=he)return r.id;return null}hitEndpoint(t,e,n){const s=n.state.viewport,o=e.x*s.scale+s.offsetX,a=e.y*s.scale+s.offsetY,r=(e.x+e.width)*s.scale+s.offsetX,c=(e.y+e.height)*s.scale+s.offsetY;return Math.hypot(t.clientX-o,t.clientY-a)<=he+2?!0:Math.hypot(t.clientX-r,t.clientY-c)<=he+2?!1:null}applyResize(t,e,n,s){const{state:o}=s,a=this.activeHandle;let r=1/0,c=1/0,l=-1/0,d=-1/0;for(const w of this.snapshots)r=Math.min(r,Math.min(w.x,w.x+w.width)),c=Math.min(c,Math.min(w.y,w.y+w.height)),l=Math.max(l,Math.max(w.x,w.x+w.width)),d=Math.max(d,Math.max(w.y,w.y+w.height));const h=l-r,p=d-c;if(h===0||p===0)return;let m=r,g=c,y=h,b=p;if(a.includes("e")&&(y=h+t),a.includes("w")&&(m=r+t,y=h-t),a.includes("s")&&(b=p+e),a.includes("n")&&(g=c+e,b=p-e),n&&(a==="nw"||a==="ne"||a==="se"||a==="sw")){const w=h/p;if(Math.abs(y/h)>Math.abs(b/p)){const E=y/w;a.includes("n")&&(g=g+(b-E)),b=E}else{const E=b*w;a.includes("w")&&(m=m+(y-E)),y=E}}const x=4;if(Math.abs(y)<x||Math.abs(b)<x)return;const v=y/h,S=b/p;for(const w of this.snapshots){const E=o.elementsById.get(w.id);!E||E.locked||(E.x=m+(w.x-r)*v,E.y=g+(w.y-c)*S,E.width=w.width*v,E.height=w.height*S,E.updatedAt=Date.now(),X(E.id))}}}class Ji{constructor(){u(this,"name","hand");u(this,"cursor","grab");u(this,"panning",!1);u(this,"last",{x:0,y:0})}onPointerDown(t,e){this.panning=!0,this.last={x:t.clientX,y:t.clientY},e.setCursor("grabbing")}onPointerMove(t,e){if(!this.panning)return;const n=e.state.viewport;n.offsetX+=t.clientX-this.last.x,n.offsetY+=t.clientY-this.last.y,this.last={x:t.clientX,y:t.clientY},e.state.requestRender()}onPointerUp(t,e){this.panning=!1,e.setCursor("grab")}onCancel(t){this.panning=!1,t.setCursor("grab")}}const Ce=["#fef08a","#fdba74","#fca5a5","#f9a8d4","#d8b4fe","#a5b4fc","#93c5fd","#86efac"];let cs=Ce[0];function Qi(){return cs}function to(i){cs=i}class eo{constructor(){u(this,"name","sticky");u(this,"cursor","crosshair")}onPointerDown(t,e){const{state:n,commands:s}=e,o=L(t.clientX,t.clientY,n.viewport),a=H("sticky",{x:o.x-110,y:o.y-80,width:220,height:160,zIndex:n.maxZIndex()+1,style:{fill:Qi(),borderRadius:12,shadow:!0,fontSize:15,textColor:"#1f2933"},data:{text:""}});s.execute("create-sticky",()=>{n.elementsById.has(a.id)||n.addElement(a),n.emitChange()},()=>{n.removeElement(a.id),n.emitChange()}),n.clearSelection(),n.selectedIds.add(a.id),e.setTool("select"),e.openTextEditor(a)}onPointerMove(t,e){}onPointerUp(t,e){}}class no{constructor(){u(this,"name","task");u(this,"cursor","crosshair")}onPointerDown(t,e){const{state:n,commands:s}=e,o=L(t.clientX,t.clientY,n.viewport),a=n.theme==="dark",r=H("task",{x:o.x-140,y:o.y-28,width:280,height:56,zIndex:n.maxZIndex()+1,style:{fill:a?"#17191b":"#ffffff",stroke:a?"rgba(255,255,255,0.12)":"rgba(0,0,0,0.09)",strokeWidth:1,borderRadius:14,shadow:!0,fontSize:15,fontWeight:"650",textColor:a?"#f6f6f3":"#252829"},data:{text:"Task title",checked:!1}});s.execute("create-task",()=>{n.elementsById.has(r.id)||n.addElement(r),n.emitChange()},()=>{n.removeElement(r.id),n.emitChange()}),n.clearSelection(),n.selectedIds.add(r.id),e.setTool("select"),e.openTextEditor(r)}onPointerMove(t,e){}onPointerUp(t,e){}}class ct{constructor(t){u(this,"name");u(this,"cursor","crosshair");u(this,"shapeType");u(this,"shapeKind");u(this,"drawing",!1);u(this,"startWorld",{x:0,y:0});u(this,"preview",null);this.name=t,this.shapeKind=t,this.shapeType=t==="ellipse"?"ellipse":"rectangle"}onPointerDown(t,e){const{state:n}=e;this.drawing=!0,this.startWorld=L(t.clientX,t.clientY,n.viewport);const s=n.theme==="dark",o=!["rectangle","ellipse","pill","cylinder"].includes(this.shapeKind);this.preview=H(this.shapeType,{x:this.startWorld.x,y:this.startWorld.y,width:0,height:0,zIndex:n.maxZIndex()+1,style:{fill:o?"#0078d4":s?"#2a2d33":"#ffffff",stroke:o?"#495057":s?"#9ca3af":"#374151",strokeWidth:o?0:1.5,borderRadius:this.shapeKind==="pill"?999:this.shapeKind==="rectangle"?8:0,fontSize:14,textColor:o?"#ffffff":s?"#f2f2f2":"#1f2933"},data:{text:"",shapeKind:this.shapeKind}}),e.renderer.overlay.preview=this.preview}onPointerMove(t,e){if(!this.drawing||!this.preview)return;const n=L(t.clientX,t.clientY,e.state.viewport);let s=n.x-this.startWorld.x,o=n.y-this.startWorld.y;if(t.shiftKey){const a=Math.max(Math.abs(s),Math.abs(o));s=Math.sign(s||1)*a,o=Math.sign(o||1)*a}this.preview.x=Math.min(this.startWorld.x,this.startWorld.x+s),this.preview.y=Math.min(this.startWorld.y,this.startWorld.y+o),this.preview.width=Math.abs(s),this.preview.height=Math.abs(o),e.state.requestRender()}onPointerUp(t,e){const{state:n,commands:s}=e;if(!this.drawing||!this.preview)return;this.drawing=!1,e.renderer.overlay.preview=null;const o=this.preview;this.preview=null,(o.width<4||o.height<4)&&(o.width=this.shapeKind==="chevron"?210:160,o.height=this.shapeKind==="chevron"?76:100,o.x-=o.width/2,o.y-=o.height/2),s.execute("create-shape",()=>{n.elementsById.has(o.id)||n.addElement(o),n.emitChange()},()=>{n.removeElement(o.id),n.emitChange()}),n.clearSelection(),n.selectedIds.add(o.id),e.setTool("select")}onCancel(t){this.drawing=!1,this.preview=null,t.renderer.overlay.preview=null,t.state.requestRender()}}class so{constructor(){u(this,"name","text");u(this,"cursor","text")}onPointerDown(t,e){const{state:n,commands:s}=e,o=L(t.clientX,t.clientY,n.viewport),a=H("text",{x:o.x,y:o.y-12,width:240,height:28,zIndex:n.maxZIndex()+1,style:{fontSize:16,textColor:n.theme==="dark"?"#f2f2f2":"#1f2933"},data:{text:""}});It(a),s.execute("create-text",()=>{n.elementsById.has(a.id)||n.addElement(a),n.emitChange()},()=>{n.removeElement(a.id),n.emitChange()}),n.clearSelection(),n.selectedIds.add(a.id),e.setTool("select"),e.openTextEditor(a)}onPointerMove(t,e){}onPointerUp(t,e){}}class Gt{constructor(t="arrow"){u(this,"name");u(this,"cursor","crosshair");u(this,"drawing",!1);u(this,"startWorld",{x:0,y:0});u(this,"preview",null);this.name=t}onPointerDown(t,e){const{state:n}=e;this.drawing=!0,this.startWorld=L(t.clientX,t.clientY,n.viewport),this.preview=H("arrow",{x:this.startWorld.x,y:this.startWorld.y,width:0,height:0,zIndex:n.maxZIndex()+1,style:{stroke:n.theme==="dark"?"#d1d5db":"#374151",strokeWidth:2,arrowEnd:!0,arrowStart:this.name==="twoWayArrow",strokeDash:this.name==="dashedArrow"||t.altKey?[8,6]:void 0},data:{text:"",labelPosition:this.name==="sidedLabelArrow"?"sides":"center"}}),e.renderer.overlay.preview=this.preview}onPointerMove(t,e){if(!this.drawing||!this.preview)return;const n=L(t.clientX,t.clientY,e.state.viewport);let s=n.x-this.startWorld.x,o=n.y-this.startWorld.y;if(t.shiftKey){const a=Math.atan2(o,s),r=Math.round(a/(Math.PI/4))*(Math.PI/4),c=Math.hypot(s,o);s=Math.cos(r)*c,o=Math.sin(r)*c}this.preview.width=s,this.preview.height=o,e.state.requestRender()}onPointerUp(t,e){const{state:n,commands:s}=e;if(!this.drawing||!this.preview)return;this.drawing=!1,e.renderer.overlay.preview=null;const o=this.preview;if(this.preview=null,Math.hypot(o.width,o.height)<8){n.requestRender();return}s.execute("create-arrow",()=>{n.elementsById.has(o.id)||n.addElement(o),n.emitChange()},()=>{n.removeElement(o.id),n.emitChange()}),n.clearSelection(),n.selectedIds.add(o.id),e.setTool("select"),(this.name==="labeledArrow"||this.name==="sidedLabelArrow")&&e.openTextEditor(o)}onCancel(t){this.drawing=!1,this.preview=null,t.renderer.overlay.preview=null,t.state.requestRender()}}class io{constructor(t){u(this,"name","image");u(this,"cursor","default");u(this,"onInsert");this.onInsert=t}onActivate(t){const e=document.createElement("input");e.type="file",e.accept="image/png,image/jpeg,image/webp,image/gif",e.multiple=!0,e.onchange=()=>{e.files&&e.files.length>0&&this.onInsert(e.files,window.innerWidth/2,window.innerHeight/2),t.setTool("select")},e.oncancel=()=>t.setTool("select"),e.click()}onPointerDown(t,e){}onPointerMove(t,e){}onPointerUp(t,e){}}const pe="psc:";class oo{constructor(){u(this,"lastSaveMs",0)}async saveBoard(t){const e=performance.now();try{await K.put("boards",t),this.lastSaveMs=performance.now()-e,this.setPref("lastBoardId",t.id),this.setPref("recovery",JSON.stringify({id:t.id,title:t.title,updatedAt:t.updatedAt,elementCount:t.elements.length}))}catch(n){throw console.error("Board save failed",n),n}}async loadBoard(t){try{return await K.get("boards",t)}catch(e){console.error("Board load failed",e);return}}async deleteBoard(t){await K.delete("boards",t)}async clearAllBoards(){await K.clearStore("boards")}async getAllBoards(){try{return await K.getAll("boards")}catch{return[]}}setPref(t,e){try{localStorage.setItem(pe+t,e)}catch{}}getPref(t){try{return localStorage.getItem(pe+t)}catch{return null}}removePref(t){try{localStorage.removeItem(pe+t)}catch{}}clearPrefs(){try{const t=[];for(let e=0;e<localStorage.length;e++){const n=localStorage.key(e);n&&n.startsWith(pe)&&t.push(n)}for(const e of t)localStorage.removeItem(e)}catch{}}async estimateStorage(){try{if(navigator.storage&&navigator.storage.estimate){const t=await navigator.storage.estimate();return{usage:t.usage??0,quota:t.quota??0}}}catch{}return{usage:0,quota:0}}}const tt=new oo;function ao(i){return new Promise((t,e)=>{const n=new FileReader;n.onload=()=>{const s=n.result;t(s.slice(s.indexOf(",")+1))},n.onerror=()=>e(n.error),n.readAsDataURL(i)})}function ro(i,t){const e=atob(i),n=new Uint8Array(e.length);for(let s=0;s<e.length;s++)n[s]=e.charCodeAt(s);return new Blob([n],{type:t})}function gn(i,t){const e=new Blob([JSON.stringify(t)],{type:"application/json"}),n=URL.createObjectURL(e),s=document.createElement("a");s.href=n,s.download=i,s.click(),URL.revokeObjectURL(n)}function yn(i){return i.replace(/[^a-z0-9-_ ]/gi,"").trim().slice(0,60)||"board"}class co{exportBoardJson(t){gn(`${yn(t.title)}.json`,t)}async exportFullBundle(t){const e=[];for(const s of t.assetIds){const o=await it.get(s);o&&e.push({id:o.id,mimeType:o.mimeType,width:o.width,height:o.height,name:o.name,base64:await ao(o.blob)})}const n={bundleVersion:1,board:t,assets:e};gn(`${yn(t.title)}-bundle.json`,n)}async importFromFile(t){let e;try{e=JSON.parse(await t.text())}catch{return null}if(typeof e!="object"||e===null)return null;const n=e;if(n.bundleVersion===1&&Array.isArray(n.assets)){const s=we(n.board);if(!s)return null;const o=new Map;for(const a of n.assets){const r=await this.importAsset(a);r&&o.set(r.originalId,r.asset.id)}for(const a of s.elements){const r=a.data.assetId;typeof r=="string"&&o.has(r)&&(a.data.assetId=o.get(r))}return s.assetIds=[...o.values()],s}return we(e)}async importAsset(t){if(typeof t!="object"||t===null)return null;const e=t;if(typeof e.id!="string"||typeof e.base64!="string"||typeof e.mimeType!="string"||!e.mimeType.startsWith("image/"))return null;try{const n=ro(e.base64,e.mimeType),s=Date.now(),o={id:ae(),type:"image",mimeType:e.mimeType,blob:n,width:typeof e.width=="number"?e.width:0,height:typeof e.height=="number"?e.height:0,sizeBytes:n.size,createdAt:s,updatedAt:s,name:typeof e.name=="string"?e.name.slice(0,100):void 0};return await it.put(o),{originalId:e.id,asset:o}}catch{return null}}}const Ne=new co,V={select:'<svg viewBox="0 0 24 24"><path d="M4 3l7 18 2.5-7.5L21 11z"/></svg>',hand:'<svg viewBox="0 0 24 24"><path d="M18 11V6.5a1.5 1.5 0 0 0-3 0V11m0-1V4.5a1.5 1.5 0 0 0-3 0V10m0 .5v-5a1.5 1.5 0 0 0-3 0V12m9-1v1.5a1.5 1.5 0 0 1 3 0V14c0 4-2.5 7-6.5 7S8 18.5 6 15l-1.8-3.2a1.4 1.4 0 0 1 2.3-1.5L8 12V7"/></svg>',sticky:'<svg viewBox="0 0 24 24"><path d="M5 4h14a1 1 0 0 1 1 1v9l-6 6H5a1 1 0 0 1-1-1V5a1 1 0 0 1 1-1z"/><path d="M14 20v-5a1 1 0 0 1 1-1h5"/></svg>',task:'<svg viewBox="0 0 24 24"><rect x="4" y="5" width="16" height="14" rx="3"/><path d="M8 12l2.3 2.3L16 8.8"/></svg>',rectangle:'<svg viewBox="0 0 24 24"><rect x="4" y="5" width="16" height="14" rx="2"/></svg>',ellipse:'<svg viewBox="0 0 24 24"><ellipse cx="12" cy="12" rx="8.5" ry="7"/></svg>',diamond:'<svg viewBox="0 0 24 24"><path d="M12 3l8 9-8 9-8-9z"/></svg>',triangle:'<svg viewBox="0 0 24 24"><path d="M12 4l9 16H3z"/></svg>',pill:'<svg viewBox="0 0 24 24"><rect x="3.5" y="7" width="17" height="10" rx="5"/></svg>',chevron:'<svg viewBox="0 0 24 24"><path d="M4 6h12l5 6-5 6H4l5-6z"/></svg>',parallelogram:'<svg viewBox="0 0 24 24"><path d="M7 5h13l-3 14H4z"/></svg>',hexagon:'<svg viewBox="0 0 24 24"><path d="M8 4h8l5 8-5 8H8l-5-8z"/></svg>',cylinder:'<svg viewBox="0 0 24 24"><ellipse cx="12" cy="6" rx="7" ry="3"/><path d="M5 6v11c0 1.7 3.1 3 7 3s7-1.3 7-3V6"/></svg>',arrowDashed:'<svg viewBox="0 0 24 24"><path stroke-dasharray="4 3" d="M4 12h14m0 0l-5-5m5 5l-5 5"/></svg>',arrowBoth:'<svg viewBox="0 0 24 24"><path d="M4 12h16m-16 0l5-5m-5 5l5 5m11-5l-5-5m5 5l-5 5"/></svg>',arrowLabel:'<svg viewBox="0 0 24 24"><path d="M3 17L17 7m0 0h-6m6 0v6"/><rect x="7" y="9" width="10" height="6" rx="1"/></svg>',text:'<svg viewBox="0 0 24 24"><path d="M5 6V4h14v2M12 4v16m-3 0h6"/></svg>',arrow:'<svg viewBox="0 0 24 24"><path d="M5 19L19 5m0 0h-7m7 0v7"/></svg>',image:'<svg viewBox="0 0 24 24"><rect x="3" y="4" width="18" height="16" rx="2"/><circle cx="9" cy="10" r="1.6"/><path d="M21 16l-5-5-9 9"/></svg>',templates:'<svg viewBox="0 0 24 24"><rect x="3" y="3" width="8" height="8" rx="1.5"/><rect x="13" y="3" width="8" height="8" rx="1.5"/><rect x="3" y="13" width="8" height="8" rx="1.5"/><rect x="13" y="13" width="8" height="8" rx="1.5"/></svg>',shapes:'<svg viewBox="0 0 24 24"><rect x="4" y="5" width="7" height="7" rx="1.5"/><circle cx="16.5" cy="8.5" r="3.5"/><path d="M7.5 14l3.8 6H3.7z"/><path d="M15 14h4l2 3-2 3h-4l2-3z"/></svg>',sun:'<svg viewBox="0 0 24 24"><circle cx="12" cy="12" r="4"/><path d="M12 2v2m0 16v2M4.9 4.9l1.4 1.4m11.4 11.4l1.4 1.4M2 12h2m16 0h2M4.9 19.1l1.4-1.4m11.4-11.4l1.4-1.4"/></svg>',moon:'<svg viewBox="0 0 24 24"><path d="M21 12.8A9 9 0 1 1 11.2 3 7 7 0 0 0 21 12.8z"/></svg>',export:'<svg viewBox="0 0 24 24"><path d="M12 15V3m0 0L7 8m5-5l5 5M4 17v2a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2v-2"/></svg>',import:'<svg viewBox="0 0 24 24"><path d="M12 3v12m0 0l-5-5m5 5l5-5M4 17v2a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2v-2"/></svg>',gauge:'<svg viewBox="0 0 24 24"><path d="M12 14l4-4M3.3 14a9 9 0 1 1 17.4 0"/></svg>',storage:'<svg viewBox="0 0 24 24"><ellipse cx="12" cy="5.5" rx="8" ry="2.5"/><path d="M4 5.5V12c0 1.4 3.6 2.5 8 2.5s8-1.1 8-2.5V5.5M4 12v6.5C4 19.9 7.6 21 12 21s8-1.1 8-2.5V12"/></svg>',flask:'<svg viewBox="0 0 24 24"><path d="M9 3h6M10 3v6L4.5 18a2 2 0 0 0 1.8 3h11.4a2 2 0 0 0 1.8-3L14 9V3"/><path d="M7 15h10"/></svg>',reset:'<svg viewBox="0 0 24 24"><path d="M3 12a9 9 0 1 0 2.6-6.3M3 4v5h5"/></svg>',camera:'<svg viewBox="0 0 24 24"><path d="M3 8a2 2 0 0 1 2-2h2l2-2h6l2 2h2a2 2 0 0 1 2 2v10a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2z"/><circle cx="12" cy="13" r="3.5"/></svg>',trash:'<svg viewBox="0 0 24 24"><path d="M4 7h16M10 11v6m4-6v6M6 7l1 13a1 1 0 0 0 1 1h8a1 1 0 0 0 1-1l1-13M9 7V4a1 1 0 0 1 1-1h4a1 1 0 0 1 1 1v3"/></svg>',embed:'<svg viewBox="0 0 24 24"><rect x="3" y="5" width="18" height="14" rx="2" stroke-dasharray="3 3"/><path d="M9 10l-2 2 2 2m6-4l2 2-2 2"/></svg>',arrowLeft:'<svg viewBox="0 0 24 24"><path d="M19 12H5m0 0l6-6m-6 6l6 6"/></svg>',search:'<svg viewBox="0 0 24 24"><circle cx="11" cy="11" r="7"/><path d="M20 20l-4-4"/></svg>',panelLeft:'<svg viewBox="0 0 24 24"><rect x="4" y="4" width="16" height="16" rx="2"/><path d="M10 4v16"/></svg>',edit:'<svg viewBox="0 0 24 24"><path d="M12 20h9"/><path d="M16.5 3.5a2.1 2.1 0 0 1 3 3L7 19l-4 1 1-4z"/></svg>',copy:'<svg viewBox="0 0 24 24"><rect x="8" y="8" width="11" height="11" rx="2"/><path d="M5 15H4a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h8a2 2 0 0 1 2 2v1"/></svg>',folder:'<svg viewBox="0 0 24 24"><path d="M4 7a2 2 0 0 1 2-2h4l2 2h6a2 2 0 0 1 2 2v7a2 2 0 0 1-2 2H6a2 2 0 0 1-2-2z"/></svg>',folderOpen:'<svg viewBox="0 0 24 24"><path d="M4 7a2 2 0 0 1 2-2h4l2 2h6a2 2 0 0 1 2 2v1M4 8l1.5 9c.1.6.6 1 1.2 1h10.6c.6 0 1.1-.4 1.2-1L20 8z"/></svg>',file:'<svg viewBox="0 0 24 24"><path d="M13 3H6a2 2 0 0 0-2 2v14a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V10z"/><path d="M13 3v7h7"/></svg>',fileText:'<svg viewBox="0 0 24 24"><path d="M13 3H6a2 2 0 0 0-2 2v14a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V10z"/><path d="M13 3v7h7M10 13h4m-4 4h4"/></svg>',board:'<svg viewBox="0 0 24 24"><rect x="3" y="3" width="7" height="7" rx="1"/><rect x="12" y="3" width="9" height="7" rx="1"/><rect x="3" y="12" width="9" height="9" rx="1"/><rect x="14" y="12" width="7" height="9" rx="1"/></svg>',doc:'<svg viewBox="0 0 24 24"><path d="M14 3H6a2 2 0 0 0-2 2v14a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V9z"/><path d="M14 3v6h6M10 13h4m-4 4h4m-4-8h1"/></svg>',skill:'<svg viewBox="0 0 24 24"><path d="M12 2l3.1 6.3 6.9 1-5 4.9 1.2 6.8-6.2-3.3-6.2 3.3 1.2-6.8-5-4.9 6.9-1z"/></svg>',plus:'<svg viewBox="0 0 24 24"><path d="M12 5v14m-7-7h14"/></svg>',moreVertical:'<svg viewBox="0 0 24 24"><circle cx="12" cy="12" r="1"/><circle cx="12" cy="5" r="1"/><circle cx="12" cy="19" r="1"/></svg>',chevronRight:'<svg viewBox="0 0 24 24"><path d="M9 18l6-6-6-6"/></svg>',chevronDown:'<svg viewBox="0 0 24 24"><path d="M6 9l6 6 6-6"/></svg>',wiki:'<svg viewBox="0 0 24 24"><path d="M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z"/><path d="M14 2v6h6M8 13h2m-2 4h6m-6-8h1"/></svg>',list:'<svg viewBox="0 0 24 24"><line x1="8" y1="6" x2="21" y2="6"/><line x1="8" y1="12" x2="21" y2="12"/><line x1="8" y1="18" x2="21" y2="18"/><circle cx="4" cy="6" r="1"/><circle cx="4" cy="12" r="1"/><circle cx="4" cy="18" r="1"/></svg>'},lo=[{tool:"select",icon:"select",label:"Select",key:"V"},{tool:"hand",icon:"hand",label:"Hand",key:"H"},{tool:"sticky",icon:"sticky",label:"Sticky note",key:"S"},{tool:"task",icon:"task",label:"Task",key:""},{tool:"text",icon:"text",label:"Text",key:"T"},{tool:"image",icon:"image",label:"Image",key:"I"}],ls=[{tool:"rectangle",icon:"rectangle",label:"Rectangle",key:"R"},{tool:"ellipse",icon:"ellipse",label:"Ellipse",key:"O"},{tool:"diamond",icon:"diamond",label:"Diamond",key:""},{tool:"triangle",icon:"triangle",label:"Triangle",key:""},{tool:"pill",icon:"pill",label:"Pill",key:""},{tool:"chevron",icon:"chevron",label:"Chevron",key:""},{tool:"parallelogram",icon:"parallelogram",label:"Parallelogram",key:""},{tool:"hexagon",icon:"hexagon",label:"Hexagon",key:""},{tool:"cylinder",icon:"cylinder",label:"Cylinder",key:""}],ho=[{tool:"arrow",icon:"arrow",label:"Arrow (hold Shift to snap)",key:"A"},{tool:"dashedArrow",icon:"arrowDashed",label:"Dashed arrow",key:""},{tool:"twoWayArrow",icon:"arrowBoth",label:"Two-way arrow",key:""},{tool:"labeledArrow",icon:"arrowLabel",label:"Centered label arrow",key:""},{tool:"sidedLabelArrow",icon:"arrowLabel",label:"Left and right labels",key:""}],po=new Set(ls.map(i=>i.tool));class uo{constructor(t,e){u(this,"element");u(this,"toolButtons",new Map);u(this,"shapeButtons",new Map);u(this,"shapeBtn");u(this,"shapeGroup");u(this,"arrowGroup");u(this,"themeBtn");this.element=document.createElement("div"),this.element.className="toolbar";for(const a of lo){const r=this.makeButton(a.icon,a.label,a.key);r.addEventListener("click",()=>e.setTool(a.tool)),this.toolButtons.set(a.tool,r),this.element.appendChild(r),a.tool==="sticky"&&this.element.appendChild(this.makeShapePicker(e)),a.tool==="text"&&this.element.appendChild(this.makeArrowPicker(e))}this.element.appendChild(this.divider());const n=this.makeButton("templates","Templates","");n.addEventListener("click",e.openTemplates),this.element.appendChild(n),this.element.appendChild(this.divider()),this.themeBtn=this.makeButton("moon","Toggle theme",""),this.themeBtn.addEventListener("click",e.toggleTheme),this.element.appendChild(this.themeBtn);const s=this.makeButton("export","Export / Import","");s.addEventListener("click",e.openExportMenu),this.element.appendChild(s);const o=this.makeButton("flask","Stress test","");if(o.addEventListener("click",e.toggleStressPanel),this.element.appendChild(o),e.copyEmbed){this.element.appendChild(this.divider());const a=this.makeButton("embed","Copy embed of a region","");a.addEventListener("click",e.copyEmbed),this.element.appendChild(a)}t.appendChild(this.element)}makeButton(t,e,n){const s=document.createElement("button");s.className="tool-btn",s.setAttribute("aria-label",e),s.innerHTML=V[t]??"";const o=document.createElement("span");if(o.className="tooltip",o.textContent=e,n){const a=document.createElement("kbd");a.textContent=n,o.appendChild(a)}return s.appendChild(o),s}makeShapePicker(t){this.shapeGroup=document.createElement("div"),this.shapeGroup.className="shape-tool-group",this.shapeBtn=this.makeButton("shapes","Shapes",""),this.shapeBtn.classList.add("shape-tool-trigger"),this.shapeBtn.addEventListener("click",n=>{n.stopPropagation(),this.shapeGroup.classList.toggle("open")});const e=document.createElement("div");e.className="shape-tool-popover";for(const n of ls){const s=this.makeButton(n.icon,n.label,n.key);s.classList.add("shape-option-btn"),s.addEventListener("click",o=>{o.stopPropagation(),t.setTool(n.tool),this.shapeGroup.classList.remove("open")}),this.shapeButtons.set(n.tool,s),e.appendChild(s)}return this.shapeGroup.append(this.shapeBtn,e),this.shapeGroup}makeArrowPicker(t){this.arrowGroup=document.createElement("div"),this.arrowGroup.className="shape-tool-group";const e=this.makeButton("arrow","Arrow types","");e.classList.add("shape-tool-trigger"),e.addEventListener("click",s=>{s.stopPropagation(),this.arrowGroup.classList.toggle("open")});const n=document.createElement("div");n.className="shape-tool-popover";for(const s of ho){const o=this.makeButton(s.icon,s.label,s.key);o.classList.add("shape-option-btn"),o.addEventListener("click",a=>{a.stopPropagation(),t.setTool(s.tool),this.arrowGroup.classList.remove("open")}),this.toolButtons.set(s.tool,o),n.appendChild(o)}return this.arrowGroup.append(e,n),this.arrowGroup}divider(){const t=document.createElement("div");return t.className="toolbar-divider",t}setActiveTool(t){var e;for(const[n,s]of this.toolButtons)s.classList.toggle("active",n===t);for(const[n,s]of this.shapeButtons)s.classList.toggle("active",n===t);(e=this.shapeBtn)==null||e.classList.toggle("active",po.has(t))}setTheme(t){const e=this.themeBtn.querySelector(".tooltip");this.themeBtn.innerHTML=V[t==="dark"?"sun":"moon"],e&&this.themeBtn.appendChild(e)}}class mo{constructor(t,e,n){u(this,"zoomLabel");u(this,"titleInput");u(this,"titleMeasure");u(this,"statusEl");u(this,"statusTextEl");u(this,"statusActionBtn");const s=document.createElement("div");if(s.className="top-left",e.onExit){const m=document.createElement("button");m.className="control-btn back-btn",m.innerHTML=`${V.arrowLeft}<span>ViteBoard</span>`,m.title="Save and back to ViteBoard",m.setAttribute("aria-label","Back to ViteBoard"),m.addEventListener("click",e.onExit),s.appendChild(m)}this.titleInput=document.createElement("input"),this.titleInput.className="board-title",this.titleInput.value=n,this.titleInput.maxLength=120,this.titleInput.setAttribute("aria-label","Board title"),this.titleInput.addEventListener("change",()=>e.onTitleChange(this.titleInput.value.trim()||"Untitled Board")),this.titleInput.addEventListener("input",()=>this.resizeTitleInput()),this.titleInput.addEventListener("keydown",m=>{m.stopPropagation(),m.key==="Enter"&&this.titleInput.blur()}),this.titleMeasure=document.createElement("span"),this.titleMeasure.className="board-title-measure",s.appendChild(this.titleInput),s.appendChild(this.titleMeasure),t.appendChild(s),this.resizeTitleInput();const o=document.createElement("div");o.className="top-right";const a=document.createElement("div");a.className="control-group";const r=this.btn("−","Zoom out (Ctrl/Cmd + wheel or Ctrl/Cmd + -)");r.addEventListener("click",e.zoomOut),a.appendChild(r),this.zoomLabel=this.btn("100%","Reset zoom to 100% (Ctrl/Cmd + 0)"),this.zoomLabel.classList.add("zoom-label"),this.zoomLabel.addEventListener("click",e.resetView),a.appendChild(this.zoomLabel);const c=this.btn("+","Zoom in (Ctrl/Cmd + wheel or Ctrl/Cmd + +)");c.addEventListener("click",e.zoomIn),a.appendChild(c),o.appendChild(a);const l=document.createElement("div");l.className="control-group";const d=this.iconBtn("reset","Reset view");d.addEventListener("click",e.resetView),l.appendChild(d);const h=this.iconBtn("storage","Storage manager");h.addEventListener("click",e.openStorageManager),l.appendChild(h);const p=this.iconBtn("gauge","Performance overlay");if(p.addEventListener("click",e.togglePerfOverlay),l.appendChild(p),e.deleteBoard){const m=this.iconBtn("trash","Delete board");m.classList.add("danger-control"),m.addEventListener("click",e.deleteBoard),l.appendChild(m)}o.appendChild(l),this.statusEl=document.createElement("div"),this.statusEl.className="board-live-status",this.statusEl.hidden=!0,this.statusTextEl=document.createElement("span"),this.statusActionBtn=document.createElement("button"),this.statusActionBtn.className="status-action-btn",this.statusActionBtn.hidden=!0,this.statusEl.append(this.statusTextEl,this.statusActionBtn),o.appendChild(this.statusEl),t.appendChild(o)}btn(t,e){const n=document.createElement("button");return n.className="control-btn",n.textContent=t,n.title=e,n.setAttribute("aria-label",e),n}iconBtn(t,e){const n=document.createElement("button");return n.className="control-btn",n.innerHTML=V[t]??"",n.title=e,n.setAttribute("aria-label",e),n}setZoom(t){this.zoomLabel.textContent=Math.round(t*100)+"%"}setTitle(t){this.titleInput.value=t,this.resizeTitleInput()}setStatus(t,e,n){this.statusEl.hidden=!t,this.statusTextEl.textContent=t,this.statusEl.dataset.state=e,this.statusActionBtn.hidden=!n,this.statusActionBtn.textContent=(n==null?void 0:n.label)??"",this.statusActionBtn.onclick=(n==null?void 0:n.onClick)??null}resizeTitleInput(){if(!this.titleMeasure||!this.titleInput)return;this.titleMeasure.textContent=this.titleInput.value||"Untitled Board";const t=Math.ceil(this.titleMeasure.getBoundingClientRect().width+22),e=Math.max(180,window.innerWidth-460);this.titleInput.style.width=Math.min(Math.max(90,t),e)+"px"}}class fo{constructor(t,e){u(this,"state");u(this,"commands");u(this,"textareas",[]);u(this,"editingId",null);this.state=t,this.commands=e}get isEditing(){return this.editingId!==null}open(t){if(this.close(),this.editingId=t.id,t.data.labelPosition==="sides"){this.openSideEditors(t);return}const e=document.createElement("textarea");e.className="text-editor",e.value=t.data.text??"",t.data.labelPosition==="sides"&&(e.placeholder="left label | right label"),this.position(e,t),document.body.appendChild(e),this.textareas=[e],e.focus(),e.select();const n=t.data.text??"";t.data.text="",t.updatedAt=Date.now(),X(t.id),this.state.requestRender();const s=()=>{const o=e.value;if(t.data.text=o,It(t),t.updatedAt=Date.now(),X(t.id),o!==n){const a=t.id,r=this.state;this.commands.push("edit-text",()=>{const c=r.elementsById.get(a);c&&(c.data.text=o,It(c),c.updatedAt=Date.now(),X(a),r.emitChange())},()=>{const c=r.elementsById.get(a);c&&(c.data.text=n,It(c),c.updatedAt=Date.now(),X(a),r.emitChange())})}this.state.emitChange(),this.close()};e.addEventListener("blur",s),e.addEventListener("keydown",o=>{o.stopPropagation(),o.key==="Escape"?(t.data.text=n,X(t.id),this.close(),this.state.requestRender()):o.key==="Enter"&&(o.metaKey||o.ctrlKey)&&e.blur()})}openSideEditors(t){const e=String(t.data.text??""),[n="",s=""]=e.split("|",2).map(d=>d.trim()),o=this.makeSideEditor("Left label",n),a=this.makeSideEditor("Right label",s);this.positionSideEditors(o,a,t),document.body.append(o,a),this.textareas=[o,a],o.focus(),o.select(),t.data.text="",t.updatedAt=Date.now(),X(t.id),this.state.requestRender();let r=!1;const c=()=>{if(r)return;r=!0;const d=`${o.value.trim()} | ${a.value.trim()}`;t.data.text=d,t.updatedAt=Date.now(),X(t.id),d!==e&&this.pushTextCommand(t.id,e,d),this.state.emitChange(),this.close()},l=()=>{r||(r=!0,t.data.text=e,X(t.id),this.close(),this.state.requestRender())};for(const d of[o,a])d.addEventListener("keydown",h=>{h.stopPropagation(),h.key==="Escape"?l():h.key==="Enter"&&(h.metaKey||h.ctrlKey)&&c()}),d.addEventListener("blur",()=>{window.setTimeout(()=>{this.textareas.includes(document.activeElement)||c()},0)})}makeSideEditor(t,e){const n=document.createElement("textarea");return n.className="text-editor text-editor-side",n.placeholder=t,n.value=e,n.style.fontFamily='-apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif',n.style.fontWeight="600",n.style.textAlign="center",n.style.lineHeight="1.35",n.style.color=this.state.theme==="dark"?"#f2f2f2":"#1f2933",n}positionSideEditors(t,e,n){const s=this.state.viewport,o=Rt(n.x,n.y,s),a=Rt(n.x+n.width,n.y+n.height,s),r=13*s.scale,c=Math.max(82,Math.min(150,Math.hypot(a.x-o.x,a.y-o.y)*.34)),l=Math.max(24,r*1.35+4);for(const[d,h]of[[t,.24],[e,.76]])d.style.left=o.x+(a.x-o.x)*h-c/2+"px",d.style.top=o.y+(a.y-o.y)*h-l/2+"px",d.style.width=c+"px",d.style.height=l+"px",d.style.fontSize=r+"px"}pushTextCommand(t,e,n){const s=this.state;this.commands.push("edit-text",()=>{const o=s.elementsById.get(t);o&&(o.data.text=n,It(o),o.updatedAt=Date.now(),X(t),s.emitChange())},()=>{const o=s.elementsById.get(t);o&&(o.data.text=e,It(o),o.updatedAt=Date.now(),X(t),s.emitChange())})}position(t,e){const n=this.state.viewport;if(e.type==="arrow"||e.type==="line"||e.type==="connector"){const b=Rt(e.x,e.y,n),x=Rt(e.x+e.width,e.y+e.height,n),v=13*n.scale,S=Math.max(100,Math.min(240,Math.hypot(x.x-b.x,x.y-b.y)-16)),w=Math.max(24,v*1.35+4);t.style.left=(b.x+x.x)/2-S/2+"px",t.style.top=(b.y+x.y)/2-w/2+"px",t.style.width=S+"px",t.style.height=w+"px",t.style.fontSize=v+"px",t.style.lineHeight="1.35",t.style.fontFamily='-apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif',t.style.fontWeight="600",t.style.color=this.state.theme==="dark"?"#f2f2f2":"#1f2933",t.style.textAlign="center";return}const s=Rt(e.x,e.y,n),o=e.data.shapeKind==="chevron",a=Te(e)*n.scale,r=o?Math.min(Math.abs(e.width)*.18,Math.abs(e.height)*.55)+8:10,c=(e.type==="sticky"?14:e.type==="task"?50:e.type==="text"?0:r)*n.scale,l=e.type!=="text"&&e.type!=="task",d=o?e.height*n.scale:e.height*n.scale-(e.type==="sticky"?28:l?r*2:0)*n.scale,h=Math.max(1,String(e.data.text??"").split(/\r?\n/).length),p=Math.max(24,a*(o?1.18:1.35)*h+4),m=l?Math.min(Math.max(24,d),p):Math.max(24,d),g=l?Math.max(0,(e.height*n.scale-m)/2):e.type==="sticky"?14*n.scale:0,y=(e.type==="task"?16:e.type==="sticky"?14:e.type==="text"?0:r)*n.scale;t.style.left=s.x+c+"px",t.style.top=s.y+g+"px",t.style.width=Math.max(40,e.width*n.scale-c-y)+"px",t.style.height=m+"px",t.style.fontSize=a+"px",t.style.lineHeight=o?"1.18":"1.35",t.style.fontFamily=e.style.fontFamily??'-apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif',t.style.fontWeight=o?"750":e.style.fontWeight??"400",t.style.color=e.style.textColor??(this.state.theme==="dark"?"#f2f2f2":"#1f2933"),t.style.textAlign=e.type==="text"||e.type==="task"?"left":"center"}close(){if(this.textareas.length){const t=this.textareas;this.textareas=[],this.editingId=null;for(const e of t)e.remove()}}}function _(i,t){const e=document.createElement("div");e.className="modal-backdrop";const n=document.createElement("div");n.className="modal",n.setAttribute("role","dialog"),n.setAttribute("aria-label",i);const s=document.createElement("button");s.className="modal-close",s.textContent="✕",s.setAttribute("aria-label","Close");const o=document.createElement("h2");o.textContent=i;const a=document.createElement("div"),r=()=>e.remove();s.addEventListener("click",r),e.addEventListener("click",c=>{c.target===e&&r()}),e.addEventListener("keydown",c=>{c.stopPropagation(),c.key==="Escape"&&r()}),n.appendChild(s),n.appendChild(o),n.appendChild(a),e.appendChild(n),document.body.appendChild(e),t(a,r),s.focus()}let lt=null,ze=null;function C(i){lt||(lt=document.createElement("div"),lt.className="toast",document.body.appendChild(lt)),lt.textContent=i,lt.classList.add("visible"),ze!==null&&clearTimeout(ze),ze=window.setTimeout(()=>{lt==null||lt.classList.remove("visible")},2600)}function gt(i){return i==="dark"?{card:"#1e2126",cardStroke:"#3a3f46",heading:"#f2f2f2",text:"#c8cdd4",accent:"#4dabf7",sticky:"#fef08a",zone:"#22262c"}:{card:"#ffffff",cardStroke:"#d8dade",heading:"#1f2933",text:"#4b5563",accent:"#6e6e6e",sticky:"#fef08a",zone:"#f0f0ed"}}let Yt=0;function yt(i){Yt=i}function N(i,t,e,n,s,o=""){return H("rectangle",{x:i,y:t,width:e,height:n,zIndex:++Yt,style:{borderRadius:10,...s},data:{text:o}})}function I(i,t,e,n,s,o,a="600"){return H("text",{x:i,y:t,width:e,height:s*1.6,zIndex:++Yt,style:{fontSize:s,textColor:o,fontWeight:a},data:{text:n}})}function W(i,t,e,n,s=180,o=120){return H("sticky",{x:i,y:t,width:s,height:o,zIndex:++Yt,style:{fill:n,borderRadius:12,shadow:!0,fontSize:13,textColor:"#1f2933"},data:{text:e}})}function z(i,t,e,n,s,o={}){return H("arrow",{x:i,y:t,width:e-i,height:n-t,zIndex:++Yt,style:{stroke:s,strokeWidth:2,arrowEnd:!0,arrowStart:o.arrowStart,strokeDash:o.dashed?[8,6]:void 0},data:{text:o.label??"",labelPosition:o.sides?"sides":"center"}})}function go(i,t,e,n,s,o=""){return H("ellipse",{x:i,y:t,width:e,height:n,zIndex:++Yt,style:s,data:{text:o}})}function yo(i,t,e,n){const s=gt(e);yt(n);const o=[];return o.push(N(i,t,760,560,{fill:s.card,stroke:s.cardStroke,strokeWidth:1.5,borderRadius:16,shadow:!0})),o.push(I(i+28,t+22,400,"User Persona",22,s.heading,"700")),o.push(I(i+28,t+60,300,"Name",13,s.accent)),o.push(W(i+28,t+86,"Jordan Lee",s.sticky,200,64)),o.push(I(i+260,t+60,300,"Role",13,s.accent)),o.push(W(i+260,t+86,"Senior Product Manager","#a5b4fc",220,64)),o.push(I(i+510,t+60,300,"Buying trigger",13,s.accent)),o.push(W(i+510,t+86,"Team scaling pains","#fdba74",220,64)),[["Goals","Ship the right features faster","#86efac"],["Pain points","Scattered docs, unclear priorities","#fca5a5"],["Jobs to be done","Align team on what to build next","#93c5fd"],["Current workaround","Spreadsheets + slide decks","#d8b4fe"],["Success criteria","Stakeholders aligned in 1 meeting","#f9a8d4"],["Key quote",'"I need clarity, not more tools."',"#fef08a"]].forEach(([r,c,l],d)=>{const h=d%3,p=Math.floor(d/3),m=i+28+h*242,g=t+188+p*178;o.push(I(m,g,230,r,13,s.accent)),o.push(W(m,g+26,c,l,220,124))}),o}const He=["Awareness","Discovery","Evaluation","Onboarding","Activation","Retention"],bo=["#93c5fd","#a5b4fc","#d8b4fe","#f9a8d4","#fdba74","#86efac"];function vo(i,t,e,n){const s=gt(e);yt(n);const o=[],a=230,r=He.length*a+56;return o.push(N(i,t,r,640,{fill:s.card,stroke:s.cardStroke,strokeWidth:1.5,borderRadius:16,shadow:!0})),o.push(I(i+28,t+22,500,"User Journey Map",22,s.heading,"700")),He.forEach((c,l)=>{const d=i+28+l*a,h=t+70;o.push(N(d,h,a-16,48,{fill:bo[l],borderRadius:10},c)),l<He.length-1&&o.push(z(d+a-14,h+24,d+a-2,h+24,s.heading)),o.push(N(d,h+64,a-16,150,{fill:s.zone,borderRadius:10},"")),o.push(I(d+10,h+70,a-36,"Actions",12,s.accent)),o.push(W(d+14,h+96,"","#fef08a",a-44,100)),o.push(N(d,h+226,a-16,150,{fill:s.zone,borderRadius:10},"")),o.push(I(d+10,h+232,a-36,"Pain points",12,s.accent)),o.push(W(d+14,h+258,"","#fca5a5",a-44,100)),o.push(N(d,h+388,a-16,150,{fill:s.zone,borderRadius:10},"")),o.push(I(d+10,h+394,a-36,"Opportunities",12,s.accent)),o.push(W(d+14,h+420,"","#86efac",a-44,100))}),o}function wo(i,t,e,n){const s=gt(e);yt(n);const o=[],a=680;o.push(N(i,t,a+120,a+130,{fill:s.card,stroke:s.cardStroke,strokeWidth:1.5,borderRadius:16,shadow:!0})),o.push(I(i+28,t+22,500,"Feature Prioritization Matrix",22,s.heading,"700"));const r=i+80,c=t+80,l=a/2;return o.push(N(r,c,l,l,{fill:"#86efac55",borderRadius:8})),o.push(N(r+l,c,l,l,{fill:"#93c5fd55",borderRadius:8})),o.push(N(r,c+l,l,l,{fill:"#fef08a55",borderRadius:8})),o.push(N(r+l,c+l,l,l,{fill:"#fca5a555",borderRadius:8})),o.push(I(r+16,c+12,300,"Quick wins",16,s.heading,"700")),o.push(I(r+l+16,c+12,300,"Strategic bets",16,s.heading,"700")),o.push(I(r+16,c+l+12,300,"Fill-ins",16,s.heading,"700")),o.push(I(r+l+16,c+l+12,300,"Avoid",16,s.heading,"700")),o.push(z(r-24,c+a,r-24,c,s.heading)),o.push(I(r-64,c+l-12,60,"Impact",14,s.text,"600")),o.push(z(r,c+a+24,r+a,c+a+24,s.heading)),o.push(I(r+l-30,c+a+34,80,"Effort",14,s.text,"600")),o.push(W(r+40,c+60,"Feature idea","#fef08a",150,90)),o.push(W(r+l+40,c+60,"Big bet","#a5b4fc",150,90)),o}const bn=[["Problem","#fca5a5"],["User","#93c5fd"],["Context","#d8b4fe"],["Current workflow","#fdba74"],["Proposed solution","#86efac"],["Edge cases","#f9a8d4"],["Acceptance criteria","#a5b4fc"],["Dependencies","#fef08a"],["Risks","#fca5a5"]];function xo(i,t,e,n){const s=gt(e);yt(n);const o=[],a=3,r=280,c=210,l=a*r+56,h=Math.ceil(bn.length/a)*c+100;return o.push(N(i,t,l,h,{fill:s.card,stroke:s.cardStroke,strokeWidth:1.5,borderRadius:16,shadow:!0})),o.push(I(i+28,t+22,500,"Product Requirements Flow",22,s.heading,"700")),bn.forEach(([p,m],g)=>{const y=g%a,b=Math.floor(g/a),x=i+28+y*r,v=t+72+b*c;o.push(I(x,v,r-30,`${g+1}. ${p}`,14,s.accent)),o.push(W(x,v+30,"",m,r-28,c-60))}),o}function Co(i,t,e,n){const s=gt(e);yt(n);const o=[];o.push(I(i,t-40,400,"System Diagram",22,s.heading,"700"));const a=(r,c,l,d,h,p)=>N(r,c,l,d,{fill:h,stroke:s.cardStroke,strokeWidth:1.5,borderRadius:12,shadow:!0,fontSize:15,fontWeight:"600",textColor:"#1f2933"},p);return o.push(go(i,t+130,110,110,{fill:"#f9a8d4",stroke:s.cardStroke,strokeWidth:1.5,fontSize:14,fontWeight:"600",textColor:"#1f2933"},"User")),o.push(a(i+200,t+140,180,90,"#93c5fd","Frontend")),o.push(a(i+470,t+140,180,90,"#a5b4fc","API / Server")),o.push(a(i+740,t+60,180,90,"#86efac","Database")),o.push(a(i+740,t+200,180,90,"#fdba74","External Service")),o.push(a(i+470,t+330,180,90,"#fef08a","Notification Service")),o.push(z(i+115,t+185,i+195,t+185,s.heading,{label:"uses"})),o.push(z(i+385,t+185,i+465,t+185,s.heading,{label:"request | response",sides:!0,arrowStart:!0})),o.push(z(i+655,t+165,i+735,t+110,s.heading,{label:"read"})),o.push(z(i+655,t+205,i+735,t+240,s.heading,{label:"webhook",dashed:!0})),o.push(z(i+560,t+235,i+560,t+325,s.heading,{label:"event",dashed:!0})),o.push(z(i+470,t+375,i+80,t+245,s.heading,{label:"notify",dashed:!0})),o}function ko(i,t,e,n){const s=gt(e);yt(n);const o=[];o.push(I(i+280,t-40,500,"Opportunity Solution Tree",22,s.heading,"700")),o.push(N(i+300,t,280,80,{fill:"#a5b4fc",borderRadius:12,shadow:!0,fontSize:15,fontWeight:"600",textColor:"#1f2933"},"Desired outcome"));const a=t+160,r=[i,i+300,i+600];for(const d of r)o.push(W(d,a,"Opportunity","#93c5fd",220,100)),o.push(z(i+440,t+85,d+110,a-5,s.heading));const c=a+180;for(const d of r)o.push(W(d,c,"Solution","#86efac",220,100)),o.push(z(d+110,a+105,d+110,c-5,s.heading));const l=c+180;for(const d of r)o.push(W(d,l,"Experiment","#fdba74",220,90)),o.push(z(d+110,c+105,d+110,l-5,s.heading));return o.push(I(i,l+120,400,"Signals / metrics",14,s.accent)),o.push(W(i,l+150,"What signal tells us this is working?","#fef08a",380,100)),o}function Eo(i,t,e,n){const s=gt(e);yt(n);const o=[];o.push(N(i,t,1060,620,{fill:s.card,stroke:s.cardStroke,strokeWidth:1.5,borderRadius:16,shadow:!0})),o.push(I(i+28,t+22,500,"Screenshot Review",22,s.heading,"700")),o.push(I(i+28,t+64,300,"Screenshot",13,s.accent));const a=H("frame",{x:i+28,y:t+92,width:480,height:360,zIndex:n+100,style:{fill:s.zone,stroke:s.cardStroke,strokeWidth:1.5,borderRadius:12,fontSize:13,textColor:s.text},data:{text:"Paste a screenshot here (Cmd/Ctrl+V)"}});return o.push(a),[["Observations","#93c5fd"],["Problems","#fca5a5"],["UX notes","#d8b4fe"],["Requirements","#86efac"]].forEach(([c,l],d)=>{const h=d%2,p=Math.floor(d/2),m=i+540+h*250,g=t+64+p*200;o.push(I(m,g,230,c,13,s.accent)),o.push(W(m,g+28,"",l,230,140))}),o.push(I(i+28,t+470,300,"Follow-up tasks",13,s.accent)),o.push(W(i+28,t+498,"","#fef08a",480,96)),o.push(I(i+540,t+470,300,"Decision",13,s.accent)),o.push(W(i+540,t+498,"","#fdba74",480,96)),o}function So(i,t,e,n){const s=gt(e);yt(n);const o=[];o.push(I(i,t,880,"Workflow map",26,s.heading,"700"));const a=[["Request","#dbeafe"],["Review","#fef3c7"],["Deliver","#dcfce7"]];for(let r=0;r<a.length;r++){const c=i+r*280;o.push(N(c,t+130,180,96,{fill:a[r][1],stroke:s.cardStroke,strokeWidth:1.5,borderRadius:12,fontSize:16,fontWeight:"650",textColor:"#1f2933",shadow:!0},a[r][0]))}return o.push(z(i+180,t+178,i+280,t+178,s.accent,{label:"approve"})),o.push(z(i+460,t+178,i+560,t+178,s.accent,{label:"ship"})),o.push(z(i+650,t+226,i+370,t+310,"#9ca3af",{label:"feedback",dashed:!0})),o.push(N(i+280,t+300,180,72,{fill:s.zone,stroke:s.cardStroke,strokeWidth:1.5,borderRadius:10,fontSize:14,textColor:s.text},"Learn and iterate")),o}function To(i,t,e,n){const s=gt(e);yt(n);const o=[];return o.push(I(i,t,800,"Handoff map",26,s.heading,"700")),[["Explore","#dbeafe"],["Decide","#fef3c7"],["Act","#dcfce7"]].forEach(([r,c],l)=>{o.push(N(i+l*270,t+150,170,92,{fill:c,stroke:s.cardStroke,strokeWidth:1.5,borderRadius:12,shadow:!0,fontSize:16,fontWeight:"650",textColor:"#1f2933"},r))}),o.push(z(i+170,t+196,i+270,t+196,s.accent,{label:"proposal"})),o.push(z(i+440,t+196,i+540,t+196,s.accent,{label:"owner | outcome",sides:!0,arrowStart:!0})),o.push(z(i+625,t+245,i+355,t+330,"#9ca3af",{label:"feedback",dashed:!0})),o.push(N(i+265,t+320,180,70,{fill:s.zone,stroke:s.cardStroke,strokeWidth:1.5,borderRadius:10,fontSize:14,textColor:s.text},"Review signal")),o}const Bo=[{id:"persona",name:"User Persona Card",description:"Name, role, goals, pain points, JTBD, success criteria.",build:yo},{id:"journey",name:"User Journey Map",description:"Awareness → Retention stages with sticky note areas.",build:vo},{id:"matrix",name:"Prioritization Matrix",description:"Impact vs effort: quick wins, strategic bets, fill-ins, avoid.",build:wo},{id:"requirements",name:"Requirements Flow",description:"Problem, user, context, solution, edge cases, risks.",build:xo},{id:"system",name:"System Diagram Starter",description:"User, frontend, API, database, external services + arrows.",build:Co},{id:"ost",name:"Opportunity Solution Tree",description:"Outcome, opportunities, solutions, experiments, signals.",build:ko},{id:"screenshot-review",name:"Screenshot Review Board",description:"Screenshot zone with observations, problems, UX notes.",build:Eo},{id:"workflow",name:"Workflow Map",description:"Labeled handoffs, a dashed feedback loop, and editable steps.",build:So},{id:"handoff",name:"Handoff Map",description:"A shared decision flow with ownership, outcomes, and feedback.",build:To}];function Mo(i,t){_("Insert a template",(e,n)=>{const s=document.createElement("div");s.className="template-grid";for(const o of Bo){const a=document.createElement("button");a.className="template-card";const r=document.createElement("span");r.className="t-name",r.textContent=o.name;const c=document.createElement("span");c.className="t-desc",c.textContent=o.description,a.appendChild(r),a.appendChild(c),a.addEventListener("click",()=>{Io(i,t,o.build),n()}),s.appendChild(a)}e.appendChild(s)})}function Io(i,t,e){const n=L(window.innerWidth/2,window.innerHeight/2,i.viewport),s=e(n.x-380,n.y-280,i.theme,i.maxZIndex());t.execute("insert-template",()=>{for(const o of s)i.elementsById.has(o.id)||i.addElement(o);i.emitChange()},()=>{for(const o of s)i.removeElement(o.id);i.emitChange()}),i.clearSelection();for(const o of s)i.selectedIds.add(o.id);i.requestRender()}function ue(i){return i<1024?i+" B":i<1024*1024?(i/1024).toFixed(1)+" KB":(i/(1024*1024)).toFixed(1)+" MB"}function Ro(i,t,e,n){_(n?"Storage":"Local storage",async(s,o)=>{const a=document.createElement("div");s.appendChild(a);const r=(g,y)=>{const b=document.createElement("div");b.className="storage-row";const x=document.createElement("span");x.textContent=g;const v=document.createElement("span");v.textContent=y,b.appendChild(x),b.appendChild(v),a.appendChild(b)};r("Elements on board",String(i.elements.length));const c=JSON.stringify(i.elements);if(r("Board data size",ue(c.length)),n)r("Workspace assets","Stored on disk under docs/assets");else{const g=await it.getAllKeys();r("Image assets",String(g.length));const y=await it.totalSizeBytes();r("Image asset size",ue(y))}const l=await tt.estimateStorage();!n&&l.quota>0&&r("Browser storage",`${ue(l.usage)} of ${ue(l.quota)}`);const d=document.createElement("div");d.className="modal-actions";const h=document.createElement("button");h.className="btn",h.textContent=n?"Clean unused managed assets":"Clear unused assets",h.addEventListener("click",async()=>{if(n){const x=i.elements.map(v=>typeof v.data.src=="string"?v.data.src:"").filter(Boolean);try{const v=await n(x);C(`Removed ${v} unused managed asset${v===1?"":"s"}`),o()}catch{C("Could not clean workspace assets")}return}const g=new Set,y=await tt.getAllBoards();for(const x of y)for(const v of x.elements){const S=v.data.assetId;typeof S=="string"&&g.add(S)}const b=await it.clearUnused(g);C(`Removed ${b} unused asset${b===1?"":"s"}`),o()}),d.appendChild(h);const p=document.createElement("button");p.className="btn danger",p.textContent="Clear board",p.addEventListener("click",()=>{confirm("Remove all elements from this board?")&&(t(),o())}),d.appendChild(p);const m=document.createElement("button");m.className="btn danger",m.textContent=n?"Reset local-only data":"Reset all local data",m.addEventListener("click",()=>{confirm("Delete ALL local boards, assets and preferences? This cannot be undone.")&&(e(),o())}),d.appendChild(m),s.appendChild(d)})}class Lo{constructor(t,e,n,s,o,a){u(this,"element");u(this,"visible",!1);u(this,"state");u(this,"renderer");u(this,"hitTester");u(this,"monitor");u(this,"imageCache");u(this,"timer",null);u(this,"storageEstimate","–");this.state=e,this.renderer=n,this.hitTester=s,this.monitor=o,this.imageCache=a,this.element=document.createElement("div"),this.element.className="perf-overlay",t.appendChild(this.element)}toggle(){this.visible=!this.visible,this.element.classList.toggle("visible",this.visible),this.visible?(this.monitor.start(),this.update(),this.timer=window.setInterval(()=>this.update(),500),this.refreshStorage()):this.timer!==null&&(clearInterval(this.timer),this.timer=null)}async refreshStorage(){const t=await it.totalSizeBytes();this.storageEstimate=(t/(1024*1024)).toFixed(1)+"MB"}update(){const t=this.state.viewport,e=[`FPS: ${this.monitor.fps}`,`Total elements: ${this.state.elements.length.toLocaleString()}`,`Visible elements: ${this.renderer.visibleCount.toLocaleString()}`,`Render time: ${this.renderer.lastRenderMs.toFixed(1)}ms`,`Hit-test time: ${this.hitTester.lastHitTestMs.toFixed(2)}ms`,`Save time: ${tt.lastSaveMs.toFixed(0)}ms`,`Image cache: ${this.imageCache.size}`,`Estimated storage: ${this.storageEstimate}`,`Zoom: ${Math.round(t.scale*100)}%`,`Viewport: x: ${Math.round(-t.offsetX/t.scale)}, y: ${Math.round(-t.offsetY/t.scale)}`,`Culling: ${this.renderer.cullingEnabled?"on":"off"} LOD: ${this.renderer.lodEnabled?"on":"off"}`];this.element.textContent=e.join(`
|
|
13
|
+
`)}}const me=["#93c5fd","#a5b4fc","#86efac","#fdba74","#fca5a5","#d8b4fe","#f9a8d4","#fef08a","#ffffff","#e5e7eb"],vn=["Onboarding","Checkout","Retention","Activation","Churn risk","API gateway","User insight","Edge case","Quick win","Tech debt","Experiment","Metric","Persona","Journey","Feature flag"];function Q(i,t){return i+Math.random()*(t-i)}function dt(i){return i[Math.floor(Math.random()*i.length)]}const ht="stress";class $o{constructor(t){u(this,"state");u(this,"lastGenerateMs",0);this.state=t}generate(t){const e=performance.now(),n=Math.sqrt(t)*280,s=["sticky","rectangle","ellipse","text","arrow"];let o=this.state.maxZIndex();const a=[];for(let r=0;r<t;r++){const c=dt(s),l=Q(-n/2,n/2),d=Q(-n/2,n/2);let h;c==="sticky"?h=H("sticky",{x:l,y:d,width:220,height:160,zIndex:++o,style:{fill:dt(Ce),borderRadius:12,shadow:!0,fontSize:14,textColor:"#1f2933"},data:{text:dt(vn),[ht]:!0}}):c==="rectangle"||c==="ellipse"?h=H(c,{x:l,y:d,width:Q(80,300),height:Q(60,200),zIndex:++o,style:{fill:dt(me),stroke:"#37415188",strokeWidth:1.5,borderRadius:c==="rectangle"?8:0},data:{[ht]:!0}}):c==="text"?h=H("text",{x:l,y:d,width:200,height:28,zIndex:++o,style:{fontSize:16,textColor:this.state.theme==="dark"?"#f2f2f2":"#1f2933"},data:{text:dt(vn),[ht]:!0}}):h=H("arrow",{x:l,y:d,width:Q(-250,250),height:Q(-250,250),zIndex:++o,style:{stroke:dt(me),strokeWidth:2,arrowEnd:!0},data:{[ht]:!0}}),a.push(h)}for(const r of a)this.state.addElement(r);this.lastGenerateMs=performance.now()-e,this.state.emitChange()}generateImagePlaceholders(t){const e=Math.sqrt(t)*420;let n=this.state.maxZIndex();for(let s=0;s<t;s++){const o=H("image",{x:Q(-e/2,e/2),y:Q(-e/2,e/2),width:320,height:220,zIndex:++n,data:{assetId:"stress-placeholder-"+s,[ht]:!0}});this.state.addElement(o)}this.state.emitChange()}generateMixedPmBoard(){this.generate(300)}randomizePositions(){const t=Math.sqrt(this.state.elements.length)*280;for(const e of this.state.elements)e.data[ht]&&(e.x=Q(-t/2,t/2),e.y=Q(-t/2,t/2));this.state.emitChange()}randomizeColors(){for(const t of this.state.elements)t.data[ht]&&(t.type==="sticky"?t.style.fill=dt(Ce):t.type==="rectangle"||t.type==="ellipse"?t.style.fill=dt(me):t.type==="arrow"&&(t.style.stroke=dt(me)));this.state.emitChange()}randomizeZIndex(){for(const t of this.state.elements)t.data[ht]&&(t.zIndex=Math.floor(Q(0,this.state.elements.length)));this.state.invalidateSort(),this.state.emitChange()}clearGenerated(){const t=this.state.elements.filter(e=>e.data[ht]);for(const e of t)this.state.removeElement(e.id);this.state.emitChange()}}class Po{constructor(t,e,n){u(this,"element");u(this,"visible",!1);this.element=document.createElement("div"),this.element.className="stress-panel";const s=(a,r,c=!1)=>{const l=document.createElement("button");l.className="btn"+(c?" danger":""),l.textContent=a,l.addEventListener("click",r),this.element.appendChild(l)},o=a=>()=>{e.generate(a),C(`Generated ${a.toLocaleString()} elements in ${e.lastGenerateMs.toFixed(0)}ms`)};s("+100",o(100)),s("+1,000",o(1e3)),s("+5,000",o(5e3)),s("+10,000",o(1e4)),s("+20,000",o(2e4)),s("+100 images",()=>{e.generateImagePlaceholders(100),C("Generated 100 image placeholders")}),s("Mixed PM board",()=>{e.generateMixedPmBoard(),C("Generated mixed PM board")}),s("Shuffle positions",()=>e.randomizePositions()),s("Shuffle colors",()=>e.randomizeColors()),s("Shuffle z-index",()=>e.randomizeZIndex()),s("Toggle culling",()=>{n.cullingEnabled=!n.cullingEnabled,C(`Viewport culling ${n.cullingEnabled?"enabled":"disabled"}`),n.state.requestRender()}),s("Toggle LOD",()=>{n.lodEnabled=!n.lodEnabled,C(`Simplified rendering ${n.lodEnabled?"enabled":"disabled"}`),n.state.requestRender()}),s("Clear generated",()=>{e.clearGenerated(),C("Cleared generated elements")},!0),t.appendChild(this.element)}toggle(){this.visible=!this.visible,this.element.classList.toggle("visible",this.visible)}}const Do=300,Ao=1e3,wn=[{label:"Small",shortLabel:"S",fontSize:13,fontWeight:"400"},{label:"Body",shortLabel:"Body",fontSize:16,fontWeight:"400"},{label:"H3",shortLabel:"H3",fontSize:18,fontWeight:"650"},{label:"H2",shortLabel:"H2",fontSize:24,fontWeight:"700"},{label:"H1",shortLabel:"H1",fontSize:32,fontWeight:"750"}],No=new Set(["text"]),zo=new Set(["rectangle","ellipse","frame"]),Ho=["#0078d4","#4dabf7","#6e6e6e","#ffffff","#0f0f0f","#fef08a","#93c5fd","#fca5a5"],Fo=[{label:"Black text",value:"#1f2933"},{label:"White text",value:"#ffffff"}];class jo{constructor(t,e={}){u(this,"state",new Ti);u(this,"commands",new Mi);u(this,"surface");u(this,"renderer");u(this,"scheduler");u(this,"hitTester");u(this,"imageCache");u(this,"monitor",new _i);u(this,"actions");u(this,"imageInsert");u(this,"toolController");u(this,"textEditor");u(this,"toolbar");u(this,"topControls");u(this,"perfOverlay");u(this,"stressPanel");u(this,"boardSaveTimer",null);u(this,"viewportSaveTimer",null);u(this,"saveInFlight",null);u(this,"saveQueued",!1);u(this,"suppressPersistence",!1);u(this,"options");u(this,"listenerAbort",new AbortController);u(this,"root");u(this,"revision",null);u(this,"stale",!1);u(this,"bottomToolCluster",null);u(this,"stickyColorPopover",null);u(this,"textSizePopover",null);u(this,"shapeStylePopover",null);u(this,"layerMenu",null);this.root=t,this.options=e,e.boardId&&(this.state.boardId=e.boardId);const n=this.listenerAbort.signal;this.surface=new Fi(t,3,n),this.imageCache=new es(it,()=>this.state.requestRender(),e.resolveAssetUrl),this.renderer=new ji(this.surface,this.state,this.imageCache),this.scheduler=new Wi(()=>this.renderer.render()),this.hitTester=new Ui(this.state),this.actions=new Ii(this.state,this.commands),this.textEditor=new fo(this.state,this.commands),this.imageInsert=new $i(this.state,this.commands,this.imageCache,C,e.uploadImage),this.state.onRenderNeeded(()=>{var s;this.scheduler.requestRender(),(s=this.topControls)==null||s.setZoom(this.state.viewport.scale),this.suppressPersistence||this.scheduleViewportSave(),this.updateContextualToolPanels()}),this.state.onChange(()=>{this.suppressPersistence||this.scheduleBoardSave()}),this.surface.onResize(()=>this.state.requestRender()),this.setupTools(t,n),this.setupUi(t),this.setupSelectionOverlays(t,n),this.setupDragDrop(t),new Di(this.state,this.actions,this.imageInsert,n),Ai({state:this.state,commands:this.commands,actions:this.actions,toolController:this.toolController,resetView:()=>this.resetView()},n),this.loadInitialState()}destroy(){this.boardSaveTimer!==null&&clearTimeout(this.boardSaveTimer),this.viewportSaveTimer!==null&&clearTimeout(this.viewportSaveTimer),this.listenerAbort.abort(),this.imageCache.clear()}setupTools(t,e){const n={state:this.state,renderer:this.renderer,surface:this.surface,hitTester:this.hitTester,commands:this.commands,setTool:s=>this.toolController.setTool(s),setCursor:s=>{this.surface.container.style.cursor=s},openTextEditor:s=>this.textEditor.open(s)};this.toolController=new Ki(this.surface.container,n,[new Zi,new Ji,new eo,new no,new ct("rectangle"),new ct("ellipse"),new ct("diamond"),new ct("triangle"),new ct("pill"),new ct("chevron"),new ct("parallelogram"),new ct("hexagon"),new ct("cylinder"),new so,new Gt,new Gt("dashedArrow"),new Gt("twoWayArrow"),new Gt("labeledArrow"),new Gt("sidedLabelArrow"),new io((s,o,a)=>void this.imageInsert.insertFiles(s,o,a))],e),this.toolController.onToolChange(s=>{var o;(o=this.toolbar)==null||o.setActiveTool(s)})}setupUi(t){this.toolbar=new uo(t,{setTool:n=>this.toolController.setTool(n),openTemplates:()=>Mo(this.state,this.commands),toggleTheme:()=>this.toggleTheme(),openExportMenu:()=>this.openExportMenu(),toggleStressPanel:()=>this.stressPanel.toggle(),copyEmbed:this.options.onExit?()=>this.startEmbedSelection():void 0}),this.toolbar.setActiveTool("select"),this.topControls=new mo(t,{onExit:this.options.onExit?()=>this.exitToDocs():void 0,resetView:()=>this.resetView(),zoomIn:()=>{oe(this.state.viewport,window.innerWidth/2,window.innerHeight/2,this.state.viewport.scale*1.2),this.state.requestRender()},zoomOut:()=>{oe(this.state.viewport,window.innerWidth/2,window.innerHeight/2,this.state.viewport.scale/1.2),this.state.requestRender()},openStorageManager:()=>Ro(this.state,()=>this.clearBoard(),()=>void this.resetAllLocalData(),this.options.cleanupUnusedAssets),togglePerfOverlay:()=>this.perfOverlay.toggle(),deleteBoard:this.options.deleteBoard?()=>this.confirmDeleteBoard():void 0,onTitleChange:n=>{this.state.title=n,this.state.emitChange()}},this.state.title),this.perfOverlay=new Lo(t,this.state,this.renderer,this.hitTester,this.monitor,this.imageCache);const e=new $o(this.state);this.stressPanel=new Po(t,e,this.renderer)}setupSelectionOverlays(t,e){this.bottomToolCluster=document.createElement("div"),this.bottomToolCluster.className="bottom-tool-cluster",t.appendChild(this.bottomToolCluster),this.bottomToolCluster.appendChild(this.toolbar.element),this.stickyColorPopover=document.createElement("div"),this.stickyColorPopover.className="context-tool-popover sticky-color-popover",this.stickyColorPopover.setAttribute("aria-hidden","true");for(const s of Ce){const o=document.createElement("button");o.type="button",o.className="sticky-color-btn",o.title="Set sticky color",o.setAttribute("aria-label",`Set sticky color ${s}`),o.style.setProperty("--swatch",s),o.addEventListener("click",()=>this.setSelectedStickyColor(s)),this.stickyColorPopover.appendChild(o)}this.bottomToolCluster.appendChild(this.stickyColorPopover),this.textSizePopover=document.createElement("div"),this.textSizePopover.className="context-tool-popover text-size-popover",this.textSizePopover.setAttribute("aria-hidden","true");for(const s of wn){const o=document.createElement("button");o.type="button",o.className="text-size-btn",o.textContent=s.shortLabel,o.setAttribute("aria-label",`Set text size ${s.label}`),o.addEventListener("click",()=>this.setSelectedTextSize(s)),this.textSizePopover.appendChild(o)}this.bottomToolCluster.appendChild(this.textSizePopover),this.shapeStylePopover=document.createElement("div"),this.shapeStylePopover.className="context-tool-popover shape-style-popover",this.shapeStylePopover.setAttribute("aria-hidden","true");for(const s of Ho){const o=document.createElement("button");o.type="button",o.className="shape-fill-btn",o.title="Set shape color",o.setAttribute("aria-label",`Set shape color ${s}`),o.style.setProperty("--swatch",s),o.addEventListener("click",()=>this.setSelectedShapeFill(s)),this.shapeStylePopover.appendChild(o)}const n=document.createElement("div");n.className="context-tool-divider",this.shapeStylePopover.appendChild(n);for(const s of Fo){const o=document.createElement("button");o.type="button",o.className="shape-text-color-btn",o.textContent=s.value==="#ffffff"?"W":"B",o.setAttribute("aria-label",s.label),o.addEventListener("click",()=>this.setSelectedShapeTextColor(s.value)),this.shapeStylePopover.appendChild(o)}this.bottomToolCluster.appendChild(this.shapeStylePopover),this.surface.interactionLayer.addEventListener("contextmenu",s=>this.openLayerMenu(s),{signal:e,capture:!0}),document.addEventListener("pointerdown",s=>{this.layerMenu&&!this.layerMenu.contains(s.target)&&this.closeLayerMenu()},{signal:e}),document.addEventListener("keydown",s=>{s.key==="Escape"&&this.closeLayerMenu()},{signal:e})}updateContextualToolPanels(){this.updateStickyColorPopover(),this.updateTextSizePopover(),this.updateShapeStylePopover()}setContextPanelVisible(t,e){t&&(t.classList.toggle("is-visible",e),t.setAttribute("aria-hidden",String(!e)))}updateStickyColorPopover(){var o;const t=this.stickyColorPopover;if(!t)return;const e=this.state.getSelected().filter(a=>a.type==="sticky"),n=e.length>0&&!this.textEditor.isEditing;if(this.setContextPanelVisible(t,n),!n)return;const s=(o=e[0])==null?void 0:o.style.fill;for(const a of t.children){const r=a,c=r.style.getPropertyValue("--swatch")===s;r.classList.toggle("active",c),r.setAttribute("aria-pressed",String(c))}}setSelectedStickyColor(t){to(t);const e=this.state.getSelected().filter(r=>r.type==="sticky"&&!r.locked);if(e.length===0)return;const n=this.state,s=e.map(r=>({id:r.id,fill:r.style.fill,textColor:r.style.textColor,updatedAt:r.updatedAt})),o=e.map(r=>({id:r.id,fill:t,textColor:"#1f2933",updatedAt:Date.now()})),a=r=>{for(const c of r){const l=n.elementsById.get(c.id);l&&(l.style.fill=c.fill,l.style.textColor=c.textColor,l.updatedAt=c.updatedAt)}n.emitChange()};this.commands.execute("sticky-color",()=>a(o),()=>a(s))}updateTextSizePopover(){var o,a;const t=this.textSizePopover;if(!t)return;const e=this.selectedTextTargets(),n=e.length>0&&!this.textEditor.isEditing;if(this.setContextPanelVisible(t,n),!n)return;const s=((o=e[0])==null?void 0:o.style.fontSize)??(((a=e[0])==null?void 0:a.type)==="sticky"?15:16);for(const r of t.children){const c=r,l=wn.find(h=>h.shortLabel===c.textContent),d=(l==null?void 0:l.fontSize)===s;c.classList.toggle("active",d),c.setAttribute("aria-pressed",String(d))}}selectedTextTargets(){return this.state.getSelected().filter(t=>No.has(t.type)&&!t.locked)}setSelectedTextSize(t){const e=this.selectedTextTargets();if(e.length===0)return;const n=this.state,s=e.map(r=>({id:r.id,fontSize:r.style.fontSize,fontWeight:r.style.fontWeight,height:r.height,updatedAt:r.updatedAt})),o=e.map(r=>({id:r.id,fontSize:t.fontSize,fontWeight:t.fontWeight,height:r.type==="text"?Math.max(r.height,Math.ceil(t.fontSize*1.45)):r.height,updatedAt:Date.now()})),a=r=>{for(const c of r){const l=n.elementsById.get(c.id);l&&(l.style.fontSize=c.fontSize,l.style.fontWeight=c.fontWeight,l.height=c.height,l.updatedAt=c.updatedAt,X(l.id))}n.emitChange()};this.commands.execute("text-size",()=>a(o),()=>a(s))}updateShapeStylePopover(){var a,r;const t=this.shapeStylePopover;if(!t)return;const e=this.selectedShapeTargets(),n=e.length>0&&!this.textEditor.isEditing;if(this.setContextPanelVisible(t,n),!n)return;const s=(a=e[0])==null?void 0:a.style.fill,o=((r=e[0])==null?void 0:r.style.textColor)??"#1f2933";for(const c of t.children){const l=c;if(l.classList.contains("shape-fill-btn")){const d=l.style.getPropertyValue("--swatch")===s;l.classList.toggle("active",d),l.setAttribute("aria-pressed",String(d))}if(l.classList.contains("shape-text-color-btn")){const h=l.textContent==="W"?o==="#ffffff":o!=="#ffffff";l.classList.toggle("active",h),l.setAttribute("aria-pressed",String(h))}}}selectedShapeTargets(){return this.state.getSelected().filter(t=>zo.has(t.type)&&!t.locked)}setSelectedShapeFill(t){const e=this.selectedShapeTargets();if(e.length===0)return;const n=this.state,s=e.map(r=>({id:r.id,fill:r.style.fill,updatedAt:r.updatedAt})),o=e.map(r=>({id:r.id,fill:t,updatedAt:Date.now()})),a=r=>{for(const c of r){const l=n.elementsById.get(c.id);l&&(l.style.fill=c.fill,l.updatedAt=c.updatedAt)}n.emitChange()};this.commands.execute("shape-fill",()=>a(o),()=>a(s))}setSelectedShapeTextColor(t){const e=this.selectedShapeTargets();if(e.length===0)return;const n=this.state,s=e.map(r=>({id:r.id,textColor:r.style.textColor,updatedAt:r.updatedAt})),o=e.map(r=>({id:r.id,textColor:t,updatedAt:Date.now()})),a=r=>{for(const c of r){const l=n.elementsById.get(c.id);l&&(l.style.textColor=c.textColor,l.updatedAt=c.updatedAt,X(l.id))}n.emitChange()};this.commands.execute("shape-text-color",()=>a(o),()=>a(s))}openLayerMenu(t){if(t.preventDefault(),t.stopPropagation(),this.textEditor.isEditing)return;const e=L(t.clientX,t.clientY,this.state.viewport),n=this.hitTester.hitTest(e.x,e.y,this.state.viewport.scale);n&&!this.state.selectedIds.has(n.id)&&(this.state.clearSelection(),this.state.selectedIds.add(n.id),this.state.requestRender());const s=this.state.getSelected();if(s.length===0){this.closeLayerMenu();return}this.closeLayerMenu();const o=document.createElement("div");o.className="layer-menu",o.setAttribute("role","menu");const a=document.createElement("div");a.className="layer-menu-label",a.textContent=s.length===1?"Layer":`${s.length} layers`,o.appendChild(a);const r=(l,d)=>{const h=document.createElement("button");h.type="button",h.setAttribute("role","menuitem"),h.textContent=l,h.addEventListener("click",()=>{d(),this.closeLayerMenu()}),o.appendChild(h)},c=()=>{const l=document.createElement("div");l.className="layer-menu-divider",o.appendChild(l)};r("Bring forward",()=>this.actions.bringForward()),r("Send backward",()=>this.actions.sendBackward()),c(),r("Bring to front",()=>this.actions.bringToFront()),r("Send to back",()=>this.actions.sendToBack()),this.root.appendChild(o),this.layerMenu=o,this.positionLayerMenu(o,t.clientX,t.clientY)}positionLayerMenu(t,e,n){t.style.left="0px",t.style.top="0px",requestAnimationFrame(()=>{const o=t.getBoundingClientRect(),a=Math.min(Math.max(12,e),window.innerWidth-o.width-12),r=Math.min(Math.max(12,n),window.innerHeight-o.height-12);t.style.left=`${a}px`,t.style.top=`${r}px`})}closeLayerMenu(){var t;(t=this.layerMenu)==null||t.remove(),this.layerMenu=null}exitToDocs(){this.boardSaveTimer!==null&&(clearTimeout(this.boardSaveTimer),this.boardSaveTimer=null),this.saveBoard().then(t=>{var e,n;t&&((n=(e=this.options).onExit)==null||n.call(e))})}startEmbedSelection(){Ze.begin(this.root,t=>{t&&this.copyEmbedSnippet(t)})}async copyEmbedSnippet(t){const e=this.state.viewport,n=L(t.x,t.y,e),s=L(t.x+t.w,t.y+t.h,e),o=Math.round(n.x),a=Math.round(n.y),r=Math.round(s.x-n.x),c=Math.round(s.y-n.y),l=`\`\`\`board
|
|
14
14
|
src: /${this.state.boardId}
|
|
15
15
|
region: ${o}, ${a}, ${r}, ${c}
|
|
16
16
|
height: 360
|
|
17
17
|
title: ${this.state.title}
|
|
18
|
-
\`\`\``;try{await navigator.clipboard.writeText(l),C("Embed snippet copied — paste it into any doc")}catch{C("Could not access clipboard")}}setupDragDrop(t){t.addEventListener("dragover",e=>{e.preventDefault(),e.dataTransfer&&(e.dataTransfer.dropEffect="copy")}),t.addEventListener("drop",e=>{var n;e.preventDefault(),(n=e.dataTransfer)!=null&&n.files&&e.dataTransfer.files.length>0&&this.imageInsert.insertFiles(e.dataTransfer.files,e.clientX,e.clientY)})}async loadInitialState(){this.suppressPersistence=!0;const t=tt.getPref("theme");if(t==="dark"||t==="light"?this.applyTheme(t):window.matchMedia("(prefers-color-scheme: dark)").matches&&this.applyTheme("dark"),this.options.loadBoard){try{const n=await this.options.loadBoard(this.options.boardId??this.state.boardId);n&&(this.revision=n.revision,this.stale=!1,this.applyDocument(n.doc),this.fitInitialRegion())}catch(n){console.error("Board file load failed",n),C("Could not load board file")}finally{this.suppressPersistence=!1}this.state.requestRender();return}const e=tt.getPref("lastBoardId")??"default-board";try{const n=await tt.loadBoard(e);n&&this.applyDocument(n)}catch(n){console.error("Board recovery failed",n),tt.getPref("recovery")&&C("Could not load saved board — starting fresh")}this.suppressPersistence=!1,this.state.requestRender()}applyDocument(t){this.state.schemaUrl=t.$schema,this.state.boardId=t.id,this.state.title=t.title,this.state.createdAt=t.createdAt,this.state.viewport={...t.viewport},this.state.elements=[],this.state.elementsById.clear();for(const e of t.elements)this.state.addElement(e);this.applyTheme(t.theme),this.topControls.setTitle(t.title),this.topControls.setZoom(t.viewport.scale),this.state.invalidateSort()}fitInitialRegion(){const t=this.options.initialRegion;if(!t)return;const[e,n,s,o]=t;if(s<=0||o<=0)return;const a=Math.min(120,Math.max(48,this.surface.width*.08)),r=88,c=124,l=Math.max(240,this.surface.width-a*2),d=Math.max(180,this.surface.height-r-c),h=Math.min(l/s,d/o),p=Math.max(.7,Math.min(1.1,this.state.viewport.scale*1.15)),m=is(Math.min(h*.58,p));this.state.viewport={scale:m,offsetX:a+(l-s*m)/2-e*m,offsetY:r+(d-o*m)/2-n*m},this.topControls.setZoom(m)}scheduleBoardSave(){this.boardSaveTimer!==null&&clearTimeout(this.boardSaveTimer),this.boardSaveTimer=window.setTimeout(()=>{this.boardSaveTimer=null,this.saveBoard()},Do)}scheduleViewportSave(){this.viewportSaveTimer===null&&(this.viewportSaveTimer=window.setTimeout(()=>{this.viewportSaveTimer=null,this.saveBoard()},Ao))}async saveBoard(){if(this.saveInFlight)return this.saveQueued=!0,this.saveInFlight;const t=async()=>{if(this.stale)return C("Board changed elsewhere — reload before saving"),this.setBoardStatus("Changed elsewhere","stale"),!1;try{return this.options.saveBoard?(this.revision=await this.options.saveBoard(ce(this.state)),this.stale=!1,this.setBoardStatus("Saved","saved")):await tt.saveBoard(ce(this.state)),!0}catch(n){return n instanceof se?(this.revision=n.currentRevision,this.stale=!0,this.setBoardStatus("Changed elsewhere","stale"),C("Board changed elsewhere — reload before saving"),!1):(C(this.options.saveBoard?"Save to file failed":"Save failed — browser storage may be full"),this.options.saveBoard&&this.setBoardStatus("Save failed","error"),!1)}};this.saveInFlight=t();const e=await this.saveInFlight;return this.saveInFlight=null,this.saveQueued&&!this.stale?(this.saveQueued=!1,this.saveBoard()):(this.saveQueued=!1,e)}markStale(){this.stale=!0,this.setBoardStatus("Changed elsewhere","stale")}async reloadLatest(){if(this.options.loadBoard&&window.confirm("Discard local edits and reload the latest board version?"))try{this.suppressPersistence=!0;const t=await this.options.loadBoard(this.options.boardId??this.state.boardId);if(!t){C("Could not reload board file"),this.suppressPersistence=!1;return}this.revision=t.revision,this.stale=!1,this.applyDocument(t.doc),this.state.requestRender(),this.setBoardStatus("Reloaded latest","saved")}catch{this.setBoardStatus("Reload failed","error"),C("Could not reload board file")}finally{this.suppressPersistence=!1}}setBoardStatus(t,e){var n;(n=this.topControls)==null||n.setStatus(t,e,e==="stale"&&this.options.loadBoard?{label:"Reload latest",onClick:()=>void this.reloadLatest()}:void 0)}applyTheme(t){var e;this.state.theme=t,document.documentElement.setAttribute("data-theme",t),tt.setPref("theme",t),(e=this.toolbar)==null||e.setTheme(t),this.state.requestRender()}toggleTheme(){this.applyTheme(this.state.theme==="dark"?"light":"dark"),this.scheduleBoardSave()}resetView(){this.state.viewport.offsetX=0,this.state.viewport.offsetY=0,this.state.viewport.scale=ss,this.state.requestRender()}clearBoard(){const t=this.state,e=[...t.elements];this.commands.execute("clear-board",()=>{for(const n of e)t.removeElement(n.id);t.emitChange()},()=>{for(const n of e)t.elementsById.has(n.id)||t.addElement(n);t.emitChange()}),C("Board cleared")}async resetAllLocalData(){await tt.clearAllBoards(),await it.clearAll(),tt.clearPrefs(),this.imageCache.clear(),this.commands.clear(),this.state.elements=[],this.state.elementsById.clear(),this.state.clearSelection(),this.state.invalidateSort(),this.resetView(),C("All local data cleared")}confirmDeleteBoard(){_("Delete board?",(t,e)=>{const n=document.createElement("p");n.className="modal-copy",n.textContent=`This will permanently delete "${this.state.title}" from the active docs root. This cannot be undone.`;const s=document.createElement("div");s.className="modal-actions";const o=document.createElement("button");o.className="btn",o.textContent="Cancel",o.addEventListener("click",e);const a=document.createElement("button");a.className="btn danger",a.textContent="Delete board",a.addEventListener("click",async()=>{var r,c,l;a.disabled=!0,this.boardSaveTimer!==null&&(clearTimeout(this.boardSaveTimer),this.boardSaveTimer=null),this.viewportSaveTimer!==null&&(clearTimeout(this.viewportSaveTimer),this.viewportSaveTimer=null);try{await((c=(r=this.options).deleteBoard)==null?void 0:c.call(r,this.state.boardId)),e(),C("Board deleted"),(l=this.options.onDeleted??this.options.onExit)==null||l()}catch{a.disabled=!1,C("Could not delete board")}}),s.append(o,a),t.append(n,s)})}openExportMenu(){_("Export & import",(t,e)=>{const n=document.createElement("div");n.className="modal-actions",n.style.flexDirection="column",n.style.alignItems="stretch";const s=(o,a,r=!1)=>{const c=document.createElement("button");c.className="btn"+(r?" primary":""),c.textContent=o,c.addEventListener("click",()=>{a(),e()}),n.appendChild(c)};s("Export current view as PNG",async()=>{const o=await zi(this.state,this.imageCache,this.surface.width,this.surface.height);un(o,this.state.title+"-view.png")},!0),s("Export full board as PNG",async()=>{const o=await Hi(this.state,this.imageCache);o?un(o,this.state.title+"-board.png"):C("Board is empty")}),s("Export board JSON (no images)",()=>{Ne.exportBoardJson(ce(this.state))}),s("Export full bundle (JSON + images)",async()=>{await Ne.exportFullBundle(ce(this.state))}),s("Import board from file…",()=>this.pickImportFile()),t.appendChild(n)})}pickImportFile(){const t=document.createElement("input");t.type="file",t.accept="application/json,.json",t.onchange=async()=>{var s;const e=(s=t.files)==null?void 0:s[0];if(!e)return;const n=await Ne.importFromFile(e);if(!n){C("Import failed — invalid board file");return}this.state.boardId=n.id,this.state.title=n.title,this.state.createdAt=n.createdAt,this.state.viewport={...n.viewport},this.state.elements=[],this.state.elementsById.clear(),this.state.clearSelection();for(const o of n.elements)this.state.addElement(o);this.applyTheme(n.theme),this.topControls.setTitle(n.title),this.commands.clear(),this.state.emitChange(),C("Board imported")},t.click()}}const xn="/__api/asset?path=",ds=new Set(["P","DIV","UL","OL","H1","H2","H3","H4","H5","H6","BLOCKQUOTE","PRE","TABLE","FIGURE","HR"]);function Wo(i){const t=[];for(const e of Array.from(i.childNodes))
|
|
18
|
+
\`\`\``;try{await navigator.clipboard.writeText(l),C("Embed snippet copied — paste it into any doc")}catch{C("Could not access clipboard")}}setupDragDrop(t){t.addEventListener("dragover",e=>{e.preventDefault(),e.dataTransfer&&(e.dataTransfer.dropEffect="copy")}),t.addEventListener("drop",e=>{var n;e.preventDefault(),(n=e.dataTransfer)!=null&&n.files&&e.dataTransfer.files.length>0&&this.imageInsert.insertFiles(e.dataTransfer.files,e.clientX,e.clientY)})}async loadInitialState(){this.suppressPersistence=!0;const t=tt.getPref("theme");if(t==="dark"||t==="light"?this.applyTheme(t):window.matchMedia("(prefers-color-scheme: dark)").matches&&this.applyTheme("dark"),this.options.loadBoard){try{const n=await this.options.loadBoard(this.options.boardId??this.state.boardId);n&&(this.revision=n.revision,this.stale=!1,this.applyDocument(n.doc),this.fitInitialRegion())}catch(n){console.error("Board file load failed",n),C("Could not load board file")}finally{this.suppressPersistence=!1}this.state.requestRender();return}const e=tt.getPref("lastBoardId")??"default-board";try{const n=await tt.loadBoard(e);n&&this.applyDocument(n)}catch(n){console.error("Board recovery failed",n),tt.getPref("recovery")&&C("Could not load saved board — starting fresh")}this.suppressPersistence=!1,this.state.requestRender()}applyDocument(t){this.state.schemaUrl=t.$schema,this.state.boardId=t.id,this.state.title=t.title,this.state.createdAt=t.createdAt,this.state.viewport={...t.viewport},this.state.elements=[],this.state.elementsById.clear();for(const e of t.elements)this.state.addElement(e);this.applyTheme(t.theme),this.topControls.setTitle(t.title),this.topControls.setZoom(t.viewport.scale),this.state.invalidateSort()}fitInitialRegion(){const t=this.options.initialRegion;if(!t)return;const[e,n,s,o]=t;if(s<=0||o<=0)return;const a=Math.min(120,Math.max(48,this.surface.width*.08)),r=88,c=124,l=Math.max(240,this.surface.width-a*2),d=Math.max(180,this.surface.height-r-c),h=Math.min(l/s,d/o),p=Math.max(.7,Math.min(1.1,this.state.viewport.scale*1.15)),m=is(Math.min(h*.58,p));this.state.viewport={scale:m,offsetX:a+(l-s*m)/2-e*m,offsetY:r+(d-o*m)/2-n*m},this.topControls.setZoom(m)}scheduleBoardSave(){this.boardSaveTimer!==null&&clearTimeout(this.boardSaveTimer),this.boardSaveTimer=window.setTimeout(()=>{this.boardSaveTimer=null,this.saveBoard()},Do)}scheduleViewportSave(){this.viewportSaveTimer===null&&(this.viewportSaveTimer=window.setTimeout(()=>{this.viewportSaveTimer=null,this.saveBoard()},Ao))}async saveBoard(){if(this.saveInFlight)return this.saveQueued=!0,this.saveInFlight;const t=async()=>{if(this.stale)return C("Board changed elsewhere — reload before saving"),this.setBoardStatus("Changed elsewhere","stale"),!1;try{return this.options.saveBoard?(this.revision=await this.options.saveBoard(ce(this.state)),this.stale=!1,this.setBoardStatus("Saved","saved")):await tt.saveBoard(ce(this.state)),!0}catch(n){return n instanceof se?(this.revision=n.currentRevision,this.stale=!0,this.setBoardStatus("Changed elsewhere","stale"),C("Board changed elsewhere — reload before saving"),!1):(C(this.options.saveBoard?"Save to file failed":"Save failed — browser storage may be full"),this.options.saveBoard&&this.setBoardStatus("Save failed","error"),!1)}};this.saveInFlight=t();const e=await this.saveInFlight;return this.saveInFlight=null,this.saveQueued&&!this.stale?(this.saveQueued=!1,this.saveBoard()):(this.saveQueued=!1,e)}markStale(){this.stale=!0,this.setBoardStatus("Changed elsewhere","stale")}async reloadLatest(){if(this.options.loadBoard&&window.confirm("Discard local edits and reload the latest board version?"))try{this.suppressPersistence=!0;const t=await this.options.loadBoard(this.options.boardId??this.state.boardId);if(!t){C("Could not reload board file"),this.suppressPersistence=!1;return}this.revision=t.revision,this.stale=!1,this.applyDocument(t.doc),this.state.requestRender(),this.setBoardStatus("Reloaded latest","saved")}catch{this.setBoardStatus("Reload failed","error"),C("Could not reload board file")}finally{this.suppressPersistence=!1}}setBoardStatus(t,e){var n;(n=this.topControls)==null||n.setStatus(t,e,e==="stale"&&this.options.loadBoard?{label:"Reload latest",onClick:()=>void this.reloadLatest()}:void 0)}applyTheme(t){var e;this.state.theme=t,document.documentElement.setAttribute("data-theme",t),tt.setPref("theme",t),(e=this.toolbar)==null||e.setTheme(t),this.state.requestRender()}toggleTheme(){this.applyTheme(this.state.theme==="dark"?"light":"dark"),this.scheduleBoardSave()}resetView(){this.state.viewport.offsetX=0,this.state.viewport.offsetY=0,this.state.viewport.scale=ss,this.state.requestRender()}clearBoard(){const t=this.state,e=[...t.elements];this.commands.execute("clear-board",()=>{for(const n of e)t.removeElement(n.id);t.emitChange()},()=>{for(const n of e)t.elementsById.has(n.id)||t.addElement(n);t.emitChange()}),C("Board cleared")}async resetAllLocalData(){await tt.clearAllBoards(),await it.clearAll(),tt.clearPrefs(),this.imageCache.clear(),this.commands.clear(),this.state.elements=[],this.state.elementsById.clear(),this.state.clearSelection(),this.state.invalidateSort(),this.resetView(),C("All local data cleared")}confirmDeleteBoard(){_("Delete board?",(t,e)=>{const n=document.createElement("p");n.className="modal-copy",n.textContent=`This will permanently delete "${this.state.title}" from the active docs root. This cannot be undone.`;const s=document.createElement("div");s.className="modal-actions";const o=document.createElement("button");o.className="btn",o.textContent="Cancel",o.addEventListener("click",e);const a=document.createElement("button");a.className="btn danger",a.textContent="Delete board",a.addEventListener("click",async()=>{var r,c,l;a.disabled=!0,this.boardSaveTimer!==null&&(clearTimeout(this.boardSaveTimer),this.boardSaveTimer=null),this.viewportSaveTimer!==null&&(clearTimeout(this.viewportSaveTimer),this.viewportSaveTimer=null);try{await((c=(r=this.options).deleteBoard)==null?void 0:c.call(r,this.state.boardId)),e(),C("Board deleted"),(l=this.options.onDeleted??this.options.onExit)==null||l()}catch{a.disabled=!1,C("Could not delete board")}}),s.append(o,a),t.append(n,s)})}openExportMenu(){_("Export & import",(t,e)=>{const n=document.createElement("div");n.className="modal-actions",n.style.flexDirection="column",n.style.alignItems="stretch";const s=(o,a,r=!1)=>{const c=document.createElement("button");c.className="btn"+(r?" primary":""),c.textContent=o,c.addEventListener("click",()=>{a(),e()}),n.appendChild(c)};s("Export current view as PNG",async()=>{const o=await zi(this.state,this.imageCache,this.surface.width,this.surface.height);un(o,this.state.title+"-view.png")},!0),s("Export full board as PNG",async()=>{const o=await Hi(this.state,this.imageCache);o?un(o,this.state.title+"-board.png"):C("Board is empty")}),s("Export board JSON (no images)",()=>{Ne.exportBoardJson(ce(this.state))}),s("Export full bundle (JSON + images)",async()=>{await Ne.exportFullBundle(ce(this.state))}),s("Import board from file…",()=>this.pickImportFile()),t.appendChild(n)})}pickImportFile(){const t=document.createElement("input");t.type="file",t.accept="application/json,.json",t.onchange=async()=>{var s;const e=(s=t.files)==null?void 0:s[0];if(!e)return;const n=await Ne.importFromFile(e);if(!n){C("Import failed — invalid board file");return}this.state.boardId=n.id,this.state.title=n.title,this.state.createdAt=n.createdAt,this.state.viewport={...n.viewport},this.state.elements=[],this.state.elementsById.clear(),this.state.clearSelection();for(const o of n.elements)this.state.addElement(o);this.applyTheme(n.theme),this.topControls.setTitle(n.title),this.commands.clear(),this.state.emitChange(),C("Board imported")},t.click()}}const xn="/__api/asset?path=",ds=new Set(["P","DIV","UL","OL","H1","H2","H3","H4","H5","H6","BLOCKQUOTE","PRE","TABLE","FIGURE","HR"]);function Wo(i){const t=[];for(const e of Array.from(i.childNodes))Je(t,e);return t.map(e=>e.replace(/[ \t]+$/gm,"")).join(`
|
|
19
19
|
|
|
20
20
|
`).replace(/\n{3,}/g,`
|
|
21
21
|
|
|
22
22
|
`).trim()+`
|
|
23
|
-
`}function
|
|
23
|
+
`}function Je(i,t){const e=Oo(t);e!==null&&e.trim()!==""&&i.push(e)}function Oo(i){if(i.nodeType===Node.TEXT_NODE){const n=(i.textContent??"").trim();return n||null}if(i.nodeType!==Node.ELEMENT_NODE)return null;const t=i,e=t.tagName;switch(e){case"H1":case"H2":case"H3":case"H4":case"H5":case"H6":return"#".repeat(Number(e[1]))+" "+ft(t).trim();case"HR":return"---";case"P":return t.classList.contains("embed-caret-spacer")&&!_o(t)?null:kn(t)?En(t):Ye(ft(t).trim());case"BLOCKQUOTE":return Cn(t).split(`
|
|
24
24
|
`).map(s=>s?`> ${s}`:">").join(`
|
|
25
25
|
`);case"UL":return ke(t,!1,0);case"OL":return ke(t,!0,0);case"PRE":{const n=t.querySelector("code"),s=Ko(n??t),o=(n??t).textContent??"";return"```"+s+`
|
|
26
|
-
`+o.replace(/\n$/,"")+"\n```"}case"TABLE":return Xo(t);case"FIGURE":return t.classList.contains("board-embed")?qo(t):Cn(t)||null;case"DIV":return kn(t)?En(t):
|
|
26
|
+
`+o.replace(/\n$/,"")+"\n```"}case"TABLE":return Xo(t);case"FIGURE":return t.classList.contains("board-embed")?qo(t):Cn(t)||null;case"DIV":return kn(t)?En(t):Ye(ft(t).trim());case"BR":return null;default:return ft(t).trim()||null}}function Cn(i){const t=[];for(const e of Array.from(i.childNodes))Je(t,e);return t.join(`
|
|
27
27
|
|
|
28
|
-
`)}function kn(i){for(const t of Array.from(i.children))if(ds.has(t.tagName))return!0;return!1}function En(i){const t=[];let e="";const n=()=>{const s=
|
|
28
|
+
`)}function kn(i){for(const t of Array.from(i.children))if(ds.has(t.tagName))return!0;return!1}function En(i){const t=[];let e="";const n=()=>{const s=Ye(e.trim());s&&t.push(s),e=""};for(const s of Array.from(i.childNodes)){if(Uo(s)){n(),Je(t,s);continue}e+=Qe(s)}return n(),t.join(`
|
|
29
29
|
|
|
30
|
-
`)||null}function Uo(i){return i.nodeType===Node.ELEMENT_NODE&&ds.has(i.tagName)}function _o(i){for(const t of Array.from(i.childNodes)){if(t.nodeType===Node.TEXT_NODE&&(t.textContent??"").trim())return!0;if(t.nodeType!==Node.ELEMENT_NODE)continue;const e=t;if(e.tagName!=="BR"&&((e.textContent??"").trim()||["IMG","FIGURE","HR"].includes(e.tagName)))return!0}return!1}function ke(i,t,e){const n=[],s=" ".repeat(e);let o=0;for(const a of Array.from(i.children)){if(a.tagName!=="LI")continue;o++;const r=t?`${o}. `:"- ";let c="";const l=[];let d=null;for(const h of Array.from(a.childNodes)){if(h.nodeType===Node.ELEMENT_NODE){const p=h;if(p.tagName==="UL"){l.push(ke(p,!1,e+1));continue}if(p.tagName==="OL"){l.push(ke(p,!0,e+1));continue}if(p.tagName==="INPUT"){d=p.checked?"[x] ":"[ ] ";continue}}c+=
|
|
30
|
+
`)||null}function Uo(i){return i.nodeType===Node.ELEMENT_NODE&&ds.has(i.tagName)}function _o(i){for(const t of Array.from(i.childNodes)){if(t.nodeType===Node.TEXT_NODE&&(t.textContent??"").trim())return!0;if(t.nodeType!==Node.ELEMENT_NODE)continue;const e=t;if(e.tagName!=="BR"&&((e.textContent??"").trim()||["IMG","FIGURE","HR"].includes(e.tagName)))return!0}return!1}function ke(i,t,e){const n=[],s=" ".repeat(e);let o=0;for(const a of Array.from(i.children)){if(a.tagName!=="LI")continue;o++;const r=t?`${o}. `:"- ";let c="";const l=[];let d=null;for(const h of Array.from(a.childNodes)){if(h.nodeType===Node.ELEMENT_NODE){const p=h;if(p.tagName==="UL"){l.push(ke(p,!1,e+1));continue}if(p.tagName==="OL"){l.push(ke(p,!0,e+1));continue}if(p.tagName==="INPUT"){d=p.checked?"[x] ":"[ ] ";continue}}c+=Qe(h)}n.push(s+r+(d??"")+c.trim());for(const h of l)h&&n.push(h)}return n.join(`
|
|
31
31
|
`)}function Xo(i){const t=Array.from(i.querySelectorAll("tr"));if(t.length===0)return"";const e=o=>Array.from(o.querySelectorAll("th,td")).map(a=>ft(a).trim()),n=e(t[0]),s=[];s.push("| "+n.join(" | ")+" |"),s.push("| "+n.map(()=>"---").join(" | ")+" |");for(let o=1;o<t.length;o++)s.push("| "+e(t[o]).join(" | ")+" |");return s.join(`
|
|
32
32
|
`)}function qo(i){const t=["```board",`src: ${i.dataset.src??""}`];return i.dataset.region&&t.push(`region: ${i.dataset.region.split(",").map(e=>e.trim()).join(", ")}`),i.dataset.height&&t.push(`height: ${i.dataset.height}`),i.dataset.title&&t.push(`title: ${i.dataset.title}`),t.push("```"),t.join(`
|
|
33
|
-
`)}function ft(i){let t="";for(const e of Array.from(i.childNodes))t+=
|
|
34
|
-
`;default:return ft(t)}}function Yo(i){const t=i.getAttribute("data-md-src");if(t)return t;const e=i.getAttribute("src")??"";return e.startsWith(xn)?decodeURIComponent(e.slice(xn.length)):e}function Ko(i){const e=(i.getAttribute("class")??"").match(/language-(\w+)/);return e?e[1]:""}function Sn(i,t){const e=t.trim();return e?`${i}${e}${i}`:""}function Vo(i){if(!i.includes("`"))return"`"+i+"`";const t=Math.max(...(i.match(/`+/g)??[""]).map(n=>n.length)),e="`".repeat(t+1);return`${e} ${i} ${e}`}function Tn(i){return i.replace(/\\/g,"\\\\").replace(/\[/g,"\\[").replace(/\]/g,"\\]").replace(/\*/g,"\\*").replace(/_/g,"\\_").replace(/`/g,"\\`")}function
|
|
33
|
+
`)}function ft(i){let t="";for(const e of Array.from(i.childNodes))t+=Qe(e);return t}function Qe(i){if(i.nodeType===Node.TEXT_NODE)return Tn(i.textContent??"");if(i.nodeType!==Node.ELEMENT_NODE)return"";const t=i;switch(t.tagName){case"STRONG":case"B":return Sn("**",ft(t));case"EM":case"I":return Sn("*",ft(t));case"CODE":return Vo(t.textContent??"");case"A":{const e=(t.getAttribute("data-md-href")??t.getAttribute("href")??"").trim(),n=ft(t).trim()||Tn(e);return e?`[${Bn(n)}](${Mn(e)})`:n}case"IMG":return`)})`;case"BR":return`
|
|
34
|
+
`;default:return ft(t)}}function Yo(i){const t=i.getAttribute("data-md-src");if(t)return t;const e=i.getAttribute("src")??"";return e.startsWith(xn)?decodeURIComponent(e.slice(xn.length)):e}function Ko(i){const e=(i.getAttribute("class")??"").match(/language-(\w+)/);return e?e[1]:""}function Sn(i,t){const e=t.trim();return e?`${i}${e}${i}`:""}function Vo(i){if(!i.includes("`"))return"`"+i+"`";const t=Math.max(...(i.match(/`+/g)??[""]).map(n=>n.length)),e="`".repeat(t+1);return`${e} ${i} ${e}`}function Tn(i){return i.replace(/\\/g,"\\\\").replace(/\[/g,"\\[").replace(/\]/g,"\\]").replace(/\*/g,"\\*").replace(/_/g,"\\_").replace(/`/g,"\\`")}function Ye(i){return i?/^#{1,6}\s/.test(i)||/^>\s?/.test(i)||/^([-+*]|\d+\.)\s+/.test(i)||/^`{3,}/.test(i)||/^(-{3,}|\*{3,}|_{3,})$/.test(i)?"\\"+i:i:null}function Bn(i){return i.replace(/\\/g,"\\\\").replace(/\]/g,"\\]")}function Mn(i){return i.trim().replace(/\s/g,"%20").replace(/\)/g,"%29").replace(/</g,"%3C").replace(/>/g,"%3E")}class tn{constructor(t){u(this,"opts");u(this,"overlay");u(this,"scrollEl");u(this,"surface");u(this,"statusEl");u(this,"statusTextEl");u(this,"reloadBtn");u(this,"fileInput");u(this,"toolbarButtons",[]);u(this,"abort",new AbortController);u(this,"frontmatter","");u(this,"revision",null);u(this,"stale",!1);u(this,"saveTimer",null);u(this,"closed",!1);u(this,"history",[]);u(this,"historyIndex",-1);u(this,"applyingHistory",!1);this.opts=t,this.build(),this.load()}static open(t){return new tn(t)}build(){this.overlay=pt("doc-editor");const t=pt("doc-editor-bar"),e=pt("doc-editor-bar-left"),n=Fe("doc-editor-done","Done");n.addEventListener("click",()=>void this.close());const s=pt("doc-editor-path");s.textContent=this.opts.path,e.append(n,s),this.statusEl=pt("doc-editor-status"),this.statusTextEl=document.createElement("span"),this.reloadBtn=Fe("status-action-btn","Reload latest"),this.reloadBtn.hidden=!0,this.reloadBtn.addEventListener("click",()=>void this.reloadLatest()),this.statusEl.append(this.statusTextEl,this.reloadBtn),this.setStatus("idle"),t.append(e,this.statusEl);const o=this.buildToolbar();this.scrollEl=pt("doc-editor-scroll"),this.surface=pt("markdown-body doc-editor-surface"),this.surface.contentEditable="true",this.surface.spellcheck=!0,this.scrollEl.appendChild(this.surface),this.fileInput=document.createElement("input"),this.fileInput.type="file",this.fileInput.accept="image/*",this.fileInput.style.display="none",this.fileInput.addEventListener("change",()=>{var c;const r=(c=this.fileInput.files)==null?void 0:c[0];r&&this.insertImageFile(r),this.fileInput.value=""}),this.overlay.append(t,o,this.scrollEl,this.fileInput),document.body.appendChild(this.overlay);const a=this.abort.signal;this.surface.addEventListener("input",()=>this.handleInput(),{signal:a}),this.surface.addEventListener("keyup",()=>this.updateToolbarState(),{signal:a}),this.surface.addEventListener("mouseup",()=>this.updateToolbarState(),{signal:a}),this.surface.addEventListener("click",r=>this.handleSurfaceClick(r),{signal:a}),document.addEventListener("selectionchange",()=>this.updateToolbarState(),{signal:a}),this.surface.addEventListener("paste",r=>this.onPaste(r),{signal:a}),this.surface.addEventListener("dragover",r=>r.preventDefault(),{signal:a}),this.surface.addEventListener("drop",r=>this.onDrop(r),{signal:a}),window.addEventListener("keydown",r=>{if(r.key==="Escape"&&document.activeElement!==this.surface&&this.close(),(r.metaKey||r.ctrlKey)&&r.key.toLowerCase()==="s"&&(r.preventDefault(),this.save()),(r.metaKey||r.ctrlKey)&&r.key.toLowerCase()==="z"){r.preventDefault(),r.shiftKey?this.redoHistory():this.undoHistory();return}if(r.ctrlKey&&!r.metaKey&&r.key.toLowerCase()==="y"){r.preventDefault(),this.redoHistory();return}this.handleEmbedDeleteKey(r)},{signal:a})}buildToolbar(){const t=pt("doc-editor-toolbar"),e=s=>{const o=pt("doc-editor-tb-group");return o.append(...s),o},n=(s,o,a,r=!1)=>{const c=Fe("doc-editor-tb-btn",r?"":s);return r&&(c.innerHTML=V[s]??"",c.classList.add("icon")),c.title=o,c.addEventListener("mousedown",l=>{l.preventDefault(),this.surface.focus(),a(),this.updateToolbarState(),this.scheduleSave()}),this.toolbarButtons.push(c),c};return t.append(e([n("¶","Paragraph",()=>this.formatBlock("P")),ut(n("H1","Heading 1",()=>this.formatBlock("H1")),"block","H1"),ut(n("H2","Heading 2",()=>this.formatBlock("H2")),"block","H2"),ut(n("H3","Heading 3",()=>this.formatBlock("H3")),"block","H3")]),e([ut(n("B","Bold (Cmd+B)",()=>document.execCommand("bold")),"command","bold"),ut(n("I","Italic (Cmd+I)",()=>document.execCommand("italic")),"command","italic"),ut(n("</>","Inline code",()=>this.toggleInlineCode()),"inline","CODE")]),e([ut(n("❝","Quote",()=>this.formatBlock("BLOCKQUOTE")),"block","BLOCKQUOTE"),ut(n("•","Bulleted list",()=>document.execCommand("insertUnorderedList")),"command","insertUnorderedList"),ut(n("1.","Numbered list",()=>document.execCommand("insertOrderedList")),"command","insertOrderedList"),n("{ }","Code block",()=>this.insertCodeBlock())]),e([n("↗","Link",()=>this.insertLink()),n("image","Image",()=>this.fileInput.click(),!0),n("―","Divider",()=>document.execCommand("insertHorizontalRule"))])),t}async load(t=this.opts.initialScrollTop??0,e=this.opts.initialScrollProgress){try{const n=await k.readFileWithRevision(this.opts.rootId,this.opts.path);this.revision=n.revision,this.stale=!1;const s=n.content,{fm:o,body:a}=Zo(s);this.frontmatter=o;const{html:r}=ne(a,{rootId:this.opts.rootId,docPath:this.opts.path});this.surface.innerHTML=r||"<p></p>",this.decorateEmbeds(),document.execCommand("defaultParagraphSeparator",!1,"p"),this.recordHistorySnapshot(!0),this.updateToolbarState(),this.setStatus("idle"),requestAnimationFrame(()=>{if(!this.closed){if(typeof e=="number"){Go(this.scrollEl,e);return}this.scrollEl.scrollTop=t}})}catch{this.surface.innerHTML="<p></p>",this.setStatus("error","Could not load file");return}}decorateEmbeds(){this.normalizeEmbedSpacing(),this.surface.querySelectorAll("figure.board-embed").forEach(t=>{t.contentEditable="false",t.tabIndex=0,t.setAttribute("role","button"),t.setAttribute("aria-label",`Board embed ${t.dataset.src??""}. Press Delete to remove.`),t.classList.add("embed-chip");const e=t.dataset.region?" · region":"";t.innerHTML=`<span class="embed-chip-icon">▦</span> Board embed: <strong>${t.dataset.src??""}</strong>${e}<span class="embed-chip-remove" aria-hidden="true">Delete</span>`,this.ensureEmbedCaretSpace(t)})}ensureEmbedCaretSpace(t){Tt(t.previousElementSibling)||t.before(Zt()),Tt(t.nextElementSibling)||t.after(Zt())}normalizeEmbedSpacing(){const t=Array.from(this.surface.querySelectorAll("figure.board-embed"));for(const n of t)In(n.previousElementSibling),In(n.nextElementSibling);let e=!1;for(const n of Array.from(this.surface.children)){if(!Tt(n)){e=!1;continue}if(hs(n)){n.classList.remove("embed-caret-spacer"),e=!1;continue}if(e){n.remove();continue}e=!0}}handleSurfaceClick(t){const e=t.target,n=e==null?void 0:e.closest("figure.board-embed.embed-chip");!n||!this.surface.contains(n)||(t.preventDefault(),this.selectEmbed(n))}selectEmbed(t){this.surface.querySelectorAll(".embed-chip.selected").forEach(s=>s.classList.remove("selected")),t.classList.add("selected");const e=document.createRange();e.selectNode(t);const n=window.getSelection();n==null||n.removeAllRanges(),n==null||n.addRange(e),t.focus()}clearEmbedSelection(){this.surface.querySelectorAll(".embed-chip.selected").forEach(t=>t.classList.remove("selected"))}handleEmbedDeleteKey(t){if(t.key!=="Backspace"&&t.key!=="Delete")return!1;const e=document.activeElement,s=(e==null?void 0:e.closest("figure.board-embed.embed-chip.selected"))??this.surface.querySelector("figure.board-embed.embed-chip.selected")??this.embedAdjacentToCaret(t.key);if(!s||!this.surface.contains(s))return!1;t.preventDefault();const o=t.key==="Backspace"?s.previousElementSibling:s.nextElementSibling;return s.remove(),this.clearEmbedSelection(),this.placeCaretInBlock(Tt(o)?o:this.surface),this.recordHistorySnapshot(),this.scheduleSave(),!0}embedAdjacentToCaret(t){const e=window.getSelection();if(!e||e.rangeCount===0||!e.isCollapsed)return null;const n=e.anchorNode,s=Jo(n,"P");if(!s||!this.surface.contains(s)||!Tt(s))return null;const o=t==="Backspace"?s.previousElementSibling:s.nextElementSibling;return o instanceof HTMLElement&&o.matches("figure.board-embed.embed-chip")?o:null}handleInput(){this.applyingHistory||(this.clearEmbedSelection(),this.recordHistorySnapshot(),this.scheduleSave())}placeCaretInBlock(t){const e=document.createRange();e.selectNodeContents(t),e.collapse(!1);const n=window.getSelection();n==null||n.removeAllRanges(),n==null||n.addRange(e),this.surface.focus()}scheduleSave(){this.normalizeEmbedSpacing(),this.saveTimer!==null&&clearTimeout(this.saveTimer),this.setStatus("saving"),this.saveTimer=window.setTimeout(()=>{this.saveTimer=null,this.save()},700)}async save(){if(this.saveTimer!==null&&(clearTimeout(this.saveTimer),this.saveTimer=null),this.stale)return this.setStatus("stale","Changed elsewhere — reload before saving"),!1;this.normalizeEmbedSpacing();const t=Wo(this.surface),e=this.frontmatter?`${this.frontmatter}
|
|
35
35
|
|
|
36
|
-
${t}`:t;try{return this.setStatus("saving"),this.revision=await k.writeFile(this.opts.rootId,this.opts.path,e,this.revision??void 0),this.stale=!1,this.setStatus("saved"),!0}catch(n){return n instanceof se?(this.revision=n.currentRevision,this.stale=!0,this.setStatus("stale","Changed elsewhere — reload before saving"),!1):(this.setStatus("error","Save failed"),!1)}}async close(){if(this.closed||!await this.save())return;this.closed=!0;const e=this.scrollEl.scrollTop,n=Rn(this.scrollEl);this.abort.abort(),this.overlay.remove(),this.opts.onClose(e,n)}markStale(){this.stale=!0,this.setStatus("stale","Changed elsewhere — reload before saving")}async reloadLatest(){window.confirm("Discard local edits and reload the latest version?")&&(this.saveTimer!==null&&(clearTimeout(this.saveTimer),this.saveTimer=null),await this.load(this.scrollEl.scrollTop,Rn(this.scrollEl)))}formatBlock(t){document.execCommand("formatBlock",!1,`<${t}>`)}insertLink(){const t=window.getSelection(),e=t&&!t.isCollapsed?t.toString().trim():"",n=window.prompt("Link URL","https://");if(!n)return;const s=n.trim();s&&(e?document.execCommand("createLink",!1,s):document.execCommand("insertHTML",!1,`<a href="${$n(s)}">${sa(s)}</a>`))}toggleInlineCode(){const t=window.getSelection();if(!t||t.rangeCount===0||t.isCollapsed)return;const e=t.getRangeAt(0),n=je(e.commonAncestorContainer,"CODE");if(n){const o=n.parentNode;for(;n.firstChild;)o.insertBefore(n.firstChild,n);o.removeChild(n);return}const s=document.createElement("code");s.appendChild(e.extractContents()),e.insertNode(s),e.setStartAfter(s),e.collapse(!0),t.removeAllRanges(),t.addRange(e)}insertCodeBlock(){document.execCommand("insertHTML",!1,'<pre class="code-block"><code>code</code></pre><p><br></p>')}updateToolbarState(){const t=window.getSelection(),e=(t==null?void 0:t.anchorNode)??null,n=!!e&&this.surface.contains(e);for(const s of this.toolbarButtons){const o=s.dataset.stateType,a=s.dataset.stateValue;let r=!1;if(n&&o==="command"&&a)try{r=document.queryCommandState(a)}catch{r=!1}else(n&&o==="block"&&a||n&&o==="inline"&&a)&&(r=!!je(e,a));s.classList.toggle("active",r),s.setAttribute("aria-pressed",r?"true":"false")}}onPaste(t){var s,o;const e=oa(((s=t.clipboardData)==null?void 0:s.getData("text/plain"))??"");if(e){t.preventDefault(),this.insertSpecialBlock(e);return}const n=(o=t.clipboardData)==null?void 0:o.items;if(n){for(const a of n)if(a.type.startsWith("image/")){const r=a.getAsFile();if(r){t.preventDefault(),this.insertImageFile(r);return}}}}insertSpecialBlock(t){this.surface.focus();const e=ra(t);this.insertBlockNode(e),this.decorateEmbeds(),this.selectEmbed(e),this.recordHistorySnapshot(),this.updateToolbarState(),this.scheduleSave()}insertBlockNode(t){const e=window.getSelection(),n=e&&e.rangeCount>0?e.getRangeAt(0):null;if(!n||!this.surface.contains(n.commonAncestorContainer)){this.surface.append(t,Zt()),this.placeCaretInBlock(this.surface.lastElementChild??this.surface);return}const s=Qo(this.surface,n.commonAncestorContainer);if(s&&ta(s)&&!Tt(s)){this.replaceBlockWithInsertedNode(s,n,t);return}n.deleteContents();const o=Zt();n.insertNode(o),n.insertNode(t),this.placeCaretInBlock(o)}replaceBlockWithInsertedNode(t,e,n){const s=document.createRange();s.selectNodeContents(t),s.setEnd(e.startContainer,e.startOffset);const o=document.createRange();o.selectNodeContents(t),o.setStart(e.endContainer,e.endOffset);const a=Ln(t,s.cloneContents()),r=Ln(t,o.cloneContents()),c=t.parentNode;if(!c)return;a&&c.insertBefore(a,t),c.insertBefore(n,t),r&&c.insertBefore(r,t),c.removeChild(t);const l=r??Zt();r||c.insertBefore(l,n.nextSibling),this.placeCaretInBlock(l)}onDrop(t){var n,s;const e=(s=(n=t.dataTransfer)==null?void 0:n.files)==null?void 0:s[0];e&&e.type.startsWith("image/")&&(t.preventDefault(),this.insertImageFile(e))}async insertImageFile(t){this.setStatus("saving","Uploading image…");try{const e=await na(t),n=await k.uploadAsset(this.opts.rootId,t.name,e),s=
|
|
37
|
-
---`,3);if(t===-1)return{fm:"",body:i};const e=i.slice(0,t+4),n=i.slice(t+4).replace(/^\n+/,"");return{fm:e,body:n}}function je(i,t){let e=i;for(;e;){if(e.nodeType===Node.ELEMENT_NODE&&e.tagName===t)return e;e=e.parentNode}return null}function Jo(i,t){let e=i;for(;e;){if(e.nodeType===Node.ELEMENT_NODE&&e.matches(t))return e;e=e.parentNode}return null}function Qo(i,t){let e=t;for(;e&&e.parentNode!==i;)e=e.parentNode;return e instanceof HTMLElement?e:null}function ta(i){return i.tagName==="P"||i.tagName==="DIV"}function Ln(i,t){if(!ea(t))return null;const e=document.createElement(i.tagName);return i.tagName==="P"&&i.classList.contains("embed-caret-spacer")&&(e.className="embed-caret-spacer"),e.appendChild(t),e}function ea(i){for(const t of Array.from(i.childNodes)){if(t.nodeType===Node.TEXT_NODE&&(t.textContent??"").trim())return!0;if(t.nodeType!==Node.ELEMENT_NODE)continue;const e=t;if(e.tagName!=="BR"&&!(e.tagName==="P"&&e.classList.contains("embed-caret-spacer"))&&((e.textContent??"").trim()||["IMG","FIGURE","HR"].includes(e.tagName)))return!0}return!1}function na(i){return new Promise((t,e)=>{const n=new FileReader;n.onload=()=>{const s=n.result;t(s.slice(s.indexOf(",")+1))},n.onerror=()=>e(n.error),n.readAsDataURL(i)})}function $n(i){return i.replace(/&/g,"&").replace(/"/g,""").replace(/</g,"<")}function sa(i){return i.replace(/&/g,"&").replace(/</g,"<").replace(/>/g,">")}const ia={board:i=>{const t=ts(i);return t.src?{kind:"board",src:t.src,region:t.region,height:t.height,title:t.title}:null}};function oa(i){const t=aa(i);if(!t)return null;const e=ia[t.language];return e?e(t.body):null}function aa(i){const e=i.trim().match(/^(`{3,})\s*([^\s`]+)?\s*\n([\s\S]*?)\n\1\s*$/);return e?{language:(e[2]??"").toLowerCase(),body:e[3]}:null}function ra(i){switch(i.kind){case"board":return ca(i)}}function ca(i){const t=document.createElement("figure");return t.className="board-embed",t.dataset.src=i.src,t.dataset.height=String(i.height),i.region&&(t.dataset.region=i.region.join(",")),i.title&&(t.dataset.title=i.title),t}class tn{constructor(t){u(this,"opts");u(this,"root");u(this,"statusEl");u(this,"statusTextEl");u(this,"reloadBtn");u(this,"textarea");u(this,"abort",new AbortController);u(this,"revision",null);u(this,"stale",!1);u(this,"saveTimer",null);u(this,"closed",!1);this.opts=t,this.build(),this.load()}static open(t){return new tn(t)}build(){this.root=zt("doc-editor text-file-editor");const t=zt("doc-editor-bar"),e=zt("doc-editor-bar-left"),n=Pn("doc-editor-done","Done");n.addEventListener("click",()=>void this.close());const s=zt("doc-editor-path");s.textContent=this.opts.path,e.append(n,s),this.statusEl=zt("doc-editor-status"),this.statusTextEl=document.createElement("span"),this.reloadBtn=Pn("status-action-btn","Reload latest"),this.reloadBtn.hidden=!0,this.reloadBtn.addEventListener("click",()=>void this.reloadLatest()),this.statusEl.append(this.statusTextEl,this.reloadBtn),this.setStatus("idle"),t.append(e,this.statusEl);const o=zt("doc-editor-scroll text-file-editor-scroll");this.textarea=document.createElement("textarea"),this.textarea.className="text-file-editor-textarea",this.textarea.spellcheck=!1,o.appendChild(this.textarea),this.root.append(t,o),this.opts.host.appendChild(this.root);const a=this.abort.signal;this.textarea.addEventListener("input",()=>this.scheduleSave(),{signal:a}),window.addEventListener("keydown",r=>{if((r.metaKey||r.ctrlKey)&&r.key.toLowerCase()==="s"){r.preventDefault(),this.save();return}r.key==="Escape"&&document.activeElement!==this.textarea&&this.close()},{signal:a})}async load(){try{const t=await k.readFileWithRevision(this.opts.rootId,this.opts.path);this.revision=t.revision,this.stale=!1,this.textarea.value=t.content,this.setStatus("idle"),requestAnimationFrame(()=>this.textarea.focus())}catch{this.textarea.value="",this.setStatus("error","Could not load file")}}scheduleSave(){this.saveTimer!==null&&clearTimeout(this.saveTimer),this.setStatus("saving"),this.saveTimer=window.setTimeout(()=>{this.saveTimer=null,this.save()},700)}async save(){if(this.saveTimer!==null&&(clearTimeout(this.saveTimer),this.saveTimer=null),this.stale)return this.setStatus("stale","Changed elsewhere — reload before saving"),!1;try{return this.setStatus("saving"),this.revision=await k.writeFile(this.opts.rootId,this.opts.path,this.textarea.value,this.revision??void 0),this.stale=!1,this.setStatus("saved"),!0}catch(t){return t instanceof se?(this.revision=t.currentRevision,this.stale=!0,this.setStatus("stale","Changed elsewhere — reload before saving"),!1):(this.setStatus("error","Save failed"),!1)}}async close(){return this.closed?!0:await this.save()?(this.closed=!0,this.abort.abort(),this.root.remove(),this.opts.onClose(),!0):!1}destroy(){this.saveTimer!==null&&clearTimeout(this.saveTimer),this.saveTimer=null,this.closed=!0,this.abort.abort(),this.root.remove()}async reloadLatest(){window.confirm("Discard local edits and reload the latest version?")&&(this.saveTimer!==null&&(clearTimeout(this.saveTimer),this.saveTimer=null),await this.load())}setStatus(t,e){const n={idle:e??"Ready",saving:e??"Saving…",saved:e??"Saved",error:e??"Save failed",stale:e??"Changed elsewhere"};this.statusEl.dataset.state=t,this.statusTextEl.textContent=n[t],this.reloadBtn.hidden=t!=="stale"}}function zt(i){const t=document.createElement("div");return t.className=i,t}function Pn(i,t){const e=document.createElement("button");return e.className=i,e.type="button",e.textContent=t,e}const Dn="docs:theme",An="docs:sidebar-collapsed",Nn="docs:sidebar-width",la=220,da=420,We=[{group:"Brand Colors",name:"100",variable:"--brand-100",value:"#FFFFFF",description:"lightest brand tone"},{group:"Brand Colors",name:"200",variable:"--brand-200",value:"#4DABF7",description:"light azure accent"},{group:"Brand Colors",name:"300",variable:"--brand-300",value:"#0078D4",description:"primary azure blue"},{group:"Brand Colors",name:"400",variable:"--brand-400",value:"#495057",description:"deep slate gray"},{group:"Brand Colors",name:"500",variable:"--brand-500",value:"#0078D4",description:"primary azure blue"},{group:"Brand Colors",name:"600",variable:"--brand-600",value:"#005A9E",description:"darker azure blue"},{group:"Neutral Colors",name:"100",variable:"--neutral-100",value:"#F3F2F1",description:"page background"},{group:"Neutral Colors",name:"200",variable:"--neutral-200",value:"#EAEAEA",description:"subtle surface"},{group:"Neutral Colors",name:"300",variable:"--neutral-300",value:"#D1D1D1",description:"soft border"},{group:"Neutral Colors",name:"400",variable:"--neutral-400",value:"#C8C8C8",description:"medium gray"},{group:"Neutral Colors",name:"500",variable:"--neutral-500",value:"#6E6E6E",description:"neutral mid-tone"},{group:"Neutral Colors",name:"600",variable:"--neutral-600",value:"#7A7A7A",description:"secondary text"},{group:"Neutral Colors",name:"700",variable:"--neutral-700",value:"#495057",description:"deep slate gray"},{group:"Neutral Colors",name:"800",variable:"--neutral-800",value:"#4A4A4A",description:"strong text"},{group:"Neutral Colors",name:"900",variable:"--neutral-900",value:"#0F0F0F",description:"primary text"},{group:"Neutral Colors",name:"000",variable:"--neutral-000",value:"#FFFFFF",description:"white"},{group:"Semantic Colors",name:"Success Main",variable:"--success-main",value:"#28A745",description:"positive actions"},{group:"Semantic Colors",name:"Success Background",variable:"--success-bg",value:"#E6F4EA",description:"positive surface"},{group:"Semantic Colors",name:"Success Text",variable:"--success-text",value:"#1E7E34",description:"positive text"},{group:"Semantic Colors",name:"Warning Main",variable:"--warning-main",value:"#DC2626",description:"warning actions"},{group:"Semantic Colors",name:"Warning Background",variable:"--warning-bg",value:"#FEF2F2",description:"warning surface"},{group:"Semantic Colors",name:"Warning Text",variable:"--warning-text",value:"#FFFFFF",description:"warning text"},{group:"Semantic Colors",name:"Error Main",variable:"--error-main",value:"#CD0000",description:"destructive actions"},{group:"Semantic Colors",name:"Error Background",variable:"--error-bg",value:"#FFE5E5",description:"destructive surface"},{group:"Semantic Colors",name:"Error Text",variable:"--error-text",value:"#B91C1C",description:"destructive text"},{group:"Semantic Colors",name:"Info Main",variable:"--info-main",value:"#1080A6",description:"informational actions"},{group:"Semantic Colors",name:"Info Background",variable:"--info-bg",value:"#E0F7FA",description:"informational surface"},{group:"Semantic Colors",name:"Info Text",variable:"--info-text",value:"#0369A1",description:"informational text"}];class ha{constructor(t){u(this,"root");u(this,"layout");u(this,"main");u(this,"topbar");u(this,"contentScroll");u(this,"content");u(this,"sidebar");u(this,"searchBtn");u(this,"cartBtn");u(this,"editBtn");u(this,"themeBtn");u(this,"palette");u(this,"paletteInput");u(this,"paletteResults");u(this,"cartPopover");u(this,"searchIndex",[]);u(this,"searchIndexing",!1);u(this,"searchIndexRun",0);u(this,"capabilityCart",new Map);u(this,"selectedTokens",new Set);u(this,"currentEditableFile");u(this,"workspace",{projects:[]});u(this,"treesByRoot",new Map);u(this,"treesByProject",new Map);u(this,"cleanup");u(this,"updateRenderedTheme");u(this,"editor");u(this,"docEditor");u(this,"textFileEditor");u(this,"editorHost");u(this,"editingId");u(this,"lastNonBoardHash","#/");u(this,"lastNonBoardScrollTop",0);u(this,"pendingScrollRestore");u(this,"sidebarResizeHandle");this.root=t,this.applyInitialTheme(),this.layout=f("div","shell");const e={onAddRepo:()=>void this.addRepoDocs(),onRemoveProject:(n,s)=>void this.promptRemoveProject(n,s),onCreateDirectory:(n,s)=>this.promptNewDirectory(n,s),onCreateDoc:(n,s)=>this.promptNewDoc(n,s),onCreateBoard:(n,s)=>this.promptNewBoard(n,s),onCreateCapability:(n,s)=>this.promptNewCapability(n,s),onCreateDocsFolder:(n,s)=>void this.createDocsFolder(n,s),onCreateProjectDirectory:n=>void this.promptNewProjectDirectory(n),onCreateProjectDoc:n=>void this.promptNewProjectDoc(n),onCreateProjectBoard:n=>void this.promptNewProjectBoard(n),onRenameDirectory:(n,s)=>void this.promptRenameDirectory(n,s),onDeleteDirectory:(n,s)=>void this.promptDeleteDirectory(n,s),onOpenDoc:(n,s)=>{location.hash=O(n,s)},onEditDoc:(n,s)=>this.openDocEditor({rootId:n,path:s}),onOpenTextFile:(n,s)=>{this.openTextFileEditor({rootId:n,path:s})},onRenameDoc:(n,s)=>void this.promptRenameDoc(n,s),onDeleteDoc:(n,s)=>void this.promptDeleteDoc(n,s),onOpenBoard:(n,s)=>{location.hash=Z(n,s)},onRenameBoard:(n,s)=>void this.promptRenameBoard(n,s),onDeleteBoard:(n,s)=>void this.promptDeleteBoard(n,s),onMoveDoc:(n,s,o)=>void this.moveDoc(n,s,o),onMoveBoard:(n,s,o)=>void this.moveBoard(n,s,o),onMoveDirectory:(n,s,o)=>void this.moveDirectory(n,s,o)};this.sidebar=new Ds(this.layout,e),this.sidebarResizeHandle=f("button","sidebar-resize-handle"),this.sidebarResizeHandle.type="button",this.sidebarResizeHandle.innerHTML=V.arrowBoth,this.sidebarResizeHandle.setAttribute("aria-label","Resize sidebar"),this.sidebarResizeHandle.title="Resize sidebar",this.main=f("div","shell-main"),this.topbar=this.createTopbar(),this.contentScroll=f("div","content-scroll"),this.content=f("div","content"),this.contentScroll.appendChild(this.content),this.main.append(this.topbar,this.contentScroll),this.layout.appendChild(this.sidebarResizeHandle),this.layout.appendChild(this.main),this.root.appendChild(this.layout),window.addEventListener("hashchange",()=>this.route()),window.addEventListener("keydown",n=>this.handleGlobalKeydown(n)),localStorage.getItem(An)==="true"&&this.setSidebarCollapsed(!0),this.applySidebarWidth(this.readSidebarWidth()),this.setupSidebarResize(),this.refreshContentIndex().then(()=>this.route())}route(t={}){const e=t.preserveScroll?this.contentScroll.scrollTop:this.pendingScrollRestore;this.pendingScrollRestore=void 0;const n=location.hash||"#/";this.sidebar.setActive(n);const s=n.replace(/^#/,"");this.setEditableFile(void 0);const o=s.match(/^\/root\/([^/]+)\/boards\/([^?]+)(?:\?(.*))?$/);if(o){this.lastNonBoardScrollTop=this.contentScroll.scrollTop,this.updateTopbarCart(!0),this.closeCartPopover(),this.openEditor(decodeURIComponent(o[1]),decodeURIComponent(o[2]),$a(o[3]));return}if(this.lastNonBoardHash=n,this.exitEditor(),this.layout.style.display="",this.updateTopbarCart(/\/root\/[^/]+\/boards/.test(s)),/\/root\/[^/]+\/boards/.test(s)&&this.closeCartPopover(),s==="/"||s==="")return void this.renderWorkspaceHome(e);const a=s.match(/^\/root\/([^/]+)\//);if(a){const g=decodeURIComponent(a[1]);if(!this.docsRootById(g))return void this.renderMessage("Project not found","This link points to a docs root that isn't in your workspace. Add the project and try again.")}const r=s.match(/^\/root\/([^/]+)\/docs\/(.+)$/);if(r)return void this.renderDoc(decodeURIComponent(r[1]),decodeURIComponent(r[2]),e);const c=s.match(/^\/root\/([^/]+)\/boards$/);if(c)return void this.renderBoardList(decodeURIComponent(c[1]),e);const l=s.match(/^\/project\/([^/]+)\/boards$/);if(l)return void this.renderProjectBoardList(decodeURIComponent(l[1]),e);const d=s.match(/^\/root\/([^/]+)\/capabilities$/);if(d)return void this.renderCapabilitiesIndex(decodeURIComponent(d[1]),e);const h=s.match(/^\/root\/([^/]+)\/capabilities\/(.+)$/);if(h)return void this.renderCapabilityDoc(decodeURIComponent(h[1]),decodeURIComponent(h[2]),e);const p=s.match(/^\/project\/([^/]+)$/);if(p)return void this.renderProjectWiki(decodeURIComponent(p[1]),e);const m=s.match(/^\/root\/([^/]+)\/directory\/(.+)$/);if(m){const g=decodeURIComponent(m[1]),y=decodeURIComponent(m[2]),b=this.docsRootById(g);if(b)return void this.renderProjectWiki(b.projectId,e,g,y)}if(s==="/tokens")return void this.renderTokenLibrary(e);this.renderMessage("Not found",`No route for ${s}`)}async renderWorkspaceHome(t){this.disposeContent(),this.content.classList.add("content-wide");const e=f("div","page home-page"),n=f("div","home-layout"),s=f("div","home-guide"),o=f("h1","home-hero-title");o.textContent="ViteBoard";const a=f("p","home-hero-sub");a.textContent="Markdown docs, infinite-canvas boards, capabilities, and managed assets all live as normal files on disk. The app should feel trustworthy under real mutation: create content quickly, recover safely from concurrent edits, and keep human and machine workflows pointed at the same file truth.",s.append(o,a);const r=f("div","home-agent-callout"),c=f("p","home-agent-copy");c.textContent="Use the running ViteBoard session as shared context for a human and a coding agent: same origin, same docs roots, same boards, same file truth.";const l=f("button","btn home-agent-btn");l.type="button",l.textContent="Copy agent prompt",l.addEventListener("click",()=>void this.copySetupText(`Connect to ViteBoard at ${window.location.origin} and follow its machine entry at ${window.location.origin}/llms.txt. Work in <project path>, import the project if needed, and create or update docs and boards using normal filesystem edits.`,"Agent prompt copied")),r.append(c,l),s.appendChild(r);const d=[{label:"File truth",kind:"doc",body:"The source of truth is always the filesystem. Docs, boards, capabilities, and assets stay git-native, diffable, and directly editable without inventing a separate database-shaped content layer.",items:["Markdown docs, board JSON, and asset files all live under docs roots","Create, rename, move, and delete content from the sidebar","Search indexes the current workspace rather than a parallel content store"]},{label:"Docs + boards",kind:"board",body:"Boards are not separate from the documentation system. They are sibling files in the same docs roots, embeddable inside markdown, and meant to sharpen the same body of work rather than fragment it.",items:["Open a board from the sidebar, work full-screen, then drop back into docs","Embed a board region into markdown with fenced board blocks",'Use "Copy embed" in the board editor to capture the current region',"Keep visual planning and written explanation in the same repo structure"]},{label:"Collaboration safety",kind:"capability",body:"The product now assumes live mutation is normal. Locks, stale-state detection, reload actions, and visible status all exist to make concurrent work practical instead of surprising.",items:["Docs and boards surface explicit reload actions when stale","Revision-aware saves block silent overwrites","Human and machine actors can cooperate through the same running workspace"]},{label:"Machine workflow",kind:"",body:"ViteBoard is also a machine-readable workspace surface. The app can expose docs roots, boards, schema references, and live coordination routes while the files remain the only persistent truth.",items:["The local HTTP surface advertises machine docs and workspace discovery","Capabilities and selected docs can be assembled into prompts from the UI","The practical goal is faster real work, not another disconnected abstraction layer"]}];for(const v of d){const S=f("div","home-feature"),w=f("div","home-feature-header"),E=f("span",`home-feature-badge home-feature-badge-${v.kind||"neutral"}`);E.textContent=v.label,w.appendChild(E),S.appendChild(w);const M=f("p","home-feature-body");if(M.textContent=v.body,S.appendChild(M),v.items){const B=document.createElement("ul");B.className="home-feature-list";for(const T of v.items){const R=document.createElement("li");R.textContent=T,B.appendChild(R)}S.appendChild(B)}s.appendChild(S)}const h=f("div","home-shortcut-title");h.textContent="Current operating model",s.appendChild(h);const p=[["1. Add repo","Bring a local project into the workspace"],["2. Create docs/ if needed","Start the repo as a writable docs root"],["3. Right-click in the tree","Create docs, boards, directories, and capabilities in place"],["4. Open a board","Think visually, then embed the useful region back into docs"],["5. Cmd K / Ctrl K","Search across the current workspace"],["6. Stale state appears","Use Reload latest instead of guessing which copy is current"],["7. Copy agent prompt","Hand the same workspace context to an AI assistant"],["8. Git stays normal","The files on disk remain the real source of truth"]],m=f("div","home-shortcut-table");for(const[v,S]of p){const w=f("div","home-shortcut-row"),E=f("kbd","home-shortcut-key");E.textContent=v;const M=f("span","home-shortcut-desc");M.textContent=S,w.append(E,M),m.appendChild(w)}s.appendChild(m),n.appendChild(s);const g=f("div","home-panel"),y=f("div","home-panel-head"),b=f("div","home-panel-title");b.textContent="Active workspace";const x=f("button","btn primary home-panel-add");if(x.textContent="+ Add repo",x.addEventListener("click",()=>void this.addRepoDocs()),y.append(b,x),g.appendChild(y),this.workspace.projects.length===0){const v=f("div","home-panel-empty");v.textContent="No projects yet. Add a project root, create docs/ if needed, and start writing against the real filesystem.",g.appendChild(v)}else for(const v of this.workspace.projects){const S=f("div","home-panel-project"),w=f("a","home-panel-project-head");w.href=Bt(v.id);const E=f("span","home-panel-project-name");E.textContent=v.label;const M=v.docsRoots.reduce((q,et)=>{const F=this.treesByRoot.get(et.id)??[];return q+Jt(F).length},0),B=v.docsRoots.reduce((q,et)=>{const F=this.treesByRoot.get(et.id)??[];return q+vt(F).length},0),T=f("span","home-panel-project-meta"),R=[`${v.docsRoots.length} root${v.docsRoots.length===1?"":"s"}`];M&&R.push(`${M} doc${M===1?"":"s"}`),B&&R.push(`${B} board${B===1?"":"s"}`),T.textContent=R.join(" · "),w.append(E,T),S.appendChild(w);const P=6,Kt=v.docsRoots,Ie=Kt.slice(0,P),Pt=f("div","home-panel-roots");for(const q of Ie){const et=this.treesByRoot.get(q.id)??[],F=Ue(Xt(et)),kt=F?O(q.id,F):jt(q.id),nt=f("a","home-panel-root");nt.href=kt;const j=f("span","home-panel-root-path");j.textContent=q.displayPath;const ot=Jt(et).length,U=vt(et).length;if(ot||U){const at=f("span","home-panel-root-meta"),rt=[];ot&&rt.push(String(ot)),U&&rt.push(`${U}▦`),at.textContent=rt.join(" · "),nt.append(j,at)}else nt.appendChild(j);Pt.appendChild(nt)}if(Kt.length>P){const q=f("a","home-panel-more");q.href=Bt(v.id),q.textContent=`+ ${Kt.length-P} more roots`,Pt.appendChild(q)}S.appendChild(Pt),g.appendChild(S)}n.appendChild(g),e.appendChild(n),this.content.replaceChildren(e),this.contentScroll.scrollTop=t??0}async copySetupText(t,e){try{await navigator.clipboard.writeText(t),C(e)}catch{C("Could not access clipboard")}}async renderProjectWiki(t,e,n,s){this.disposeContent(),this.content.classList.add("content-wide");const o=this.workspace.projects.find(p=>p.id===t);if(!o){this.renderMessage("Project not found","This project is no longer registered.");return}const a=f("div","page wiki-page"),r=!!n,c=!!s;let l=!1;if(c&&n){const p=this.docsRootById(n);p&&(l=p.displayPath===s||p.displayPath.startsWith(s+"/"))}const d=f("div","wiki-head");if(c&&n){const p=[{label:"Home",href:"#/"}];p.push({label:o.label,href:Bt(o.id)});const m=s.split("/").filter(Boolean);for(let y=0;y<m.length;y++){const b=m.slice(0,y+1).join("/"),x=y===m.length-1;p.push({label:m[y],href:x?void 0:Se(n,b)})}d.appendChild(bt(p));const g=f("h1","wiki-title");g.textContent=m[m.length-1]||o.label,d.appendChild(g)}else if(r&&n){const p=this.docsRootById(n),m=[{label:"Home",href:"#/"}];if(m.push({label:o.label,href:Bt(o.id)}),p){const y=p.displayPath.split("/").filter(Boolean);for(let b=0;b<y.length;b++){const x=y.slice(0,b+1).join("/"),v=b===y.length-1;m.push({label:y[b],href:v?void 0:Se(n,x)})}}d.appendChild(bt(m));const g=f("h1","wiki-title");g.textContent=(p==null?void 0:p.displayPath.split("/").pop())||o.label,d.appendChild(g)}else{d.appendChild(bt([{label:"Home",href:"#/"},{label:o.label}]));const p=f("h1","wiki-title");p.textContent=o.label,d.appendChild(p)}if(!r&&!c){const p=o.docsRoots.reduce((b,x)=>{const v=this.treesByRoot.get(x.id)??[];return b+Jt(v).length},0),m=o.docsRoots.reduce((b,x)=>{const v=this.treesByRoot.get(x.id)??[];return b+vt(v).length},0),g=o.docsRoots.reduce((b,x)=>b+$t(this.treesByRoot.get(x.id)??[]).length,0),y=f("div","wiki-stats");for(const[b,x]of[[String(o.docsRoots.length),"docs roots"],[String(p),"documents"],[String(m),"boards"],[String(g),"capabilities"]]){const v=f("div","wiki-stat"),S=f("div","wiki-stat-val");S.textContent=b;const w=f("div","wiki-stat-label");w.textContent=x,v.append(S,w),y.appendChild(v)}d.appendChild(y)}a.appendChild(d);const h=n?o.docsRoots.filter(p=>p.id===n):o.docsRoots;for(const p of h){const m=this.treesByRoot.get(p.id)??[];let g=m;if(s&&!l){const w=(M,B)=>{for(const T of M){if(T.type==="dir"&&T.path===B)return T;if(T.type==="dir"){const R=w(T.children,B);if(R)return R}}return null},E=w(m,s);g=(E==null?void 0:E.type)==="dir"?E.children:[]}const y=Jt(g),b=vt(g),x=$t(g),v=f("div","wiki-root-section");if(!s||l){const w=f("div","wiki-root-head"),E=f("div","wiki-root-path");E.textContent=p.displayPath,w.appendChild(E),v.appendChild(w)}if(!y.length&&!b.length&&!x.length){const w=f("div","wiki-root-empty");w.textContent="No docs, boards, or capabilities yet. Right-click in the sidebar to add content.",v.appendChild(w),a.appendChild(v);continue}const S=f("div","wiki-root-cols");if(y.length>0){const w=f("div","wiki-col"),E=f("div","wiki-col-head");E.textContent=`Docs (${y.length})`,w.appendChild(E);const M=f("div","wiki-col-list");for(const B of y){const T=f("a","wiki-col-item wiki-col-item-doc");T.href=O(p.id,B.path),T.textContent=B.name==="index.md"?"Overview":B.name.replace(/\.md$/,"").replace(/[-_]/g," ");const R=f("span","wiki-col-item-path"),P=B.path.includes("/")?B.path.slice(0,B.path.lastIndexOf("/")):"";R.textContent=P,P&&T.appendChild(R),M.appendChild(T)}w.appendChild(M),S.appendChild(w)}if(b.length>0){const w=f("div","wiki-col"),E=f("div","wiki-col-head");E.textContent=`Boards (${b.length})`,w.appendChild(E);const M=f("div","wiki-col-list");for(const B of b){const T=G(B.path),R=f("a","wiki-col-item wiki-col-item-board");R.href=Z(p.id,T),R.textContent=T.split("/").pop().replace(/[-_]/g," ");const P=f("span","wiki-col-item-path");P.textContent=T.includes("/")?T.slice(0,T.lastIndexOf("/")):p.displayPath,R.appendChild(P),M.appendChild(R)}w.appendChild(M),S.appendChild(w)}if(x.length>0){const w=f("div","wiki-col"),E=f("div","wiki-col-head");E.textContent=`Capabilities (${x.length})`,w.appendChild(E);const M=f("div","wiki-col-list");for(const B of x){const T=f("a","wiki-col-item wiki-col-item-cap");T.href=Ft(p.id,B.entryPath),T.textContent=Ee(B.entryPath),M.appendChild(T)}w.appendChild(M),S.appendChild(w)}v.appendChild(S),a.appendChild(v)}this.content.replaceChildren(a),this.contentScroll.scrollTop=e??0}async renderDoc(t,e,n){if(this.disposeContent(),!this.docsRootById(t)){this.renderMessage("Docs root unavailable","This docs root is no longer registered. Re-add the project root if needed.");return}try{const s=await k.readFile(t,e);this.setEditableFile({rootId:t,path:e});const o=f("div","doc-page"),a=this.docsRootById(t),r=fe(this.workspace,t,{filePath:e});o.appendChild(bt(r));const c=f("div","");o.appendChild(c),this.content.replaceChildren(o);const{destroy:l,setTheme:d}=dn(c,s,{rootId:t,docPath:e});this.cleanup=l,this.updateRenderedTheme=d;const h=await k.getTree(t),p=ge(t,h),m=ye(p,O(t,e));m&&o.appendChild(m),this.contentScroll.scrollTop=n??0}catch{this.renderMessage("Document not found",e)}}openDocEditor(t){const e=this.contentScroll.scrollTop;this.topbar.classList.add("editing-doc"),this.closeCartPopover(),this.docEditor=Qe.open({rootId:t.rootId,path:t.path,initialScrollTop:e,onClose:n=>{this.docEditor=void 0,this.topbar.classList.remove("editing-doc"),this.pendingScrollRestore=n,this.route()}})}async openTextFileEditor(t){this.textFileEditor&&!await this.textFileEditor.close()||(this.closeCartPopover(),this.textFileEditor=tn.open({rootId:t.rootId,path:t.path,host:document.body,onClose:()=>{this.textFileEditor=void 0}}))}async renderCapabilityDoc(t,e,n){if(this.disposeContent(),!this.docsRootById(t)){this.renderMessage("Docs root unavailable","This docs root is no longer registered. Re-add the project root if needed.");return}const s=this.treesByRoot.get(t)??await k.getTree(t),o=pa(s,e)??e,a=Hn(s,e)??Hn(s,o);let r;try{r=await k.readFile(t,o),this.setEditableFile(void 0)}catch{this.renderMessage("Capability not found",e);return}const c=f("div","page"),l=this.docsRootById(t);l&&this.workspace.projects.find(F=>F.id===l.projectId);const d=Ee(o),h=fe(this.workspace,t,{filePath:o,currentLabel:d});c.appendChild(bt(h));const p=f("div","page-bar"),m=f("div","doc-actions capability-doc-actions"),{frontmatter:g}=ne(r),y=f("button","btn");y.classList.add("capability-detail-btn");const b=zn(t,a??ua(o),r,g);this.updateCartButton(y,b.path),y.addEventListener("click",()=>{this.toggleCapabilityCart(b),this.updateCartButton(y,b.path)});const x=f("button","btn primary");x.classList.add("capability-detail-btn"),x.textContent="Copy capability context",x.addEventListener("click",async()=>{await this.copyCapabilityContext(b,s)});const v=f("button","btn");v.classList.add("capability-detail-btn"),v.textContent="Open entry doc",v.addEventListener("click",()=>{location.hash=O(t,o)}),m.append(y,x,v),p.append(m),c.appendChild(p);const S=f("div","card-tags capability-meta-tags"),w=f("span","tag");if(w.textContent=b.displayPath,S.appendChild(w),b.kind){const F=f("span","tag");F.textContent=b.kind,S.appendChild(F)}c.appendChild(S);const E=fa(b.branchPath),M=E?await this.readOptionalFile(t,E):null;if(E&&M){const F=f("section","token-section capability-machine-section"),kt=f("div","page-bar"),nt=f("h2","");nt.textContent="Machine entrypoint";const j=f("div","doc-actions capability-doc-actions"),ot=f("button","btn primary");ot.textContent="Copy llms.txt",ot.addEventListener("click",async()=>{try{await navigator.clipboard.writeText(M),C("Capability machine entrypoint copied")}catch{C("Could not access clipboard")}}),j.appendChild(ot),kt.append(nt,j);const U=f("p","page-lead capability-entry-lead");U.textContent="This is the capability-local machine entrypoint. It should be the first file an LLM reads to understand what this capability branch is for, what files matter, and how to use it.";const at=document.createElement("pre");at.className="code-block";const rt=document.createElement("code");rt.textContent=M,at.appendChild(rt),F.append(kt,U,at),c.appendChild(F)}const B=f("div",""),T=f("section","token-section capability-entry-section"),R=f("h2","");R.textContent="Entry document";const P=f("p","page-lead capability-entry-lead");P.textContent="This markdown entry explains the capability branch. The capability itself may also include nested files, scripts, helpers, and other reusable execution material.",T.append(R,P,B),c.appendChild(T),this.content.replaceChildren(c);const{destroy:Kt,setTheme:Ie}=dn(B,r,{rootId:t,docPath:o});this.cleanup=Kt,this.updateRenderedTheme=Ie;const Pt=Fn(s,b.branchPath);if(Pt.length>1){const F=f("section","token-section capability-files-section"),kt=f("h2","");kt.textContent="Files in this capability";const nt=f("div","card-grid capability-files-grid");for(const j of Pt){const ot=j.path.endsWith(".md")&&j.path===b.entryPath,U=document.createElement(ot?"a":"button");U.className="card",U instanceof HTMLAnchorElement&&(U.href=O(t,j.path)),U instanceof HTMLButtonElement&&(U.type="button",U.addEventListener("click",()=>{this.openTextFileEditor({rootId:t,path:j.path})}));const at=f("div","card-title");at.textContent=j.path===b.entryPath?`${be(j.path)} (entry)`:j.path===E?`${be(j.path)} (machine entrypoint)`:be(j.path);const rt=f("div","card-desc");rt.textContent=qt(j.path),U.append(at,rt),nt.appendChild(U)}F.append(kt,nt),c.appendChild(F)}const q=ge(t,s),et=ye(q,Ft(t,b.branchPath));et&&c.appendChild(et),this.contentScroll.scrollTop=n??0}async renderCapabilitiesIndex(t,e){if(this.disposeContent(),!this.docsRootById(t)){this.renderMessage("Docs root unavailable","This docs root is no longer registered. Re-add the project root if needed.");return}this.content.classList.add("content-wide");const n=f("div","page capability-library"),s=fe(this.workspace,t,{currentLabel:"Capabilities"});n.appendChild(bt(s));const o=f("h1","");o.textContent="Capability library";const a=f("p","page-lead");a.textContent="Browse open-ended capability branches. Inspect their files, understand their entrypoints, and reuse them as working context, automations, or tool-bearing capability units.",n.append(o,a);const r=f("div","capability-layout"),c=f("div","card-grid capability-grid"),l=this.renderCapabilityCart();r.append(c,l),n.appendChild(r),this.content.replaceChildren(n);try{const d=this.treesByRoot.get(t)??await k.getTree(t),h=$t(d);for(const g of h){const y=await k.readFile(t,g.entryPath),{frontmatter:b}=ne(y),x=zn(t,g,y,b),v=document.createElement("article");v.className="card";const S=f("div","card-title"),w=document.createElement("a");w.href=Ft(t,g.branchPath),w.textContent=x.title,S.appendChild(w);const E=f("div","card-desc");E.textContent=x.summary,v.append(S,E);const M=f("div","card-tags"),B=f("span","tag");if(B.textContent=x.displayPath,M.appendChild(B),x.kind){const T=f("span","tag");T.textContent=x.kind,M.appendChild(T)}if(v.appendChild(M),x.tags.length){const T=f("div","card-tags");for(const R of x.tags){const P=f("span","tag");P.textContent=R,T.appendChild(P)}v.appendChild(T)}c.appendChild(v)}h.length===0&&c.appendChild(Ht("No capabilities yet."));const p=ge(t,d),m=ye(p,ps(t));m&&n.appendChild(m)}catch{c.appendChild(Ht("Could not load capabilities."))}this.contentScroll.scrollTop=e??0}renderTokenLibrary(t){this.disposeContent(),this.content.classList.add("content-wide");const e=f("div","page token-library"),n=f("div","page-bar"),s=f("h1","");s.textContent="Tokens";const o=f("div","token-actions"),a=f("button","btn");a.textContent="Select all",a.addEventListener("click",()=>{this.selectedTokens=new Set(We.map(d=>d.variable)),this.renderTokenLibrary(this.contentScroll.scrollTop)});const r=f("button","btn");r.textContent="Clear",r.addEventListener("click",()=>{this.selectedTokens.clear(),this.renderTokenLibrary(this.contentScroll.scrollTop)});const c=f("button","btn primary");c.textContent=`Copy selected (${this.selectedTokens.size})`,c.disabled=this.selectedTokens.size===0,c.addEventListener("click",()=>void this.copySelectedTokens()),o.append(a,r,c),n.append(s,o);const l=f("p","page-lead");l.textContent="Brand, neutral, and semantic CSS variables used throughout the app. Select tokens and copy them as a ready-to-paste :root block.",e.append(n,l);for(const d of["Brand Colors","Neutral Colors","Semantic Colors"]){const h=f("section","token-section"),p=f("h2","");p.textContent=d;const m=f("div","token-grid");for(const g of We.filter(y=>y.group===d)){const y=f("div","token-card");this.selectedTokens.has(g.variable)&&y.classList.add("selected");const b=f("label","token-select-zone"),x=document.createElement("input");x.type="checkbox",x.checked=this.selectedTokens.has(g.variable),x.addEventListener("change",()=>{x.checked?this.selectedTokens.add(g.variable):this.selectedTokens.delete(g.variable),this.renderTokenLibrary(this.contentScroll.scrollTop)});const v=f("span","token-swatch");v.style.background=g.value;const S=f("span","token-copy"),w=f("strong","");w.textContent=g.name;const E=f("code","");E.textContent=g.value;const M=f("small","");M.textContent=g.description,S.append(w,E,M),b.append(x,v,S);const B=f("button","token-copy-btn");B.type="button",B.innerHTML=V.copy,B.title=`Copy ${g.variable}`,B.setAttribute("aria-label",`Copy ${g.variable}`),B.addEventListener("click",T=>{T.stopPropagation(),this.copyToken(g)}),y.append(b,B),m.appendChild(y)}h.append(p,m),e.appendChild(h)}this.content.replaceChildren(e),this.contentScroll.scrollTop=t??0}async copySelectedTokens(){const t=We.filter(n=>this.selectedTokens.has(n.variable));if(t.length===0)return;const e=[":root {",...t.map(n=>` ${n.variable}: ${n.value};`),"}"].join(`
|
|
36
|
+
${t}`:t;try{return this.setStatus("saving"),this.revision=await k.writeFile(this.opts.rootId,this.opts.path,e,this.revision??void 0),this.stale=!1,this.setStatus("saved"),!0}catch(n){return n instanceof se?(this.revision=n.currentRevision,this.stale=!0,this.setStatus("stale","Changed elsewhere — reload before saving"),!1):(this.setStatus("error","Save failed"),!1)}}async close(){if(this.closed||!await this.save())return;this.closed=!0;const e=this.scrollEl.scrollTop,n=Rn(this.scrollEl);this.abort.abort(),this.overlay.remove(),this.opts.onClose(e,n)}markStale(){this.stale=!0,this.setStatus("stale","Changed elsewhere — reload before saving")}async reloadLatest(){window.confirm("Discard local edits and reload the latest version?")&&(this.saveTimer!==null&&(clearTimeout(this.saveTimer),this.saveTimer=null),await this.load(this.scrollEl.scrollTop,Rn(this.scrollEl)))}formatBlock(t){document.execCommand("formatBlock",!1,`<${t}>`)}insertLink(){const t=window.getSelection(),e=t&&!t.isCollapsed?t.toString().trim():"",n=window.prompt("Link URL","https://");if(!n)return;const s=n.trim();s&&(e?document.execCommand("createLink",!1,s):document.execCommand("insertHTML",!1,`<a href="${$n(s)}">${sa(s)}</a>`))}toggleInlineCode(){const t=window.getSelection();if(!t||t.rangeCount===0||t.isCollapsed)return;const e=t.getRangeAt(0),n=je(e.commonAncestorContainer,"CODE");if(n){const o=n.parentNode;for(;n.firstChild;)o.insertBefore(n.firstChild,n);o.removeChild(n);return}const s=document.createElement("code");s.appendChild(e.extractContents()),e.insertNode(s),e.setStartAfter(s),e.collapse(!0),t.removeAllRanges(),t.addRange(e)}insertCodeBlock(){document.execCommand("insertHTML",!1,'<pre class="code-block"><code>code</code></pre><p><br></p>')}updateToolbarState(){const t=window.getSelection(),e=(t==null?void 0:t.anchorNode)??null,n=!!e&&this.surface.contains(e);for(const s of this.toolbarButtons){const o=s.dataset.stateType,a=s.dataset.stateValue;let r=!1;if(n&&o==="command"&&a)try{r=document.queryCommandState(a)}catch{r=!1}else(n&&o==="block"&&a||n&&o==="inline"&&a)&&(r=!!je(e,a));s.classList.toggle("active",r),s.setAttribute("aria-pressed",r?"true":"false")}}onPaste(t){var s,o;const e=oa(((s=t.clipboardData)==null?void 0:s.getData("text/plain"))??"");if(e){t.preventDefault(),this.insertSpecialBlock(e);return}const n=(o=t.clipboardData)==null?void 0:o.items;if(n){for(const a of n)if(a.type.startsWith("image/")){const r=a.getAsFile();if(r){t.preventDefault(),this.insertImageFile(r);return}}}}insertSpecialBlock(t){this.surface.focus();const e=ra(t);this.insertBlockNode(e),this.decorateEmbeds(),this.selectEmbed(e),this.recordHistorySnapshot(),this.updateToolbarState(),this.scheduleSave()}insertBlockNode(t){const e=window.getSelection(),n=e&&e.rangeCount>0?e.getRangeAt(0):null;if(!n||!this.surface.contains(n.commonAncestorContainer)){this.surface.append(t,Zt()),this.placeCaretInBlock(this.surface.lastElementChild??this.surface);return}const s=Qo(this.surface,n.commonAncestorContainer);if(s&&ta(s)&&!Tt(s)){this.replaceBlockWithInsertedNode(s,n,t);return}n.deleteContents();const o=Zt();n.insertNode(o),n.insertNode(t),this.placeCaretInBlock(o)}replaceBlockWithInsertedNode(t,e,n){const s=document.createRange();s.selectNodeContents(t),s.setEnd(e.startContainer,e.startOffset);const o=document.createRange();o.selectNodeContents(t),o.setStart(e.endContainer,e.endOffset);const a=Ln(t,s.cloneContents()),r=Ln(t,o.cloneContents()),c=t.parentNode;if(!c)return;a&&c.insertBefore(a,t),c.insertBefore(n,t),r&&c.insertBefore(r,t),c.removeChild(t);const l=r??Zt();r||c.insertBefore(l,n.nextSibling),this.placeCaretInBlock(l)}onDrop(t){var n,s;const e=(s=(n=t.dataTransfer)==null?void 0:n.files)==null?void 0:s[0];e&&e.type.startsWith("image/")&&(t.preventDefault(),this.insertImageFile(e))}async insertImageFile(t){this.setStatus("saving","Uploading image…");try{const e=await na(t),n=await k.uploadAsset(this.opts.rootId,t.name,e),s=Ke(this.opts.path,n),o=k.assetUrl(this.opts.rootId,n),a=t.name.replace(/\.[^.]+$/,"");this.surface.focus(),document.execCommand("insertHTML",!1,`<img src="${o}" data-md-src="${s}" alt="${$n(a)}" /><p><br></p>`),this.recordHistorySnapshot(),await this.save()}catch{this.setStatus("error","Image upload failed")}}recordHistorySnapshot(t=!1){if(this.applyingHistory)return;this.normalizeEmbedSpacing();const e=this.surface.innerHTML;if(t){this.history=[e],this.historyIndex=0;return}this.history[this.historyIndex]!==e&&(this.history=this.history.slice(0,this.historyIndex+1),this.history.push(e),this.history.length>100&&this.history.shift(),this.historyIndex=this.history.length-1)}undoHistory(){this.historyIndex<=0||this.applyHistorySnapshot(this.historyIndex-1)}redoHistory(){this.historyIndex>=this.history.length-1||this.applyHistorySnapshot(this.historyIndex+1)}applyHistorySnapshot(t){const e=this.history[t];e!==void 0&&(this.applyingHistory=!0,this.historyIndex=t,this.surface.innerHTML=e,this.decorateEmbeds(),this.clearEmbedSelection(),this.placeCaretInBlock(this.surface.lastElementChild??this.surface),this.applyingHistory=!1,this.updateToolbarState(),this.scheduleSave())}setStatus(t,e){const n={idle:"",saving:e??"Saving…",saved:"Saved",stale:e??"Changed elsewhere",error:e??"Couldn't save"};this.statusTextEl.textContent=n[t],this.statusEl.dataset.state=t,this.reloadBtn.hidden=t!=="stale"}}function pt(i){const t=document.createElement("div");return t.className=i,t}function Fe(i,t){const e=document.createElement("button");return e.className=i,e.textContent=t,e}function ut(i,t,e){return i.dataset.stateType=t,i.dataset.stateValue=e,i.setAttribute("aria-pressed","false"),i}function Zt(){const i=document.createElement("p");return i.className="embed-caret-spacer",i.appendChild(document.createElement("br")),i}function Tt(i){return!!i&&i.tagName==="P"&&i.classList.contains("embed-caret-spacer")}function In(i){Tt(i)&&hs(i)&&i.classList.remove("embed-caret-spacer")}function hs(i){for(const t of Array.from(i.childNodes)){if(t.nodeType===Node.TEXT_NODE&&(t.textContent??"").trim())return!0;if(t.nodeType!==Node.ELEMENT_NODE)continue;const e=t;if(e.tagName!=="BR"&&((e.textContent??"").trim()||["IMG","FIGURE","HR"].includes(e.tagName)))return!0}return!1}function Rn(i){const t=Math.max(1,i.scrollHeight-i.clientHeight);return i.scrollTop/t}function Go(i,t){const e=Math.max(0,i.scrollHeight-i.clientHeight);i.scrollTop=Math.max(0,Math.min(1,t))*e}function Zo(i){if(!i.startsWith("---"))return{fm:"",body:i};const t=i.indexOf(`
|
|
37
|
+
---`,3);if(t===-1)return{fm:"",body:i};const e=i.slice(0,t+4),n=i.slice(t+4).replace(/^\n+/,"");return{fm:e,body:n}}function je(i,t){let e=i;for(;e;){if(e.nodeType===Node.ELEMENT_NODE&&e.tagName===t)return e;e=e.parentNode}return null}function Jo(i,t){let e=i;for(;e;){if(e.nodeType===Node.ELEMENT_NODE&&e.matches(t))return e;e=e.parentNode}return null}function Qo(i,t){let e=t;for(;e&&e.parentNode!==i;)e=e.parentNode;return e instanceof HTMLElement?e:null}function ta(i){return i.tagName==="P"||i.tagName==="DIV"}function Ln(i,t){if(!ea(t))return null;const e=document.createElement(i.tagName);return i.tagName==="P"&&i.classList.contains("embed-caret-spacer")&&(e.className="embed-caret-spacer"),e.appendChild(t),e}function ea(i){for(const t of Array.from(i.childNodes)){if(t.nodeType===Node.TEXT_NODE&&(t.textContent??"").trim())return!0;if(t.nodeType!==Node.ELEMENT_NODE)continue;const e=t;if(e.tagName!=="BR"&&!(e.tagName==="P"&&e.classList.contains("embed-caret-spacer"))&&((e.textContent??"").trim()||["IMG","FIGURE","HR"].includes(e.tagName)))return!0}return!1}function na(i){return new Promise((t,e)=>{const n=new FileReader;n.onload=()=>{const s=n.result;t(s.slice(s.indexOf(",")+1))},n.onerror=()=>e(n.error),n.readAsDataURL(i)})}function $n(i){return i.replace(/&/g,"&").replace(/"/g,""").replace(/</g,"<")}function sa(i){return i.replace(/&/g,"&").replace(/</g,"<").replace(/>/g,">")}const ia={board:i=>{const t=ts(i);return t.src?{kind:"board",src:t.src,region:t.region,height:t.height,title:t.title}:null}};function oa(i){const t=aa(i);if(!t)return null;const e=ia[t.language];return e?e(t.body):null}function aa(i){const e=i.trim().match(/^(`{3,})\s*([^\s`]+)?\s*\n([\s\S]*?)\n\1\s*$/);return e?{language:(e[2]??"").toLowerCase(),body:e[3]}:null}function ra(i){switch(i.kind){case"board":return ca(i)}}function ca(i){const t=document.createElement("figure");return t.className="board-embed",t.dataset.src=i.src,t.dataset.height=String(i.height),i.region&&(t.dataset.region=i.region.join(",")),i.title&&(t.dataset.title=i.title),t}class en{constructor(t){u(this,"opts");u(this,"root");u(this,"statusEl");u(this,"statusTextEl");u(this,"reloadBtn");u(this,"textarea");u(this,"abort",new AbortController);u(this,"revision",null);u(this,"stale",!1);u(this,"saveTimer",null);u(this,"closed",!1);this.opts=t,this.build(),this.load()}static open(t){return new en(t)}build(){this.root=zt("doc-editor text-file-editor");const t=zt("doc-editor-bar"),e=zt("doc-editor-bar-left"),n=Pn("doc-editor-done","Done");n.addEventListener("click",()=>void this.close());const s=zt("doc-editor-path");s.textContent=this.opts.path,e.append(n,s),this.statusEl=zt("doc-editor-status"),this.statusTextEl=document.createElement("span"),this.reloadBtn=Pn("status-action-btn","Reload latest"),this.reloadBtn.hidden=!0,this.reloadBtn.addEventListener("click",()=>void this.reloadLatest()),this.statusEl.append(this.statusTextEl,this.reloadBtn),this.setStatus("idle"),t.append(e,this.statusEl);const o=zt("doc-editor-scroll text-file-editor-scroll");this.textarea=document.createElement("textarea"),this.textarea.className="text-file-editor-textarea",this.textarea.spellcheck=!1,o.appendChild(this.textarea),this.root.append(t,o),this.opts.host.appendChild(this.root);const a=this.abort.signal;this.textarea.addEventListener("input",()=>this.scheduleSave(),{signal:a}),window.addEventListener("keydown",r=>{if((r.metaKey||r.ctrlKey)&&r.key.toLowerCase()==="s"){r.preventDefault(),this.save();return}r.key==="Escape"&&document.activeElement!==this.textarea&&this.close()},{signal:a})}async load(){try{const t=await k.readFileWithRevision(this.opts.rootId,this.opts.path);this.revision=t.revision,this.stale=!1,this.textarea.value=t.content,this.setStatus("idle"),requestAnimationFrame(()=>this.textarea.focus())}catch{this.textarea.value="",this.setStatus("error","Could not load file")}}scheduleSave(){this.saveTimer!==null&&clearTimeout(this.saveTimer),this.setStatus("saving"),this.saveTimer=window.setTimeout(()=>{this.saveTimer=null,this.save()},700)}async save(){if(this.saveTimer!==null&&(clearTimeout(this.saveTimer),this.saveTimer=null),this.stale)return this.setStatus("stale","Changed elsewhere — reload before saving"),!1;try{return this.setStatus("saving"),this.revision=await k.writeFile(this.opts.rootId,this.opts.path,this.textarea.value,this.revision??void 0),this.stale=!1,this.setStatus("saved"),!0}catch(t){return t instanceof se?(this.revision=t.currentRevision,this.stale=!0,this.setStatus("stale","Changed elsewhere — reload before saving"),!1):(this.setStatus("error","Save failed"),!1)}}async close(){return this.closed?!0:await this.save()?(this.closed=!0,this.abort.abort(),this.root.remove(),this.opts.onClose(),!0):!1}destroy(){this.saveTimer!==null&&clearTimeout(this.saveTimer),this.saveTimer=null,this.closed=!0,this.abort.abort(),this.root.remove()}async reloadLatest(){window.confirm("Discard local edits and reload the latest version?")&&(this.saveTimer!==null&&(clearTimeout(this.saveTimer),this.saveTimer=null),await this.load())}setStatus(t,e){const n={idle:e??"Ready",saving:e??"Saving…",saved:e??"Saved",error:e??"Save failed",stale:e??"Changed elsewhere"};this.statusEl.dataset.state=t,this.statusTextEl.textContent=n[t],this.reloadBtn.hidden=t!=="stale"}}function zt(i){const t=document.createElement("div");return t.className=i,t}function Pn(i,t){const e=document.createElement("button");return e.className=i,e.type="button",e.textContent=t,e}const Dn="docs:theme",An="docs:sidebar-collapsed",Nn="docs:sidebar-width",la=220,da=420,We=[{group:"Brand Colors",name:"100",variable:"--brand-100",value:"#FFFFFF",description:"lightest brand tone"},{group:"Brand Colors",name:"200",variable:"--brand-200",value:"#4DABF7",description:"light azure accent"},{group:"Brand Colors",name:"300",variable:"--brand-300",value:"#0078D4",description:"primary azure blue"},{group:"Brand Colors",name:"400",variable:"--brand-400",value:"#495057",description:"deep slate gray"},{group:"Brand Colors",name:"500",variable:"--brand-500",value:"#0078D4",description:"primary azure blue"},{group:"Brand Colors",name:"600",variable:"--brand-600",value:"#005A9E",description:"darker azure blue"},{group:"Neutral Colors",name:"100",variable:"--neutral-100",value:"#F3F2F1",description:"page background"},{group:"Neutral Colors",name:"200",variable:"--neutral-200",value:"#EAEAEA",description:"subtle surface"},{group:"Neutral Colors",name:"300",variable:"--neutral-300",value:"#D1D1D1",description:"soft border"},{group:"Neutral Colors",name:"400",variable:"--neutral-400",value:"#C8C8C8",description:"medium gray"},{group:"Neutral Colors",name:"500",variable:"--neutral-500",value:"#6E6E6E",description:"neutral mid-tone"},{group:"Neutral Colors",name:"600",variable:"--neutral-600",value:"#7A7A7A",description:"secondary text"},{group:"Neutral Colors",name:"700",variable:"--neutral-700",value:"#495057",description:"deep slate gray"},{group:"Neutral Colors",name:"800",variable:"--neutral-800",value:"#4A4A4A",description:"strong text"},{group:"Neutral Colors",name:"900",variable:"--neutral-900",value:"#0F0F0F",description:"primary text"},{group:"Neutral Colors",name:"000",variable:"--neutral-000",value:"#FFFFFF",description:"white"},{group:"Semantic Colors",name:"Success Main",variable:"--success-main",value:"#28A745",description:"positive actions"},{group:"Semantic Colors",name:"Success Background",variable:"--success-bg",value:"#E6F4EA",description:"positive surface"},{group:"Semantic Colors",name:"Success Text",variable:"--success-text",value:"#1E7E34",description:"positive text"},{group:"Semantic Colors",name:"Warning Main",variable:"--warning-main",value:"#DC2626",description:"warning actions"},{group:"Semantic Colors",name:"Warning Background",variable:"--warning-bg",value:"#FEF2F2",description:"warning surface"},{group:"Semantic Colors",name:"Warning Text",variable:"--warning-text",value:"#FFFFFF",description:"warning text"},{group:"Semantic Colors",name:"Error Main",variable:"--error-main",value:"#CD0000",description:"destructive actions"},{group:"Semantic Colors",name:"Error Background",variable:"--error-bg",value:"#FFE5E5",description:"destructive surface"},{group:"Semantic Colors",name:"Error Text",variable:"--error-text",value:"#B91C1C",description:"destructive text"},{group:"Semantic Colors",name:"Info Main",variable:"--info-main",value:"#1080A6",description:"informational actions"},{group:"Semantic Colors",name:"Info Background",variable:"--info-bg",value:"#E0F7FA",description:"informational surface"},{group:"Semantic Colors",name:"Info Text",variable:"--info-text",value:"#0369A1",description:"informational text"}];class ha{constructor(t){u(this,"root");u(this,"layout");u(this,"main");u(this,"topbar");u(this,"contentScroll");u(this,"content");u(this,"sidebar");u(this,"searchBtn");u(this,"cartBtn");u(this,"editBtn");u(this,"themeBtn");u(this,"palette");u(this,"paletteInput");u(this,"paletteResults");u(this,"cartPopover");u(this,"searchIndex",[]);u(this,"searchIndexing",!1);u(this,"searchIndexRun",0);u(this,"capabilityCart",new Map);u(this,"selectedTokens",new Set);u(this,"currentEditableFile");u(this,"workspace",{projects:[]});u(this,"treesByRoot",new Map);u(this,"treesByProject",new Map);u(this,"cleanup");u(this,"updateRenderedTheme");u(this,"editor");u(this,"docEditor");u(this,"textFileEditor");u(this,"editorHost");u(this,"editingId");u(this,"lastNonBoardHash","#/");u(this,"lastNonBoardScrollTop",0);u(this,"pendingScrollRestore");u(this,"sidebarResizeHandle");this.root=t,this.applyInitialTheme(),this.layout=f("div","shell");const e={onAddRepo:()=>void this.addRepoDocs(),onRemoveProject:(n,s)=>void this.promptRemoveProject(n,s),onCreateDirectory:(n,s)=>this.promptNewDirectory(n,s),onCreateDoc:(n,s)=>this.promptNewDoc(n,s),onCreateBoard:(n,s)=>this.promptNewBoard(n,s),onCreateCapability:(n,s)=>this.promptNewCapability(n,s),onCreateDocsFolder:(n,s)=>void this.createDocsFolder(n,s),onCreateProjectDirectory:n=>void this.promptNewProjectDirectory(n),onCreateProjectDoc:n=>void this.promptNewProjectDoc(n),onCreateProjectBoard:n=>void this.promptNewProjectBoard(n),onRenameDirectory:(n,s)=>void this.promptRenameDirectory(n,s),onDeleteDirectory:(n,s)=>void this.promptDeleteDirectory(n,s),onOpenDoc:(n,s)=>{location.hash=O(n,s)},onEditDoc:(n,s)=>this.openDocEditor({rootId:n,path:s}),onOpenTextFile:(n,s)=>{this.openTextFileEditor({rootId:n,path:s})},onRenameDoc:(n,s)=>void this.promptRenameDoc(n,s),onDeleteDoc:(n,s)=>void this.promptDeleteDoc(n,s),onOpenBoard:(n,s)=>{location.hash=Z(n,s)},onRenameBoard:(n,s)=>void this.promptRenameBoard(n,s),onDeleteBoard:(n,s)=>void this.promptDeleteBoard(n,s),onMoveDoc:(n,s,o)=>void this.moveDoc(n,s,o),onMoveBoard:(n,s,o)=>void this.moveBoard(n,s,o),onMoveDirectory:(n,s,o)=>void this.moveDirectory(n,s,o)};this.sidebar=new Ds(this.layout,e),this.sidebarResizeHandle=f("button","sidebar-resize-handle"),this.sidebarResizeHandle.type="button",this.sidebarResizeHandle.innerHTML=V.arrowBoth,this.sidebarResizeHandle.setAttribute("aria-label","Resize sidebar"),this.sidebarResizeHandle.title="Resize sidebar",this.main=f("div","shell-main"),this.topbar=this.createTopbar(),this.contentScroll=f("div","content-scroll"),this.content=f("div","content"),this.contentScroll.appendChild(this.content),this.main.append(this.topbar,this.contentScroll),this.layout.appendChild(this.sidebarResizeHandle),this.layout.appendChild(this.main),this.root.appendChild(this.layout),window.addEventListener("hashchange",()=>this.route()),window.addEventListener("keydown",n=>this.handleGlobalKeydown(n)),localStorage.getItem(An)==="true"&&this.setSidebarCollapsed(!0),this.applySidebarWidth(this.readSidebarWidth()),this.setupSidebarResize(),this.refreshContentIndex().then(()=>this.route())}route(t={}){const e=t.preserveScroll?this.contentScroll.scrollTop:this.pendingScrollRestore;this.pendingScrollRestore=void 0;const n=location.hash||"#/";this.sidebar.setActive(n);const s=n.replace(/^#/,"");this.setEditableFile(void 0);const o=s.match(/^\/root\/([^/]+)\/boards\/([^?]+)(?:\?(.*))?$/);if(o){this.lastNonBoardScrollTop=this.contentScroll.scrollTop,this.updateTopbarCart(!0),this.closeCartPopover(),this.openEditor(decodeURIComponent(o[1]),decodeURIComponent(o[2]),$a(o[3]));return}if(this.lastNonBoardHash=n,this.exitEditor(),this.layout.style.display="",this.updateTopbarCart(/\/root\/[^/]+\/boards/.test(s)),/\/root\/[^/]+\/boards/.test(s)&&this.closeCartPopover(),s==="/"||s==="")return void this.renderWorkspaceHome(e);const a=s.match(/^\/root\/([^/]+)\//);if(a){const g=decodeURIComponent(a[1]);if(!this.docsRootById(g))return void this.renderMessage("Project not found","This link points to a docs root that isn't in your workspace. Add the project and try again.")}const r=s.match(/^\/root\/([^/]+)\/docs\/(.+)$/);if(r)return void this.renderDoc(decodeURIComponent(r[1]),decodeURIComponent(r[2]),e);const c=s.match(/^\/root\/([^/]+)\/boards$/);if(c)return void this.renderBoardList(decodeURIComponent(c[1]),e);const l=s.match(/^\/project\/([^/]+)\/boards$/);if(l)return void this.renderProjectBoardList(decodeURIComponent(l[1]),e);const d=s.match(/^\/root\/([^/]+)\/capabilities$/);if(d)return void this.renderCapabilitiesIndex(decodeURIComponent(d[1]),e);const h=s.match(/^\/root\/([^/]+)\/capabilities\/(.+)$/);if(h)return void this.renderCapabilityDoc(decodeURIComponent(h[1]),decodeURIComponent(h[2]),e);const p=s.match(/^\/project\/([^/]+)$/);if(p)return void this.renderProjectWiki(decodeURIComponent(p[1]),e);const m=s.match(/^\/root\/([^/]+)\/directory\/(.+)$/);if(m){const g=decodeURIComponent(m[1]),y=decodeURIComponent(m[2]),b=this.docsRootById(g);if(b)return void this.renderProjectWiki(b.projectId,e,g,y)}if(s==="/tokens")return void this.renderTokenLibrary(e);this.renderMessage("Not found",`No route for ${s}`)}async renderWorkspaceHome(t){this.disposeContent(),this.content.classList.add("content-wide");const e=f("div","page home-page"),n=f("div","home-layout"),s=f("div","home-guide"),o=f("h1","home-hero-title");o.textContent="ViteBoard";const a=f("p","home-hero-sub");a.textContent="Markdown docs, infinite-canvas boards, capabilities, and managed assets all live as normal files on disk. The app should feel trustworthy under real mutation: create content quickly, recover safely from concurrent edits, and keep human and machine workflows pointed at the same file truth.",s.append(o,a);const r=f("div","home-agent-callout"),c=f("p","home-agent-copy");c.textContent="Use the running ViteBoard session as shared context for a human and a coding agent: same origin, same docs roots, same boards, same file truth.";const l=f("button","btn home-agent-btn");l.type="button",l.textContent="Copy agent prompt",l.addEventListener("click",()=>void this.copySetupText(`Connect to ViteBoard at ${window.location.origin} and follow its machine entry at ${window.location.origin}/llms.txt. Work in <project path>, import the project if needed, and create or update docs and boards using normal filesystem edits.`,"Agent prompt copied")),r.append(c,l),s.appendChild(r);const d=[{label:"File truth",kind:"doc",body:"The source of truth is always the filesystem. Docs, boards, capabilities, and assets stay git-native, diffable, and directly editable without inventing a separate database-shaped content layer.",items:["Markdown docs, board JSON, and asset files all live under docs roots","Create, rename, move, and delete content from the sidebar","Search indexes the current workspace rather than a parallel content store"]},{label:"Docs + boards",kind:"board",body:"Boards are not separate from the documentation system. They are sibling files in the same docs roots, embeddable inside markdown, and meant to sharpen the same body of work rather than fragment it.",items:["Open a board from the sidebar, work full-screen, then drop back into docs","Embed a board region into markdown with fenced board blocks",'Use "Copy embed" in the board editor to capture the current region',"Keep visual planning and written explanation in the same repo structure"]},{label:"Collaboration safety",kind:"capability",body:"The product now assumes live mutation is normal. Locks, stale-state detection, reload actions, and visible status all exist to make concurrent work practical instead of surprising.",items:["Docs and boards surface explicit reload actions when stale","Revision-aware saves block silent overwrites","Human and machine actors can cooperate through the same running workspace"]},{label:"Machine workflow",kind:"",body:"ViteBoard is also a machine-readable workspace surface. The app can expose docs roots, boards, schema references, and live coordination routes while the files remain the only persistent truth.",items:["The local HTTP surface advertises machine docs and workspace discovery","Capabilities and selected docs can be assembled into prompts from the UI","The practical goal is faster real work, not another disconnected abstraction layer"]}];for(const v of d){const S=f("div","home-feature"),w=f("div","home-feature-header"),E=f("span",`home-feature-badge home-feature-badge-${v.kind||"neutral"}`);E.textContent=v.label,w.appendChild(E),S.appendChild(w);const M=f("p","home-feature-body");if(M.textContent=v.body,S.appendChild(M),v.items){const B=document.createElement("ul");B.className="home-feature-list";for(const T of v.items){const R=document.createElement("li");R.textContent=T,B.appendChild(R)}S.appendChild(B)}s.appendChild(S)}const h=f("div","home-shortcut-title");h.textContent="Current operating model",s.appendChild(h);const p=[["1. Add repo","Bring a local project into the workspace"],["2. Create docs/ if needed","Start the repo as a writable docs root"],["3. Right-click in the tree","Create docs, boards, directories, and capabilities in place"],["4. Open a board","Think visually, then embed the useful region back into docs"],["5. Cmd K / Ctrl K","Search across the current workspace"],["6. Stale state appears","Use Reload latest instead of guessing which copy is current"],["7. Copy agent prompt","Hand the same workspace context to an AI assistant"],["8. Git stays normal","The files on disk remain the real source of truth"]],m=f("div","home-shortcut-table");for(const[v,S]of p){const w=f("div","home-shortcut-row"),E=f("kbd","home-shortcut-key");E.textContent=v;const M=f("span","home-shortcut-desc");M.textContent=S,w.append(E,M),m.appendChild(w)}s.appendChild(m),n.appendChild(s);const g=f("div","home-panel"),y=f("div","home-panel-head"),b=f("div","home-panel-title");b.textContent="Active workspace";const x=f("button","btn primary home-panel-add");if(x.textContent="+ Add repo",x.addEventListener("click",()=>void this.addRepoDocs()),y.append(b,x),g.appendChild(y),this.workspace.projects.length===0){const v=f("div","home-panel-empty");v.textContent="No projects yet. Add a project root, create docs/ if needed, and start writing against the real filesystem.",g.appendChild(v)}else for(const v of this.workspace.projects){const S=f("div","home-panel-project"),w=f("a","home-panel-project-head");w.href=Bt(v.id);const E=f("span","home-panel-project-name");E.textContent=v.label;const M=v.docsRoots.reduce((q,et)=>{const F=this.treesByRoot.get(et.id)??[];return q+Jt(F).length},0),B=v.docsRoots.reduce((q,et)=>{const F=this.treesByRoot.get(et.id)??[];return q+vt(F).length},0),T=f("span","home-panel-project-meta"),R=[`${v.docsRoots.length} root${v.docsRoots.length===1?"":"s"}`];M&&R.push(`${M} doc${M===1?"":"s"}`),B&&R.push(`${B} board${B===1?"":"s"}`),T.textContent=R.join(" · "),w.append(E,T),S.appendChild(w);const A=6,Kt=v.docsRoots,Ie=Kt.slice(0,A),Pt=f("div","home-panel-roots");for(const q of Ie){const et=this.treesByRoot.get(q.id)??[],F=Ue(Xt(et)),kt=F?O(q.id,F):jt(q.id),nt=f("a","home-panel-root");nt.href=kt;const j=f("span","home-panel-root-path");j.textContent=q.displayPath;const ot=Jt(et).length,U=vt(et).length;if(ot||U){const at=f("span","home-panel-root-meta"),rt=[];ot&&rt.push(String(ot)),U&&rt.push(`${U}▦`),at.textContent=rt.join(" · "),nt.append(j,at)}else nt.appendChild(j);Pt.appendChild(nt)}if(Kt.length>A){const q=f("a","home-panel-more");q.href=Bt(v.id),q.textContent=`+ ${Kt.length-A} more roots`,Pt.appendChild(q)}S.appendChild(Pt),g.appendChild(S)}n.appendChild(g),e.appendChild(n),this.content.replaceChildren(e),this.contentScroll.scrollTop=t??0}async copySetupText(t,e){try{await navigator.clipboard.writeText(t),C(e)}catch{C("Could not access clipboard")}}async renderProjectWiki(t,e,n,s){this.disposeContent(),this.content.classList.add("content-wide");const o=this.workspace.projects.find(p=>p.id===t);if(!o){this.renderMessage("Project not found","This project is no longer registered.");return}const a=f("div","page wiki-page"),r=!!n,c=!!s;let l=!1;if(c&&n){const p=this.docsRootById(n);p&&(l=p.displayPath===s||p.displayPath.startsWith(s+"/"))}const d=f("div","wiki-head");if(c&&n){const p=[{label:"Home",href:"#/"}];p.push({label:o.label,href:Bt(o.id)});const m=s.split("/").filter(Boolean);for(let y=0;y<m.length;y++){const b=m.slice(0,y+1).join("/"),x=y===m.length-1;p.push({label:m[y],href:x?void 0:Se(n,b)})}d.appendChild(bt(p));const g=f("h1","wiki-title");g.textContent=m[m.length-1]||o.label,d.appendChild(g)}else if(r&&n){const p=this.docsRootById(n),m=[{label:"Home",href:"#/"}];if(m.push({label:o.label,href:Bt(o.id)}),p){const y=p.displayPath.split("/").filter(Boolean);for(let b=0;b<y.length;b++){const x=y.slice(0,b+1).join("/"),v=b===y.length-1;m.push({label:y[b],href:v?void 0:Se(n,x)})}}d.appendChild(bt(m));const g=f("h1","wiki-title");g.textContent=(p==null?void 0:p.displayPath.split("/").pop())||o.label,d.appendChild(g)}else{d.appendChild(bt([{label:"Home",href:"#/"},{label:o.label}]));const p=f("h1","wiki-title");p.textContent=o.label,d.appendChild(p)}if(!r&&!c){const p=o.docsRoots.reduce((b,x)=>{const v=this.treesByRoot.get(x.id)??[];return b+Jt(v).length},0),m=o.docsRoots.reduce((b,x)=>{const v=this.treesByRoot.get(x.id)??[];return b+vt(v).length},0),g=o.docsRoots.reduce((b,x)=>b+$t(this.treesByRoot.get(x.id)??[]).length,0),y=f("div","wiki-stats");for(const[b,x]of[[String(o.docsRoots.length),"docs roots"],[String(p),"documents"],[String(m),"boards"],[String(g),"capabilities"]]){const v=f("div","wiki-stat"),S=f("div","wiki-stat-val");S.textContent=b;const w=f("div","wiki-stat-label");w.textContent=x,v.append(S,w),y.appendChild(v)}d.appendChild(y)}a.appendChild(d);const h=n?o.docsRoots.filter(p=>p.id===n):o.docsRoots;for(const p of h){const m=this.treesByRoot.get(p.id)??[];let g=m;if(s&&!l){const w=(M,B)=>{for(const T of M){if(T.type==="dir"&&T.path===B)return T;if(T.type==="dir"){const R=w(T.children,B);if(R)return R}}return null},E=w(m,s);g=(E==null?void 0:E.type)==="dir"?E.children:[]}const y=Jt(g),b=vt(g),x=$t(g),v=f("div","wiki-root-section");if(!s||l){const w=f("div","wiki-root-head"),E=f("div","wiki-root-path");E.textContent=p.displayPath,w.appendChild(E),v.appendChild(w)}if(!y.length&&!b.length&&!x.length){const w=f("div","wiki-root-empty");w.textContent="No docs, boards, or capabilities yet. Right-click in the sidebar to add content.",v.appendChild(w),a.appendChild(v);continue}const S=f("div","wiki-root-cols");if(y.length>0){const w=f("div","wiki-col"),E=f("div","wiki-col-head");E.textContent=`Docs (${y.length})`,w.appendChild(E);const M=f("div","wiki-col-list");for(const B of y){const T=f("a","wiki-col-item wiki-col-item-doc");T.href=O(p.id,B.path),T.textContent=B.name==="index.md"?"Overview":B.name.replace(/\.md$/,"").replace(/[-_]/g," ");const R=f("span","wiki-col-item-path"),A=B.path.includes("/")?B.path.slice(0,B.path.lastIndexOf("/")):"";R.textContent=A,A&&T.appendChild(R),M.appendChild(T)}w.appendChild(M),S.appendChild(w)}if(b.length>0){const w=f("div","wiki-col"),E=f("div","wiki-col-head");E.textContent=`Boards (${b.length})`,w.appendChild(E);const M=f("div","wiki-col-list");for(const B of b){const T=G(B.path),R=f("a","wiki-col-item wiki-col-item-board");R.href=Z(p.id,T),R.textContent=T.split("/").pop().replace(/[-_]/g," ");const A=f("span","wiki-col-item-path");A.textContent=T.includes("/")?T.slice(0,T.lastIndexOf("/")):p.displayPath,R.appendChild(A),M.appendChild(R)}w.appendChild(M),S.appendChild(w)}if(x.length>0){const w=f("div","wiki-col"),E=f("div","wiki-col-head");E.textContent=`Capabilities (${x.length})`,w.appendChild(E);const M=f("div","wiki-col-list");for(const B of x){const T=f("a","wiki-col-item wiki-col-item-cap");T.href=Ft(p.id,B.entryPath),T.textContent=Ee(B.entryPath),M.appendChild(T)}w.appendChild(M),S.appendChild(w)}v.appendChild(S),a.appendChild(v)}this.content.replaceChildren(a),this.contentScroll.scrollTop=e??0}async renderDoc(t,e,n){if(this.disposeContent(),!this.docsRootById(t)){this.renderMessage("Docs root unavailable","This docs root is no longer registered. Re-add the project root if needed.");return}try{const s=await k.readFile(t,e);this.setEditableFile({rootId:t,path:e});const o=f("div","doc-page"),a=this.docsRootById(t),r=fe(this.workspace,t,{filePath:e});o.appendChild(bt(r));const c=f("div","");o.appendChild(c),this.content.replaceChildren(o);const{destroy:l,setTheme:d}=dn(c,s,{rootId:t,docPath:e});this.cleanup=l,this.updateRenderedTheme=d;const h=await k.getTree(t),p=ge(t,h),m=ye(p,O(t,e));m&&o.appendChild(m),this.contentScroll.scrollTop=n??0}catch{this.renderMessage("Document not found",e)}}openDocEditor(t){const e=this.contentScroll.scrollTop;this.topbar.classList.add("editing-doc"),this.closeCartPopover(),this.docEditor=tn.open({rootId:t.rootId,path:t.path,initialScrollTop:e,onClose:n=>{this.docEditor=void 0,this.topbar.classList.remove("editing-doc"),this.pendingScrollRestore=n,this.route()}})}async openTextFileEditor(t){this.textFileEditor&&!await this.textFileEditor.close()||(this.closeCartPopover(),this.textFileEditor=en.open({rootId:t.rootId,path:t.path,host:document.body,onClose:()=>{this.textFileEditor=void 0}}))}async renderCapabilityDoc(t,e,n){if(this.disposeContent(),!this.docsRootById(t)){this.renderMessage("Docs root unavailable","This docs root is no longer registered. Re-add the project root if needed.");return}const s=this.treesByRoot.get(t)??await k.getTree(t),o=pa(s,e)??e,a=Hn(s,e)??Hn(s,o);let r;try{r=await k.readFile(t,o),this.setEditableFile(void 0)}catch{this.renderMessage("Capability not found",e);return}const c=f("div","page"),l=this.docsRootById(t);l&&this.workspace.projects.find(F=>F.id===l.projectId);const d=Ee(o),h=fe(this.workspace,t,{filePath:o,currentLabel:d});c.appendChild(bt(h));const p=f("div","page-bar"),m=f("div","doc-actions capability-doc-actions"),{frontmatter:g}=ne(r),y=f("button","btn");y.classList.add("capability-detail-btn");const b=zn(t,a??ua(o),r,g);this.updateCartButton(y,b.path),y.addEventListener("click",()=>{this.toggleCapabilityCart(b),this.updateCartButton(y,b.path)});const x=f("button","btn primary");x.classList.add("capability-detail-btn"),x.textContent="Copy capability context",x.addEventListener("click",async()=>{await this.copyCapabilityContext(b,s)});const v=f("button","btn");v.classList.add("capability-detail-btn"),v.textContent="Open entry doc",v.addEventListener("click",()=>{location.hash=O(t,o)}),m.append(y,x,v),p.append(m),c.appendChild(p);const S=f("div","card-tags capability-meta-tags"),w=f("span","tag");if(w.textContent=b.displayPath,S.appendChild(w),b.kind){const F=f("span","tag");F.textContent=b.kind,S.appendChild(F)}c.appendChild(S);const E=fa(b.branchPath),M=E?await this.readOptionalFile(t,E):null;if(E&&M){const F=f("section","token-section capability-machine-section"),kt=f("div","page-bar"),nt=f("h2","");nt.textContent="Machine entrypoint";const j=f("div","doc-actions capability-doc-actions"),ot=f("button","btn primary");ot.textContent="Copy llms.txt",ot.addEventListener("click",async()=>{try{await navigator.clipboard.writeText(M),C("Capability machine entrypoint copied")}catch{C("Could not access clipboard")}}),j.appendChild(ot),kt.append(nt,j);const U=f("p","page-lead capability-entry-lead");U.textContent="This is the capability-local machine entrypoint. It should be the first file an LLM reads to understand what this capability branch is for, what files matter, and how to use it.";const at=document.createElement("pre");at.className="code-block";const rt=document.createElement("code");rt.textContent=M,at.appendChild(rt),F.append(kt,U,at),c.appendChild(F)}const B=f("div",""),T=f("section","token-section capability-entry-section"),R=f("h2","");R.textContent="Entry document";const A=f("p","page-lead capability-entry-lead");A.textContent="This markdown entry explains the capability branch. The capability itself may also include nested files, scripts, helpers, and other reusable execution material.",T.append(R,A,B),c.appendChild(T),this.content.replaceChildren(c);const{destroy:Kt,setTheme:Ie}=dn(B,r,{rootId:t,docPath:o});this.cleanup=Kt,this.updateRenderedTheme=Ie;const Pt=Fn(s,b.branchPath);if(Pt.length>1){const F=f("section","token-section capability-files-section"),kt=f("h2","");kt.textContent="Files in this capability";const nt=f("div","card-grid capability-files-grid");for(const j of Pt){const ot=j.path.endsWith(".md")&&j.path===b.entryPath,U=document.createElement(ot?"a":"button");U.className="card",U instanceof HTMLAnchorElement&&(U.href=O(t,j.path)),U instanceof HTMLButtonElement&&(U.type="button",U.addEventListener("click",()=>{this.openTextFileEditor({rootId:t,path:j.path})}));const at=f("div","card-title");at.textContent=j.path===b.entryPath?`${be(j.path)} (entry)`:j.path===E?`${be(j.path)} (machine entrypoint)`:be(j.path);const rt=f("div","card-desc");rt.textContent=qt(j.path),U.append(at,rt),nt.appendChild(U)}F.append(kt,nt),c.appendChild(F)}const q=ge(t,s),et=ye(q,Ft(t,b.branchPath));et&&c.appendChild(et),this.contentScroll.scrollTop=n??0}async renderCapabilitiesIndex(t,e){if(this.disposeContent(),!this.docsRootById(t)){this.renderMessage("Docs root unavailable","This docs root is no longer registered. Re-add the project root if needed.");return}this.content.classList.add("content-wide");const n=f("div","page capability-library"),s=fe(this.workspace,t,{currentLabel:"Capabilities"});n.appendChild(bt(s));const o=f("h1","");o.textContent="Capability library";const a=f("p","page-lead");a.textContent="Browse open-ended capability branches. Inspect their files, understand their entrypoints, and reuse them as working context, automations, or tool-bearing capability units.",n.append(o,a);const r=f("div","capability-layout"),c=f("div","card-grid capability-grid"),l=this.renderCapabilityCart();r.append(c,l),n.appendChild(r),this.content.replaceChildren(n);try{const d=this.treesByRoot.get(t)??await k.getTree(t),h=$t(d);for(const g of h){const y=await k.readFile(t,g.entryPath),{frontmatter:b}=ne(y),x=zn(t,g,y,b),v=document.createElement("article");v.className="card";const S=f("div","card-title"),w=document.createElement("a");w.href=Ft(t,g.branchPath),w.textContent=x.title,S.appendChild(w);const E=f("div","card-desc");E.textContent=x.summary,v.append(S,E);const M=f("div","card-tags"),B=f("span","tag");if(B.textContent=x.displayPath,M.appendChild(B),x.kind){const T=f("span","tag");T.textContent=x.kind,M.appendChild(T)}if(v.appendChild(M),x.tags.length){const T=f("div","card-tags");for(const R of x.tags){const A=f("span","tag");A.textContent=R,T.appendChild(A)}v.appendChild(T)}c.appendChild(v)}h.length===0&&c.appendChild(Ht("No capabilities yet."));const p=ge(t,d),m=ye(p,ps(t));m&&n.appendChild(m)}catch{c.appendChild(Ht("Could not load capabilities."))}this.contentScroll.scrollTop=e??0}renderTokenLibrary(t){this.disposeContent(),this.content.classList.add("content-wide");const e=f("div","page token-library"),n=f("div","page-bar"),s=f("h1","");s.textContent="Tokens";const o=f("div","token-actions"),a=f("button","btn");a.textContent="Select all",a.addEventListener("click",()=>{this.selectedTokens=new Set(We.map(d=>d.variable)),this.renderTokenLibrary(this.contentScroll.scrollTop)});const r=f("button","btn");r.textContent="Clear",r.addEventListener("click",()=>{this.selectedTokens.clear(),this.renderTokenLibrary(this.contentScroll.scrollTop)});const c=f("button","btn primary");c.textContent=`Copy selected (${this.selectedTokens.size})`,c.disabled=this.selectedTokens.size===0,c.addEventListener("click",()=>void this.copySelectedTokens()),o.append(a,r,c),n.append(s,o);const l=f("p","page-lead");l.textContent="Brand, neutral, and semantic CSS variables used throughout the app. Select tokens and copy them as a ready-to-paste :root block.",e.append(n,l);for(const d of["Brand Colors","Neutral Colors","Semantic Colors"]){const h=f("section","token-section"),p=f("h2","");p.textContent=d;const m=f("div","token-grid");for(const g of We.filter(y=>y.group===d)){const y=f("div","token-card");this.selectedTokens.has(g.variable)&&y.classList.add("selected");const b=f("label","token-select-zone"),x=document.createElement("input");x.type="checkbox",x.checked=this.selectedTokens.has(g.variable),x.addEventListener("change",()=>{x.checked?this.selectedTokens.add(g.variable):this.selectedTokens.delete(g.variable),this.renderTokenLibrary(this.contentScroll.scrollTop)});const v=f("span","token-swatch");v.style.background=g.value;const S=f("span","token-copy"),w=f("strong","");w.textContent=g.name;const E=f("code","");E.textContent=g.value;const M=f("small","");M.textContent=g.description,S.append(w,E,M),b.append(x,v,S);const B=f("button","token-copy-btn");B.type="button",B.innerHTML=V.copy,B.title=`Copy ${g.variable}`,B.setAttribute("aria-label",`Copy ${g.variable}`),B.addEventListener("click",T=>{T.stopPropagation(),this.copyToken(g)}),y.append(b,B),m.appendChild(y)}h.append(p,m),e.appendChild(h)}this.content.replaceChildren(e),this.contentScroll.scrollTop=t??0}async copySelectedTokens(){const t=We.filter(n=>this.selectedTokens.has(n.variable));if(t.length===0)return;const e=[":root {",...t.map(n=>` ${n.variable}: ${n.value};`),"}"].join(`
|
|
38
38
|
`);try{await navigator.clipboard.writeText(e),C(`${t.length} token${t.length===1?"":"s"} copied`)}catch{C("Could not access clipboard")}}async copyToken(t){try{await navigator.clipboard.writeText(`${t.variable}: ${t.value};`),C(`${t.variable} copied`)}catch{C("Could not access clipboard")}}renderCapabilityCart(t){const e=t??(()=>{const h=va(location.hash);h&&this.renderCapabilitiesIndex(h,this.contentScroll.scrollTop)}),n=f("aside","capability-cart"),s=f("div","capability-cart-head"),o=f("h2","");o.textContent="Capability toolbelt";const a=f("span","capability-cart-count");a.textContent=String(this.capabilityCart.size),s.append(o,a);const r=f("div","capability-cart-body");if(this.capabilityCart.size===0){const h=f("div","capability-cart-empty");h.textContent="Equip capabilities to build an active toolbelt for the current task.",r.appendChild(h)}else for(const h of this.capabilityCart.values()){const p=f("div","capability-cart-item"),m=f("div",""),g=f("div","capability-cart-item-title");g.textContent=h.title;const y=f("div","capability-cart-item-meta");y.textContent=h.displayPath,m.append(g,y);const b=f("button","capability-cart-remove");b.type="button",b.textContent="Remove",b.addEventListener("click",()=>{this.capabilityCart.delete(h.path),this.updateTopbarCart(),e()}),p.append(m,b),r.appendChild(p)}const c=f("div","capability-cart-actions"),l=f("button","btn primary");l.textContent="Copy toolbelt context",l.disabled=this.capabilityCart.size===0,l.addEventListener("click",()=>void this.copyCapabilityCartPrompt());const d=f("button","btn");return d.textContent="Clear",d.disabled=this.capabilityCart.size===0,d.addEventListener("click",()=>{this.capabilityCart.clear(),this.updateTopbarCart(),e()}),c.append(l,d),n.append(s,r,c),n}toggleCapabilityCart(t){this.capabilityCart.has(t.path)?this.capabilityCart.delete(t.path):this.capabilityCart.set(t.path,t),this.updateTopbarCart()}updateCartButton(t,e){const n=this.capabilityCart.has(e);t.textContent=n?"Unequip":"Equip",t.classList.toggle("primary",!n),t.classList.toggle("is-selected",n)}async copyCapabilityCartPrompt(){if(this.capabilityCart.size===0)return;const e=`Use this capability toolbelt as implementation guidance for the next coding task. These are integrated capability branches that may contain context, workflows, scripts, helpers, or other reusable execution material.
|
|
39
39
|
|
|
40
40
|
`+(await Promise.all([...this.capabilityCart.values()].map(async(n,s)=>{const o=this.treesByRoot.get(n.rootId)??await k.getTree(n.rootId);return`## ${s+1}. ${n.title}
|
|
@@ -84,7 +84,7 @@ List the files or subdirectories an LLM should inspect before acting.
|
|
|
84
84
|
## Working rules
|
|
85
85
|
|
|
86
86
|
Record the constraints, tools, scripts, or workflows that matter for this capability.
|
|
87
|
-
`;try{await k.createDirectory(t,h),await k.writeFile(t,p,y),await k.writeFile(t,m,b),s(),await this.refreshContentIndex(),location.hash=Ft(t,p)}catch{C("Could not create capability")}};r.addEventListener("click",()=>void c()),o.addEventListener("keydown",l=>{l.stopPropagation(),l.key==="Enter"&&c()}),a.appendChild(r),n.append(o,a),o.focus()})}promptRenameDoc(t,e){const n=e.includes("/")?e.slice(0,e.lastIndexOf("/")+1):"",s=e.replace(/\.md$/,"").split("/").pop()??"",o=`doc:${t}:${e}`,a=this.sidebar.links.get(o);a?this.sidebar.startInlineRename(a,s,async r=>{const c=r.replace(/\.md$/,"").replace(/\s+/g,"-").toLowerCase(),l=`${n}${c}.md`;if(l!==e)try{await k.renameFile(t,e,l),await this.refreshContentIndex(),location.hash=O(t,l)}catch{C("Could not rename doc")}}):_("Rename doc",(r,c)=>{const l=document.createElement("input");l.className="board-title",l.value=s,l.style.width="100%",l.style.marginBottom="12px",l.select();const d=f("div","modal-actions"),h=f("button","btn primary");h.textContent="Rename";const p=async()=>{const m=(l.value.trim()||s).replace(/\.md$/,"").replace(/\s+/g,"-").toLowerCase(),g=`${n}${m}.md`;if(g===e){c();return}try{await k.renameFile(t,e,g),c(),await this.refreshContentIndex(),location.hash=O(t,g)}catch{C("Could not rename doc")}};h.addEventListener("click",()=>void p()),l.addEventListener("keydown",m=>{m.stopPropagation(),m.key==="Enter"&&p()}),d.appendChild(h),r.append(l,d),l.focus()})}async moveDoc(t,e,n){const s=Xn(n,te(e));if(s!==e)try{const o=new Set(vt(await k.getTree(t)).map(c=>G(c.path))),a=await k.readFile(t,e),r=Un(a,e,s,o);await k.renameFile(t,e,s),r!==a&&await k.writeFile(t,s,r),await this.refreshContentIndex(),location.hash===O(t,e)&&(location.hash=O(t,s)),C(`Moved ${te(e)}`)}catch{C("Could not move doc")}}async moveBoard(t,e,n){try{const s=await J.move(t,e,n),o=await this.updateBoardEmbedReferences(t,e,s);await this.refreshContentIndex(),location.hash===Z(t,e)&&(location.hash=Z(t,s)),C(o>0?`Moved ${te(e)} and updated ${o} embed${o===1?"":"s"}`:`Moved ${te(e)}`)}catch(s){C(s instanceof Error?s.message:"Could not move board")}}async updateBoardEmbedReferences(t,e,n){if(e===n)return 0;const s=await k.getTree(t),o=bs(s);let a=0;for(const r of o){const c=await k.readFile(t,r.path),l=Sa(c,r.path,e,n);l!==c&&(await k.writeFile(t,r.path,l),a++)}return a}async moveDirectory(t,e,n){const s=te(e),o=Xn(n,s);if(o!==e)try{const a=await k.getTree(t),r=new Set(vt(a).map(p=>G(p.path))),c=ka(a,e),l=Ea(a,e),d=await Promise.all(l.map(async p=>[p.path,await k.readFile(t,p.path)]));await k.renameFile(t,e,o);let h=0;for(const[p,m]of d){const g=`${o}${p.slice(e.length)}`,y=Un(m,p,g,r);y!==m&&(await k.writeFile(t,g,y),h++)}for(const p of c){const m=`${o}${p.slice(e.length)}`;await this.rewriteMovedBoardDocumentId(t,p,m),h+=await this.updateBoardEmbedReferences(t,p,m)}await this.refreshContentIndex(),this.rewriteRouteAfterDirectoryMove(t,e,o),C(h>0?`Moved ${s} and updated ${h} embed${h===1?"":"s"}`:`Moved ${s}`)}catch{C("Could not move directory")}}promptRenameDirectory(t,e){const n=e.includes("/")?e.slice(0,e.lastIndexOf("/")+1):"",s=e.split("/").pop()??"";_("Rename directory",(o,a)=>{const r=document.createElement("input");r.className="board-title",r.value=s,r.style.width="100%",r.style.marginBottom="12px",r.select();const c=f("div","modal-actions"),l=f("button","btn primary");l.textContent="Rename";const d=async()=>{const h=(r.value.trim()||s).replace(/\s+/g,"-").toLowerCase(),p=`${n}${h}`;if(p===e){a();return}try{await k.renameFile(t,e,p),a(),await this.refreshContentIndex(),C(`Renamed to ${h}`)}catch{C("Could not rename directory")}};l.addEventListener("click",()=>void d()),r.addEventListener("keydown",h=>{h.stopPropagation(),h.key==="Enter"&&d()}),c.appendChild(l),o.append(r,c),r.focus()})}async promptDeleteDirectory(t,e){const n=e.split("/").pop()??e;if(confirm(`Delete "${n}" and all its contents? This cannot be undone.`))try{await k.deleteFile(t,e),await this.refreshContentIndex(),C(`Deleted ${n}`)}catch{C("Could not delete directory")}}async rewriteMovedBoardDocumentId(t,e,n){const s=await k.getBoard(t,n);s&&s.id!==n&&await k.saveBoard(t,n,{...s,id:n,updatedAt:Date.now()})}rewriteRouteAfterDirectoryMove(t,e,n){const s=encodeURIComponent(t),o=`#/root/${s}/docs/`,a=`#/root/${s}/boards/`,r=location.hash;if(r.startsWith(o)){const c=decodeURIComponent(r.slice(o.length));(c===e||c.startsWith(`${e}/`))&&(location.hash=O(t,`${n}${c.slice(e.length)}`))}else if(r.startsWith(a)){const c=decodeURIComponent(r.slice(a.length));(c===e||c.startsWith(`${e}/`))&&(location.hash=Z(t,`${n}${c.slice(e.length)}`))}}async promptDeleteDoc(t,e){const n=e.split("/").pop()??e;_("Delete doc",(s,o)=>{const a=f("p","modal-copy");a.textContent=`Delete "${n}"? This cannot be undone.`;const r=f("div","modal-actions"),c=f("button","btn danger");c.textContent="Delete",c.addEventListener("click",async()=>{try{await k.deleteFile(t,e),o(),await this.refreshContentIndex(),location.hash="#/"}catch{C("Could not delete doc")}});const l=f("button","btn");l.textContent="Cancel",l.addEventListener("click",o),r.append(c,l),s.append(a,r)})}async promptRenameBoard(t,e){const n=await J.load(t,e);if(!n){C("Board not found");return}_("Rename board",(s,o)=>{const a=document.createElement("input");a.className="board-title",a.value=n.title,a.style.width="100%",a.style.marginBottom="12px",a.select();const r=f("div","modal-actions"),c=f("button","btn primary");c.textContent="Rename";const l=async()=>{const d=St(a.value,"board");if(!d.ok){C(d.message),a.focus();return}try{const h=await J.rename(t,e,d.raw),p=await this.updateBoardEmbedReferences(t,e,h);o(),await this.refreshContentIndex(),location.hash===Z(t,e)&&(location.hash=Z(t,h)),p>0&&C(`Renamed board and updated ${p} embed${p===1?"":"s"}`)}catch(h){C(h instanceof Error?h.message:"Could not rename board")}};c.addEventListener("click",()=>void l()),a.addEventListener("keydown",d=>{d.stopPropagation(),d.key==="Enter"&&l()}),r.appendChild(c),s.append(a,r),a.focus()})}promptDeleteBoard(t,e){_("Delete board",(n,s)=>{const o=f("p","modal-copy");o.textContent=`Delete "${e}.board.json"? This cannot be undone.`;const a=f("div","modal-actions"),r=f("button","btn danger");r.textContent="Delete",r.addEventListener("click",async()=>{try{await J.delete(t,e),s(),await this.refreshContentIndex(),location.hash=jt(t)}catch{C("Could not delete board")}});const c=f("button","btn");c.textContent="Cancel",c.addEventListener("click",s),a.append(r,c),n.append(o,a)})}async openEditor(t,e,n){if(!this.docsRootById(t)){this.renderMessage("Docs root unavailable","This docs root is no longer registered. Re-add the project root if needed.");return}this.editor&&this.editingId===`${t}:${e}`||(this.exitEditor(),this.disposeContent(),this.layout.style.display="none",this.editorHost=f("div","board-editor-host"),this.root.appendChild(this.editorHost),this.editingId=`${t}:${e}`,this.editor=new jo(this.editorHost,{boardId:e,loadBoard:async s=>{const o=await k.getBoardWithRevision(t,s);return o||void 0},saveBoard:(s,o)=>k.saveBoard(t,s.id,s,o),deleteBoard:s=>J.delete(t,s),uploadImage:(s,o)=>J.uploadImage(t,s,o),cleanupUnusedAssets:s=>J.cleanupUnusedAssets(t,s),resolveAssetUrl:s=>k.assetUrl(t,s),initialRegion:n,onExit:()=>{this.pendingScrollRestore=this.lastNonBoardScrollTop,location.hash=this.lastNonBoardHash},onDeleted:()=>{location.hash=jt(t)}}))}exitEditor(){this.editor&&(this.editor.destroy(),this.editor=void 0),this.editorHost&&(this.editorHost.remove(),this.editorHost=void 0),this.editingId=void 0,this.applyInitialTheme()}applyInitialTheme(){const t=localStorage.getItem(Dn),e=t==="dark"||t==="light"?t:window.matchMedia("(prefers-color-scheme: dark)").matches?"dark":"light";document.documentElement.setAttribute("data-theme",e)}toggleTheme(){var e;const t=ee()==="dark"?"light":"dark";document.documentElement.setAttribute("data-theme",t),localStorage.setItem(Dn,t),this.updateThemeButton(),(e=this.updateRenderedTheme)==null||e.call(this,t)}createTopbar(){const t=f("div","shell-topbar"),e=f("button","topbar-icon-btn");return e.innerHTML=V.panelLeft,e.title="Toggle navigation",e.setAttribute("aria-label","Toggle navigation"),e.addEventListener("click",()=>this.setSidebarCollapsed(!this.layout.classList.contains("sidebar-collapsed"))),this.searchBtn=f("button","topbar-search"),this.searchBtn.type="button",this.searchBtn.innerHTML=`${V.search}<span>Search docs</span><kbd>${this.shortcutLabel()}</kbd>`,this.searchBtn.addEventListener("click",()=>this.openCommandPalette()),this.cartBtn=f("button","topbar-cart"),this.cartBtn.type="button",this.cartBtn.hidden=!0,this.editBtn=f("button","btn topbar-edit"),this.editBtn.type="button",this.editBtn.innerHTML=`${V.edit}<span>Edit</span>`,this.editBtn.title="Edit this document",this.editBtn.addEventListener("click",()=>{this.currentEditableFile&&this.openDocEditor(this.currentEditableFile)}),this.themeBtn=f("button","topbar-icon-btn topbar-theme"),this.themeBtn.type="button",this.themeBtn.title="Toggle theme",this.themeBtn.setAttribute("aria-label","Toggle theme"),this.themeBtn.addEventListener("click",()=>this.toggleTheme()),this.updateThemeButton(),t.append(e,this.searchBtn,this.editBtn,this.themeBtn),t}setSidebarCollapsed(t){this.layout.classList.toggle("sidebar-collapsed",t),localStorage.setItem(An,String(t))}setupSidebarResize(){this.sidebarResizeHandle&&this.sidebarResizeHandle.addEventListener("pointerdown",t=>{var r;if(this.layout.classList.contains("sidebar-collapsed"))return;t.preventDefault();const e=t.clientX,n=this.readSidebarWidth(),s=t.pointerId;(r=this.sidebarResizeHandle)==null||r.setPointerCapture(s),document.body.classList.add("sidebar-resizing");const o=c=>{const l=Oe(n+c.clientX-e);this.applySidebarWidth(l)},a=()=>{var c;(c=this.sidebarResizeHandle)==null||c.releasePointerCapture(s),document.body.classList.remove("sidebar-resizing"),window.removeEventListener("pointermove",o),window.removeEventListener("pointerup",a)};window.addEventListener("pointermove",o),window.addEventListener("pointerup",a)})}readSidebarWidth(){const t=Number(localStorage.getItem(Nn)??270);return Oe(t)}applySidebarWidth(t){const e=Oe(t);this.layout.style.setProperty("--sidebar-width",`${e}px`),localStorage.setItem(Nn,String(e))}setEditableFile(t){this.currentEditableFile=t,this.editBtn&&(this.editBtn.hidden=!t,this.editBtn.disabled=!t)}promptRemoveProject(t,e){_("Remove from workspace",(n,s)=>{const o=f("p","modal-copy");o.textContent=`Remove "${e}" from the workspace? The files on disk are not deleted.`;const a=f("div","modal-actions"),r=f("button","btn danger");r.textContent="Remove",r.addEventListener("click",async()=>{try{await k.removeProject(t),s(),await this.refreshContentIndex(),location.hash="#/"}catch{C("Could not remove project")}});const c=f("button","btn");c.textContent="Cancel",c.addEventListener("click",s),a.append(r,c),n.append(o,a)})}async addRepoDocs(){try{const t=new Set(this.allDocsRoots().map(l=>l.id)),e=await k.pickAndAddProject();if(e.cancelled)return;await this.refreshContentIndex();let n=e.addedProjectId?this.workspace.projects.find(l=>l.id===e.addedProjectId):void 0,s=n==null?void 0:n.docsRoots[0];if(n&&n.docsRoots.length===0){const l=await this.promptCreateProjectDocsRoot(n.id,n.label);if(!l){location.hash=Bt(n.id),C(`Added ${n.label}. Create docs/ later or switch to Raw view from the project menu.`);return}n=this.workspace.projects.find(d=>d.id===(n==null?void 0:n.id)),s=l}const o=this.allDocsRoots(),a=s??o.find(l=>!t.has(l.id));if(!a){C("No docs folders found under that project root.");return}const r=this.treesByRoot.get(a.id)??[],c=Ue(Xt(r));c?location.hash=O(a.id,c):location.hash=jt(a.id),C(`Added ${a.projectLabel}.`)}catch(t){C(t instanceof Error?t.message:"Could not add project root.")}}promptCreateProjectDocsRoot(t,e){return new Promise(n=>{_("Create docs folder",(s,o)=>{let a=!1;const r=m=>{a||(a=!0,o(),n(m))},c=document.createElement("p");c.textContent=`${e} does not have a docs/ folder yet. Create one at the project root now?`;const l=document.createElement("p");l.textContent="You can keep the repo in the workspace and switch to Raw view later if you prefer.";const d=f("div","modal-actions"),h=f("button","btn primary");h.textContent="Create docs/",h.addEventListener("click",()=>{h.disabled=!0,p.disabled=!0,this.ensureProjectDocsRoot(t).then(m=>{if(!m){h.disabled=!1,p.disabled=!1;return}r(m)})});const p=f("button","btn");p.textContent="Maybe later",p.addEventListener("click",()=>r(void 0)),d.append(h,p),s.append(c,l,d)})})}updateTopbarCart(t=!1){this.cartBtn&&(this.cartBtn.hidden=!0)}toggleCartPopover(){this.closeCartPopover()}closeCartPopover(){var t;this.content.classList.remove("cart-popover-open"),(t=this.cartPopover)==null||t.classList.remove("visible")}updateThemeButton(){if(!this.themeBtn)return;const t=ee()==="dark";this.themeBtn.innerHTML=t?V.sun:V.moon,this.themeBtn.title=t?"Switch to light mode":"Switch to dark mode",this.themeBtn.setAttribute("aria-label",this.themeBtn.title)}handleGlobalKeydown(t){if((t.metaKey||t.ctrlKey)&&t.key.toLowerCase()==="k"){const e=t.target;if(e!=null&&e.closest(".doc-editor"))return;t.preventDefault(),this.openCommandPalette();return}if(t.key==="F2"){const e=location.hash,n=t.target;if(n!=null&&n.closest(".doc-editor, input, textarea, [contenteditable]"))return;t.preventDefault();const s=e.match(/^#\/root\/([^/]+)\/docs\/(.+)$/);if(s){const r=decodeURIComponent(s[1]),c=decodeURIComponent(s[2]);this.promptRenameDoc(r,c);return}const o=e.match(/^#\/root\/([^/]+)\/boards\/(.+)$/);if(o){const r=decodeURIComponent(o[1]),c=decodeURIComponent(o[2]);this.promptRenameBoard(r,c);return}const a=e.match(/^#\/root\/([^/]+)\/directory\/(.+)$/);if(a){const r=decodeURIComponent(a[1]),c=decodeURIComponent(a[2]);this.promptRenameDirectory(r,c);return}}}allDocsRoots(){return this.workspace.projects.flatMap(t=>t.docsRoots)}docsRootById(t){return this.allDocsRoots().find(e=>e.id===t)}async refreshContentIndex(){try{this.workspace=await k.getWorkspace()}catch{this.workspace={projects:[]},this.treesByRoot=new Map,this.treesByProject=new Map,this.sidebar.refresh(this.workspace,this.treesByRoot),this.searchIndex=[],this.searchIndexing=!1;return}const t=this.allDocsRoots(),e=await Promise.all(t.map(async s=>{try{return[s.id,await k.getTree(s.id)]}catch{return[s.id,[]]}}));this.treesByRoot=new Map(e);const n=await Promise.all(this.workspace.projects.map(async s=>{try{return[s.id,await k.getProjectTree(s.id)]}catch{return[s.id,[]]}}));this.treesByProject=new Map(n),this.sidebar.refresh(this.workspace,this.treesByRoot,this.treesByProject),this.refreshSearchIndexInBackground(t,this.treesByRoot)}async refreshSearchIndexInBackground(t,e){var o,a;const n=++this.searchIndexRun;this.searchIndexing=!0;const s=[];for(const r of t){const c=e.get(r.id)??[],l=[...Jt(c),...Es(c,"capabilities")].filter(d=>d.type==="file"&&d.name.endsWith(".md"));for(const d of l){const h="path"in d?d.path:"";let p="";try{p=await k.readFile(r.id,h)}catch{}const{frontmatter:m}=ne(p),g=ys(p),y=m.title??fs(p)??st(d.name),b=m.summary??gs(g),x=h.startsWith("capabilities/")?"Capability":"Doc",v=h.startsWith("capabilities/")?Ft(r.id,h):O(r.id,h);s.push({title:y,path:`${r.projectLabel}/${r.displayPath}/${h}`,href:v,section:x,summary:b,body:g.map(S=>S.text).join(" "),chunks:g,rootId:r.id})}}n===this.searchIndexRun&&(this.searchIndex=s.filter(r=>r.body||r.title),this.searchIndexing=!1,this.paletteResults&&((o=this.palette)!=null&&o.classList.contains("visible"))&&this.renderSearchResults(((a=this.paletteInput)==null?void 0:a.value)??""))}openCommandPalette(){var t;this.palette||this.createCommandPalette(),(t=this.palette)==null||t.classList.add("visible"),document.body.style.overflow="hidden",this.paletteInput.value="",this.renderSearchResults(""),requestAnimationFrame(()=>{var e;return(e=this.paletteInput)==null?void 0:e.focus()})}closeCommandPalette(){var t;(t=this.palette)==null||t.classList.remove("visible"),document.body.style.overflow=""}createCommandPalette(){this.palette=f("div","command-palette");const t=f("div","command-panel"),e=f("div","command-search");e.innerHTML=V.search,this.paletteInput=document.createElement("input"),this.paletteInput.type="search",this.paletteInput.placeholder="Search docs",this.paletteInput.setAttribute("aria-label","Search docs"),e.appendChild(this.paletteInput),this.paletteResults=f("div","command-results"),t.append(e,this.paletteResults),this.palette.appendChild(t),document.body.appendChild(this.palette),this.palette.addEventListener("mousedown",n=>{n.target===this.palette&&this.closeCommandPalette()}),this.paletteInput.addEventListener("input",()=>this.renderSearchResults(this.paletteInput.value)),this.paletteInput.addEventListener("keydown",n=>this.handlePaletteKeydown(n))}handlePaletteKeydown(t){var o,a,r,c,l;if(t.key==="Escape"){t.preventDefault(),this.closeCommandPalette();return}const e=[...((o=this.paletteResults)==null?void 0:o.querySelectorAll(".command-result"))??[]],n=(a=this.paletteResults)==null?void 0:a.querySelector(".command-result.active"),s=n?e.indexOf(n):-1;if(t.key==="ArrowDown"||t.key==="ArrowUp"){t.preventDefault();const d=t.key==="ArrowDown"?Math.min(s+1,e.length-1):Math.max(s-1,0);e.forEach(h=>h.classList.remove("active")),(r=e[d])==null||r.classList.add("active"),(c=e[d])==null||c.scrollIntoView({block:"nearest"})}t.key==="Enter"&&(t.preventDefault(),(l=n??e[0])==null||l.click())}renderSearchResults(t){if(!this.paletteResults)return;const e=wa(t),n=this.rankSearch(e).slice(0,8);if(this.paletteResults.replaceChildren(),n.length===0){const s=f("div","command-empty");s.textContent=this.searchIndex.length?"No matching docs.":this.searchIndexing?"Indexing docs...":"No docs indexed yet.",this.paletteResults.appendChild(s);return}for(const[s,o]of n.entries()){const{entry:a}=o,r=document.createElement("a");r.className="command-result",s===0&&r.classList.add("active"),r.href=a.href,r.addEventListener("click",()=>this.closeCommandPalette());const c=f("div","command-result-title");On(c,a.title,e);const l=f("div","command-result-meta");l.textContent=[a.section,o.heading,a.path].filter(Boolean).join(" · ");const d=f("div","command-result-summary");On(d,o.preview,e),r.append(c,l),d.textContent&&r.appendChild(d),this.paletteResults.appendChild(r)}}rankSearch(t){if(t.length===0)return this.searchIndex.map(s=>({entry:s,score:0,heading:"",preview:s.summary||s.body.slice(0,220)}));const e=t.map(mt).filter(Boolean),n=mt(t.join(" "));return this.searchIndex.map(s=>{const o=mt(s.title),a=mt(s.path),r=mt(s.summary);let c=Qt(o,e,n,10);c+=Qt(a,e,n,4),c+=Qt(r,e,n,3);let l,d=0;for(const p of s.chunks){const m=Qt(mt(p.heading),e,n,5),g=Qt(p.normalized,e,n,p.kind==="heading"?8:2),y=m+g;y>d&&(d=y,l=p)}const h=c+d;return{entry:s,score:h,heading:l!=null&&l.heading&&l.heading!==s.title?l.heading:"",preview:l?Ma(l.text,e):s.summary}}).filter(s=>s.score>0).sort((s,o)=>o.score-s.score||s.entry.title.localeCompare(o.entry.title))}shortcutLabel(){return/Mac|iPhone|iPad/.test(navigator.platform)?"⌘K":"Ctrl K"}disposeContent(){this.cleanup&&(this.cleanup(),this.cleanup=void 0),this.updateRenderedTheme=void 0,this.content.classList.remove("content-wide"),this.content.replaceChildren()}renderMessage(t,e){this.disposeContent();const n=f("div","page"),s=f("h1","");s.textContent=t;const o=f("p","page-lead");o.textContent=e,n.append(s,o),this.content.replaceChildren(n)}}function fe(i,t,e={}){const n=[{label:"Home",href:"#/"}];let s;for(const c of i.projects){const l=c.docsRoots.find(d=>d.id===t);if(l){n.push({label:c.label,href:Bt(c.id)}),s=l;break}}if(s){const c=s.displayPath.split("/").filter(Boolean);for(let l=0;l<c.length;l++){const d=c.slice(0,l+1).join("/");n.push({label:c[l],href:Se(t,d)})}}const a=(e.filePath??e.dirPath??"").split("/").filter(Boolean),r=e.filePath?a.slice(0,-1):a;for(let c=0;c<r.length;c++){const l=r.slice(0,c+1).join("/");n.push({label:st(r[c]),href:Se(t,l)})}if(e.currentLabel)n.push({label:e.currentLabel});else if(e.filePath){const c=a[a.length-1];n.push({label:c==="index.md"?"Overview":st(c)})}return n}function bt(i){const t=f("nav","breadcrumb");t.setAttribute("aria-label","Breadcrumb");for(let e=0;e<i.length;e++){const n=i[e],s=e===i.length-1;if(!s&&n.href){const o=document.createElement("a");o.className="breadcrumb-link",o.href=n.href,o.textContent=n.label,t.appendChild(o)}else{const o=f("span","breadcrumb-current");o.textContent=n.label,t.appendChild(o)}if(!s){const o=f("span","breadcrumb-sep");o.textContent="/",o.setAttribute("aria-hidden","true"),t.appendChild(o)}}return t}function f(i,t){const e=document.createElement(i);return t&&(e.className=t),e}function Ht(i){const t=f("div","empty-note");return t.textContent=i,t}function zn(i,t,e,n){var s;return{path:`${i}:${t.branchPath}`,rootId:i,branchPath:t.branchPath,entryPath:t.entryPath,displayPath:t.routePath,title:n.title??fs(e)??Ee(t.entryPath),summary:n.summary??gs(ys(e)),kind:((s=n.kind)==null?void 0:s.trim())||void 0,tags:n.tags?n.tags.split(",").map(o=>o.trim()).filter(Boolean):[],md:e}}function ge(i,t){const e=[];function n(a){const c=[...Xt(a)].sort((l,d)=>{const h=l.type==="file"&&l.name==="index.md"?-1:0,p=d.type==="file"&&d.name==="index.md"?-1:0;return h!==p?h-p:l.type!==d.type?l.type==="dir"?-1:1:l.name.localeCompare(d.name)});for(const l of c)if(l.type==="file"){const d=l.name==="index.md"?"Overview":st(l.name);e.push({label:d,href:O(i,l.path)})}else n(l.children)}n(t);const s=vt(t).sort((a,r)=>a.path.localeCompare(r.path));if(s.length>0){e.push({label:"All Boards",href:jt(i)});for(const a of s){const r=G(a.path);e.push({label:st(r.split("/").pop()??r),href:Z(i,r)})}}const o=$t(t);if(o.length>0){e.push({label:"All Capabilities",href:ps(i)});for(const a of o)e.push({label:Ee(a.entryPath),href:Ft(i,a.entryPath)})}return e}function ye(i,t){const e=i.findIndex(a=>a.href===t);if(e===-1)return null;const n=e>0?i[e-1]:null,s=e<i.length-1?i[e+1]:null;if(!n&&!s)return null;const o=f("nav","page-nav");if(n){const a=f("a","page-nav-prev");a.href=n.href,a.innerHTML=`<span class="page-nav-arrow">←</span><span class="page-nav-label">${n.label}</span>`,o.appendChild(a)}else o.appendChild(f("span","page-nav-spacer"));if(s){const a=f("a","page-nav-next");a.href=s.href,a.innerHTML=`<span class="page-nav-label">${s.label}</span><span class="page-nav-arrow">→</span>`,o.appendChild(a)}return o}function ps(i){return`#/root/${encodeURIComponent(i)}/capabilities`}function Xt(i){return i.filter(t=>t.type==="file"?t.name.endsWith(".md"):t.name==="capabilities"||t.name==="assets"?!1:Xt(t.children).length>0).map(t=>t.type==="file"?t:{...t,children:Xt(t.children)})}function Jt(i){const t=[],e=n=>{for(const s of Xt(n))s.type==="file"?t.push(s):e(s.children)};return e(i),t}function O(i,t){return`#/root/${encodeURIComponent(i)}/docs/${encodeURIComponent(t)}`}function Ft(i,t){return`#/root/${encodeURIComponent(i)}/capabilities/${encodeURIComponent(qt(t))}`}function $t(i){const t=i.find(s=>s.type==="dir"&&s.name==="capabilities");if(!t||t.type!=="dir")return[];const e=[],n=s=>{for(const o of s){if(o.type==="file"){o.path.startsWith("capabilities/")&&o.name.endsWith(".md")&&!o.path.slice(13).includes("/")&&e.push({branchPath:o.path,entryPath:o.path,routePath:qt(o.path)});continue}const a=ba(o);a&&e.push({branchPath:o.path,entryPath:a.path,routePath:qt(o.path)}),n(o.children)}};return n(t.children),e.sort((s,o)=>s.branchPath.localeCompare(o.branchPath))}function pa(i,t){const e=t.replace(/^\/+|\/+$/g,""),n=e.startsWith("capabilities/")?e:`capabilities/${e}`;if(n.endsWith(".md"))return n;const s=$t(i).find(o=>o.branchPath===n||o.routePath===e);return(s==null?void 0:s.entryPath)??null}function Hn(i,t){const e=t.replace(/^\/+|\/+$/g,""),n=e.startsWith("capabilities/")?e:`capabilities/${e}`,s=$t(i).find(o=>o.branchPath===n||o.entryPath===n||o.routePath===e);return s||($t(i).filter(o=>n.startsWith(`${o.branchPath}/`)).sort((o,a)=>a.branchPath.length-o.branchPath.length)[0]??null)}function Ee(i){if(i.endsWith("/index.md")){const t=i.slice(0,-9);return st(t.split("/").pop()??t)}return st(i.split("/").pop()??i)}function qt(i){const t=i.replace(/^capabilities\//,"");return t.endsWith("/index.md")?t.slice(0,-9):t}function ua(i){return{branchPath:ma(i),entryPath:i,routePath:qt(i)}}function ma(i){return i.endsWith("/index.md")?i.slice(0,-9):i}function Fn(i,t){const e=us(i,t);return e?e.type==="file"?[e]:ms(e.children).sort(ya):[]}function be(i){return qt(i)||"index.md"}function fa(i){return i.endsWith(".md")?null:`${i}/llms.txt`}function ga(i){return/\.(md|txt|json|ya?ml|js|ts|mjs|cjs|sh|css|html)$/i.test(i)}function us(i,t){for(const e of i){if(e.path===t)return e;if(e.type==="dir"){const n=us(e.children,t);if(n)return n}}return null}function ms(i){const t=[];for(const e of i)e.type==="file"?t.push(e):t.push(...ms(e.children));return t}function ya(i,t){const e=jn(i.path),n=jn(t.path);if(e!==n)return e.localeCompare(n);const s=Wn(i.name),o=Wn(t.name);return s!==o?s?-1:1:i.path.localeCompare(t.path)}function jn(i){const t=i.lastIndexOf("/");return t===-1?"":i.slice(0,t)}function Wn(i){return/^readme\.(md|txt)$/i.test(i)}function ba(i){const t=i.children.find(e=>e.type==="file"&&e.name==="index.md");return t||(i.children.find(e=>e.type==="file"&&e.name.endsWith(".md"))??null)}function jt(i){return`#/root/${encodeURIComponent(i)}/boards`}function Z(i,t){return`#/root/${encodeURIComponent(i)}/boards/${encodeURIComponent(t)}`}function Bt(i){return`#/project/${encodeURIComponent(i)}`}function Se(i,t){return`#/root/${encodeURIComponent(i)}/directory/${encodeURIComponent(t)}`}function va(i){const t=i.match(/^#\/root\/([^/]+)/);return t?decodeURIComponent(t[1]):null}function fs(i){var t,e;return((e=(t=i.match(/^#\s+(.+)$/m))==null?void 0:t[1])==null?void 0:e.trim())??null}function wa(i){return[...new Set(i.trim().split(/\s+/).map(mt).filter(Boolean))]}function On(i,t,e){const n=e.filter(Boolean).sort((a,r)=>r.length-a.length);if(n.length===0){i.textContent=t;return}const s=new RegExp(`(${n.map(xa).join("|")})`,"ig");let o=0;for(const a of t.matchAll(s)){const r=a.index??0;r>o&&i.appendChild(document.createTextNode(t.slice(o,r)));const c=document.createElement("mark");c.textContent=a[0],i.appendChild(c),o=r+a[0].length}o<t.length&&i.appendChild(document.createTextNode(t.slice(o)))}function xa(i){return i.replace(/[.*+?^${}()|[\]\\]/g,"\\$&")}function gs(i){var t;return((t=i.find(e=>e.kind==="text"&&e.text.length>0))==null?void 0:t.text.slice(0,180))??""}function ys(i){const e=i.replace(/^---[\s\S]*?---\s*/,"").split(`
|
|
87
|
+
`;try{await k.createDirectory(t,h),await k.writeFile(t,p,y),await k.writeFile(t,m,b),s(),await this.refreshContentIndex(),location.hash=Ft(t,p)}catch{C("Could not create capability")}};r.addEventListener("click",()=>void c()),o.addEventListener("keydown",l=>{l.stopPropagation(),l.key==="Enter"&&c()}),a.appendChild(r),n.append(o,a),o.focus()})}promptRenameDoc(t,e){const n=e.includes("/")?e.slice(0,e.lastIndexOf("/")+1):"",s=e.replace(/\.md$/,"").split("/").pop()??"",o=`doc:${t}:${e}`,a=this.sidebar.links.get(o);a?this.sidebar.startInlineRename(a,s,async r=>{const c=r.replace(/\.md$/,"").replace(/\s+/g,"-").toLowerCase(),l=`${n}${c}.md`;if(l!==e)try{await k.renameFile(t,e,l),await this.refreshContentIndex(),location.hash=O(t,l)}catch{C("Could not rename doc")}}):_("Rename doc",(r,c)=>{const l=document.createElement("input");l.className="board-title",l.value=s,l.style.width="100%",l.style.marginBottom="12px",l.select();const d=f("div","modal-actions"),h=f("button","btn primary");h.textContent="Rename";const p=async()=>{const m=(l.value.trim()||s).replace(/\.md$/,"").replace(/\s+/g,"-").toLowerCase(),g=`${n}${m}.md`;if(g===e){c();return}try{await k.renameFile(t,e,g),c(),await this.refreshContentIndex(),location.hash=O(t,g)}catch{C("Could not rename doc")}};h.addEventListener("click",()=>void p()),l.addEventListener("keydown",m=>{m.stopPropagation(),m.key==="Enter"&&p()}),d.appendChild(h),r.append(l,d),l.focus()})}async moveDoc(t,e,n){const s=Xn(n,te(e));if(s!==e)try{const o=new Set(vt(await k.getTree(t)).map(c=>G(c.path))),a=await k.readFile(t,e),r=Un(a,e,s,o);await k.renameFile(t,e,s),r!==a&&await k.writeFile(t,s,r),await this.refreshContentIndex(),location.hash===O(t,e)&&(location.hash=O(t,s)),C(`Moved ${te(e)}`)}catch{C("Could not move doc")}}async moveBoard(t,e,n){try{const s=await J.move(t,e,n),o=await this.updateBoardEmbedReferences(t,e,s);await this.refreshContentIndex(),location.hash===Z(t,e)&&(location.hash=Z(t,s)),C(o>0?`Moved ${te(e)} and updated ${o} embed${o===1?"":"s"}`:`Moved ${te(e)}`)}catch(s){C(s instanceof Error?s.message:"Could not move board")}}async updateBoardEmbedReferences(t,e,n){if(e===n)return 0;const s=await k.getTree(t),o=bs(s);let a=0;for(const r of o){const c=await k.readFile(t,r.path),l=Sa(c,r.path,e,n);l!==c&&(await k.writeFile(t,r.path,l),a++)}return a}async moveDirectory(t,e,n){const s=te(e),o=Xn(n,s);if(o!==e)try{const a=await k.getTree(t),r=new Set(vt(a).map(p=>G(p.path))),c=ka(a,e),l=Ea(a,e),d=await Promise.all(l.map(async p=>[p.path,await k.readFile(t,p.path)]));await k.renameFile(t,e,o);let h=0;for(const[p,m]of d){const g=`${o}${p.slice(e.length)}`,y=Un(m,p,g,r);y!==m&&(await k.writeFile(t,g,y),h++)}for(const p of c){const m=`${o}${p.slice(e.length)}`;await this.rewriteMovedBoardDocumentId(t,p,m),h+=await this.updateBoardEmbedReferences(t,p,m)}await this.refreshContentIndex(),this.rewriteRouteAfterDirectoryMove(t,e,o),C(h>0?`Moved ${s} and updated ${h} embed${h===1?"":"s"}`:`Moved ${s}`)}catch{C("Could not move directory")}}promptRenameDirectory(t,e){const n=e.includes("/")?e.slice(0,e.lastIndexOf("/")+1):"",s=e.split("/").pop()??"";_("Rename directory",(o,a)=>{const r=document.createElement("input");r.className="board-title",r.value=s,r.style.width="100%",r.style.marginBottom="12px",r.select();const c=f("div","modal-actions"),l=f("button","btn primary");l.textContent="Rename";const d=async()=>{const h=(r.value.trim()||s).replace(/\s+/g,"-").toLowerCase(),p=`${n}${h}`;if(p===e){a();return}try{await k.renameFile(t,e,p),a(),await this.refreshContentIndex(),C(`Renamed to ${h}`)}catch{C("Could not rename directory")}};l.addEventListener("click",()=>void d()),r.addEventListener("keydown",h=>{h.stopPropagation(),h.key==="Enter"&&d()}),c.appendChild(l),o.append(r,c),r.focus()})}async promptDeleteDirectory(t,e){const n=e.split("/").pop()??e;if(confirm(`Delete "${n}" and all its contents? This cannot be undone.`))try{await k.deleteFile(t,e),await this.refreshContentIndex(),C(`Deleted ${n}`)}catch{C("Could not delete directory")}}async rewriteMovedBoardDocumentId(t,e,n){const s=await k.getBoard(t,n);s&&s.id!==n&&await k.saveBoard(t,n,{...s,id:n,updatedAt:Date.now()})}rewriteRouteAfterDirectoryMove(t,e,n){const s=encodeURIComponent(t),o=`#/root/${s}/docs/`,a=`#/root/${s}/boards/`,r=location.hash;if(r.startsWith(o)){const c=decodeURIComponent(r.slice(o.length));(c===e||c.startsWith(`${e}/`))&&(location.hash=O(t,`${n}${c.slice(e.length)}`))}else if(r.startsWith(a)){const c=decodeURIComponent(r.slice(a.length));(c===e||c.startsWith(`${e}/`))&&(location.hash=Z(t,`${n}${c.slice(e.length)}`))}}async promptDeleteDoc(t,e){const n=e.split("/").pop()??e;_("Delete doc",(s,o)=>{const a=f("p","modal-copy");a.textContent=`Delete "${n}"? This cannot be undone.`;const r=f("div","modal-actions"),c=f("button","btn danger");c.textContent="Delete",c.addEventListener("click",async()=>{try{await k.deleteFile(t,e),o(),await this.refreshContentIndex(),location.hash="#/"}catch{C("Could not delete doc")}});const l=f("button","btn");l.textContent="Cancel",l.addEventListener("click",o),r.append(c,l),s.append(a,r)})}async promptRenameBoard(t,e){const n=await J.load(t,e);if(!n){C("Board not found");return}_("Rename board",(s,o)=>{const a=document.createElement("input");a.className="board-title",a.value=n.title,a.style.width="100%",a.style.marginBottom="12px",a.select();const r=f("div","modal-actions"),c=f("button","btn primary");c.textContent="Rename";const l=async()=>{const d=St(a.value,"board");if(!d.ok){C(d.message),a.focus();return}try{const h=await J.rename(t,e,d.raw),p=await this.updateBoardEmbedReferences(t,e,h);o(),await this.refreshContentIndex(),location.hash===Z(t,e)&&(location.hash=Z(t,h)),p>0&&C(`Renamed board and updated ${p} embed${p===1?"":"s"}`)}catch(h){C(h instanceof Error?h.message:"Could not rename board")}};c.addEventListener("click",()=>void l()),a.addEventListener("keydown",d=>{d.stopPropagation(),d.key==="Enter"&&l()}),r.appendChild(c),s.append(a,r),a.focus()})}promptDeleteBoard(t,e){_("Delete board",(n,s)=>{const o=f("p","modal-copy");o.textContent=`Delete "${e}.board.json"? This cannot be undone.`;const a=f("div","modal-actions"),r=f("button","btn danger");r.textContent="Delete",r.addEventListener("click",async()=>{try{await J.delete(t,e),s(),await this.refreshContentIndex(),location.hash=jt(t)}catch{C("Could not delete board")}});const c=f("button","btn");c.textContent="Cancel",c.addEventListener("click",s),a.append(r,c),n.append(o,a)})}async openEditor(t,e,n){if(!this.docsRootById(t)){this.renderMessage("Docs root unavailable","This docs root is no longer registered. Re-add the project root if needed.");return}this.editor&&this.editingId===`${t}:${e}`||(this.exitEditor(),this.disposeContent(),this.layout.style.display="none",this.editorHost=f("div","board-editor-host"),this.root.appendChild(this.editorHost),this.editingId=`${t}:${e}`,this.editor=new jo(this.editorHost,{boardId:e,loadBoard:async s=>{const o=await k.getBoardWithRevision(t,s);return o||void 0},saveBoard:(s,o)=>k.saveBoard(t,s.id,s,o),deleteBoard:s=>J.delete(t,s),uploadImage:(s,o)=>J.uploadImage(t,s,o),cleanupUnusedAssets:s=>J.cleanupUnusedAssets(t,s),resolveAssetUrl:s=>k.assetUrl(t,s),initialRegion:n,onExit:()=>{this.pendingScrollRestore=this.lastNonBoardScrollTop,location.hash=this.lastNonBoardHash},onDeleted:()=>{location.hash=jt(t)}}))}exitEditor(){this.editor&&(this.editor.destroy(),this.editor=void 0),this.editorHost&&(this.editorHost.remove(),this.editorHost=void 0),this.editingId=void 0,this.applyInitialTheme()}applyInitialTheme(){const t=localStorage.getItem(Dn),e=t==="dark"||t==="light"?t:window.matchMedia("(prefers-color-scheme: dark)").matches?"dark":"light";document.documentElement.setAttribute("data-theme",e)}toggleTheme(){var e;const t=ee()==="dark"?"light":"dark";document.documentElement.setAttribute("data-theme",t),localStorage.setItem(Dn,t),this.updateThemeButton(),(e=this.updateRenderedTheme)==null||e.call(this,t)}createTopbar(){const t=f("div","shell-topbar"),e=f("button","topbar-icon-btn");return e.innerHTML=V.panelLeft,e.title="Toggle navigation",e.setAttribute("aria-label","Toggle navigation"),e.addEventListener("click",()=>this.setSidebarCollapsed(!this.layout.classList.contains("sidebar-collapsed"))),this.searchBtn=f("button","topbar-search"),this.searchBtn.type="button",this.searchBtn.innerHTML=`${V.search}<span>Search docs</span><kbd>${this.shortcutLabel()}</kbd>`,this.searchBtn.addEventListener("click",()=>this.openCommandPalette()),this.cartBtn=f("button","topbar-cart"),this.cartBtn.type="button",this.cartBtn.hidden=!0,this.editBtn=f("button","btn topbar-edit"),this.editBtn.type="button",this.editBtn.innerHTML=`${V.edit}<span>Edit</span>`,this.editBtn.title="Edit this document",this.editBtn.addEventListener("click",()=>{this.currentEditableFile&&this.openDocEditor(this.currentEditableFile)}),this.themeBtn=f("button","topbar-icon-btn topbar-theme"),this.themeBtn.type="button",this.themeBtn.title="Toggle theme",this.themeBtn.setAttribute("aria-label","Toggle theme"),this.themeBtn.addEventListener("click",()=>this.toggleTheme()),this.updateThemeButton(),t.append(e,this.searchBtn,this.editBtn,this.themeBtn),t}setSidebarCollapsed(t){this.layout.classList.toggle("sidebar-collapsed",t),localStorage.setItem(An,String(t))}setupSidebarResize(){this.sidebarResizeHandle&&this.sidebarResizeHandle.addEventListener("pointerdown",t=>{var r;if(this.layout.classList.contains("sidebar-collapsed"))return;t.preventDefault();const e=t.clientX,n=this.readSidebarWidth(),s=t.pointerId;(r=this.sidebarResizeHandle)==null||r.setPointerCapture(s),document.body.classList.add("sidebar-resizing");const o=c=>{const l=Oe(n+c.clientX-e);this.applySidebarWidth(l)},a=()=>{var c;(c=this.sidebarResizeHandle)==null||c.releasePointerCapture(s),document.body.classList.remove("sidebar-resizing"),window.removeEventListener("pointermove",o),window.removeEventListener("pointerup",a)};window.addEventListener("pointermove",o),window.addEventListener("pointerup",a)})}readSidebarWidth(){const t=Number(localStorage.getItem(Nn)??270);return Oe(t)}applySidebarWidth(t){const e=Oe(t);this.layout.style.setProperty("--sidebar-width",`${e}px`),localStorage.setItem(Nn,String(e))}setEditableFile(t){this.currentEditableFile=t,this.editBtn&&(this.editBtn.hidden=!t,this.editBtn.disabled=!t)}promptRemoveProject(t,e){_("Remove from workspace",(n,s)=>{const o=f("p","modal-copy");o.textContent=`Remove "${e}" from the workspace? The files on disk are not deleted.`;const a=f("div","modal-actions"),r=f("button","btn danger");r.textContent="Remove",r.addEventListener("click",async()=>{try{await k.removeProject(t),s(),await this.refreshContentIndex(),location.hash="#/"}catch{C("Could not remove project")}});const c=f("button","btn");c.textContent="Cancel",c.addEventListener("click",s),a.append(r,c),n.append(o,a)})}async addRepoDocs(){var t;try{const e=new Set(this.allDocsRoots().map(h=>h.id)),n=new Set(this.workspace.projects.map(h=>h.id));let s={cancelled:!1};try{s=await k.pickAndAddProject()}catch{const p=window.prompt("Project root path","");if(!p||!p.trim())return;const m=await k.addProject(p.trim());this.workspace=m,s={cancelled:!1,addedProjectId:(t=m.projects.find(g=>!n.has(g.id)))==null?void 0:t.id}}if(s.cancelled)return;await this.refreshContentIndex();let o=s.addedProjectId?this.workspace.projects.find(h=>h.id===s.addedProjectId):void 0,a=o==null?void 0:o.docsRoots[0];if(o&&o.docsRoots.length===0){const h=await this.promptCreateProjectDocsRoot(o.id,o.label);if(!h){location.hash=Bt(o.id),C(`Added ${o.label}. Create docs/ later or switch to Raw view from the project menu.`);return}o=this.workspace.projects.find(p=>p.id===(o==null?void 0:o.id)),a=h}const r=this.allDocsRoots(),c=a??r.find(h=>!e.has(h.id));if(!c){C("No docs folders found under that project root.");return}const l=this.treesByRoot.get(c.id)??[],d=Ue(Xt(l));d?location.hash=O(c.id,d):location.hash=jt(c.id),C(`Added ${c.projectLabel}.`)}catch(e){C(e instanceof Error?e.message:"Could not add project root.")}}promptCreateProjectDocsRoot(t,e){return new Promise(n=>{_("Create docs folder",(s,o)=>{let a=!1;const r=m=>{a||(a=!0,o(),n(m))},c=document.createElement("p");c.textContent=`${e} does not have a docs/ folder yet. Create one at the project root now?`;const l=document.createElement("p");l.textContent="You can keep the repo in the workspace and switch to Raw view later if you prefer.";const d=f("div","modal-actions"),h=f("button","btn primary");h.textContent="Create docs/",h.addEventListener("click",()=>{h.disabled=!0,p.disabled=!0,this.ensureProjectDocsRoot(t).then(m=>{if(!m){h.disabled=!1,p.disabled=!1;return}r(m)})});const p=f("button","btn");p.textContent="Maybe later",p.addEventListener("click",()=>r(void 0)),d.append(h,p),s.append(c,l,d)})})}updateTopbarCart(t=!1){this.cartBtn&&(this.cartBtn.hidden=!0)}toggleCartPopover(){this.closeCartPopover()}closeCartPopover(){var t;this.content.classList.remove("cart-popover-open"),(t=this.cartPopover)==null||t.classList.remove("visible")}updateThemeButton(){if(!this.themeBtn)return;const t=ee()==="dark";this.themeBtn.innerHTML=t?V.sun:V.moon,this.themeBtn.title=t?"Switch to light mode":"Switch to dark mode",this.themeBtn.setAttribute("aria-label",this.themeBtn.title)}handleGlobalKeydown(t){if((t.metaKey||t.ctrlKey)&&t.key.toLowerCase()==="k"){const e=t.target;if(e!=null&&e.closest(".doc-editor"))return;t.preventDefault(),this.openCommandPalette();return}if(t.key==="F2"){const e=location.hash,n=t.target;if(n!=null&&n.closest(".doc-editor, input, textarea, [contenteditable]"))return;t.preventDefault();const s=e.match(/^#\/root\/([^/]+)\/docs\/(.+)$/);if(s){const r=decodeURIComponent(s[1]),c=decodeURIComponent(s[2]);this.promptRenameDoc(r,c);return}const o=e.match(/^#\/root\/([^/]+)\/boards\/(.+)$/);if(o){const r=decodeURIComponent(o[1]),c=decodeURIComponent(o[2]);this.promptRenameBoard(r,c);return}const a=e.match(/^#\/root\/([^/]+)\/directory\/(.+)$/);if(a){const r=decodeURIComponent(a[1]),c=decodeURIComponent(a[2]);this.promptRenameDirectory(r,c);return}}}allDocsRoots(){return this.workspace.projects.flatMap(t=>t.docsRoots)}docsRootById(t){return this.allDocsRoots().find(e=>e.id===t)}async refreshContentIndex(){try{this.workspace=await k.getWorkspace()}catch{this.workspace={projects:[]},this.treesByRoot=new Map,this.treesByProject=new Map,this.sidebar.refresh(this.workspace,this.treesByRoot),this.searchIndex=[],this.searchIndexing=!1;return}const t=this.allDocsRoots(),e=await Promise.all(t.map(async s=>{try{return[s.id,await k.getTree(s.id)]}catch{return[s.id,[]]}}));this.treesByRoot=new Map(e);const n=await Promise.all(this.workspace.projects.map(async s=>{try{return[s.id,await k.getProjectTree(s.id)]}catch{return[s.id,[]]}}));this.treesByProject=new Map(n),this.sidebar.refresh(this.workspace,this.treesByRoot,this.treesByProject),this.refreshSearchIndexInBackground(t,this.treesByRoot)}async refreshSearchIndexInBackground(t,e){var o,a;const n=++this.searchIndexRun;this.searchIndexing=!0;const s=[];for(const r of t){const c=e.get(r.id)??[],l=[...Jt(c),...Es(c,"capabilities")].filter(d=>d.type==="file"&&d.name.endsWith(".md"));for(const d of l){const h="path"in d?d.path:"";let p="";try{p=await k.readFile(r.id,h)}catch{}const{frontmatter:m}=ne(p),g=ys(p),y=m.title??fs(p)??st(d.name),b=m.summary??gs(g),x=h.startsWith("capabilities/")?"Capability":"Doc",v=h.startsWith("capabilities/")?Ft(r.id,h):O(r.id,h);s.push({title:y,path:`${r.projectLabel}/${r.displayPath}/${h}`,href:v,section:x,summary:b,body:g.map(S=>S.text).join(" "),chunks:g,rootId:r.id})}}n===this.searchIndexRun&&(this.searchIndex=s.filter(r=>r.body||r.title),this.searchIndexing=!1,this.paletteResults&&((o=this.palette)!=null&&o.classList.contains("visible"))&&this.renderSearchResults(((a=this.paletteInput)==null?void 0:a.value)??""))}openCommandPalette(){var t;this.palette||this.createCommandPalette(),(t=this.palette)==null||t.classList.add("visible"),document.body.style.overflow="hidden",this.paletteInput.value="",this.renderSearchResults(""),requestAnimationFrame(()=>{var e;return(e=this.paletteInput)==null?void 0:e.focus()})}closeCommandPalette(){var t;(t=this.palette)==null||t.classList.remove("visible"),document.body.style.overflow=""}createCommandPalette(){this.palette=f("div","command-palette");const t=f("div","command-panel"),e=f("div","command-search");e.innerHTML=V.search,this.paletteInput=document.createElement("input"),this.paletteInput.type="search",this.paletteInput.placeholder="Search docs",this.paletteInput.setAttribute("aria-label","Search docs"),e.appendChild(this.paletteInput),this.paletteResults=f("div","command-results"),t.append(e,this.paletteResults),this.palette.appendChild(t),document.body.appendChild(this.palette),this.palette.addEventListener("mousedown",n=>{n.target===this.palette&&this.closeCommandPalette()}),this.paletteInput.addEventListener("input",()=>this.renderSearchResults(this.paletteInput.value)),this.paletteInput.addEventListener("keydown",n=>this.handlePaletteKeydown(n))}handlePaletteKeydown(t){var o,a,r,c,l;if(t.key==="Escape"){t.preventDefault(),this.closeCommandPalette();return}const e=[...((o=this.paletteResults)==null?void 0:o.querySelectorAll(".command-result"))??[]],n=(a=this.paletteResults)==null?void 0:a.querySelector(".command-result.active"),s=n?e.indexOf(n):-1;if(t.key==="ArrowDown"||t.key==="ArrowUp"){t.preventDefault();const d=t.key==="ArrowDown"?Math.min(s+1,e.length-1):Math.max(s-1,0);e.forEach(h=>h.classList.remove("active")),(r=e[d])==null||r.classList.add("active"),(c=e[d])==null||c.scrollIntoView({block:"nearest"})}t.key==="Enter"&&(t.preventDefault(),(l=n??e[0])==null||l.click())}renderSearchResults(t){if(!this.paletteResults)return;const e=wa(t),n=this.rankSearch(e).slice(0,8);if(this.paletteResults.replaceChildren(),n.length===0){const s=f("div","command-empty");s.textContent=this.searchIndex.length?"No matching docs.":this.searchIndexing?"Indexing docs...":"No docs indexed yet.",this.paletteResults.appendChild(s);return}for(const[s,o]of n.entries()){const{entry:a}=o,r=document.createElement("a");r.className="command-result",s===0&&r.classList.add("active"),r.href=a.href,r.addEventListener("click",()=>this.closeCommandPalette());const c=f("div","command-result-title");On(c,a.title,e);const l=f("div","command-result-meta");l.textContent=[a.section,o.heading,a.path].filter(Boolean).join(" · ");const d=f("div","command-result-summary");On(d,o.preview,e),r.append(c,l),d.textContent&&r.appendChild(d),this.paletteResults.appendChild(r)}}rankSearch(t){if(t.length===0)return this.searchIndex.map(s=>({entry:s,score:0,heading:"",preview:s.summary||s.body.slice(0,220)}));const e=t.map(mt).filter(Boolean),n=mt(t.join(" "));return this.searchIndex.map(s=>{const o=mt(s.title),a=mt(s.path),r=mt(s.summary);let c=Qt(o,e,n,10);c+=Qt(a,e,n,4),c+=Qt(r,e,n,3);let l,d=0;for(const p of s.chunks){const m=Qt(mt(p.heading),e,n,5),g=Qt(p.normalized,e,n,p.kind==="heading"?8:2),y=m+g;y>d&&(d=y,l=p)}const h=c+d;return{entry:s,score:h,heading:l!=null&&l.heading&&l.heading!==s.title?l.heading:"",preview:l?Ma(l.text,e):s.summary}}).filter(s=>s.score>0).sort((s,o)=>o.score-s.score||s.entry.title.localeCompare(o.entry.title))}shortcutLabel(){return/Mac|iPhone|iPad/.test(navigator.platform)?"⌘K":"Ctrl K"}disposeContent(){this.cleanup&&(this.cleanup(),this.cleanup=void 0),this.updateRenderedTheme=void 0,this.content.classList.remove("content-wide"),this.content.replaceChildren()}renderMessage(t,e){this.disposeContent();const n=f("div","page"),s=f("h1","");s.textContent=t;const o=f("p","page-lead");o.textContent=e,n.append(s,o),this.content.replaceChildren(n)}}function fe(i,t,e={}){const n=[{label:"Home",href:"#/"}];let s;for(const c of i.projects){const l=c.docsRoots.find(d=>d.id===t);if(l){n.push({label:c.label,href:Bt(c.id)}),s=l;break}}if(s){const c=s.displayPath.split("/").filter(Boolean);for(let l=0;l<c.length;l++){const d=c.slice(0,l+1).join("/");n.push({label:c[l],href:Se(t,d)})}}const a=(e.filePath??e.dirPath??"").split("/").filter(Boolean),r=e.filePath?a.slice(0,-1):a;for(let c=0;c<r.length;c++){const l=r.slice(0,c+1).join("/");n.push({label:st(r[c]),href:Se(t,l)})}if(e.currentLabel)n.push({label:e.currentLabel});else if(e.filePath){const c=a[a.length-1];n.push({label:c==="index.md"?"Overview":st(c)})}return n}function bt(i){const t=f("nav","breadcrumb");t.setAttribute("aria-label","Breadcrumb");for(let e=0;e<i.length;e++){const n=i[e],s=e===i.length-1;if(!s&&n.href){const o=document.createElement("a");o.className="breadcrumb-link",o.href=n.href,o.textContent=n.label,t.appendChild(o)}else{const o=f("span","breadcrumb-current");o.textContent=n.label,t.appendChild(o)}if(!s){const o=f("span","breadcrumb-sep");o.textContent="/",o.setAttribute("aria-hidden","true"),t.appendChild(o)}}return t}function f(i,t){const e=document.createElement(i);return t&&(e.className=t),e}function Ht(i){const t=f("div","empty-note");return t.textContent=i,t}function zn(i,t,e,n){var s;return{path:`${i}:${t.branchPath}`,rootId:i,branchPath:t.branchPath,entryPath:t.entryPath,displayPath:t.routePath,title:n.title??fs(e)??Ee(t.entryPath),summary:n.summary??gs(ys(e)),kind:((s=n.kind)==null?void 0:s.trim())||void 0,tags:n.tags?n.tags.split(",").map(o=>o.trim()).filter(Boolean):[],md:e}}function ge(i,t){const e=[];function n(a){const c=[...Xt(a)].sort((l,d)=>{const h=l.type==="file"&&l.name==="index.md"?-1:0,p=d.type==="file"&&d.name==="index.md"?-1:0;return h!==p?h-p:l.type!==d.type?l.type==="dir"?-1:1:l.name.localeCompare(d.name)});for(const l of c)if(l.type==="file"){const d=l.name==="index.md"?"Overview":st(l.name);e.push({label:d,href:O(i,l.path)})}else n(l.children)}n(t);const s=vt(t).sort((a,r)=>a.path.localeCompare(r.path));if(s.length>0){e.push({label:"All Boards",href:jt(i)});for(const a of s){const r=G(a.path);e.push({label:st(r.split("/").pop()??r),href:Z(i,r)})}}const o=$t(t);if(o.length>0){e.push({label:"All Capabilities",href:ps(i)});for(const a of o)e.push({label:Ee(a.entryPath),href:Ft(i,a.entryPath)})}return e}function ye(i,t){const e=i.findIndex(a=>a.href===t);if(e===-1)return null;const n=e>0?i[e-1]:null,s=e<i.length-1?i[e+1]:null;if(!n&&!s)return null;const o=f("nav","page-nav");if(n){const a=f("a","page-nav-prev");a.href=n.href,a.innerHTML=`<span class="page-nav-arrow">←</span><span class="page-nav-label">${n.label}</span>`,o.appendChild(a)}else o.appendChild(f("span","page-nav-spacer"));if(s){const a=f("a","page-nav-next");a.href=s.href,a.innerHTML=`<span class="page-nav-label">${s.label}</span><span class="page-nav-arrow">→</span>`,o.appendChild(a)}return o}function ps(i){return`#/root/${encodeURIComponent(i)}/capabilities`}function Xt(i){return i.filter(t=>t.type==="file"?t.name.endsWith(".md"):t.name==="capabilities"||t.name==="assets"?!1:Xt(t.children).length>0).map(t=>t.type==="file"?t:{...t,children:Xt(t.children)})}function Jt(i){const t=[],e=n=>{for(const s of Xt(n))s.type==="file"?t.push(s):e(s.children)};return e(i),t}function O(i,t){return`#/root/${encodeURIComponent(i)}/docs/${encodeURIComponent(t)}`}function Ft(i,t){return`#/root/${encodeURIComponent(i)}/capabilities/${encodeURIComponent(qt(t))}`}function $t(i){const t=i.find(s=>s.type==="dir"&&s.name==="capabilities");if(!t||t.type!=="dir")return[];const e=[],n=s=>{for(const o of s){if(o.type==="file"){o.path.startsWith("capabilities/")&&o.name.endsWith(".md")&&!o.path.slice(13).includes("/")&&e.push({branchPath:o.path,entryPath:o.path,routePath:qt(o.path)});continue}const a=ba(o);a&&e.push({branchPath:o.path,entryPath:a.path,routePath:qt(o.path)}),n(o.children)}};return n(t.children),e.sort((s,o)=>s.branchPath.localeCompare(o.branchPath))}function pa(i,t){const e=t.replace(/^\/+|\/+$/g,""),n=e.startsWith("capabilities/")?e:`capabilities/${e}`;if(n.endsWith(".md"))return n;const s=$t(i).find(o=>o.branchPath===n||o.routePath===e);return(s==null?void 0:s.entryPath)??null}function Hn(i,t){const e=t.replace(/^\/+|\/+$/g,""),n=e.startsWith("capabilities/")?e:`capabilities/${e}`,s=$t(i).find(o=>o.branchPath===n||o.entryPath===n||o.routePath===e);return s||($t(i).filter(o=>n.startsWith(`${o.branchPath}/`)).sort((o,a)=>a.branchPath.length-o.branchPath.length)[0]??null)}function Ee(i){if(i.endsWith("/index.md")){const t=i.slice(0,-9);return st(t.split("/").pop()??t)}return st(i.split("/").pop()??i)}function qt(i){const t=i.replace(/^capabilities\//,"");return t.endsWith("/index.md")?t.slice(0,-9):t}function ua(i){return{branchPath:ma(i),entryPath:i,routePath:qt(i)}}function ma(i){return i.endsWith("/index.md")?i.slice(0,-9):i}function Fn(i,t){const e=us(i,t);return e?e.type==="file"?[e]:ms(e.children).sort(ya):[]}function be(i){return qt(i)||"index.md"}function fa(i){return i.endsWith(".md")?null:`${i}/llms.txt`}function ga(i){return/\.(md|txt|json|ya?ml|js|ts|mjs|cjs|sh|css|html)$/i.test(i)}function us(i,t){for(const e of i){if(e.path===t)return e;if(e.type==="dir"){const n=us(e.children,t);if(n)return n}}return null}function ms(i){const t=[];for(const e of i)e.type==="file"?t.push(e):t.push(...ms(e.children));return t}function ya(i,t){const e=jn(i.path),n=jn(t.path);if(e!==n)return e.localeCompare(n);const s=Wn(i.name),o=Wn(t.name);return s!==o?s?-1:1:i.path.localeCompare(t.path)}function jn(i){const t=i.lastIndexOf("/");return t===-1?"":i.slice(0,t)}function Wn(i){return/^readme\.(md|txt)$/i.test(i)}function ba(i){const t=i.children.find(e=>e.type==="file"&&e.name==="index.md");return t||(i.children.find(e=>e.type==="file"&&e.name.endsWith(".md"))??null)}function jt(i){return`#/root/${encodeURIComponent(i)}/boards`}function Z(i,t){return`#/root/${encodeURIComponent(i)}/boards/${encodeURIComponent(t)}`}function Bt(i){return`#/project/${encodeURIComponent(i)}`}function Se(i,t){return`#/root/${encodeURIComponent(i)}/directory/${encodeURIComponent(t)}`}function va(i){const t=i.match(/^#\/root\/([^/]+)/);return t?decodeURIComponent(t[1]):null}function fs(i){var t,e;return((e=(t=i.match(/^#\s+(.+)$/m))==null?void 0:t[1])==null?void 0:e.trim())??null}function wa(i){return[...new Set(i.trim().split(/\s+/).map(mt).filter(Boolean))]}function On(i,t,e){const n=e.filter(Boolean).sort((a,r)=>r.length-a.length);if(n.length===0){i.textContent=t;return}const s=new RegExp(`(${n.map(xa).join("|")})`,"ig");let o=0;for(const a of t.matchAll(s)){const r=a.index??0;r>o&&i.appendChild(document.createTextNode(t.slice(o,r)));const c=document.createElement("mark");c.textContent=a[0],i.appendChild(c),o=r+a[0].length}o<t.length&&i.appendChild(document.createTextNode(t.slice(o)))}function xa(i){return i.replace(/[.*+?^${}()|[\]\\]/g,"\\$&")}function gs(i){var t;return((t=i.find(e=>e.kind==="text"&&e.text.length>0))==null?void 0:t.text.slice(0,180))??""}function ys(i){const e=i.replace(/^---[\s\S]*?---\s*/,"").split(`
|
|
88
88
|
`),n=[];let s="",o=[];const a=(c,l="text",d=s)=>{const h=_n(c);h&&n.push({heading:d,text:h,normalized:mt(h),kind:l})},r=()=>{o.length!==0&&(a(o.join(" "),"text"),o=[])};for(let c=0;c<e.length;c++){const l=e[c],d=l.match(/^(`{3,})\s*([\w-]+)?\s*$/);if(d){r();const m=d[1].length,g=(d[2]??"").toLowerCase(),y=new RegExp("^`{"+m+",}\\s*$"),b=[];for(c++;c<e.length&&!y.test(e[c]);)b.push(e[c]),c++;a(g==="board"?Ca(b.join(`
|
|
89
89
|
`)):b.join(`
|
|
90
90
|
`),g==="board"?"board":"code");continue}const h=l.match(/^(#{1,6})\s+(.+)$/);if(h){r(),s=_n(h[2]),a(s,"heading",s);continue}if(l.trim()===""||/^(-{3,}|\*{3,}|_{3,})\s*$/.test(l)){r();continue}if(Ia(l))continue;const p=l.replace(/^>\s?/,"").replace(/^\s*([-*+]|\d+\.)\s+/,"").replace(/^\[([ xX])\]\s+/,"").replace(/\|/g," ");o.push(p)}return r(),n}function Ca(i){return i.split(`
|
|
@@ -92,4 +92,4 @@ Record the constraints, tools, scripts, or workflows that matter for this capabi
|
|
|
92
92
|
`);let o=!1,a,r=!1;const c=s.map(l=>{if(!o){const m=l.match(/^(`{3,})\s*board\s*$/i);return m&&(o=!0,a=new RegExp("^`{"+m[1].length+",}\\s*$")),l}if(a!=null&&a.test(l))return o=!1,a=void 0,l;const d=l.match(/^(\s*src\s*:\s*)(.*)$/i);if(!d)return l;const h=vs(d[2]);if(!h.value)return l;const p=Ba(h.value,t,e,n);return p===h.value?l:(r=!0,`${d[1]}${p}${h.suffix}`)});return r?c.join(`
|
|
93
93
|
`):i}function Sa(i,t,e,n){const s=i.split(`
|
|
94
94
|
`);let o=!1,a,r=!1;const c=s.map(l=>{if(!o){const m=l.match(/^(`{3,})\s*board\s*$/i);return m&&(o=!0,a=new RegExp("^`{"+m[1].length+",}\\s*$")),l}if(a!=null&&a.test(l))return o=!1,a=void 0,l;const d=l.match(/^(\s*src\s*:\s*)(.*)$/i);if(!d)return l;const h=vs(d[2]);return!h.value||!re(h.value,t).includes(e)?l:(r=!0,`${d[1]}${Ta(h.value,t,e,n)}${h.suffix}`)});return r?c.join(`
|
|
95
|
-
`):i}function vs(i){var o;const t=i.indexOf("#"),e=t===-1?i:i.slice(0,t),n=t===-1?"":i.slice(t),s=((o=e.match(/\s*$/))==null?void 0:o[0])??"";return{value:e.trim(),suffix:`${s}${n}`}}function Ta(i,t,e,n){const s=i.trim(),o=s.startsWith("/"),a=s.startsWith("./")||s.startsWith("../"),r=s.endsWith(".board.json"),c=re(s,t),l=!a&&c[0]!==e&&c.includes(e);if(o){const h=`/${n}`;return r&&!h.endsWith(".board.json")?`${h}.board.json`:h}let d=a||l?ws(
|
|
95
|
+
`):i}function vs(i){var o;const t=i.indexOf("#"),e=t===-1?i:i.slice(0,t),n=t===-1?"":i.slice(t),s=((o=e.match(/\s*$/))==null?void 0:o[0])??"";return{value:e.trim(),suffix:`${s}${n}`}}function Ta(i,t,e,n){const s=i.trim(),o=s.startsWith("/"),a=s.startsWith("./")||s.startsWith("../"),r=s.endsWith(".board.json"),c=re(s,t),l=!a&&c[0]!==e&&c.includes(e);if(o){const h=`/${n}`;return r&&!h.endsWith(".board.json")?`${h}.board.json`:h}let d=a||l?ws(Ke(t,n)):n;return r&&!d.endsWith(".board.json")&&(d=`${d}.board.json`),d}function Ba(i,t,e,n){const s=i.trim(),o=s.startsWith("./")||s.startsWith("../"),a=re(s,t),r=a[0]??"",c=a.find(p=>p!==r&&n.has(p));if(!o&&(!c||n.has(r)))return i;const l=s.endsWith(".board.json"),d=o?Rs(s,t):c;if(!d)return i;let h=ws(Ke(e,d));return l&&!h.endsWith(".board.json")&&(h=`${h}.board.json`),h}function ws(i){return!i||i.startsWith("./")||i.startsWith("../")?i:`./${i}`}function _n(i){return i.replace(/!\[([^\]]*)\]\(([^)]+)\)/g,"$1 $2").replace(/\[([^\]]+)\]\(([^)]+)\)/g,"$1 $2").replace(/`([^`]+)`/g,"$1").replace(/~~([\s\S]*?)~~/g,"$1").replace(/\*\*\*([\s\S]*?)\*\*\*/g,"$1").replace(/___([\s\S]*?)___/g,"$1").replace(/\*\*([\s\S]*?)\*\*/g,"$1").replace(/__([\s\S]*?)__/g,"$1").replace(/(^|[\s([{])\*([^*\s][\s\S]*?[^*\s])\*(?=$|[\s)\]},.!?:;])/g,"$1$2").replace(/(^|[\s([{])_([^_\s][\s\S]*?[^_\s])_(?=$|[\s)\]},.!?:;])/g,"$1$2").replace(/\\([\\`*_[\]{}()#+\-.!|>])/g,"$1").replace(/<[^>]+>/g," ").replace(/ /g," ").replace(/"/g,'"').replace(/'/g,"'").replace(/&/g,"&").replace(/</g,"<").replace(/>/g,">").replace(/(^|[\s([{])[*_]{1,3}(?=\S)/g,"$1").replace(new RegExp("(?<=\\S)[*_]{1,3}(?=$|[\\s)\\]},.!?:;])","g"),"").replace(/\s+/g," ").trim()}function mt(i){return i.normalize("NFKD").replace(/[\u0300-\u036f]/g,"").toLowerCase().replace(/[^a-z0-9]+/g," ").trim()}function Qt(i,t,e,n){if(!i)return 0;let s=e&&i.includes(e)?n*4:0;for(const o of t)i===o&&(s+=n*5),i.startsWith(o)&&(s+=n*3),i.includes(o)&&(s+=n);return s}function Ma(i,t){if(t.length===0)return i.slice(0,220);const e=mt(i),n=t.map(l=>e.indexOf(l)).filter(l=>l>=0).sort((l,d)=>l-d)[0];if(n===void 0)return i.slice(0,220);const s=e.length===0?0:n/e.length,o=Math.round(i.length*s),a=Math.max(0,o-90),r=Math.min(i.length,o+170),c=i.slice(a,r).trim();return`${a>0?"... ":""}${c}${r<i.length?" ...":""}`}function Ia(i){return/^\s*\|?\s*:?-{1,}:?\s*(\|\s*:?-{1,}:?\s*)*\|?\s*$/.test(i)}function st(i){const t=i.replace(/\.md$/,"").replace(/[-_]/g," ");return t.charAt(0).toUpperCase()+t.slice(1)}function Ra(i){return i.trim().replace(/[\\/]+/g,"-").replace(/\s+/g,"-").replace(/[^a-z0-9-_]/gi,"-").replace(/-+/g,"-").replace(/^-|-$/g,"").toLowerCase()}const La=new Set([".","..","assets","boards","capabilities","docs"]);function St(i,t){const e=t==="doc"?"doc":t,n=i.trim();if(!n)return{ok:!1,message:`Enter a ${e} name.`};if(n.length>80)return{ok:!1,message:"Name must be 80 characters or fewer."};if(/[\\/]/.test(n))return{ok:!1,message:"Name cannot contain slashes."};if(/^\.+$/.test(n))return{ok:!1,message:"Name cannot contain only dots."};if(n.startsWith("."))return{ok:!1,message:"Name cannot start with a dot."};if(/[<>:"|?*\x00-\x1F]/.test(n))return{ok:!1,message:"Name contains characters that are not allowed in files."};const s=Ra(n);return s?s.length>64?{ok:!1,message:"Name is too long after formatting."}:La.has(s)?{ok:!1,message:`"${s}" is reserved by the workspace.`}:/[a-z0-9]/.test(s)?{ok:!0,raw:n,slug:s}:{ok:!1,message:"Name must include letters or numbers."}:{ok:!1,message:"Name must include letters or numbers."}}function te(i){const t=i.replace(/^\/+|\/+$/g,"");return t.split("/").pop()??t}function Xn(i,t){const e=i.replace(/^\/+|\/+$/g,""),n=t.replace(/^\/+|\/+$/g,"");return e?`${e}/${n}`:n}function $a(i){if(!i)return;const t=new URLSearchParams(i).get("region");if(!t)return;const e=t.split(",").map(n=>Number(n.trim()));if(!(e.length!==4||e.some(n=>!Number.isFinite(n))||e[2]<=0||e[3]<=0))return[e[0],e[1],e[2],e[3]]}function Oe(i){return Math.max(la,Math.min(da,i))}const xs=document.getElementById("app");if(!xs)throw new Error("Missing #app root element");new ha(xs);
|