collabmd 0.1.21 → 0.1.23
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +94 -7
- package/bin/collabmd.js +3 -2
- package/docker-compose.yml +13 -1
- package/package.json +2 -1
- package/public/assets/css/style.css +1 -1
- package/public/assets/js/chunks/{chunk-HEWVH67U.js → chunk-CYK7KO7W.js} +8 -8
- package/public/assets/js/chunks/editor-session-S5AT7BMV.js +22 -0
- package/public/assets/js/{excalidraw-editor-TCIH6GJL.js → excalidraw-editor-5YWMGLKF.js} +145 -62
- package/public/assets/js/excalidraw-editor.js +1 -1
- package/public/assets/js/main.js +503 -182
- package/public/index.html +104 -84
- package/src/client/application/app-shell/git-feature.js +247 -9
- package/src/client/application/app-shell/ui-feature.js +65 -7
- package/src/client/application/app-shell/workspace-feature.js +46 -0
- package/src/client/application/app-shell-elements.js +2 -0
- package/src/client/application/mermaid-preview-hydrator.js +1 -1
- package/src/client/application/plantuml-preview-hydrator.js +1 -1
- package/src/client/application/workspace-coordinator.js +147 -18
- package/src/client/application/workspace-preview-controller.js +34 -0
- package/src/client/application/workspace-route-controller.js +104 -0
- package/src/client/bootstrap/collabmd-app-shell.js +95 -0
- package/src/client/domain/runtime-paths.js +5 -0
- package/src/client/excalidraw-editor.js +50 -2
- package/src/client/infrastructure/auth-client.js +219 -52
- package/src/client/infrastructure/browser-navigation-port.js +20 -0
- package/src/client/infrastructure/editor-collaboration-client.js +4 -0
- package/src/client/infrastructure/editor-session.js +47 -7
- package/src/client/infrastructure/editor-view-adapter.js +122 -58
- package/src/client/infrastructure/runtime-config.js +66 -0
- package/src/client/presentation/comment-ui-controller.js +82 -26
- package/src/client/presentation/comments-panel.js +2 -2
- package/src/client/presentation/excalidraw-embed-controller.js +60 -2
- package/src/client/presentation/file-history-view-controller.js +806 -0
- package/src/client/presentation/git-diff-view-controller.js +718 -121
- package/src/client/presentation/git-panel-controller.js +458 -66
- package/src/client/presentation/layout-controller.js +1 -1
- package/src/client/styles/components/actions.css +89 -0
- package/src/client/styles/components/feedback.css +43 -0
- package/src/client/styles/components/navigation.css +68 -0
- package/src/client/styles/components/scrollbars.css +104 -0
- package/src/client/styles/components/states.css +289 -0
- package/src/client/styles/components/surfaces.css +155 -0
- package/src/client/styles/features/backlinks.css +213 -0
- package/src/client/styles/features/collaboration-chat.css +228 -0
- package/src/client/styles/features/collaboration-dialogs.css +154 -0
- package/src/client/styles/features/collaboration-presence.css +103 -0
- package/src/client/styles/features/collaboration-ui.css +3 -0
- package/src/client/styles/features/comment-card.css +236 -0
- package/src/client/styles/features/comment-markdown.css +127 -0
- package/src/client/styles/features/comment-overlays.css +60 -0
- package/src/client/styles/features/comments-drawer.css +120 -0
- package/src/client/styles/features/comments.css +4 -0
- package/src/client/styles/features/diagram-preview.css +227 -0
- package/src/client/styles/features/diff-commit.css +268 -0
- package/src/client/styles/features/diff-lines.css +160 -0
- package/src/client/styles/features/diff-toolbar.css +98 -0
- package/src/client/styles/features/diff.css +3 -0
- package/src/client/styles/features/embedded-preview.css +218 -0
- package/src/client/styles/features/git-branch.css +155 -0
- package/src/client/styles/features/git-files.css +105 -0
- package/src/client/styles/features/git-history.css +339 -0
- package/src/client/styles/features/git.css +3 -0
- package/src/client/styles/features/media-lightbox.css +157 -0
- package/src/client/styles/features/outline.css +115 -0
- package/src/client/styles/features/preview-content.css +3 -0
- package/src/client/styles/features/preview-markdown.css +201 -0
- package/src/client/styles/features/preview-sidebars.css +2 -0
- package/src/client/styles/features/quick-switcher.css +167 -0
- package/src/client/styles/foundation/themes.css +347 -0
- package/src/client/styles/foundation/tokens.css +66 -0
- package/src/client/styles/foundation/utilities.css +36 -0
- package/src/client/styles/layout/editor-page.css +203 -0
- package/src/client/styles/layout/overlays.css +132 -0
- package/src/client/styles/layout/responsive.css +251 -0
- package/src/client/styles/layout/shell.css +314 -0
- package/src/client/styles/layout/sidebar.css +176 -0
- package/src/client/styles/layout/view-modes.css +92 -0
- package/src/client/styles/overrides/codemirror.css +53 -0
- package/src/client/styles/overrides/highlightjs.css +7 -0
- package/src/client/styles/overrides/vendor.css +2 -0
- package/src/client/styles/primitives/controls.css +276 -0
- package/src/client/styles/style.css +25 -4945
- package/src/server/auth/create-auth-service.js +373 -15
- package/src/server/auth/session-cookie.js +30 -4
- package/src/server/config/env.js +121 -5
- package/src/server/create-app-server.js +8 -0
- package/src/server/domain/collaboration/collaboration-room.js +90 -47
- package/src/server/index.js +3 -1
- package/src/server/infrastructure/git/command-runner.js +2 -1
- package/src/server/infrastructure/git/git-service.js +48 -2
- package/src/server/infrastructure/git/history-service.js +683 -0
- package/src/server/infrastructure/git/parsers.js +30 -0
- package/src/server/infrastructure/git/responses.js +73 -0
- package/src/server/infrastructure/http/create-auth-api-handler.js +30 -2
- package/src/server/infrastructure/http/create-git-api-command-handler.js +2 -0
- package/src/server/infrastructure/http/create-git-api-handler.js +2 -0
- package/src/server/infrastructure/http/create-git-api-query-handler.js +61 -0
- package/src/server/infrastructure/http/create-request-handler.js +15 -0
- package/public/assets/js/chunks/editor-session-EAUBJCHH.js +0 -22
package/public/assets/js/main.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import{C as
|
|
1
|
+
import{A as ri,B as oi,C as Fe,D as Et,G as ai,a as Wt,b,c as ye,d as Xt,e as Jt,k as Pe,t as ke,u as Le,v as ei,w as ti,x as ii,y as si,z as ni}from"./chunks/chunk-CYK7KO7W.js";import{a as Gt,b as we,d as Yt,e as Se}from"./chunks/chunk-5QRWYPYT.js";import{a as p,b as qt,c as T,e as he,f as Kt,g as Vt,h as Y,i as jt,j as ve,k as be,l as Ce,m as Qt,n as Zt,o as Ee,p as K}from"./chunks/chunk-GFDM7YCF.js";import"./chunks/chunk-775E65SU.js";var us={edit:`
|
|
2
2
|
<svg viewBox="0 0 16 16" aria-hidden="true" focusable="false">
|
|
3
3
|
<path d="M11.8 1.8a1.5 1.5 0 0 1 2.1 2.1l-7.2 7.2-3.2.9.9-3.2z" fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="1.4"/>
|
|
4
4
|
<path d="M10.7 2.9l2.4 2.4" fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="1.4"/>
|
|
@@ -17,53 +17,164 @@ import{C as Xt,a as _t,b as C,c as pe,d as Kt,e as jt,k as Ce,t as Ee,u as Se,v
|
|
|
17
17
|
<path d="M6 5V2H2M10 5V2h4M10 11v3h4M6 11v3H2" fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="1.4"/>
|
|
18
18
|
<path d="M4.5 4.5h7v7h-7z" fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="1.4"/>
|
|
19
19
|
</svg>
|
|
20
|
-
`};function T(n,e){if(!(n instanceof HTMLElement))return;let t=en[e];if(!t){n.classList.remove("is-icon-only");return}n.classList.add("is-icon-only"),n.dataset.icon=e,n.innerHTML=t.trim()}var k={default:1,animationDurationMs:160,max:3,min:.5,step:.1},P={default:1,animationDurationMs:160,max:3,min:.1,step:.1},W=500,Jt=2,ei=2;function ie(n,e){return typeof window.requestIdleCallback=="function"?window.requestIdleCallback(n,{timeout:e}):window.setTimeout(()=>{n({didTimeout:!1,timeRemaining:()=>0})},1)}function ne(n){if(n!==null){if(typeof window.cancelIdleCallback=="function"){window.cancelIdleCallback(n);return}window.clearTimeout(n)}}function X(n,e,t){let i=e.getAttribute(t);if(i===null){n.removeAttribute(t);return}n.setAttribute(t,i)}function ce(n){let e=n.viewBox?.baseVal,t=Number.parseFloat(n.getAttribute("width")||""),i=Number.parseFloat(n.getAttribute("height")||""),s=n.getBoundingClientRect(),r=typeof n.getBBox=="function"?n.getBBox():null;return{height:e?.height||r?.height||i||s.height||480,width:e?.width||r?.width||t||s.width||640}}function ti(n){if(!n||typeof n.getBBox!="function")return ce(n);try{let e=n.getBBox();if(!Number.isFinite(e.width)||!Number.isFinite(e.height)||e.width<=0||e.height<=0)return ce(n);let t=16,i=e.x-t,s=e.y-t,r=e.width+t*2,a=e.height+t*2;return n.setAttribute("viewBox",`${i} ${s} ${r} ${a}`),n.setAttribute("width",String(r)),n.setAttribute("height",String(a)),n.setAttribute("preserveAspectRatio","xMinYMin meet"),{width:r,height:a}}catch{return ce(n)}}function j(n){let e=window.getComputedStyle(n),t=Number.parseFloat(e.paddingLeft||"0")+Number.parseFloat(e.paddingRight||"0"),i=Number.parseFloat(e.paddingTop||"0")+Number.parseFloat(e.paddingBottom||"0");return{height:Math.max(n.clientHeight-i,0),width:Math.max(n.clientWidth-t,0)}}function Pe(n){return 1-(1-n)**3}function ii(n){return bt(n,{label:"Mermaid diagram",message:"Loads when visible"})}function bt(n,{label:e="Mermaid diagram",message:t="Loads when visible"}={}){let i=document.createElement("div");i.className="mermaid-placeholder-card";let s=document.createElement("div");s.className="mermaid-placeholder-copy";let r=document.createElement("strong");r.textContent=e;let a=document.createElement("span");a.textContent=t;let o=document.createElement("button");return o.type="button",o.className="mermaid-placeholder-btn",o.dataset.mermaidKey=n,o.textContent="Render",s.append(r,a),i.append(s,o),i}function Ct(n,e="Renders server-side when visible"){let t=document.createElement("div");t.className="plantuml-placeholder-card";let i=document.createElement("div");i.className="plantuml-placeholder-copy";let s=document.createElement("strong");s.textContent="PlantUML diagram";let r=document.createElement("span");r.textContent=e;let a=document.createElement("button");return a.type="button",a.className="plantuml-placeholder-btn",a.dataset.plantumlKey=n,a.textContent="Render",i.append(s,r),t.append(i,a),t}function ni(n){let t=new DOMParser().parseFromString(n,"image/svg+xml"),i=t.documentElement;if(!i||i.nodeName.toLowerCase()!=="svg")throw new Error("Renderer returned invalid SVG");return t.querySelectorAll("script, foreignObject").forEach(s=>{s.remove()}),Array.from(t.querySelectorAll("*")).forEach(s=>{Array.from(s.attributes).forEach(r=>{let a=r.name.toLowerCase(),o=r.value||"";if(a.startsWith("on")){s.removeAttribute(r.name);return}(a==="href"||a==="xlink:href")&&/^\s*javascript:/i.test(o)&&s.removeAttribute(r.name)})}),i.outerHTML}function si({nextSource:n="",nextTarget:e="",preservedSource:t="",preservedTarget:i=""}={}){return n?n===t:e?e===i:!1}function ri(n,e,t){if(!n||!e)return!1;let i=e.getBoundingClientRect(),s=n.getBoundingClientRect();return s.bottom>=i.top-t&&s.top<=i.bottom+t}function tn(n){return`data-${n.replace(/[A-Z]/g,e=>`-${e.toLowerCase()}`)}`}var se=class{constructor(e,{batchSize:t,datasetKeys:i,fetchFn:s=(...d)=>fetch(...d),filePathLabel:r,requestIdleRenderFn:a=ie,cancelIdleRenderFn:o=ne,intersectionObserverFactory:l=(d,w)=>new IntersectionObserver(d,w),isNearViewportFn:h=ri,requestAnimationFrameFn:c=d=>requestAnimationFrame(d),shellClassName:u,sourceClassName:p}){this.renderer=e,this.batchSize=t,this.datasetKeys=i,this.fetchFn=s,this.filePathLabel=r,this.requestIdleRenderFn=a,this.cancelIdleRenderFn=o,this.intersectionObserverFactory=l,this.isNearViewportFn=h,this.requestAnimationFrameFn=c,this.shellClassName=u,this.sourceClassName=p,this.shellSelector=`.${u}`,this.sourceSelector=`.${p}`,this.attributeNames=Object.fromEntries(Object.entries(i).map(([d,w])=>[d,tn(w)])),this.observer=null,this.idleId=null,this.pendingShells=[],this.hydrationInProgress=!1,this.instanceCounter=0,this.preservedShells=new Map,this.fileInflightRequests=new Map}destroy(){this.cancelHydration(),this.preservedShells.clear()}cancelHydration(){this.observer&&(this.observer.disconnect(),this.observer=null),this.cancelIdleRenderFn(this.idleId),this.idleId=null,this.pendingShells=[],this.hydrationInProgress=!1}cancelPendingIdleWork(){this.cancelIdleRenderFn(this.idleId),this.idleId=null}clearPreservedShells(){this.preservedShells.clear()}hasPendingWork(){return this.hydrationInProgress||this.pendingShells.length>0}preserveHydratedShellsForCommit(){this.preservedShells.clear();let e=this.renderer.previewElement;e&&Array.from(e.querySelectorAll(`${this.shellSelector}[${this.attributeNames.hydrated}="true"][${this.attributeNames.key}]`)).forEach(t=>{let i=t.dataset[this.datasetKeys.key],s=t.querySelector(this.sourceSelector)?.textContent??"",r=t.dataset[this.datasetKeys.target]??"";!i||!s&&!r||(t.isConnected&&t.remove(),this.preservedShells.set(i,{key:i,shell:t,source:s,target:r}))})}reconcileHydratedShells(){let e=this.renderer.previewElement;if(!e||this.preservedShells.size===0){this.preservedShells.clear();return}let t=!1;Array.from(e.querySelectorAll(`${this.shellSelector}[${this.attributeNames.key}]`)).forEach(i=>{let s=i.dataset[this.datasetKeys.key],r=s?this.preservedShells.get(s):null;if(!r)return;let a=i.querySelector(this.sourceSelector)?.textContent??"",o=i.dataset[this.datasetKeys.target]??"";si({nextSource:a,nextTarget:o,preservedSource:r.source,preservedTarget:r.target})&&(this.syncPreservedShell(r.shell,i),i.replaceWith(r.shell),t=t||r.shell.classList.contains("is-maximized"),this.preservedShells.delete(s))}),this.preservedShells.clear(),this.handleReconcile({restoredMaximizedShell:t})}handleReconcile(){}syncPreservedShell(e,t){X(e,t,this.attributeNames.sourceLine),X(e,t,this.attributeNames.sourceLineEnd),X(e,t,this.attributeNames.key),X(e,t,this.attributeNames.target),X(e,t,this.attributeNames.label),X(e,t,this.attributeNames.sourceHash),e.classList.add(this.shellClassName),e.dataset[this.datasetKeys.hydrated]="true",this.removeDatasetValue(e,"queued");let i=t.querySelector(this.sourceSelector),s=e.querySelector(this.sourceSelector);if(!s&&i&&(s=i.cloneNode(!0),e.prepend(s)),s&&i){let r=i.textContent??"";(r||!t.dataset[this.datasetKeys.target])&&(s.textContent=r),s.hidden=!0}}setupHydration(e){let t=this.renderer.previewElement,i=this.renderer.previewContainer;if(!t||!i)return 0;let s=Array.from(t.querySelectorAll(this.shellSelector));return s.length===0?0:(this.observer=this.intersectionObserverFactory(r=>{r.forEach(a=>{a.isIntersecting&&this.enqueueShell(a.target)})},{root:i,rootMargin:this.renderer.isLargeDocument?"180px 0px":"420px 0px"}),s.forEach(r=>this.observer.observe(r)),this.requestAnimationFrameFn(()=>{e===this.renderer.activeRenderVersion&&(this.hydrateVisibleShells(),this.renderer.updateHydrationPhase())}),s.length)}hydrateVisibleShells(){let e=this.renderer.previewElement,t=this.renderer.previewContainer;if(this.renderer.hydrationPaused||!e||!t)return;let i=this.renderer.isLargeDocument?180:420;Array.from(e.querySelectorAll(this.shellSelector)).forEach(s=>{this.isNearViewportFn(s,t,i)&&this.enqueueShell(s,{prioritize:!0})})}enqueueShell(e,{prioritize:t=!1}={}){!e?.isConnected||this.isShellHydrated(e)||this.isShellQueued(e)||(e.dataset[this.datasetKeys.queued]="true",t?this.pendingShells.unshift(e):this.pendingShells.push(e),!this.renderer.hydrationPaused&&(this.renderer.updateHydrationPhase(),this.scheduleHydration()))}scheduleHydration(){this.renderer.hydrationPaused||this.hydrationInProgress||this.idleId!==null||(this.idleId=this.requestIdleRenderFn(()=>{this.idleId=null,this.flushHydrationQueue()},W))}async flushHydrationQueue(){if(this.renderer.hydrationPaused||this.hydrationInProgress)return;let e=[];for(;this.pendingShells.length>0&&e.length<this.batchSize;){let i=this.pendingShells.shift();!i?.isConnected||this.isShellHydrated(i)||(this.removeDatasetValue(i,"queued"),e.push(i))}if(e.length===0){this.renderer.updateHydrationPhase();return}this.hydrationInProgress=!0,this.renderer.setPhase("hydrating");let t=null;try{t=await this.prepareHydrationBatch(e)}catch(i){this.handlePrepareHydrationBatchError(e,i),this.hydrationInProgress=!1,this.renderer.updateHydrationPhase();return}for(let i of e)await this.hydrateShell(i,t);this.hydrationInProgress=!1,this.pendingShells.length>0&&this.scheduleHydration(),this.renderer.updateHydrationPhase()}async prepareHydrationBatch(){return null}handlePrepareHydrationBatchError(e,t){}async hydrateShell(){throw new Error("hydrateShell must be implemented by subclasses")}markShellHydrated(e){e.dataset[this.datasetKeys.hydrated]="true",e.dataset[this.datasetKeys.instanceId]=String(++this.instanceCounter)}isShellHydrated(e){return e?.dataset?.[this.datasetKeys.hydrated]==="true"}removeDatasetValue(e,t){let i=this.datasetKeys[t];!i||!e||(e.removeAttribute?.(this.attributeNames[t]),e.dataset&&delete e.dataset[i])}isShellQueued(e){return e?.dataset?.[this.datasetKeys.queued]==="true"}async fetchSource(e){let t=String(e??"").trim();if(!t)throw new Error(`Missing ${this.filePathLabel} file path`);if(this.fileInflightRequests.has(t))return this.fileInflightRequests.get(t);let i=this.fetchFn(C(`/file?path=${encodeURIComponent(t)}`),{headers:{Accept:"application/json"}}).then(async s=>{let r=await s.json().catch(()=>null);if(!s.ok||typeof r?.content!="string")throw new Error(r?.error||`Failed to load ${t}`);return r.content}).finally(()=>{this.fileInflightRequests.delete(t)});return this.fileInflightRequests.set(t,i),i}};var Le=class extends se{constructor(e){super(e,{batchSize:Jt,datasetKeys:{hydrated:"mermaidHydrated",instanceId:"mermaidInstanceId",key:"mermaidKey",label:"mermaidLabel",queued:"mermaidQueued",sourceHash:"mermaidSourceHash",sourceLine:"sourceLine",sourceLineEnd:"sourceLineEnd",target:"mermaidTarget"},filePathLabel:"Mermaid",shellClassName:"mermaid-shell",sourceClassName:"mermaid-source"}),this.renderer=e,this.currentTheme=document.documentElement?.dataset.theme==="light"?"light":"dark",this.loader=null,this.runtime=null,this.shellRefits=new WeakMap}applyTheme(e){this.currentTheme=e;let t=this.runtime;t&&(this.configureMermaid(t),this.resetHydratedShells())}configureMermaid(e){e.initialize({startOnLoad:!1,flowchart:{defaultRenderer:"dagre-wrapper",useMaxWidth:!0},class:{defaultRenderer:"dagre-wrapper",useMaxWidth:!0},theme:this.currentTheme==="dark"?"dark":"default",themeVariables:this.currentTheme==="dark"?{background:"#161822",clusterBkg:"#1a1c28",edgeLabelBackground:"#161822",lineColor:"#8b8ba0",mainBkg:"#1c1e2c",nodeBorder:"#383a50",primaryBorderColor:"#383a50",primaryColor:"#818cf8",primaryTextColor:"#e2e2ea",secondaryColor:"#1c1e2c",tertiaryColor:"#161822",titleColor:"#e2e2ea"}:{}})}ensureMermaid(){return this.runtime?(this.configureMermaid(this.runtime),Promise.resolve(this.runtime)):this.loader?this.loader:(this.loader=import("./chunks/mermaid-runtime-BIFNJ2CT.js").then(e=>{let t=e?.default;if(!t)throw new Error("Mermaid runtime failed to initialize");return this.runtime=t,this.configureMermaid(t),t}).catch(e=>{throw this.loader=null,this.runtime=null,new Error(e instanceof Error?e.message:"Failed to load Mermaid runtime")}),this.loader)}handleReconcile({restoredMaximizedShell:e}){e&&document.body.classList.add("mermaid-maximized-open")}async prepareHydrationBatch(){return this.ensureMermaid()}handlePrepareHydrationBatchError(e,t){console.warn("[preview] Mermaid runtime failed to load:",t)}async hydrateShell(e,t){if(!t||!e?.isConnected||this.isShellHydrated(e))return;let i=e.querySelector(".mermaid-source");i||(i=document.createElement("span"),i.className="mermaid-source",i.hidden=!0,e.appendChild(i));let s=i.textContent??"";try{if(!s.trim()&&e.dataset.mermaidTarget){if(s=await this.fetchSource(e.dataset.mermaidTarget),!e.isConnected)return;i.textContent=s}if(!s.trim())throw new Error(e.dataset.mermaidTarget?"Mermaid file is empty":"Mermaid source is empty");s=this.prepareSource(s),e.querySelector(".mermaid-placeholder-card")?.remove();let r=document.createElement("div");r.className="mermaid mermaid-render-node",r.id=e.dataset.mermaidKey||`mermaid-${Date.now()}`;let a=e.getAttribute("data-source-line"),o=e.getAttribute("data-source-line-end");if(a&&r.setAttribute("data-source-line",a),o&&r.setAttribute("data-source-line-end",o),r.textContent=s,e.appendChild(r),await t.run({nodes:[r]}),!r.isConnected||e!==r.parentElement)return;this.enhanceDiagram(e,r),this.markShellHydrated(e)}catch(r){console.warn("[preview] Mermaid render failed:",r),e.querySelector(":scope > .mermaid-toolbar")?.remove(),e.querySelector(":scope > .mermaid-frame")?.remove(),e.querySelector(":scope > .mermaid-render-node")?.remove(),e.querySelector(".mermaid-placeholder-card")||i?.after(bt(e.dataset.mermaidKey||"mermaid",{label:e.dataset.mermaidLabel||"Mermaid diagram",message:r instanceof Error?r.message:"Render failed"}))}}prepareSource(e){let t=String(e??"");if(!/%%\{[\s\S]*?\binit\s*:/m.test(t)){let r=this.getPreviewInitConfig(t);r&&(t=`%%{init: ${JSON.stringify(r)}}%%
|
|
20
|
+
`};function A(s,e){if(!(s instanceof HTMLElement))return;let t=us[e];if(!t){s.classList.remove("is-icon-only");return}s.classList.add("is-icon-only"),s.dataset.icon=e,s.innerHTML=t.trim()}var L={default:1,animationDurationMs:160,max:3,min:.5,step:.1},F={default:1,animationDurationMs:160,max:3,min:.1,step:.1},V=500,li=2,ci=2;function se(s,e){return typeof window.requestIdleCallback=="function"?window.requestIdleCallback(s,{timeout:e}):window.setTimeout(()=>{s({didTimeout:!1,timeRemaining:()=>0})},1)}function ne(s){if(s!==null){if(typeof window.cancelIdleCallback=="function"){window.cancelIdleCallback(s);return}window.clearTimeout(s)}}function X(s,e,t){let i=e.getAttribute(t);if(i===null){s.removeAttribute(t);return}s.setAttribute(t,i)}function de(s){let e=s.viewBox?.baseVal,t=Number.parseFloat(s.getAttribute("width")||""),i=Number.parseFloat(s.getAttribute("height")||""),n=s.getBoundingClientRect(),r=typeof s.getBBox=="function"?s.getBBox():null;return{height:e?.height||r?.height||i||n.height||480,width:e?.width||r?.width||t||n.width||640}}function hi(s){if(!s||typeof s.getBBox!="function")return de(s);try{let e=s.getBBox();if(!Number.isFinite(e.width)||!Number.isFinite(e.height)||e.width<=0||e.height<=0)return de(s);let t=16,i=e.x-t,n=e.y-t,r=e.width+t*2,o=e.height+t*2;return s.setAttribute("viewBox",`${i} ${n} ${r} ${o}`),s.setAttribute("width",String(r)),s.setAttribute("height",String(o)),s.setAttribute("preserveAspectRatio","xMinYMin meet"),{width:r,height:o}}catch{return de(s)}}function Q(s){let e=window.getComputedStyle(s),t=Number.parseFloat(e.paddingLeft||"0")+Number.parseFloat(e.paddingRight||"0"),i=Number.parseFloat(e.paddingTop||"0")+Number.parseFloat(e.paddingBottom||"0");return{height:Math.max(s.clientHeight-i,0),width:Math.max(s.clientWidth-t,0)}}function xe(s){return 1-(1-s)**3}function di(s){return St(s,{label:"Mermaid diagram",message:"Loads when visible"})}function St(s,{label:e="Mermaid diagram",message:t="Loads when visible"}={}){let i=document.createElement("div");i.className="mermaid-placeholder-card";let n=document.createElement("div");n.className="mermaid-placeholder-copy";let r=document.createElement("strong");r.textContent=e;let o=document.createElement("span");o.textContent=t;let a=document.createElement("button");return a.type="button",a.className="mermaid-placeholder-btn",a.dataset.mermaidKey=s,a.textContent="Render",n.append(r,o),i.append(n,a),i}function Pt(s,e="Renders server-side when visible"){let t=document.createElement("div");t.className="plantuml-placeholder-card";let i=document.createElement("div");i.className="plantuml-placeholder-copy";let n=document.createElement("strong");n.textContent="PlantUML diagram";let r=document.createElement("span");r.textContent=e;let o=document.createElement("button");return o.type="button",o.className="plantuml-placeholder-btn",o.dataset.plantumlKey=s,o.textContent="Render",i.append(n,r),t.append(i,o),t}function ui(s){let t=new DOMParser().parseFromString(s,"image/svg+xml"),i=t.documentElement;if(!i||i.nodeName.toLowerCase()!=="svg")throw new Error("Renderer returned invalid SVG");return t.querySelectorAll("script, foreignObject").forEach(n=>{n.remove()}),Array.from(t.querySelectorAll("*")).forEach(n=>{Array.from(n.attributes).forEach(r=>{let o=r.name.toLowerCase(),a=r.value||"";if(o.startsWith("on")){n.removeAttribute(r.name);return}(o==="href"||o==="xlink:href")&&/^\s*javascript:/i.test(a)&&n.removeAttribute(r.name)})}),i.outerHTML}function mi({nextSource:s="",nextTarget:e="",preservedSource:t="",preservedTarget:i=""}={}){return s?s===t:e?e===i:!1}function pi(s,e,t){if(!s||!e)return!1;let i=e.getBoundingClientRect(),n=s.getBoundingClientRect();return n.bottom>=i.top-t&&n.top<=i.bottom+t}function ms(s){return`data-${s.replace(/[A-Z]/g,e=>`-${e.toLowerCase()}`)}`}var re=class{constructor(e,{batchSize:t,datasetKeys:i,fetchFn:n=(...d)=>fetch(...d),filePathLabel:r,requestIdleRenderFn:o=se,cancelIdleRenderFn:a=ne,intersectionObserverFactory:c=(d,w)=>new IntersectionObserver(d,w),isNearViewportFn:h=pi,requestAnimationFrameFn:l=d=>requestAnimationFrame(d),shellClassName:u,sourceClassName:m}){this.renderer=e,this.batchSize=t,this.datasetKeys=i,this.fetchFn=n,this.filePathLabel=r,this.requestIdleRenderFn=o,this.cancelIdleRenderFn=a,this.intersectionObserverFactory=c,this.isNearViewportFn=h,this.requestAnimationFrameFn=l,this.shellClassName=u,this.sourceClassName=m,this.shellSelector=`.${u}`,this.sourceSelector=`.${m}`,this.attributeNames=Object.fromEntries(Object.entries(i).map(([d,w])=>[d,ms(w)])),this.observer=null,this.idleId=null,this.pendingShells=[],this.hydrationInProgress=!1,this.instanceCounter=0,this.preservedShells=new Map,this.fileInflightRequests=new Map}destroy(){this.cancelHydration(),this.preservedShells.clear()}cancelHydration(){this.observer&&(this.observer.disconnect(),this.observer=null),this.cancelIdleRenderFn(this.idleId),this.idleId=null,this.pendingShells=[],this.hydrationInProgress=!1}cancelPendingIdleWork(){this.cancelIdleRenderFn(this.idleId),this.idleId=null}clearPreservedShells(){this.preservedShells.clear()}hasPendingWork(){return this.hydrationInProgress||this.pendingShells.length>0}preserveHydratedShellsForCommit(){this.preservedShells.clear();let e=this.renderer.previewElement;e&&Array.from(e.querySelectorAll(`${this.shellSelector}[${this.attributeNames.hydrated}="true"][${this.attributeNames.key}]`)).forEach(t=>{let i=t.dataset[this.datasetKeys.key],n=t.querySelector(this.sourceSelector)?.textContent??"",r=t.dataset[this.datasetKeys.target]??"";!i||!n&&!r||(t.isConnected&&t.remove(),this.preservedShells.set(i,{key:i,shell:t,source:n,target:r}))})}reconcileHydratedShells(){let e=this.renderer.previewElement;if(!e||this.preservedShells.size===0){this.preservedShells.clear();return}let t=!1;Array.from(e.querySelectorAll(`${this.shellSelector}[${this.attributeNames.key}]`)).forEach(i=>{let n=i.dataset[this.datasetKeys.key],r=n?this.preservedShells.get(n):null;if(!r)return;let o=i.querySelector(this.sourceSelector)?.textContent??"",a=i.dataset[this.datasetKeys.target]??"";mi({nextSource:o,nextTarget:a,preservedSource:r.source,preservedTarget:r.target})&&(this.syncPreservedShell(r.shell,i),i.replaceWith(r.shell),t=t||r.shell.classList.contains("is-maximized"),this.preservedShells.delete(n))}),this.preservedShells.clear(),this.handleReconcile({restoredMaximizedShell:t})}handleReconcile(){}syncPreservedShell(e,t){X(e,t,this.attributeNames.sourceLine),X(e,t,this.attributeNames.sourceLineEnd),X(e,t,this.attributeNames.key),X(e,t,this.attributeNames.target),X(e,t,this.attributeNames.label),X(e,t,this.attributeNames.sourceHash),e.classList.add(this.shellClassName),e.dataset[this.datasetKeys.hydrated]="true",this.removeDatasetValue(e,"queued");let i=t.querySelector(this.sourceSelector),n=e.querySelector(this.sourceSelector);if(!n&&i&&(n=i.cloneNode(!0),e.prepend(n)),n&&i){let r=i.textContent??"";(r||!t.dataset[this.datasetKeys.target])&&(n.textContent=r),n.hidden=!0}}setupHydration(e){let t=this.renderer.previewElement,i=this.renderer.previewContainer;if(!t||!i)return 0;let n=Array.from(t.querySelectorAll(this.shellSelector));return n.length===0?0:(this.observer=this.intersectionObserverFactory(r=>{r.forEach(o=>{o.isIntersecting&&this.enqueueShell(o.target)})},{root:i,rootMargin:this.renderer.isLargeDocument?"180px 0px":"420px 0px"}),n.forEach(r=>this.observer.observe(r)),this.requestAnimationFrameFn(()=>{e===this.renderer.activeRenderVersion&&(this.hydrateVisibleShells(),this.renderer.updateHydrationPhase())}),n.length)}hydrateVisibleShells(){let e=this.renderer.previewElement,t=this.renderer.previewContainer;if(this.renderer.hydrationPaused||!e||!t)return;let i=this.renderer.isLargeDocument?180:420;Array.from(e.querySelectorAll(this.shellSelector)).forEach(n=>{this.isNearViewportFn(n,t,i)&&this.enqueueShell(n,{prioritize:!0})})}enqueueShell(e,{prioritize:t=!1}={}){!e?.isConnected||this.isShellHydrated(e)||this.isShellQueued(e)||(e.dataset[this.datasetKeys.queued]="true",t?this.pendingShells.unshift(e):this.pendingShells.push(e),!this.renderer.hydrationPaused&&(this.renderer.updateHydrationPhase(),this.scheduleHydration()))}scheduleHydration(){this.renderer.hydrationPaused||this.hydrationInProgress||this.idleId!==null||(this.idleId=this.requestIdleRenderFn(()=>{this.idleId=null,this.flushHydrationQueue()},V))}async flushHydrationQueue(){if(this.renderer.hydrationPaused||this.hydrationInProgress)return;let e=[];for(;this.pendingShells.length>0&&e.length<this.batchSize;){let i=this.pendingShells.shift();!i?.isConnected||this.isShellHydrated(i)||(this.removeDatasetValue(i,"queued"),e.push(i))}if(e.length===0){this.renderer.updateHydrationPhase();return}this.hydrationInProgress=!0,this.renderer.setPhase("hydrating");let t=null;try{t=await this.prepareHydrationBatch(e)}catch(i){this.handlePrepareHydrationBatchError(e,i),this.hydrationInProgress=!1,this.renderer.updateHydrationPhase();return}for(let i of e)await this.hydrateShell(i,t);this.hydrationInProgress=!1,this.pendingShells.length>0&&this.scheduleHydration(),this.renderer.updateHydrationPhase()}async prepareHydrationBatch(){return null}handlePrepareHydrationBatchError(e,t){}async hydrateShell(){throw new Error("hydrateShell must be implemented by subclasses")}markShellHydrated(e){e.dataset[this.datasetKeys.hydrated]="true",e.dataset[this.datasetKeys.instanceId]=String(++this.instanceCounter)}isShellHydrated(e){return e?.dataset?.[this.datasetKeys.hydrated]==="true"}removeDatasetValue(e,t){let i=this.datasetKeys[t];!i||!e||(e.removeAttribute?.(this.attributeNames[t]),e.dataset&&delete e.dataset[i])}isShellQueued(e){return e?.dataset?.[this.datasetKeys.queued]==="true"}async fetchSource(e){let t=String(e??"").trim();if(!t)throw new Error(`Missing ${this.filePathLabel} file path`);if(this.fileInflightRequests.has(t))return this.fileInflightRequests.get(t);let i=this.fetchFn(b(`/file?path=${encodeURIComponent(t)}`),{headers:{Accept:"application/json"}}).then(async n=>{let r=await n.json().catch(()=>null);if(!n.ok||typeof r?.content!="string")throw new Error(r?.error||`Failed to load ${t}`);return r.content}).finally(()=>{this.fileInflightRequests.delete(t)});return this.fileInflightRequests.set(t,i),i}};var Me=class extends re{constructor(e){super(e,{batchSize:li,datasetKeys:{hydrated:"mermaidHydrated",instanceId:"mermaidInstanceId",key:"mermaidKey",label:"mermaidLabel",queued:"mermaidQueued",sourceHash:"mermaidSourceHash",sourceLine:"sourceLine",sourceLineEnd:"sourceLineEnd",target:"mermaidTarget"},filePathLabel:"Mermaid",shellClassName:"mermaid-shell",sourceClassName:"mermaid-source"}),this.renderer=e,this.currentTheme=document.documentElement?.dataset.theme==="light"?"light":"dark",this.loader=null,this.runtime=null,this.shellRefits=new WeakMap}applyTheme(e){this.currentTheme=e;let t=this.runtime;t&&(this.configureMermaid(t),this.resetHydratedShells())}configureMermaid(e){e.initialize({startOnLoad:!1,flowchart:{defaultRenderer:"dagre-wrapper",useMaxWidth:!0},class:{defaultRenderer:"dagre-wrapper",useMaxWidth:!0},theme:this.currentTheme==="dark"?"dark":"default",themeVariables:this.currentTheme==="dark"?{background:"#161822",clusterBkg:"#1a1c28",edgeLabelBackground:"#161822",lineColor:"#8b8ba0",mainBkg:"#1c1e2c",nodeBorder:"#383a50",primaryBorderColor:"#383a50",primaryColor:"#818cf8",primaryTextColor:"#e2e2ea",secondaryColor:"#1c1e2c",tertiaryColor:"#161822",titleColor:"#e2e2ea"}:{}})}ensureMermaid(){return this.runtime?(this.configureMermaid(this.runtime),Promise.resolve(this.runtime)):this.loader?this.loader:(this.loader=import("./chunks/mermaid-runtime-BIFNJ2CT.js").then(e=>{let t=e?.default;if(!t)throw new Error("Mermaid runtime failed to initialize");return this.runtime=t,this.configureMermaid(t),t}).catch(e=>{throw this.loader=null,this.runtime=null,new Error(e instanceof Error?e.message:"Failed to load Mermaid runtime")}),this.loader)}handleReconcile({restoredMaximizedShell:e}){e&&document.body.classList.add("mermaid-maximized-open")}async prepareHydrationBatch(){return this.ensureMermaid()}handlePrepareHydrationBatchError(e,t){console.warn("[preview] Mermaid runtime failed to load:",t)}async hydrateShell(e,t){if(!t||!e?.isConnected||this.isShellHydrated(e))return;let i=e.querySelector(".mermaid-source");i||(i=document.createElement("span"),i.className="mermaid-source",i.hidden=!0,e.appendChild(i));let n=i.textContent??"";try{if(!n.trim()&&e.dataset.mermaidTarget){if(n=await this.fetchSource(e.dataset.mermaidTarget),!e.isConnected)return;i.textContent=n}if(!n.trim())throw new Error(e.dataset.mermaidTarget?"Mermaid file is empty":"Mermaid source is empty");n=this.prepareSource(n),e.querySelector(".mermaid-placeholder-card")?.remove();let r=document.createElement("div");r.className="mermaid mermaid-render-node",r.id=e.dataset.mermaidKey||`mermaid-${Date.now()}`;let o=e.getAttribute("data-source-line"),a=e.getAttribute("data-source-line-end");if(o&&r.setAttribute("data-source-line",o),a&&r.setAttribute("data-source-line-end",a),r.textContent=n,e.appendChild(r),await t.run({nodes:[r]}),!r.isConnected||e!==r.parentElement)return;this.enhanceDiagram(e,r),this.markShellHydrated(e)}catch(r){console.warn("[preview] Mermaid render failed:",r),e.querySelector(":scope > .mermaid-toolbar")?.remove(),e.querySelector(":scope > .mermaid-frame")?.remove(),e.querySelector(":scope > .mermaid-render-node")?.remove(),e.querySelector(".mermaid-placeholder-card")||i?.after(St(e.dataset.mermaidKey||"mermaid",{label:e.dataset.mermaidLabel||"Mermaid diagram",message:r instanceof Error?r.message:"Render failed"}))}}prepareSource(e){let t=String(e??"");if(!/%%\{[\s\S]*?\binit\s*:/m.test(t)){let r=this.getPreviewInitConfig(t);r&&(t=`%%{init: ${JSON.stringify(r)}}%%
|
|
21
21
|
${t}`)}if(!/^\s*gantt\b/m.test(t)||/\btodayMarker\b/.test(t))return t;let i=t.split(`
|
|
22
|
-
`),
|
|
23
|
-
`))}getPreviewInitConfig(e){return/^\s*stateDiagram(?:-v2)?\b/m.test(e)?{htmlLabels:!1}:/^\s*classDiagram\b/m.test(e)?{htmlLabels:!1}:/^\s*gantt\b/m.test(e)?{htmlLabels:!1}:null}resetHydratedShells(){let e=this.renderer.previewElement;if(!e)return;let t=Array.from(e.querySelectorAll('.mermaid-shell[data-mermaid-hydrated="true"]'));t.length!==0&&t.forEach(i=>{this.shellRefits.delete(i),i.removeAttribute("data-mermaid-hydrated"),i.querySelector(":scope > .mermaid-toolbar")?.remove(),i.querySelector(":scope > .mermaid-frame")?.remove(),i.querySelector(":scope > .mermaid-render-node")?.remove(),i.querySelector(".mermaid-placeholder-card")||i.querySelector(".mermaid-source")?.after(ii(i.dataset.mermaidKey||"mermaid")),this.enqueueShell(i,{prioritize:!0})})}enhanceDiagram(e,t){let i=t.querySelector("svg");if(!i){t.remove();return}let s=document.createElement("div");s.className="mermaid-toolbar diagram-preview-toolbar";let r=this.createZoomButton("\u2212","Zoom out"),a=this.createZoomButton("+","Zoom in"),o=this.createZoomButton("Reset","Reset zoom"),l=this.createZoomButton("Max","Maximize diagram");l.classList.add("mermaid-maximize-btn"),T(l,"maximize");let h=document.createElement("span");h.className="mermaid-zoom-label diagram-preview-zoom-label",h.setAttribute("aria-live","polite"),s.append(r,h,o,a,l);let c=document.createElement("div");c.className="mermaid-frame diagram-preview-frame";let{width:u,height:p}=ti(i),d=k.default,w=1,m=null,b=null,E=!1,I=0,F=!1,A=null,z=0,U=0,R=0,B=0;i.style.display="block",i.style.margin="0 auto",i.style.maxWidth="none";let N=()=>{let f=j(c);if(!Number.isFinite(u)||u<=0||f.width<=0)return k.default;let y=f.width/u;return!Number.isFinite(y)||y<=0?k.default:x(y,k.min,k.max)},$=f=>{d=x(f,k.min,k.max),i.style.width=`${u*d}px`,i.style.height=`${p*d}px`,h.textContent=`${Math.round(d*100)}%`,r.disabled=d<=k.min,a.disabled=d>=k.max;let y=j(c),v=u*d>y.width||p*d>y.height;c.classList.toggle("is-pannable",v),i.style.margin=v?"0":"0 auto"},G=()=>({x:c.scrollLeft+c.clientWidth/2,y:c.scrollTop+c.clientHeight/2}),V=(f,y,v)=>{if(f===0)return;let S=y/f;c.scrollLeft=v.x*S-c.clientWidth/2,c.scrollTop=v.y*S-c.clientHeight/2},Y=f=>{let y=x(f,k.min,k.max),v=d;if(y===v)return;let S=G(),gt=performance.now();m&&cancelAnimationFrame(m);let ae=wt=>{let oe=x((wt-gt)/k.animationDurationMs,0,1),yt=Pe(oe),le=v+(y-v)*yt;if($(le),V(v,le,S),oe<1){m=requestAnimationFrame(ae);return}m=null,$(y),V(v,y,S)};m=requestAnimationFrame(ae)},K=f=>{E=!0,Y(d+f)},D=({animate:f=!1}={})=>{if(w=N(),E=!1,I=j(c).width,f&&Math.abs(w-d)>.001){Y(w);return}m&&(cancelAnimationFrame(m),m=null),$(w),c.scrollLeft=0,c.scrollTop=0},M=({force:f=!1}={})=>{b&&cancelAnimationFrame(b),b=requestAnimationFrame(()=>{if(b=null,!e.isConnected)return;let y=j(c).width,v=Math.abs(y-I)>1;!f&&E||!f&&I>0&&!v||D()})};this.shellRefits.set(e,M),r.addEventListener("click",()=>K(-k.step)),a.addEventListener("click",()=>K(k.step)),o.addEventListener("click",()=>{D({animate:!0})});let H=()=>{let f=e.classList.contains("is-maximized");T(l,f?"restore":"maximize");let y=f?"Restore diagram size":"Maximize diagram";l.setAttribute("aria-label",y),l.title=y},te=f=>{let y=this.renderer.previewElement;if(f){let v=y.querySelector(".mermaid-shell.is-maximized");if(v&&v!==e){v.classList.remove("is-maximized"),this.shellRefits.get(v)?.();let S=v.querySelector(".mermaid-maximize-btn");S&&(T(S,"maximize"),S.setAttribute("aria-label","Maximize diagram"),S.title="Maximize diagram")}e.classList.add("is-maximized"),document.body.classList.add("mermaid-maximized-open"),H(),M({force:!0});return}e.classList.remove("is-maximized"),y.querySelector(".mermaid-shell.is-maximized")||document.body.classList.remove("mermaid-maximized-open"),H(),M({force:!0})};H(),l.addEventListener("click",()=>{te(!e.classList.contains("is-maximized"))});let O=()=>{if(F){if(F=!1,c.classList.remove("is-dragging"),A!==null&&typeof c.releasePointerCapture=="function")try{c.releasePointerCapture(A)}catch{}A=null}};c.addEventListener("pointerdown",f=>{f.button!==0||!c.classList.contains("is-pannable")||(m&&(cancelAnimationFrame(m),m=null),F=!0,A=f.pointerId,z=f.clientX,U=f.clientY,R=c.scrollLeft,B=c.scrollTop,c.classList.add("is-dragging"),c.setPointerCapture?.(f.pointerId),f.preventDefault())}),c.addEventListener("pointermove",f=>{F&&(c.scrollLeft=R-(f.clientX-z),c.scrollTop=B-(f.clientY-U))}),c.addEventListener("pointerup",O),c.addEventListener("pointercancel",O),c.addEventListener("lostpointercapture",O),c.appendChild(i);let _=e.querySelector(".mermaid-source");t.remove(),e.replaceChildren(),_&&(_.hidden=!0,e.appendChild(_)),e.append(s,c),M({force:!0})}scheduleActiveRefit(){let e=this.renderer.previewElement;e&&Array.from(e.querySelectorAll('.mermaid-shell[data-mermaid-hydrated="true"]')).forEach(t=>{this.shellRefits.get(t)?.()})}createZoomButton(e,t){let i=document.createElement("button");return i.type="button",i.className="mermaid-zoom-btn diagram-preview-action-btn",i.setAttribute("aria-label",t),i.title=t,i.textContent=e,i}};var xe=class extends se{constructor(e){super(e,{batchSize:ei,datasetKeys:{hydrated:"plantumlHydrated",instanceId:"plantumlInstanceId",key:"plantumlKey",label:"plantumlLabel",queued:"plantumlQueued",sourceHash:"plantumlSourceHash",sourceLine:"sourceLine",sourceLineEnd:"sourceLineEnd",target:"plantumlTarget"},filePathLabel:"PlantUML",shellClassName:"plantuml-shell",sourceClassName:"plantuml-source"}),this.renderer=e,this.svgCache=new Map,this.svgInflightRequests=new Map,this.shellRefits=new WeakMap,this.activeMaximizedShell=null,this.maximizedRoot=null,this.resizeFrameId=null}destroy(){this.cancelHydration(),this.preservedShells.clear(),this.clearActiveShell(),this.resizeFrameId&&(cancelAnimationFrame(this.resizeFrameId),this.resizeFrameId=null),this.maximizedRoot?.remove(),this.maximizedRoot=null}clearActiveShell(){this.activeMaximizedShell=null,this.maximizedRoot&&this.maximizedRoot.childElementCount===0&&(this.maximizedRoot.hidden=!0)}syncActiveShell(){return this.activeMaximizedShell?.isConnected&&this.activeMaximizedShell.classList.contains("is-maximized")?this.activeMaximizedShell:(this.clearActiveShell(),null)}scheduleActiveRefit(){this.resizeFrameId&&cancelAnimationFrame(this.resizeFrameId),this.resizeFrameId=requestAnimationFrame(()=>{this.resizeFrameId=null;let e=this.syncActiveShell();e&&this.shellRefits.get(e)?.()})}handleReconcile({restoredMaximizedShell:e}){e&&document.body.classList.add("plantuml-maximized-open"),this.syncActiveShell()}ensureMaximizedRoot(){if(this.maximizedRoot?.isConnected&&this.maximizedRoot.parentElement===document.body)return this.maximizedRoot;let e=document.body.querySelector('[data-plantuml-maximized-root="true"]');return e||(e=document.createElement("div"),e.dataset.plantumlMaximizedRoot="true",e.className="plantuml-maximized-root",document.body.appendChild(e)),this.maximizedRoot=e,e}mountShellInMaximizedRoot(e){if(!e)return;let t=this.ensureMaximizedRoot();t.hidden=!1,e._plantumlRestoreParent=e.parentElement||null,e._plantumlRestoreNextSibling=e.nextSibling||null,t.appendChild(e)}restoreShellMount(e){if(!e)return;let t=e._plantumlRestoreParent,i=e._plantumlRestoreNextSibling;t?.isConnected&&(i?.parentElement===t?t.insertBefore(e,i):t.appendChild(e)),e._plantumlRestoreParent=null,e._plantumlRestoreNextSibling=null,this.maximizedRoot&&this.maximizedRoot.childElementCount===0&&(this.maximizedRoot.hidden=!0)}async hydrateShell(e){if(!e?.isConnected||this.isShellHydrated(e))return;let t=e.querySelector(".plantuml-source");t||(t=document.createElement("span"),t.className="plantuml-source",t.hidden=!0,e.appendChild(t)),e.querySelector(".plantuml-placeholder-card")?.remove();try{let i=t.textContent??"";if(!i.trim()&&e.dataset.plantumlTarget){if(i=await this.fetchSource(e.dataset.plantumlTarget),!e.isConnected)return;t.textContent=i}if(!i.trim())throw new Error(e.dataset.plantumlTarget?"PlantUML file is empty":"PlantUML source is empty");let s=await this.fetchSvg(i);if(!e.isConnected)return;this.enhanceDiagram(e,s),this.markShellHydrated(e)}catch(i){console.warn("[preview] PlantUML render failed:",i),e.querySelector(":scope > .plantuml-toolbar")?.remove(),e.querySelector(":scope > .plantuml-frame")?.remove(),e.querySelector(".plantuml-placeholder-card")||t?.after(Ct(e.dataset.plantumlKey||"plantuml",i instanceof Error?i.message:"Render failed"))}}async fetchSvg(e){let t=e;if(this.svgCache.has(t))return this.svgCache.get(t);if(this.svgInflightRequests.has(t))return this.svgInflightRequests.get(t);let i=fetch(C("/plantuml/render"),{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({source:e})}).then(async s=>{let r=await s.json().catch(()=>null);if(!s.ok||!r?.ok||typeof r.svg!="string")throw new Error(r?.error||"Failed to render PlantUML");let a=ni(r.svg);return this.svgCache.set(t,a),a}).finally(()=>{this.svgInflightRequests.delete(t)});return this.svgInflightRequests.set(t,i),i}resetShell(e,{clearCache:t=!1,message:i="Renders server-side when visible"}={}){let s=e.querySelector(".plantuml-source")?.textContent??"";t&&s&&(this.svgCache.delete(s),this.svgInflightRequests.delete(s)),this.shellRefits.delete(e),this.activeMaximizedShell===e&&(this.restoreShellMount(e),this.clearActiveShell()),e.removeAttribute("data-plantuml-hydrated"),e.removeAttribute("data-plantuml-instance-id"),e.removeAttribute("data-plantuml-queued"),e.classList.remove("is-maximized"),this.syncActiveShell()||document.body.classList.remove("plantuml-maximized-open"),e.querySelector(":scope > .plantuml-toolbar")?.remove(),e.querySelector(":scope > .plantuml-frame")?.remove(),e.querySelector(".plantuml-placeholder-card")||e.querySelector(".plantuml-source")?.after(Ct(e.dataset.plantumlKey||"plantuml",i))}enhanceDiagram(e,t){let i=document.createElement("div");i.innerHTML=t;let s=i.querySelector("svg");if(!s)throw new Error("Renderer returned invalid SVG");let r=document.createElement("div");r.className="plantuml-toolbar diagram-preview-toolbar";let a=document.createElement("div");a.className="plantuml-frame diagram-preview-frame";let o=this.createToolButton("\u2212","Zoom out"),l=this.createToolButton("+","Zoom in"),h=this.createToolButton("Reset","Reset zoom"),c=this.createToolButton("Reload","Reload diagram"),u=this.createToolButton("Max","Maximize diagram");u.classList.add("plantuml-maximize-btn"),T(c,"refresh"),T(u,"maximize");let p=document.createElement("span");p.className="plantuml-zoom-label diagram-preview-zoom-label",p.setAttribute("aria-live","polite"),r.append(o,p,h,l,c,u);let{width:d,height:w}=ce(s),m=P.default,b=1,E=null,I=!1,F=null,A=0,z=0,U=0,R=0;s.style.display="block",s.style.margin="0 auto",s.style.maxWidth="none";let B=()=>{let f=j(a);return!Number.isFinite(d)||d<=0||f.width<=0?P.default:x(Math.min(P.default,f.width/d),P.min,P.max)},N=f=>{m=x(f,P.min,P.max),s.style.width=`${d*m}px`,s.style.height=`${w*m}px`,p.textContent=`${Math.round(m*100)}%`,o.disabled=m<=P.min,l.disabled=m>=P.max;let y=j(a),v=d*m>y.width||w*m>y.height;a.classList.toggle("is-pannable",v)},$=()=>({x:a.scrollLeft+a.clientWidth/2,y:a.scrollTop+a.clientHeight/2}),G=(f,y,v)=>{if(f===0)return;let S=y/f;a.scrollLeft=v.x*S-a.clientWidth/2,a.scrollTop=v.y*S-a.clientHeight/2},V=f=>{let y=x(f,P.min,P.max),v=m;if(y===v)return;let S=$(),gt=performance.now();E&&cancelAnimationFrame(E);let ae=wt=>{let oe=x((wt-gt)/P.animationDurationMs,0,1),yt=Pe(oe),le=v+(y-v)*yt;if(N(le),G(v,le,S),oe<1){E=requestAnimationFrame(ae);return}E=null,N(y),G(v,y,S)};E=requestAnimationFrame(ae)},Y=f=>{V(m+f)},K=({animate:f=!1}={})=>{if(b=B(),f&&Math.abs(b-m)>.001){V(b);return}E&&(cancelAnimationFrame(E),E=null),N(b),a.scrollLeft=0,a.scrollTop=0},D=null,M=()=>{D&&cancelAnimationFrame(D),D=requestAnimationFrame(()=>{D=null,e.isConnected&&K()})};this.shellRefits.set(e,M),o.addEventListener("click",()=>Y(-P.step)),l.addEventListener("click",()=>Y(P.step)),h.addEventListener("click",()=>{K({animate:!0})});let H=()=>{let f=e.classList.contains("is-maximized");T(u,f?"restore":"maximize");let y=f?"Restore diagram size":"Maximize diagram";u.setAttribute("aria-label",y),u.title=y},te=f=>{if(f){let y=this.syncActiveShell();if(y&&y!==e){this.restoreShellMount(y),y.classList.remove("is-maximized"),this.activeMaximizedShell===y&&this.clearActiveShell(),this.shellRefits.get(y)?.();let v=y.querySelector(".plantuml-maximize-btn");v&&(T(v,"maximize"),v.setAttribute("aria-label","Maximize diagram"),v.title="Maximize diagram")}this.mountShellInMaximizedRoot(e),e.classList.add("is-maximized"),this.activeMaximizedShell=e,document.body.classList.add("plantuml-maximized-open"),H(),M();return}this.restoreShellMount(e),e.classList.remove("is-maximized"),this.activeMaximizedShell===e&&this.clearActiveShell(),this.syncActiveShell()||document.body.classList.remove("plantuml-maximized-open"),H(),M()};c.addEventListener("click",()=>{this.resetShell(e,{clearCache:!0,message:"Refreshing\u2026"}),this.enqueueShell(e,{prioritize:!0})}),H(),u.addEventListener("click",()=>{te(!e.classList.contains("is-maximized"))});let O=()=>{if(I){if(I=!1,a.classList.remove("is-dragging"),F!==null&&typeof a.releasePointerCapture=="function")try{a.releasePointerCapture(F)}catch{}F=null}};a.addEventListener("pointerdown",f=>{f.button!==0||!a.classList.contains("is-pannable")||(E&&(cancelAnimationFrame(E),E=null),I=!0,F=f.pointerId,A=f.clientX,z=f.clientY,U=a.scrollLeft,R=a.scrollTop,a.classList.add("is-dragging"),a.setPointerCapture?.(f.pointerId),f.preventDefault())}),a.addEventListener("pointermove",f=>{I&&(a.scrollLeft=U-(f.clientX-A),a.scrollTop=R-(f.clientY-z))}),a.addEventListener("pointerup",O),a.addEventListener("pointercancel",O),a.addEventListener("lostpointercapture",O),a.appendChild(s);let _=e.querySelector(".plantuml-source");e.replaceChildren(),_&&(_.hidden=!0,e.appendChild(_)),e.append(r,a),b=B(),N(b)}createToolButton(e,t){let i=document.createElement("button");return i.type="button",i.className="plantuml-tool-btn diagram-preview-action-btn",i.setAttribute("aria-label",t),i.title=t,i.textContent=e,i}};function nn(){return new Worker(new URL("./preview-render-worker.js",import.meta.url),{type:"module"})}var Ie=class{constructor({attachmentApiPath:e="/api/attachment",cancelIdleRenderFn:t=ne,compilePreviewDocumentLoader:i=()=>import("./chunks/preview-render-compiler-6Y7TKXFJ.js"),createWorkerFn:s=nn,getFileList:r,getSourceFilePath:a=null,idleTimeoutMs:o=W,requestIdleRenderFn:l=ie}={}){this.attachmentApiPath=e,this.cancelIdleRenderFn=t,this.compilePreviewDocumentLoader=i,this.createWorkerFn=s,this.getFileList=r,this.getSourceFilePath=a,this.idleTimeoutMs=o,this.requestIdleRenderFn=l,this.worker=null,this.workerDisabled=!1,this.workerJob=null,this.workerPrewarmId=null,this.handleWorkerMessage=h=>{if(!this.workerJob||h.data?.renderVersion!==this.workerJob.renderVersion)return;let c=this.workerJob;if(this.workerJob=null,h.data?.error){c.reject(new Error(h.data.error));return}c.resolve({html:h.data.html,stats:h.data.stats})},this.handleWorkerError=h=>{let c=new Error(h.message||"Preview worker failed");this.workerJob&&(this.workerJob.reject(c),this.workerJob=null),this.reset("Preview worker failed",{disable:!0})}}hasPendingJob(){return this.workerJob!==null}schedulePrewarm({timeout:e=this.idleTimeoutMs}={}){this.workerDisabled||this.worker||this.workerPrewarmId!==null||(this.workerPrewarmId=this.requestIdleRenderFn(()=>{this.workerPrewarmId=null,this.ensureWorker()},e))}ensureWorker(){if(this.workerDisabled)return null;if(this.worker)return this.worker;try{return this.worker=this.createWorkerFn(),this.worker.addEventListener("message",this.handleWorkerMessage),this.worker.addEventListener("error",this.handleWorkerError),this.worker}catch{return this.workerDisabled=!0,null}}async compile(e,t){if(this.ensureWorker()){this.workerJob&&this.reset("Superseded preview render");let r=this.ensureWorker();return new Promise((a,o)=>{this.workerJob={reject:o,renderVersion:t,resolve:a},r.postMessage({attachmentApiPath:this.attachmentApiPath,fileList:this.getFileList?.()??[],markdownText:e,renderVersion:t,sourceFilePath:this.getSourceFilePath?.()??""})})}let{compilePreviewDocument:s}=await this.compilePreviewDocumentLoader();return s({attachmentApiPath:this.attachmentApiPath,fileList:this.getFileList?.()??[],markdownText:e,sourceFilePath:this.getSourceFilePath?.()??""})}cancelWorkerJob(e){this.workerJob&&(this.workerJob.reject(new Error(e)),this.workerJob=null)}reset(e,{disable:t=!1}={}){this.cancelWorkerJob(e),this.worker&&(this.worker.removeEventListener("message",this.handleWorkerMessage),this.worker.removeEventListener("error",this.handleWorkerError),this.worker.terminate(),this.worker=null),t&&(this.workerDisabled=!0)}destroy(e="Preview renderer destroyed"){this.workerPrewarmId!==null&&this.cancelIdleRenderFn(this.workerPrewarmId),this.workerPrewarmId=null,this.reset(e)}};var Fe=class{constructor({cancelAnimationFrameFn:e=h=>cancelAnimationFrame(h),cancelIdleRenderFn:t=ne,clearTimeoutFn:i=h=>clearTimeout(h),getRenderProfileFn:s=be,idleTimeoutMs:r=W,requestAnimationFrameFn:a=h=>requestAnimationFrame(h),requestIdleRenderFn:o=ie,setTimeoutFn:l=(h,c)=>setTimeout(h,c)}={}){this.cancelAnimationFrameFn=e,this.cancelIdleRenderFn=t,this.clearTimeoutFn=i,this.getRenderProfileFn=s,this.idleTimeoutMs=r,this.requestAnimationFrameFn=a,this.requestIdleRenderFn=o,this.setTimeoutFn=l,this.frameId=null,this.idleId=null,this.timeoutId=null}queue({markdownText:e,onRenderRequested:t,renderVersion:i}){let s=this.getRenderProfileFn(e);this.cancel();let r=()=>{this.frameId=this.requestAnimationFrameFn(()=>{this.frameId=null,this.timeoutId=null,t?.(e,i)})},a=()=>{if(s.deferUntilIdle){this.idleId=this.requestIdleRenderFn(()=>{this.idleId=null,r()},this.idleTimeoutMs);return}r()};this.timeoutId=this.setTimeoutFn(a,s.debounceMs)}cancel(){this.clearTimeoutFn(this.timeoutId),this.frameId&&this.cancelAnimationFrameFn(this.frameId),this.cancelIdleRenderFn(this.idleId),this.frameId=null,this.idleId=null,this.timeoutId=null}destroy(){this.cancel()}};var Te=class{constructor({getContent:e,getFileList:t,getSourceFilePath:i,onAfterRenderCommit:s,onBeforeRenderCommit:r,onRenderComplete:a,outlineController:o,previewContainer:l,previewElement:h}){this.getContent=e,this.getFileList=t,this.getSourceFilePath=i,this.onAfterRenderCommit=s,this.onBeforeRenderCommit=r,this.onRenderComplete=a,this.outlineController=o,this.previewContainer=l,this.previewElement=h,this.renderHost=null,this.pendingRenderVersion=0,this.activeRenderVersion=0,this.readyRenderVersion=0,this.currentStats=null,this.isLargeDocument=!1,this.hydrationPaused=!1,this.handlePreviewClick=c=>{let u=c.target.closest(".mermaid-placeholder-btn");if(u){let d=u.closest(".mermaid-shell");if(!d)return;c.preventDefault(),this.enqueueMermaidShell(d,{prioritize:!0});return}let p=c.target.closest(".plantuml-placeholder-btn");if(p){let d=p.closest(".plantuml-shell");if(!d)return;c.preventDefault(),this.enqueuePlantUmlShell(d,{prioritize:!0})}},this.handleWindowResize=()=>{this.mermaidHydrator.scheduleActiveRefit(),this.plantUmlHydrator.scheduleActiveRefit()},this.mermaidHydrator=new Le(this),this.plantUmlHydrator=new xe(this),this.renderScheduler=new Fe({getRenderProfileFn:be}),this.renderExecutor=new Ie({attachmentApiPath:C("/attachment"),getFileList:()=>this.getFileList?.()??[],getSourceFilePath:()=>this.getSourceFilePath?.()??"",idleTimeoutMs:W}),this.previewElement?.addEventListener("click",this.handlePreviewClick),window.addEventListener("resize",this.handleWindowResize),this.setPhase("ready")}ensureRenderHost(){if(!this.previewElement)return null;if(this.renderHost?.isConnected&&this.renderHost.parentElement===this.previewElement)return this.renderHost;let e=this.previewElement.querySelector('[data-preview-render-host="true"]');return e||(e=document.createElement("div"),e.dataset.previewRenderHost="true",this.previewElement.appendChild(e)),this.renderHost=e,this.renderHost}normalizePreviewChildren(e=this.renderHost){this.previewElement&&Array.from(this.previewElement.children).forEach(t=>{t===e||t.dataset.excalidrawOverlayRoot==="true"||t.dataset.videoOverlayRoot==="true"||t.remove()})}getReservedPreviewHeight(){let e=this.renderHost?.getBoundingClientRect?.().height??0,t=this.previewContainer?.clientHeight??0;return Math.max(Math.round(e),Math.round(t),320)}beginDocumentLoad(){this.cancelScheduledRender(),this.cancelMermaidHydration(),this.cancelPlantUmlHydration(),this.mermaidHydrator.clearPreservedShells(),this.plantUmlHydrator.clearPreservedShells(),this.clearActivePlantUmlShell(),this.onBeforeRenderCommit?.(this.previewElement),this.pendingRenderVersion+=1,this.activeRenderVersion=this.pendingRenderVersion,this.readyRenderVersion=0,this.currentStats=null,this.isLargeDocument=!1,this.renderExecutor.hasPendingJob()&&this.resetWorker("Document changed");let e=this.ensureRenderHost();this.normalizePreviewChildren(e);let t=this.getReservedPreviewHeight();e&&(e.replaceChildren(),e.style.minHeight=`${t}px`);let i=document.createElement("div");i.className="preview-shell",i.style.minHeight=`${t}px`,i.textContent="Rendering preview\u2026",e?.append(i),this.setPhase("shell")}applyTheme(e){let t=document.getElementById("hljs-theme");if(t){let{darkHref:i,lightHref:s}=t.dataset;t.href=e==="dark"?i:s}this.mermaidHydrator.applyTheme(e)}configureMermaid(e){this.mermaidHydrator.configureMermaid(e)}ensureMermaid(){return this.mermaidHydrator.ensureMermaid()}queueRender(){let e=this.getContent();this.cancelScheduledRender(),this.pendingRenderVersion+=1;let t=this.pendingRenderVersion;this.renderScheduler.queue({markdownText:e,onRenderRequested:(i,s)=>{this.render(i,s)},renderVersion:t})}async render(e=this.getContent(),t=this.pendingRenderVersion){if(this.previewElement)try{let i=await this.compilePreview(e,t);if(t!==this.pendingRenderVersion)return;this.commitBaseRender(i,t)}catch(i){if(t!==this.pendingRenderVersion)return;console.warn("[preview] Failed to render preview:",i)}}destroy(){this.renderScheduler.destroy(),this.mermaidHydrator.destroy(),this.plantUmlHydrator.destroy(),this.renderExecutor.destroy(),this.previewElement?.removeEventListener("click",this.handlePreviewClick),window.removeEventListener("resize",this.handleWindowResize)}setPhase(e){this.previewElement&&(this.previewElement.dataset.renderPhase=e)}cancelScheduledRender(){this.renderScheduler.cancel()}cancelMermaidHydration(){this.mermaidHydrator.cancelHydration()}cancelPlantUmlHydration(){this.plantUmlHydrator.cancelHydration()}clearActivePlantUmlShell(){this.plantUmlHydrator.clearActiveShell()}scheduleActiveMermaidRefit(){this.mermaidHydrator.scheduleActiveRefit()}syncActivePlantUmlShell(){return this.plantUmlHydrator.syncActiveShell()}scheduleActivePlantUmlRefit(){this.plantUmlHydrator.scheduleActiveRefit()}setHydrationPaused(e){if(this.hydrationPaused=!!e,this.hydrationPaused){this.mermaidHydrator.cancelPendingIdleWork(),this.plantUmlHydrator.cancelPendingIdleWork();return}this.mermaidHydrator.hydrateVisibleShells(),this.mermaidHydrator.scheduleHydration(),this.plantUmlHydrator.hydrateVisibleShells(),this.plantUmlHydrator.scheduleHydration(),this.updateHydrationPhase()}resetWorker(e,{disable:t=!1}={}){this.renderExecutor.reset(e,{disable:t})}scheduleWorkerPrewarm({timeout:e=W}={}){this.renderExecutor.schedulePrewarm({timeout:e})}async compilePreview(e,t){return this.renderExecutor.compile(e,t)}commitBaseRender({html:e,stats:t},i){this.activeRenderVersion=i,this.readyRenderVersion=0,this.currentStats=t,this.isLargeDocument=Vt(t),this.cancelMermaidHydration(),this.cancelPlantUmlHydration(),document.body.classList.remove("mermaid-maximized-open"),document.body.classList.remove("plantuml-maximized-open"),this.preserveHydratedMermaidsForCommit(),this.preserveHydratedPlantUmlsForCommit(),this.onBeforeRenderCommit?.(this.previewElement);let s=this.ensureRenderHost();this.normalizePreviewChildren(s),s&&(s.innerHTML=e),this.reconcileHydratedMermaids(),this.reconcileHydratedPlantUmls(),this.setPhase("base"),this.outlineController.refresh(),this.onAfterRenderCommit?.(this.previewElement,{...t,isLargeDocument:this.isLargeDocument,renderVersion:i});let r=this.setupMermaidHydration(i),a=this.setupPlantUmlHydration(i);r===0&&a===0&&this.notifyReady()}preserveHydratedMermaidsForCommit(){this.mermaidHydrator.preserveHydratedShellsForCommit()}preserveHydratedPlantUmlsForCommit(){this.plantUmlHydrator.preserveHydratedShellsForCommit()}reconcileHydratedMermaids(){this.mermaidHydrator.reconcileHydratedShells()}reconcileHydratedPlantUmls(){this.plantUmlHydrator.reconcileHydratedShells()}syncPreservedMermaidShell(e,t){this.mermaidHydrator.syncPreservedShell(e,t)}syncPreservedPlantUmlShell(e,t){this.plantUmlHydrator.syncPreservedShell(e,t)}setupMermaidHydration(e){return this.mermaidHydrator.setupHydration(e)}hydrateVisibleMermaids(){this.mermaidHydrator.hydrateVisibleShells()}enqueueMermaidShell(e,{prioritize:t=!1}={}){this.mermaidHydrator.enqueueShell(e,{prioritize:t})}scheduleMermaidHydration(){this.mermaidHydrator.scheduleHydration()}async flushMermaidHydrationQueue(){await this.mermaidHydrator.flushHydrationQueue()}async hydrateMermaidShell(e,t){await this.mermaidHydrator.hydrateShell(e,t)}resetHydratedMermaids(){this.mermaidHydrator.resetHydratedShells()}setupPlantUmlHydration(e){return this.plantUmlHydrator.setupHydration(e)}hydrateVisiblePlantUmls(){this.plantUmlHydrator.hydrateVisibleShells()}enqueuePlantUmlShell(e,{prioritize:t=!1}={}){this.plantUmlHydrator.enqueueShell(e,{prioritize:t})}schedulePlantUmlHydration(){this.plantUmlHydrator.scheduleHydration()}async flushPlantUmlHydrationQueue(){await this.plantUmlHydrator.flushHydrationQueue()}async hydratePlantUmlShell(e){await this.plantUmlHydrator.hydrateShell(e)}updateHydrationPhase(){if(this.hydrationPaused&&(this.mermaidHydrator.hasPendingWork()||this.plantUmlHydrator.hasPendingWork())){this.setPhase("base");return}if(this.mermaidHydrator.hasPendingWork()||this.plantUmlHydrator.hasPendingWork()){this.setPhase("hydrating");return}this.notifyReady()}notifyReady(){this.renderHost&&(this.renderHost.style.minHeight=""),this.setPhase("ready"),this.readyRenderVersion!==this.activeRenderVersion&&(this.readyRenderVersion=this.activeRenderVersion,this.onRenderComplete?.({isLargeDocument:this.isLargeDocument,stats:this.currentStats}))}async fetchPlantUmlSvg(e){return this.plantUmlHydrator.fetchSvg(e)}async fetchPlantUmlSource(e){return this.plantUmlHydrator.fetchSource(e)}async fetchMermaidSource(e){return this.mermaidHydrator.fetchSource(e)}resetPlantUmlShell(e,{clearCache:t=!1,message:i="Renders server-side when visible"}={}){this.plantUmlHydrator.resetShell(e,{clearCache:t,message:i})}enhancePlantUmlDiagram(e,t){this.plantUmlHydrator.enhanceDiagram(e,t)}enhanceMermaidDiagram(e,t){this.mermaidHydrator.enhanceDiagram(e,t)}createMermaidZoomButton(e,t){return this.mermaidHydrator.createZoomButton(e,t)}createPlantUmlToolButton(e,t){return this.plantUmlHydrator.createToolButton(e,t)}};var Ae=class{constructor({backlinksPanel:e,clearInitialFileBootstrap:t,closeSidebarOnMobile:i,elements:s,excalidrawEmbed:r,fileExplorer:a,getIsTabActive:o,getSessionLoadToken:l,gitDiffView:h,gitPanel:c,imageLightbox:u=null,lobby:p,navigation:d,previewRenderer:w,renderAvatars:m,renderPresence:b,resetPreviewMode:E,scrollSyncController:I,setSession:F,setSessionLoadToken:A,setSidebarTab:z,setCurrentFilePath:U,showGitDiff:R,syncMainChrome:B,videoEmbed:N,workspaceCoordinator:$,layoutController:G}){this.backlinksPanel=e,this.clearInitialFileBootstrap=t,this.closeSidebarOnMobile=i,this.elements=s,this.excalidrawEmbed=r,this.fileExplorer=a,this.getIsTabActive=o,this.getSessionLoadToken=l,this.gitDiffView=h,this.gitPanel=c,this.imageLightbox=u,this.lobby=p,this.navigation=d,this.previewRenderer=w,this.renderAvatars=m,this.renderPresence=b,this.resetPreviewMode=E,this.scrollSyncController=I,this.setSession=F,this.setSessionLoadToken=A,this.setSidebarTab=z,this.setCurrentFilePath=U,this.showGitDiff=R,this.syncMainChrome=B,this.videoEmbed=N,this.workspaceCoordinator=$,this.layoutController=G}async handleHashChange(){if(!this.getIsTabActive())return;let e=this.navigation.getHashRoute();if(e.type==="empty"){this.gitPanel.setSelection(),this.showEmptyState(),this.syncMainChrome({mode:"empty",title:"CollabMD"});return}if(e.type==="git-diff"){this.setSidebarTab("git"),await this.showGitDiff(e);return}this.setSidebarTab("files"),await this.openFile(e.filePath)}showEmptyState(){this.gitDiffView.hide(),this.workspaceCoordinator.cleanupSession(),this.setSession(null),this.setSessionLoadToken(this.getSessionLoadToken()+1),this.clearInitialFileBootstrap(),this.resetPreviewMode(),this.elements.outlineToggle?.classList.remove("hidden"),this.elements.markdownToolbar?.classList.add("hidden"),this.setCurrentFilePath(null),this.lobby.setCurrentFile(null),this.fileExplorer.setActiveFile(null),this.elements.emptyState?.classList.remove("hidden"),this.elements.editorPage?.classList.add("hidden"),this.elements.diffPage?.classList.add("hidden"),this.elements.previewContent&&(this.elements.previewContent.innerHTML="",this.elements.previewContent.dataset.renderPhase="ready"),this.videoEmbed?.reconcileEmbeds(this.elements.previewContent),this.resetPreviewSurface(),this.renderAvatars(),this.renderPresence(),this.backlinksPanel.clear(),this.elements.activeFileName&&(this.elements.activeFileName.textContent="CollabMD")}showDiffState(){this.setSessionLoadToken(this.getSessionLoadToken()+1),this.clearInitialFileBootstrap(),this.workspaceCoordinator.cleanupSession(),this.setSession(null),this.resetPreviewMode(),this.layoutController.reset(),this.setCurrentFilePath(null),this.lobby.setCurrentFile(null),this.fileExplorer.setActiveFile(null),this.elements.emptyState?.classList.add("hidden"),this.elements.editorPage?.classList.add("hidden"),this.elements.diffPage?.classList.remove("hidden"),this.elements.previewContent&&(this.elements.previewContent.innerHTML="",this.elements.previewContent.dataset.renderPhase="ready"),this.videoEmbed?.reconcileEmbeds(this.elements.previewContent),this.resetPreviewSurface(),this.elements.outlineToggle?.classList.add("hidden"),this.elements.markdownToolbar?.classList.add("hidden"),this.renderAvatars(),this.renderPresence(),this.backlinksPanel.clear()}async openFile(e){this.imageLightbox?.close?.(),this.gitPanel.setSelection(),this.gitDiffView.hide(),this.syncMainChrome({mode:"editor"}),await this.workspaceCoordinator.openFile(e),this.setSession(this.workspaceCoordinator.getSession())}cleanupSession(){this.workspaceCoordinator.cleanupSession(),this.setSession(this.workspaceCoordinator.getSession())}handleFileSelection(e,{closeSidebarOnMobile:t=!1}={}){t&&this.closeSidebarOnMobile(),this.navigation.navigateToFile(e)}resetPreviewSurface(){this.imageLightbox?.close?.(),this.previewRenderer.setHydrationPaused(!1),this.excalidrawEmbed.setHydrationPaused(!1),this.videoEmbed?.detachForCommit(),this.scrollSyncController.setLargeDocumentMode(!1),this.scrollSyncController.invalidatePreviewBlocks()}};function L(n){let e=String(n??"").trim().replace(/\\/g,"/").replace(/^\/+/u,"").split("/").map(t=>t.trim()).filter(Boolean);return e.some(t=>t==="."||t==="..")?"":e.join("/")}function re(n,e){let t=L(n),i=L(e);return t?i?`${t}/${i}`:t:i}function ai(n,e){return n.toLowerCase().endsWith(e.toLowerCase())?n:`${n}${e}`}function Me(n){return`# ${q(String(n??"").split("/").pop()||"")||"Untitled"}
|
|
22
|
+
`),n=i.findIndex(r=>/^\s*gantt\b/.test(r));return n===-1?t:(i.splice(n+1,0," todayMarker off"),i.join(`
|
|
23
|
+
`))}getPreviewInitConfig(e){return/^\s*stateDiagram(?:-v2)?\b/m.test(e)?{htmlLabels:!1}:/^\s*classDiagram\b/m.test(e)?{htmlLabels:!1}:/^\s*gantt\b/m.test(e)?{htmlLabels:!1}:null}resetHydratedShells(){let e=this.renderer.previewElement;if(!e)return;let t=Array.from(e.querySelectorAll('.mermaid-shell[data-mermaid-hydrated="true"]'));t.length!==0&&t.forEach(i=>{this.shellRefits.delete(i),i.removeAttribute("data-mermaid-hydrated"),i.querySelector(":scope > .mermaid-toolbar")?.remove(),i.querySelector(":scope > .mermaid-frame")?.remove(),i.querySelector(":scope > .mermaid-render-node")?.remove(),i.querySelector(".mermaid-placeholder-card")||i.querySelector(".mermaid-source")?.after(di(i.dataset.mermaidKey||"mermaid")),this.enqueueShell(i,{prioritize:!0})})}enhanceDiagram(e,t){let i=t.querySelector("svg");if(!i){t.remove();return}let n=document.createElement("div");n.className="mermaid-toolbar diagram-preview-toolbar";let r=this.createZoomButton("\u2212","Zoom out"),o=this.createZoomButton("+","Zoom in"),a=this.createZoomButton("Reset","Reset zoom"),c=this.createZoomButton("Max","Maximize diagram");c.classList.add("mermaid-maximize-btn"),A(c,"maximize");let h=document.createElement("span");h.className="mermaid-zoom-label diagram-preview-zoom-label",h.setAttribute("aria-live","polite"),n.append(r,h,a,o,c);let l=document.createElement("div");l.className="mermaid-frame diagram-preview-frame";let{width:u,height:m}=hi(i),d=L.default,w=1,f=null,y=null,E=!1,S=0,k=!1,M=null,D=0,_=0,R=0,$=0;i.style.display="block",i.style.margin="0 auto",i.style.maxWidth="none";let H=()=>{let g=Q(l);if(!Number.isFinite(u)||u<=0||g.width<=0)return L.default;let v=g.width/u;return!Number.isFinite(v)||v<=0?L.default:T(v,L.min,L.max)},q=g=>{d=T(g,L.min,L.max),i.style.width=`${u*d}px`,i.style.height=`${m*d}px`,h.textContent=`${Math.round(d*100)}%`,r.disabled=d<=L.min,o.disabled=d>=L.max;let v=Q(l),C=u*d>v.width||m*d>v.height;l.classList.toggle("is-pannable",C),i.style.margin=C?"0":"0 auto"},j=()=>({x:l.scrollLeft+l.clientWidth/2,y:l.scrollTop+l.clientHeight/2}),W=(g,v,C)=>{if(g===0)return;let P=v/g;l.scrollLeft=C.x*P-l.clientWidth/2,l.scrollTop=C.y*P-l.clientHeight/2},G=g=>{let v=T(g,L.min,L.max),C=d;if(v===C)return;let P=j(),ie=performance.now();f&&cancelAnimationFrame(f);let ae=bt=>{let le=T((bt-ie)/L.animationDurationMs,0,1),Ct=xe(le),ce=C+(v-C)*Ct;if(q(ce),W(C,ce,P),le<1){f=requestAnimationFrame(ae);return}f=null,q(v),W(C,v,P)};f=requestAnimationFrame(ae)},O=g=>{E=!0,G(d+g)},N=({animate:g=!1}={})=>{if(w=H(),E=!1,S=Q(l).width,g&&Math.abs(w-d)>.001){G(w);return}f&&(cancelAnimationFrame(f),f=null),q(w),l.scrollLeft=0,l.scrollTop=0},I=({force:g=!1}={})=>{y&&cancelAnimationFrame(y),y=requestAnimationFrame(()=>{if(y=null,!e.isConnected)return;let v=Q(l).width,C=Math.abs(v-S)>1;!g&&E||!g&&S>0&&!C||N()})};this.shellRefits.set(e,I),r.addEventListener("click",()=>O(-L.step)),o.addEventListener("click",()=>O(L.step)),a.addEventListener("click",()=>{N({animate:!0})});let B=()=>{let g=e.classList.contains("is-maximized");A(c,g?"restore":"maximize");let v=g?"Restore diagram size":"Maximize diagram";c.setAttribute("aria-label",v),c.title=v},te=g=>{let v=this.renderer.previewElement;if(g){let C=v.querySelector(".mermaid-shell.is-maximized");if(C&&C!==e){C.classList.remove("is-maximized"),this.shellRefits.get(C)?.();let P=C.querySelector(".mermaid-maximize-btn");P&&(A(P,"maximize"),P.setAttribute("aria-label","Maximize diagram"),P.title="Maximize diagram")}e.classList.add("is-maximized"),document.body.classList.add("mermaid-maximized-open"),B(),I({force:!0});return}e.classList.remove("is-maximized"),v.querySelector(".mermaid-shell.is-maximized")||document.body.classList.remove("mermaid-maximized-open"),B(),I({force:!0})};B(),c.addEventListener("click",()=>{te(!e.classList.contains("is-maximized"))});let z=()=>{if(k){if(k=!1,l.classList.remove("is-dragging"),M!==null&&typeof l.releasePointerCapture=="function")try{l.releasePointerCapture(M)}catch{}M=null}};l.addEventListener("pointerdown",g=>{g.button!==0||!l.classList.contains("is-pannable")||(f&&(cancelAnimationFrame(f),f=null),k=!0,M=g.pointerId,D=g.clientX,_=g.clientY,R=l.scrollLeft,$=l.scrollTop,l.classList.add("is-dragging"),l.setPointerCapture?.(g.pointerId),g.preventDefault())}),l.addEventListener("pointermove",g=>{k&&(l.scrollLeft=R-(g.clientX-D),l.scrollTop=$-(g.clientY-_))}),l.addEventListener("pointerup",z),l.addEventListener("pointercancel",z),l.addEventListener("lostpointercapture",z),l.appendChild(i);let U=e.querySelector(".mermaid-source");t.remove(),e.replaceChildren(),U&&(U.hidden=!0,e.appendChild(U)),e.append(n,l),I({force:!0})}scheduleActiveRefit(){let e=this.renderer.previewElement;e&&Array.from(e.querySelectorAll('.mermaid-shell[data-mermaid-hydrated="true"]')).forEach(t=>{this.shellRefits.get(t)?.()})}createZoomButton(e,t){let i=document.createElement("button");return i.type="button",i.className="mermaid-zoom-btn ui-preview-action",i.setAttribute("aria-label",t),i.title=t,i.textContent=e,i}};var Te=class extends re{constructor(e){super(e,{batchSize:ci,datasetKeys:{hydrated:"plantumlHydrated",instanceId:"plantumlInstanceId",key:"plantumlKey",label:"plantumlLabel",queued:"plantumlQueued",sourceHash:"plantumlSourceHash",sourceLine:"sourceLine",sourceLineEnd:"sourceLineEnd",target:"plantumlTarget"},filePathLabel:"PlantUML",shellClassName:"plantuml-shell",sourceClassName:"plantuml-source"}),this.renderer=e,this.svgCache=new Map,this.svgInflightRequests=new Map,this.shellRefits=new WeakMap,this.activeMaximizedShell=null,this.maximizedRoot=null,this.resizeFrameId=null}destroy(){this.cancelHydration(),this.preservedShells.clear(),this.clearActiveShell(),this.resizeFrameId&&(cancelAnimationFrame(this.resizeFrameId),this.resizeFrameId=null),this.maximizedRoot?.remove(),this.maximizedRoot=null}clearActiveShell(){this.activeMaximizedShell=null,this.maximizedRoot&&this.maximizedRoot.childElementCount===0&&(this.maximizedRoot.hidden=!0)}syncActiveShell(){return this.activeMaximizedShell?.isConnected&&this.activeMaximizedShell.classList.contains("is-maximized")?this.activeMaximizedShell:(this.clearActiveShell(),null)}scheduleActiveRefit(){this.resizeFrameId&&cancelAnimationFrame(this.resizeFrameId),this.resizeFrameId=requestAnimationFrame(()=>{this.resizeFrameId=null;let e=this.syncActiveShell();e&&this.shellRefits.get(e)?.()})}handleReconcile({restoredMaximizedShell:e}){e&&document.body.classList.add("plantuml-maximized-open"),this.syncActiveShell()}ensureMaximizedRoot(){if(this.maximizedRoot?.isConnected&&this.maximizedRoot.parentElement===document.body)return this.maximizedRoot;let e=document.body.querySelector('[data-plantuml-maximized-root="true"]');return e||(e=document.createElement("div"),e.dataset.plantumlMaximizedRoot="true",e.className="plantuml-maximized-root",document.body.appendChild(e)),this.maximizedRoot=e,e}mountShellInMaximizedRoot(e){if(!e)return;let t=this.ensureMaximizedRoot();t.hidden=!1,e._plantumlRestoreParent=e.parentElement||null,e._plantumlRestoreNextSibling=e.nextSibling||null,t.appendChild(e)}restoreShellMount(e){if(!e)return;let t=e._plantumlRestoreParent,i=e._plantumlRestoreNextSibling;t?.isConnected&&(i?.parentElement===t?t.insertBefore(e,i):t.appendChild(e)),e._plantumlRestoreParent=null,e._plantumlRestoreNextSibling=null,this.maximizedRoot&&this.maximizedRoot.childElementCount===0&&(this.maximizedRoot.hidden=!0)}async hydrateShell(e){if(!e?.isConnected||this.isShellHydrated(e))return;let t=e.querySelector(".plantuml-source");t||(t=document.createElement("span"),t.className="plantuml-source",t.hidden=!0,e.appendChild(t)),e.querySelector(".plantuml-placeholder-card")?.remove();try{let i=t.textContent??"";if(!i.trim()&&e.dataset.plantumlTarget){if(i=await this.fetchSource(e.dataset.plantumlTarget),!e.isConnected)return;t.textContent=i}if(!i.trim())throw new Error(e.dataset.plantumlTarget?"PlantUML file is empty":"PlantUML source is empty");let n=await this.fetchSvg(i);if(!e.isConnected)return;this.enhanceDiagram(e,n),this.markShellHydrated(e)}catch(i){console.warn("[preview] PlantUML render failed:",i),e.querySelector(":scope > .plantuml-toolbar")?.remove(),e.querySelector(":scope > .plantuml-frame")?.remove(),e.querySelector(".plantuml-placeholder-card")||t?.after(Pt(e.dataset.plantumlKey||"plantuml",i instanceof Error?i.message:"Render failed"))}}async fetchSvg(e){let t=e;if(this.svgCache.has(t))return this.svgCache.get(t);if(this.svgInflightRequests.has(t))return this.svgInflightRequests.get(t);let i=fetch(b("/plantuml/render"),{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({source:e})}).then(async n=>{let r=await n.json().catch(()=>null);if(!n.ok||!r?.ok||typeof r.svg!="string")throw new Error(r?.error||"Failed to render PlantUML");let o=ui(r.svg);return this.svgCache.set(t,o),o}).finally(()=>{this.svgInflightRequests.delete(t)});return this.svgInflightRequests.set(t,i),i}resetShell(e,{clearCache:t=!1,message:i="Renders server-side when visible"}={}){let n=e.querySelector(".plantuml-source")?.textContent??"";t&&n&&(this.svgCache.delete(n),this.svgInflightRequests.delete(n)),this.shellRefits.delete(e),this.activeMaximizedShell===e&&(this.restoreShellMount(e),this.clearActiveShell()),e.removeAttribute("data-plantuml-hydrated"),e.removeAttribute("data-plantuml-instance-id"),e.removeAttribute("data-plantuml-queued"),e.classList.remove("is-maximized"),this.syncActiveShell()||document.body.classList.remove("plantuml-maximized-open"),e.querySelector(":scope > .plantuml-toolbar")?.remove(),e.querySelector(":scope > .plantuml-frame")?.remove(),e.querySelector(".plantuml-placeholder-card")||e.querySelector(".plantuml-source")?.after(Pt(e.dataset.plantumlKey||"plantuml",i))}enhanceDiagram(e,t){let i=document.createElement("div");i.innerHTML=t;let n=i.querySelector("svg");if(!n)throw new Error("Renderer returned invalid SVG");let r=document.createElement("div");r.className="plantuml-toolbar diagram-preview-toolbar";let o=document.createElement("div");o.className="plantuml-frame diagram-preview-frame";let a=this.createToolButton("\u2212","Zoom out"),c=this.createToolButton("+","Zoom in"),h=this.createToolButton("Reset","Reset zoom"),l=this.createToolButton("Reload","Reload diagram"),u=this.createToolButton("Max","Maximize diagram");u.classList.add("plantuml-maximize-btn"),A(l,"refresh"),A(u,"maximize");let m=document.createElement("span");m.className="plantuml-zoom-label diagram-preview-zoom-label",m.setAttribute("aria-live","polite"),r.append(a,m,h,c,l,u);let{width:d,height:w}=de(n),f=F.default,y=1,E=null,S=!1,k=null,M=0,D=0,_=0,R=0;n.style.display="block",n.style.margin="0 auto",n.style.maxWidth="none";let $=()=>{let g=Q(o);return!Number.isFinite(d)||d<=0||g.width<=0?F.default:T(Math.min(F.default,g.width/d),F.min,F.max)},H=g=>{f=T(g,F.min,F.max),n.style.width=`${d*f}px`,n.style.height=`${w*f}px`,m.textContent=`${Math.round(f*100)}%`,a.disabled=f<=F.min,c.disabled=f>=F.max;let v=Q(o),C=d*f>v.width||w*f>v.height;o.classList.toggle("is-pannable",C)},q=()=>({x:o.scrollLeft+o.clientWidth/2,y:o.scrollTop+o.clientHeight/2}),j=(g,v,C)=>{if(g===0)return;let P=v/g;o.scrollLeft=C.x*P-o.clientWidth/2,o.scrollTop=C.y*P-o.clientHeight/2},W=g=>{let v=T(g,F.min,F.max),C=f;if(v===C)return;let P=q(),ie=performance.now();E&&cancelAnimationFrame(E);let ae=bt=>{let le=T((bt-ie)/F.animationDurationMs,0,1),Ct=xe(le),ce=C+(v-C)*Ct;if(H(ce),j(C,ce,P),le<1){E=requestAnimationFrame(ae);return}E=null,H(v),j(C,v,P)};E=requestAnimationFrame(ae)},G=g=>{W(f+g)},O=({animate:g=!1}={})=>{if(y=$(),g&&Math.abs(y-f)>.001){W(y);return}E&&(cancelAnimationFrame(E),E=null),H(y),o.scrollLeft=0,o.scrollTop=0},N=null,I=()=>{N&&cancelAnimationFrame(N),N=requestAnimationFrame(()=>{N=null,e.isConnected&&O()})};this.shellRefits.set(e,I),a.addEventListener("click",()=>G(-F.step)),c.addEventListener("click",()=>G(F.step)),h.addEventListener("click",()=>{O({animate:!0})});let B=()=>{let g=e.classList.contains("is-maximized");A(u,g?"restore":"maximize");let v=g?"Restore diagram size":"Maximize diagram";u.setAttribute("aria-label",v),u.title=v},te=g=>{if(g){let v=this.syncActiveShell();if(v&&v!==e){this.restoreShellMount(v),v.classList.remove("is-maximized"),this.activeMaximizedShell===v&&this.clearActiveShell(),this.shellRefits.get(v)?.();let C=v.querySelector(".plantuml-maximize-btn");C&&(A(C,"maximize"),C.setAttribute("aria-label","Maximize diagram"),C.title="Maximize diagram")}this.mountShellInMaximizedRoot(e),e.classList.add("is-maximized"),this.activeMaximizedShell=e,document.body.classList.add("plantuml-maximized-open"),B(),I();return}this.restoreShellMount(e),e.classList.remove("is-maximized"),this.activeMaximizedShell===e&&this.clearActiveShell(),this.syncActiveShell()||document.body.classList.remove("plantuml-maximized-open"),B(),I()};l.addEventListener("click",()=>{this.resetShell(e,{clearCache:!0,message:"Refreshing\u2026"}),this.enqueueShell(e,{prioritize:!0})}),B(),u.addEventListener("click",()=>{te(!e.classList.contains("is-maximized"))});let z=()=>{if(S){if(S=!1,o.classList.remove("is-dragging"),k!==null&&typeof o.releasePointerCapture=="function")try{o.releasePointerCapture(k)}catch{}k=null}};o.addEventListener("pointerdown",g=>{g.button!==0||!o.classList.contains("is-pannable")||(E&&(cancelAnimationFrame(E),E=null),S=!0,k=g.pointerId,M=g.clientX,D=g.clientY,_=o.scrollLeft,R=o.scrollTop,o.classList.add("is-dragging"),o.setPointerCapture?.(g.pointerId),g.preventDefault())}),o.addEventListener("pointermove",g=>{S&&(o.scrollLeft=_-(g.clientX-M),o.scrollTop=R-(g.clientY-D))}),o.addEventListener("pointerup",z),o.addEventListener("pointercancel",z),o.addEventListener("lostpointercapture",z),o.appendChild(n);let U=e.querySelector(".plantuml-source");e.replaceChildren(),U&&(U.hidden=!0,e.appendChild(U)),e.append(r,o),y=$(),H(y)}createToolButton(e,t){let i=document.createElement("button");return i.type="button",i.className="plantuml-tool-btn ui-preview-action",i.setAttribute("aria-label",t),i.title=t,i.textContent=e,i}};function ps(){return new Worker(new URL("./preview-render-worker.js",import.meta.url),{type:"module"})}var Ie=class{constructor({attachmentApiPath:e="/api/attachment",cancelIdleRenderFn:t=ne,compilePreviewDocumentLoader:i=()=>import("./chunks/preview-render-compiler-6Y7TKXFJ.js"),createWorkerFn:n=ps,getFileList:r,getSourceFilePath:o=null,idleTimeoutMs:a=V,requestIdleRenderFn:c=se}={}){this.attachmentApiPath=e,this.cancelIdleRenderFn=t,this.compilePreviewDocumentLoader=i,this.createWorkerFn=n,this.getFileList=r,this.getSourceFilePath=o,this.idleTimeoutMs=a,this.requestIdleRenderFn=c,this.worker=null,this.workerDisabled=!1,this.workerJob=null,this.workerPrewarmId=null,this.handleWorkerMessage=h=>{if(!this.workerJob||h.data?.renderVersion!==this.workerJob.renderVersion)return;let l=this.workerJob;if(this.workerJob=null,h.data?.error){l.reject(new Error(h.data.error));return}l.resolve({html:h.data.html,stats:h.data.stats})},this.handleWorkerError=h=>{let l=new Error(h.message||"Preview worker failed");this.workerJob&&(this.workerJob.reject(l),this.workerJob=null),this.reset("Preview worker failed",{disable:!0})}}hasPendingJob(){return this.workerJob!==null}schedulePrewarm({timeout:e=this.idleTimeoutMs}={}){this.workerDisabled||this.worker||this.workerPrewarmId!==null||(this.workerPrewarmId=this.requestIdleRenderFn(()=>{this.workerPrewarmId=null,this.ensureWorker()},e))}ensureWorker(){if(this.workerDisabled)return null;if(this.worker)return this.worker;try{return this.worker=this.createWorkerFn(),this.worker.addEventListener("message",this.handleWorkerMessage),this.worker.addEventListener("error",this.handleWorkerError),this.worker}catch{return this.workerDisabled=!0,null}}async compile(e,t){if(this.ensureWorker()){this.workerJob&&this.reset("Superseded preview render");let r=this.ensureWorker();return new Promise((o,a)=>{this.workerJob={reject:a,renderVersion:t,resolve:o},r.postMessage({attachmentApiPath:this.attachmentApiPath,fileList:this.getFileList?.()??[],markdownText:e,renderVersion:t,sourceFilePath:this.getSourceFilePath?.()??""})})}let{compilePreviewDocument:n}=await this.compilePreviewDocumentLoader();return n({attachmentApiPath:this.attachmentApiPath,fileList:this.getFileList?.()??[],markdownText:e,sourceFilePath:this.getSourceFilePath?.()??""})}cancelWorkerJob(e){this.workerJob&&(this.workerJob.reject(new Error(e)),this.workerJob=null)}reset(e,{disable:t=!1}={}){this.cancelWorkerJob(e),this.worker&&(this.worker.removeEventListener("message",this.handleWorkerMessage),this.worker.removeEventListener("error",this.handleWorkerError),this.worker.terminate(),this.worker=null),t&&(this.workerDisabled=!0)}destroy(e="Preview renderer destroyed"){this.workerPrewarmId!==null&&this.cancelIdleRenderFn(this.workerPrewarmId),this.workerPrewarmId=null,this.reset(e)}};var Ae=class{constructor({cancelAnimationFrameFn:e=h=>cancelAnimationFrame(h),cancelIdleRenderFn:t=ne,clearTimeoutFn:i=h=>clearTimeout(h),getRenderProfileFn:n=Se,idleTimeoutMs:r=V,requestAnimationFrameFn:o=h=>requestAnimationFrame(h),requestIdleRenderFn:a=se,setTimeoutFn:c=(h,l)=>setTimeout(h,l)}={}){this.cancelAnimationFrameFn=e,this.cancelIdleRenderFn=t,this.clearTimeoutFn=i,this.getRenderProfileFn=n,this.idleTimeoutMs=r,this.requestAnimationFrameFn=o,this.requestIdleRenderFn=a,this.setTimeoutFn=c,this.frameId=null,this.idleId=null,this.timeoutId=null}queue({markdownText:e,onRenderRequested:t,renderVersion:i}){let n=this.getRenderProfileFn(e);this.cancel();let r=()=>{this.frameId=this.requestAnimationFrameFn(()=>{this.frameId=null,this.timeoutId=null,t?.(e,i)})},o=()=>{if(n.deferUntilIdle){this.idleId=this.requestIdleRenderFn(()=>{this.idleId=null,r()},this.idleTimeoutMs);return}r()};this.timeoutId=this.setTimeoutFn(o,n.debounceMs)}cancel(){this.clearTimeoutFn(this.timeoutId),this.frameId&&this.cancelAnimationFrameFn(this.frameId),this.cancelIdleRenderFn(this.idleId),this.frameId=null,this.idleId=null,this.timeoutId=null}destroy(){this.cancel()}};var Be=class{constructor({getContent:e,getFileList:t,getSourceFilePath:i,onAfterRenderCommit:n,onBeforeRenderCommit:r,onRenderComplete:o,outlineController:a,previewContainer:c,previewElement:h}){this.getContent=e,this.getFileList=t,this.getSourceFilePath=i,this.onAfterRenderCommit=n,this.onBeforeRenderCommit=r,this.onRenderComplete=o,this.outlineController=a,this.previewContainer=c,this.previewElement=h,this.renderHost=null,this.pendingRenderVersion=0,this.activeRenderVersion=0,this.readyRenderVersion=0,this.currentStats=null,this.isLargeDocument=!1,this.hydrationPaused=!1,this.handlePreviewClick=l=>{let u=l.target.closest(".mermaid-placeholder-btn");if(u){let d=u.closest(".mermaid-shell");if(!d)return;l.preventDefault(),this.enqueueMermaidShell(d,{prioritize:!0});return}let m=l.target.closest(".plantuml-placeholder-btn");if(m){let d=m.closest(".plantuml-shell");if(!d)return;l.preventDefault(),this.enqueuePlantUmlShell(d,{prioritize:!0})}},this.handleWindowResize=()=>{this.mermaidHydrator.scheduleActiveRefit(),this.plantUmlHydrator.scheduleActiveRefit()},this.mermaidHydrator=new Me(this),this.plantUmlHydrator=new Te(this),this.renderScheduler=new Ae({getRenderProfileFn:Se}),this.renderExecutor=new Ie({attachmentApiPath:b("/attachment"),getFileList:()=>this.getFileList?.()??[],getSourceFilePath:()=>this.getSourceFilePath?.()??"",idleTimeoutMs:V}),this.previewElement?.addEventListener("click",this.handlePreviewClick),window.addEventListener("resize",this.handleWindowResize),this.setPhase("ready")}ensureRenderHost(){if(!this.previewElement)return null;if(this.renderHost?.isConnected&&this.renderHost.parentElement===this.previewElement)return this.renderHost;let e=this.previewElement.querySelector('[data-preview-render-host="true"]');return e||(e=document.createElement("div"),e.dataset.previewRenderHost="true",this.previewElement.appendChild(e)),this.renderHost=e,this.renderHost}normalizePreviewChildren(e=this.renderHost){this.previewElement&&Array.from(this.previewElement.children).forEach(t=>{t===e||t.dataset.excalidrawOverlayRoot==="true"||t.dataset.videoOverlayRoot==="true"||t.remove()})}getReservedPreviewHeight(){let e=this.renderHost?.getBoundingClientRect?.().height??0,t=this.previewContainer?.clientHeight??0;return Math.max(Math.round(e),Math.round(t),320)}beginDocumentLoad(){this.cancelScheduledRender(),this.cancelMermaidHydration(),this.cancelPlantUmlHydration(),this.mermaidHydrator.clearPreservedShells(),this.plantUmlHydrator.clearPreservedShells(),this.clearActivePlantUmlShell(),this.onBeforeRenderCommit?.(this.previewElement),this.pendingRenderVersion+=1,this.activeRenderVersion=this.pendingRenderVersion,this.readyRenderVersion=0,this.currentStats=null,this.isLargeDocument=!1,this.renderExecutor.hasPendingJob()&&this.resetWorker("Document changed");let e=this.ensureRenderHost();this.normalizePreviewChildren(e);let t=this.getReservedPreviewHeight();e&&(e.replaceChildren(),e.style.minHeight=`${t}px`);let i=document.createElement("div");i.className="preview-shell",i.style.minHeight=`${t}px`,i.textContent="Rendering preview\u2026",e?.append(i),this.setPhase("shell")}applyTheme(e){let t=document.getElementById("hljs-theme");if(t){let{darkHref:i,lightHref:n}=t.dataset;t.href=e==="dark"?i:n}this.mermaidHydrator.applyTheme(e)}configureMermaid(e){this.mermaidHydrator.configureMermaid(e)}ensureMermaid(){return this.mermaidHydrator.ensureMermaid()}queueRender(){let e=this.getContent();this.cancelScheduledRender(),this.pendingRenderVersion+=1;let t=this.pendingRenderVersion;this.renderScheduler.queue({markdownText:e,onRenderRequested:(i,n)=>{this.render(i,n)},renderVersion:t})}async render(e=this.getContent(),t=this.pendingRenderVersion){if(this.previewElement)try{let i=await this.compilePreview(e,t);if(t!==this.pendingRenderVersion)return;this.commitBaseRender(i,t)}catch(i){if(t!==this.pendingRenderVersion)return;console.warn("[preview] Failed to render preview:",i)}}destroy(){this.renderScheduler.destroy(),this.mermaidHydrator.destroy(),this.plantUmlHydrator.destroy(),this.renderExecutor.destroy(),this.previewElement?.removeEventListener("click",this.handlePreviewClick),window.removeEventListener("resize",this.handleWindowResize)}setPhase(e){this.previewElement&&(this.previewElement.dataset.renderPhase=e)}cancelScheduledRender(){this.renderScheduler.cancel()}cancelMermaidHydration(){this.mermaidHydrator.cancelHydration()}cancelPlantUmlHydration(){this.plantUmlHydrator.cancelHydration()}clearActivePlantUmlShell(){this.plantUmlHydrator.clearActiveShell()}scheduleActiveMermaidRefit(){this.mermaidHydrator.scheduleActiveRefit()}syncActivePlantUmlShell(){return this.plantUmlHydrator.syncActiveShell()}scheduleActivePlantUmlRefit(){this.plantUmlHydrator.scheduleActiveRefit()}setHydrationPaused(e){if(this.hydrationPaused=!!e,this.hydrationPaused){this.mermaidHydrator.cancelPendingIdleWork(),this.plantUmlHydrator.cancelPendingIdleWork();return}this.mermaidHydrator.hydrateVisibleShells(),this.mermaidHydrator.scheduleHydration(),this.plantUmlHydrator.hydrateVisibleShells(),this.plantUmlHydrator.scheduleHydration(),this.updateHydrationPhase()}resetWorker(e,{disable:t=!1}={}){this.renderExecutor.reset(e,{disable:t})}scheduleWorkerPrewarm({timeout:e=V}={}){this.renderExecutor.schedulePrewarm({timeout:e})}async compilePreview(e,t){return this.renderExecutor.compile(e,t)}commitBaseRender({html:e,stats:t},i){this.activeRenderVersion=i,this.readyRenderVersion=0,this.currentStats=t,this.isLargeDocument=Yt(t),this.cancelMermaidHydration(),this.cancelPlantUmlHydration(),document.body.classList.remove("mermaid-maximized-open"),document.body.classList.remove("plantuml-maximized-open"),this.preserveHydratedMermaidsForCommit(),this.preserveHydratedPlantUmlsForCommit(),this.onBeforeRenderCommit?.(this.previewElement);let n=this.ensureRenderHost();this.normalizePreviewChildren(n),n&&(n.innerHTML=e),this.reconcileHydratedMermaids(),this.reconcileHydratedPlantUmls(),this.setPhase("base"),this.outlineController.refresh(),this.onAfterRenderCommit?.(this.previewElement,{...t,isLargeDocument:this.isLargeDocument,renderVersion:i});let r=this.setupMermaidHydration(i),o=this.setupPlantUmlHydration(i);r===0&&o===0&&this.notifyReady()}preserveHydratedMermaidsForCommit(){this.mermaidHydrator.preserveHydratedShellsForCommit()}preserveHydratedPlantUmlsForCommit(){this.plantUmlHydrator.preserveHydratedShellsForCommit()}reconcileHydratedMermaids(){this.mermaidHydrator.reconcileHydratedShells()}reconcileHydratedPlantUmls(){this.plantUmlHydrator.reconcileHydratedShells()}syncPreservedMermaidShell(e,t){this.mermaidHydrator.syncPreservedShell(e,t)}syncPreservedPlantUmlShell(e,t){this.plantUmlHydrator.syncPreservedShell(e,t)}setupMermaidHydration(e){return this.mermaidHydrator.setupHydration(e)}hydrateVisibleMermaids(){this.mermaidHydrator.hydrateVisibleShells()}enqueueMermaidShell(e,{prioritize:t=!1}={}){this.mermaidHydrator.enqueueShell(e,{prioritize:t})}scheduleMermaidHydration(){this.mermaidHydrator.scheduleHydration()}async flushMermaidHydrationQueue(){await this.mermaidHydrator.flushHydrationQueue()}async hydrateMermaidShell(e,t){await this.mermaidHydrator.hydrateShell(e,t)}resetHydratedMermaids(){this.mermaidHydrator.resetHydratedShells()}setupPlantUmlHydration(e){return this.plantUmlHydrator.setupHydration(e)}hydrateVisiblePlantUmls(){this.plantUmlHydrator.hydrateVisibleShells()}enqueuePlantUmlShell(e,{prioritize:t=!1}={}){this.plantUmlHydrator.enqueueShell(e,{prioritize:t})}schedulePlantUmlHydration(){this.plantUmlHydrator.scheduleHydration()}async flushPlantUmlHydrationQueue(){await this.plantUmlHydrator.flushHydrationQueue()}async hydratePlantUmlShell(e){await this.plantUmlHydrator.hydrateShell(e)}updateHydrationPhase(){if(this.hydrationPaused&&(this.mermaidHydrator.hasPendingWork()||this.plantUmlHydrator.hasPendingWork())){this.setPhase("base");return}if(this.mermaidHydrator.hasPendingWork()||this.plantUmlHydrator.hasPendingWork()){this.setPhase("hydrating");return}this.notifyReady()}notifyReady(){this.renderHost&&(this.renderHost.style.minHeight=""),this.setPhase("ready"),this.readyRenderVersion!==this.activeRenderVersion&&(this.readyRenderVersion=this.activeRenderVersion,this.onRenderComplete?.({isLargeDocument:this.isLargeDocument,stats:this.currentStats}))}async fetchPlantUmlSvg(e){return this.plantUmlHydrator.fetchSvg(e)}async fetchPlantUmlSource(e){return this.plantUmlHydrator.fetchSource(e)}async fetchMermaidSource(e){return this.mermaidHydrator.fetchSource(e)}resetPlantUmlShell(e,{clearCache:t=!1,message:i="Renders server-side when visible"}={}){this.plantUmlHydrator.resetShell(e,{clearCache:t,message:i})}enhancePlantUmlDiagram(e,t){this.plantUmlHydrator.enhanceDiagram(e,t)}enhanceMermaidDiagram(e,t){this.mermaidHydrator.enhanceDiagram(e,t)}createMermaidZoomButton(e,t){return this.mermaidHydrator.createZoomButton(e,t)}createPlantUmlToolButton(e,t){return this.plantUmlHydrator.createToolButton(e,t)}};var Re=class{constructor({backlinksPanel:e,clearInitialFileBootstrap:t,clearStaticPreviewDocument:i=null,closeSidebarOnMobile:n,elements:r,excalidrawEmbed:o,fileHistoryView:a=null,fileExplorer:c,getIsTabActive:h,getSessionLoadToken:l,gitDiffView:u,gitPanel:m,imageLightbox:d=null,lobby:w,navigation:f,previewRenderer:y,renderAvatars:E,renderPresence:S,resetPreviewMode:k,scrollSyncController:M,setSession:D,setSessionLoadToken:_,setSidebarTab:R,setCurrentFilePath:$,showGitCommit:H,showGitDiff:q,showGitFileHistory:j,showGitFilePreview:W,showGitHistory:G,syncMainChrome:O,videoEmbed:N,workspaceCoordinator:I,layoutController:B}){this.backlinksPanel=e,this.clearInitialFileBootstrap=t,this.clearStaticPreviewDocument=i,this.closeSidebarOnMobile=n,this.elements=r,this.excalidrawEmbed=o,this.fileHistoryView=a,this.fileExplorer=c,this.getIsTabActive=h,this.getSessionLoadToken=l,this.gitDiffView=u,this.gitPanel=m,this.imageLightbox=d,this.lobby=w,this.navigation=f,this.previewRenderer=y,this.renderAvatars=E,this.renderPresence=S,this.resetPreviewMode=k,this.scrollSyncController=M,this.setSession=D,this.setSessionLoadToken=_,this.setSidebarTab=R,this.setCurrentFilePath=$,this.showGitCommit=H,this.showGitDiff=q,this.showGitFileHistory=j,this.showGitFilePreview=W,this.showGitHistory=G,this.syncMainChrome=O,this.videoEmbed=N,this.workspaceCoordinator=I,this.layoutController=B}async handleHashChange(){if(!this.getIsTabActive())return;let e=this.navigation.getHashRoute();if(e.type==="empty"){this.gitPanel.setSelection(),this.showEmptyState(),this.syncMainChrome({mode:"empty",title:"CollabMD"});return}if(e.type==="git-diff"){this.setSidebarTab("git"),await this.showGitDiff(e);return}if(e.type==="git-file-history"){this.setSidebarTab("files"),await this.showGitFileHistory(e);return}if(e.type==="git-file-preview"){this.setSidebarTab("files"),await this.showGitFilePreview(e);return}if(e.type==="git-history"){this.setSidebarTab("git"),await this.showGitHistory();return}if(e.type==="git-commit"){this.setSidebarTab("git"),await this.showGitCommit(e);return}this.setSidebarTab("files"),await this.openFile(e.filePath)}showEmptyState(){this.gitDiffView.hide(),this.fileHistoryView?.hide?.(),this.workspaceCoordinator.cleanupSession(),this.clearStaticPreviewDocument?.(),this.setSession(null),this.setSessionLoadToken(this.getSessionLoadToken()+1),this.clearInitialFileBootstrap(),this.resetPreviewMode(),this.elements.outlineToggle?.classList.remove("hidden"),this.elements.markdownToolbar?.classList.add("hidden"),this.setCurrentFilePath(null),this.lobby.setCurrentFile(null),this.fileExplorer.setActiveFile(null),this.elements.emptyState?.classList.remove("hidden"),this.elements.editorPage?.classList.add("hidden"),this.elements.diffPage?.classList.add("hidden"),this.elements.previewContent&&(this.elements.previewContent.innerHTML="",this.elements.previewContent.dataset.renderPhase="ready"),this.videoEmbed?.reconcileEmbeds(this.elements.previewContent),this.resetPreviewSurface(),this.renderAvatars(),this.renderPresence(),this.backlinksPanel.clear(),this.elements.activeFileName&&(this.elements.activeFileName.textContent="CollabMD")}showDiffState(){this.fileHistoryView?.hide?.(),this.setSessionLoadToken(this.getSessionLoadToken()+1),this.clearInitialFileBootstrap(),this.clearStaticPreviewDocument?.(),this.workspaceCoordinator.cleanupSession(),this.setSession(null),this.resetPreviewMode(),this.layoutController.reset(),this.setCurrentFilePath(null),this.lobby.setCurrentFile(null),this.fileExplorer.setActiveFile(null),this.elements.emptyState?.classList.add("hidden"),this.elements.editorPage?.classList.add("hidden"),this.elements.diffPage?.classList.remove("hidden"),this.elements.previewContent&&(this.elements.previewContent.innerHTML="",this.elements.previewContent.dataset.renderPhase="ready"),this.videoEmbed?.reconcileEmbeds(this.elements.previewContent),this.resetPreviewSurface(),this.elements.outlineToggle?.classList.add("hidden"),this.elements.markdownToolbar?.classList.add("hidden"),this.renderAvatars(),this.renderPresence(),this.backlinksPanel.clear()}showFileHistoryState(e){this.gitDiffView.hide(),this.setSessionLoadToken(this.getSessionLoadToken()+1),this.clearInitialFileBootstrap(),this.clearStaticPreviewDocument?.(),this.workspaceCoordinator.cleanupSession(),this.setSession(null),this.resetPreviewMode(),this.layoutController.reset(),this.setCurrentFilePath(e),this.lobby.setCurrentFile(null),this.fileExplorer.setActiveFile(e),this.elements.emptyState?.classList.add("hidden"),this.elements.editorPage?.classList.add("hidden"),this.elements.diffPage?.classList.remove("hidden"),this.elements.previewContent&&(this.elements.previewContent.innerHTML="",this.elements.previewContent.dataset.renderPhase="ready"),this.videoEmbed?.reconcileEmbeds(this.elements.previewContent),this.resetPreviewSurface(),this.elements.outlineToggle?.classList.add("hidden"),this.elements.markdownToolbar?.classList.add("hidden"),this.renderAvatars(),this.renderPresence(),this.backlinksPanel.clear()}showPreviewOnlyState(e){this.gitDiffView.hide(),this.fileHistoryView?.hide?.(),this.setSessionLoadToken(this.getSessionLoadToken()+1),this.clearInitialFileBootstrap(),this.clearStaticPreviewDocument?.(),this.workspaceCoordinator.cleanupSession(),this.setSession(null),this.resetPreviewMode(),this.layoutController.reset(),this.setCurrentFilePath(e),this.lobby.setCurrentFile(null),this.fileExplorer.setActiveFile(e),this.elements.emptyState?.classList.add("hidden"),this.elements.editorPage?.classList.remove("hidden"),this.elements.diffPage?.classList.add("hidden"),this.elements.previewContent&&(this.elements.previewContent.innerHTML="",this.elements.previewContent.dataset.renderPhase="ready"),this.videoEmbed?.reconcileEmbeds(this.elements.previewContent),this.resetPreviewSurface(),this.elements.markdownToolbar?.classList.add("hidden"),this.renderAvatars(),this.renderPresence(),this.backlinksPanel.clear()}async openFile(e){this.imageLightbox?.close?.(),this.gitPanel.setSelection(),this.gitDiffView.hide(),this.fileHistoryView?.hide?.(),this.clearStaticPreviewDocument?.(),this.syncMainChrome({mode:"editor"}),await this.workspaceCoordinator.openFile(e),this.setSession(this.workspaceCoordinator.getSession())}cleanupSession(){this.workspaceCoordinator.cleanupSession(),this.setSession(this.workspaceCoordinator.getSession())}handleFileSelection(e,{closeSidebarOnMobile:t=!1}={}){t&&this.closeSidebarOnMobile(),this.navigation.navigateToFile(e)}resetPreviewSurface(){this.imageLightbox?.close?.(),this.previewRenderer.setHydrationPaused(!1),this.excalidrawEmbed.setHydrationPaused(!1),this.videoEmbed?.detachForCommit(),this.scrollSyncController.setLargeDocumentMode(!1),this.scrollSyncController.invalidatePreviewBlocks()}};function x(s){let e=String(s??"").trim().replace(/\\/g,"/").replace(/^\/+/u,"").split("/").map(t=>t.trim()).filter(Boolean);return e.some(t=>t==="."||t==="..")?"":e.join("/")}function oe(s,e){let t=x(s),i=x(e);return t?i?`${t}/${i}`:t:i}function fi(s,e){return s.toLowerCase().endsWith(e.toLowerCase())?s:`${s}${e}`}function He(s){return`# ${K(String(s??"").split("/").pop()||"")||"Untitled"}
|
|
24
24
|
|
|
25
|
-
`}function
|
|
26
|
-
`),path:t}}function
|
|
27
|
-
`),path:t}}var
|
|
25
|
+
`}function gi(s){let e=x(s),t=ve(e)?e:`${e}.mmd`;return{content:["flowchart TD"," A[Start] --> B{Decide}"," B -->|Yes| C[Ship it]"," B -->|No| D[Revise]",""].join(`
|
|
26
|
+
`),path:t}}function yi(s){let e=x(s),t=be(e)?e:`${e}.puml`;return{content:["@startuml","Alice -> Bob: Hello","@enduml",""].join(`
|
|
27
|
+
`),path:t}}var Ne=class{constructor({getFileList:e,navigation:t,refreshExplorer:i,toastController:n,vaultApiClient:r}){this.getFileList=e,this.navigation=t,this.refreshExplorer=i,this.toastController=n,this.vaultApiClient=r}handleWikiLinkClick(e){let t=qt(e,this.getFileList());if(t){this.navigation.navigateToFile(t);return}let i=this.normalizeNewWikiFilePath(e);if(!i){this.toastController.show("Cannot create an empty wiki-link target");return}this.createAndOpenFile(i,e)}normalizeNewWikiFilePath(e){let t=x(e);return t?t.endsWith(".md")?t:`${t}.md`:null}async createAndOpenFile(e,t){try{await this.vaultApiClient.createFile({content:He(t||e),path:e}),await this.refreshExplorer(),this.navigation.navigateToFile(e)}catch(i){this.toastController.show(`Failed to create file: ${i.message}`)}}};var De=class{constructor({backlinksPanel:e,elements:t,excalidrawEmbed:i,getDisplayName:n,getSession:r,isExcalidrawFile:o,isImageFile:a,isMermaidFile:c,isPlantUmlFile:h,layoutController:l,outlineController:u,previewRenderer:m,schedulePreviewLayoutSync:d,scrollSyncController:w,videoEmbed:f}){this.backlinksPanel=e,this.elements=t,this.excalidrawEmbed=i,this.getDisplayName=n,this.getSession=r,this.isExcalidrawFile=o??(()=>!1),this.isImageFile=a??(()=>!1),this.isMermaidFile=c??(()=>!1),this.isPlantUmlFile=h??(()=>!1),this.layoutController=l,this.outlineController=u,this.previewRenderer=m,this.schedulePreviewLayoutSyncCallback=d,this.scrollSyncController=w,this.videoEmbed=f}createDiagramPreviewDocument(e,t=""){let i=String(t??""),n=Math.max(...i.match(/`+/g)?.map(o=>o.length)??[0]),r="`".repeat(Math.max(3,n+1));return`${r}${e}
|
|
28
28
|
${i}
|
|
29
|
-
${r}`}getPreviewSource(e){let t=this.getSession()?.getText()??"";return this.isMermaidFile(e)?this.createDiagramPreviewDocument("mermaid",t):this.isPlantUmlFile(e)?this.createDiagramPreviewDocument("plantuml",t):t}resetPreviewMode(){this.elements.previewContent?.classList.remove("is-excalidraw-file-preview"),this.elements.previewContent?.classList.remove("is-image-file-preview"),this.elements.previewContent?.classList.remove("is-mermaid-file-preview"),this.elements.previewContent?.classList.remove("is-plantuml-file-preview")}syncFileChrome(e){let t=this.isExcalidrawFile(e),i=this.isImageFile(e),s=Z(e),r=this.isMermaidFile(e),a=this.isPlantUmlFile(e),o=Wt(e);if(this.elements.markdownToolbar?.classList.toggle("hidden",!s),this.elements.outlineToggle?.classList.toggle("hidden",o||i),this.elements.previewContent?.classList.toggle("is-mermaid-file-preview",r),this.elements.previewContent?.classList.toggle("is-plantuml-file-preview",a),t||i){this.layoutController.setView("preview",{persist:!1}),this.outlineController.close(),this.backlinksPanel.clear();return}(r||a)&&(this.outlineController.close(),this.backlinksPanel.clear())}renderExcalidrawFilePreview(e){let t=this.elements.previewContent;if(!t)return;this.videoEmbed?.detachForCommit(),this.excalidrawEmbed.detachForCommit(),this.resetPreviewMode(),t.classList.add("is-excalidraw-file-preview");let i=this.previewRenderer.ensureRenderHost();this.previewRenderer.normalizePreviewChildren(i);let s=document.createElement("div");s.className="excalidraw-embed-placeholder",s.dataset.embedKey=`${e}#file-preview`,s.dataset.embedLabel=this.getDisplayName(e),s.dataset.embedTarget=e;let r=document.createElement("div");r.className="preview-shell",r.textContent="Loading Excalidraw preview\u2026",s.appendChild(r),i&&(i.replaceChildren(s),i.style.minHeight=""),t.dataset.renderPhase="ready",this.outlineController.refresh(),this.scrollSyncController.setLargeDocumentMode(!1),this.scrollSyncController.invalidatePreviewBlocks(),this.videoEmbed?.reconcileEmbeds(t),this.excalidrawEmbed.reconcileEmbeds(t,{isLargeDocument:!1}),this.excalidrawEmbed.hydrateVisibleEmbeds(),this.schedulePreviewLayoutSyncCallback({delayMs:0})}renderImageFilePreview(e){let t=this.elements.previewContent;if(!t)return;this.videoEmbed?.detachForCommit(),this.excalidrawEmbed.detachForCommit(),this.resetPreviewMode(),t.classList.add("is-image-file-preview");let i=this.previewRenderer.ensureRenderHost();this.previewRenderer.normalizePreviewChildren(i);let s=document.createElement("figure");s.className="image-file-preview-shell";let r=document.createElement("img");r.className="image-file-preview-image",r.alt=this.getDisplayName(e),r.src=C(`/attachment?path=${encodeURIComponent(e)}`),s.appendChild(r),i&&(i.replaceChildren(s),i.style.minHeight=""),t.dataset.renderPhase="ready",this.outlineController.refresh(),this.scrollSyncController.setLargeDocumentMode(!1),this.scrollSyncController.invalidatePreviewBlocks(),this.videoEmbed?.reconcileEmbeds(t),this.schedulePreviewLayoutSyncCallback({delayMs:0})}createResizeHandler(e){let t=null;return()=>{clearTimeout(t),t=setTimeout(()=>{e?.(),this.schedulePreviewLayoutSyncCallback({delayMs:0})},100)}}initializePreviewLayoutObserver(e=()=>{}){if(typeof ResizeObserver!="function"||!this.elements.previewContent)return null;let t=new ResizeObserver(()=>{e()});return t.observe(this.elements.previewContent),t}schedulePreviewLayoutSync({hydrationPaused:e,previewLayoutSyncTimer:t,setPendingPreviewLayoutSync:i,setPreviewLayoutSyncTimer:s,delayMs:r=120}){if(e){i(!0);return}clearTimeout(t);let a=setTimeout(()=>{s(null);let o=!!this.getSession(),l=this.elements.previewContent?.classList?.contains?.("is-excalidraw-file-preview")??!1;if(!(!o&&!l||!this.elements.previewContent)&&this.elements.previewContent.dataset.renderPhase!=="shell"){if(e){i(!0);return}this.previewRenderer.scheduleActiveMermaidRefit(),this.previewRenderer.scheduleActivePlantUmlRefit(),this.videoEmbed?.syncLayout(),this.excalidrawEmbed.syncLayout(),!(l&&!o)&&(this.scrollSyncController.invalidatePreviewBlocks(),this.scrollSyncController.warmPreviewBlocks({onReady:()=>{this.getSession()&&(this.scrollSyncController.realignAfterLayoutChange(),this.outlineController.scheduleActiveHeadingUpdate())}}))}},r);s(a)}handleEditorScrollActivityChange({isActive:e,pendingPreviewLayoutSync:t,previewLayoutSyncTimer:i,setHydrationPaused:s,setPendingPreviewLayoutSync:r,setPreviewLayoutSyncTimer:a}){let o=!!e;if(s(o),this.previewRenderer.setHydrationPaused(o),this.excalidrawEmbed.setHydrationPaused(o),o){clearTimeout(i),a(null),r(!0);return}t&&(r(!1),this.schedulePreviewLayoutSync({delayMs:0,hydrationPaused:!1,previewLayoutSyncTimer:null,setPendingPreviewLayoutSync:r,setPreviewLayoutSyncTimer:a}))}};var Ne=class{constructor({attachEditorScroller:e,createEditorSession:t,loadEditorSessionClass:i,scrollContainerForSession:s}){this.attachEditorScroller=e,this.createEditorSession=t,this.loadEditorSessionClass=i,this.scrollContainerForSession=s}async createSession(e){let t=await this.loadEditorSessionClass();return this.createEditorSession(t,e)}attachSessionScroller(e){this.attachEditorScroller(this.scrollContainerForSession(e))}clearSessionScroller(){this.attachEditorScroller(null)}};var De=class{constructor({beginDocumentLoad:e,getDisplayName:t,loadBacklinks:i,onBeforeFileOpen:s,onFileOpenError:r,onFileOpenReady:a,onRenderExcalidrawPreview:o,onRenderImagePreview:l,onSyncWrapToggle:h,onUpdateActiveFile:c,onUpdateCurrentFile:u,onUpdateLobbyCurrentFile:p,onUpdateVisibleChrome:d,onViewModeReset:w,renderPresence:m,showEditorLoading:b,stateStore:E}){this.beginDocumentLoad=e,this.getDisplayName=t,this.loadBacklinks=i,this.onBeforeFileOpen=s,this.onFileOpenError=r,this.onFileOpenReady=a,this.onRenderExcalidrawPreview=o,this.onRenderImagePreview=l,this.onSyncWrapToggle=h,this.onUpdateActiveFile=c,this.onUpdateCurrentFile=u,this.onUpdateLobbyCurrentFile=p,this.onUpdateVisibleChrome=d,this.onViewModeReset=w,this.renderPresence=m,this.showEditorLoading=b,this.stateStore=E}prepareForFileOpen(e,{resetConnectionState:t=!0}={}){return this.onViewModeReset(),this.onBeforeFileOpen(),this.stateStore.set("connectionHelpShown",!1),t&&this.stateStore.set("connectionState",{status:"connecting",unreachable:!1}),this.stateStore.set("currentFilePath",e),this.onUpdateCurrentFile(e),this.onUpdateLobbyCurrentFile(e),this.onUpdateActiveFile(e),this.onUpdateVisibleChrome(e,{displayName:this.getDisplayName(e),isMarkdown:Z(e)}),this.showEditorLoading(),this.beginDocumentLoad(),this.renderPresence(),{supportsBacklinks:ve(e)}}markFileOpenReady(e){this.onFileOpenReady(e)}finalizeFileOpen({filePath:e,isExcalidraw:t=!1,isImage:i=!1,session:s=null,supportsBacklinks:r}){t&&this.onRenderExcalidrawPreview(e),i&&this.onRenderImagePreview(e),this.onSyncWrapToggle(),r&&s&&this.loadBacklinks(e)}handleFileOpenError(){this.onFileOpenError()}};var He=class{constructor({attachEditorScroller:e,beginDocumentLoad:t,cleanupAfterSessionDestroy:i,createEditorSession:s,getDisplayName:r,getFileList:a,getLineWrappingEnabled:o,getLocalUser:l,getStoredUserName:h,getTheme:c,isExcalidrawFile:u,isImageFile:p,isMermaidFile:d,isPlantUmlFile:w,isTabActive:m,loadEditorSessionClass:b,loadBacklinks:E,onBeforeFileOpen:I,onConnectionChange:F,onContentChange:A,onCommentsChange:z,onFileAwarenessChange:U,onFileOpenError:R,onFileOpenReady:B,onImagePaste:N,onSelectionChange:$,onSessionAssigned:G=null,onRenderExcalidrawPreview:V,onRenderImagePreview:Y,onSyncWrapToggle:K,onUpdateActiveFile:D,onUpdateCurrentFile:M,onUpdateLobbyCurrentFile:H,onUpdateVisibleChrome:te,onViewModeReset:O,renderPresence:_,scrollContainerForSession:f,showEditorLoading:y,stateStore:v}){this.attachEditorScroller=e,this.beginDocumentLoad=t,this.cleanupAfterSessionDestroy=i,this.createEditorSession=s,this.getDisplayName=r,this.getFileList=a,this.getLineWrappingEnabled=o,this.getLocalUser=l,this.getStoredUserName=h,this.getTheme=c,this.isExcalidrawFile=u??(()=>!1),this.isImageFile=p??(()=>!1),this.isMermaidFile=d??(()=>!1),this.isPlantUmlFile=w??(()=>!1),this.isTabActive=m,this.loadEditorSessionClassPort=b,this.loadBacklinks=E,this.onBeforeFileOpen=I,this.onConnectionChange=F,this.onContentChange=A,this.onCommentsChange=z,this.onFileAwarenessChange=U,this.onFileOpenError=R,this.onFileOpenReady=B,this.onImagePaste=N,this.onSelectionChange=$,this.onSessionAssigned=G,this.onRenderExcalidrawPreview=V,this.onSyncWrapToggle=K,this.onUpdateActiveFile=D,this.onUpdateCurrentFile=M,this.onUpdateLobbyCurrentFile=H,this.onUpdateVisibleChrome=te,this.renderPresence=_,this.stateStore=v,this.session=null,this.lifecycle=new Ne({attachEditorScroller:e,createEditorSession:s,loadEditorSessionClass:()=>this.loadEditorSessionClassPort(),scrollContainerForSession:f}),this.chromeController=new De({beginDocumentLoad:t,getDisplayName:r,loadBacklinks:E,onBeforeFileOpen:I,onFileOpenError:R,onFileOpenReady:B,onRenderExcalidrawPreview:V,onRenderImagePreview:Y,onSyncWrapToggle:K,onUpdateActiveFile:D,onUpdateCurrentFile:M,onUpdateLobbyCurrentFile:H,onUpdateVisibleChrome:te,onViewModeReset:O,renderPresence:_,showEditorLoading:y,stateStore:v})}getSession(){return this.session}loadEditorSessionClass(){return this.loadEditorSessionClassPort()}waitForNextPaint(){return new Promise(e=>{requestAnimationFrame(()=>{requestAnimationFrame(e)})})}cleanupSession(){this.session?.destroy(),this.session=null,this.lifecycle.clearSessionScroller(),this.cleanupAfterSessionDestroy()}async openFile(e){if(!this.isTabActive())return;let t=this.isExcalidrawFile(e),i=this.isImageFile(e),s=this.isMermaidFile(e),r=this.isPlantUmlFile(e);if(e===this.stateStore.get("currentFilePath")&&(this.session||t||i)){this.onUpdateActiveFile(e),this.onUpdateLobbyCurrentFile(e);return}let a=this.stateStore.nextSessionLoadToken();this.cleanupSession();let o=this.chromeController.prepareForFileOpen(e,{resetConnectionState:!t&&!i});if(t||i){if(this.onSessionAssigned?.(null),a!==this.stateStore.get("sessionLoadToken"))return;this.chromeController.markFileOpenReady(null),this.chromeController.finalizeFileOpen({filePath:e,isExcalidraw:t,isImage:i,session:null,supportsBacklinks:o.supportsBacklinks});return}let l=await this.lifecycle.createSession({filePath:e,getFileList:this.getFileList,lineWrappingEnabled:this.getLineWrappingEnabled(),localUser:this.getLocalUser(),onAwarenessChange:h=>this.onFileAwarenessChange(h),onConnectionChange:h=>this.onConnectionChange(h),onCommentsChange:h=>this.onCommentsChange?.(h),onContentChange:()=>{t||this.onContentChange({isMermaid:s,isPlantUml:r})},onImagePaste:h=>this.onImagePaste?.(h),preferredUserName:this.getStoredUserName(),onSelectionChange:h=>this.onSelectionChange?.(h),theme:this.getTheme()});this.session=l,this.onSessionAssigned?.(l);try{if(await l.initialize(e),a!==this.stateStore.get("sessionLoadToken")){l.destroy();return}if(this.lifecycle.attachSessionScroller(l),l.applyTheme(this.getTheme()),await l.waitForInitialSync(),l.ensureInitialContent?.(),a!==this.stateStore.get("sessionLoadToken")){l.destroy();return}if(this.chromeController.markFileOpenReady(l),l.requestMeasure(),await this.waitForNextPaint(),a!==this.stateStore.get("sessionLoadToken")){l.destroy();return}this.chromeController.finalizeFileOpen({filePath:e,isExcalidraw:t,session:l,supportsBacklinks:o.supportsBacklinks})}catch(h){if(console.error("[app] Failed to initialize editor:",h),l.destroy(),this.lifecycle.clearSessionScroller(),this.session===l&&(this.session=null),a!==this.stateStore.get("sessionLoadToken"))return;this.chromeController.handleFileOpenError()}}};var _e=class{constructor(e={}){this.state={activeSidebarTab:"files",chatInitialSyncComplete:!1,chatIsOpen:!1,chatMessageIds:new Set,chatMessages:[],chatUnreadCount:0,connectionHelpShown:!1,connectionState:{status:"disconnected",unreachable:!1},currentFilePath:null,fileExplorerReady:!1,followedCursorSignature:"",followedUserClientId:null,gitRepoAvailable:!1,globalUsers:[],isTabActive:!1,sessionLoadToken:0,...e}}get(e){return this.state[e]}set(e,t){return this.state[e]=t,t}nextSessionLoadToken(){let e=Number(this.state.sessionLoadToken||0)+1;return this.state.sessionLoadToken=e,e}replaceChatState({initialSyncComplete:e,isOpen:t,messageIds:i,messages:s,unreadCount:r}){this.state.chatMessages=Array.isArray(s)?s:[],this.state.chatMessageIds=i instanceof Set?i:new Set,this.state.chatUnreadCount=Number.isFinite(r)?r:0,this.state.chatIsOpen=!!t,this.state.chatInitialSyncComplete=!!e}};function ci(n=document){return{currentUserName:n.getElementById("currentUserName"),chatContainer:n.getElementById("chatContainer"),chatEmptyState:n.getElementById("chatEmptyState"),chatForm:n.getElementById("chatForm"),chatInput:n.getElementById("chatInput"),chatMessages:n.getElementById("chatMessages"),chatNotificationButton:n.getElementById("chatNotificationBtn"),chatPanel:n.getElementById("chatPanel"),chatStatus:n.getElementById("chatStatus"),chatToastContainer:n.getElementById("chatToastContainer"),chatToggleBadge:n.getElementById("chatToggleBadge"),chatToggleButton:n.getElementById("chatToggleBtn"),gitCommitCancel:n.getElementById("gitCommitCancel"),gitCommitCopy:n.getElementById("gitCommitCopy"),gitCommitDialog:n.getElementById("gitCommitDialog"),gitCommitForm:n.getElementById("gitCommitForm"),gitCommitInput:n.getElementById("gitCommitInput"),gitCommitSubmit:n.getElementById("gitCommitSubmit"),gitCommitTitle:n.getElementById("gitCommitTitle"),gitResetCancel:n.getElementById("gitResetCancel"),gitResetCopy:n.getElementById("gitResetCopy"),gitResetDialog:n.getElementById("gitResetDialog"),gitResetFileName:n.getElementById("gitResetFileName"),gitResetSubmit:n.getElementById("gitResetSubmit"),gitResetTitle:n.getElementById("gitResetTitle"),displayNameCancel:n.getElementById("displayNameCancel"),displayNameCopy:n.getElementById("displayNameCopy"),displayNameDialog:n.getElementById("displayNameDialog"),displayNameForm:n.getElementById("displayNameForm"),displayNameInput:n.getElementById("displayNameInput"),displayNameSubmit:n.getElementById("displayNameSubmit"),displayNameTitle:n.getElementById("displayNameTitle"),editNameButton:n.getElementById("editNameBtn"),editorContainer:n.getElementById("editorContainer"),markdownToolbar:n.getElementById("markdownToolbar"),editorPage:n.getElementById("editor-page"),diffPage:n.getElementById("diff-page"),fileSearch:n.getElementById("fileSearch"),filesSidebarTab:n.getElementById("filesSidebarTab"),gitSearch:n.getElementById("gitSearch"),gitSearchInput:n.getElementById("gitSearchInput"),gitSidebarTab:n.getElementById("gitSidebarTab"),gitOperationStatus:n.getElementById("gitOperationStatus"),lineInfo:n.getElementById("lineInfo"),mobileViewToggle:n.getElementById("mobileViewToggle"),previewContent:n.getElementById("previewContent"),previewContainer:n.getElementById("previewContainer"),shareButton:n.getElementById("shareBtn"),toastContainer:n.getElementById("toastContainer"),toggleWrapButton:n.getElementById("toggleWrapBtn"),userAvatars:n.getElementById("userAvatars"),userCount:n.getElementById("userCount"),wrapToggleLabel:n.getElementById("wrapToggleLabel"),activeFileName:n.getElementById("activeFileName"),sidebarToggle:n.getElementById("sidebarToggle"),sidebarClose:n.getElementById("sidebarClose"),sidebar:n.getElementById("sidebar"),emptyState:n.getElementById("emptyState"),emptyStateNewFileBtn:n.getElementById("emptyStateNewFileBtn"),emptyStateSearchBtn:n.getElementById("emptyStateSearchBtn"),backlinksPanel:n.getElementById("backlinksPanel"),backlinksInlinePanel:n.getElementById("backlinksInlinePanel"),commentSelectionButton:n.getElementById("commentSelectionBtn"),commentsDrawer:n.getElementById("commentsDrawer"),commentsDrawerEmpty:n.getElementById("commentsDrawerEmpty"),commentsDrawerList:n.getElementById("commentsDrawerList"),commentsToggleButton:n.getElementById("commentsToggle"),outlineToggle:n.getElementById("outlineToggle"),tabLockCopy:n.getElementById("tabLockCopy"),tabLockOverlay:n.getElementById("tabLockOverlay"),tabLockTakeoverButton:n.getElementById("tabLockTakeoverBtn"),tabLockTitle:n.getElementById("tabLockTitle"),toolbarCenter:n.getElementById("toolbarCenter"),toolbarDiffBadge:n.getElementById("toolbarDiffBadge"),sidebarTabs:n.getElementById("sidebarTabs")}}var hi={updateChatMessages(n,{initial:e=!1}={}){let t=new Set(this.chatMessageIds),i=this.lobby.getLocalUser()?.peerId??null;if(this.chatMessages=n,this.chatMessageIds=new Set(n.map(r=>r.id)),!this.chatInitialSyncComplete){e&&(this.chatInitialSyncComplete=!0),this.renderChat();return}let s=n.filter(r=>!t.has(r.id)&&r.peerId&&r.peerId!==i);this.chatIsOpen?this.chatUnreadCount=0:s.length>0&&(this.chatUnreadCount+=s.length);for(let r of s)this.maybeNotifyChatMessage(r);this.renderChat()},toggleChatPanel(){if(this.chatIsOpen){this.closeChatPanel();return}this.openChatPanel()},openChatPanel(){this.chatIsOpen=!0,this.chatUnreadCount=0,this.renderChat(),requestAnimationFrame(()=>{this.elements.chatInput?.focus(),this.scrollChatToBottom()})},closeChatPanel(){this.chatIsOpen&&(this.chatIsOpen=!1,this.renderChat())},handleChatSubmit(){if(!this.isTabActive)return;let n=this.elements.chatInput;if(!n)return;if(!this.lobby.sendChatMessage(n.value)){n.focus();return}if(n.value="",!this.chatIsOpen){this.openChatPanel();return}this.renderChat()},renderChat(){this.elements.chatContainer?.classList.toggle("is-open",this.chatIsOpen),this.elements.chatPanel?.classList.toggle("hidden",!this.chatIsOpen),this.syncChatToggleButton(),this.syncChatNotificationButton();let n=this.elements.chatMessages,e=this.elements.chatEmptyState;if(this.elements.chatStatus&&(this.elements.chatStatus.textContent=this.chatInitialSyncComplete?`${this.globalUsers.length} online`:"Syncing..."),!n)return;if(n.replaceChildren(),this.chatMessages.length===0){e?.classList.remove("hidden"),n.classList.add("hidden");return}e?.classList.add("hidden"),n.classList.remove("hidden");let t=document.createDocumentFragment();this.chatMessages.forEach(i=>{t.appendChild(this.createChatMessageElement(i))}),n.appendChild(t),this.chatIsOpen&&this.scrollChatToBottom()},createChatMessageElement(n){let e=document.createElement("article"),t=n.peerId===this.lobby.getLocalUser()?.peerId;e.className="chat-message",e.classList.toggle("is-local",t);let i=document.createElement("div");i.className="chat-message-avatar",i.style.backgroundColor=n.userColor||"var(--color-primary)",i.textContent=(n.userName||"?").charAt(0).toUpperCase(),i.setAttribute("aria-hidden","true");let s=document.createElement("div");s.className="chat-message-body";let r=document.createElement("div");r.className="chat-message-meta";let a=document.createElement("span");a.className="chat-message-author",a.textContent=t?`${n.userName} (you)`:n.userName;let o=document.createElement("span");o.className="chat-message-time",o.textContent=this.formatChatTimestamp(n.createdAt),r.append(a,o);let l=this.getChatMessageFileLabel(n.filePath);if(l){let c=document.createElement("span");c.className="chat-message-file",c.textContent=l,r.append(c)}let h=document.createElement("p");return h.className="chat-message-text",h.textContent=n.text,s.append(r,h),e.append(i,s),e},scrollChatToBottom(){let n=this.elements.chatMessages;n&&requestAnimationFrame(()=>{n.scrollTop=n.scrollHeight})},formatChatTimestamp(n){if(!Number.isFinite(n))return"";try{return this.chatTimeFormatter.format(new Date(n))}catch{return""}},getChatMessageFileLabel(n){return n?this.getDisplayName(n):""},formatChatToastMessage(n){let e=n?.userName||"Someone",t=String(n?.text??"").replace(/\s+/g," ").trim(),i=t.length>88?`${t.slice(0,85).trimEnd()}...`:t;return`${e}: ${i}`},syncChatToggleButton(){let n=this.elements.chatToggleButton,e=this.elements.chatToggleBadge;if(!n)return;let t=this.chatUnreadCount>0,i=t&&!this.chatIsOpen;n.classList.toggle("is-active",this.chatIsOpen),n.classList.toggle("is-unread",i),n.setAttribute("aria-expanded",String(this.chatIsOpen)),n.setAttribute("aria-label",t?`Open team chat, ${this.chatUnreadCount} unread`:"Open team chat"),n.title=this.chatUnreadCount>0?`Team chat (${this.chatUnreadCount} unread)`:"Team chat",e&&(e.classList.toggle("hidden",!t),e.textContent=this.chatUnreadCount>9?"9+":String(this.chatUnreadCount))},syncChatNotificationButton(){let n=this.elements.chatNotificationButton;if(!n)return;let e=this.notifications.getPermission();this.chatNotificationPermission=e;let t="Enable alerts",i="Enable browser notifications for new chat messages",s=!1;e==="unsupported"?(t="No alerts",i="Browser notifications are unavailable here"):e==="denied"?(t="Alerts blocked",i="Browser notifications are blocked for this site"):e==="granted"&&(s=this.chatNotificationsEnabled,t=s?"Alerts on":"Alerts off",i=s?"Disable browser notifications for chat":"Enable browser notifications for chat"),n.textContent=t,n.title=i,n.setAttribute("aria-pressed",String(s)),n.classList.toggle("is-enabled",s),n.classList.toggle("is-blocked",e==="denied")},async handleChatNotificationToggle(){let n=this.notifications.getPermission();if(this.chatNotificationPermission=n,n==="unsupported"){this.toastController.show("Browser notifications are unavailable here"),this.syncChatNotificationButton();return}if(n==="denied"){this.chatNotificationsEnabled=!1,this.preferences.setChatNotificationsEnabled(!1),this.toastController.show("Browser notifications are blocked for this site"),this.syncChatNotificationButton();return}if(n==="default"){let e=await this.notifications.requestPermission();if(this.chatNotificationPermission=e,e!=="granted"){this.chatNotificationsEnabled=!1,this.preferences.setChatNotificationsEnabled(!1),e==="denied"&&this.toastController.show("Browser notifications were blocked"),this.syncChatNotificationButton();return}this.chatNotificationsEnabled=!0,this.preferences.setChatNotificationsEnabled(!0),this.syncChatNotificationButton();return}this.chatNotificationsEnabled=!this.chatNotificationsEnabled,this.preferences.setChatNotificationsEnabled(this.chatNotificationsEnabled),this.syncChatNotificationButton()},maybeNotifyChatMessage(n){if(this.chatInitialSyncComplete){if(document.hidden){this.maybeShowBrowserChatNotification(n);return}!this.isTabActive||this.chatIsOpen||(this.chatToastController??this.toastController).show(this.formatChatToastMessage(n),4e3)}},maybeShowBrowserChatNotification(n){if(!this.chatNotificationsEnabled||this.notifications.getPermission()!=="granted")return;let e=`CollabMD chat \u2022 ${n.userName}`,t=this.getChatMessageFileLabel(n.filePath),i=t?`${t}: ${n.text}`:n.text,s=this.notifications.createNotification({body:i,onClick:()=>{n.filePath&&this.navigation.navigateToFile(n.filePath)},tag:`collabmd-chat-${n.id}`,title:e});s&&setTimeout(()=>{s.close?.()},6e3)}};var di={getCommentFileKind(n=this.currentFilePath){return Ut(n)||"markdown"},syncCommentChrome(n=this.currentFilePath){let e=Gt(n)&&!this.isExcalidrawFile(n);this.commentUi.setCurrentFile(n,{fileKind:this.getCommentFileKind(n),supported:e}),this.handleCommentThreadsChange(this.session?.getCommentThreads?.()??[]),this.handleCommentSelectionChange(this.session?.getCurrentSelectionCommentAnchor?.()??null)},handleCommentSelectionChange(n){this.commentUi.setSelectionAnchor(n)},handleCommentThreadsChange(n=[]){this.commentUi.setThreads(n)},handleCommentEditorContentChange(){this.commentUi.handleEditorContentChange()},refreshCommentUiLayout(){this.commentUi.refreshLayout()}};function Et(n=[]){return Array.from(new Set((n??[]).filter(Boolean)))}function sn(n=[]){return Array.from(new Map((n??[]).filter(e=>e?.oldPath&&e?.newPath&&e.oldPath!==e.newPath).map(e=>[`${e.oldPath}:${e.newPath}`,{newPath:e.newPath,oldPath:e.oldPath}])).values())}function rn(n=[]){return(n??[]).filter(e=>e?.path&&Number.isFinite(e?.from)&&Number.isFinite(e?.to)).map(e=>({from:Math.max(0,Math.round(e.from)),path:e.path,to:Math.max(0,Math.round(e.to))}))}function St({changedPaths:n=[],deletedPaths:e=[],refreshExplorer:t=!0,renamedPaths:i=[]}={}){return{changedPaths:Et(n),deletedPaths:Et(e),refreshExplorer:t!==!1,renamedPaths:sn(i)}}function kt(n){return!n||typeof n!="object"||typeof n.id!="string"?null:{action:typeof n.action=="string"?n.action:"workspace",createdAt:Number.isFinite(n.createdAt)?n.createdAt:Date.now(),highlightRanges:rn(n.highlightRanges),id:n.id,origin:typeof n.origin=="string"?n.origin:"api",reloadRequiredPaths:Et(n.reloadRequiredPaths),requestId:typeof n.requestId=="string"?n.requestId:null,sourceRef:typeof n.sourceRef=="string"?n.sourceRef:null,workspaceChange:St(n.workspaceChange)}}function ui(n={}){return St(n)}function an(){return globalThis.crypto?.randomUUID?globalThis.crypto.randomUUID():`workspace-${Date.now()}-${Math.random().toString(16).slice(2,10)}`}var mi={formatPullBackupToast(n=null){let e=Number(n?.fileCount||0);return e===1?"Pulled latest changes. 1 overlapping local file was backed up.":e>1?`Pulled latest changes. ${e} overlapping local files were backed up.`:"Pulled latest changes. Overlapping local changes were recorded in a pull backup."},setGitOperationStatus(n=""){let e=this.elements.gitOperationStatus;if(!e)return;let t=String(n??"").trim();e.textContent=t,e.classList.toggle("hidden",!t)},async runGitActionWithStatus(n,e){this.setGitOperationStatus(n);try{return await e()}finally{this.setGitOperationStatus("")}},handleGitDiffSelection(n,{closeSidebarOnMobile:e=!1,scope:t="working-tree"}={}){e&&this.closeSidebarOnMobile(),this.navigation.navigateToGitDiff({filePath:n,scope:t})},handleGitRepoChange(n,e=null){this.gitRepoAvailable=!!n,this.elements.sidebarTabs?.classList.toggle("hidden",!this.gitRepoAvailable),this.elements.gitSidebarTab?.classList.toggle("hidden",!this.gitRepoAvailable);let t=n&&e?.summary?.changedFiles>0;if(this.elements.gitSidebarTab?.classList.toggle("has-changes",t),this.gitDiffView.setRepoStatus(this.gitRepoAvailable?e:null),!this.gitRepoAvailable&&this.activeSidebarTab==="git"){this.setSidebarTab("files");return}this.gitRepoAvailable&&this.navigation.getHashRoute().type==="git-diff"&&this.activeSidebarTab!=="git"&&this.setSidebarTab("git")},syncMainChrome({mode:n,title:e=null}={}){let t=n==="diff";this.elements.toolbarCenter?.classList.toggle("hidden",t),this.elements.mobileViewToggle?.classList.toggle("hidden",t),this.elements.userCount?.classList.toggle("hidden",t),this.elements.toolbarDiffBadge?.classList.toggle("hidden",!t),e&&this.elements.activeFileName&&(this.elements.activeFileName.textContent=e)},async showGitDiff({filePath:n=null,scope:e="all"}={}){this.gitPanel.setSelection(n?{path:n,scope:e}:{}),this.showDiffState(),this.syncMainChrome({mode:"diff",title:this.gitDiffView.getToolbarTitle({filePath:n,scope:e})}),await this.gitDiffView.open({filePath:n,scope:e})},async postGitAction(n,e){let t=an();this.pendingWorkspaceRequestIds?.add(t);let i=await fetch(n,{body:JSON.stringify(e),headers:{"Content-Type":"application/json","X-CollabMD-Request-Id":t},method:"POST"}),s=await i.json();if(!i.ok){this.pendingWorkspaceRequestIds?.delete(t);let r=new Error(s.error||"Git action failed");throw typeof s?.code=="string"&&(r.code=s.code),r}return s},async refreshWorkspaceAfterGitAction({filePath:n=null,preferredScope:e=null}={}){await this.fileExplorer.refresh(),await this.refreshGitAfterAction({filePath:n,preferredScope:e})},async refreshGitAfterAction({filePath:n=null,preferredScope:e=null}={}){await this.gitPanel.refresh({force:!0});let t=this.navigation.getHashRoute();if(t.type!=="git-diff")return;let i=n??t.filePath,s=e??t.scope;if(s!==t.scope||i!==t.filePath){this.navigation.navigateToGitDiff({filePath:i,scope:s});return}await this.showGitDiff({filePath:t.filePath,scope:t.scope})},async finalizeGitAction({action:n,filePath:e=null,preferredScope:t=null,result:i={},showLocalFileToast:s=!1}={}){let r=ui(i.workspaceChange);return await this.refreshWorkspaceAfterGitAction({filePath:e,preferredScope:t}),this.handleWorkspaceChangeForCurrentFile(r,{action:n,local:!0,showToast:s}),r},handleWorkspaceChangeForCurrentFile(n,{action:e="git",local:t=!1,showToast:i=!0}={}){let s=this.currentFilePath;if(!s)return!1;let r=n.deletedPaths.includes(s),a=n.renamedPaths.find(l=>l.oldPath===s);if(!r&&!a)return!1;if(!i)return a?this.navigation.navigateToFile(a.newPath):this.navigation.navigateToFile(null),!0;let o=this.getDisplayName(s);return a?(this.navigation.navigateToFile(a.newPath),this.toastController.show(t?`${o} moved to ${this.getDisplayName(a.newPath)}`:`${o} moved on disk`),!0):(this.navigation.navigateToFile(null),this.toastController.show(t?`${o} was removed by ${e}`:`${o} was removed after a ${e} operation`),!0)},async handleIncomingWorkspaceEvent(n){if(!this.isTabActive||!n)return;if(n.requestId&&this.pendingWorkspaceRequestIds?.has(n.requestId)){this.pendingWorkspaceRequestIds.delete(n.requestId);return}let e=ui(n.workspaceChange);if(n.origin==="git"&&await this.refreshGitAfterAction(),this.handleWorkspaceChangeForCurrentFile(e,{action:n.action||n.origin||"workspace",local:!1,showToast:!0}),n.origin==="filesystem"&&this.currentFilePath&&e.changedPaths.includes(this.currentFilePath)){let i=e.changedPaths.length===1&&Array.isArray(n.highlightRanges)?n.highlightRanges.find(r=>r.path===this.currentFilePath):null;i&&this.session?.flashExternalUpdate?.(i)||this.toastController.show(`${this.getDisplayName(this.currentFilePath)} updated from disk`)}this.currentFilePath&&Array.isArray(n.reloadRequiredPaths)&&n.reloadRequiredPaths.includes(this.currentFilePath)&&this.toastController.show(`${this.getDisplayName(this.currentFilePath)} needs a manual reload`)},async stageGitFile(n,{scope:e="working-tree"}={}){n&&await this.runGitActionWithStatus("Staging changes...",async()=>{let t=await this.postGitAction(C("/git/stage"),{path:n});await this.finalizeGitAction({action:"stage",filePath:n,preferredScope:e==="all"?"all":"staged",result:t})})},async unstageGitFile(n,{scope:e="staged"}={}){n&&await this.runGitActionWithStatus("Unstaging changes...",async()=>{let t=await this.postGitAction(C("/git/unstage"),{path:n});await this.finalizeGitAction({action:"unstage",filePath:n,preferredScope:e==="all"?"all":"working-tree",result:t})})},async pushGitBranch(){await this.runGitActionWithStatus("Pushing branch...",async()=>{try{let n=await this.postGitAction(C("/git/push"),{});await this.finalizeGitAction({action:"push",result:n})}catch(n){this.toastController.show(n.message||"Failed to push branch")}})},async pullGitBranch(){await this.runGitActionWithStatus("Pulling branch...",async()=>{try{let n=await this.postGitAction(C("/git/pull"),{});await this.finalizeGitAction({action:"pull",result:n,showLocalFileToast:!0}),n.pullBackup&&this.toastController.show(this.formatPullBackupToast(n.pullBackup),5e3)}catch(n){if(n?.code==="pull_diverged_ff_only"){this.toastController.show("Cannot pull because local and remote commits have diverged. Fast-forward only pull is not possible.",5e3);return}if(n?.code==="pull_conflicted_after_autostash"){this.toastController.show("Pull updated the branch, but reapplying local changes caused conflicts. Review the conflicted files and the pull backup summary.",6e3);return}this.toastController.show(n.message||"Failed to pull branch")}})},openGitResetDialog(n){if(!this.isTabActive||!n)return;let e=this.elements.gitResetDialog;!e||!this.elements.gitResetFileName||(this.pendingGitResetPath=n,this.elements.gitResetTitle&&(this.elements.gitResetTitle.textContent="Reset file to current branch"),this.elements.gitResetCopy&&(this.elements.gitResetCopy.textContent="Restore this file from the current checked-out branch. If this branch does not contain the file, the file will be deleted locally."),this.elements.gitResetFileName.value=n,this.elements.gitResetSubmit&&(this.elements.gitResetSubmit.textContent="Reset File"),this.elements.gitResetSubmit?.toggleAttribute("disabled",!1),!e.open&&(typeof e.showModal=="function"?e.showModal():e.setAttribute("open","true")))},async handleGitResetSubmit(){let n=this.pendingGitResetPath,e=this.elements.gitResetDialog,t=this.elements.gitResetSubmit;if(!(!n||!e)){t?.toggleAttribute("disabled",!0),t&&(t.textContent="Resetting...");try{await this.runGitActionWithStatus("Resetting file...",async()=>{let i=await this.postGitAction(C("/git/reset-file"),{path:n});await this.finalizeGitAction({action:"reset",filePath:n,result:i,showLocalFileToast:!0})}),e.close()}catch(i){this.toastController.show(i.message||"Failed to reset file")}finally{t&&(t.textContent="Reset File"),t?.toggleAttribute("disabled",!1)}}},openGitCommitDialog(){if(!this.isTabActive)return;let n=this.elements.gitCommitDialog,e=this.elements.gitCommitInput;if(!(!n||!e)){if(this.elements.gitCommitTitle&&(this.elements.gitCommitTitle.textContent="Commit staged changes"),this.elements.gitCommitCopy){let t=Number(this.gitPanel.status?.summary?.staged||0);this.elements.gitCommitCopy.textContent=t>0?`${t} staged file${t===1?"":"s"} will be included.`:"All staged changes will be included."}this.elements.gitCommitSubmit&&(this.elements.gitCommitSubmit.textContent="Commit staged changes"),e.value="",!n.open&&(typeof n.showModal=="function"?n.showModal():n.setAttribute("open","true"),requestAnimationFrame(()=>{e.focus(),e.select()}))}},async handleGitCommitSubmit(){let n=this.elements.gitCommitDialog,e=this.elements.gitCommitInput,t=this.elements.gitCommitSubmit,i=String(e?.value??"").trim();if(!(!n||!e)){if(!i){e.focus(),this.toastController.show("Commit message cannot be empty");return}t?.toggleAttribute("disabled",!0),t&&(t.textContent="Committing...");try{await this.runGitActionWithStatus("Committing changes...",async()=>{let s=await this.postGitAction(C("/git/commit"),{message:i});await this.finalizeGitAction({action:"commit",result:s})}),n.close()}catch(s){this.toastController.show(s.message||"Failed to commit staged changes")}finally{t&&(t.textContent="Commit staged changes"),t?.toggleAttribute("disabled",!1)}}}};var pi={updateGlobalUsers(n){this.globalUsers=n,this.syncFollowedUser(),this.renderAvatars(),this.renderChat(),this.renderPresence(),this.syncCurrentUserName()},updateFileAwareness(n){this.syncFollowedUser()},renderPresence(){let n=this.elements.userCount;if(!n)return;let e=!!this.session,t=!!(this.currentFilePath&&this.isExcalidrawFile?.(this.currentFilePath)),i=!!(this.currentFilePath&&this.isImageFile?.(this.currentFilePath)),r=!e&&(!this.currentFilePath||t||i)?this.lobby?.getConnectionState?.()??this.connectionState:this.connectionState;if(r.status==="connected"){n.textContent=`${this.globalUsers.length} online`,n.style.opacity="1";return}if(r.status==="connecting"){n.textContent=r.unreachable?"Unreachable":"Connecting...",n.style.opacity="0.6";return}n.textContent="Offline",n.style.opacity="0.6"},renderAvatars(){let n=this.elements.userAvatars;if(!n)return;n.innerHTML="";let e=[...this.globalUsers],t=e.findIndex(r=>r.isLocal);if(t>0){let[r]=e.splice(t,1);e.unshift(r)}let i=e.findIndex(r=>!r.isLocal&&r.clientId===this.followedUserClientId),s=e[0]?.isLocal?1:0;if(i>s){let[r]=e.splice(i,1);e.splice(s,0,r)}if(e.slice(0,5).forEach(r=>{let a=document.createElement(r.isLocal?"div":"button");a.className="user-avatar",a.classList.toggle("is-local",r.isLocal),a.style.backgroundColor=r.color,a.classList.toggle("is-following",r.clientId===this.followedUserClientId);let o=document.createElement("span");o.className="user-avatar-initial",o.textContent=r.name.charAt(0).toUpperCase(),a.appendChild(o);let l=r.currentFile&&r.currentFile===this.currentFilePath,h=r.currentFile?this.getDisplayName(r.currentFile):"No file";if(r.isLocal){let c=document.createElement("span");c.className="user-avatar-self-label",c.textContent="You",a.appendChild(c),a.title=`${r.name} (you) \u2014 ${h}`,a.setAttribute("role","img"),a.setAttribute("aria-label",`${r.name} (you) \u2014 ${h}`)}else{a.type="button",a.classList.add("user-avatar-button"),l||a.classList.add("different-file");let c=r.clientId===this.followedUserClientId?`Stop following ${r.name}`:l?`Follow ${r.name}`:`Follow ${r.name} \u2014 ${h}`;a.title=c,a.setAttribute("aria-label",c),a.addEventListener("click",()=>this.toggleFollowUser(r.clientId))}n.appendChild(a)}),e.length>5){let r=document.createElement("div");r.className="user-avatar",r.style.backgroundColor="var(--color-surface-dynamic)",r.style.color="var(--color-text-muted)";let a=document.createElement("span");a.className="user-avatar-initial",a.textContent=`+${e.length-5}`,r.appendChild(a),n.appendChild(r)}},toggleFollowUser(n){if(!n)return;if(this.followedUserClientId===n){this.stopFollowingUser();return}let e=this.globalUsers.find(t=>t.clientId===n&&!t.isLocal);if(e){if(this.followedUserClientId=n,this.followedCursorSignature="",this.renderAvatars(),e.currentFile&&e.currentFile!==this.currentFilePath){this.navigation.navigateToFile(e.currentFile);return}requestAnimationFrame(()=>{this.followedUserClientId===n&&this.followUserCursor(e,{force:!0})})}},stopFollowingUser(){this.followedUserClientId&&(this.currentFilePath&&this.isExcalidrawFile?.(this.currentFilePath)&&this.excalidrawEmbed?.setFollowedUser(this.currentFilePath,null),this.followedUserClientId=null,this.followedCursorSignature="",this.renderAvatars())},syncFollowedUser(){if(!this.followedUserClientId)return;let n=this.globalUsers.find(e=>e.clientId===this.followedUserClientId);if(!n||n.isLocal){this.stopFollowingUser();return}if(n.currentFile&&n.currentFile!==this.currentFilePath){this.navigation.navigateToFile(n.currentFile);return}this.followUserCursor(n)},followUserCursor(n,{force:e=!1}={}){if(this.currentFilePath&&this.isExcalidrawFile?.(this.currentFilePath)){this.followExcalidrawUser(n,{force:e});return}let t=this.resolveFileClientId(n.peerId),i=t!=null?this.session?.getUserViewport(t):null,s=t!=null?this.session?.getUserCursor(t):null,r=s?.cursorHead??null,a=s?.cursorLine??null,o=s?.cursorAnchor??null,l=i?.topLine??null,h=i?.viewportRatio??.35;if(!n||l==null&&(r==null||a==null)){this.followedCursorSignature="";return}let c=`${n.clientId}:${l??"no-viewport"}:${o??"no-anchor"}:${r??"no-head"}`;if(!e&&c===this.followedCursorSignature)return;(t!=null&&this.session?.scrollToUserViewport(t)||t!=null&&this.session?.scrollToUserCursor(t,"center")||r!=null&&this.session?.scrollToPosition(r,"center")||a!=null&&this.session?.scrollToLine(a,h))&&(this.followedCursorSignature=c)},followExcalidrawUser(n,{force:e=!1}={}){if(!n?.peerId||!this.currentFilePath){this.followedCursorSignature="";return}let t=`excalidraw:${this.currentFilePath}:${n.peerId}`;!e&&t===this.followedCursorSignature||Promise.resolve(this.excalidrawEmbed?.setFollowedUser(this.currentFilePath,n.peerId)).then(i=>{i===!1||this.followedUserClientId!==n.clientId||(this.followedCursorSignature=t)}).catch(()=>{})},resolveFileClientId(n){if(!n||!this.session?.awareness)return null;for(let[e,t]of this.session.awareness.getStates())if(t.user?.peerId===n)return e;return null}};var ln="image/png,image/jpeg,image/webp,image/gif,image/svg+xml",fi={initialize(){this.themeController.initialize(),this.previewRenderer.applyTheme(this.themeController.getTheme()),this.previewRenderer.scheduleWorkerPrewarm(),this.scheduleEditorSessionPrewarm?.(),this.outlineController.initialize(),this.layoutController.initialize(),this.scrollSyncController.initialize(),this.fileExplorer.initialize(),this.gitPanel.initialize(),this.gitDiffView.initialize(),this.initializePreviewLayoutObserver(),this.syncCurrentUserName(),this.syncWrapToggle(),this.syncChatNotificationButton(),this.renderChat(),this.gitPanel.refresh({force:!0}),this.elements.chatInput?.setAttribute("maxlength",String(this.lobbyChatMessageMaxLength)),this.bindEvents(),this.restoreSidebarState(),this.tabActivityLock.initialize(),this.tabActivityLock.tryActivate(),window.addEventListener("hashchange",()=>this.handleHashChange()),window.addEventListener("resize",this.createResizeHandler()),this.fileExplorerReadyPromise=this.fileExplorer.refresh().then(()=>{if(this.fileExplorerReady=!0,this.isTabActive)return this.handleHashChange()})},bindEvents(){this.elements.emptyStateNewFileBtn?.addEventListener("click",()=>{this.fileExplorer.actionController.handleNewFile()}),this.elements.emptyStateSearchBtn?.addEventListener("click",()=>{this.toggleQuickSwitcher()}),this.elements.chatToggleButton?.addEventListener("click",()=>{this.toggleChatPanel()}),this.elements.chatForm?.addEventListener("submit",n=>{n.preventDefault(),this.handleChatSubmit()}),this.elements.chatNotificationButton?.addEventListener("click",()=>{this.handleChatNotificationToggle()}),this.elements.shareButton?.addEventListener("click",()=>{this.copyCurrentLink()}),this.elements.editNameButton?.addEventListener("click",()=>{this.openDisplayNameDialog()}),this.elements.displayNameCancel?.addEventListener("click",()=>{this.elements.displayNameDialog?.close()}),this.elements.gitCommitCancel?.addEventListener("click",()=>{this.elements.gitCommitDialog?.close()}),this.elements.gitResetCancel?.addEventListener("click",()=>{this.elements.gitResetDialog?.close()}),this.elements.gitResetSubmit?.addEventListener("click",()=>{this.handleGitResetSubmit()}),this.elements.gitCommitDialog?.addEventListener("close",()=>{this.elements.gitCommitInput&&(this.elements.gitCommitInput.value=""),this.elements.gitCommitSubmit&&(this.elements.gitCommitSubmit.textContent="Commit staged changes")}),this.elements.gitResetDialog?.addEventListener("close",()=>{this.pendingGitResetPath=null,this.elements.gitResetFileName&&(this.elements.gitResetFileName.value=""),this.elements.gitResetSubmit&&(this.elements.gitResetSubmit.textContent="Reset File")}),this.elements.markdownToolbar?.addEventListener("click",n=>{let t=(n.target instanceof Element?n.target.closest("[data-markdown-action]"):null)?.getAttribute("data-markdown-action");t&&this.applyMarkdownToolbarAction(t)}),this.elements.displayNameForm?.addEventListener("submit",n=>{n.preventDefault(),this.handleDisplayNameSubmit()}),this.elements.gitCommitForm?.addEventListener("submit",n=>{n.preventDefault(),this.handleGitCommitSubmit()}),this.elements.tabLockTakeoverButton?.addEventListener("click",()=>{this.handleTabTakeover()}),this.elements.toggleWrapButton?.addEventListener("click",()=>{this.toggleLineWrapping()}),this.elements.previewContent?.addEventListener("click",n=>{let e=n.target.closest("a.wiki-link[data-wiki-target]");e&&(n.preventDefault(),this.handleWikiLinkClick(e.dataset.wikiTarget))}),this.elements.sidebarToggle?.addEventListener("click",()=>{this.toggleSidebar()}),this.elements.sidebarClose?.addEventListener("click",()=>{this.closeSidebarOnMobile()}),this.elements.filesSidebarTab?.addEventListener("click",()=>{this.setSidebarTab("files")}),this.elements.gitSidebarTab?.addEventListener("click",()=>{this.gitRepoAvailable&&this.setSidebarTab("git")}),document.addEventListener("pointerdown",n=>{this.chatIsOpen&&(this.elements.chatContainer?.contains(n.target)||this.closeChatPanel())}),document.addEventListener("keydown",n=>{if(n.key==="Escape"&&this.chatIsOpen){this.closeChatPanel();return}(n.metaKey||n.ctrlKey)&&n.key==="k"&&(n.preventDefault(),this.toggleQuickSwitcher())})},isMobileViewport(){return this.mobileBreakpointQuery.matches},closeSidebarOnMobile(){let n=this.elements.sidebar;!n||!this.isMobileViewport()||n.classList.contains("collapsed")||this.setSidebarVisibility(!1)},toggleSidebar(){let n=this.elements.sidebar;if(!n)return;let e=n.classList.contains("collapsed");this.setSidebarVisibility(e)},restoreSidebarState(){if(!this.elements.sidebar)return;let e=this.isMobileViewport(),t=this.preferences.getSidebarVisible(),i=!0;t==="true"?i=!0:(t==="false"||e)&&(i=!1),this.applySidebarVisibility(i)},setSidebarVisibility(n){this.applySidebarVisibility(n),this.preferences.setSidebarVisible(n)},applySidebarVisibility(n){let e=this.elements.sidebar;if(!e)return;let t=!n,i=t&&this.isMobileViewport();e.classList.toggle("collapsed",t),e.toggleAttribute("hidden",i),e.setAttribute("aria-hidden",i?"true":"false"),e.inert=t},setSidebarTab(n){let e=n==="git"&&this.gitRepoAvailable?"git":"files";this.activeSidebarTab=e,this.elements.filesSidebarTab?.classList.toggle("active",e==="files"),this.elements.gitSidebarTab?.classList.toggle("active",e==="git"),document.getElementById("fileTree")?.classList.toggle("hidden",e!=="files"),this.elements.fileSearch?.classList.toggle("hidden",e!=="files"),this.elements.gitSearch?.classList.toggle("hidden",e!=="git"),document.getElementById("gitPanel")?.classList.toggle("active",e==="git"),document.getElementById("gitPanel")?.classList.toggle("hidden",e!=="git"),this.gitPanel.setActive(e==="git")},applyMarkdownToolbarAction(n){if(!this.session||!Z(this.currentFilePath))return;if(n==="image"){this.handleToolbarImageInsert();return}this.session.applyMarkdownToolbarAction(n)||this.toastController.show("Formatting action is unavailable")},async handleToolbarImageInsert(){let n=await this.pickImageFile();n&&await this.handleEditorImageInsert(n)},pickImageFile(){return new Promise(n=>{let e=document.createElement("input");e.type="file",e.accept=ln,e.style.position="fixed",e.style.left="-9999px",document.body.appendChild(e);let t=!1,i=null,s=a=>{t||(t=!0,i&&window.clearTimeout(i),window.removeEventListener("focus",r),e.remove(),n(a))},r=()=>{i=window.setTimeout(()=>{t||e.files?.length||s(null)},250)};e.addEventListener("change",()=>{s(e.files?.[0]??null)},{once:!0}),e.addEventListener("cancel",()=>{s(null)},{once:!0}),window.addEventListener("focus",r,{once:!0}),e.click()})},async handleEditorImageInsert(n){if(!this.session||!Z(this.currentFilePath))return console.warn("[ui] Ignoring image insert because there is no active markdown session.",{currentFilePath:this.currentFilePath,hasSession:!!this.session}),!1;let e=this.currentFilePath,t=this.session;try{console.debug("[ui] Uploading image attachment.",{fileName:n?.name||"",size:n?.size??null,sourcePath:e,type:n?.type||""});let i=await this.vaultApiClient.uploadImageAttachment({file:n,fileName:n?.name||"",sourcePath:e});return await this.fileExplorer.refresh(),this.currentFilePath===e&&this.session&&this.session===t&&typeof i?.markdown=="string"&&(console.debug("[ui] Inserting uploaded image markdown into the editor.",{sourcePath:e,storedPath:i.path??""}),this.session.insertText(i.markdown)),!0}catch(i){return console.error("[ui] Failed to insert image attachment:",i),this.toastController.show(i.message||"Failed to upload image"),!1}},handleThemeChange(n){this.previewRenderer.applyTheme(n),!this.isExcalidrawFile(this.currentFilePath)&&!this.isImageFile?.(this.currentFilePath)&&this.previewRenderer.queueRender(),this.session?.applyTheme(n),this.excalidrawEmbed.updateTheme(n)},handleConnectionChange(n){this.connectionState=n,this.renderPresence(),n.unreachable&&!this.connectionHelpShown&&(this.connectionHelpShown=!0,this.toastController.show(`Cannot reach server at ${n.wsBaseUrl}`,6e3))},openDisplayNameDialog({mode:n="edit"}={}){if(!this.isTabActive)return;let e=this.elements.displayNameDialog,t=this.elements.displayNameInput,i=this.elements.displayNameTitle,s=this.elements.displayNameCopy,r=this.elements.displayNameCancel,a=this.elements.displayNameSubmit;if(!e||!t)return;let o=n==="onboarding";i&&(i.textContent=o?"Choose your display name":"Update display name"),s&&(s.textContent=o?"Pick a name collaborators will see. You can skip for now and continue as a guest.":"Your name will be visible to everyone editing this vault."),r&&(r.textContent=o?"Skip for now":"Cancel"),a&&(a.textContent=o?"Continue":"Save name"),t.value=o?"":this.getCurrentUserName(),!e.open&&(typeof e.showModal=="function"?e.showModal():e.setAttribute("open","true"),requestAnimationFrame(()=>{t.focus(),t.select()}))},promptForDisplayNameIfNeeded(){!this.isTabActive||this._hasPromptedForDisplayName||this.getStoredUserName()||(this._hasPromptedForDisplayName=!0,requestAnimationFrame(()=>{this.openDisplayNameDialog({mode:"onboarding"})}))},handleDisplayNameSubmit(){let n=this.elements.displayNameInput,e=this.elements.displayNameDialog;if(!n||!e)return;let t=this.session?this.session.setUserName(n.value):Kt(n.value);if(!t){n.focus(),this.toastController.show(`Name must be 1-${24} characters`);return}this.preferences.setUserName(t),this.lobby.setUserName(t),this.excalidrawEmbed.updateLocalUser(this.lobby.getLocalUser()),this.syncCurrentUserName(),this.renderChat(),e.close()},async copyCurrentLink(){try{await navigator.clipboard.writeText(window.location.href),this.toastController.show("Link copied")}catch{this.toastController.show("Failed to copy link")}},getCurrentUser(){return this.globalUsers.find(n=>n.isLocal)??this.session?.getLocalUser()??this.lobby?.getLocalUser()??null},getCurrentUserName(){return this.getCurrentUser()?.name??this.getStoredUserName()??""},getStoredUserName(){return this.preferences.getUserName()},syncCurrentUserName(){let n=this.elements.currentUserName;if(!n)return;let e=this.getCurrentUserName();n.textContent=e||"Set name",n.classList.toggle("has-name",!!e),this.elements.editNameButton?.setAttribute("aria-label",`${e||"Set name"}. Change display name`)},toggleLineWrapping(){let e=!(this.session?.isLineWrappingEnabled()??this.getStoredLineWrapping());this.session?.setLineWrapping(e),this.preferences.setLineWrappingEnabled(e),this.syncWrapToggle(e),this.session?.requestMeasure(),this.scrollSyncController.syncPreviewToEditor()},getStoredLineWrapping(){return this.preferences.getLineWrappingEnabled()},handleTabTakeover(){this.tabActivityLock.tryActivate({takeover:!0})},handleTabActivated({takeover:n=!1}={}){let e=!this.isTabActive;this.isTabActive=!0,this.hideTabLockOverlay(),this.lobby.provider||this.lobby.connect(),this.workspaceSync.provider||this.workspaceSync.connect(),e&&(this.fileExplorerReady&&this.handleHashChange(),this.promptForDisplayNameIfNeeded()),n&&this.toastController.show("This tab is now active")},handleTabBlocked({reason:n}={}){let e=this.isTabActive;this.isTabActive=!1,this.elements.displayNameDialog?.open&&this.elements.displayNameDialog.close(),this.lobby.disconnect(),this.workspaceSync.disconnect(),this.globalUsers=[],this.chatMessages=[],this.chatMessageIds.clear(),this.chatUnreadCount=0,this.chatInitialSyncComplete=!1,this.followedUserClientId=null,this.followedCursorSignature="",this.connectionState={status:"disconnected",unreachable:!1},this.showEmptyState(),this.renderChat(),this.showTabLockOverlay({reason:n}),e&&n==="taken-over"&&this.toastController.show("Another tab took over this session")},showTabLockOverlay({reason:n}={}){let e=this.elements.tabLockOverlay,t=this.elements.tabLockTitle,i=this.elements.tabLockCopy;e&&(t&&(t.textContent=n==="taken-over"?"This tab is no longer active":"This vault is active in another tab"),i&&(i.textContent=n==="taken-over"?"Another tab took over the live session. This tab is now disconnected until you explicitly take over here again.":"To avoid duplicate presence and chat, only one tab can stay connected at a time. Use the other tab, or take over the session here."),e.classList.remove("hidden"))},hideTabLockOverlay(){this.elements.tabLockOverlay?.classList.add("hidden")},syncWrapToggle(n){let e=n??this.session?.isLineWrappingEnabled()??this.getStoredLineWrapping(),t=this.elements.wrapToggleLabel,i=this.elements.toggleWrapButton,s=e?"Wrap on":"Wrap off";t&&(t.textContent=s),i&&i.setAttribute("aria-label",`${s}. ${e?"Disable line wrap":"Enable line wrap"}`)},scheduleBacklinkRefresh(){clearTimeout(this._backlinkRefreshTimer),this._backlinkRefreshTimer=setTimeout(()=>{ve(this.currentFilePath)&&this.backlinksPanel.load(this.currentFilePath)},2e3)},showEditorLoading(){this.elements.editorContainer&&(this.elements.editorContainer.classList.add("is-loading-editor"),this.elements.editorContainer.innerHTML=`
|
|
29
|
+
${r}`}getPreviewSource(e){let t=this.getSession()?.getText()??"";return this.isMermaidFile(e)?this.createDiagramPreviewDocument("mermaid",t):this.isPlantUmlFile(e)?this.createDiagramPreviewDocument("plantuml",t):t}resetPreviewMode(){this.elements.previewContent?.classList.remove("is-excalidraw-file-preview"),this.elements.previewContent?.classList.remove("is-image-file-preview"),this.elements.previewContent?.classList.remove("is-mermaid-file-preview"),this.elements.previewContent?.classList.remove("is-plantuml-file-preview")}syncFileChrome(e){let t=this.isExcalidrawFile(e),i=this.isImageFile(e),n=Y(e),r=this.isMermaidFile(e),o=this.isPlantUmlFile(e),a=Qt(e);if(this.elements.markdownToolbar?.classList.toggle("hidden",!n),this.elements.outlineToggle?.classList.toggle("hidden",a||i),this.elements.previewContent?.classList.toggle("is-mermaid-file-preview",r),this.elements.previewContent?.classList.toggle("is-plantuml-file-preview",o),t||i){this.layoutController.setView("preview",{persist:!1}),this.outlineController.close(),this.backlinksPanel.clear();return}(r||o)&&(this.outlineController.close(),this.backlinksPanel.clear())}renderExcalidrawFilePreview(e){let t=this.elements.previewContent;if(!t)return;this.videoEmbed?.detachForCommit(),this.excalidrawEmbed.detachForCommit(),this.resetPreviewMode(),t.classList.add("is-excalidraw-file-preview");let i=this.previewRenderer.ensureRenderHost();this.previewRenderer.normalizePreviewChildren(i);let n=document.createElement("div");n.className="excalidraw-embed-placeholder",n.dataset.embedKey=`${e}#file-preview`,n.dataset.embedLabel=this.getDisplayName(e),n.dataset.embedTarget=e;let r=document.createElement("div");r.className="preview-shell",r.textContent="Loading Excalidraw preview\u2026",n.appendChild(r),i&&(i.replaceChildren(n),i.style.minHeight=""),t.dataset.renderPhase="ready",this.outlineController.refresh(),this.scrollSyncController.setLargeDocumentMode(!1),this.scrollSyncController.invalidatePreviewBlocks(),this.videoEmbed?.reconcileEmbeds(t),this.excalidrawEmbed.reconcileEmbeds(t,{isLargeDocument:!1}),this.excalidrawEmbed.hydrateVisibleEmbeds(),this.schedulePreviewLayoutSyncCallback({delayMs:0})}renderImageFilePreview(e){let t=this.elements.previewContent;if(!t)return;this.videoEmbed?.detachForCommit(),this.excalidrawEmbed.detachForCommit(),this.resetPreviewMode(),t.classList.add("is-image-file-preview");let i=this.previewRenderer.ensureRenderHost();this.previewRenderer.normalizePreviewChildren(i);let n=document.createElement("figure");n.className="image-file-preview-shell";let r=document.createElement("img");r.className="image-file-preview-image",r.alt=this.getDisplayName(e),r.src=b(`/attachment?path=${encodeURIComponent(e)}`),n.appendChild(r),i&&(i.replaceChildren(n),i.style.minHeight=""),t.dataset.renderPhase="ready",this.outlineController.refresh(),this.scrollSyncController.setLargeDocumentMode(!1),this.scrollSyncController.invalidatePreviewBlocks(),this.videoEmbed?.reconcileEmbeds(t),this.schedulePreviewLayoutSyncCallback({delayMs:0})}renderTextFilePreview({content:e=""}={}){let t=this.elements.previewContent;if(!t)return;this.videoEmbed?.detachForCommit(),this.excalidrawEmbed.detachForCommit(),this.resetPreviewMode();let i=this.previewRenderer.ensureRenderHost();this.previewRenderer.normalizePreviewChildren(i);let n=document.createElement("div");n.className="preview-shell";let r=document.createElement("pre"),o=document.createElement("code");o.textContent=String(e??""),r.appendChild(o),n.appendChild(r),i&&(i.replaceChildren(n),i.style.minHeight=""),t.dataset.renderPhase="ready",this.outlineController.close(),this.backlinksPanel.clear(),this.scrollSyncController.setLargeDocumentMode(!1),this.scrollSyncController.invalidatePreviewBlocks(),this.videoEmbed?.reconcileEmbeds(t),this.schedulePreviewLayoutSyncCallback({delayMs:0})}createResizeHandler(e){let t=null;return()=>{clearTimeout(t),t=setTimeout(()=>{e?.(),this.schedulePreviewLayoutSyncCallback({delayMs:0})},100)}}initializePreviewLayoutObserver(e=()=>{}){if(typeof ResizeObserver!="function"||!this.elements.previewContent)return null;let t=new ResizeObserver(()=>{e()});return t.observe(this.elements.previewContent),t}schedulePreviewLayoutSync({hydrationPaused:e,previewLayoutSyncTimer:t,setPendingPreviewLayoutSync:i,setPreviewLayoutSyncTimer:n,delayMs:r=120}){if(e){i(!0);return}clearTimeout(t);let o=setTimeout(()=>{n(null);let a=!!this.getSession(),c=this.elements.previewContent?.classList?.contains?.("is-excalidraw-file-preview")??!1;if(!(!a&&!c||!this.elements.previewContent)&&this.elements.previewContent.dataset.renderPhase!=="shell"){if(e){i(!0);return}this.previewRenderer.scheduleActiveMermaidRefit(),this.previewRenderer.scheduleActivePlantUmlRefit(),this.videoEmbed?.syncLayout(),this.excalidrawEmbed.syncLayout(),!(c&&!a)&&(this.scrollSyncController.invalidatePreviewBlocks(),this.scrollSyncController.warmPreviewBlocks({onReady:()=>{this.getSession()&&(this.scrollSyncController.realignAfterLayoutChange(),this.outlineController.scheduleActiveHeadingUpdate())}}))}},r);n(o)}handleEditorScrollActivityChange({isActive:e,pendingPreviewLayoutSync:t,previewLayoutSyncTimer:i,setHydrationPaused:n,setPendingPreviewLayoutSync:r,setPreviewLayoutSyncTimer:o}){let a=!!e;if(n(a),this.previewRenderer.setHydrationPaused(a),this.excalidrawEmbed.setHydrationPaused(a),a){clearTimeout(i),o(null),r(!0);return}t&&(r(!1),this.schedulePreviewLayoutSync({delayMs:0,hydrationPaused:!1,previewLayoutSyncTimer:null,setPendingPreviewLayoutSync:r,setPreviewLayoutSyncTimer:o}))}};var _e=class{constructor({attachEditorScroller:e,createEditorSession:t,loadEditorSessionClass:i,scrollContainerForSession:n}){this.attachEditorScroller=e,this.createEditorSession=t,this.loadEditorSessionClass=i,this.scrollContainerForSession=n}async createSession(e){let t=await this.loadEditorSessionClass();return this.createEditorSession(t,e)}attachSessionScroller(e){this.attachEditorScroller(this.scrollContainerForSession(e))}clearSessionScroller(){this.attachEditorScroller(null)}};var $e=class{constructor({beginDocumentLoad:e,getDisplayName:t,loadBacklinks:i,onBeforeFileOpen:n,onFileOpenError:r,onFileOpenReady:o,onRenderExcalidrawPreview:a,onRenderImagePreview:c,onSyncWrapToggle:h,onUpdateActiveFile:l,onUpdateCurrentFile:u,onUpdateLobbyCurrentFile:m,onUpdateVisibleChrome:d,onViewModeReset:w,renderPresence:f,showEditorLoading:y,stateStore:E}){this.beginDocumentLoad=e,this.getDisplayName=t,this.loadBacklinks=i,this.onBeforeFileOpen=n,this.onFileOpenError=r,this.onFileOpenReady=o,this.onRenderExcalidrawPreview=a,this.onRenderImagePreview=c,this.onSyncWrapToggle=h,this.onUpdateActiveFile=l,this.onUpdateCurrentFile=u,this.onUpdateLobbyCurrentFile=m,this.onUpdateVisibleChrome=d,this.onViewModeReset=w,this.renderPresence=f,this.showEditorLoading=y,this.stateStore=E}prepareForFileOpen(e,{resetConnectionState:t=!0}={}){return this.onViewModeReset(),this.onBeforeFileOpen(),this.stateStore.set("connectionHelpShown",!1),t&&this.stateStore.set("connectionState",{status:"connecting",unreachable:!1}),this.stateStore.set("currentFilePath",e),this.onUpdateCurrentFile(e),this.onUpdateLobbyCurrentFile(e),this.onUpdateActiveFile(e),this.onUpdateVisibleChrome(e,{displayName:this.getDisplayName(e),isMarkdown:Y(e)}),this.showEditorLoading(),this.beginDocumentLoad(),this.renderPresence(),{supportsBacklinks:Ee(e)}}markFileOpenReady(e){this.onFileOpenReady(e)}finalizeFileOpen({filePath:e,isExcalidraw:t=!1,isImage:i=!1,session:n=null,supportsBacklinks:r}){t&&this.onRenderExcalidrawPreview(e),i&&this.onRenderImagePreview(e),this.onSyncWrapToggle(),r&&n&&this.loadBacklinks(e)}handleFileOpenError(){this.onFileOpenError()}};var fs=150;function gs(s){return new Promise(e=>{setTimeout(e,s)})}var Oe=class{constructor({attachEditorScroller:e,beginDocumentLoad:t,cleanupAfterSessionDestroy:i,createEditorSession:n,getDisplayName:r,getFileList:o,getLineWrappingEnabled:a,getLocalUser:c,getStoredUserName:h,getTheme:l,isExcalidrawFile:u,isImageFile:m,isMermaidFile:d,isPlantUmlFile:w,isTabActive:f,loadBootstrapContent:y=null,loadEditorSessionClass:E,loadBacklinks:S,onBeforeFileOpen:k,onConnectionChange:M,onContentChange:D,onCommentsChange:_,onFileAwarenessChange:R,onFileOpenError:$,onFileOpenReady:H,onImagePaste:q,onSelectionChange:j,onSessionAssigned:W=null,onFileOpenMetric:G=null,onRenderExcalidrawPreview:O,onRenderImagePreview:N,onSyncWrapToggle:I,onUpdateActiveFile:B,onUpdateCurrentFile:te,onUpdateLobbyCurrentFile:z,onUpdateVisibleChrome:U,onViewModeReset:g,renderPresence:v,scrollContainerForSession:C,showEditorLoading:P,stateStore:ie}){this.attachEditorScroller=e,this.beginDocumentLoad=t,this.cleanupAfterSessionDestroy=i,this.createEditorSession=n,this.getDisplayName=r,this.getFileList=o,this.getLineWrappingEnabled=a,this.getLocalUser=c,this.getStoredUserName=h,this.getTheme=l,this.isExcalidrawFile=u??(()=>!1),this.isImageFile=m??(()=>!1),this.isMermaidFile=d??(()=>!1),this.isPlantUmlFile=w??(()=>!1),this.isTabActive=f,this.loadBootstrapContent=y,this.loadEditorSessionClassPort=E,this.loadBacklinks=S,this.onBeforeFileOpen=k,this.onConnectionChange=M,this.onContentChange=D,this.onCommentsChange=_,this.onFileAwarenessChange=R,this.onFileOpenError=$,this.onFileOpenReady=H,this.onImagePaste=q,this.onSelectionChange=j,this.onSessionAssigned=W,this.onFileOpenMetric=G,this.onRenderExcalidrawPreview=O,this.onSyncWrapToggle=I,this.onUpdateActiveFile=B,this.onUpdateCurrentFile=te,this.onUpdateLobbyCurrentFile=z,this.onUpdateVisibleChrome=U,this.renderPresence=v,this.stateStore=ie,this.session=null,this.lifecycle=new _e({attachEditorScroller:e,createEditorSession:n,loadEditorSessionClass:()=>this.loadEditorSessionClassPort(),scrollContainerForSession:C}),this.chromeController=new $e({beginDocumentLoad:t,getDisplayName:r,loadBacklinks:S,onBeforeFileOpen:k,onFileOpenError:$,onFileOpenReady:H,onRenderExcalidrawPreview:O,onRenderImagePreview:N,onSyncWrapToggle:I,onUpdateActiveFile:B,onUpdateCurrentFile:te,onUpdateLobbyCurrentFile:z,onUpdateVisibleChrome:U,onViewModeReset:g,renderPresence:v,showEditorLoading:P,stateStore:ie})}getSession(){return this.session}loadEditorSessionClass(){return this.loadEditorSessionClassPort()}waitForNextPaint(){return new Promise(e=>{requestAnimationFrame(()=>{requestAnimationFrame(e)})})}reportFileOpenMetric(e,t,i={}){this.onFileOpenMetric?.(e,{filePath:this.stateStore.get("currentFilePath"),loadToken:t,...i})}cleanupSession(){this.session?.destroy(),this.session=null,this.lifecycle.clearSessionScroller(),this.cleanupAfterSessionDestroy()}async openFile(e){if(!this.isTabActive())return;let t=this.isExcalidrawFile(e),i=this.isImageFile(e),n=this.isMermaidFile(e),r=this.isPlantUmlFile(e);if(e===this.stateStore.get("currentFilePath")&&(this.session||t||i)){this.onUpdateActiveFile(e),this.onUpdateLobbyCurrentFile(e);return}let o=this.stateStore.nextSessionLoadToken(),a=performance.now();this.cleanupSession();let c=this.chromeController.prepareForFileOpen(e,{resetConnectionState:!t&&!i});if(this.reportFileOpenMetric("open_started",o,{filePath:e}),t||i){if(this.onSessionAssigned?.(null),o!==this.stateStore.get("sessionLoadToken"))return;this.chromeController.markFileOpenReady(null),this.chromeController.finalizeFileOpen({filePath:e,isExcalidraw:t,isImage:i,session:null,supportsBacklinks:c.supportsBacklinks});return}let h=await this.lifecycle.createSession({filePath:e,getFileList:this.getFileList,lineWrappingEnabled:this.getLineWrappingEnabled(),localUser:this.getLocalUser(),onAwarenessChange:l=>this.onFileAwarenessChange(l),onConnectionChange:l=>this.onConnectionChange(l),onCommentsChange:l=>this.onCommentsChange?.(l),onContentChange:()=>{t||this.onContentChange({isMermaid:n,isPlantUml:r})},onImagePaste:l=>this.onImagePaste?.(l),preferredUserName:this.getStoredUserName(),onSelectionChange:l=>this.onSelectionChange?.(l),theme:this.getTheme()});this.session=h,this.onSessionAssigned?.(h);try{let l=!1,u=!1,m=!1,d=async S=>{l||o!==this.stateStore.get("sessionLoadToken")||(l=!0,this.lifecycle.attachSessionScroller(h),h.applyTheme(this.getTheme()),this.chromeController.markFileOpenReady(h),this.reportFileOpenMetric("editor_ready",o,{reason:S}),h.requestMeasure(),await this.waitForNextPaint(),!(u||o!==this.stateStore.get("sessionLoadToken"))&&(u=!0,this.chromeController.finalizeFileOpen({filePath:e,isExcalidraw:t,session:h,supportsBacklinks:c.supportsBacklinks})))},w=this.loadBootstrapContent?(async()=>{this.reportFileOpenMetric("bootstrap_fetch_started",o);try{let S=await this.loadBootstrapContent(e);return this.reportFileOpenMetric("bootstrap_fetch_completed",o,{found:S!==null}),S}catch(S){return this.reportFileOpenMetric("bootstrap_fetch_completed",o,{error:S.message,found:!1}),null}})():Promise.resolve(null),f=h.initialize(e),y=(async()=>(await f,o!==this.stateStore.get("sessionLoadToken")||(await h.waitForInitialSync(null),o!==this.stateStore.get("sessionLoadToken"))?!1:(m=!0,h.activateCollaborativeView?.(),this.lifecycle.attachSessionScroller(h),h.applyTheme(this.getTheme()),this.reportFileOpenMetric("initial_sync_complete",o),h.ensureInitialContent?.(),l?h.requestMeasure():await d("live-sync"),!0)))(),E=(async()=>{let S=await w;if(S===null||m||l||o!==this.stateStore.get("sessionLoadToken"))return!1;let k=performance.now()-a,M=Math.max(0,fs-k);return M>0&&await Promise.race([y.then(R=>R?"live-sync":"stale"),gs(M).then(()=>"timeout")])==="live-sync"||m||l||o!==this.stateStore.get("sessionLoadToken")||!h.showBootstrapContent({content:S,filePath:e})&&!h.hasBootstrapContent?.()?!1:(this.reportFileOpenMetric("bootstrap_shown",o),await d("bootstrap"),!0)})();if(await f,o!==this.stateStore.get("sessionLoadToken")){h.destroy();return}if(await Promise.all([y,E]),o!==this.stateStore.get("sessionLoadToken")){h.destroy();return}l||(h.ensureInitialContent?.(),await d("post-initialize"))}catch(l){if(console.error("[app] Failed to initialize editor:",l),h.destroy(),this.lifecycle.clearSessionScroller(),this.session===h&&(this.session=null),o!==this.stateStore.get("sessionLoadToken"))return;this.chromeController.handleFileOpenError()}}};var ze=class{constructor(e={}){this.state={activeSidebarTab:"files",chatInitialSyncComplete:!1,chatIsOpen:!1,chatMessageIds:new Set,chatMessages:[],chatUnreadCount:0,connectionHelpShown:!1,connectionState:{status:"disconnected",unreachable:!1},currentFilePath:null,fileExplorerReady:!1,followedCursorSignature:"",followedUserClientId:null,gitRepoAvailable:!1,globalUsers:[],isTabActive:!1,sessionLoadToken:0,...e}}get(e){return this.state[e]}set(e,t){return this.state[e]=t,t}nextSessionLoadToken(){let e=Number(this.state.sessionLoadToken||0)+1;return this.state.sessionLoadToken=e,e}replaceChatState({initialSyncComplete:e,isOpen:t,messageIds:i,messages:n,unreadCount:r}){this.state.chatMessages=Array.isArray(n)?n:[],this.state.chatMessageIds=i instanceof Set?i:new Set,this.state.chatUnreadCount=Number.isFinite(r)?r:0,this.state.chatIsOpen=!!t,this.state.chatInitialSyncComplete=!!e}};function wi(s=document){return{currentUserName:s.getElementById("currentUserName"),chatContainer:s.getElementById("chatContainer"),chatEmptyState:s.getElementById("chatEmptyState"),chatForm:s.getElementById("chatForm"),chatInput:s.getElementById("chatInput"),chatMessages:s.getElementById("chatMessages"),chatNotificationButton:s.getElementById("chatNotificationBtn"),chatPanel:s.getElementById("chatPanel"),chatStatus:s.getElementById("chatStatus"),chatToastContainer:s.getElementById("chatToastContainer"),chatToggleBadge:s.getElementById("chatToggleBadge"),chatToggleButton:s.getElementById("chatToggleBtn"),gitCommitCancel:s.getElementById("gitCommitCancel"),gitCommitCopy:s.getElementById("gitCommitCopy"),gitCommitDialog:s.getElementById("gitCommitDialog"),gitCommitForm:s.getElementById("gitCommitForm"),gitCommitInput:s.getElementById("gitCommitInput"),gitCommitSubmit:s.getElementById("gitCommitSubmit"),gitCommitTitle:s.getElementById("gitCommitTitle"),gitResetCancel:s.getElementById("gitResetCancel"),gitResetCopy:s.getElementById("gitResetCopy"),gitResetDialog:s.getElementById("gitResetDialog"),gitResetFileName:s.getElementById("gitResetFileName"),gitResetSubmit:s.getElementById("gitResetSubmit"),gitResetTitle:s.getElementById("gitResetTitle"),displayNameCancel:s.getElementById("displayNameCancel"),displayNameCopy:s.getElementById("displayNameCopy"),displayNameDialog:s.getElementById("displayNameDialog"),displayNameForm:s.getElementById("displayNameForm"),displayNameInput:s.getElementById("displayNameInput"),displayNameSubmit:s.getElementById("displayNameSubmit"),displayNameTitle:s.getElementById("displayNameTitle"),editNameButton:s.getElementById("editNameBtn"),editorContainer:s.getElementById("editorContainer"),markdownToolbar:s.getElementById("markdownToolbar"),editorPage:s.getElementById("editor-page"),diffPage:s.getElementById("diff-page"),fileSearch:s.getElementById("fileSearch"),fileHistoryButton:s.getElementById("fileHistoryBtn"),fileHistoryButtonLabel:s.getElementById("fileHistoryBtnLabel"),filesSidebarTab:s.getElementById("filesSidebarTab"),gitSearch:s.getElementById("gitSearch"),gitSearchInput:s.getElementById("gitSearchInput"),gitSidebarTab:s.getElementById("gitSidebarTab"),gitOperationStatus:s.getElementById("gitOperationStatus"),lineInfo:s.getElementById("lineInfo"),mobileViewToggle:s.getElementById("mobileViewToggle"),previewContent:s.getElementById("previewContent"),previewContainer:s.getElementById("previewContainer"),shareButton:s.getElementById("shareBtn"),toastContainer:s.getElementById("toastContainer"),toggleWrapButton:s.getElementById("toggleWrapBtn"),userAvatars:s.getElementById("userAvatars"),userCount:s.getElementById("userCount"),wrapToggleLabel:s.getElementById("wrapToggleLabel"),activeFileName:s.getElementById("activeFileName"),sidebarToggle:s.getElementById("sidebarToggle"),sidebarClose:s.getElementById("sidebarClose"),sidebar:s.getElementById("sidebar"),emptyState:s.getElementById("emptyState"),emptyStateNewFileBtn:s.getElementById("emptyStateNewFileBtn"),emptyStateSearchBtn:s.getElementById("emptyStateSearchBtn"),backlinksPanel:s.getElementById("backlinksPanel"),backlinksInlinePanel:s.getElementById("backlinksInlinePanel"),commentSelectionButton:s.getElementById("commentSelectionBtn"),commentsDrawer:s.getElementById("commentsDrawer"),commentsDrawerEmpty:s.getElementById("commentsDrawerEmpty"),commentsDrawerList:s.getElementById("commentsDrawerList"),commentsToggleButton:s.getElementById("commentsToggle"),outlineToggle:s.getElementById("outlineToggle"),tabLockCopy:s.getElementById("tabLockCopy"),tabLockOverlay:s.getElementById("tabLockOverlay"),tabLockTakeoverButton:s.getElementById("tabLockTakeoverBtn"),tabLockTitle:s.getElementById("tabLockTitle"),toolbarCenter:s.getElementById("toolbarCenter"),toolbarDiffBadge:s.getElementById("toolbarDiffBadge"),sidebarTabs:s.getElementById("sidebarTabs")}}var vi={updateChatMessages(s,{initial:e=!1}={}){let t=new Set(this.chatMessageIds),i=this.lobby.getLocalUser()?.peerId??null;if(this.chatMessages=s,this.chatMessageIds=new Set(s.map(r=>r.id)),!this.chatInitialSyncComplete){e&&(this.chatInitialSyncComplete=!0),this.renderChat();return}let n=s.filter(r=>!t.has(r.id)&&r.peerId&&r.peerId!==i);this.chatIsOpen?this.chatUnreadCount=0:n.length>0&&(this.chatUnreadCount+=n.length);for(let r of n)this.maybeNotifyChatMessage(r);this.renderChat()},toggleChatPanel(){if(this.chatIsOpen){this.closeChatPanel();return}this.openChatPanel()},openChatPanel(){this.chatIsOpen=!0,this.chatUnreadCount=0,this.renderChat(),requestAnimationFrame(()=>{this.elements.chatInput?.focus(),this.scrollChatToBottom()})},closeChatPanel(){this.chatIsOpen&&(this.chatIsOpen=!1,this.renderChat())},handleChatSubmit(){if(!this.isTabActive)return;let s=this.elements.chatInput;if(!s)return;if(!this.lobby.sendChatMessage(s.value)){s.focus();return}if(s.value="",!this.chatIsOpen){this.openChatPanel();return}this.renderChat()},renderChat(){this.elements.chatContainer?.classList.toggle("is-open",this.chatIsOpen),this.elements.chatPanel?.classList.toggle("hidden",!this.chatIsOpen),this.syncChatToggleButton(),this.syncChatNotificationButton();let s=this.elements.chatMessages,e=this.elements.chatEmptyState;if(this.elements.chatStatus&&(this.elements.chatStatus.textContent=this.chatInitialSyncComplete?`${this.globalUsers.length} online`:"Syncing..."),!s)return;if(s.replaceChildren(),this.chatMessages.length===0){e?.classList.remove("hidden"),s.classList.add("hidden");return}e?.classList.add("hidden"),s.classList.remove("hidden");let t=document.createDocumentFragment();this.chatMessages.forEach(i=>{t.appendChild(this.createChatMessageElement(i))}),s.appendChild(t),this.chatIsOpen&&this.scrollChatToBottom()},createChatMessageElement(s){let e=document.createElement("article"),t=s.peerId===this.lobby.getLocalUser()?.peerId;e.className="chat-message",e.classList.toggle("is-local",t);let i=document.createElement("div");i.className="chat-message-avatar",i.style.backgroundColor=s.userColor||"var(--color-primary)",i.textContent=(s.userName||"?").charAt(0).toUpperCase(),i.setAttribute("aria-hidden","true");let n=document.createElement("div");n.className="chat-message-body";let r=document.createElement("div");r.className="chat-message-meta";let o=document.createElement("span");o.className="chat-message-author",o.textContent=t?`${s.userName} (you)`:s.userName;let a=document.createElement("span");a.className="chat-message-time",a.textContent=this.formatChatTimestamp(s.createdAt),r.append(o,a);let c=this.getChatMessageFileLabel(s.filePath);if(c){let l=document.createElement("span");l.className="chat-message-file",l.textContent=c,r.append(l)}let h=document.createElement("p");return h.className="chat-message-text",h.textContent=s.text,n.append(r,h),e.append(i,n),e},scrollChatToBottom(){let s=this.elements.chatMessages;s&&requestAnimationFrame(()=>{s.scrollTop=s.scrollHeight})},formatChatTimestamp(s){if(!Number.isFinite(s))return"";try{return this.chatTimeFormatter.format(new Date(s))}catch{return""}},getChatMessageFileLabel(s){return s?this.getDisplayName(s):""},formatChatToastMessage(s){let e=s?.userName||"Someone",t=String(s?.text??"").replace(/\s+/g," ").trim(),i=t.length>88?`${t.slice(0,85).trimEnd()}...`:t;return`${e}: ${i}`},syncChatToggleButton(){let s=this.elements.chatToggleButton,e=this.elements.chatToggleBadge;if(!s)return;let t=this.chatUnreadCount>0,i=t&&!this.chatIsOpen;s.classList.toggle("is-active",this.chatIsOpen),s.classList.toggle("is-unread",i),s.setAttribute("aria-expanded",String(this.chatIsOpen)),s.setAttribute("aria-label",t?`Open team chat, ${this.chatUnreadCount} unread`:"Open team chat"),s.title=this.chatUnreadCount>0?`Team chat (${this.chatUnreadCount} unread)`:"Team chat",e&&(e.classList.toggle("hidden",!t),e.textContent=this.chatUnreadCount>9?"9+":String(this.chatUnreadCount))},syncChatNotificationButton(){let s=this.elements.chatNotificationButton;if(!s)return;let e=this.notifications.getPermission();this.chatNotificationPermission=e;let t="Enable alerts",i="Enable browser notifications for new chat messages",n=!1;e==="unsupported"?(t="No alerts",i="Browser notifications are unavailable here"):e==="denied"?(t="Alerts blocked",i="Browser notifications are blocked for this site"):e==="granted"&&(n=this.chatNotificationsEnabled,t=n?"Alerts on":"Alerts off",i=n?"Disable browser notifications for chat":"Enable browser notifications for chat"),s.textContent=t,s.title=i,s.setAttribute("aria-pressed",String(n)),s.classList.toggle("is-enabled",n),s.classList.toggle("is-blocked",e==="denied")},async handleChatNotificationToggle(){let s=this.notifications.getPermission();if(this.chatNotificationPermission=s,s==="unsupported"){this.toastController.show("Browser notifications are unavailable here"),this.syncChatNotificationButton();return}if(s==="denied"){this.chatNotificationsEnabled=!1,this.preferences.setChatNotificationsEnabled(!1),this.toastController.show("Browser notifications are blocked for this site"),this.syncChatNotificationButton();return}if(s==="default"){let e=await this.notifications.requestPermission();if(this.chatNotificationPermission=e,e!=="granted"){this.chatNotificationsEnabled=!1,this.preferences.setChatNotificationsEnabled(!1),e==="denied"&&this.toastController.show("Browser notifications were blocked"),this.syncChatNotificationButton();return}this.chatNotificationsEnabled=!0,this.preferences.setChatNotificationsEnabled(!0),this.syncChatNotificationButton();return}this.chatNotificationsEnabled=!this.chatNotificationsEnabled,this.preferences.setChatNotificationsEnabled(this.chatNotificationsEnabled),this.syncChatNotificationButton()},maybeNotifyChatMessage(s){if(this.chatInitialSyncComplete){if(document.hidden){this.maybeShowBrowserChatNotification(s);return}!this.isTabActive||this.chatIsOpen||(this.chatToastController??this.toastController).show(this.formatChatToastMessage(s),4e3)}},maybeShowBrowserChatNotification(s){if(!this.chatNotificationsEnabled||this.notifications.getPermission()!=="granted")return;let e=`CollabMD chat \u2022 ${s.userName}`,t=this.getChatMessageFileLabel(s.filePath),i=t?`${t}: ${s.text}`:s.text,n=this.notifications.createNotification({body:i,onClick:()=>{s.filePath&&this.navigation.navigateToFile(s.filePath)},tag:`collabmd-chat-${s.id}`,title:e});n&&setTimeout(()=>{n.close?.()},6e3)}};var bi={getCommentFileKind(s=this.currentFilePath){return he(s)||"markdown"},syncCommentChrome(s=this.currentFilePath){let e=Zt(s)&&!this.isExcalidrawFile(s);this.commentUi.setCurrentFile(s,{fileKind:this.getCommentFileKind(s),supported:e}),this.handleCommentThreadsChange(this.session?.getCommentThreads?.()??[]),this.handleCommentSelectionChange(this.session?.getCurrentSelectionCommentAnchor?.()??null)},handleCommentSelectionChange(s){this.commentUi.setSelectionAnchor(s)},handleCommentThreadsChange(s=[]){this.commentUi.setThreads(s)},handleCommentEditorContentChange(){this.commentUi.handleEditorContentChange()},refreshCommentUiLayout(){this.commentUi.refreshLayout()}};function kt(s=[]){return Array.from(new Set((s??[]).filter(Boolean)))}function ys(s=[]){return Array.from(new Map((s??[]).filter(e=>e?.oldPath&&e?.newPath&&e.oldPath!==e.newPath).map(e=>[`${e.oldPath}:${e.newPath}`,{newPath:e.newPath,oldPath:e.oldPath}])).values())}function ws(s=[]){return(s??[]).filter(e=>e?.path&&Number.isFinite(e?.from)&&Number.isFinite(e?.to)).map(e=>({from:Math.max(0,Math.round(e.from)),path:e.path,to:Math.max(0,Math.round(e.to))}))}function Lt({changedPaths:s=[],deletedPaths:e=[],refreshExplorer:t=!0,renamedPaths:i=[]}={}){return{changedPaths:kt(s),deletedPaths:kt(e),refreshExplorer:t!==!1,renamedPaths:ys(i)}}function Ft(s){return!s||typeof s!="object"||typeof s.id!="string"?null:{action:typeof s.action=="string"?s.action:"workspace",createdAt:Number.isFinite(s.createdAt)?s.createdAt:Date.now(),highlightRanges:ws(s.highlightRanges),id:s.id,origin:typeof s.origin=="string"?s.origin:"api",reloadRequiredPaths:kt(s.reloadRequiredPaths),requestId:typeof s.requestId=="string"?s.requestId:null,sourceRef:typeof s.sourceRef=="string"?s.sourceRef:null,workspaceChange:Lt(s.workspaceChange)}}function Ci(s={}){return Lt(s)}function vs(){return globalThis.crypto?.randomUUID?globalThis.crypto.randomUUID():`workspace-${Date.now()}-${Math.random().toString(16).slice(2,10)}`}var Ei={formatPullBackupToast(s=null){let e=Number(s?.fileCount||0);return e===1?"Pulled latest changes. 1 overlapping local file was backed up.":e>1?`Pulled latest changes. ${e} overlapping local files were backed up.`:"Pulled latest changes. Overlapping local changes were recorded in a pull backup."},setGitOperationStatus(s=""){let e=this.elements.gitOperationStatus;if(!e)return;let t=String(s??"").trim();e.textContent=t,e.classList.toggle("hidden",!t)},async runGitActionWithStatus(s,e){this.setGitOperationStatus(s);try{return await e()}finally{this.setGitOperationStatus("")}},handleGitDiffSelection(s,{closeSidebarOnMobile:e=!1,scope:t="working-tree"}={}){e&&this.closeSidebarOnMobile(),this.navigation.navigateToGitDiff({filePath:s,scope:t})},handleGitCommitSelection(s,{closeSidebarOnMobile:e=!1,historyFilePath:t=null,path:i=null}={}){e&&this.closeSidebarOnMobile(),this.navigation.navigateToGitCommit({hash:s,historyFilePath:t,path:i})},handleGitHistorySelection({closeSidebarOnMobile:s=!1}={}){s&&this.closeSidebarOnMobile(),this.navigation.navigateToGitHistory()},handleGitFileHistorySelection(s=this.currentFilePath,{closeSidebarOnMobile:e=!1}={}){e&&this.closeSidebarOnMobile(),s&&this.navigation.navigateToGitFileHistory({filePath:s})},handleGitFilePreviewSelection({hash:s,path:e,currentFilePath:t=null,closeSidebarOnMobile:i=!1}={}){i&&this.closeSidebarOnMobile(),!(!s||!e)&&this.navigation.navigateToGitFilePreview({hash:s,path:e,currentFilePath:t})},handleGitRepoChange(s,e=null){this.gitRepoAvailable=!!s,this.elements.sidebarTabs?.classList.toggle("hidden",!this.gitRepoAvailable),this.elements.gitSidebarTab?.classList.toggle("hidden",!this.gitRepoAvailable);let t=s&&e?.summary?.changedFiles>0;if(this.elements.gitSidebarTab?.classList.toggle("has-changes",t),this.gitDiffView.setRepoStatus(this.gitRepoAvailable?e:null),!this.gitRepoAvailable&&this.activeSidebarTab==="git"){this.syncFileHistoryButton({mode:this.navigation.getHashRoute().type==="git-file-preview"?"history-preview":"editor"}),this.setSidebarTab("files");return}let i=this.navigation.getHashRoute().type;this.gitRepoAvailable&&(i==="git-diff"||i==="git-commit"||i==="git-history")&&this.activeSidebarTab!=="git"&&this.setSidebarTab("git"),this.syncFileHistoryButton({filePath:this.currentFilePath,mode:i==="git-file-preview"?"history-preview":i==="file"?"editor":"empty"})},syncFileHistoryButton({filePath:s=this.currentFilePath,mode:e="editor"}={}){let t=this.elements.fileHistoryButton,i=this.elements.fileHistoryButtonLabel;if(!t||!i)return;if(!(this.gitRepoAvailable&&this.supportsFileHistory?.(s))){t.classList.add("hidden");return}if(t.classList.remove("hidden"),e==="history-preview"){i.textContent="Back to History",t.setAttribute("aria-label","Back to file history"),t.title="Back to file history";return}if(e!=="editor"){t.classList.add("hidden");return}i.textContent="History",t.setAttribute("aria-label","Open file history"),t.title="View file history"},syncMainChrome({badgeLabel:s="",mode:e,title:t=null}={}){let i=e==="diff"||e==="history"||e==="history-preview";this.elements.toolbarCenter?.classList.toggle("hidden",i),this.elements.mobileViewToggle?.classList.toggle("hidden",i),this.elements.userCount?.classList.toggle("hidden",i),this.elements.toolbarDiffBadge?.classList.toggle("hidden",!s),this.elements.toolbarDiffBadge&&(this.elements.toolbarDiffBadge.textContent=s),t&&this.elements.activeFileName&&(this.elements.activeFileName.textContent=t),this.syncFileHistoryButton({filePath:this.currentFilePath,mode:e})},async showGitDiff({filePath:s=null,scope:e="all"}={}){this.clearStaticPreviewDocument?.(),this.gitPanel.setSelection(s?{path:s,scope:e,source:"workspace"}:{}),this.gitPanel.setMode("changes"),this.showDiffState(),this.syncMainChrome({badgeLabel:"Diff",mode:"diff",title:this.gitDiffView.getToolbarTitle({filePath:s,scope:e})}),this.syncFileHistoryButton({filePath:s,mode:"diff"}),await this.gitDiffView.openWorkspaceDiff({filePath:s,scope:e})},async showGitCommit({hash:s,path:e=null,historyFilePath:t=null}={}){this.clearStaticPreviewDocument?.(),this.gitPanel.setMode("history"),this.gitPanel.setSelection(s?{commitHash:s,path:e,source:"commit"}:{source:"commit"}),this.showDiffState(),this.syncMainChrome({badgeLabel:"Diff",mode:"diff",title:this.gitDiffView.getToolbarTitle({commitHash:s,path:e,source:"commit"})}),this.syncFileHistoryButton({filePath:e,mode:"diff"}),await this.gitDiffView.openCommitDiff({hash:s,historyFilePath:t,path:e})},async showGitHistory(){this.clearStaticPreviewDocument?.(),this.gitPanel.setMode("history"),this.gitPanel.setSelection({source:"commit"}),this.workspaceRouteController?.showEmptyState?.(),this.syncMainChrome({mode:"empty",title:"Git History"}),this.syncFileHistoryButton({mode:"empty"})},async showGitFileHistory({filePath:s=null}={}){if(!s){this.workspaceRouteController?.showEmptyState?.();return}this.clearStaticPreviewDocument?.(),this.commentUi?.attachSession?.(null),this.commentUi?.setCurrentFile?.(s,{fileKind:this.getCommentFileKind(s),supported:!1}),this.handleCommentThreadsChange?.([]),this.handleCommentSelectionChange?.(null),this.workspaceRouteController?.showFileHistoryState?.(s),this.syncMainChrome({badgeLabel:"History",mode:"history",title:this.getDisplayName(s)}),this.syncFileHistoryButton({filePath:s,mode:"history"}),await this.fileHistoryView.openFileHistory({filePath:s})},async showGitFilePreview({hash:s,filePath:e=null,currentFilePath:t=null}={}){let i=String(t??"").trim()||e;if(!s||!e||!i){this.workspaceRouteController?.showEmptyState?.();return}this.commentUi?.attachSession?.(null),this.commentUi?.setCurrentFile?.(i,{fileKind:this.getCommentFileKind(i),supported:!1}),this.handleCommentThreadsChange?.([]),this.handleCommentSelectionChange?.(null),this.workspaceRouteController?.showPreviewOnlyState?.(i),this.layoutController.setView("preview",{persist:!1}),this.syncMainChrome({badgeLabel:"History Preview",mode:"history-preview",title:this.getDisplayName(i)}),this.syncFileHistoryButton({filePath:i,mode:"history-preview"});try{let n=new URLSearchParams;n.set("hash",s),n.set("path",e);let r=await fetch(b(`/git/file-snapshot?${n.toString()}`)),o=await r.json();if(!r.ok)throw new Error(o.error||"Failed to load historical file preview");if(this.setStaticPreviewDocument?.({...o,currentFilePath:i}),this.resetPreviewMode(),this.elements.markdownToolbar?.classList.add("hidden"),this.elements.outlineToggle?.classList.toggle("hidden",o.fileKind!=="markdown"),o.fileKind==="markdown"||o.fileKind==="mermaid"||o.fileKind==="plantuml"){o.fileKind==="mermaid"?this.elements.previewContent?.classList.add("is-mermaid-file-preview"):o.fileKind==="plantuml"&&this.elements.previewContent?.classList.add("is-plantuml-file-preview"),this.previewRenderer.beginDocumentLoad(),this.previewRenderer.queueRender();return}this.elements.outlineToggle?.classList.add("hidden"),this.renderTextFilePreview({content:o.content,filePath:i})}catch(n){console.error("[git-preview] Failed to load file snapshot:",n),this.clearStaticPreviewDocument?.(),this.toastController.show("Failed to load historical file preview"),this.renderTextFilePreview({content:"Failed to load historical file preview.",filePath:i}),this.elements.outlineToggle?.classList.add("hidden")}},async postGitAction(s,e){let t=vs();this.pendingWorkspaceRequestIds?.add(t);let i=await fetch(s,{body:JSON.stringify(e),headers:{"Content-Type":"application/json","X-CollabMD-Request-Id":t},method:"POST"}),n=await i.json();if(!i.ok){this.pendingWorkspaceRequestIds?.delete(t);let r=new Error(n.error||"Git action failed");throw typeof n?.code=="string"&&(r.code=n.code),r}return n},async refreshWorkspaceAfterGitAction({filePath:s=null,preferredScope:e=null}={}){await this.fileExplorer.refresh(),await this.refreshGitAfterAction({filePath:s,preferredScope:e})},async refreshGitAfterAction({filePath:s=null,preferredScope:e=null}={}){await this.gitPanel.refresh({force:!0});let t=this.navigation.getHashRoute();if(t.type==="git-history"){await this.showGitHistory();return}if(t.type==="git-file-history"){await this.showGitFileHistory({filePath:t.filePath});return}if(t.type==="git-file-preview"){await this.showGitFilePreview({hash:t.hash,filePath:t.filePath,currentFilePath:t.currentFilePath});return}if(t.type==="git-commit"){await this.showGitCommit({hash:t.hash,path:t.path,historyFilePath:t.historyFilePath});return}if(t.type!=="git-diff")return;let i=s??t.filePath,n=e??t.scope;if(n!==t.scope||i!==t.filePath){this.navigation.navigateToGitDiff({filePath:i,scope:n});return}await this.showGitDiff({filePath:t.filePath,scope:t.scope})},async finalizeGitAction({action:s,filePath:e=null,preferredScope:t=null,result:i={},showLocalFileToast:n=!1}={}){let r=Ci(i.workspaceChange);return await this.refreshWorkspaceAfterGitAction({filePath:e,preferredScope:t}),this.handleWorkspaceChangeForCurrentFile(r,{action:s,local:!0,showToast:n}),r},handleWorkspaceChangeForCurrentFile(s,{action:e="git",local:t=!1,showToast:i=!0}={}){let n=this.currentFilePath;if(!n)return!1;let r=s.deletedPaths.includes(n),o=s.renamedPaths.find(c=>c.oldPath===n);if(!r&&!o)return!1;if(!i)return o?this.navigation.navigateToFile(o.newPath):this.navigation.navigateToFile(null),!0;let a=this.getDisplayName(n);return o?(this.navigation.navigateToFile(o.newPath),this.toastController.show(t?`${a} moved to ${this.getDisplayName(o.newPath)}`:`${a} moved on disk`),!0):(this.navigation.navigateToFile(null),this.toastController.show(t?`${a} was removed by ${e}`:`${a} was removed after a ${e} operation`),!0)},async handleIncomingWorkspaceEvent(s){if(!this.isTabActive||!s)return;if(s.requestId&&this.pendingWorkspaceRequestIds?.has(s.requestId)){this.pendingWorkspaceRequestIds.delete(s.requestId);return}let e=Ci(s.workspaceChange);if(s.origin==="git"&&await this.refreshGitAfterAction(),this.handleWorkspaceChangeForCurrentFile(e,{action:s.action||s.origin||"workspace",local:!1,showToast:!0}),s.origin==="filesystem"&&this.currentFilePath&&e.changedPaths.includes(this.currentFilePath)){let i=e.changedPaths.length===1&&Array.isArray(s.highlightRanges)?s.highlightRanges.find(r=>r.path===this.currentFilePath):null;i&&this.session?.flashExternalUpdate?.(i)||this.toastController.show(`${this.getDisplayName(this.currentFilePath)} updated from disk`)}this.currentFilePath&&Array.isArray(s.reloadRequiredPaths)&&s.reloadRequiredPaths.includes(this.currentFilePath)&&this.toastController.show(`${this.getDisplayName(this.currentFilePath)} needs a manual reload`)},async stageGitFile(s,{scope:e="working-tree"}={}){s&&await this.runGitActionWithStatus("Staging changes...",async()=>{let t=await this.postGitAction(b("/git/stage"),{path:s});await this.finalizeGitAction({action:"stage",filePath:s,preferredScope:e==="all"?"all":"staged",result:t})})},async unstageGitFile(s,{scope:e="staged"}={}){s&&await this.runGitActionWithStatus("Unstaging changes...",async()=>{let t=await this.postGitAction(b("/git/unstage"),{path:s});await this.finalizeGitAction({action:"unstage",filePath:s,preferredScope:e==="all"?"all":"working-tree",result:t})})},async pushGitBranch(){await this.runGitActionWithStatus("Pushing branch...",async()=>{try{let s=await this.postGitAction(b("/git/push"),{});await this.finalizeGitAction({action:"push",result:s})}catch(s){this.toastController.show(s.message||"Failed to push branch")}})},async pullGitBranch(){await this.runGitActionWithStatus("Pulling branch...",async()=>{try{let s=await this.postGitAction(b("/git/pull"),{});await this.finalizeGitAction({action:"pull",result:s,showLocalFileToast:!0}),s.pullBackup&&this.toastController.show(this.formatPullBackupToast(s.pullBackup),5e3)}catch(s){if(s?.code==="pull_diverged_ff_only"){this.toastController.show("Cannot pull because local and remote commits have diverged. Fast-forward only pull is not possible.",5e3);return}if(s?.code==="pull_conflicted_after_autostash"){this.toastController.show("Pull updated the branch, but reapplying local changes caused conflicts. Review the conflicted files and the pull backup summary.",6e3);return}this.toastController.show(s.message||"Failed to pull branch")}})},openGitResetDialog(s){if(!this.isTabActive||!s)return;let e=this.elements.gitResetDialog;!e||!this.elements.gitResetFileName||(this.pendingGitResetPath=s,this.elements.gitResetTitle&&(this.elements.gitResetTitle.textContent="Reset file to current branch"),this.elements.gitResetCopy&&(this.elements.gitResetCopy.textContent="Restore this file from the current checked-out branch. If this branch does not contain the file, the file will be deleted locally."),this.elements.gitResetFileName.value=s,this.elements.gitResetSubmit&&(this.elements.gitResetSubmit.textContent="Reset File"),this.elements.gitResetSubmit?.toggleAttribute("disabled",!1),!e.open&&(typeof e.showModal=="function"?e.showModal():e.setAttribute("open","true")))},async handleGitResetSubmit(){let s=this.pendingGitResetPath,e=this.elements.gitResetDialog,t=this.elements.gitResetSubmit;if(!(!s||!e)){t?.toggleAttribute("disabled",!0),t&&(t.textContent="Resetting...");try{await this.runGitActionWithStatus("Resetting file...",async()=>{let i=await this.postGitAction(b("/git/reset-file"),{path:s});await this.finalizeGitAction({action:"reset",filePath:s,result:i,showLocalFileToast:!0})}),e.close()}catch(i){this.toastController.show(i.message||"Failed to reset file")}finally{t&&(t.textContent="Reset File"),t?.toggleAttribute("disabled",!1)}}},openGitCommitDialog(){if(!this.isTabActive)return;let s=this.elements.gitCommitDialog,e=this.elements.gitCommitInput;if(!(!s||!e)){if(this.elements.gitCommitTitle&&(this.elements.gitCommitTitle.textContent="Commit staged changes"),this.elements.gitCommitCopy){let t=Number(this.gitPanel.status?.summary?.staged||0);this.elements.gitCommitCopy.textContent=t>0?`${t} staged file${t===1?"":"s"} will be included.`:"All staged changes will be included."}this.elements.gitCommitSubmit&&(this.elements.gitCommitSubmit.textContent="Commit staged changes"),e.value="",!s.open&&(typeof s.showModal=="function"?s.showModal():s.setAttribute("open","true"),requestAnimationFrame(()=>{e.focus(),e.select()}))}},async handleGitCommitSubmit(){let s=this.elements.gitCommitDialog,e=this.elements.gitCommitInput,t=this.elements.gitCommitSubmit,i=String(e?.value??"").trim();if(!(!s||!e)){if(!i){e.focus(),this.toastController.show("Commit message cannot be empty");return}t?.toggleAttribute("disabled",!0),t&&(t.textContent="Committing...");try{await this.runGitActionWithStatus("Committing changes...",async()=>{let n=await this.postGitAction(b("/git/commit"),{message:i});await this.finalizeGitAction({action:"commit",result:n})}),s.close()}catch(n){this.toastController.show(n.message||"Failed to commit staged changes")}finally{t&&(t.textContent="Commit staged changes"),t?.toggleAttribute("disabled",!1)}}}};var Si={updateGlobalUsers(s){this.globalUsers=s,this.syncFollowedUser(),this.renderAvatars(),this.renderChat(),this.renderPresence(),this.syncCurrentUserName()},updateFileAwareness(s){this.syncFollowedUser()},renderPresence(){let s=this.elements.userCount;if(!s)return;let e=!!this.session,t=!!(this.currentFilePath&&this.isExcalidrawFile?.(this.currentFilePath)),i=!!(this.currentFilePath&&this.isImageFile?.(this.currentFilePath)),r=!e&&(!this.currentFilePath||t||i)?this.lobby?.getConnectionState?.()??this.connectionState:this.connectionState;if(r.status==="connected"){s.textContent=`${this.globalUsers.length} online`,s.style.opacity="1";return}if(r.status==="connecting"){s.textContent=r.unreachable?"Unreachable":"Connecting...",s.style.opacity="0.6";return}s.textContent="Offline",s.style.opacity="0.6"},renderAvatars(){let s=this.elements.userAvatars;if(!s)return;s.innerHTML="";let e=[...this.globalUsers],t=e.findIndex(r=>r.isLocal);if(t>0){let[r]=e.splice(t,1);e.unshift(r)}let i=e.findIndex(r=>!r.isLocal&&r.clientId===this.followedUserClientId),n=e[0]?.isLocal?1:0;if(i>n){let[r]=e.splice(i,1);e.splice(n,0,r)}if(e.slice(0,5).forEach(r=>{let o=document.createElement(r.isLocal?"div":"button");o.className="user-avatar",o.classList.toggle("is-local",r.isLocal),o.style.backgroundColor=r.color,o.classList.toggle("is-following",r.clientId===this.followedUserClientId);let a=document.createElement("span");a.className="user-avatar-initial",a.textContent=r.name.charAt(0).toUpperCase(),o.appendChild(a);let c=r.currentFile&&r.currentFile===this.currentFilePath,h=r.currentFile?this.getDisplayName(r.currentFile):"No file";if(r.isLocal){let l=document.createElement("span");l.className="user-avatar-self-label",l.textContent="You",o.appendChild(l),o.title=`${r.name} (you) \u2014 ${h}`,o.setAttribute("role","img"),o.setAttribute("aria-label",`${r.name} (you) \u2014 ${h}`)}else{o.type="button",o.classList.add("user-avatar-button"),c||o.classList.add("different-file");let l=r.clientId===this.followedUserClientId?`Stop following ${r.name}`:c?`Follow ${r.name}`:`Follow ${r.name} \u2014 ${h}`;o.title=l,o.setAttribute("aria-label",l),o.addEventListener("click",()=>this.toggleFollowUser(r.clientId))}s.appendChild(o)}),e.length>5){let r=document.createElement("div");r.className="user-avatar",r.style.backgroundColor="var(--color-surface-dynamic)",r.style.color="var(--color-text-muted)";let o=document.createElement("span");o.className="user-avatar-initial",o.textContent=`+${e.length-5}`,r.appendChild(o),s.appendChild(r)}},toggleFollowUser(s){if(!s)return;if(this.followedUserClientId===s){this.stopFollowingUser();return}let e=this.globalUsers.find(t=>t.clientId===s&&!t.isLocal);if(e){if(this.followedUserClientId=s,this.followedCursorSignature="",this.renderAvatars(),e.currentFile&&e.currentFile!==this.currentFilePath){this.navigation.navigateToFile(e.currentFile);return}requestAnimationFrame(()=>{this.followedUserClientId===s&&this.followUserCursor(e,{force:!0})})}},stopFollowingUser(){this.followedUserClientId&&(this.currentFilePath&&this.isExcalidrawFile?.(this.currentFilePath)&&this.excalidrawEmbed?.setFollowedUser(this.currentFilePath,null),this.followedUserClientId=null,this.followedCursorSignature="",this.renderAvatars())},syncFollowedUser(){if(!this.followedUserClientId)return;let s=this.globalUsers.find(e=>e.clientId===this.followedUserClientId);if(!s||s.isLocal){this.stopFollowingUser();return}if(s.currentFile&&s.currentFile!==this.currentFilePath){this.navigation.navigateToFile(s.currentFile);return}this.followUserCursor(s)},followUserCursor(s,{force:e=!1}={}){if(this.currentFilePath&&this.isExcalidrawFile?.(this.currentFilePath)){this.followExcalidrawUser(s,{force:e});return}let t=this.resolveFileClientId(s.peerId),i=t!=null?this.session?.getUserViewport(t):null,n=t!=null?this.session?.getUserCursor(t):null,r=n?.cursorHead??null,o=n?.cursorLine??null,a=n?.cursorAnchor??null,c=i?.topLine??null,h=i?.viewportRatio??.35;if(!s||c==null&&(r==null||o==null)){this.followedCursorSignature="";return}let l=`${s.clientId}:${c??"no-viewport"}:${a??"no-anchor"}:${r??"no-head"}`;if(!e&&l===this.followedCursorSignature)return;(t!=null&&this.session?.scrollToUserViewport(t)||t!=null&&this.session?.scrollToUserCursor(t,"center")||r!=null&&this.session?.scrollToPosition(r,"center")||o!=null&&this.session?.scrollToLine(o,h))&&(this.followedCursorSignature=l)},followExcalidrawUser(s,{force:e=!1}={}){if(!s?.peerId||!this.currentFilePath){this.followedCursorSignature="";return}let t=`excalidraw:${this.currentFilePath}:${s.peerId}`;!e&&t===this.followedCursorSignature||Promise.resolve(this.excalidrawEmbed?.setFollowedUser(this.currentFilePath,s.peerId)).then(i=>{i===!1||this.followedUserClientId!==s.clientId||(this.followedCursorSignature=t)}).catch(()=>{})},resolveFileClientId(s){if(!s||!this.session?.awareness)return null;for(let[e,t]of this.session.awareness.getStates())if(t.user?.peerId===s)return e;return null}};var Cs="image/png,image/jpeg,image/webp,image/gif,image/svg+xml",Pi={initialize(){this.themeController.initialize(),this.previewRenderer.applyTheme(this.themeController.getTheme()),this.previewRenderer.scheduleWorkerPrewarm(),this.scheduleEditorSessionPrewarm?.(),this.outlineController.initialize(),this.layoutController.initialize(),this.scrollSyncController.initialize(),this.fileExplorer.initialize(),this.gitPanel.initialize(),this.gitDiffView.initialize(),this.fileHistoryView.initialize(),this.initializePreviewLayoutObserver(),this.syncIdentityManagementUi(),this.syncCurrentUserName(),this.syncWrapToggle(),this.syncChatNotificationButton(),this.syncFileHistoryButton({mode:"empty"}),this.renderChat(),this.gitPanel.refresh({force:!0}),this.elements.chatInput?.setAttribute("maxlength",String(this.lobbyChatMessageMaxLength)),this.bindEvents(),this.restoreSidebarState(),this.tabActivityLock.initialize(),this.tabActivityLock.tryActivate(),window.addEventListener("hashchange",()=>this.handleHashChange()),window.addEventListener("resize",this.createResizeHandler()),this.fileExplorerReadyPromise=this.fileExplorer.refresh().then(()=>{if(this.fileExplorerReady=!0,this.isTabActive)return this.handleHashChange()})},isIdentityManagedByAuth(){return this.runtimeConfig?.auth?.strategy==="oidc"&&this.runtimeConfig?.auth?.provider==="google"},bindEvents(){this.elements.emptyStateNewFileBtn?.addEventListener("click",()=>{this.fileExplorer.actionController.handleNewFile()}),this.elements.emptyStateSearchBtn?.addEventListener("click",()=>{this.toggleQuickSwitcher()}),this.elements.chatToggleButton?.addEventListener("click",()=>{this.toggleChatPanel()}),this.elements.chatForm?.addEventListener("submit",s=>{s.preventDefault(),this.handleChatSubmit()}),this.elements.chatNotificationButton?.addEventListener("click",()=>{this.handleChatNotificationToggle()}),this.elements.shareButton?.addEventListener("click",()=>{this.copyCurrentLink()}),this.elements.fileHistoryButton?.addEventListener("click",()=>{let s=this.navigation.getHashRoute();if(s.type==="git-file-preview"){this.handleGitFileHistorySelection(s.currentFilePath??s.filePath,{closeSidebarOnMobile:!0});return}this.handleGitFileHistorySelection(this.currentFilePath,{closeSidebarOnMobile:!0})}),this.elements.editNameButton?.addEventListener("click",()=>{this.openDisplayNameDialog()}),this.elements.displayNameCancel?.addEventListener("click",()=>{this.elements.displayNameDialog?.close()}),this.elements.gitCommitCancel?.addEventListener("click",()=>{this.elements.gitCommitDialog?.close()}),this.elements.gitResetCancel?.addEventListener("click",()=>{this.elements.gitResetDialog?.close()}),this.elements.gitResetSubmit?.addEventListener("click",()=>{this.handleGitResetSubmit()}),this.elements.gitCommitDialog?.addEventListener("close",()=>{this.elements.gitCommitInput&&(this.elements.gitCommitInput.value=""),this.elements.gitCommitSubmit&&(this.elements.gitCommitSubmit.textContent="Commit staged changes")}),this.elements.gitResetDialog?.addEventListener("close",()=>{this.pendingGitResetPath=null,this.elements.gitResetFileName&&(this.elements.gitResetFileName.value=""),this.elements.gitResetSubmit&&(this.elements.gitResetSubmit.textContent="Reset File")}),this.elements.markdownToolbar?.addEventListener("click",s=>{let t=(s.target instanceof Element?s.target.closest("[data-markdown-action]"):null)?.getAttribute("data-markdown-action");t&&this.applyMarkdownToolbarAction(t)}),this.elements.displayNameForm?.addEventListener("submit",s=>{s.preventDefault(),this.handleDisplayNameSubmit()}),this.elements.gitCommitForm?.addEventListener("submit",s=>{s.preventDefault(),this.handleGitCommitSubmit()}),this.elements.tabLockTakeoverButton?.addEventListener("click",()=>{this.handleTabTakeover()}),this.elements.toggleWrapButton?.addEventListener("click",()=>{this.toggleLineWrapping()}),this.elements.previewContent?.addEventListener("click",s=>{let e=s.target.closest("a.wiki-link[data-wiki-target]");e&&(s.preventDefault(),this.handleWikiLinkClick(e.dataset.wikiTarget))}),this.elements.sidebarToggle?.addEventListener("click",()=>{this.toggleSidebar()}),this.elements.sidebarClose?.addEventListener("click",()=>{this.closeSidebarOnMobile()}),this.elements.filesSidebarTab?.addEventListener("click",()=>{this.setSidebarTab("files")}),this.elements.gitSidebarTab?.addEventListener("click",()=>{this.gitRepoAvailable&&this.setSidebarTab("git")}),document.addEventListener("pointerdown",s=>{this.chatIsOpen&&(this.elements.chatContainer?.contains(s.target)||this.closeChatPanel())}),document.addEventListener("keydown",s=>{if(s.key==="Escape"&&this.chatIsOpen){this.closeChatPanel();return}(s.metaKey||s.ctrlKey)&&s.key==="k"&&(s.preventDefault(),this.toggleQuickSwitcher())})},isMobileViewport(){return this.mobileBreakpointQuery.matches},closeSidebarOnMobile(){let s=this.elements.sidebar;!s||!this.isMobileViewport()||s.classList.contains("collapsed")||this.setSidebarVisibility(!1)},toggleSidebar(){let s=this.elements.sidebar;if(!s)return;let e=s.classList.contains("collapsed");this.setSidebarVisibility(e)},restoreSidebarState(){if(!this.elements.sidebar)return;let e=this.isMobileViewport(),t=this.preferences.getSidebarVisible(),i=!0;t==="true"?i=!0:(t==="false"||e)&&(i=!1),this.applySidebarVisibility(i)},setSidebarVisibility(s){this.applySidebarVisibility(s),this.preferences.setSidebarVisible(s)},applySidebarVisibility(s){let e=this.elements.sidebar;if(!e)return;let t=!s,i=t&&this.isMobileViewport();e.classList.toggle("collapsed",t),e.toggleAttribute("hidden",i),e.setAttribute("aria-hidden",i?"true":"false"),e.inert=t},setSidebarTab(s){let e=s==="git"&&this.gitRepoAvailable?"git":"files";this.activeSidebarTab=e,this.elements.filesSidebarTab?.classList.toggle("active",e==="files"),this.elements.gitSidebarTab?.classList.toggle("active",e==="git"),document.getElementById("fileTree")?.classList.toggle("hidden",e!=="files"),this.elements.fileSearch?.classList.toggle("hidden",e!=="files"),this.elements.gitSearch?.classList.toggle("hidden",e!=="git"),document.getElementById("gitPanel")?.classList.toggle("active",e==="git"),document.getElementById("gitPanel")?.classList.toggle("hidden",e!=="git"),this.gitPanel.setActive(e==="git")},applyMarkdownToolbarAction(s){if(!this.session||!Y(this.currentFilePath))return;if(s==="image"){this.handleToolbarImageInsert();return}this.session.applyMarkdownToolbarAction(s)||this.toastController.show("Formatting action is unavailable")},async handleToolbarImageInsert(){let s=await this.pickImageFile();s&&await this.handleEditorImageInsert(s)},pickImageFile(){return new Promise(s=>{let e=document.createElement("input");e.type="file",e.accept=Cs,e.style.position="fixed",e.style.left="-9999px",document.body.appendChild(e);let t=!1,i=null,n=o=>{t||(t=!0,i&&window.clearTimeout(i),window.removeEventListener("focus",r),e.remove(),s(o))},r=()=>{i=window.setTimeout(()=>{t||e.files?.length||n(null)},250)};e.addEventListener("change",()=>{n(e.files?.[0]??null)},{once:!0}),e.addEventListener("cancel",()=>{n(null)},{once:!0}),window.addEventListener("focus",r,{once:!0}),e.click()})},async handleEditorImageInsert(s){if(!this.session||!Y(this.currentFilePath))return console.warn("[ui] Ignoring image insert because there is no active markdown session.",{currentFilePath:this.currentFilePath,hasSession:!!this.session}),!1;let e=this.currentFilePath,t=this.session;try{console.debug("[ui] Uploading image attachment.",{fileName:s?.name||"",size:s?.size??null,sourcePath:e,type:s?.type||""});let i=await this.vaultApiClient.uploadImageAttachment({file:s,fileName:s?.name||"",sourcePath:e});return await this.fileExplorer.refresh(),this.currentFilePath===e&&this.session&&this.session===t&&typeof i?.markdown=="string"&&(console.debug("[ui] Inserting uploaded image markdown into the editor.",{sourcePath:e,storedPath:i.path??""}),this.session.insertText(i.markdown)),!0}catch(i){return console.error("[ui] Failed to insert image attachment:",i),this.toastController.show(i.message||"Failed to upload image"),!1}},handleThemeChange(s){this.previewRenderer.applyTheme(s),!this.isExcalidrawFile(this.currentFilePath)&&!this.isImageFile?.(this.currentFilePath)&&this.previewRenderer.queueRender(),this.session?.applyTheme(s),this.excalidrawEmbed.updateTheme(s)},handleConnectionChange(s){this.connectionState=s,s?.firstConnection&&this.recordFileOpenMetric?.("ws_connected",{status:s.status}),this.renderPresence(),s.unreachable&&!this.connectionHelpShown&&(this.connectionHelpShown=!0,this.toastController.show(`Cannot reach server at ${s.wsBaseUrl}`,6e3))},openDisplayNameDialog({mode:s="edit"}={}){if(this.isIdentityManagedByAuth()||!this.isTabActive)return;let e=this.elements.displayNameDialog,t=this.elements.displayNameInput,i=this.elements.displayNameTitle,n=this.elements.displayNameCopy,r=this.elements.displayNameCancel,o=this.elements.displayNameSubmit;if(!e||!t)return;let a=s==="onboarding";i&&(i.textContent=a?"Choose your display name":"Update display name"),n&&(n.textContent=a?"Pick a name collaborators will see. You can skip for now and continue as a guest.":"Your name will be visible to everyone editing this vault."),r&&(r.textContent=a?"Skip for now":"Cancel"),o&&(o.textContent=a?"Continue":"Save name"),t.value=a?"":this.getCurrentUserName(),!e.open&&(typeof e.showModal=="function"?e.showModal():e.setAttribute("open","true"),requestAnimationFrame(()=>{t.focus(),t.select()}))},promptForDisplayNameIfNeeded(){!this.isTabActive||this._hasPromptedForDisplayName||this.getStoredUserName()||this.isIdentityManagedByAuth()||(this._hasPromptedForDisplayName=!0,requestAnimationFrame(()=>{this.openDisplayNameDialog({mode:"onboarding"})}))},handleDisplayNameSubmit(){if(this.isIdentityManagedByAuth())return;let s=this.elements.displayNameInput,e=this.elements.displayNameDialog;if(!s||!e)return;let t=this.session?this.session.setUserName(s.value):Xt(s.value);if(!t){s.focus(),this.toastController.show(`Name must be 1-${24} characters`);return}this.preferences.setUserName(t),this.lobby.setUserName(t),this.excalidrawEmbed.updateLocalUser(this.lobby.getLocalUser()),this.syncCurrentUserName(),this.renderChat(),e.close()},async copyCurrentLink(){try{await navigator.clipboard.writeText(window.location.href),this.toastController.show("Link copied")}catch{this.toastController.show("Failed to copy link")}},getCurrentUser(){return this.globalUsers.find(s=>s.isLocal)??this.session?.getLocalUser()??this.lobby?.getLocalUser()??null},getCurrentUserName(){return this.getCurrentUser()?.name??this.getStoredUserName()??""},getStoredUserName(){return this.preferences.getUserName()},syncCurrentUserName(){let s=this.elements.currentUserName;if(!s)return;let e=this.getCurrentUserName();s.textContent=e||"Set name",s.classList.toggle("has-name",!!e),this.isIdentityManagedByAuth()||this.elements.editNameButton?.setAttribute("aria-label",`${e||"Set name"}. Change display name`)},syncIdentityManagementUi(){let s=this.isIdentityManagedByAuth();this.elements.editNameButton?.classList.toggle("hidden",s),this.elements.editNameButton?.toggleAttribute("disabled",s),s&&this.elements.displayNameDialog?.open&&this.elements.displayNameDialog.close()},toggleLineWrapping(){let e=!(this.session?.isLineWrappingEnabled()??this.getStoredLineWrapping());this.session?.setLineWrapping(e),this.preferences.setLineWrappingEnabled(e),this.syncWrapToggle(e),this.session?.requestMeasure(),this.scrollSyncController.syncPreviewToEditor()},getStoredLineWrapping(){return this.preferences.getLineWrappingEnabled()},handleTabTakeover(){this.tabActivityLock.tryActivate({takeover:!0})},handleTabActivated({takeover:s=!1}={}){let e=!this.isTabActive;this.isTabActive=!0,this.hideTabLockOverlay(),this.lobby.provider||this.lobby.connect(),this.workspaceSync.provider||this.workspaceSync.connect(),e&&(this.fileExplorerReady&&this.handleHashChange(),this.promptForDisplayNameIfNeeded()),s&&this.toastController.show("This tab is now active")},async handleTabBlocked({reason:s}={}){let e=this.isTabActive,t=this.currentFilePath,i=!!(t&&this.isExcalidrawFile?.(t));this.isTabActive=!1,this.elements.displayNameDialog?.open&&this.elements.displayNameDialog.close(),this.lobby.disconnect(),this.workspaceSync.disconnect(),this.globalUsers=[],this.chatMessages=[],this.chatMessageIds.clear(),this.chatUnreadCount=0,this.chatInitialSyncComplete=!1,this.followedUserClientId=null,this.followedCursorSignature="",this.connectionState={status:"disconnected",unreachable:!1},this.showTabLockOverlay({reason:s}),i&&await this.excalidrawEmbed.prepareFileDisconnect(t),this.showEmptyState(),this.renderChat(),e&&s==="taken-over"&&this.toastController.show("Another tab took over this session")},showTabLockOverlay({reason:s}={}){let e=this.elements.tabLockOverlay,t=this.elements.tabLockTitle,i=this.elements.tabLockCopy;e&&(t&&(t.textContent=s==="taken-over"?"This tab is no longer active":"This vault is active in another tab"),i&&(i.textContent=s==="taken-over"?"Another tab took over the live session. This tab is now disconnected until you explicitly take over here again.":"To avoid duplicate presence and chat, only one tab can stay connected at a time. Use the other tab, or take over the session here."),e.classList.remove("hidden"))},hideTabLockOverlay(){this.elements.tabLockOverlay?.classList.add("hidden")},syncWrapToggle(s){let e=s??this.session?.isLineWrappingEnabled()??this.getStoredLineWrapping(),t=this.elements.wrapToggleLabel,i=this.elements.toggleWrapButton,n=e?"Wrap on":"Wrap off";t&&(t.textContent=n),i&&i.setAttribute("aria-label",`${n}. ${e?"Disable line wrap":"Enable line wrap"}`)},scheduleBacklinkRefresh(){clearTimeout(this._backlinkRefreshTimer),this._backlinkRefreshTimer=setTimeout(()=>{Ee(this.currentFilePath)&&this.backlinksPanel.load(this.currentFilePath)},2e3)},showEditorLoading(){this.elements.editorContainer&&(this.elements.editorContainer.classList.add("is-loading-editor"),this.elements.editorContainer.innerHTML=`
|
|
30
30
|
<div class="editor-loading" id="editorLoading">
|
|
31
31
|
<div class="loading-spinner"></div>
|
|
32
32
|
<span class="loading-text">Loading file...</span>
|
|
33
33
|
</div>`)},hideEditorLoading(){this.elements.editorContainer&&(this.elements.editorContainer.classList.remove("is-loading-editor"),this.elements.editorContainer.querySelector("#editorLoading")?.remove())},showEditorLoadError(){this.elements.editorContainer&&(this.elements.editorContainer.classList.remove("is-loading-editor"),this.elements.editorContainer.innerHTML=`
|
|
34
34
|
<div class="editor-loading" id="editorLoading">
|
|
35
35
|
<span class="loading-text">Failed to load file</span>
|
|
36
|
-
</div>`)},clearInitialFileBootstrap(){document.documentElement.removeAttribute("data-initial-file-requested")}};var gi={isExcalidrawFile(n){return qt(n)},isImageFile(n){return ye(n)},isMermaidFile(n){return ge(n)},isPlantUmlFile(n){return we(n)},createDiagramPreviewDocument(n,e=""){return this.workspacePreviewController.createDiagramPreviewDocument(n,e)},getPreviewSource(){return this.workspacePreviewController.getPreviewSource(this.currentFilePath)},getDisplayName(n){return q(String(n??"").split("/").pop())},resetPreviewMode(){this.workspacePreviewController.resetPreviewMode()},syncFileChrome(n){this.workspacePreviewController.syncFileChrome(n)},renderExcalidrawFilePreview(n){this.workspacePreviewController.renderExcalidrawFilePreview(n)},renderImageFilePreview(n){this.workspacePreviewController.renderImageFilePreview(n)},createResizeHandler(){return this.workspacePreviewController.createResizeHandler(()=>this.restoreSidebarState())},initializePreviewLayoutObserver(){this._previewLayoutResizeObserver?.disconnect(),this._previewLayoutResizeObserver=this.workspacePreviewController.initializePreviewLayoutObserver(()=>this.schedulePreviewLayoutSync())},schedulePreviewLayoutSync({delayMs:n=120}={}){this.workspacePreviewController.schedulePreviewLayoutSync({delayMs:n,hydrationPaused:this._previewHydrationPaused,previewLayoutSyncTimer:this._previewLayoutSyncTimer,setPendingPreviewLayoutSync:e=>{this._pendingPreviewLayoutSync=e},setPreviewLayoutSyncTimer:e=>{this._previewLayoutSyncTimer=e}})},handleEditorScrollActivityChange(n){this.workspacePreviewController.handleEditorScrollActivityChange({isActive:n,pendingPreviewLayoutSync:this._pendingPreviewLayoutSync,previewLayoutSyncTimer:this._previewLayoutSyncTimer,setHydrationPaused:e=>{this._previewHydrationPaused=e},setPendingPreviewLayoutSync:e=>{this._pendingPreviewLayoutSync=e},setPreviewLayoutSyncTimer:e=>{this._previewLayoutSyncTimer=e}})},async handleHashChange(){await this.workspaceRouteController.handleHashChange()},showEmptyState(){clearTimeout(this._previewLayoutSyncTimer),this._previewLayoutSyncTimer=null,this._pendingPreviewLayoutSync=!1,this._previewHydrationPaused=!1,this.workspaceRouteController.showEmptyState()},showDiffState(){clearTimeout(this._previewLayoutSyncTimer),this._previewLayoutSyncTimer=null,this._pendingPreviewLayoutSync=!1,this._previewHydrationPaused=!1,this.workspaceRouteController.showDiffState()},async openFile(n){await this.workspaceRouteController.openFile(n)},cleanupSession(){this.workspaceRouteController.cleanupSession()},handleWikiLinkClick(n){this.wikiLinkFileController.handleWikiLinkClick(n)},normalizeNewWikiFilePath(n){return this.wikiLinkFileController.normalizeNewWikiFilePath(n)},async createAndOpenFile(n,e){await this.wikiLinkFileController.createAndOpenFile(n,e)},handleFileSelection(n,{closeSidebarOnMobile:e=!1}={}){this.workspaceRouteController.handleFileSelection(n,{closeSidebarOnMobile:e})}};var hn="__lobby__",Lt=280,wi=40;function dn(n){return String(n??"").replace(/\s+/g," ").trim().slice(0,Lt)||null}function yi(n){return globalThis.crypto?.randomUUID?globalThis.crypto.randomUUID():`${n||"user"}-${Date.now()}-${Math.random().toString(36).slice(2,10)}`}function Pt(n){if(!n||typeof n!="object"||typeof n.id!="string")return null;let e=n.workspaceChange&&typeof n.workspaceChange=="object"?n.workspaceChange:{};return{action:typeof n.action=="string"?n.action:"git",createdAt:Number.isFinite(n.createdAt)?n.createdAt:Date.now(),id:n.id,peerId:typeof n.peerId=="string"?n.peerId:null,sourceRef:typeof n.sourceRef=="string"?n.sourceRef:null,workspaceChange:{changedPaths:Array.isArray(e.changedPaths)?e.changedPaths.filter(Boolean):[],deletedPaths:Array.isArray(e.deletedPaths)?e.deletedPaths.filter(Boolean):[],refreshExplorer:e.refreshExplorer!==!1,renamedPaths:Array.isArray(e.renamedPaths)?e.renamedPaths.filter(t=>t?.oldPath&&t?.newPath):[]}}}var ze=class{constructor({preferredUserName:e,onChange:t,onChatChange:i,onWorkspaceEvent:s}){this.onChange=t,this.onChatChange=i,this.onWorkspaceEvent=s,this.wsBaseUrl=pe(),this.ydoc=new Ce,this.chatMessages=this.ydoc.getArray("chat-messages"),this.workspaceEvents=this.ydoc.getArray("workspace-events"),this.provider=null,this.awareness=null,this.localUser=jt(e),this.currentFile=null,this._connected=!1,this._didInitialSync=!1,this.seenWorkspaceEventIds=new Set,this.handleAwarenessChange=()=>{this._emitChange()},this.handleChatMessagesChange=()=>{this._emitChatChange()},this.handleWorkspaceEventsChange=()=>{this._emitWorkspaceEvents()}}connect(){this.provider||(this._didInitialSync=!1,this.provider=new Ee(this.wsBaseUrl,hn,this.ydoc,{disableBc:!0,maxBackoffTime:5e3}),ke(this.provider),this.awareness=this.provider.awareness,this.awareness.setLocalStateField("user",this.localUser),this.awareness.setLocalStateField("currentFile",this.currentFile),this.awareness.on("change",this.handleAwarenessChange),this.chatMessages.observe(this.handleChatMessagesChange),this.workspaceEvents.observe(this.handleWorkspaceEventsChange),this.provider.on("status",({status:e})=>{this._connected=e==="connected"}),this.provider.on("sync",e=>{!e||this._didInitialSync||(this._didInitialSync=!0,this._primeWorkspaceEventCache(),this._emitChange(),this._emitChatChange({initial:!0}))}))}setCurrentFile(e){this.currentFile=e,this.awareness&&this.awareness.setLocalStateField("currentFile",e)}setUserName(e){e&&(this.localUser={...this.localUser,name:e},this.awareness&&this.awareness.setLocalStateField("user",this.localUser))}getLocalUser(){return this.localUser}sendChatMessage(e){let t=dn(e);if(!t)return null;let i={createdAt:Date.now(),filePath:this.currentFile??null,id:yi(this.localUser.peerId),peerId:this.localUser.peerId,text:t,userColor:this.localUser.color,userName:this.localUser.name};return this.ydoc.transact(()=>{this.chatMessages.push([i]);let s=this.chatMessages.length-wi;s>0&&this.chatMessages.delete(0,s)},"lobby-chat-message"),i}sendWorkspaceEvent({action:e="git",sourceRef:t=null,workspaceChange:i={}}={}){let s=Pt({action:e,createdAt:Date.now(),id:yi(this.localUser.peerId),peerId:this.localUser.peerId,sourceRef:t,workspaceChange:i});return s?(this.ydoc.transact(()=>{this.workspaceEvents.push([s]);let r=this.workspaceEvents.length-wi;r>0&&this.workspaceEvents.delete(0,r)},"lobby-workspace-event"),this.seenWorkspaceEventIds.add(s.id),s):null}getMessages(){return this.chatMessages.toArray().filter(e=>e&&typeof e.id=="string"&&typeof e.peerId=="string"&&typeof e.text=="string"&&typeof e.userName=="string")}getUsers(){if(!this.awareness)return[];let e=[];return this.awareness.getStates().forEach((t,i)=>{t.user&&e.push({...t.user,clientId:i,currentFile:t.currentFile??null,isLocal:i===this.awareness.clientID})}),e}getConnectionState(){return this._connected?{status:"connected",unreachable:!1}:this.provider?{status:"connecting",unreachable:!1}:{status:"disconnected",unreachable:!1}}disconnect(){this.provider&&(this.awareness?.off("change",this.handleAwarenessChange),this.chatMessages?.unobserve(this.handleChatMessagesChange),this.workspaceEvents?.unobserve(this.handleWorkspaceEventsChange)),this.provider?.disconnect(),this.provider?.destroy(),this.provider=null,this.awareness=null,this._connected=!1,this._didInitialSync=!1,this.seenWorkspaceEventIds.clear()}destroy(){this.disconnect(),this.ydoc?.destroy(),this.ydoc=null}_emitChange(){this.onChange?.(this.getUsers())}_emitChatChange(e={}){this.onChatChange?.(this.getMessages(),e)}_primeWorkspaceEventCache(){this.workspaceEvents.toArray().forEach(e=>{let t=Pt(e);t&&this.seenWorkspaceEventIds.add(t.id)})}_emitWorkspaceEvents(){if(!this._didInitialSync){this._primeWorkspaceEventCache();return}this.workspaceEvents.toArray().forEach(e=>{let t=Pt(e);!t||this.seenWorkspaceEventIds.has(t.id)||(this.seenWorkspaceEventIds.add(t.id),t.peerId!==this.localUser.peerId&&this.onWorkspaceEvent?.(t))})}};var Ue=class{getHashRoute(){return Qt()}navigateToFile(e){Yt(e)}navigateToGitDiff(e){Zt(e)}};var $e=class{constructor({NotificationImpl:e=globalThis.Notification,focusWindow:t=()=>globalThis.window?.focus?.()}={}){this.NotificationImpl=e,this.focusWindow=t}getPermission(){return typeof this.NotificationImpl!="function"?"unsupported":this.NotificationImpl.permission}async requestPermission(){return typeof this.NotificationImpl!="function"?"unsupported":this.NotificationImpl.requestPermission()}createNotification({body:e,onClick:t,tag:i,title:s}){if(typeof this.NotificationImpl!="function")return null;let r=new this.NotificationImpl(s,{body:e,tag:i});return typeof t=="function"&&r.addEventListener("click",()=>{this.focusWindow(),t()}),r}};var Oe=class{constructor({chatNotificationsKey:e,lineWrappingKey:t,sidebarVisibleKey:i,userNameKey:s,storage:r=globalThis.localStorage}){this.chatNotificationsKey=e,this.lineWrappingKey=t,this.sidebarVisibleKey=i,this.storage=r,this.userNameKey=s}getUserName(){try{return this.storage.getItem(this.userNameKey)||""}catch{return""}}setUserName(e){try{this.storage.setItem(this.userNameKey,e)}catch{}}getLineWrappingEnabled(){try{return this.storage.getItem(this.lineWrappingKey)!=="false"}catch{return!0}}setLineWrappingEnabled(e){try{this.storage.setItem(this.lineWrappingKey,String(e))}catch{}}getSidebarVisible(){try{return this.storage.getItem(this.sidebarVisibleKey)}catch{return null}}setSidebarVisible(e){try{this.storage.setItem(this.sidebarVisibleKey,e?"true":"false")}catch{}}getChatNotificationsEnabled(){try{return this.storage.getItem(this.chatNotificationsKey)==="true"}catch{return!1}}setChatNotificationsEnabled(e){try{this.storage.setItem(this.chatNotificationsKey,String(e))}catch{}}};var qe="collabmd-active-tab-lock",vi="collabmd-tab-id",un="collabmd-tab-lock";function xt(){return Date.now()}function bi(){return globalThis.crypto?.randomUUID?globalThis.crypto.randomUUID():`tab-${xt()}-${Math.random().toString(36).slice(2,10)}`}function Ci(n){if(!n)return null;try{return JSON.parse(n)}catch{return null}}var We=class{constructor({heartbeatIntervalMs:e=4e3,onBlocked:t,onActivated:i,onStolen:s}={}){this.heartbeatIntervalMs=e,this.staleAfterMs=e*3,this.onBlocked=t,this.onActivated=i,this.onStolen=s,this.tabId=this.getOrCreateTabId(),this.channel=null,this.heartbeatTimer=null,this.isOwner=!1,this.handleStorageEvent=this.handleStorageEvent.bind(this),this.handlePageHide=this.handlePageHide.bind(this)}initialize(){window.addEventListener("storage",this.handleStorageEvent),window.addEventListener("pagehide",this.handlePageHide),"BroadcastChannel"in globalThis&&(this.channel=new BroadcastChannel(un),this.channel.addEventListener("message",e=>{this.handleChannelMessage(e.data)}))}destroy(){this.release(),window.removeEventListener("storage",this.handleStorageEvent),window.removeEventListener("pagehide",this.handlePageHide),this.channel?.close(),this.channel=null}tryActivate({takeover:e=!1}={}){let t=this.readLock();return this.isFreshLock(t)&&t.tabId!==this.tabId&&!e?(this.isOwner=!1,this.stopHeartbeat(),this.onBlocked?.({reason:"active-elsewhere",ownerTabId:t.tabId}),!1):(this.writeLock(),this.startHeartbeat(),this.isOwner=!0,this.channel?.postMessage({type:"claimed",takeover:e,tabId:this.tabId}),this.onActivated?.({takeover:e}),!0)}release(){this.readLock()?.tabId===this.tabId&&(localStorage.removeItem(qe),this.channel?.postMessage({type:"released",tabId:this.tabId})),this.isOwner=!1,this.stopHeartbeat()}getOrCreateTabId(){try{let e=window.sessionStorage.getItem(vi);if(e)return e;let t=bi();return window.sessionStorage.setItem(vi,t),t}catch{return bi()}}readLock(){try{return Ci(window.localStorage.getItem(qe))}catch{return null}}isFreshLock(e){return!!(e&&typeof e.tabId=="string"&&Number.isFinite(e.updatedAt)&&xt()-e.updatedAt<this.staleAfterMs)}writeLock(){try{window.localStorage.setItem(qe,JSON.stringify({tabId:this.tabId,updatedAt:xt()}))}catch{}}startHeartbeat(){this.stopHeartbeat(),this.writeLock(),this.heartbeatTimer=window.setInterval(()=>{if(!this.isOwner){this.stopHeartbeat();return}this.writeLock()},this.heartbeatIntervalMs)}stopHeartbeat(){this.heartbeatTimer&&(window.clearInterval(this.heartbeatTimer),this.heartbeatTimer=null)}handleStorageEvent(e){if(e.key!==qe)return;let t=Ci(e.newValue);this.handleExternalLockChange(t)}handleChannelMessage(e){!e||typeof e!="object"||e.tabId===this.tabId||e.type==="claimed"&&this.handleExternalLockChange(this.readLock())}handleExternalLockChange(e){this.isOwner&&this.isFreshLock(e)&&e.tabId!==this.tabId&&(this.isOwner=!1,this.stopHeartbeat(),this.onStolen?.({ownerTabId:e.tabId}))}handlePageHide(){this.release()}};function Ei(n){return encodeURIComponent(String(n??""))}async function J(n,e){let t=await n.json().catch(()=>({}));if(!n.ok||t.ok===!1){let i=new Error(t.error||e);throw i.status=n.status,i.body=t,i}return t}var Ge=class{async readTree(){let e=await fetch(C("/files"));return J(e,"Failed to load file tree")}async readFile(e){let t=await fetch(C(`/file?path=${encodeURIComponent(e)}`));return J(t,"Failed to read file")}async createFile({content:e,path:t}){let i=await fetch(C("/file"),{body:JSON.stringify({content:e,path:t}),headers:{"Content-Type":"application/json"},method:"POST"});return J(i,"Failed to create file")}async renameFile({oldPath:e,newPath:t}){let i=await fetch(C("/file"),{body:JSON.stringify({newPath:t,oldPath:e}),headers:{"Content-Type":"application/json"},method:"PATCH"});return J(i,"Failed to rename file")}async deleteFile(e){let t=await fetch(C(`/file?path=${encodeURIComponent(e)}`),{method:"DELETE"});return J(t,"Failed to delete file")}async createDirectory(e){let t=await fetch(C("/directory"),{body:JSON.stringify({path:e}),headers:{"Content-Type":"application/json"},method:"POST"});return J(t,"Failed to create folder")}async uploadImageAttachment({file:e,fileName:t="",sourcePath:i}){let s=await fetch(C("/attachments"),{body:e,headers:{"Content-Type":e?.type||"application/octet-stream","X-CollabMD-File-Name":Ei(t),"X-CollabMD-Source-Path":Ei(i)},method:"POST"});return J(s,"Failed to upload image")}},he=new Ge;var Si="__workspace__";function ki(n){return!n?.path||!n?.type?null:n.nodeType==="directory"||n.type==="directory"?{children:[],name:n.name,path:n.path,type:"directory"}:{name:n.name,path:n.path,type:n.type}}function Ft(n=[]){return n.sort((e,t)=>e.type==="directory"&&t.type!=="directory"?-1:e.type!=="directory"&&t.type==="directory"?1:e.name.localeCompare(t.name,void 0,{sensitivity:"base"})),n.forEach(e=>{Array.isArray(e.children)&&Ft(e.children)}),n}function mn(n){return n instanceof Map?n:new Map(Object.entries(n??{}))}function It(n=[],e="asc"){let t=e==="desc"?-1:1;return[...n].sort((i,s)=>{let r=i.split("/").length-s.split("/").length;return r!==0?r*t:i.localeCompare(s,void 0,{sensitivity:"base"})*t})}var Tt=class{constructor(){this.entriesByPath=new Map,this.nodesByPath=new Map,this.nodeParentPathByPath=new Map,this.roots=[]}reset(e){return this.entriesByPath=mn(e),this.nodesByPath=new Map,this.nodeParentPathByPath=new Map,this.roots=[],this.entriesByPath.forEach(t=>{let i=ki(t);i&&this.nodesByPath.set(t.path,i)}),It(Array.from(this.nodesByPath.keys())).forEach(t=>{let i=this.nodesByPath.get(t);i&&this.attachNode(t,i,this.entriesByPath.get(t)?.parentPath||"")}),Ft(this.roots),this.roots}getTree(){return this.roots}applyMapChanges(e,t){let i=[],s=[];return e.forEach((r,a)=>{r.action==="delete"?i.push(a):s.push(a)}),It(i,"desc").forEach(r=>{this.removeEntry(r)}),It(s).forEach(r=>{this.upsertEntry(r,t.get(r))}),Ft(this.roots),this.roots}removeEntry(e){let t=this.nodesByPath.get(e);if(!t){this.entriesByPath.delete(e),this.nodeParentPathByPath.delete(e);return}this.detachNode(e,t),this.nodesByPath.delete(e),this.entriesByPath.delete(e),this.nodeParentPathByPath.delete(e)}upsertEntry(e,t){if(!t?.path||!t?.type){this.removeEntry(e);return}let i=ki(t);if(!i){this.removeEntry(e);return}let r=this.nodesByPath.get(e);!r||r.type==="directory"!=(i.type==="directory")?(r&&this.detachNode(e,r),r=i,this.nodesByPath.set(e,r)):(r.name=i.name,r.path=i.path,r.type=i.type,r.type==="directory"&&!Array.isArray(r.children)&&(r.children=[]),r.type!=="directory"&&Array.isArray(r.children)&&delete r.children),this.entriesByPath.set(e,t),this.attachNode(e,r,t.parentPath||""),r.type==="directory"&&this.rehomeChildren(e)}detachNode(e,t){let i=this.nodeParentPathByPath.get(e)||"",s=i?this.nodesByPath.get(i)?.children:this.roots,r=s?.indexOf?.(t)??-1;r>=0&&s.splice(r,1),this.nodeParentPathByPath.delete(e)}attachNode(e,t,i=""){let s=this.nodesByPath.get(i)?.type==="directory"?i:"",r=this.nodeParentPathByPath.get(e);if(r===s)return;r!==void 0&&this.detachNode(e,t);let a=s?this.nodesByPath.get(s)?.children:this.roots;a.includes(t)||a.push(t),this.nodeParentPathByPath.set(e,s)}rehomeChildren(e){this.entriesByPath.forEach((t,i)=>{if(t?.parentPath!==e)return;let s=this.nodesByPath.get(i);s&&this.attachNode(i,s,e)})}},Ve=class{constructor({onTreeChange:e=()=>{},onWorkspaceEvent:t=()=>{}}={}){this.onTreeChange=e,this.onWorkspaceEvent=t,this.ydoc=new Ce,this.entries=this.ydoc.getMap("entries"),this.events=this.ydoc.getArray("events"),this.provider=null,this._didInitialSync=!1,this.seenEventIds=new Set,this.treeModel=new Tt,this.handleEntriesChange=i=>{!this._didInitialSync||!i||this.onTreeChange(this.treeModel.applyMapChanges(i.changes.keys,this.entries),{changedPaths:Array.from(i.changes.keys.keys()),reset:!1})},this.handleEventsChange=()=>{if(!this._didInitialSync){this.primeEventCache();return}this.events.toArray().forEach(i=>{let s=kt(i);!s||this.seenEventIds.has(s.id)||(this.seenEventIds.add(s.id),this.onWorkspaceEvent(s))})}}connect(){this.provider||(this._didInitialSync=!1,this.provider=new Ee(pe(),Si,this.ydoc,{disableBc:!0,maxBackoffTime:5e3}),ke(this.provider),this.entries.observe(this.handleEntriesChange),this.events.observe(this.handleEventsChange),this.provider.on("sync",e=>{!e||this._didInitialSync||(this._didInitialSync=!0,this.primeEventCache(),this.onTreeChange(this.treeModel.reset(this.entries.toJSON()),{changedPaths:[],reset:!0}))}))}primeEventCache(){this.events.toArray().forEach(e=>{let t=kt(e);t&&this.seenEventIds.add(t.id)})}disconnect(){this.entries.unobserve(this.handleEntriesChange),this.events.unobserve(this.handleEventsChange),this.provider?.disconnect(),this.provider?.destroy(),this.provider=null,this._didInitialSync=!1,this.seenEventIds.clear(),this.treeModel.reset(new Map)}destroy(){this.disconnect(),this.ydoc.destroy()}};var Ke=class{constructor({documentRef:e=document,inlinePanelElement:t=null,onFileSelect:i,panelElement:s}){this.documentRef=e,this.panelRoot=s,this.inlinePanel=t,this.onFileSelect=i,this._expanded=!1,this._currentFile=null,this._fetchController=null,this._backlinks=[];let r=this.panelRoot?.querySelector('[data-backlinks-variant="dock"]')??this.panelRoot;this.panels=[this._createPanelRef(r),this._createPanelRef(this.inlinePanel)].filter(Boolean),this.handleDocumentPointerDown=a=>{if(!this._expanded)return;let o=a?.target;o&&this.panels.some(({panel:l})=>l?.contains?.(o))||this.close()},this.handleDocumentKeyDown=a=>{!this._expanded||a?.key!=="Escape"||(a.preventDefault?.(),this.close())},this.bindEvents()}bindEvents(){this.panels.forEach(e=>{e.header?.addEventListener("click",()=>{this._backlinks.length!==0&&(this._expanded=!this._expanded,this._applyExpandState())}),e.header?.addEventListener("keydown",t=>{t.key!=="Enter"&&t.key!==" "||(t.preventDefault(),e.header.click())})}),this.documentRef?.addEventListener?.("pointerdown",this.handleDocumentPointerDown),this.documentRef?.addEventListener?.("keydown",this.handleDocumentKeyDown)}async load(e){let t=e!==this._currentFile;if(this._currentFile=e,t&&(this._expanded=!1),!e){this._backlinks=[],this._render();return}this._fetchController?.abort(),this._fetchController=new AbortController;try{let s=await(await fetch(C(`/backlinks?file=${encodeURIComponent(e)}`),{signal:this._fetchController.signal})).json();if(this._currentFile!==e)return;this._backlinks=s.backlinks??[]}catch(i){if(i.name==="AbortError")return;console.warn("[backlinks] Failed to load:",i.message),this._backlinks=[]}this._render()}clear(){this._currentFile=null,this._backlinks=[],this._expanded=!1,this._render()}close(){this._expanded&&(this._expanded=!1,this._applyExpandState())}_createPanelRef(e){return e?{panel:e,header:e.querySelector(".backlinks-header"),toggle:e.querySelector(".backlinks-toggle"),countBadge:e.querySelector(".backlinks-count"),body:e.querySelector(".backlinks-body"),list:e.querySelector(".backlinks-list")}:null}_render(){let e=this._backlinks.length,t=e===1?"Linked Mention":"Linked Mentions",i=!!this._currentFile&&e>0;this.panelRoot?.classList?.toggle("hidden",!i),this.inlinePanel?.classList?.toggle("hidden",!i),i||(this._expanded=!1),this.panels.forEach(s=>{s.countBadge.textContent=i?String(e):"",s.toggle.textContent=t,s.header?.classList.toggle("backlinks-header-empty",!i),i?this._renderList(s.list):s.list.innerHTML=""}),this._applyExpandState()}_renderList(e){if(!e)return;e.innerHTML="";let t=this.documentRef?.createDocumentFragment?.(),i=t??e;this._backlinks.forEach(s=>{i.appendChild(this._createBacklinkItem(s))}),t&&e.appendChild(t)}_createBacklinkItem(e){let t=e.file.replace(/\.md$/i,"").split("/").pop(),i=e.file.includes("/")?e.file.substring(0,e.file.lastIndexOf("/")):"",s=this.documentRef.createElement("button");s.type="button",s.className="backlink-item",s.addEventListener("click",()=>{this.close(),this.onFileSelect?.(e.file)});let r=this.documentRef.createElement("div");if(r.className="backlink-file-name",r.innerHTML=`
|
|
36
|
+
</div>`)},clearInitialFileBootstrap(){document.documentElement.removeAttribute("data-initial-file-requested")}};var ki={isExcalidrawFile(s){return jt(s)},isImageFile(s){return Ce(s)},isMermaidFile(s){return ve(s)},isPlantUmlFile(s){return be(s)},createDiagramPreviewDocument(s,e=""){return this.workspacePreviewController.createDiagramPreviewDocument(s,e)},getPreviewSource(){let s=this.getStaticPreviewDocument?.(),e=s?.currentFilePath??s?.filePath??null;return s&&e&&e===this.currentFilePath?this.isMermaidFile(this.currentFilePath)?this.createDiagramPreviewDocument("mermaid",s.content):this.isPlantUmlFile(this.currentFilePath)?this.createDiagramPreviewDocument("plantuml",s.content):String(s.content??""):this.workspacePreviewController.getPreviewSource(this.currentFilePath)},getStaticPreviewDocument(){return this._staticPreviewDocument??null},setStaticPreviewDocument(s){let e=s?.filePath??s?.path??null,t=s?.currentFilePath??e;this._staticPreviewDocument=s?{content:String(s.content??""),currentFilePath:t,fileKind:s.fileKind??he(e),filePath:e,hash:s.hash??null}:null},clearStaticPreviewDocument(){this._staticPreviewDocument=null},supportsFileHistory(s){let e=he(s);return e!==null&&e!=="image"},getDisplayName(s){return K(String(s??"").split("/").pop())},resetPreviewMode(){this.workspacePreviewController.resetPreviewMode()},syncFileChrome(s){this.workspacePreviewController.syncFileChrome(s)},renderExcalidrawFilePreview(s){this.workspacePreviewController.renderExcalidrawFilePreview(s)},renderImageFilePreview(s){this.workspacePreviewController.renderImageFilePreview(s)},renderTextFilePreview(s){this.workspacePreviewController.renderTextFilePreview(s)},createResizeHandler(){return this.workspacePreviewController.createResizeHandler(()=>this.restoreSidebarState())},initializePreviewLayoutObserver(){this._previewLayoutResizeObserver?.disconnect(),this._previewLayoutResizeObserver=this.workspacePreviewController.initializePreviewLayoutObserver(()=>this.schedulePreviewLayoutSync())},schedulePreviewLayoutSync({delayMs:s=120}={}){this.workspacePreviewController.schedulePreviewLayoutSync({delayMs:s,hydrationPaused:this._previewHydrationPaused,previewLayoutSyncTimer:this._previewLayoutSyncTimer,setPendingPreviewLayoutSync:e=>{this._pendingPreviewLayoutSync=e},setPreviewLayoutSyncTimer:e=>{this._previewLayoutSyncTimer=e}})},handleEditorScrollActivityChange(s){this.workspacePreviewController.handleEditorScrollActivityChange({isActive:s,pendingPreviewLayoutSync:this._pendingPreviewLayoutSync,previewLayoutSyncTimer:this._previewLayoutSyncTimer,setHydrationPaused:e=>{this._previewHydrationPaused=e},setPendingPreviewLayoutSync:e=>{this._pendingPreviewLayoutSync=e},setPreviewLayoutSyncTimer:e=>{this._previewLayoutSyncTimer=e}})},async handleHashChange(){await this.workspaceRouteController.handleHashChange()},showEmptyState(){clearTimeout(this._previewLayoutSyncTimer),this._previewLayoutSyncTimer=null,this._pendingPreviewLayoutSync=!1,this._previewHydrationPaused=!1,this.workspaceRouteController.showEmptyState()},showDiffState(){clearTimeout(this._previewLayoutSyncTimer),this._previewLayoutSyncTimer=null,this._pendingPreviewLayoutSync=!1,this._previewHydrationPaused=!1,this.workspaceRouteController.showDiffState()},async openFile(s){await this.workspaceRouteController.openFile(s)},cleanupSession(){this.workspaceRouteController.cleanupSession()},handleWikiLinkClick(s){this.wikiLinkFileController.handleWikiLinkClick(s)},normalizeNewWikiFilePath(s){return this.wikiLinkFileController.normalizeNewWikiFilePath(s)},async createAndOpenFile(s,e){await this.wikiLinkFileController.createAndOpenFile(s,e)},handleFileSelection(s,{closeSidebarOnMobile:e=!1}={}){this.workspaceRouteController.handleFileSelection(s,{closeSidebarOnMobile:e})}};var Ss="__lobby__",Mt=280,Li=40;function Ps(s){return String(s??"").replace(/\s+/g," ").trim().slice(0,Mt)||null}function Fi(s){return globalThis.crypto?.randomUUID?globalThis.crypto.randomUUID():`${s||"user"}-${Date.now()}-${Math.random().toString(36).slice(2,10)}`}function xt(s){if(!s||typeof s!="object"||typeof s.id!="string")return null;let e=s.workspaceChange&&typeof s.workspaceChange=="object"?s.workspaceChange:{};return{action:typeof s.action=="string"?s.action:"git",createdAt:Number.isFinite(s.createdAt)?s.createdAt:Date.now(),id:s.id,peerId:typeof s.peerId=="string"?s.peerId:null,sourceRef:typeof s.sourceRef=="string"?s.sourceRef:null,workspaceChange:{changedPaths:Array.isArray(e.changedPaths)?e.changedPaths.filter(Boolean):[],deletedPaths:Array.isArray(e.deletedPaths)?e.deletedPaths.filter(Boolean):[],refreshExplorer:e.refreshExplorer!==!1,renamedPaths:Array.isArray(e.renamedPaths)?e.renamedPaths.filter(t=>t?.oldPath&&t?.newPath):[]}}}var Ue=class{constructor({preferredUserName:e,onChange:t,onChatChange:i,onWorkspaceEvent:n}){this.onChange=t,this.onChatChange=i,this.onWorkspaceEvent=n,this.wsBaseUrl=ye(),this.ydoc=new Pe,this.chatMessages=this.ydoc.getArray("chat-messages"),this.workspaceEvents=this.ydoc.getArray("workspace-events"),this.provider=null,this.awareness=null,this.localUser=Jt(e),this.currentFile=null,this._connected=!1,this._didInitialSync=!1,this.seenWorkspaceEventIds=new Set,this.handleAwarenessChange=()=>{this._emitChange()},this.handleChatMessagesChange=()=>{this._emitChatChange()},this.handleWorkspaceEventsChange=()=>{this._emitWorkspaceEvents()}}connect(){this.provider||(this._didInitialSync=!1,this.provider=new ke(this.wsBaseUrl,Ss,this.ydoc,{disableBc:!0,maxBackoffTime:5e3}),Fe(this.provider),this.awareness=this.provider.awareness,this.awareness.setLocalStateField("user",this.localUser),this.awareness.setLocalStateField("currentFile",this.currentFile),this.awareness.on("change",this.handleAwarenessChange),this.chatMessages.observe(this.handleChatMessagesChange),this.workspaceEvents.observe(this.handleWorkspaceEventsChange),this.provider.on("status",({status:e})=>{this._connected=e==="connected"}),this.provider.on("sync",e=>{!e||this._didInitialSync||(this._didInitialSync=!0,this._primeWorkspaceEventCache(),this._emitChange(),this._emitChatChange({initial:!0}))}))}setCurrentFile(e){this.currentFile=e,this.awareness&&this.awareness.setLocalStateField("currentFile",e)}setUserName(e){e&&(this.localUser={...this.localUser,name:e},this.awareness&&this.awareness.setLocalStateField("user",this.localUser))}getLocalUser(){return this.localUser}sendChatMessage(e){let t=Ps(e);if(!t)return null;let i={createdAt:Date.now(),filePath:this.currentFile??null,id:Fi(this.localUser.peerId),peerId:this.localUser.peerId,text:t,userColor:this.localUser.color,userName:this.localUser.name};return this.ydoc.transact(()=>{this.chatMessages.push([i]);let n=this.chatMessages.length-Li;n>0&&this.chatMessages.delete(0,n)},"lobby-chat-message"),i}sendWorkspaceEvent({action:e="git",sourceRef:t=null,workspaceChange:i={}}={}){let n=xt({action:e,createdAt:Date.now(),id:Fi(this.localUser.peerId),peerId:this.localUser.peerId,sourceRef:t,workspaceChange:i});return n?(this.ydoc.transact(()=>{this.workspaceEvents.push([n]);let r=this.workspaceEvents.length-Li;r>0&&this.workspaceEvents.delete(0,r)},"lobby-workspace-event"),this.seenWorkspaceEventIds.add(n.id),n):null}getMessages(){return this.chatMessages.toArray().filter(e=>e&&typeof e.id=="string"&&typeof e.peerId=="string"&&typeof e.text=="string"&&typeof e.userName=="string")}getUsers(){if(!this.awareness)return[];let e=[];return this.awareness.getStates().forEach((t,i)=>{t.user&&e.push({...t.user,clientId:i,currentFile:t.currentFile??null,isLocal:i===this.awareness.clientID})}),e}getConnectionState(){return this._connected?{status:"connected",unreachable:!1}:this.provider?{status:"connecting",unreachable:!1}:{status:"disconnected",unreachable:!1}}disconnect(){this.provider&&(this.awareness?.off("change",this.handleAwarenessChange),this.chatMessages?.unobserve(this.handleChatMessagesChange),this.workspaceEvents?.unobserve(this.handleWorkspaceEventsChange)),this.provider?.disconnect(),this.provider?.destroy(),this.provider=null,this.awareness=null,this._connected=!1,this._didInitialSync=!1,this.seenWorkspaceEventIds.clear()}destroy(){this.disconnect(),this.ydoc?.destroy(),this.ydoc=null}_emitChange(){this.onChange?.(this.getUsers())}_emitChatChange(e={}){this.onChatChange?.(this.getMessages(),e)}_primeWorkspaceEventCache(){this.workspaceEvents.toArray().forEach(e=>{let t=xt(e);t&&this.seenWorkspaceEventIds.add(t.id)})}_emitWorkspaceEvents(){if(!this._didInitialSync){this._primeWorkspaceEventCache();return}this.workspaceEvents.toArray().forEach(e=>{let t=xt(e);!t||this.seenWorkspaceEventIds.has(t.id)||(this.seenWorkspaceEventIds.add(t.id),t.peerId!==this.localUser.peerId&&this.onWorkspaceEvent?.(t))})}};var qe=class{getHashRoute(){return ei()}navigateToFile(e){ti(e)}navigateToGitDiff(e){ii(e)}navigateToGitCommit(e){si(e)}navigateToGitHistory(){ni()}navigateToGitFileHistory(e){ri(e)}navigateToGitFilePreview(e){oi(e)}};var We=class{constructor({NotificationImpl:e=globalThis.Notification,focusWindow:t=()=>globalThis.window?.focus?.()}={}){this.NotificationImpl=e,this.focusWindow=t}getPermission(){return typeof this.NotificationImpl!="function"?"unsupported":this.NotificationImpl.permission}async requestPermission(){return typeof this.NotificationImpl!="function"?"unsupported":this.NotificationImpl.requestPermission()}createNotification({body:e,onClick:t,tag:i,title:n}){if(typeof this.NotificationImpl!="function")return null;let r=new this.NotificationImpl(n,{body:e,tag:i});return typeof t=="function"&&r.addEventListener("click",()=>{this.focusWindow(),t()}),r}};var Ge=class{constructor({chatNotificationsKey:e,lineWrappingKey:t,sidebarVisibleKey:i,userNameKey:n,storage:r=globalThis.localStorage}){this.chatNotificationsKey=e,this.lineWrappingKey=t,this.sidebarVisibleKey=i,this.storage=r,this.userNameKey=n}getUserName(){try{return this.storage.getItem(this.userNameKey)||""}catch{return""}}setUserName(e){try{this.storage.setItem(this.userNameKey,e)}catch{}}getLineWrappingEnabled(){try{return this.storage.getItem(this.lineWrappingKey)!=="false"}catch{return!0}}setLineWrappingEnabled(e){try{this.storage.setItem(this.lineWrappingKey,String(e))}catch{}}getSidebarVisible(){try{return this.storage.getItem(this.sidebarVisibleKey)}catch{return null}}setSidebarVisible(e){try{this.storage.setItem(this.sidebarVisibleKey,e?"true":"false")}catch{}}getChatNotificationsEnabled(){try{return this.storage.getItem(this.chatNotificationsKey)==="true"}catch{return!1}}setChatNotificationsEnabled(e){try{this.storage.setItem(this.chatNotificationsKey,String(e))}catch{}}};var Ke="collabmd-active-tab-lock",xi="collabmd-tab-id",ks="collabmd-tab-lock";function Tt(){return Date.now()}function Mi(){return globalThis.crypto?.randomUUID?globalThis.crypto.randomUUID():`tab-${Tt()}-${Math.random().toString(36).slice(2,10)}`}function Ti(s){if(!s)return null;try{return JSON.parse(s)}catch{return null}}var Ve=class{constructor({heartbeatIntervalMs:e=4e3,onBlocked:t,onActivated:i,onStolen:n}={}){this.heartbeatIntervalMs=e,this.staleAfterMs=e*3,this.onBlocked=t,this.onActivated=i,this.onStolen=n,this.tabId=this.getOrCreateTabId(),this.channel=null,this.heartbeatTimer=null,this.isOwner=!1,this.handleStorageEvent=this.handleStorageEvent.bind(this),this.handlePageHide=this.handlePageHide.bind(this)}initialize(){window.addEventListener("storage",this.handleStorageEvent),window.addEventListener("pagehide",this.handlePageHide),"BroadcastChannel"in globalThis&&(this.channel=new BroadcastChannel(ks),this.channel.addEventListener("message",e=>{this.handleChannelMessage(e.data)}))}destroy(){this.release(),window.removeEventListener("storage",this.handleStorageEvent),window.removeEventListener("pagehide",this.handlePageHide),this.channel?.close(),this.channel=null}tryActivate({takeover:e=!1}={}){let t=this.readLock();return this.isFreshLock(t)&&t.tabId!==this.tabId&&!e?(this.isOwner=!1,this.stopHeartbeat(),this.onBlocked?.({reason:"active-elsewhere",ownerTabId:t.tabId}),!1):(this.writeLock(),this.startHeartbeat(),this.isOwner=!0,this.channel?.postMessage({type:"claimed",takeover:e,tabId:this.tabId}),this.onActivated?.({takeover:e}),!0)}release(){this.readLock()?.tabId===this.tabId&&(localStorage.removeItem(Ke),this.channel?.postMessage({type:"released",tabId:this.tabId})),this.isOwner=!1,this.stopHeartbeat()}getOrCreateTabId(){try{let e=window.sessionStorage.getItem(xi);if(e)return e;let t=Mi();return window.sessionStorage.setItem(xi,t),t}catch{return Mi()}}readLock(){try{return Ti(window.localStorage.getItem(Ke))}catch{return null}}isFreshLock(e){return!!(e&&typeof e.tabId=="string"&&Number.isFinite(e.updatedAt)&&Tt()-e.updatedAt<this.staleAfterMs)}writeLock(){try{window.localStorage.setItem(Ke,JSON.stringify({tabId:this.tabId,updatedAt:Tt()}))}catch{}}startHeartbeat(){this.stopHeartbeat(),this.writeLock(),this.heartbeatTimer=window.setInterval(()=>{if(!this.isOwner){this.stopHeartbeat();return}this.writeLock()},this.heartbeatIntervalMs)}stopHeartbeat(){this.heartbeatTimer&&(window.clearInterval(this.heartbeatTimer),this.heartbeatTimer=null)}handleStorageEvent(e){if(e.key!==Ke)return;let t=Ti(e.newValue);this.handleExternalLockChange(t)}handleChannelMessage(e){!e||typeof e!="object"||e.tabId===this.tabId||e.type==="claimed"&&this.handleExternalLockChange(this.readLock())}handleExternalLockChange(e){this.isOwner&&this.isFreshLock(e)&&e.tabId!==this.tabId&&(this.isOwner=!1,this.stopHeartbeat(),this.onStolen?.({ownerTabId:e.tabId}))}handlePageHide(){this.release()}};function Ii(s){return encodeURIComponent(String(s??""))}async function J(s,e){let t=await s.json().catch(()=>({}));if(!s.ok||t.ok===!1){let i=new Error(t.error||e);throw i.status=s.status,i.body=t,i}return t}var je=class{async readTree(){let e=await fetch(b("/files"));return J(e,"Failed to load file tree")}async readFile(e){let t=await fetch(b(`/file?path=${encodeURIComponent(e)}`));return J(t,"Failed to read file")}async createFile({content:e,path:t}){let i=await fetch(b("/file"),{body:JSON.stringify({content:e,path:t}),headers:{"Content-Type":"application/json"},method:"POST"});return J(i,"Failed to create file")}async renameFile({oldPath:e,newPath:t}){let i=await fetch(b("/file"),{body:JSON.stringify({newPath:t,oldPath:e}),headers:{"Content-Type":"application/json"},method:"PATCH"});return J(i,"Failed to rename file")}async deleteFile(e){let t=await fetch(b(`/file?path=${encodeURIComponent(e)}`),{method:"DELETE"});return J(t,"Failed to delete file")}async createDirectory(e){let t=await fetch(b("/directory"),{body:JSON.stringify({path:e}),headers:{"Content-Type":"application/json"},method:"POST"});return J(t,"Failed to create folder")}async uploadImageAttachment({file:e,fileName:t="",sourcePath:i}){let n=await fetch(b("/attachments"),{body:e,headers:{"Content-Type":e?.type||"application/octet-stream","X-CollabMD-File-Name":Ii(t),"X-CollabMD-Source-Path":Ii(i)},method:"POST"});return J(n,"Failed to upload image")}},ue=new je;var Ai="__workspace__";function Bi(s){return!s?.path||!s?.type?null:s.nodeType==="directory"||s.type==="directory"?{children:[],name:s.name,path:s.path,type:"directory"}:{name:s.name,path:s.path,type:s.type}}function At(s=[]){return s.sort((e,t)=>e.type==="directory"&&t.type!=="directory"?-1:e.type!=="directory"&&t.type==="directory"?1:e.name.localeCompare(t.name,void 0,{sensitivity:"base"})),s.forEach(e=>{Array.isArray(e.children)&&At(e.children)}),s}function Ls(s){return s instanceof Map?s:new Map(Object.entries(s??{}))}function It(s=[],e="asc"){let t=e==="desc"?-1:1;return[...s].sort((i,n)=>{let r=i.split("/").length-n.split("/").length;return r!==0?r*t:i.localeCompare(n,void 0,{sensitivity:"base"})*t})}var Bt=class{constructor(){this.entriesByPath=new Map,this.nodesByPath=new Map,this.nodeParentPathByPath=new Map,this.roots=[]}reset(e){return this.entriesByPath=Ls(e),this.nodesByPath=new Map,this.nodeParentPathByPath=new Map,this.roots=[],this.entriesByPath.forEach(t=>{let i=Bi(t);i&&this.nodesByPath.set(t.path,i)}),It(Array.from(this.nodesByPath.keys())).forEach(t=>{let i=this.nodesByPath.get(t);i&&this.attachNode(t,i,this.entriesByPath.get(t)?.parentPath||"")}),At(this.roots),this.roots}getTree(){return this.roots}applyMapChanges(e,t){let i=[],n=[];return e.forEach((r,o)=>{r.action==="delete"?i.push(o):n.push(o)}),It(i,"desc").forEach(r=>{this.removeEntry(r)}),It(n).forEach(r=>{this.upsertEntry(r,t.get(r))}),At(this.roots),this.roots}removeEntry(e){let t=this.nodesByPath.get(e);if(!t){this.entriesByPath.delete(e),this.nodeParentPathByPath.delete(e);return}this.detachNode(e,t),this.nodesByPath.delete(e),this.entriesByPath.delete(e),this.nodeParentPathByPath.delete(e)}upsertEntry(e,t){if(!t?.path||!t?.type){this.removeEntry(e);return}let i=Bi(t);if(!i){this.removeEntry(e);return}let r=this.nodesByPath.get(e);!r||r.type==="directory"!=(i.type==="directory")?(r&&this.detachNode(e,r),r=i,this.nodesByPath.set(e,r)):(r.name=i.name,r.path=i.path,r.type=i.type,r.type==="directory"&&!Array.isArray(r.children)&&(r.children=[]),r.type!=="directory"&&Array.isArray(r.children)&&delete r.children),this.entriesByPath.set(e,t),this.attachNode(e,r,t.parentPath||""),r.type==="directory"&&this.rehomeChildren(e)}detachNode(e,t){let i=this.nodeParentPathByPath.get(e)||"",n=i?this.nodesByPath.get(i)?.children:this.roots,r=n?.indexOf?.(t)??-1;r>=0&&n.splice(r,1),this.nodeParentPathByPath.delete(e)}attachNode(e,t,i=""){let n=this.nodesByPath.get(i)?.type==="directory"?i:"",r=this.nodeParentPathByPath.get(e);if(r===n)return;r!==void 0&&this.detachNode(e,t);let o=n?this.nodesByPath.get(n)?.children:this.roots;o.includes(t)||o.push(t),this.nodeParentPathByPath.set(e,n)}rehomeChildren(e){this.entriesByPath.forEach((t,i)=>{if(t?.parentPath!==e)return;let n=this.nodesByPath.get(i);n&&this.attachNode(i,n,e)})}},Qe=class{constructor({onTreeChange:e=()=>{},onWorkspaceEvent:t=()=>{}}={}){this.onTreeChange=e,this.onWorkspaceEvent=t,this.ydoc=new Pe,this.entries=this.ydoc.getMap("entries"),this.events=this.ydoc.getArray("events"),this.provider=null,this._didInitialSync=!1,this.seenEventIds=new Set,this.treeModel=new Bt,this.handleEntriesChange=i=>{!this._didInitialSync||!i||this.onTreeChange(this.treeModel.applyMapChanges(i.changes.keys,this.entries),{changedPaths:Array.from(i.changes.keys.keys()),reset:!1})},this.handleEventsChange=()=>{if(!this._didInitialSync){this.primeEventCache();return}this.events.toArray().forEach(i=>{let n=Ft(i);!n||this.seenEventIds.has(n.id)||(this.seenEventIds.add(n.id),this.onWorkspaceEvent(n))})}}connect(){this.provider||(this._didInitialSync=!1,this.provider=new ke(ye(),Ai,this.ydoc,{disableBc:!0,maxBackoffTime:5e3}),Fe(this.provider),this.entries.observe(this.handleEntriesChange),this.events.observe(this.handleEventsChange),this.provider.on("sync",e=>{!e||this._didInitialSync||(this._didInitialSync=!0,this.primeEventCache(),this.onTreeChange(this.treeModel.reset(this.entries.toJSON()),{changedPaths:[],reset:!0}))}))}primeEventCache(){this.events.toArray().forEach(e=>{let t=Ft(e);t&&this.seenEventIds.add(t.id)})}disconnect(){this.entries.unobserve(this.handleEntriesChange),this.events.unobserve(this.handleEventsChange),this.provider?.disconnect(),this.provider?.destroy(),this.provider=null,this._didInitialSync=!1,this.seenEventIds.clear(),this.treeModel.reset(new Map)}destroy(){this.disconnect(),this.ydoc.destroy()}};var Ze=class{constructor({documentRef:e=document,inlinePanelElement:t=null,onFileSelect:i,panelElement:n}){this.documentRef=e,this.panelRoot=n,this.inlinePanel=t,this.onFileSelect=i,this._expanded=!1,this._currentFile=null,this._fetchController=null,this._backlinks=[];let r=this.panelRoot?.querySelector('[data-backlinks-variant="dock"]')??this.panelRoot;this.panels=[this._createPanelRef(r),this._createPanelRef(this.inlinePanel)].filter(Boolean),this.handleDocumentPointerDown=o=>{if(!this._expanded)return;let a=o?.target;a&&this.panels.some(({panel:c})=>c?.contains?.(a))||this.close()},this.handleDocumentKeyDown=o=>{!this._expanded||o?.key!=="Escape"||(o.preventDefault?.(),this.close())},this.bindEvents()}bindEvents(){this.panels.forEach(e=>{e.header?.addEventListener("click",()=>{this._backlinks.length!==0&&(this._expanded=!this._expanded,this._applyExpandState())}),e.header?.addEventListener("keydown",t=>{t.key!=="Enter"&&t.key!==" "||(t.preventDefault(),e.header.click())})}),this.documentRef?.addEventListener?.("pointerdown",this.handleDocumentPointerDown),this.documentRef?.addEventListener?.("keydown",this.handleDocumentKeyDown)}async load(e){let t=e!==this._currentFile;if(this._currentFile=e,t&&(this._expanded=!1),!e){this._backlinks=[],this._render();return}this._fetchController?.abort(),this._fetchController=new AbortController;try{let n=await(await fetch(b(`/backlinks?file=${encodeURIComponent(e)}`),{signal:this._fetchController.signal})).json();if(this._currentFile!==e)return;this._backlinks=n.backlinks??[]}catch(i){if(i.name==="AbortError")return;console.warn("[backlinks] Failed to load:",i.message),this._backlinks=[]}this._render()}clear(){this._currentFile=null,this._backlinks=[],this._expanded=!1,this._render()}close(){this._expanded&&(this._expanded=!1,this._applyExpandState())}_createPanelRef(e){return e?{panel:e,header:e.querySelector(".backlinks-header"),toggle:e.querySelector(".backlinks-toggle"),countBadge:e.querySelector(".backlinks-count"),body:e.querySelector(".backlinks-body"),list:e.querySelector(".backlinks-list")}:null}_render(){let e=this._backlinks.length,t=e===1?"Linked Mention":"Linked Mentions",i=!!this._currentFile&&e>0;this.panelRoot?.classList?.toggle("hidden",!i),this.inlinePanel?.classList?.toggle("hidden",!i),i||(this._expanded=!1),this.panels.forEach(n=>{n.countBadge.textContent=i?String(e):"",n.toggle.textContent=t,n.header?.classList.toggle("backlinks-header-empty",!i),i?this._renderList(n.list):n.list.innerHTML=""}),this._applyExpandState()}_renderList(e){if(!e)return;e.innerHTML="";let t=this.documentRef?.createDocumentFragment?.(),i=t??e;this._backlinks.forEach(n=>{i.appendChild(this._createBacklinkItem(n))}),t&&e.appendChild(t)}_createBacklinkItem(e){let t=e.file.replace(/\.md$/i,"").split("/").pop(),i=e.file.includes("/")?e.file.substring(0,e.file.lastIndexOf("/")):"",n=this.documentRef.createElement("button");n.type="button",n.className="backlink-item",n.addEventListener("click",()=>{this.close(),this.onFileSelect?.(e.file)});let r=this.documentRef.createElement("div");if(r.className="backlink-file-name",r.innerHTML=`
|
|
37
37
|
<svg class="backlink-icon" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
|
|
38
38
|
<path d="M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z"/>
|
|
39
39
|
<polyline points="14 2 14 8 20 8"/>
|
|
40
40
|
</svg>
|
|
41
|
-
<span>${
|
|
42
|
-
${i?`<span class="backlink-dir">${
|
|
43
|
-
`,
|
|
41
|
+
<span>${p(t)}</span>
|
|
42
|
+
${i?`<span class="backlink-dir">${p(i)}</span>`:""}
|
|
43
|
+
`,n.appendChild(r),e.contexts.slice(0,3).forEach(o=>{let a=this.documentRef.createElement("div");a.className="backlink-context",a.textContent=o,n.appendChild(a)}),e.contexts.length>3){let o=this.documentRef.createElement("div");o.className="backlink-context backlink-more",o.textContent=`+${e.contexts.length-3} more`,n.appendChild(o)}return n}_applyExpandState(){let e=this._expanded&&this._backlinks.length>0;this.panels.forEach(t=>{t.panel.classList.toggle("expanded",e),t.header?.setAttribute("aria-expanded",String(e)),t.header?.setAttribute("aria-disabled",String(this._backlinks.length===0)),t.body?.setAttribute("aria-hidden",String(!e)),t.body?.toggleAttribute("inert",!e)})}};function Rt(s,e,t,i,n,r){return s?.(e,t,i,n,r)??r.renderToken(e,t,i)}function Fs(s=""){return`<p>${p(String(s??"")).replace(/\n/g,"<br>")}</p>`}function xs(){let s=Gt({breaks:!0,highlight(n,r){try{return r&&we.getLanguage(r)?we.highlight(n,{ignoreIllegals:!0,language:r}).value:we.highlightAuto(n).value}catch{return p(n)}},html:!1,linkify:!0,typographer:!0}),e=s.renderer.rules.link_open,t=s.renderer.rules.table_open,i=s.renderer.rules.table_close;return s.renderer.rules.link_open=(n,r,o,a,c)=>(n[r].attrSet("target","_blank"),n[r].attrSet("rel","noopener noreferrer"),Rt(e,n,r,o,a,c)),s.renderer.rules.table_open=(n,r,o,a,c)=>`<div class="comment-markdown-table">${Rt(t,n,r,o,a,c)}`,s.renderer.rules.table_close=(n,r,o,a,c)=>`${Rt(i,n,r,o,a,c)}</div>`,s}var Ms=xs();function Ri(s=""){let e=String(s??"");try{return Ms.render(e)}catch{return Fs(e)}}var Hi=14,Ni=520,Ts=150,Is=12,Ye=36,As=28,Xe=30,Bs=400,Rs=769,Hs=Object.freeze(["\u{1F44D}","\u2764\uFE0F","\u{1F389}","\u{1F440}","\u{1F680}"]),Ns=Object.freeze(["\u{1F602}","\u{1F525}","\u2705","\u{1F64F}","\u{1F4A1}","\u{1F914}","\u{1F44F}","\u{1F604}","\u{1F3AF}","\u{1F64C}"]);function ee(s,e,t){return Math.min(Math.max(s,e),t)}function Ds(s=[]){return[...s].sort((e,t)=>(e.anchor?.startLine??0)-(t.anchor?.startLine??0)||e.createdAt-t.createdAt)}function Dt(s){return s?.anchorKind||s?.kind||"line"}function Ht(s){return Dt(s)==="text"&&Number.isFinite(s?.startIndex)&&Number.isFinite(s?.endIndex)&&s.endIndex>s.startIndex}function Di(s,e){return s===e?!0:!s||!e?!1:Dt(s)===Dt(e)&&(s.startIndex??null)===(e.startIndex??null)&&(s.endIndex??null)===(e.endIndex??null)&&(s.startLine??null)===(e.startLine??null)&&(s.endLine??null)===(e.endLine??null)&&(s.anchorQuote??s.quote??"")===(e.anchorQuote??e.quote??"")}function _i(s){return s?(s.kind||s.anchorKind)==="text"&&s.quote?s.startLine===s.endLine?`Line ${s.startLine}`:`Lines ${s.startLine}-${s.endLine}`:s.startLine===s.endLine?`Line ${s.startLine}`:`Lines ${s.startLine}-${s.endLine}`:"No source anchor"}function _s(s={}){return[s.kind||s.anchorKind||"line",s.startLine??0,s.endLine??0,s.quote||""].join("::")}function $s(s){return s&&!s.querySelector("[data-source-line]")}function $i(s){let e=Number.parseInt(s||"",10);return Number.isFinite(e)?e:null}function Os(s=[]){return s.reduce((e,t)=>e?(t?.createdAt??0)>=(e?.createdAt??0)?t:e:t,null)}function zs(s){return s?.threads?.reduce((e,t)=>{let i=Os(t?.messages??[]);return i&&(i.createdAt??0)>=(e?.createdAt??0)?i:e},null)}function Oi(s,e="comment-markdown"){let t=document.createElement("div");return t.className=e,t.innerHTML=Ri(s),t}function zi(s,e){return!!(e&&s?.users?.some(t=>t?.userId===e))}function Us(s){return String(Array.isArray(s?.users)?s.users.length:0)}function Nt(s,e,t){return s?.threadId===e&&s?.messageId===t}function qs(s){let e=s?.querySelector?.(".comment-reaction-picker"),t=e?.closest?.(".comment-reaction-picker-wrap"),i=s?.querySelector?.(".comment-card-scroll");return!(e instanceof HTMLElement)||!(t instanceof HTMLElement)||!(i instanceof HTMLElement)?null:{picker:e,scroll:i,wrap:t}}function Ui(s,e){let t=$i(s?.getAttribute?.("data-source-line")),i=$i(s?.getAttribute?.("data-source-line-end"))??t;return!t||!i||!e?!1:e.startLine<=i&&e.endLine>=t}function Ws(s){let e=document.createTreeWalker(s,NodeFilter.SHOW_TEXT),t="",i=[],n=!0;for(;e.nextNode();){let r=e.currentNode,o=r.textContent||"";for(let a=0;a<o.length;a+=1){let c=o[a];if(/\s/.test(c)){if(n)continue;t+=" ",i.push({node:r,offset:a}),n=!0;continue}t+=c,i.push({node:r,offset:a}),n=!1}}for(;t.endsWith(" ");)t=t.slice(0,-1),i.pop();return{map:i,normalized:t}}function Gs(s,e){let t=ai(e);if(!s||!t)return null;let i=Ws(s);if(!i.normalized)return null;let n=i.normalized.indexOf(t);if(n<0||i.normalized.indexOf(t,n+1)>=0)return null;let r=i.map[n],o=i.map[n+t.length-1];if(!r||!o)return null;let a=document.createRange();return a.setStart(r.node,r.offset),a.setEnd(o.node,o.offset+1),a}function qi(s,e){return{bottom:s.bottom-e.top,height:s.height,left:s.left-e.left,right:s.right-e.left,top:s.top-e.top,width:s.width}}function Ks(s=[]){if(!Array.isArray(s)||s.length===0)return null;let e=Math.min(...s.map(r=>r.left)),t=Math.min(...s.map(r=>r.top)),i=Math.max(...s.map(r=>r.right)),n=Math.max(...s.map(r=>r.bottom));return{bottom:n,height:n-t,left:e,right:i,top:t,width:i-e}}function Vs(s,e,t){return t?s>=t.left&&s<=t.right&&e>=t.top&&e<=t.bottom:!1}function Je(s=[]){return[...new Set(s.filter(Boolean))].sort()}function js(s=[]){return Je(s).join(" ")}function Wi(s){let e=document.createDocumentFragment(),t=document.createElement("span");if(t.className="comment-marker-icon",t.setAttribute("aria-hidden","true"),t.innerHTML=`
|
|
44
44
|
<svg viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
|
|
45
45
|
<path d="M3 4.75A1.75 1.75 0 0 1 4.75 3h6.5A1.75 1.75 0 0 1 13 4.75v4.5A1.75 1.75 0 0 1 11.25 11H8.9L6.5 13v-2H4.75A1.75 1.75 0 0 1 3 9.25v-4.5Z" stroke="currentColor" stroke-width="1.35" stroke-linejoin="round"/>
|
|
46
46
|
</svg>
|
|
47
|
-
`,e.appendChild(t),n>1){let i=document.createElement("span");i.className="comment-marker-count",i.textContent=String(n),e.appendChild(i)}return e}var Ze=class{constructor({commentSelectionButton:e,commentsDrawer:t,commentsDrawerEmpty:i,commentsDrawerList:s,commentsToggleButton:r,editorContainer:a,onWillOpenDrawer:o,onCreateThread:l,onNavigateToLine:h,onReplyToThread:c,onToggleReaction:u,onResolveThread:p,previewContainer:d,previewElement:w}){this.commentSelectionButton=e,this.commentsDrawer=t,this.commentsDrawerEmpty=i,this.commentsDrawerList=s,this.commentsToggleButton=r,this.editorContainer=a,this.onWillOpenDrawer=o,this.onCreateThread=l,this.onNavigateToLine=h,this.onReplyToThread=c,this.onToggleReaction=u,this.onResolveThread=p,this.previewContainer=d,this.previewElement=w,this.currentFile=null,this.fileKind="markdown",this.supported=!1,this.drawerOpen=!1,this.threads=[],this.selectionAnchor=null,this.pendingSelectionAnchor=null,this.committedSelectionAnchor=null,this.selectionRevealTimer=0,this.pointerSelecting=!1,this.session=null,this.activeCard=null,this.hoveredEditorGroupKeys=[],this.hoveredEditorGroupKeysSignature="",this.hoveredPreviewGroupKeys=[],this.hoveredPreviewGroupKeysSignature="",this.previewHoverRegions=[],this.lastPreviewPointerPosition=null,this.editorLayer=null,this.previewLayer=null,this.previewHighlightLayer=null,this.cardRoot=null,this.pendingCardFocusElement=null,this.reactionPicker=null,this.layoutFrame=0,this.timeFormatter=new Intl.DateTimeFormat(void 0,{day:"numeric",hour:"numeric",minute:"2-digit",month:"short"}),this.handleEditorScroll=()=>this.scheduleLayoutRefresh(),this.handlePreviewScroll=()=>this.scheduleLayoutRefresh(),this.handleWindowResize=()=>this.scheduleLayoutRefresh(),this.handlePreviewPointerMove=m=>{this.lastPreviewPointerPosition={x:m.clientX,y:m.clientY},this.updateHoveredPreviewGroups(this.getPreviewGroupKeysAtPoint(m.clientX,m.clientY))},this.handlePreviewPointerLeave=()=>{this.lastPreviewPointerPosition=null,this.updateHoveredPreviewGroups([])},this.handlePreviewFocusIn=m=>{this.updateHoveredPreviewGroups(this.getPreviewGroupKeysForTarget(m.target))},this.handlePreviewFocusOut=m=>{this.updateHoveredPreviewGroups(this.getPreviewGroupKeysForTarget(m.relatedTarget))},this.handleCommentSelectionButtonPointerDown=m=>{m.preventDefault()},this.handleEditorPointerDown=m=>{m.button!==0||!this.supported||!this.session||!m.target?.closest?.(".cm-editor")||m.target?.closest?.(".comment-editor-layer")||(this.pointerSelecting=!0,this.clearSelectionRevealTimer(),this.committedSelectionAnchor&&(this.committedSelectionAnchor=null,this.scheduleLayoutRefresh()))},this.handleDocumentPointerUp=()=>{this.pointerSelecting&&requestAnimationFrame(()=>{let m=this.supported?this.session?.getCurrentSelectionCommentAnchor?.()??null:null;this.pointerSelecting=!1,this.selectionAnchor=m,this.renderToolbar(),this.pendingSelectionAnchor=Mt(m)?m:null,this.clearSelectionRevealTimer(),this.committedSelectionAnchor=Mt(m)&&this.activeCard?.mode!=="create"?m:null,this.scheduleLayoutRefresh()})},this.handleEditorFocusOut=m=>{let b=m.relatedTarget;b instanceof Node&&(this.editorContainer?.contains(b)||this.cardRoot?.contains(b)||this.commentSelectionButton?.contains(b))||(this.clearSelectionRevealTimer(),this.pendingSelectionAnchor=null,this.committedSelectionAnchor=null,this.scheduleLayoutRefresh())},this.handleDocumentPointerDown=m=>{let b=m.target;if(this.activeCard&&this.cardRoot){if(this.cardRoot.contains(b))return;this.closeCard()}this.drawerOpen&&(b instanceof Node&&(this.commentsDrawer?.contains(b)||this.commentsToggleButton?.contains(b))||this.closeDrawer())},this.handleDocumentKeyDown=m=>{if(m.key==="Escape"&&this.reactionPicker){this.reactionPicker=null,this.renderCard();return}m.key==="Escape"&&this.activeCard&&this.closeCard(),m.key==="Escape"&&this.committedSelectionAnchor&&(this.clearSelectionRevealTimer(),this.pendingSelectionAnchor=null,this.committedSelectionAnchor=null,this.scheduleLayoutRefresh())},this.commentSelectionButton?.addEventListener("pointerdown",this.handleCommentSelectionButtonPointerDown),this.commentSelectionButton?.addEventListener("click",()=>{this.openComposerForSelection("toolbar")}),this.commentsToggleButton?.addEventListener("click",()=>{this.setDrawerOpen(!this.drawerOpen)}),this.previewContainer?.addEventListener("scroll",this.handlePreviewScroll,{passive:!0}),this.previewElement?.addEventListener("pointermove",this.handlePreviewPointerMove,{passive:!0}),this.previewElement?.addEventListener("pointerleave",this.handlePreviewPointerLeave),this.previewElement?.addEventListener("focusin",this.handlePreviewFocusIn),this.previewElement?.addEventListener("focusout",this.handlePreviewFocusOut),this.editorContainer?.addEventListener("pointerdown",this.handleEditorPointerDown),this.editorContainer?.addEventListener("focusout",this.handleEditorFocusOut),window.addEventListener("resize",this.handleWindowResize),document.addEventListener("pointerup",this.handleDocumentPointerUp),document.addEventListener("pointercancel",this.handleDocumentPointerUp),document.addEventListener("pointerdown",this.handleDocumentPointerDown),document.addEventListener("keydown",this.handleDocumentKeyDown)}destroy(){this.layoutFrame&&(cancelAnimationFrame(this.layoutFrame),this.layoutFrame=0),this.attachSession(null),this.previewContainer?.removeEventListener("scroll",this.handlePreviewScroll),this.previewElement?.removeEventListener("pointermove",this.handlePreviewPointerMove),this.previewElement?.removeEventListener("pointerleave",this.handlePreviewPointerLeave),this.previewElement?.removeEventListener("focusin",this.handlePreviewFocusIn),this.previewElement?.removeEventListener("focusout",this.handlePreviewFocusOut),this.commentSelectionButton?.removeEventListener("pointerdown",this.handleCommentSelectionButtonPointerDown),this.editorContainer?.removeEventListener("pointerdown",this.handleEditorPointerDown),this.editorContainer?.removeEventListener("focusout",this.handleEditorFocusOut),window.removeEventListener("resize",this.handleWindowResize),document.removeEventListener("pointerup",this.handleDocumentPointerUp),document.removeEventListener("pointercancel",this.handleDocumentPointerUp),document.removeEventListener("pointerdown",this.handleDocumentPointerDown),document.removeEventListener("keydown",this.handleDocumentKeyDown),this.previewHoverRegions=[],this.cardRoot?.remove(),this.editorLayer?.remove(),this.previewLayer?.remove(),this.pendingCardFocusElement=null}attachSession(e){this.session?.getScrollContainer?.()?.removeEventListener("scroll",this.handleEditorScroll),this.session=e,this.selectionAnchor=e?.getCurrentSelectionCommentAnchor?.()??null,this.pendingSelectionAnchor=null,this.committedSelectionAnchor=null,this.reactionPicker=null,this.clearSelectionRevealTimer(),this.pointerSelecting=!1,e?.getScrollContainer?.()?.addEventListener("scroll",this.handleEditorScroll,{passive:!0}),this.render()}setCurrentFile(e,{fileKind:t="markdown",supported:i=!1}={}){let s=this.currentFile!==e;this.currentFile=e,this.fileKind=t,this.supported=!!(e&&i),s&&(this.drawerOpen=!1,this.threads=[],this.selectionAnchor=null,this.pendingSelectionAnchor=null,this.committedSelectionAnchor=null,this.clearSelectionRevealTimer(),this.pointerSelecting=!1,this.activeCard=null,this.updateHoveredEditorGroups([]),this.updateHoveredPreviewGroups([]),this.previewHoverRegions=[],this.lastPreviewPointerPosition=null,this.reactionPicker=null),this.supported||(this.drawerOpen=!1,this.activeCard=null,this.threads=[],this.selectionAnchor=null,this.pendingSelectionAnchor=null,this.committedSelectionAnchor=null,this.clearSelectionRevealTimer(),this.pointerSelecting=!1,this.updateHoveredEditorGroups([]),this.updateHoveredPreviewGroups([]),this.previewHoverRegions=[],this.lastPreviewPointerPosition=null,this.reactionPicker=null),this.render()}setSelectionAnchor(e){if(this.selectionAnchor=this.supported?e:null,!this.supported||!this.selectionAnchor){this.pendingSelectionAnchor=null,this.committedSelectionAnchor=null,this.clearSelectionRevealTimer(),this.renderToolbar(),this.scheduleLayoutRefresh();return}if(!Mt(this.selectionAnchor)){this.pendingSelectionAnchor=null,this.committedSelectionAnchor=null,this.clearSelectionRevealTimer(),this.renderToolbar(),this.scheduleLayoutRefresh();return}if(this.pendingSelectionAnchor=this.selectionAnchor,this.activeCard?.mode==="create"){this.clearSelectionRevealTimer(),this.renderToolbar(),this.scheduleLayoutRefresh();return}if(this.pointerSelecting){this.clearSelectionRevealTimer(),this.committedSelectionAnchor=null,this.renderToolbar(),this.scheduleLayoutRefresh();return}if(Ii(this.committedSelectionAnchor,this.selectionAnchor)){this.renderToolbar(),this.scheduleLayoutRefresh();return}this.scheduleSelectionReveal(this.selectionAnchor),this.renderToolbar(),this.scheduleLayoutRefresh()}handleEditorContentChange(){this.activeCard?.mode!=="create"&&(this.clearSelectionRevealTimer(),this.pendingSelectionAnchor=null,this.committedSelectionAnchor=null,this.scheduleLayoutRefresh())}setThreads(e=[]){this.threads=Sn(e),this.activeCard?.mode==="group"&&!this.getThreadGroups().some(t=>t.key===this.activeCard.groupKey)&&(this.activeCard=null),this.reactionPicker&&!this.threads.some(t=>t.id===this.reactionPicker.threadId&&t.messages?.some(i=>i.id===this.reactionPicker.messageId))&&(this.reactionPicker=null),this.render()}setDrawerOpen(e){let t=!!e;t!==this.drawerOpen&&(t&&this.onWillOpenDrawer?.(),this.drawerOpen=t,this.render())}closeDrawer(){this.setDrawerOpen(!1)}refreshLayout(){this.renderEditorLayer(),this.renderPreviewLayer(),this.repositionActiveCard()}scheduleLayoutRefresh(){this.layoutFrame||(this.layoutFrame=requestAnimationFrame(()=>{this.layoutFrame=0,this.refreshLayout()}))}render(){this.renderToolbar(),this.renderDrawer(),this.renderCard(),this.scheduleLayoutRefresh()}renderToolbar(){let e=this.threads.length,t=this.supported&&!!this.session;if(this.commentSelectionButton?.classList.toggle("hidden",!t),this.commentsToggleButton?.classList.toggle("hidden",!this.supported),this.commentSelectionButton&&(this.commentSelectionButton.disabled=!this.selectionAnchor),this.commentsToggleButton){this.commentsToggleButton.classList.toggle("active",this.drawerOpen),this.commentsToggleButton.setAttribute("aria-expanded",String(this.drawerOpen));let i=e>0?`Comments ${e}`:"Comments",s=this.commentsToggleButton.querySelector(".pane-header-btn-label");s?s.textContent=i:this.commentsToggleButton.textContent=i}}renderDrawer(){if(!this.commentsDrawer||!this.commentsDrawerList)return;this.commentsDrawer.classList.toggle("hidden",!this.supported||!this.drawerOpen),this.commentsDrawerList.replaceChildren();let e=this.getThreadGroups();if(this.commentsDrawerEmpty?.classList.toggle("hidden",e.length>0),!this.supported||e.length===0)return;let t=document.createDocumentFragment();e.forEach(i=>{let s=document.createElement("button");s.type="button",s.className="comments-drawer-item",s.classList.toggle("is-active",this.activeCard?.groupKey===i.key),s.addEventListener("pointerdown",w=>{w.preventDefault()}),s.addEventListener("click",()=>{this.openThreadGroup(i,{anchor:i.anchor,origin:"drawer",sourceRect:s.getBoundingClientRect()})});let r=document.createElement("div");r.className="comments-drawer-item-header";let a=document.createElement("span");a.className="comments-drawer-item-title",a.textContent=Fi(i.anchor);let o=document.createElement("span");o.className="comments-drawer-item-count",o.textContent=String(i.threads.length),r.append(a,o);let l=document.createElement("p");l.className="comments-drawer-item-quote",l.textContent=i.anchor.quote||i.anchor.excerpt||"Source anchored comment";let h=xn(i),c=Ai(h?.body||"","comment-markdown comments-drawer-item-preview"),u=document.createElement("div");u.className="comments-drawer-item-footer";let p=document.createElement("span");p.textContent=`${i.threads.length} thread${i.threads.length===1?"":"s"}`;let d=document.createElement("span");d.className="comments-drawer-item-updated",d.textContent=h?`${h.userName} \u2022 ${this.formatTimestamp(h.createdAt)}`:"",u.append(p,d),s.append(r,l,c,u),t.appendChild(s)}),this.commentsDrawerList.appendChild(t)}ensureEditorLayer(){if(this.editorLayer?.isConnected&&this.editorLayer.parentElement===this.editorContainer)return this.editorLayer;let e=document.createElement("div");return e.className="comment-editor-layer",this.editorContainer?.appendChild(e),this.editorLayer=e,e}renderEditorLayer(){let e=this.ensureEditorLayer();if(e.replaceChildren(),!this.supported||!this.session)return;let t=this.editorContainer?.getBoundingClientRect?.();if(!t)return;let i=this.getThreadGroups(),s=[];if(i.forEach(c=>{let u=this.session.getCommentAnchorClientRect?.(c.anchor);if(!u)return;let p=Bi(u,t);if(p.bottom<0||p.top>t.height)return;let d=document.createElement("button");d.type="button",d.className="comment-editor-badge",d.dataset.count=String(c.threads.length);let w=this.activeCard?.groupKey===c.key,m=this.hoveredEditorGroupKeys.includes(c.key);d.classList.toggle("is-active",w),d.classList.toggle("is-hovered",m),d.classList.toggle("is-passive",!w&&!m),d.setAttribute("aria-label",`${c.threads.length} comment thread${c.threads.length===1?"":"s"}`),d.appendChild(Ni(c.threads.length));let b=Math.max(p.top,8);d.style.top=`${b}px`,d.style.left=`${Math.max(t.width-36,8)}px`,d.title=`${c.threads.length} comment${c.threads.length===1?"":"s"}`,d.addEventListener("pointerdown",E=>{E.preventDefault()}),d.addEventListener("pointerenter",()=>{this.updateHoveredEditorGroups([c.key])}),d.addEventListener("pointerleave",()=>{this.updateHoveredEditorGroups([])}),d.addEventListener("focusin",()=>{this.updateHoveredEditorGroups([c.key])}),d.addEventListener("focusout",()=>{this.updateHoveredEditorGroups([])}),d.addEventListener("click",()=>{this.openThreadGroup(c,{anchor:c.anchor,origin:"editor",sourceRect:u})}),e.appendChild(d),s.push(b)}),!this.committedSelectionAnchor||this.activeCard?.mode==="create")return;let r=this.session.getCommentAnchorClientRect?.(this.committedSelectionAnchor),a=this.session.getSelectionChipClientRect?.(this.committedSelectionAnchor)??r;if(!a)return;let o=Bi(a,t);if(o.bottom<0||o.top>t.height)return;let l=ee(o.top,8,Math.max(t.height-je,8));for(;s.some(c=>Math.abs(c-l)<je-4);)l=ee(l+je,8,Math.max(t.height-je,8));let h=document.createElement("button");h.type="button",h.className="comment-selection-chip",h.textContent="Comment",h.style.top=`${l}px`,h.style.right=`${yn}px`,h.addEventListener("pointerdown",c=>{c.preventDefault(),c.stopPropagation(),this.openComposerForSelection("editor",h.getBoundingClientRect())}),e.appendChild(h)}ensurePreviewLayer(){if(this.previewLayer?.isConnected&&this.previewLayer.parentElement===this.previewElement)return this.previewLayer;let e=document.createElement("div");e.className="comment-preview-highlights";let t=document.createElement("div");return t.className="comment-preview-layer",this.previewElement?.append(e,t),this.previewHighlightLayer=e,this.previewLayer=t,t}renderPreviewLayer(){if(this.ensurePreviewLayer(),this.previewLayer?.replaceChildren(),this.previewHighlightLayer?.replaceChildren(),!this.supported||!this.previewElement){this.previewHoverRegions=[];return}let e=this.previewElement.getBoundingClientRect(),t=this.getThreadGroups(),i=[],s=[],r=this.shouldRenderPassivePreviewMarkers();t.forEach(a=>{let o=this.resolvePreviewTarget(a.anchor);if(!o?.bubbleRect)return;s.push({key:a.key,rects:o.hoverRects?.length>0?o.hoverRects:[o.bubbleRect]});let l=this.activeCard?.groupKey===a.key,h=this.hoveredPreviewGroupKeys.includes(a.key),c=l||h;if(o.highlightRects?.forEach(d=>{let w=document.createElement("div");w.className="comment-preview-highlight",w.classList.toggle("is-active",l),w.classList.toggle("is-hovered",h),w.classList.toggle("is-passive",!c),w.style.left=`${d.left-e.left}px`,w.style.top=`${d.top-e.top}px`,w.style.width=`${d.width}px`,w.style.height=`${d.height}px`,this.previewHighlightLayer?.appendChild(w)}),!r&&!c)return;let u=document.createElement("button");u.type="button",u.className="comment-preview-badge",u.dataset.commentPreviewGroupKeys=a.key,u.classList.toggle("is-active",l),u.classList.toggle("is-hovered",h),u.classList.toggle("is-passive",!c),u.setAttribute("aria-label",`${a.threads.length} comment thread${a.threads.length===1?"":"s"}`),u.appendChild(Ni(a.threads.length));let p=ee(o.bubbleRect.top-e.top,6,Math.max(this.previewElement.clientHeight-Qe,6));for(;i.some(d=>Math.abs(d-p)<Qe-4);)p=ee(p+Qe,6,Math.max(this.previewElement.clientHeight-Qe,6));u.style.top=`${p}px`,u.title=`${a.threads.length} comment${a.threads.length===1?"":"s"}`,u.addEventListener("pointerdown",d=>{d.preventDefault()}),u.addEventListener("click",()=>{this.openThreadGroup(a,{anchor:a.anchor,origin:"preview",sourceRect:u.getBoundingClientRect()})}),this.previewLayer?.appendChild(u),i.push(p)}),this.previewHoverRegions=s,this.lastPreviewPointerPosition&&this.updateHoveredPreviewGroups(this.getPreviewGroupKeysAtPoint(this.lastPreviewPointerPosition.x,this.lastPreviewPointerPosition.y))}resolvePreviewTarget(e){if(!this.previewElement||!e)return null;let t=Array.from(this.previewElement.querySelectorAll(".mermaid-shell, .plantuml-shell")).find(r=>Ri(r,e));if(t)return{bubbleRect:t.getBoundingClientRect(),highlightRects:[],hoverRects:[t.getBoundingClientRect()]};let i=Array.from(this.previewElement.querySelectorAll("[data-source-line]")).filter(r=>Pn(r)&&Ri(r,e));if(e.kind==="text"&&e.quote){let r=i.map(a=>({element:a,range:An(a,e.quote)})).filter(a=>a.range);if(r.length===1){let a=Array.from(r[0].range.getClientRects());return{bubbleRect:Mn(a)||r[0].element.getBoundingClientRect(),highlightRects:a,hoverRects:a}}}let s=i[0];return s?{bubbleRect:s.getBoundingClientRect(),highlightRects:[],hoverRects:[s.getBoundingClientRect()]}:null}ensureCardRoot(){if(this.cardRoot?.isConnected&&this.cardRoot.parentElement===document.body)return this.cardRoot;let e=document.createElement("div");return e.className="comment-card-root hidden",document.body.appendChild(e),this.cardRoot=e,e}openComposerForSelection(e="editor",t=null){let i=this.session?.getCurrentSelectionCommentAnchor?.();if(!i)return;this.selectionAnchor=i,this.reactionPicker=null;let s=e==="editor"&&t?"editor-chip":e,r=t??(e==="toolbar"?this.commentSelectionButton?.getBoundingClientRect?.():this.session?.getCommentAnchorClientRect?.(i));this.activeCard={anchor:i,mode:"create",origin:s,replyThreadId:null,sourceRect:r},this.render()}openThreadGroup(e,{anchor:t,origin:i,sourceRect:s}){this.reactionPicker=null,this.activeCard={anchor:t,groupKey:e.key,mode:"group",origin:i,replyThreadId:null,sourceRect:s},this.renderDrawer(),this.renderCard()}closeCard(){this.activeCard=null,this.pendingCardFocusElement=null,this.reactionPicker=null,this.renderCard(),this.scheduleLayoutRefresh()}getThreadGroups(){let e=new Map;return this.threads.forEach(t=>{let i=kn(t.anchor),s=e.get(i);if(s){s.threads.push(t);return}e.set(i,{anchor:t.anchor,key:i,threads:[t]})}),Array.from(e.values()).sort((t,i)=>(t.anchor?.startLine??0)-(i.anchor?.startLine??0))}updateCardSourceRect(){return this.activeCard?this.activeCard.origin==="editor"?this.session?.getCommentAnchorClientRect?.(this.activeCard.anchor)??this.activeCard.sourceRect:this.activeCard.origin==="editor-chip"?this.activeCard.sourceRect:this.activeCard.origin==="preview"?this.resolvePreviewTarget(this.activeCard.anchor)?.bubbleRect??this.activeCard.sourceRect:this.activeCard.origin==="toolbar"?this.commentSelectionButton?.getBoundingClientRect?.()??this.activeCard.sourceRect:this.activeCard.sourceRect:null}renderCard(){let e=this.ensureCardRoot();if(e.replaceChildren(),e.classList.toggle("hidden",!this.activeCard),!this.activeCard){this.pendingCardFocusElement=null,e.style.visibility="";return}this.pendingCardFocusElement=null;let t=document.createElement("section");t.className="comment-card",t.addEventListener("click",h=>{!this.reactionPicker||h.target?.closest?.(".comment-reaction-picker-wrap")||(this.reactionPicker=null,requestAnimationFrame(()=>{this.activeCard&&this.renderCard()}))});let i=document.createElement("div");i.className="comment-card-header";let s=document.createElement("div");s.className="comment-card-title-wrap";let r=document.createElement("h3");r.className="comment-card-title",r.textContent=this.activeCard.mode==="create"?"New comment":"Comment threads";let a=document.createElement("p");a.className="comment-card-meta",a.textContent=Fi(this.activeCard.anchor),s.append(r,a);let o=document.createElement("button");o.type="button",o.className="comment-card-close",o.setAttribute("aria-label","Close comments"),o.textContent="Close",o.addEventListener("click",()=>this.closeCard()),i.append(s,o),t.appendChild(i);let l=document.createElement("div");if(l.className="comment-card-scroll",this.activeCard.anchor?.quote){let h=document.createElement("p");h.className="comment-card-quote",h.textContent=this.activeCard.anchor.quote,l.appendChild(h)}if(this.activeCard.mode==="create")l.appendChild(this.createComposer());else{let h=this.getThreadGroups().find(c=>c.key===this.activeCard.groupKey);if(!h){this.closeCard();return}h.threads.forEach(c=>{l.appendChild(this.createThreadElement(c))})}e.style.visibility="hidden",t.appendChild(l),e.appendChild(t),this.updateReactionPickerPosition(t),this.positionCard(t),e.style.visibility="",this.flushPendingCardFocus(),this.scheduleLayoutRefresh()}getPreviewGroupKeysForTarget(e){if(!(e instanceof Node))return[];let t=e.closest?.("[data-comment-preview-group-keys]");return Bn(String(t?.dataset?.commentPreviewGroupKeys??"").split(/\s+/).filter(Boolean)).split(" ").filter(Boolean)}getPreviewGroupKeysAtPoint(e,t){if(!Number.isFinite(e)||!Number.isFinite(t))return[];let i=document.elementFromPoint(e,t),s=this.getPreviewGroupKeysForTarget(i);if(s.length>0)return s;let r=this.previewHoverRegions.filter(a=>a.rects.some(o=>Rn(e,t,o))).map(a=>a.key);return Ye(r)}updateHoveredPreviewGroups(e=[]){let t=Ye(e),i=t.join(" ");i!==this.hoveredPreviewGroupKeysSignature&&(this.hoveredPreviewGroupKeys=t,this.hoveredPreviewGroupKeysSignature=i,this.scheduleLayoutRefresh())}updateHoveredEditorGroups(e=[]){let t=Ye(e),i=t.join(" ");i!==this.hoveredEditorGroupKeysSignature&&(this.hoveredEditorGroupKeys=t,this.hoveredEditorGroupKeysSignature=i,this.scheduleLayoutRefresh())}syncHoveredPreviewGroupsFromTarget(e){this.updateHoveredPreviewGroups(this.getPreviewGroupKeysForTarget(e))}shouldRenderPassivePreviewMarkers(){let e=this.previewContainer?.clientWidth??this.previewElement?.clientWidth??0;return window.innerWidth>=bn&&e>=vn}updateReactionPickerPosition(e){let t=Fn(e);if(!t)return;let{picker:i,scroll:s,wrap:r}=t;i.classList.remove("is-upward"),i.style.maxHeight="";let a=r.getBoundingClientRect(),o=s.getBoundingClientRect(),l=i.getBoundingClientRect(),h=12,c=window.innerHeight-12,u=Math.min(o.bottom,c),p=Math.max(o.top,h),d=Math.max(u-a.bottom-8,0),w=Math.max(a.top-p-8,0),m=l.height>d&&w>d,b=Math.max(m?w:d,120);i.classList.toggle("is-upward",m),i.style.maxHeight=`${b}px`}repositionActiveCard(){let e=this.cardRoot?.firstElementChild;if(!e||!this.activeCard){this.cardRoot&&(this.cardRoot.style.visibility="");return}this.positionCard(e),this.cardRoot.style.visibility="",this.flushPendingCardFocus()}createComposer(){let e=document.createElement("form");e.className="comment-card-form";let t=document.createElement("textarea");t.className="input comment-card-input",t.rows=4,t.maxLength=vt,t.placeholder="Add context, feedback, or a question...";let i=document.createElement("div");i.className="comment-card-actions";let s=document.createElement("button");s.type="button",s.className="btn btn-secondary",s.textContent="Cancel",s.addEventListener("click",()=>this.closeCard());let r=document.createElement("button");return r.type="submit",r.className="btn btn-primary",r.textContent="Post comment",i.append(s,r),e.append(t,i),e.addEventListener("submit",async a=>{if(a.preventDefault(),!await this.onCreateThread?.({anchor:this.activeCard?.anchor,body:t.value})){t.focus();return}this.closeCard()}),this.pendingCardFocusElement=t,e}createThreadElement(e){let t=document.createElement("article");t.className="comment-thread-card";let i=document.createElement("div");i.className="comment-thread-card-header";let s=document.createElement("div");s.className="comment-thread-card-heading";let r=document.createElement("span");r.className="comment-thread-card-author",r.textContent=e.createdByName;let a=document.createElement("span");a.className="comment-thread-card-time",a.textContent=this.formatTimestamp(e.createdAt);let o=document.createElement("div");o.className="comment-thread-card-actions";let l=document.createElement("button");l.type="button",l.className="comment-thread-card-action",l.textContent="Jump",l.addEventListener("click",()=>this.onNavigateToLine?.(e.anchor?.startLine??1));let h=document.createElement("button");h.type="button",h.className="comment-thread-card-action";let c=this.activeCard?.replyThreadId===e.id;h.classList.toggle("is-active",c),h.textContent="Reply",h.setAttribute("aria-pressed",String(c)),h.setAttribute("aria-label",c?"Cancel reply":"Reply to thread"),h.title=c?"Cancel reply":"Reply to thread",h.addEventListener("click",()=>{this.activeCard={...this.activeCard,replyThreadId:c?null:e.id},this.renderCard()});let u=document.createElement("button");return u.type="button",u.className="comment-thread-card-action is-danger",u.textContent="Resolve",u.addEventListener("click",async()=>{await this.onResolveThread?.(e.id)}),o.append(l,h,u),s.append(r,a),i.append(s,o),t.append(i),e.messages.forEach(p=>{t.appendChild(this.createMessageElement(e,p))}),this.activeCard?.replyThreadId===e.id&&t.appendChild(this.createReplyComposer(e)),t}createMessageElement(e,t){let i=document.createElement("div");i.className="comment-message-card";let s=document.createElement("div");s.className="comment-message-card-meta";let r=document.createElement("span");r.className="comment-message-card-author",r.textContent=t.userName;let a=document.createElement("span");a.className="comment-message-card-time",a.textContent=this.formatTimestamp(t.createdAt);let o=Ai(t.body,"comment-message-card-body comment-markdown");return s.append(r,a),i.append(s,o),i.appendChild(this.createReactionBar(e,t)),i}createReactionBar(e,t){let i=this.session?.getLocalUser?.()?.userId??"",s=document.createElement("div");s.className="comment-reaction-bar";let r=new Set((t.reactions??[]).map(c=>c.emoji)),a=document.createElement("div");a.className="comment-reaction-chips",(t.reactions??[]).forEach(c=>{let u=document.createElement("button");u.type="button",u.className="comment-reaction-chip",u.classList.toggle("is-active",Mi(c,i)),u.setAttribute("aria-pressed",String(Mi(c,i))),u.title=c.users?.map(w=>w.userName).join(", ")||c.emoji;let p=document.createElement("span");p.className="comment-reaction-chip-emoji",p.textContent=c.emoji;let d=document.createElement("span");d.className="comment-reaction-chip-count",d.textContent=In(c),u.append(p,d),u.addEventListener("click",async()=>{await this.onToggleReaction?.(e.id,t.id,c.emoji)}),a.appendChild(u)});let o=document.createElement("div");o.className="comment-reaction-actions",Cn.filter(c=>!r.has(c)).forEach(c=>{o.appendChild(this.createQuickReactionButton(e,t,c))});let l=document.createElement("div");l.className="comment-reaction-picker-wrap";let h=document.createElement("button");return h.type="button",h.className="comment-reaction-more-trigger",h.dataset.reactionPickerToggle="true",h.setAttribute("aria-expanded",String(Rt(this.reactionPicker,e.id,t.id))),h.textContent="More",h.addEventListener("click",()=>{let c=Rt(this.reactionPicker,e.id,t.id);this.reactionPicker=c?null:{messageId:t.id,threadId:e.id},this.renderCard()}),l.appendChild(h),Rt(this.reactionPicker,e.id,t.id)&&l.appendChild(this.createReactionPicker(e,t)),o.appendChild(l),s.append(a,o),s}createQuickReactionButton(e,t,i){let s=document.createElement("button");return s.type="button",s.className="comment-reaction-quick-add",s.textContent=i,s.title=`React with ${i}`,s.addEventListener("click",async()=>{await this.onToggleReaction?.(e.id,t.id,i)}),s}createReactionPicker(e,t){let i=document.createElement("div");i.className="comment-reaction-picker";let s=document.createElement("div");return s.className="comment-reaction-picker-grid",En.forEach(r=>{s.appendChild(this.createReactionPickerButton(e,t,r))}),i.appendChild(s),i}createReactionPickerButton(e,t,i){let s=document.createElement("button");return s.type="button",s.className="comment-reaction-picker-btn",s.textContent=i,s.title=`React with ${i}`,s.addEventListener("click",async()=>{await this.onToggleReaction?.(e.id,t.id,i)&&(this.reactionPicker=null,this.renderCard())}),s}createReplyComposer(e){let t=document.createElement("form");t.className="comment-reply-form";let i=document.createElement("textarea");i.className="input comment-card-input",i.rows=3,i.maxLength=vt,i.placeholder="Reply to thread...";let s=document.createElement("div");s.className="comment-card-actions";let r=document.createElement("button");r.type="button",r.className="btn btn-secondary",r.textContent="Cancel",r.addEventListener("click",()=>{this.activeCard={...this.activeCard,replyThreadId:null},this.renderCard()});let a=document.createElement("button");return a.type="submit",a.className="btn btn-primary",a.textContent="Reply",s.append(r,a),t.append(i,s),this.pendingCardFocusElement=i,t.addEventListener("submit",async o=>{if(o.preventDefault(),!await this.onReplyToThread?.(e.id,i.value)){i.focus();return}this.activeCard={...this.activeCard,replyThreadId:null},this.renderCard()}),t}positionCard(e){let t=this.updateCardSourceRect(),i=window.innerWidth,s=window.innerHeight,r=e.getBoundingClientRect(),a=ee((i-r.width)/2,16,i-r.width-16),o=ee((s-r.height)/4,16,s-r.height-16),l=a,h=o;t&&(l=ee(t.left,16,i-Math.min(r.width,xi)-16),h=t.bottom+Li,h+r.height>s-16&&(h=Math.max(t.top-r.height-Li,16))),this.cardRoot.style.left=`${l}px`,this.cardRoot.style.top=`${h}px`,this.cardRoot.style.width=`${Math.min(Math.max(r.width,xi),i-32)}px`}formatTimestamp(e){if(!Number.isFinite(e))return"";try{return this.timeFormatter.format(new Date(e))}catch{return""}}flushPendingCardFocus(){let e=this.pendingCardFocusElement;if(!(e instanceof HTMLElement)||!e.isConnected){this.pendingCardFocusElement=null;return}this.pendingCardFocusElement=null;let t=()=>{if(!e.isConnected)return;let i=document.activeElement;i instanceof HTMLElement&&this.editorContainer?.contains(i)&&i.blur(),e.focus({preventScroll:!0})};t(),document.activeElement!==e&&requestAnimationFrame(()=>{t(),document.activeElement!==e&&setTimeout(()=>{t()},50)})}clearSelectionRevealTimer(){this.selectionRevealTimer&&(clearTimeout(this.selectionRevealTimer),this.selectionRevealTimer=0)}scheduleSelectionReveal(e){this.clearSelectionRevealTimer(),this.selectionRevealTimer=window.setTimeout(()=>{this.selectionRevealTimer=0,!(this.pointerSelecting||this.activeCard?.mode==="create"||!Ii(this.pendingSelectionAnchor,e))&&(this.committedSelectionAnchor=e,this.scheduleLayoutRefresh())},wn)}};function Xe(n,e){let t=new Map;e.forEach(s=>{let a=n.get(s.key)??{filePath:s.filePath,iframe:null,instanceId:null,key:s.key,label:s.label,placeholder:s.placeholder,queued:!1,reusedFromEmbed:!1,wrapper:null};a.filePath=s.filePath,a.key=s.key,a.label=s.label,a.placeholder=s.placeholder,t.set(s.key,a)});let i=[];return n.forEach((s,r)=>{t.has(r)||i.push(s)}),{nextEntries:t,removedEntries:i}}var de=420,Nn=500,Dn=15e3,Hn=800,_n=3,zn=200,Un="/excalidraw-editor.html";function $n(n,e){return typeof window.requestIdleCallback=="function"?window.requestIdleCallback(n,{timeout:e}):window.setTimeout(()=>{n({didTimeout:!1,timeRemaining:()=>0})},1)}function Je(n){if(n!==null){if(typeof window.cancelIdleCallback=="function"){window.cancelIdleCallback(n);return}window.clearTimeout(n)}}function On(n,e,t){if(!n||!e)return!1;let i=e.getBoundingClientRect(),s=n.getBoundingClientRect();return s.bottom>=i.top-t&&s.top<=i.bottom+t}var et=class{constructor({getTheme:e,getLocalUser:t,onOpenFile:i=null,previewContainer:s,previewElement:r,toastController:a}){this.getTheme=e,this.getLocalUser=t,this.onOpenFile=i,this.previewContainer=s,this.previewElement=r,this.toastController=a,this.embedEntries=new Map,this.hydrationQueue=[],this.hydrationIdleId=null,this.hydrationPaused=!1,this.hydrationInProgress=!1,this.instanceCounter=0,this.isLargeDocument=!1,this.maximizedEmbed=null,this.overlayRoot=null,this.maximizedRoot=null,this.placeholderObserver=null,this.followedPeerIdsByFilePath=new Map,this._onMessage=this._onMessage.bind(this),this._onKeyDown=this._onKeyDown.bind(this),this._onPreviewClick=this._onPreviewClick.bind(this),window.addEventListener("message",this._onMessage),window.addEventListener("keydown",this._onKeyDown),this.previewElement?.addEventListener("click",this._onPreviewClick)}destroy(){window.removeEventListener("message",this._onMessage),window.removeEventListener("keydown",this._onKeyDown),this.previewElement?.removeEventListener("click",this._onPreviewClick),this._disconnectPlaceholderObserver(),Je(this.hydrationIdleId),this.hydrationIdleId=null,this.hydrationQueue=[],this._exitMaximizedEmbed(),document.body.classList.remove("excalidraw-maximized-open"),this.embedEntries.forEach(e=>{this._clearEntryBootTimeout(e),e.wrapper?.remove(),e.placeholder=null}),this.embedEntries.clear(),this.followedPeerIdsByFilePath.clear(),this.overlayRoot?.remove(),this.overlayRoot=null,this.maximizedRoot?.remove(),this.maximizedRoot=null}async setFollowedUser(e,t=null){if(!e)return!1;this.followedPeerIdsByFilePath.set(e,t||null);let i=this._findEntryByFilePath(e);return i&&(i.wrapper||await this._hydrateEntry(i),i.followedPeerId=this.followedPeerIdsByFilePath.get(e)??null,this._syncEntryFollowState(i)),!0}detachForCommit(){this._disconnectPlaceholderObserver(),Je(this.hydrationIdleId),this.hydrationIdleId=null,this.hydrationQueue=[],this.hydrationInProgress=!1,this.overlayRoot&&(this.overlayRoot.hidden=!0),this.maximizedRoot&&(this.maximizedRoot.hidden=!0),this.embedEntries.forEach(e=>{e.queued=!1,e.placeholder=null})}setHydrationPaused(e){if(this.hydrationPaused=!!e,this.hydrationPaused){Je(this.hydrationIdleId),this.hydrationIdleId=null;return}this.hydrateVisibleEmbeds(),this._scheduleHydration()}reconcileEmbeds(e,{isLargeDocument:t=!1}={}){this.isLargeDocument=!!t,this._disconnectPlaceholderObserver(),Je(this.hydrationIdleId),this.hydrationIdleId=null,this.hydrationQueue=[],this.hydrationInProgress=!1;let i=Array.from(e.querySelectorAll(".excalidraw-embed-placeholder[data-embed-key]")).map(a=>({filePath:a.dataset.embedTarget,key:a.dataset.embedKey,label:a.dataset.embedLabel||a.dataset.embedTarget,placeholder:a})),{nextEntries:s,removedEntries:r}=Xe(this.embedEntries,i);this._adoptReusableEntries(s,r),r.forEach(a=>this._destroyEntry(a)),this.embedEntries=s,this._ensurePlaceholderObserver(),this.embedEntries.forEach(a=>{if(a.queued=!1,a.followedPeerId=this.followedPeerIdsByFilePath.get(a.filePath),a.wrapper){this._updateEmbedLabel(a),this._attachWrapper(a);return}a.placeholder&&this.placeholderObserver?.observe(a.placeholder)}),this.hydrationPaused||this.hydrateVisibleEmbeds(),this.syncLayout()}hydrateVisibleEmbeds(){if(this.hydrationPaused)return;let e=this.isLargeDocument?180:420;this.embedEntries.forEach(t=>{t.wrapper||!t.placeholder?.isConnected||On(t.placeholder,this.previewContainer,e)&&this._enqueueHydration(t,{prioritize:!0})})}updateTheme(e){this.embedEntries.forEach(t=>{this._postMessageToEntry(t,{source:"collabmd-host",type:"set-theme",theme:e})})}updateLocalUser(e){this.embedEntries.forEach(t=>{this._syncEntryUser(t,e)})}_ensurePlaceholderObserver(){this.previewContainer&&(this.placeholderObserver=new IntersectionObserver(e=>{e.forEach(t=>{if(!t.isIntersecting)return;let i=this.embedEntries.get(t.target.dataset.embedKey);i&&this._enqueueHydration(i)})},{root:this.previewContainer,rootMargin:this.isLargeDocument?"180px 0px":"420px 0px"}))}_disconnectPlaceholderObserver(){this.placeholderObserver&&(this.placeholderObserver.disconnect(),this.placeholderObserver=null)}_enqueueHydration(e,{prioritize:t=!1}={}){if(!(!e||e.wrapper||e.queued)&&(e.queued=!0,t?this.hydrationQueue.unshift(e.key):this.hydrationQueue.push(e.key),!this.hydrationPaused)){if(t&&!this.hydrationInProgress&&this.hydrationIdleId===null){this._flushHydrationQueue();return}this._scheduleHydration()}}_scheduleHydration(){this.hydrationPaused||this.hydrationInProgress||this.hydrationIdleId!==null||(this.hydrationIdleId=$n(()=>{this.hydrationIdleId=null,this._flushHydrationQueue()},Nn))}async _flushHydrationQueue(){if(this.hydrationPaused||this.hydrationInProgress)return;let e=null;for(;this.hydrationQueue.length>0&&!e;){let t=this.hydrationQueue.shift(),i=this.embedEntries.get(t);if(!i||i.wrapper||!i.placeholder?.isConnected){i&&(i.queued=!1);continue}e=i}e&&(this.hydrationInProgress=!0,e.queued=!1,await this._hydrateEntry(e),this.hydrationInProgress=!1,this.hydrationQueue.length>0&&this._scheduleHydration())}async _hydrateEntry(e){if(!(!e.placeholder?.isConnected&&!e.wrapper)){if(!e.wrapper){let t=this._createEmbedContainer(e);e.wrapper=t.wrapper,e.iframe=t.iframe,e.labelElement=t.labelElement,e.instanceId=t.instanceId,e.isReady=!1,e.bootAttempts=(e.bootAttempts??0)+1,this._armEntryBootTimeout(e)}e.followedPeerId=this.followedPeerIdsByFilePath.get(e.filePath),this._updateEmbedLabel(e),this._attachWrapper(e)}}_attachWrapper(e){let t=e.placeholder?.isConnected?e.placeholder:this.previewElement?.querySelector(`.excalidraw-embed-placeholder[data-embed-key="${e.key}"]`);if(!t)return;if(e.placeholder=t,this._syncMountedEntryMetadata(e),this._shouldInlineFilePreview(e)){e.wrapper.style.position="",e.wrapper.style.top="",e.wrapper.style.left="",e.wrapper.style.width="",e.wrapper.style.margin="",e.wrapper.style.pointerEvents="auto",t.replaceWith(e.wrapper),e.placeholder=null;return}let i=this._ensureOverlayRoot();i.hidden=!1,e.wrapper?.parentElement!==i&&i.appendChild(e.wrapper),this._syncEntryLayout(e)}_adoptReusableEntries(e,t){e.forEach((i,s)=>{if(i.wrapper||i.iframe)return;let r=t.findIndex(o=>o.filePath===i.filePath&&this._getEntryMode(o)===this._getEntryMode(i)&&(o.wrapper||o.iframe));if(r<0)return;let[a]=t.splice(r,1);a.filePath=i.filePath,a.key=i.key,a.label=i.label,a.placeholder=i.placeholder,a.queued=!1,a.reusedFromEmbed=this._isFilePreviewEntry(i),e.set(s,a)})}_destroyEntry(e){this.maximizedEmbed?.wrapper===e.wrapper&&this._exitMaximizedEmbed(),this._clearEntryBootTimeout(e),this._resetPlaceholderLayout(e),e.wrapper?.remove(),e.placeholder=null}_armEntryBootTimeout(e){this._clearEntryBootTimeout(e),e.bootTimerId=window.setTimeout(()=>{this._handleEntryBootTimeout(e)},Dn)}_clearEntryBootTimeout(e){e?.bootTimerId&&(window.clearTimeout(e.bootTimerId),e.bootTimerId=null)}async _handleEntryBootTimeout(e){if(e?.iframe?.isConnected){if((e.bootAttempts??0)>=_n){this._clearEntryBootTimeout(e),this.toastController?.show(`Excalidraw embed timed out: ${e.label}`);return}await this._retryEntryBootstrap(e)}}async _retryEntryBootstrap(e){e&&(this._clearEntryBootTimeout(e),this._resetPlaceholderLayout(e),this.maximizedEmbed?.wrapper===e.wrapper&&this._exitMaximizedEmbed(),e.wrapper?.remove(),e.wrapper=null,e.iframe=null,e.labelElement=null,e.instanceId=null,e.isReady=!1,await this._hydrateEntry(e))}_findEntryByContentWindow(e){if(!e)return null;for(let t of this.embedEntries.values())if(t.iframe?.contentWindow===e)return t;return null}_findEntryByFilePath(e){if(!e)return null;for(let t of this.embedEntries.values())if(t.filePath===e)return t;return null}_updateEmbedLabel(e){e.labelElement&&(e.labelElement.textContent=e.label.replace(/\.excalidraw$/i,""))}_syncMountedEntryMetadata(e){e.wrapper&&(e.wrapper.dataset.embedKey=e.key,e.wrapper.dataset.file=e.filePath),e.iframe&&(e.iframe.title=`Excalidraw: ${e.filePath}`)}_buildIframeUrl(e){let t=new URL(_t(Un)),i=this.getTheme?.()||"dark";t.searchParams.set("file",e.filePath),t.searchParams.set("theme",i),t.searchParams.set("boot",e.instanceId||""),this._isFilePreviewEntry(e)||t.searchParams.set("mode","preview");let s=this.getLocalUser?.();s?.name&&t.searchParams.set("userName",s.name),s?.color&&t.searchParams.set("userColor",s.color),s?.colorLight&&t.searchParams.set("userColorLight",s.colorLight),s?.peerId&&t.searchParams.set("userPeerId",s.peerId);let r=new URLSearchParams(window.location.search),a=r.get("server");return a&&t.searchParams.set("server",a),r.get("test")==="1"&&t.searchParams.set("test","1"),r.has("syncTimeoutMs")&&t.searchParams.set("syncTimeoutMs",r.get("syncTimeoutMs")),t}_createEmbedContainer(e){let t=document.createElement("div");t.className="excalidraw-embed diagram-preview-shell",t.dataset.embedKey=e.key,t.dataset.file=e.filePath;let i=document.createElement("div");i.className="excalidraw-embed-header diagram-preview-toolbar";let s=document.createElement("span");s.className="excalidraw-embed-icon",s.innerHTML='<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M12 19l7-7 3 3-7 7-3-3z"/><path d="M18 13l-1.5-7.5L2 2l3.5 14.5L13 18l5-5z"/><path d="M2 2l7.586 7.586"/><circle cx="11" cy="11" r="2"/></svg>';let r=document.createElement("span");r.className="excalidraw-embed-label",r.textContent=e.label.replace(/\.excalidraw$/i,"");let a=document.createElement("button");a.type="button",a.className="excalidraw-embed-btn diagram-preview-action-btn",a.title="Edit in Excalidraw",a.setAttribute("aria-label","Edit in Excalidraw"),T(a,"edit");let o=document.createElement("button");o.type="button",o.className="excalidraw-embed-btn diagram-preview-action-btn",o.title="Maximize diagram",o.setAttribute("aria-label","Maximize diagram"),T(o,"maximize"),i.append(s,r),this._isFilePreviewEntry(e)||i.append(a),i.append(o);let l=document.createElement("iframe");l.className="excalidraw-embed-iframe",l.dataset.instanceId=String(++this.instanceCounter),e.instanceId=l.dataset.instanceId,l.src=this._buildIframeUrl(e).toString(),l.setAttribute("loading","eager"),l.title=`Excalidraw: ${e.filePath}`,l.style.height=`${de}px`;let h=document.createElement("div");h.className="excalidraw-embed-resizer",h.title="Drag to resize",this._setupResizer(h,l,()=>this._syncEntryLayout(e)),t.append(i,l,h);let c=!1,u=`${de}px`,p=()=>{T(o,c?"restore":"maximize"),o.title=c?"Restore diagram size":"Maximize diagram",o.setAttribute("aria-label",c?"Restore diagram size":"Maximize diagram")},d=()=>{c&&(c=!1,t.classList.remove("is-maximized"),p(),document.body.classList.remove("excalidraw-maximized-open"),this._restoreWrapperMount(e),l.style.height=u,this.maximizedEmbed?.wrapper===t&&(this.maximizedEmbed=null),this._syncEntryLayout(e))},w=()=>{c||(this._exitMaximizedEmbed(),c=!0,u=l.style.height||`${de}px`,this._mountWrapperInMaximizedRoot(e),t.classList.add("is-maximized"),p(),document.body.classList.add("excalidraw-maximized-open"),this.maximizedEmbed={wrapper:t,exit:d},this._syncEntryLayout(e))};return o.addEventListener("click",()=>{c?d():w()}),a.addEventListener("click",()=>{this.onOpenFile?.(e.filePath)}),p(),{iframe:l,instanceId:l.dataset.instanceId,labelElement:r,wrapper:t}}_setupResizer(e,t,i=null){let s=0,r=0,a=l=>{let h=l.clientY-s,c=Math.min(Math.max(r+h,zn),Hn);t.style.height=`${c}px`,t.style.pointerEvents="none"},o=()=>{t.style.pointerEvents="",document.removeEventListener("pointermove",a),document.removeEventListener("pointerup",o),i?.()};e.addEventListener("pointerdown",l=>{l.preventDefault(),s=l.clientY,r=t.offsetHeight,document.addEventListener("pointermove",a),document.addEventListener("pointerup",o)})}_ensureOverlayRoot(){if(this.overlayRoot?.isConnected&&this.overlayRoot.parentElement===this.previewElement)return this.overlayRoot;let e=this.previewElement?.querySelector('[data-excalidraw-overlay-root="true"]');return e||(e=document.createElement("div"),e.dataset.excalidrawOverlayRoot="true",e.className="excalidraw-embed-overlay-root",this.previewElement?.appendChild(e)),this.overlayRoot=e,e}_ensureMaximizedRoot(){if(this.maximizedRoot?.isConnected&&this.maximizedRoot.parentElement===document.body)return this.maximizedRoot;let e=document.body.querySelector('[data-excalidraw-maximized-root="true"]');return e||(e=document.createElement("div"),e.dataset.excalidrawMaximizedRoot="true",e.className="excalidraw-maximized-root",document.body.appendChild(e)),this.maximizedRoot=e,e}_isFilePreviewEntry(e){return e?.key===`${e?.filePath}#file-preview`}_getEntryMode(e){return this._isFilePreviewEntry(e)?"edit":"preview"}_shouldInlineFilePreview(e){return this._isFilePreviewEntry(e)&&!e?.reusedFromEmbed}_resetPlaceholderLayout(e){!e?.placeholder?.isConnected||this._shouldInlineFilePreview(e)||(e.placeholder.classList.remove("is-hydrated"),e.placeholder.removeAttribute("data-embed-hydrated"),e.placeholder.style.height="",e.placeholder.style.pointerEvents="")}_mountWrapperInMaximizedRoot(e){if(!e?.wrapper)return;let t=this._ensureMaximizedRoot();t.hidden=!1,e.restoreParent=e.wrapper.parentElement||null,e.restoreNextSibling=e.wrapper.nextSibling||null,e.wrapper.style.position="",e.wrapper.style.top="",e.wrapper.style.left="",e.wrapper.style.width="",e.wrapper.style.margin="",e.wrapper.parentElement!==t&&t.appendChild(e.wrapper)}_restoreWrapperMount(e){if(e?.wrapper){if(this._shouldInlineFilePreview(e)){let{restoreParent:t,restoreNextSibling:i}=e;t?.isConnected&&(i?.parentElement===t?t.insertBefore(e.wrapper,i):t.appendChild(e.wrapper))}else{let t=this._ensureOverlayRoot();t.hidden=!1,e.wrapper.parentElement!==t&&t.appendChild(e.wrapper)}e.restoreParent=null,e.restoreNextSibling=null,this.maximizedRoot&&this.maximizedRoot.childElementCount===0&&(this.maximizedRoot.hidden=!0)}}_syncEntryLayout(e){if(!e?.wrapper||this._shouldInlineFilePreview(e))return;let t=e.placeholder?.isConnected?e.placeholder:this.previewElement?.querySelector(`.excalidraw-embed-placeholder[data-embed-key="${e.key}"]`);if(!t)return;e.placeholder=t,t.classList.add("is-hydrated"),t.dataset.embedHydrated="true",t.style.pointerEvents="none",this._isFilePreviewEntry(e)&&t.childElementCount>0&&t.replaceChildren();let i=e.wrapper.classList.contains("is-maximized"),s=e.wrapper.querySelector(".excalidraw-embed-header")?.offsetHeight||0,r=e.iframe?.offsetHeight||Number.parseFloat(e.iframe?.style.height||"")||de,a=i?0:e.wrapper.querySelector(".excalidraw-embed-resizer")?.offsetHeight||0,o=Math.ceil(s+r+a);if(i||(e.inlineHeightPx=o),t.style.height=`${Math.ceil(e.inlineHeightPx||o||de)}px`,e.wrapper.style.pointerEvents="auto",i){e.wrapper.style.position="",e.wrapper.style.top="",e.wrapper.style.left="",e.wrapper.style.width="",e.wrapper.style.margin="";return}e.wrapper.style.position="absolute",e.wrapper.style.top=`${t.offsetTop}px`,e.wrapper.style.left=`${t.offsetLeft}px`,e.wrapper.style.width=`${t.offsetWidth}px`,e.wrapper.style.margin="0"}syncLayout(){this.embedEntries.forEach(e=>{e.wrapper&&!this._shouldInlineFilePreview(e)&&this._syncEntryLayout(e)})}_onPreviewClick(e){let t=e.target.closest(".excalidraw-embed-placeholder-btn");if(!t)return;e.preventDefault();let i=this.embedEntries.get(t.dataset.embedKey);i&&this._hydrateEntry(i)}_onMessage(e){if(e.origin!==window.location.origin)return;let t=e.data;if(!t||t.source!=="excalidraw-editor")return;let i=this._findEntryByContentWindow(e.source);if(i){if(t.type==="ready"){i.isReady=!0,this._clearEntryBootTimeout(i),this._syncEntryUser(i),this._postMessageToEntry(i,{source:"collabmd-host",type:"set-theme",theme:this.getTheme?.()||"dark"}),this._syncEntryFollowState(i);return}t.type==="error"&&(i.isReady=!1,this._handleEntryBootTimeout(i))}}_onKeyDown(e){e.key==="Escape"&&this._exitMaximizedEmbed()}_exitMaximizedEmbed(){this.maximizedEmbed?.exit&&this.maximizedEmbed.exit(),this.maximizedEmbed=null,document.body.classList.remove("excalidraw-maximized-open")}_postMessageToEntry(e,t){e?.iframe?.contentWindow?.postMessage(t,window.location.origin)}_syncEntryUser(e,t=null){let i=t||this.getLocalUser?.();i&&this._postMessageToEntry(e,{source:"collabmd-host",type:"set-user",user:{color:i.color||"",colorLight:i.colorLight||"",name:i.name||"",peerId:i.peerId||""}})}_syncEntryFollowState(e){!e?.isReady||e.followedPeerId===void 0||this._postMessageToEntry(e,{source:"collabmd-host",type:"follow-user",peerId:e.followedPeerId})}};function qn(n){return String(n??"").replace(/\/+$/u,"").split("/").filter(Boolean).pop()||""}function Wn(){return JSON.stringify({type:"excalidraw",version:2,source:"collabmd",elements:[],appState:{viewBackgroundColor:"#ffffff",gridSize:null},files:{}})}var tt=class{constructor({onFileDelete:e,onFileSelect:t,state:i,toastController:s,vaultClient:r,view:a,refresh:o}){this.onFileDelete=e,this.onFileSelect=t,this.state=i,this.toastController=s,this.vaultClient=r,this.view=a,this.refresh=o,this.newFileButton=document.getElementById("newFileBtn"),this.newDrawingButton=document.getElementById("newDrawingBtn"),this.newMermaidButton=document.getElementById("newMermaidBtn"),this.newPlantumlButton=document.getElementById("newPlantumlBtn"),this.newFolderButton=document.getElementById("newFolderBtn"),this.refreshButton=document.getElementById("refreshFilesBtn"),this.actionDialog=document.getElementById("fileActionDialog"),this.actionForm=document.getElementById("fileActionForm"),this.actionTitle=document.getElementById("fileActionTitle"),this.actionCopy=document.getElementById("fileActionCopy"),this.actionField=document.getElementById("fileActionField"),this.actionLabel=document.getElementById("fileActionLabel"),this.actionInput=document.getElementById("fileActionInput"),this.actionHint=document.getElementById("fileActionHint"),this.actionNote=document.getElementById("fileActionNote"),this.actionCancelButton=document.getElementById("fileActionCancel"),this.actionSubmitButton=document.getElementById("fileActionSubmit"),this.pendingAction=null,this.actionBusy=!1}initialize(){this.newFileButton?.addEventListener("click",()=>this.handleNewFile()),this.newDrawingButton?.addEventListener("click",()=>this.handleNewDrawing()),this.newMermaidButton?.addEventListener("click",()=>this.handleNewMermaid()),this.newPlantumlButton?.addEventListener("click",()=>this.handleNewPlantUml()),this.newFolderButton?.addEventListener("click",()=>this.handleNewFolder()),this.refreshButton?.addEventListener("click",()=>this.refresh()),this.actionCancelButton?.addEventListener("click",()=>this.closeActionDialog()),this.actionForm?.addEventListener("submit",e=>{e.preventDefault(),this.handleActionSubmit()}),this.actionDialog?.addEventListener("close",()=>this.resetActionDialog())}createContextMenuItems(e=""){return[{label:"New markdown file",onSelect:()=>this.handleNewFile({parentDir:e})},{label:"New Excalidraw drawing",onSelect:()=>this.handleNewDrawing({parentDir:e})},{label:"New Mermaid diagram",onSelect:()=>this.handleNewMermaid({parentDir:e})},{label:"New PlantUML diagram",onSelect:()=>this.handleNewPlantUml({parentDir:e})},{label:"New folder",onSelect:()=>this.handleNewFolder({parentDir:e})}]}getFileContextMenuItems(e){return[{label:"Rename",onSelect:()=>this.handleRename(e)},{label:"Delete",danger:!0,onSelect:()=>this.handleDelete(e)}]}showToast(e){e&&this.toastController?.show(String(e))}showError(e,t){this.showToast(t?.message?`${e}: ${t.message}`:e)}ensureExtension(e,t){return ai(e,t)}openActionDialog({title:e,copy:t,label:i="Path",hint:s="",note:r="",placeholder:a="",value:o="",submitLabel:l="Save",destructive:h=!1,requiresInput:c=!0,emptyMessage:u="A value is required",onSubmit:p}){!this.actionDialog||!this.actionTitle||!this.actionCopy||!this.actionSubmitButton||!this.actionCancelButton||c&&!this.actionInput||(this.actionDialog.open&&(typeof this.actionDialog.close=="function"?this.actionDialog.close():(this.actionDialog.removeAttribute("open"),this.resetActionDialog())),this.pendingAction={requiresInput:c,emptyMessage:u,onSubmit:p},this.view?.removeContextMenu?.(),this.actionTitle.textContent=e,this.actionCopy.textContent=t,this.actionField&&(this.actionField.hidden=!c),this.actionLabel&&(this.actionLabel.textContent=i),this.actionInput&&(this.actionInput.value=o,this.actionInput.placeholder=a,this.actionInput.required=c,this.actionInput.disabled=!1),this.actionHint&&(this.actionHint.textContent=s,this.actionHint.hidden=!c||!s),this.actionNote&&(this.actionNote.textContent=r,this.actionNote.hidden=!r,this.actionNote.classList.toggle("is-danger",h)),this.actionSubmitButton.textContent=l,this.actionSubmitButton.disabled=!1,this.actionSubmitButton.classList.toggle("btn-primary",!h),this.actionSubmitButton.classList.toggle("btn-danger",h),this.actionCancelButton.disabled=!1,typeof this.actionDialog.showModal=="function"?this.actionDialog.showModal():this.actionDialog.setAttribute("open","true"),requestAnimationFrame(()=>{if(!c||!this.actionInput){this.actionSubmitButton.focus();return}this.actionInput.focus(),o&&this.actionInput.select()}))}resetActionDialog(){this.pendingAction=null,this.actionBusy=!1,this.actionField&&(this.actionField.hidden=!1),this.actionLabel&&(this.actionLabel.textContent="Path"),this.actionInput&&(this.actionInput.value="",this.actionInput.placeholder="",this.actionInput.required=!0,this.actionInput.disabled=!1),this.actionHint&&(this.actionHint.textContent="",this.actionHint.hidden=!0),this.actionNote&&(this.actionNote.textContent="",this.actionNote.hidden=!0,this.actionNote.classList.remove("is-danger")),this.actionSubmitButton&&(this.actionSubmitButton.textContent="Save",this.actionSubmitButton.disabled=!1,this.actionSubmitButton.classList.add("btn-primary"),this.actionSubmitButton.classList.remove("btn-danger")),this.actionCancelButton&&(this.actionCancelButton.disabled=!1)}closeActionDialog(){if(this.actionDialog){if(this.actionDialog.open&&typeof this.actionDialog.close=="function"){this.actionDialog.close();return}this.actionDialog.removeAttribute("open"),this.resetActionDialog()}}setActionDialogBusy(e){this.actionBusy=e,this.actionInput&&(this.actionInput.disabled=e||!(this.pendingAction?.requiresInput??!0)),this.actionCancelButton&&(this.actionCancelButton.disabled=e),this.actionSubmitButton&&(this.actionSubmitButton.disabled=e)}async handleActionSubmit(){if(!this.pendingAction?.onSubmit||this.actionBusy)return;let e=this.pendingAction.requiresInput,t=e?this.actionInput?.value.trim()??"":void 0;if(e&&!t){this.showToast(this.pendingAction.emptyMessage),this.actionInput?.focus();return}this.setActionDialogBusy(!0);let i=!1;try{i=await this.pendingAction.onSubmit(t)}catch(s){i=!1,this.showError("Failed to complete action",s)}if(this.setActionDialogBusy(!1),i!==!1){this.closeActionDialog();return}e&&this.actionInput&&(this.actionInput.focus(),this.actionInput.select())}async createVaultFile(e,t,{openAfterCreate:i=!1,errorMessage:s="Failed to create file"}={}){try{return await this.vaultClient.createFile({content:t,path:e}),this.state.expandDirectoryPath(e,{includeLeaf:!1}),await this.refresh(),i&&this.onFileSelect?.(e),!0}catch(r){return this.showToast(r?.message||s),!1}}async createDirectory(e){let t=L(e);if(!t)return this.showToast("Folder path is required"),!1;try{return await this.vaultClient.createDirectory(t),this.state.expandDirectoryPath(t),await this.refresh(),!0}catch(i){return this.showToast(i?.message||"Failed to create folder"),!1}}async renameVaultFile(e,t,i){let s=String(t??"").trim();if(!s)return this.showToast("File name is required"),!1;if(/[\\/]/u.test(s))return this.showToast("Rename only supports the file name right now"),!1;let r=q(s).trim();if(!r)return this.showToast("File name is required"),!1;let o=`${e.includes("/")?e.substring(0,e.lastIndexOf("/")+1):""}${r}${i}`;if(o===e)return!0;try{return await this.vaultClient.renameFile({newPath:o,oldPath:e}),this.state.expandDirectoryPath(o,{includeLeaf:!1}),await this.refresh(),this.state.activeFilePath===e&&(this.state.activeFilePath=o,this.onFileSelect?.(o)),!0}catch(l){return this.showToast(l?.message||"Failed to rename"),!1}}async deleteVaultFile(e){try{return await this.vaultClient.deleteFile(e),await this.refresh(),this.state.activeFilePath===e&&(this.state.activeFilePath=null,this.onFileDelete?.(e)),!0}catch(t){return this.showToast(t?.message||"Failed to delete"),!1}}getCreateContext(e=""){let t=L(e);return{hintPrefix:t?'Use "/" to create nested items under this folder.':'Use "/" to place it inside a folder.',inputLabelSuffix:t?"name or path":"path",note:t?`Parent folder: ${t}`:"",normalizedParentDir:t}}handleNewFile({parentDir:e=""}={}){let t=this.getCreateContext(e);this.openActionDialog({title:"Create markdown file",copy:t.normalizedParentDir?"Add a new note inside the selected folder. It opens immediately after creation.":"Add a new note to the vault. It opens immediately after creation.",label:`File ${t.inputLabelSuffix}`,hint:`${t.hintPrefix} ".md" is added automatically.`,note:t.note,placeholder:t.normalizedParentDir?"my-note":"notes/my-note",submitLabel:"Create file",emptyMessage:"File path is required",onSubmit:i=>{let s=L(i);if(!s)return this.showToast("File path is required"),!1;let r=this.ensureExtension(re(t.normalizedParentDir,s),".md");return this.createVaultFile(r,Me(r),{errorMessage:"Failed to create file",openAfterCreate:!0})}})}handleNewFolder({parentDir:e=""}={}){let t=this.getCreateContext(e);this.openActionDialog({title:"Create folder",copy:t.normalizedParentDir?"Add a new folder inside the selected folder.":"Add a new folder to organize notes and diagrams.",label:`Folder ${t.inputLabelSuffix}`,hint:t.hintPrefix,note:t.note,placeholder:t.normalizedParentDir?"archive":"notes/archive",submitLabel:"Create folder",emptyMessage:"Folder path is required",onSubmit:i=>this.createDirectory(re(t.normalizedParentDir,i))})}handleNewDrawing({parentDir:e=""}={}){let t=this.getCreateContext(e);this.openActionDialog({title:"Create Excalidraw drawing",copy:t.normalizedParentDir?"Start a new drawing inside the selected folder.":"Start a new drawing file in the vault.",label:`Drawing ${t.inputLabelSuffix}`,hint:`${t.hintPrefix} ".excalidraw" is added automatically.`,note:t.note,placeholder:t.normalizedParentDir?"architecture":"diagrams/architecture",submitLabel:"Create drawing",emptyMessage:"Drawing path is required",onSubmit:i=>{let s=L(i);if(!s)return this.showToast("Drawing path is required"),!1;let r=this.ensureExtension(re(t.normalizedParentDir,s),".excalidraw");return this.createVaultFile(r,Wn(),{errorMessage:"Failed to create drawing",openAfterCreate:!0})}})}handleNewMermaid({parentDir:e=""}={}){let t=this.getCreateContext(e);this.openActionDialog({title:"Create Mermaid diagram",copy:t.normalizedParentDir?"Create a new `.mmd` or `.mermaid` file inside the selected folder.":"Create a new `.mmd` or `.mermaid` file with starter diagram content.",label:`Diagram ${t.inputLabelSuffix}`,hint:`${t.hintPrefix} ".mmd" is added automatically unless you enter ".mermaid".`,note:t.note,placeholder:t.normalizedParentDir?"flow":"diagrams/flow",submitLabel:"Create diagram",emptyMessage:"Diagram path is required",onSubmit:i=>{let s=L(i);if(!s)return this.showToast("Diagram path is required"),!1;let r=oi(re(t.normalizedParentDir,s));return this.createVaultFile(r.path,r.content,{errorMessage:"Failed to create Mermaid diagram",openAfterCreate:!0})}})}handleNewPlantUml({parentDir:e=""}={}){let t=this.getCreateContext(e);this.openActionDialog({title:"Create PlantUML diagram",copy:t.normalizedParentDir?"Create a new `.puml` or `.plantuml` file inside the selected folder.":"Create a new `.puml` or `.plantuml` file with starter diagram content.",label:`Diagram ${t.inputLabelSuffix}`,hint:`${t.hintPrefix} ".puml" is added automatically unless you enter ".plantuml".`,note:t.note,placeholder:t.normalizedParentDir?"sequence-flow":"diagrams/sequence-flow",submitLabel:"Create diagram",emptyMessage:"Diagram path is required",onSubmit:i=>{let s=L(i);if(!s)return this.showToast("Diagram path is required"),!1;let r=li(re(t.normalizedParentDir,s));return this.createVaultFile(r.path,r.content,{errorMessage:"Failed to create PlantUML diagram",openAfterCreate:!0})}})}handleRename(e){let t=qn(e),i=Ot(t)??".md";this.openActionDialog({title:"Rename file",copy:"Update the file name without changing its current type.",label:"Name",hint:`${i} is kept automatically.`,value:q(t),submitLabel:"Rename file",emptyMessage:"File name is required",onSubmit:s=>this.renameVaultFile(e,s,i)})}handleDelete(e){this.openActionDialog({title:"Delete file",copy:"This permanently removes the file from the vault.",note:e,submitLabel:"Delete file",destructive:!0,requiresInput:!1,onSubmit:()=>this.deleteVaultFile(e)})}};function Di(n,e=[]){for(let t of n){if(t.type==="file"||t.type==="excalidraw"||t.type==="mermaid"||t.type==="plantuml"||t.type==="image"){e.push(t.path);continue}t.type==="directory"&&Array.isArray(t.children)&&Di(t.children,e)}return e}var it=class{constructor(){this.tree=[],this.flatFiles=[],this.activeFilePath=null,this.expandedDirs=new Set,this.searchQuery=""}setTree(e){this.tree=Array.isArray(e)?e:[],this.flatFiles=Di(this.tree,[])}setSearchQuery(e){this.searchQuery=String(e??"").trim().toLowerCase()}getSearchMatches(){return this.searchQuery?this.flatFiles.filter(e=>e.toLowerCase().includes(this.searchQuery)):[]}setActiveFile(e){this.activeFilePath=e||null,e&&this.expandDirectoryPath(e,{includeLeaf:!1})}toggleDirectory(e){return this.expandedDirs.has(e)?(this.expandedDirs.delete(e),!1):(this.expandedDirs.add(e),!0)}expandDirectoryPath(e,{includeLeaf:t=!0}={}){let i=L(e);if(!i)return;let s=i.split("/"),r=t?s.length:Math.max(s.length-1,0),a="";for(let o=0;o<r;o+=1)a=a?`${a}/${s[o]}`:s[o],this.expandedDirs.add(a)}};function Gn(n){return String(n??"").replace(/\/+$/u,"").split("/").filter(Boolean).pop()||""}function Vn(n){let e=String(n??"").replace(/\/+$/u,""),t=e.lastIndexOf("/");return t>=0?e.slice(0,t):""}function Hi(n=[],e=""){for(let t of n){if(t.path===e)return t;if(t.type==="directory"&&Array.isArray(t.children)){let i=Hi(t.children,e);if(i)return i}}return null}var nt=class{constructor({onDirectoryToggle:e,onFileContextMenu:t,onFileSelect:i,onSearchChange:s,onTreeContextMenu:r}){this.onDirectoryToggle=e,this.onFileContextMenu=t,this.onFileSelect=i,this.onSearchChange=s,this.onTreeContextMenu=r,this.treeContainer=document.getElementById("fileTree"),this.searchInput=document.getElementById("fileSearchInput"),this.renderedDirectoryWrappers=new Map,this.renderedChildContainers=new Map,this.lastRenderMode="tree"}initialize(){this.searchInput?.addEventListener("input",e=>{this.onSearchChange?.(e.target.value)}),this.treeContainer?.addEventListener("contextmenu",e=>{e.target.closest(".file-tree-item")||(e.preventDefault(),this.onTreeContextMenu?.(e))})}render({activeFilePath:e,changedPaths:t=null,expandedDirs:i,reset:s=!1,searchMatches:r,searchQuery:a,tree:o}){if(!this.treeContainer)return;if(a){this.lastRenderMode="search",this.renderSearchResults(r,e);return}if(s||this.lastRenderMode!=="tree"||!Array.isArray(t)||t.length===0){this.renderFullTree(o,{activeFilePath:e,expandedDirs:i}),this.lastRenderMode="tree";return}let l=Array.from(new Set(t.map(h=>Vn(h)))).sort((h,c)=>h.split("/").length-c.split("/").length).filter((h,c,u)=>!u.slice(0,c).some(p=>p&&h.startsWith(`${p}/`)));if(l.includes("")){this.renderFullTree(o,{activeFilePath:e,expandedDirs:i}),this.lastRenderMode="tree";return}for(let h of l)if(!this.rerenderDirectoryBranch(h,o,{activeFilePath:e,expandedDirs:i})){this.renderFullTree(o,{activeFilePath:e,expandedDirs:i}),this.lastRenderMode="tree";return}this.lastRenderMode="tree"}renderSearchResults(e,t){if(!this.treeContainer)return;if(this.resetTreeIndexes(),this.treeContainer.innerHTML="",e.length===0){this.treeContainer.innerHTML='<div class="file-tree-empty">No matches</div>';return}let i=document.createDocumentFragment();for(let s of e)i.appendChild(this.createFileItem({activeFilePath:t,depth:0,filePath:s,fileType:$t(s)??"file",name:Gn(s)}));this.treeContainer.appendChild(i)}renderFullTree(e,{activeFilePath:t,expandedDirs:i}){if(this.resetTreeIndexes(),this.treeContainer.innerHTML="",e.length===0){this.treeContainer.innerHTML='<div class="file-tree-empty">No vault files found</div>';return}let s=document.createDocumentFragment();this.renderNodes(e,s,{activeFilePath:t,depth:0,expandedDirs:i}),this.treeContainer.appendChild(s)}resetTreeIndexes(){this.renderedDirectoryWrappers.clear(),this.renderedChildContainers.clear()}renderNodes(e,t,{activeFilePath:i,depth:s,expandedDirs:r}){for(let a of e){if(a.type==="directory"){t.appendChild(this.createDirectoryItem(a,{activeFilePath:i,depth:s,expandedDirs:r}));continue}t.appendChild(this.createFileItem({activeFilePath:i,depth:s,filePath:a.path,fileType:a.type,name:a.name}))}}createDirectoryItem(e,{activeFilePath:t,depth:i,expandedDirs:s}){let r=document.createElement("div");r.className="file-tree-group";let a=document.createElement("button");a.className="file-tree-item file-tree-dir",a.style.setProperty("--depth",i),a.dataset.depth=i;let o=s.has(e.path);if(a.setAttribute("aria-expanded",String(o)),a.innerHTML=`
|
|
48
|
-
<svg class="file-tree-chevron${
|
|
47
|
+
`,e.appendChild(t),s>1){let i=document.createElement("span");i.className="comment-marker-count",i.textContent=String(s),e.appendChild(i)}return e}var et=class{constructor({commentSelectionButton:e,commentsDrawer:t,commentsDrawerEmpty:i,commentsDrawerList:n,commentsToggleButton:r,editorContainer:o,onWillOpenDrawer:a,onCreateThread:c,onNavigateToLine:h,onReplyToThread:l,onToggleReaction:u,onResolveThread:m,previewContainer:d,previewElement:w}){this.commentSelectionButton=e,this.commentsDrawer=t,this.commentsDrawerEmpty=i,this.commentsDrawerList=n,this.commentsToggleButton=r,this.editorContainer=o,this.onWillOpenDrawer=a,this.onCreateThread=c,this.onNavigateToLine=h,this.onReplyToThread=l,this.onToggleReaction=u,this.onResolveThread=m,this.previewContainer=d,this.previewElement=w,this.currentFile=null,this.fileKind="markdown",this.supported=!1,this.drawerOpen=!1,this.threads=[],this.selectionAnchor=null,this.pendingSelectionAnchor=null,this.committedSelectionAnchor=null,this.selectionRevealTimer=0,this.pointerSelecting=!1,this.session=null,this.activeCard=null,this.hoveredEditorGroupKeys=[],this.hoveredEditorGroupKeysSignature="",this.hoveredPreviewGroupKeys=[],this.hoveredPreviewGroupKeysSignature="",this.previewHoverRegions=[],this.lastPreviewPointerPosition=null,this.editorLayer=null,this.previewLayer=null,this.previewHighlightLayer=null,this.cardRoot=null,this.pendingCardFocusElement=null,this.reactionPicker=null,this.layoutFrame=0,this.timeFormatter=new Intl.DateTimeFormat(void 0,{day:"numeric",hour:"numeric",minute:"2-digit",month:"short"}),this.handleEditorScroll=()=>this.scheduleLayoutRefresh(),this.handlePreviewScroll=()=>this.scheduleLayoutRefresh(),this.handleWindowResize=()=>this.scheduleLayoutRefresh(),this.handlePreviewPointerMove=f=>{this.lastPreviewPointerPosition={x:f.clientX,y:f.clientY},this.updateHoveredPreviewGroups(this.getPreviewGroupKeysAtPoint(f.clientX,f.clientY))},this.handlePreviewPointerLeave=()=>{this.lastPreviewPointerPosition=null,this.updateHoveredPreviewGroups([])},this.handlePreviewFocusIn=f=>{this.updateHoveredPreviewGroups(this.getPreviewGroupKeysForTarget(f.target))},this.handlePreviewFocusOut=f=>{this.updateHoveredPreviewGroups(this.getPreviewGroupKeysForTarget(f.relatedTarget))},this.handleCommentSelectionButtonPointerDown=f=>{f.preventDefault()},this.handleEditorPointerDown=f=>{f.button!==0||!this.supported||!this.session||!f.target?.closest?.(".cm-editor")||f.target?.closest?.(".comment-editor-layer")||(this.pointerSelecting=!0,this.clearSelectionRevealTimer(),this.committedSelectionAnchor&&(this.committedSelectionAnchor=null,this.scheduleLayoutRefresh()))},this.handleDocumentPointerUp=()=>{this.pointerSelecting&&requestAnimationFrame(()=>{let f=this.supported?this.session?.getCurrentSelectionCommentAnchor?.()??null:null;this.pointerSelecting=!1,this.selectionAnchor=f,this.renderToolbar(),this.pendingSelectionAnchor=Ht(f)?f:null,this.clearSelectionRevealTimer(),this.committedSelectionAnchor=Ht(f)&&this.activeCard?.mode!=="create"?f:null,this.scheduleLayoutRefresh()})},this.handleEditorFocusOut=f=>{let y=f.relatedTarget;y instanceof Node&&(this.editorContainer?.contains(y)||this.cardRoot?.contains(y)||this.commentSelectionButton?.contains(y))||(this.clearSelectionRevealTimer(),this.pendingSelectionAnchor=null,this.committedSelectionAnchor=null,this.scheduleLayoutRefresh())},this.handleDocumentPointerDown=f=>{let y=f.target;if(this.activeCard&&this.cardRoot){if(this.cardRoot.contains(y))return;this.closeCard()}this.drawerOpen&&(y instanceof Node&&(this.commentsDrawer?.contains(y)||this.commentsToggleButton?.contains(y))||this.closeDrawer())},this.handleDocumentKeyDown=f=>{if(f.key==="Escape"&&this.reactionPicker){this.reactionPicker=null,this.renderCard();return}f.key==="Escape"&&this.activeCard&&this.closeCard(),f.key==="Escape"&&this.committedSelectionAnchor&&(this.clearSelectionRevealTimer(),this.pendingSelectionAnchor=null,this.committedSelectionAnchor=null,this.scheduleLayoutRefresh())},this.commentSelectionButton?.addEventListener("pointerdown",this.handleCommentSelectionButtonPointerDown),this.commentSelectionButton?.addEventListener("click",()=>{this.openComposerForSelection("toolbar")}),this.commentsToggleButton?.addEventListener("click",()=>{this.setDrawerOpen(!this.drawerOpen)}),this.previewContainer?.addEventListener("scroll",this.handlePreviewScroll,{passive:!0}),this.previewElement?.addEventListener("pointermove",this.handlePreviewPointerMove,{passive:!0}),this.previewElement?.addEventListener("pointerleave",this.handlePreviewPointerLeave),this.previewElement?.addEventListener("focusin",this.handlePreviewFocusIn),this.previewElement?.addEventListener("focusout",this.handlePreviewFocusOut),this.editorContainer?.addEventListener("pointerdown",this.handleEditorPointerDown),this.editorContainer?.addEventListener("focusout",this.handleEditorFocusOut),window.addEventListener("resize",this.handleWindowResize),document.addEventListener("pointerup",this.handleDocumentPointerUp),document.addEventListener("pointercancel",this.handleDocumentPointerUp),document.addEventListener("pointerdown",this.handleDocumentPointerDown),document.addEventListener("keydown",this.handleDocumentKeyDown)}destroy(){this.layoutFrame&&(cancelAnimationFrame(this.layoutFrame),this.layoutFrame=0),this.attachSession(null),this.previewContainer?.removeEventListener("scroll",this.handlePreviewScroll),this.previewElement?.removeEventListener("pointermove",this.handlePreviewPointerMove),this.previewElement?.removeEventListener("pointerleave",this.handlePreviewPointerLeave),this.previewElement?.removeEventListener("focusin",this.handlePreviewFocusIn),this.previewElement?.removeEventListener("focusout",this.handlePreviewFocusOut),this.commentSelectionButton?.removeEventListener("pointerdown",this.handleCommentSelectionButtonPointerDown),this.editorContainer?.removeEventListener("pointerdown",this.handleEditorPointerDown),this.editorContainer?.removeEventListener("focusout",this.handleEditorFocusOut),window.removeEventListener("resize",this.handleWindowResize),document.removeEventListener("pointerup",this.handleDocumentPointerUp),document.removeEventListener("pointercancel",this.handleDocumentPointerUp),document.removeEventListener("pointerdown",this.handleDocumentPointerDown),document.removeEventListener("keydown",this.handleDocumentKeyDown),this.previewHoverRegions=[],this.cardRoot?.remove(),this.editorLayer?.remove(),this.previewLayer?.remove(),this.pendingCardFocusElement=null}attachSession(e){this.session?.getScrollContainer?.()?.removeEventListener("scroll",this.handleEditorScroll),this.session=e,this.selectionAnchor=e?.getCurrentSelectionCommentAnchor?.()??null,this.pendingSelectionAnchor=null,this.committedSelectionAnchor=null,this.reactionPicker=null,this.clearSelectionRevealTimer(),this.pointerSelecting=!1,e?.getScrollContainer?.()?.addEventListener("scroll",this.handleEditorScroll,{passive:!0}),this.render()}setCurrentFile(e,{fileKind:t="markdown",supported:i=!1}={}){let n=this.currentFile!==e;this.currentFile=e,this.fileKind=t,this.supported=!!(e&&i),n&&(this.drawerOpen=!1,this.threads=[],this.selectionAnchor=null,this.pendingSelectionAnchor=null,this.committedSelectionAnchor=null,this.clearSelectionRevealTimer(),this.pointerSelecting=!1,this.activeCard=null,this.updateHoveredEditorGroups([]),this.updateHoveredPreviewGroups([]),this.previewHoverRegions=[],this.lastPreviewPointerPosition=null,this.reactionPicker=null),this.supported||(this.drawerOpen=!1,this.activeCard=null,this.threads=[],this.selectionAnchor=null,this.pendingSelectionAnchor=null,this.committedSelectionAnchor=null,this.clearSelectionRevealTimer(),this.pointerSelecting=!1,this.updateHoveredEditorGroups([]),this.updateHoveredPreviewGroups([]),this.previewHoverRegions=[],this.lastPreviewPointerPosition=null,this.reactionPicker=null),this.render()}setSelectionAnchor(e){if(this.selectionAnchor=this.supported?e:null,!this.supported||!this.selectionAnchor){this.pendingSelectionAnchor=null,this.committedSelectionAnchor=null,this.clearSelectionRevealTimer(),this.renderToolbar(),this.scheduleLayoutRefresh();return}if(!Ht(this.selectionAnchor)){this.pendingSelectionAnchor=null,this.committedSelectionAnchor=null,this.clearSelectionRevealTimer(),this.renderToolbar(),this.scheduleLayoutRefresh();return}if(this.pendingSelectionAnchor=this.selectionAnchor,this.activeCard?.mode==="create"){this.clearSelectionRevealTimer(),this.renderToolbar(),this.scheduleLayoutRefresh();return}if(this.pointerSelecting){this.clearSelectionRevealTimer(),this.committedSelectionAnchor=null,this.renderToolbar(),this.scheduleLayoutRefresh();return}if(Di(this.committedSelectionAnchor,this.selectionAnchor)){this.renderToolbar(),this.scheduleLayoutRefresh();return}this.scheduleSelectionReveal(this.selectionAnchor),this.renderToolbar(),this.scheduleLayoutRefresh()}handleEditorContentChange(){this.activeCard?.mode!=="create"&&(this.clearSelectionRevealTimer(),this.pendingSelectionAnchor=null,this.committedSelectionAnchor=null,this.scheduleLayoutRefresh())}setThreads(e=[]){this.threads=Ds(e),this.activeCard?.mode==="group"&&!this.getThreadGroups().some(t=>t.key===this.activeCard.groupKey)&&(this.activeCard=null),this.reactionPicker&&!this.threads.some(t=>t.id===this.reactionPicker.threadId&&t.messages?.some(i=>i.id===this.reactionPicker.messageId))&&(this.reactionPicker=null),this.render()}setDrawerOpen(e){let t=!!e;t!==this.drawerOpen&&(t&&this.onWillOpenDrawer?.(),this.drawerOpen=t,this.render())}closeDrawer(){this.setDrawerOpen(!1)}refreshLayout(){this.renderEditorLayer(),this.renderPreviewLayer(),this.repositionActiveCard()}syncPreviewRailLayout(e=0){if(!this.previewElement)return!1;let t=this.supported&&e>0,i=0,n=0,r=i,o=n;if(t){let l=getComputedStyle(this.previewElement),u=Number.parseFloat(l.getPropertyValue("--preview-comment-rail-reserved"))||0,m=Number.parseFloat(l.paddingRight)||0,d=Number.parseFloat(l.getPropertyValue("--preview-comment-rail-inset"))||0,w=Math.max(m-u,0),f=Math.max(e+d-w,0),y=this.previewContainer?.getBoundingClientRect(),E=this.previewElement.getBoundingClientRect(),S=y?Math.max(y.right-E.right,0):0;o=Math.min(S,f),r=Math.max(f-o,0)}let a=`${Math.ceil(r)}px`,c=`${Math.floor(o)}px`,h=this.previewElement.style.getPropertyValue("--preview-comment-rail-reserved")!==a||this.previewElement.style.getPropertyValue("--preview-comment-rail-offset")!==c;return h&&(this.previewElement.style.setProperty("--preview-comment-rail-reserved",a),this.previewElement.style.setProperty("--preview-comment-rail-offset",c)),h}scheduleLayoutRefresh(){this.layoutFrame||(this.layoutFrame=requestAnimationFrame(()=>{this.layoutFrame=0,this.refreshLayout()}))}render(){this.renderToolbar(),this.renderDrawer(),this.renderCard(),this.scheduleLayoutRefresh()}renderToolbar(){let e=this.threads.length,t=this.supported&&!!this.session;if(this.commentSelectionButton?.classList.toggle("hidden",!t),this.commentsToggleButton?.classList.toggle("hidden",!this.supported),this.commentSelectionButton&&(this.commentSelectionButton.disabled=!this.selectionAnchor),this.commentsToggleButton){this.commentsToggleButton.classList.toggle("active",this.drawerOpen),this.commentsToggleButton.setAttribute("aria-expanded",String(this.drawerOpen));let i=e>0?`Comments ${e}`:"Comments",n=this.commentsToggleButton.querySelector(".ui-action-label");n?n.textContent=i:this.commentsToggleButton.textContent=i}}renderDrawer(){if(!this.commentsDrawer||!this.commentsDrawerList)return;this.commentsDrawer.classList.toggle("hidden",!this.supported||!this.drawerOpen),this.commentsDrawerList.replaceChildren();let e=this.getThreadGroups();if(this.commentsDrawerEmpty?.classList.toggle("hidden",e.length>0),!this.supported||e.length===0)return;let t=document.createDocumentFragment();e.forEach(i=>{let n=document.createElement("button");n.type="button",n.className="ui-record-surface comments-drawer-item",n.classList.toggle("is-active",this.activeCard?.groupKey===i.key),n.addEventListener("pointerdown",w=>{w.preventDefault()}),n.addEventListener("click",()=>{this.openThreadGroup(i,{anchor:i.anchor,origin:"drawer",sourceRect:n.getBoundingClientRect()})});let r=document.createElement("div");r.className="ui-record-header comments-drawer-item-header";let o=document.createElement("span");o.className="comments-drawer-item-title",o.textContent=_i(i.anchor);let a=document.createElement("span");a.className="ui-pill-badge ui-pill-badge--count ui-pill-badge--accent comments-drawer-item-count",a.textContent=String(i.threads.length),r.append(o,a);let c=document.createElement("p");c.className="comments-drawer-item-quote",c.textContent=i.anchor.quote||i.anchor.excerpt||"Source anchored comment";let h=zs(i),l=Oi(h?.body||"","comment-markdown comments-drawer-item-preview"),u=document.createElement("div");u.className="ui-record-meta comments-drawer-item-footer";let m=document.createElement("span");m.textContent=`${i.threads.length} thread${i.threads.length===1?"":"s"}`;let d=document.createElement("span");d.className="comments-drawer-item-updated",d.textContent=h?`${h.userName} \u2022 ${this.formatTimestamp(h.createdAt)}`:"",u.append(m,d),n.append(r,c,l,u),t.appendChild(n)}),this.commentsDrawerList.appendChild(t)}ensureEditorLayer(){if(this.editorLayer?.isConnected&&this.editorLayer.parentElement===this.editorContainer)return this.editorLayer;let e=document.createElement("div");return e.className="comment-editor-layer",this.editorContainer?.appendChild(e),this.editorLayer=e,e}renderEditorLayer(){let e=this.ensureEditorLayer();if(e.replaceChildren(),!this.supported||!this.session)return;let t=this.editorContainer?.getBoundingClientRect?.();if(!t)return;let i=this.getThreadGroups(),n=[];if(i.forEach(l=>{let u=this.session.getCommentAnchorClientRect?.(l.anchor);if(!u)return;let m=qi(u,t);if(m.bottom<0||m.top>t.height)return;let d=document.createElement("button");d.type="button",d.className="ui-state-marker ui-state-marker--comment comment-editor-badge",d.dataset.count=String(l.threads.length);let w=this.activeCard?.groupKey===l.key,f=this.hoveredEditorGroupKeys.includes(l.key);d.classList.toggle("is-active",w),d.classList.toggle("is-hovered",f),d.classList.toggle("is-passive",!w&&!f),d.setAttribute("aria-label",`${l.threads.length} comment thread${l.threads.length===1?"":"s"}`),d.appendChild(Wi(l.threads.length));let y=Math.max(m.top,8);d.style.top=`${y}px`,d.style.left=`${Math.max(t.width-36,8)}px`,d.title=`${l.threads.length} comment${l.threads.length===1?"":"s"}`,d.addEventListener("pointerdown",E=>{E.preventDefault()}),d.addEventListener("pointerenter",()=>{this.updateHoveredEditorGroups([l.key])}),d.addEventListener("pointerleave",()=>{this.updateHoveredEditorGroups([])}),d.addEventListener("focusin",()=>{this.updateHoveredEditorGroups([l.key])}),d.addEventListener("focusout",()=>{this.updateHoveredEditorGroups([])}),d.addEventListener("click",()=>{this.openThreadGroup(l,{anchor:l.anchor,origin:"editor",sourceRect:u})}),e.appendChild(d),n.push(y)}),!this.committedSelectionAnchor||this.activeCard?.mode==="create")return;let r=this.session.getCommentAnchorClientRect?.(this.committedSelectionAnchor),o=this.session.getSelectionChipClientRect?.(this.committedSelectionAnchor)??r;if(!o)return;let a=qi(o,t);if(a.bottom<0||a.top>t.height)return;let c=ee(a.top,8,Math.max(t.height-Ye,8));for(;n.some(l=>Math.abs(l-c)<Ye-4);)c=ee(c+Ye,8,Math.max(t.height-Ye,8));let h=document.createElement("button");h.type="button",h.className="ui-selection-pill ui-selection-pill--comment comment-selection-chip",h.textContent="Comment",h.style.top=`${c}px`,h.style.right=`${Is}px`,h.addEventListener("pointerdown",l=>{l.preventDefault(),l.stopPropagation(),this.openComposerForSelection("editor",h.getBoundingClientRect())}),e.appendChild(h)}ensurePreviewLayer(){if(this.previewLayer?.isConnected&&this.previewLayer.parentElement===this.previewElement)return this.previewLayer;let e=document.createElement("div");e.className="comment-preview-highlights";let t=document.createElement("div");return t.className="comment-preview-layer",this.previewElement?.append(e,t),this.previewHighlightLayer=e,this.previewLayer=t,t}renderPreviewLayer(){if(this.ensurePreviewLayer(),this.previewLayer?.replaceChildren(),this.previewHighlightLayer?.replaceChildren(),!this.supported||!this.previewElement){this.previewHoverRegions=[],this.syncPreviewRailLayout(0);return}let e=this.previewElement.getBoundingClientRect(),t=this.getThreadGroups(),i=[],n=[],r=this.shouldRenderPassivePreviewMarkers(),o=[];t.forEach(c=>{let h=this.resolvePreviewTarget(c.anchor);if(!h?.bubbleRect)return;n.push({key:c.key,rects:h.hoverRects?.length>0?h.hoverRects:[h.bubbleRect]});let l=this.activeCard?.groupKey===c.key,u=this.hoveredPreviewGroupKeys.includes(c.key),m=l||u;if(h.highlightRects?.forEach(f=>{let y=document.createElement("div");y.className="comment-preview-highlight",y.classList.toggle("is-active",l),y.classList.toggle("is-hovered",u),y.classList.toggle("is-passive",!m),y.style.left=`${f.left-e.left}px`,y.style.top=`${f.top-e.top}px`,y.style.width=`${f.width}px`,y.style.height=`${f.height}px`,this.previewHighlightLayer?.appendChild(y)}),!r&&!m)return;let d=document.createElement("button");d.type="button",d.className="ui-state-marker ui-state-marker--comment comment-preview-badge",d.dataset.commentPreviewGroupKeys=c.key,d.classList.toggle("is-active",l),d.classList.toggle("is-hovered",u),d.classList.toggle("is-passive",!m),d.setAttribute("aria-label",`${c.threads.length} comment thread${c.threads.length===1?"":"s"}`),d.appendChild(Wi(c.threads.length));let w=ee(h.bubbleRect.top-e.top,6,Math.max(this.previewElement.clientHeight-Xe,6));for(;i.some(f=>Math.abs(f-w)<Xe-4);)w=ee(w+Xe,6,Math.max(this.previewElement.clientHeight-Xe,6));d.style.top=`${w}px`,d.title=`${c.threads.length} comment${c.threads.length===1?"":"s"}`,d.addEventListener("pointerdown",f=>{f.preventDefault()}),d.addEventListener("click",()=>{this.openThreadGroup(c,{anchor:c.anchor,origin:"preview",sourceRect:d.getBoundingClientRect()})}),this.previewLayer?.appendChild(d),i.push(w),o.push(d)}),this.previewHoverRegions=n;let a=o.reduce((c,h)=>Math.max(c,h.offsetWidth||As),0);this.syncPreviewRailLayout(a)&&this.scheduleLayoutRefresh(),this.lastPreviewPointerPosition&&this.updateHoveredPreviewGroups(this.getPreviewGroupKeysAtPoint(this.lastPreviewPointerPosition.x,this.lastPreviewPointerPosition.y))}resolvePreviewTarget(e){if(!this.previewElement||!e)return null;let t=Array.from(this.previewElement.querySelectorAll(".mermaid-shell, .plantuml-shell")).find(r=>Ui(r,e));if(t)return{bubbleRect:t.getBoundingClientRect(),highlightRects:[],hoverRects:[t.getBoundingClientRect()]};let i=Array.from(this.previewElement.querySelectorAll("[data-source-line]")).filter(r=>$s(r)&&Ui(r,e));if(e.kind==="text"&&e.quote){let r=i.map(o=>({element:o,range:Gs(o,e.quote)})).filter(o=>o.range);if(r.length===1){let o=Array.from(r[0].range.getClientRects());return{bubbleRect:Ks(o)||r[0].element.getBoundingClientRect(),highlightRects:o,hoverRects:o}}}let n=i[0];return n?{bubbleRect:n.getBoundingClientRect(),highlightRects:[],hoverRects:[n.getBoundingClientRect()]}:null}ensureCardRoot(){if(this.cardRoot?.isConnected&&this.cardRoot.parentElement===document.body)return this.cardRoot;let e=document.createElement("div");return e.className="comment-card-root hidden",document.body.appendChild(e),this.cardRoot=e,e}openComposerForSelection(e="editor",t=null){let i=this.session?.getCurrentSelectionCommentAnchor?.();if(!i)return;this.selectionAnchor=i,this.reactionPicker=null;let n=e==="editor"&&t?"editor-chip":e,r=t??(e==="toolbar"?this.commentSelectionButton?.getBoundingClientRect?.():this.session?.getCommentAnchorClientRect?.(i));this.activeCard={anchor:i,mode:"create",origin:n,replyThreadId:null,sourceRect:r},this.render()}openThreadGroup(e,{anchor:t,origin:i,sourceRect:n}){this.reactionPicker=null,this.activeCard={anchor:t,groupKey:e.key,mode:"group",origin:i,replyThreadId:null,sourceRect:n},this.renderDrawer(),this.renderCard()}closeCard(){this.activeCard=null,this.pendingCardFocusElement=null,this.reactionPicker=null,this.renderCard(),this.scheduleLayoutRefresh()}getThreadGroups(){let e=new Map;return this.threads.forEach(t=>{let i=_s(t.anchor),n=e.get(i);if(n){n.threads.push(t);return}e.set(i,{anchor:t.anchor,key:i,threads:[t]})}),Array.from(e.values()).sort((t,i)=>(t.anchor?.startLine??0)-(i.anchor?.startLine??0))}updateCardSourceRect(){return this.activeCard?this.activeCard.origin==="editor"?this.session?.getCommentAnchorClientRect?.(this.activeCard.anchor)??this.activeCard.sourceRect:this.activeCard.origin==="editor-chip"?this.activeCard.sourceRect:this.activeCard.origin==="preview"?this.resolvePreviewTarget(this.activeCard.anchor)?.bubbleRect??this.activeCard.sourceRect:this.activeCard.origin==="toolbar"?this.commentSelectionButton?.getBoundingClientRect?.()??this.activeCard.sourceRect:this.activeCard.sourceRect:null}renderCard(){let e=this.ensureCardRoot();if(e.replaceChildren(),e.classList.toggle("hidden",!this.activeCard),!this.activeCard){this.pendingCardFocusElement=null,e.style.visibility="";return}this.pendingCardFocusElement=null;let t=document.createElement("section");t.className="comment-card",t.addEventListener("click",h=>{!this.reactionPicker||h.target?.closest?.(".comment-reaction-picker-wrap")||(this.reactionPicker=null,requestAnimationFrame(()=>{this.activeCard&&this.renderCard()}))});let i=document.createElement("div");i.className="ui-record-header comment-card-header";let n=document.createElement("div");n.className="comment-card-title-wrap";let r=document.createElement("h3");r.className="comment-card-title",r.textContent=this.activeCard.mode==="create"?"New comment":"Comment threads";let o=document.createElement("p");o.className="comment-card-meta",o.textContent=_i(this.activeCard.anchor),n.append(r,o);let a=document.createElement("button");a.type="button",a.className="ui-button ui-button--compact btn btn-ghost ui-pill-button ui-action-pill comment-card-close",a.setAttribute("aria-label","Close comments"),a.textContent="Close",a.addEventListener("click",()=>this.closeCard()),i.append(n,a),t.appendChild(i);let c=document.createElement("div");if(c.className="comment-card-scroll",this.activeCard.anchor?.quote){let h=document.createElement("p");h.className="comment-card-quote",h.textContent=this.activeCard.anchor.quote,c.appendChild(h)}if(this.activeCard.mode==="create")c.appendChild(this.createComposer());else{let h=this.getThreadGroups().find(l=>l.key===this.activeCard.groupKey);if(!h){this.closeCard();return}h.threads.forEach(l=>{c.appendChild(this.createThreadElement(l))})}e.style.visibility="hidden",t.appendChild(c),e.appendChild(t),this.updateReactionPickerPosition(t),this.positionCard(t),e.style.visibility="",this.flushPendingCardFocus(),this.scheduleLayoutRefresh()}getPreviewGroupKeysForTarget(e){if(!(e instanceof Node))return[];let t=e.closest?.("[data-comment-preview-group-keys]");return js(String(t?.dataset?.commentPreviewGroupKeys??"").split(/\s+/).filter(Boolean)).split(" ").filter(Boolean)}getPreviewGroupKeysAtPoint(e,t){if(!Number.isFinite(e)||!Number.isFinite(t))return[];let i=document.elementFromPoint(e,t),n=this.getPreviewGroupKeysForTarget(i);if(n.length>0)return n;let r=this.previewHoverRegions.filter(o=>o.rects.some(a=>Vs(e,t,a))).map(o=>o.key);return Je(r)}updateHoveredPreviewGroups(e=[]){let t=Je(e),i=t.join(" ");i!==this.hoveredPreviewGroupKeysSignature&&(this.hoveredPreviewGroupKeys=t,this.hoveredPreviewGroupKeysSignature=i,this.scheduleLayoutRefresh())}updateHoveredEditorGroups(e=[]){let t=Je(e),i=t.join(" ");i!==this.hoveredEditorGroupKeysSignature&&(this.hoveredEditorGroupKeys=t,this.hoveredEditorGroupKeysSignature=i,this.scheduleLayoutRefresh())}syncHoveredPreviewGroupsFromTarget(e){this.updateHoveredPreviewGroups(this.getPreviewGroupKeysForTarget(e))}shouldRenderPassivePreviewMarkers(){let e=this.previewContainer?.clientWidth??this.previewElement?.clientWidth??0;return window.innerWidth>=Rs&&e>=Bs}updateReactionPickerPosition(e){let t=qs(e);if(!t)return;let{picker:i,scroll:n,wrap:r}=t;i.classList.remove("is-upward"),i.style.maxHeight="";let o=r.getBoundingClientRect(),a=n.getBoundingClientRect(),c=i.getBoundingClientRect(),h=12,l=window.innerHeight-12,u=Math.min(a.bottom,l),m=Math.max(a.top,h),d=Math.max(u-o.bottom-8,0),w=Math.max(o.top-m-8,0),f=c.height>d&&w>d,y=Math.max(f?w:d,120);i.classList.toggle("is-upward",f),i.style.maxHeight=`${y}px`}repositionActiveCard(){let e=this.cardRoot?.firstElementChild;if(!e||!this.activeCard){this.cardRoot&&(this.cardRoot.style.visibility="");return}this.positionCard(e),this.cardRoot.style.visibility="",this.flushPendingCardFocus()}createComposer(){let e=document.createElement("form");e.className="comment-card-form";let t=document.createElement("textarea");t.className="input comment-card-input",t.rows=4,t.maxLength=Et,t.placeholder="Add context, feedback, or a question...";let i=document.createElement("div");i.className="ui-record-actions comment-card-actions";let n=document.createElement("button");n.type="button",n.className="ui-button btn btn-secondary",n.textContent="Cancel",n.addEventListener("click",()=>this.closeCard());let r=document.createElement("button");return r.type="submit",r.className="ui-button btn btn-primary",r.textContent="Post comment",i.append(n,r),e.append(t,i),e.addEventListener("submit",async o=>{if(o.preventDefault(),!await this.onCreateThread?.({anchor:this.activeCard?.anchor,body:t.value})){t.focus();return}this.closeCard()}),this.pendingCardFocusElement=t,e}createThreadElement(e){let t=document.createElement("article");t.className="comment-thread-card";let i=document.createElement("div");i.className="ui-record-header comment-thread-card-header";let n=document.createElement("div");n.className="comment-thread-card-heading";let r=document.createElement("span");r.className="comment-thread-card-author",r.textContent=e.createdByName;let o=document.createElement("span");o.className="comment-thread-card-time",o.textContent=this.formatTimestamp(e.createdAt);let a=document.createElement("div");a.className="ui-record-actions comment-thread-card-actions";let c=document.createElement("button");c.type="button",c.className="ui-button ui-button--compact btn btn-ghost ui-pill-button ui-action-pill comment-thread-card-action",c.textContent="Jump",c.addEventListener("click",()=>this.onNavigateToLine?.(e.anchor?.startLine??1));let h=document.createElement("button");h.type="button",h.className="ui-button ui-button--compact btn btn-ghost ui-pill-button ui-action-pill comment-thread-card-action";let l=this.activeCard?.replyThreadId===e.id;h.classList.toggle("is-active",l),h.textContent="Reply",h.setAttribute("aria-pressed",String(l)),h.setAttribute("aria-label",l?"Cancel reply":"Reply to thread"),h.title=l?"Cancel reply":"Reply to thread",h.addEventListener("click",()=>{this.activeCard={...this.activeCard,replyThreadId:l?null:e.id},this.renderCard()});let u=document.createElement("button");return u.type="button",u.className="ui-button ui-button--compact btn btn-ghost ui-pill-button ui-action-pill comment-thread-card-action is-danger",u.textContent="Resolve",u.addEventListener("click",async()=>{await this.onResolveThread?.(e.id)}),a.append(c,h,u),n.append(r,o),i.append(n,a),t.append(i),e.messages.forEach(m=>{t.appendChild(this.createMessageElement(e,m))}),this.activeCard?.replyThreadId===e.id&&t.appendChild(this.createReplyComposer(e)),t}createMessageElement(e,t){let i=document.createElement("div");i.className="comment-message-card";let n=document.createElement("div");n.className="ui-record-meta comment-message-card-meta";let r=document.createElement("span");r.className="comment-message-card-author",r.textContent=t.userName;let o=document.createElement("span");o.className="comment-message-card-time",o.textContent=this.formatTimestamp(t.createdAt);let a=Oi(t.body,"comment-message-card-body comment-markdown");return n.append(r,o),i.append(n,a),i.appendChild(this.createReactionBar(e,t)),i}createReactionBar(e,t){let i=this.session?.getLocalUser?.()?.userId??"",n=document.createElement("div");n.className="comment-reaction-bar";let r=new Set((t.reactions??[]).map(l=>l.emoji)),o=document.createElement("div");o.className="comment-reaction-chips",(t.reactions??[]).forEach(l=>{let u=document.createElement("button");u.type="button",u.className="ui-chip-button ui-chip-button--comment comment-reaction-chip",u.classList.toggle("is-active",zi(l,i)),u.setAttribute("aria-pressed",String(zi(l,i))),u.title=l.users?.map(w=>w.userName).join(", ")||l.emoji;let m=document.createElement("span");m.className="comment-reaction-chip-emoji",m.textContent=l.emoji;let d=document.createElement("span");d.className="comment-reaction-chip-count",d.textContent=Us(l),u.append(m,d),u.addEventListener("click",async()=>{await this.onToggleReaction?.(e.id,t.id,l.emoji)}),o.appendChild(u)});let a=document.createElement("div");a.className="comment-reaction-actions",Hs.filter(l=>!r.has(l)).forEach(l=>{a.appendChild(this.createQuickReactionButton(e,t,l))});let c=document.createElement("div");c.className="comment-reaction-picker-wrap";let h=document.createElement("button");return h.type="button",h.className="ui-chip-button ui-chip-button--comment comment-reaction-more-trigger",h.dataset.reactionPickerToggle="true",h.setAttribute("aria-expanded",String(Nt(this.reactionPicker,e.id,t.id))),h.textContent="More",h.addEventListener("click",()=>{let l=Nt(this.reactionPicker,e.id,t.id);this.reactionPicker=l?null:{messageId:t.id,threadId:e.id},this.renderCard()}),c.appendChild(h),Nt(this.reactionPicker,e.id,t.id)&&c.appendChild(this.createReactionPicker(e,t)),a.appendChild(c),n.append(o,a),n}createQuickReactionButton(e,t,i){let n=document.createElement("button");return n.type="button",n.className="ui-icon-chip ui-icon-chip--comment comment-reaction-quick-add",n.textContent=i,n.title=`React with ${i}`,n.addEventListener("click",async()=>{await this.onToggleReaction?.(e.id,t.id,i)}),n}createReactionPicker(e,t){let i=document.createElement("div");i.className="comment-reaction-picker";let n=document.createElement("div");return n.className="comment-reaction-picker-grid",Ns.forEach(r=>{n.appendChild(this.createReactionPickerButton(e,t,r))}),i.appendChild(n),i}createReactionPickerButton(e,t,i){let n=document.createElement("button");return n.type="button",n.className="ui-icon-chip ui-icon-chip--comment comment-reaction-picker-btn",n.textContent=i,n.title=`React with ${i}`,n.addEventListener("click",async()=>{await this.onToggleReaction?.(e.id,t.id,i)&&(this.reactionPicker=null,this.renderCard())}),n}createReplyComposer(e){let t=document.createElement("form");t.className="comment-reply-form";let i=document.createElement("textarea");i.className="input comment-card-input",i.rows=3,i.maxLength=Et,i.placeholder="Reply to thread...";let n=document.createElement("div");n.className="ui-record-actions comment-card-actions";let r=document.createElement("button");r.type="button",r.className="ui-button btn btn-secondary",r.textContent="Cancel",r.addEventListener("click",()=>{this.activeCard={...this.activeCard,replyThreadId:null},this.renderCard()});let o=document.createElement("button");return o.type="submit",o.className="ui-button btn btn-primary",o.textContent="Reply",n.append(r,o),t.append(i,n),this.pendingCardFocusElement=i,t.addEventListener("submit",async a=>{if(a.preventDefault(),!await this.onReplyToThread?.(e.id,i.value)){i.focus();return}this.activeCard={...this.activeCard,replyThreadId:null},this.renderCard()}),t}positionCard(e){let t=this.updateCardSourceRect(),i=window.innerWidth,n=window.innerHeight,r=e.getBoundingClientRect(),o=ee((i-r.width)/2,16,i-r.width-16),a=ee((n-r.height)/4,16,n-r.height-16),c=o,h=a;t&&(c=ee(t.left,16,i-Math.min(r.width,Ni)-16),h=t.bottom+Hi,h+r.height>n-16&&(h=Math.max(t.top-r.height-Hi,16))),this.cardRoot.style.left=`${c}px`,this.cardRoot.style.top=`${h}px`,this.cardRoot.style.width=`${Math.min(Math.max(r.width,Ni),i-32)}px`}formatTimestamp(e){if(!Number.isFinite(e))return"";try{return this.timeFormatter.format(new Date(e))}catch{return""}}flushPendingCardFocus(){let e=this.pendingCardFocusElement;if(!(e instanceof HTMLElement)||!e.isConnected){this.pendingCardFocusElement=null;return}this.pendingCardFocusElement=null;let t=()=>{if(!e.isConnected)return;let i=document.activeElement;i instanceof HTMLElement&&this.editorContainer?.contains(i)&&i.blur(),e.focus({preventScroll:!0})};t(),document.activeElement!==e&&requestAnimationFrame(()=>{t(),document.activeElement!==e&&setTimeout(()=>{t()},50)})}clearSelectionRevealTimer(){this.selectionRevealTimer&&(clearTimeout(this.selectionRevealTimer),this.selectionRevealTimer=0)}scheduleSelectionReveal(e){this.clearSelectionRevealTimer(),this.selectionRevealTimer=window.setTimeout(()=>{this.selectionRevealTimer=0,!(this.pointerSelecting||this.activeCard?.mode==="create"||!Di(this.pendingSelectionAnchor,e))&&(this.committedSelectionAnchor=e,this.scheduleLayoutRefresh())},Ts)}};function tt(s,e){let t=new Map;e.forEach(n=>{let o=s.get(n.key)??{filePath:n.filePath,iframe:null,instanceId:null,key:n.key,label:n.label,placeholder:n.placeholder,queued:!1,reusedFromEmbed:!1,wrapper:null};o.filePath=n.filePath,o.key=n.key,o.label=n.label,o.placeholder=n.placeholder,t.set(n.key,o)});let i=[];return s.forEach((n,r)=>{t.has(r)||i.push(n)}),{nextEntries:t,removedEntries:i}}var me=420,Qs=500,Zs=15e3,Ys=800,Xs=3,Js=200,en="/excalidraw-editor.html";function tn(s,e){return typeof window.requestIdleCallback=="function"?window.requestIdleCallback(s,{timeout:e}):window.setTimeout(()=>{s({didTimeout:!1,timeRemaining:()=>0})},1)}function it(s){if(s!==null){if(typeof window.cancelIdleCallback=="function"){window.cancelIdleCallback(s);return}window.clearTimeout(s)}}function sn(s,e,t){if(!s||!e)return!1;let i=e.getBoundingClientRect(),n=s.getBoundingClientRect();return n.bottom>=i.top-t&&n.top<=i.bottom+t}var st=class{constructor({getTheme:e,getLocalUser:t,onOpenFile:i=null,previewContainer:n,previewElement:r,toastController:o}){this.getTheme=e,this.getLocalUser=t,this.onOpenFile=i,this.previewContainer=n,this.previewElement=r,this.toastController=o,this.embedEntries=new Map,this.hydrationQueue=[],this.hydrationIdleId=null,this.hydrationPaused=!1,this.hydrationInProgress=!1,this.instanceCounter=0,this.isLargeDocument=!1,this.maximizedEmbed=null,this.overlayRoot=null,this.maximizedRoot=null,this.placeholderObserver=null,this.followedPeerIdsByFilePath=new Map,this.pendingDisconnectRequests=new Map,this.disconnectRequestCounter=0,this._onMessage=this._onMessage.bind(this),this._onKeyDown=this._onKeyDown.bind(this),this._onPreviewClick=this._onPreviewClick.bind(this),window.addEventListener("message",this._onMessage),window.addEventListener("keydown",this._onKeyDown),this.previewElement?.addEventListener("click",this._onPreviewClick)}destroy(){window.removeEventListener("message",this._onMessage),window.removeEventListener("keydown",this._onKeyDown),this.previewElement?.removeEventListener("click",this._onPreviewClick),this._disconnectPlaceholderObserver(),it(this.hydrationIdleId),this.hydrationIdleId=null,this.hydrationQueue=[],this._exitMaximizedEmbed(),document.body.classList.remove("excalidraw-maximized-open"),this.embedEntries.forEach(e=>{this._clearEntryBootTimeout(e),e.wrapper?.remove(),e.placeholder=null}),this.embedEntries.clear(),this.pendingDisconnectRequests.forEach(e=>{e.resolve(!1)}),this.pendingDisconnectRequests.clear(),this.followedPeerIdsByFilePath.clear(),this.overlayRoot?.remove(),this.overlayRoot=null,this.maximizedRoot?.remove(),this.maximizedRoot=null}async setFollowedUser(e,t=null){if(!e)return!1;this.followedPeerIdsByFilePath.set(e,t||null);let i=this._findEntryByFilePath(e);return i&&(i.wrapper||await this._hydrateEntry(i),i.followedPeerId=this.followedPeerIdsByFilePath.get(e)??null,this._syncEntryFollowState(i)),!0}detachForCommit(){this._disconnectPlaceholderObserver(),it(this.hydrationIdleId),this.hydrationIdleId=null,this.hydrationQueue=[],this.hydrationInProgress=!1,this.overlayRoot&&(this.overlayRoot.hidden=!0),this.maximizedRoot&&(this.maximizedRoot.hidden=!0),this.embedEntries.forEach(e=>{e.queued=!1,e.placeholder=null})}setHydrationPaused(e){if(this.hydrationPaused=!!e,this.hydrationPaused){it(this.hydrationIdleId),this.hydrationIdleId=null;return}this.hydrateVisibleEmbeds(),this._scheduleHydration()}reconcileEmbeds(e,{isLargeDocument:t=!1}={}){this.isLargeDocument=!!t,this._disconnectPlaceholderObserver(),it(this.hydrationIdleId),this.hydrationIdleId=null,this.hydrationQueue=[],this.hydrationInProgress=!1;let i=Array.from(e.querySelectorAll(".excalidraw-embed-placeholder[data-embed-key]")).map(o=>({filePath:o.dataset.embedTarget,key:o.dataset.embedKey,label:o.dataset.embedLabel||o.dataset.embedTarget,placeholder:o})),{nextEntries:n,removedEntries:r}=tt(this.embedEntries,i);this._adoptReusableEntries(n,r),r.forEach(o=>this._destroyEntry(o)),this.embedEntries=n,this._ensurePlaceholderObserver(),this.embedEntries.forEach(o=>{if(o.queued=!1,o.followedPeerId=this.followedPeerIdsByFilePath.get(o.filePath),o.wrapper){this._updateEmbedLabel(o),this._attachWrapper(o);return}o.placeholder&&this.placeholderObserver?.observe(o.placeholder)}),this.hydrationPaused||this.hydrateVisibleEmbeds(),this.syncLayout()}hydrateVisibleEmbeds(){if(this.hydrationPaused)return;let e=this.isLargeDocument?180:420;this.embedEntries.forEach(t=>{t.wrapper||!t.placeholder?.isConnected||sn(t.placeholder,this.previewContainer,e)&&this._enqueueHydration(t,{prioritize:!0})})}updateTheme(e){this.embedEntries.forEach(t=>{this._postMessageToEntry(t,{source:"collabmd-host",type:"set-theme",theme:e})})}updateLocalUser(e){this.embedEntries.forEach(t=>{this._syncEntryUser(t,e)})}prepareFileDisconnect(e,{timeoutMs:t=250}={}){let i=this._findEntryByFilePath(e);if(!i?.iframe?.contentWindow)return Promise.resolve(!1);let n=`disconnect-${++this.disconnectRequestCounter}`;return new Promise(r=>{let o=c=>{if(!this.pendingDisconnectRequests.has(n))return;let h=this.pendingDisconnectRequests.get(n);window.clearTimeout(h.timeoutId),this.pendingDisconnectRequests.delete(n),r(c)},a=window.setTimeout(()=>{o(!1)},t);this.pendingDisconnectRequests.set(n,{entry:i,resolve:o,timeoutId:a}),this._postMessageToEntry(i,{source:"collabmd-host",type:"prepare-disconnect",requestId:n})})}_ensurePlaceholderObserver(){this.previewContainer&&(this.placeholderObserver=new IntersectionObserver(e=>{e.forEach(t=>{if(!t.isIntersecting)return;let i=this.embedEntries.get(t.target.dataset.embedKey);i&&this._enqueueHydration(i)})},{root:this.previewContainer,rootMargin:this.isLargeDocument?"180px 0px":"420px 0px"}))}_disconnectPlaceholderObserver(){this.placeholderObserver&&(this.placeholderObserver.disconnect(),this.placeholderObserver=null)}_enqueueHydration(e,{prioritize:t=!1}={}){if(!(!e||e.wrapper||e.queued)&&(e.queued=!0,t?this.hydrationQueue.unshift(e.key):this.hydrationQueue.push(e.key),!this.hydrationPaused)){if(t&&!this.hydrationInProgress&&this.hydrationIdleId===null){this._flushHydrationQueue();return}this._scheduleHydration()}}_scheduleHydration(){this.hydrationPaused||this.hydrationInProgress||this.hydrationIdleId!==null||(this.hydrationIdleId=tn(()=>{this.hydrationIdleId=null,this._flushHydrationQueue()},Qs))}async _flushHydrationQueue(){if(this.hydrationPaused||this.hydrationInProgress)return;let e=null;for(;this.hydrationQueue.length>0&&!e;){let t=this.hydrationQueue.shift(),i=this.embedEntries.get(t);if(!i||i.wrapper||!i.placeholder?.isConnected){i&&(i.queued=!1);continue}e=i}e&&(this.hydrationInProgress=!0,e.queued=!1,await this._hydrateEntry(e),this.hydrationInProgress=!1,this.hydrationQueue.length>0&&this._scheduleHydration())}async _hydrateEntry(e){if(!(!e.placeholder?.isConnected&&!e.wrapper)){if(!e.wrapper){let t=this._createEmbedContainer(e);e.wrapper=t.wrapper,e.iframe=t.iframe,e.labelElement=t.labelElement,e.instanceId=t.instanceId,e.isReady=!1,e.bootAttempts=(e.bootAttempts??0)+1,this._armEntryBootTimeout(e)}e.followedPeerId=this.followedPeerIdsByFilePath.get(e.filePath),this._updateEmbedLabel(e),this._attachWrapper(e)}}_attachWrapper(e){let t=e.placeholder?.isConnected?e.placeholder:this.previewElement?.querySelector(`.excalidraw-embed-placeholder[data-embed-key="${e.key}"]`);if(!t)return;if(e.placeholder=t,this._syncMountedEntryMetadata(e),this._shouldInlineFilePreview(e)){e.wrapper.style.position="",e.wrapper.style.top="",e.wrapper.style.left="",e.wrapper.style.width="",e.wrapper.style.margin="",e.wrapper.style.pointerEvents="auto",t.replaceWith(e.wrapper),e.placeholder=null;return}let i=this._ensureOverlayRoot();i.hidden=!1,e.wrapper?.parentElement!==i&&i.appendChild(e.wrapper),this._syncEntryLayout(e)}_adoptReusableEntries(e,t){e.forEach((i,n)=>{if(i.wrapper||i.iframe)return;let r=t.findIndex(a=>a.filePath===i.filePath&&this._getEntryMode(a)===this._getEntryMode(i)&&(a.wrapper||a.iframe));if(r<0)return;let[o]=t.splice(r,1);o.filePath=i.filePath,o.key=i.key,o.label=i.label,o.placeholder=i.placeholder,o.queued=!1,o.reusedFromEmbed=this._isFilePreviewEntry(i),e.set(n,o)})}_destroyEntry(e){this.pendingDisconnectRequests.forEach((t,i)=>{t.entry===e&&(t.resolve(!1),this.pendingDisconnectRequests.delete(i))}),this.maximizedEmbed?.wrapper===e.wrapper&&this._exitMaximizedEmbed(),this._clearEntryBootTimeout(e),this._resetPlaceholderLayout(e),e.wrapper?.remove(),e.placeholder=null}_armEntryBootTimeout(e){this._clearEntryBootTimeout(e),e.bootTimerId=window.setTimeout(()=>{this._handleEntryBootTimeout(e)},Zs)}_clearEntryBootTimeout(e){e?.bootTimerId&&(window.clearTimeout(e.bootTimerId),e.bootTimerId=null)}async _handleEntryBootTimeout(e){if(e?.iframe?.isConnected){if((e.bootAttempts??0)>=Xs){this._clearEntryBootTimeout(e),this.toastController?.show(`Excalidraw embed timed out: ${e.label}`);return}await this._retryEntryBootstrap(e)}}async _retryEntryBootstrap(e){e&&(this._clearEntryBootTimeout(e),this._resetPlaceholderLayout(e),this.maximizedEmbed?.wrapper===e.wrapper&&this._exitMaximizedEmbed(),e.wrapper?.remove(),e.wrapper=null,e.iframe=null,e.labelElement=null,e.instanceId=null,e.isReady=!1,await this._hydrateEntry(e))}_findEntryByContentWindow(e){if(!e)return null;for(let t of this.embedEntries.values())if(t.iframe?.contentWindow===e)return t;return null}_findEntryByFilePath(e){if(!e)return null;for(let t of this.embedEntries.values())if(t.filePath===e)return t;return null}_updateEmbedLabel(e){e.labelElement&&(e.labelElement.textContent=e.label.replace(/\.excalidraw$/i,""))}_syncMountedEntryMetadata(e){e.wrapper&&(e.wrapper.dataset.embedKey=e.key,e.wrapper.dataset.file=e.filePath),e.iframe&&(e.iframe.title=`Excalidraw: ${e.filePath}`)}_buildIframeUrl(e){let t=new URL(Wt(en)),i=this.getTheme?.()||"dark";t.searchParams.set("file",e.filePath),t.searchParams.set("theme",i),t.searchParams.set("boot",e.instanceId||""),this._isFilePreviewEntry(e)||t.searchParams.set("mode","preview");let n=this.getLocalUser?.();n?.name&&t.searchParams.set("userName",n.name),n?.color&&t.searchParams.set("userColor",n.color),n?.colorLight&&t.searchParams.set("userColorLight",n.colorLight),n?.peerId&&t.searchParams.set("userPeerId",n.peerId);let r=new URLSearchParams(window.location.search),o=r.get("server");return o&&t.searchParams.set("server",o),r.get("test")==="1"&&t.searchParams.set("test","1"),r.has("syncTimeoutMs")&&t.searchParams.set("syncTimeoutMs",r.get("syncTimeoutMs")),t}_createEmbedContainer(e){let t=document.createElement("div");t.className="excalidraw-embed diagram-preview-shell",t.dataset.embedKey=e.key,t.dataset.file=e.filePath;let i=document.createElement("div");i.className="excalidraw-embed-header diagram-preview-toolbar";let n=document.createElement("span");n.className="excalidraw-embed-icon",n.innerHTML='<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M12 19l7-7 3 3-7 7-3-3z"/><path d="M18 13l-1.5-7.5L2 2l3.5 14.5L13 18l5-5z"/><path d="M2 2l7.586 7.586"/><circle cx="11" cy="11" r="2"/></svg>';let r=document.createElement("span");r.className="excalidraw-embed-label",r.textContent=e.label.replace(/\.excalidraw$/i,"");let o=document.createElement("button");o.type="button",o.className="excalidraw-embed-btn ui-preview-action ui-preview-action--icon-only",o.title="Edit in Excalidraw",o.setAttribute("aria-label","Edit in Excalidraw"),A(o,"edit");let a=document.createElement("button");a.type="button",a.className="excalidraw-embed-btn ui-preview-action ui-preview-action--icon-only",a.title="Maximize diagram",a.setAttribute("aria-label","Maximize diagram"),A(a,"maximize"),i.append(n,r),this._isFilePreviewEntry(e)||i.append(o),i.append(a);let c=document.createElement("iframe");c.className="excalidraw-embed-iframe",c.dataset.instanceId=String(++this.instanceCounter),e.instanceId=c.dataset.instanceId,c.src=this._buildIframeUrl(e).toString(),c.setAttribute("loading","eager"),c.title=`Excalidraw: ${e.filePath}`,c.style.height=`${me}px`;let h=document.createElement("div");h.className="excalidraw-embed-resizer",h.title="Drag to resize",this._setupResizer(h,c,()=>this._syncEntryLayout(e)),t.append(i,c,h);let l=!1,u=`${me}px`,m=()=>{A(a,l?"restore":"maximize"),a.title=l?"Restore diagram size":"Maximize diagram",a.setAttribute("aria-label",l?"Restore diagram size":"Maximize diagram")},d=()=>{l&&(l=!1,t.classList.remove("is-maximized"),m(),document.body.classList.remove("excalidraw-maximized-open"),this._restoreWrapperMount(e),c.style.height=u,this.maximizedEmbed?.wrapper===t&&(this.maximizedEmbed=null),this._syncEntryLayout(e))},w=()=>{l||(this._exitMaximizedEmbed(),l=!0,u=c.style.height||`${me}px`,this._mountWrapperInMaximizedRoot(e),t.classList.add("is-maximized"),m(),document.body.classList.add("excalidraw-maximized-open"),this.maximizedEmbed={wrapper:t,exit:d},this._syncEntryLayout(e))};return a.addEventListener("click",()=>{l?d():w()}),o.addEventListener("click",()=>{this.onOpenFile?.(e.filePath)}),m(),{iframe:c,instanceId:c.dataset.instanceId,labelElement:r,wrapper:t}}_setupResizer(e,t,i=null){let n=0,r=0,o=c=>{let h=c.clientY-n,l=Math.min(Math.max(r+h,Js),Ys);t.style.height=`${l}px`,t.style.pointerEvents="none"},a=()=>{t.style.pointerEvents="",document.removeEventListener("pointermove",o),document.removeEventListener("pointerup",a),i?.()};e.addEventListener("pointerdown",c=>{c.preventDefault(),n=c.clientY,r=t.offsetHeight,document.addEventListener("pointermove",o),document.addEventListener("pointerup",a)})}_ensureOverlayRoot(){if(this.overlayRoot?.isConnected&&this.overlayRoot.parentElement===this.previewElement)return this.overlayRoot;let e=this.previewElement?.querySelector('[data-excalidraw-overlay-root="true"]');return e||(e=document.createElement("div"),e.dataset.excalidrawOverlayRoot="true",e.className="excalidraw-embed-overlay-root",this.previewElement?.appendChild(e)),this.overlayRoot=e,e}_ensureMaximizedRoot(){if(this.maximizedRoot?.isConnected&&this.maximizedRoot.parentElement===document.body)return this.maximizedRoot;let e=document.body.querySelector('[data-excalidraw-maximized-root="true"]');return e||(e=document.createElement("div"),e.dataset.excalidrawMaximizedRoot="true",e.className="excalidraw-maximized-root",document.body.appendChild(e)),this.maximizedRoot=e,e}_isFilePreviewEntry(e){return e?.key===`${e?.filePath}#file-preview`}_getEntryMode(e){return this._isFilePreviewEntry(e)?"edit":"preview"}_shouldInlineFilePreview(e){return this._isFilePreviewEntry(e)&&!e?.reusedFromEmbed}_resetPlaceholderLayout(e){!e?.placeholder?.isConnected||this._shouldInlineFilePreview(e)||(e.placeholder.classList.remove("is-hydrated"),e.placeholder.removeAttribute("data-embed-hydrated"),e.placeholder.style.height="",e.placeholder.style.pointerEvents="")}_mountWrapperInMaximizedRoot(e){if(!e?.wrapper)return;let t=this._ensureMaximizedRoot();t.hidden=!1,e.restoreParent=e.wrapper.parentElement||null,e.restoreNextSibling=e.wrapper.nextSibling||null,e.wrapper.style.position="",e.wrapper.style.top="",e.wrapper.style.left="",e.wrapper.style.width="",e.wrapper.style.margin="",e.wrapper.parentElement!==t&&t.appendChild(e.wrapper)}_restoreWrapperMount(e){if(e?.wrapper){if(this._shouldInlineFilePreview(e)){let{restoreParent:t,restoreNextSibling:i}=e;t?.isConnected&&(i?.parentElement===t?t.insertBefore(e.wrapper,i):t.appendChild(e.wrapper))}else{let t=this._ensureOverlayRoot();t.hidden=!1,e.wrapper.parentElement!==t&&t.appendChild(e.wrapper)}e.restoreParent=null,e.restoreNextSibling=null,this.maximizedRoot&&this.maximizedRoot.childElementCount===0&&(this.maximizedRoot.hidden=!0)}}_syncEntryLayout(e){if(!e?.wrapper||this._shouldInlineFilePreview(e))return;let t=e.placeholder?.isConnected?e.placeholder:this.previewElement?.querySelector(`.excalidraw-embed-placeholder[data-embed-key="${e.key}"]`);if(!t)return;e.placeholder=t,t.classList.add("is-hydrated"),t.dataset.embedHydrated="true",t.style.pointerEvents="none",this._isFilePreviewEntry(e)&&t.childElementCount>0&&t.replaceChildren();let i=e.wrapper.classList.contains("is-maximized"),n=e.wrapper.querySelector(".excalidraw-embed-header")?.offsetHeight||0,r=e.iframe?.offsetHeight||Number.parseFloat(e.iframe?.style.height||"")||me,o=i?0:e.wrapper.querySelector(".excalidraw-embed-resizer")?.offsetHeight||0,a=Math.ceil(n+r+o);if(i||(e.inlineHeightPx=a),t.style.height=`${Math.ceil(e.inlineHeightPx||a||me)}px`,e.wrapper.style.pointerEvents="auto",i){e.wrapper.style.position="",e.wrapper.style.top="",e.wrapper.style.left="",e.wrapper.style.width="",e.wrapper.style.margin="";return}e.wrapper.style.position="absolute",e.wrapper.style.top=`${t.offsetTop}px`,e.wrapper.style.left=`${t.offsetLeft}px`,e.wrapper.style.width=`${t.offsetWidth}px`,e.wrapper.style.margin="0"}syncLayout(){this.embedEntries.forEach(e=>{e.wrapper&&!this._shouldInlineFilePreview(e)&&this._syncEntryLayout(e)})}_onPreviewClick(e){let t=e.target.closest(".excalidraw-embed-placeholder-btn");if(!t)return;e.preventDefault();let i=this.embedEntries.get(t.dataset.embedKey);i&&this._hydrateEntry(i)}_onMessage(e){if(e.origin!==window.location.origin)return;let t=e.data;if(!t||t.source!=="excalidraw-editor")return;let i=this._findEntryByContentWindow(e.source);if(i){if(t.type==="ready"){i.isReady=!0,this._clearEntryBootTimeout(i),this._syncEntryUser(i),this._postMessageToEntry(i,{source:"collabmd-host",type:"set-theme",theme:this.getTheme?.()||"dark"}),this._syncEntryFollowState(i);return}if(t.type==="error"){i.isReady=!1,this._handleEntryBootTimeout(i);return}if(t.type==="disconnect-ready"){let n=this.pendingDisconnectRequests.get(t.requestId);n?.entry===i&&n.resolve(!0)}}}_onKeyDown(e){e.key==="Escape"&&this._exitMaximizedEmbed()}_exitMaximizedEmbed(){this.maximizedEmbed?.exit&&this.maximizedEmbed.exit(),this.maximizedEmbed=null,document.body.classList.remove("excalidraw-maximized-open")}_postMessageToEntry(e,t){e?.iframe?.contentWindow?.postMessage(t,window.location.origin)}_syncEntryUser(e,t=null){let i=t||this.getLocalUser?.();i&&this._postMessageToEntry(e,{source:"collabmd-host",type:"set-user",user:{color:i.color||"",colorLight:i.colorLight||"",name:i.name||"",peerId:i.peerId||""}})}_syncEntryFollowState(e){!e?.isReady||e.followedPeerId===void 0||this._postMessageToEntry(e,{source:"collabmd-host",type:"follow-user",peerId:e.followedPeerId})}};function nn(s){return String(s??"").replace(/\/+$/u,"").split("/").filter(Boolean).pop()||""}function rn(){return JSON.stringify({type:"excalidraw",version:2,source:"collabmd",elements:[],appState:{viewBackgroundColor:"#ffffff",gridSize:null},files:{}})}var nt=class{constructor({onFileDelete:e,onFileSelect:t,state:i,toastController:n,vaultClient:r,view:o,refresh:a}){this.onFileDelete=e,this.onFileSelect=t,this.state=i,this.toastController=n,this.vaultClient=r,this.view=o,this.refresh=a,this.newFileButton=document.getElementById("newFileBtn"),this.newDrawingButton=document.getElementById("newDrawingBtn"),this.newMermaidButton=document.getElementById("newMermaidBtn"),this.newPlantumlButton=document.getElementById("newPlantumlBtn"),this.newFolderButton=document.getElementById("newFolderBtn"),this.refreshButton=document.getElementById("refreshFilesBtn"),this.actionDialog=document.getElementById("fileActionDialog"),this.actionForm=document.getElementById("fileActionForm"),this.actionTitle=document.getElementById("fileActionTitle"),this.actionCopy=document.getElementById("fileActionCopy"),this.actionField=document.getElementById("fileActionField"),this.actionLabel=document.getElementById("fileActionLabel"),this.actionInput=document.getElementById("fileActionInput"),this.actionHint=document.getElementById("fileActionHint"),this.actionNote=document.getElementById("fileActionNote"),this.actionCancelButton=document.getElementById("fileActionCancel"),this.actionSubmitButton=document.getElementById("fileActionSubmit"),this.pendingAction=null,this.actionBusy=!1}initialize(){this.newFileButton?.addEventListener("click",()=>this.handleNewFile()),this.newDrawingButton?.addEventListener("click",()=>this.handleNewDrawing()),this.newMermaidButton?.addEventListener("click",()=>this.handleNewMermaid()),this.newPlantumlButton?.addEventListener("click",()=>this.handleNewPlantUml()),this.newFolderButton?.addEventListener("click",()=>this.handleNewFolder()),this.refreshButton?.addEventListener("click",()=>this.refresh()),this.actionCancelButton?.addEventListener("click",()=>this.closeActionDialog()),this.actionForm?.addEventListener("submit",e=>{e.preventDefault(),this.handleActionSubmit()}),this.actionDialog?.addEventListener("close",()=>this.resetActionDialog())}createContextMenuItems(e=""){return[{label:"New markdown file",onSelect:()=>this.handleNewFile({parentDir:e})},{label:"New Excalidraw drawing",onSelect:()=>this.handleNewDrawing({parentDir:e})},{label:"New Mermaid diagram",onSelect:()=>this.handleNewMermaid({parentDir:e})},{label:"New PlantUML diagram",onSelect:()=>this.handleNewPlantUml({parentDir:e})},{label:"New folder",onSelect:()=>this.handleNewFolder({parentDir:e})}]}getFileContextMenuItems(e){return[{label:"Rename",onSelect:()=>this.handleRename(e)},{label:"Delete",danger:!0,onSelect:()=>this.handleDelete(e)}]}showToast(e){e&&this.toastController?.show(String(e))}showError(e,t){this.showToast(t?.message?`${e}: ${t.message}`:e)}ensureExtension(e,t){return fi(e,t)}openActionDialog({title:e,copy:t,label:i="Path",hint:n="",note:r="",placeholder:o="",value:a="",submitLabel:c="Save",destructive:h=!1,requiresInput:l=!0,emptyMessage:u="A value is required",onSubmit:m}){!this.actionDialog||!this.actionTitle||!this.actionCopy||!this.actionSubmitButton||!this.actionCancelButton||l&&!this.actionInput||(this.actionDialog.open&&(typeof this.actionDialog.close=="function"?this.actionDialog.close():(this.actionDialog.removeAttribute("open"),this.resetActionDialog())),this.pendingAction={requiresInput:l,emptyMessage:u,onSubmit:m},this.view?.removeContextMenu?.(),this.actionTitle.textContent=e,this.actionCopy.textContent=t,this.actionField&&(this.actionField.hidden=!l),this.actionLabel&&(this.actionLabel.textContent=i),this.actionInput&&(this.actionInput.value=a,this.actionInput.placeholder=o,this.actionInput.required=l,this.actionInput.disabled=!1),this.actionHint&&(this.actionHint.textContent=n,this.actionHint.hidden=!l||!n),this.actionNote&&(this.actionNote.textContent=r,this.actionNote.hidden=!r,this.actionNote.classList.toggle("is-danger",h)),this.actionSubmitButton.textContent=c,this.actionSubmitButton.disabled=!1,this.actionSubmitButton.classList.toggle("btn-primary",!h),this.actionSubmitButton.classList.toggle("btn-danger",h),this.actionCancelButton.disabled=!1,typeof this.actionDialog.showModal=="function"?this.actionDialog.showModal():this.actionDialog.setAttribute("open","true"),requestAnimationFrame(()=>{if(!l||!this.actionInput){this.actionSubmitButton.focus();return}this.actionInput.focus(),a&&this.actionInput.select()}))}resetActionDialog(){this.pendingAction=null,this.actionBusy=!1,this.actionField&&(this.actionField.hidden=!1),this.actionLabel&&(this.actionLabel.textContent="Path"),this.actionInput&&(this.actionInput.value="",this.actionInput.placeholder="",this.actionInput.required=!0,this.actionInput.disabled=!1),this.actionHint&&(this.actionHint.textContent="",this.actionHint.hidden=!0),this.actionNote&&(this.actionNote.textContent="",this.actionNote.hidden=!0,this.actionNote.classList.remove("is-danger")),this.actionSubmitButton&&(this.actionSubmitButton.textContent="Save",this.actionSubmitButton.disabled=!1,this.actionSubmitButton.classList.add("btn-primary"),this.actionSubmitButton.classList.remove("btn-danger")),this.actionCancelButton&&(this.actionCancelButton.disabled=!1)}closeActionDialog(){if(this.actionDialog){if(this.actionDialog.open&&typeof this.actionDialog.close=="function"){this.actionDialog.close();return}this.actionDialog.removeAttribute("open"),this.resetActionDialog()}}setActionDialogBusy(e){this.actionBusy=e,this.actionInput&&(this.actionInput.disabled=e||!(this.pendingAction?.requiresInput??!0)),this.actionCancelButton&&(this.actionCancelButton.disabled=e),this.actionSubmitButton&&(this.actionSubmitButton.disabled=e)}async handleActionSubmit(){if(!this.pendingAction?.onSubmit||this.actionBusy)return;let e=this.pendingAction.requiresInput,t=e?this.actionInput?.value.trim()??"":void 0;if(e&&!t){this.showToast(this.pendingAction.emptyMessage),this.actionInput?.focus();return}this.setActionDialogBusy(!0);let i=!1;try{i=await this.pendingAction.onSubmit(t)}catch(n){i=!1,this.showError("Failed to complete action",n)}if(this.setActionDialogBusy(!1),i!==!1){this.closeActionDialog();return}e&&this.actionInput&&(this.actionInput.focus(),this.actionInput.select())}async createVaultFile(e,t,{openAfterCreate:i=!1,errorMessage:n="Failed to create file"}={}){try{return await this.vaultClient.createFile({content:t,path:e}),this.state.expandDirectoryPath(e,{includeLeaf:!1}),await this.refresh(),i&&this.onFileSelect?.(e),!0}catch(r){return this.showToast(r?.message||n),!1}}async createDirectory(e){let t=x(e);if(!t)return this.showToast("Folder path is required"),!1;try{return await this.vaultClient.createDirectory(t),this.state.expandDirectoryPath(t),await this.refresh(),!0}catch(i){return this.showToast(i?.message||"Failed to create folder"),!1}}async renameVaultFile(e,t,i){let n=String(t??"").trim();if(!n)return this.showToast("File name is required"),!1;if(/[\\/]/u.test(n))return this.showToast("Rename only supports the file name right now"),!1;let r=K(n).trim();if(!r)return this.showToast("File name is required"),!1;let a=`${e.includes("/")?e.substring(0,e.lastIndexOf("/")+1):""}${r}${i}`;if(a===e)return!0;try{return await this.vaultClient.renameFile({newPath:a,oldPath:e}),this.state.expandDirectoryPath(a,{includeLeaf:!1}),await this.refresh(),this.state.activeFilePath===e&&(this.state.activeFilePath=a,this.onFileSelect?.(a)),!0}catch(c){return this.showToast(c?.message||"Failed to rename"),!1}}async deleteVaultFile(e){try{return await this.vaultClient.deleteFile(e),await this.refresh(),this.state.activeFilePath===e&&(this.state.activeFilePath=null,this.onFileDelete?.(e)),!0}catch(t){return this.showToast(t?.message||"Failed to delete"),!1}}getCreateContext(e=""){let t=x(e);return{hintPrefix:t?'Use "/" to create nested items under this folder.':'Use "/" to place it inside a folder.',inputLabelSuffix:t?"name or path":"path",note:t?`Parent folder: ${t}`:"",normalizedParentDir:t}}handleNewFile({parentDir:e=""}={}){let t=this.getCreateContext(e);this.openActionDialog({title:"Create markdown file",copy:t.normalizedParentDir?"Add a new note inside the selected folder. It opens immediately after creation.":"Add a new note to the vault. It opens immediately after creation.",label:`File ${t.inputLabelSuffix}`,hint:`${t.hintPrefix} ".md" is added automatically.`,note:t.note,placeholder:t.normalizedParentDir?"my-note":"notes/my-note",submitLabel:"Create file",emptyMessage:"File path is required",onSubmit:i=>{let n=x(i);if(!n)return this.showToast("File path is required"),!1;let r=this.ensureExtension(oe(t.normalizedParentDir,n),".md");return this.createVaultFile(r,He(r),{errorMessage:"Failed to create file",openAfterCreate:!0})}})}handleNewFolder({parentDir:e=""}={}){let t=this.getCreateContext(e);this.openActionDialog({title:"Create folder",copy:t.normalizedParentDir?"Add a new folder inside the selected folder.":"Add a new folder to organize notes and diagrams.",label:`Folder ${t.inputLabelSuffix}`,hint:t.hintPrefix,note:t.note,placeholder:t.normalizedParentDir?"archive":"notes/archive",submitLabel:"Create folder",emptyMessage:"Folder path is required",onSubmit:i=>this.createDirectory(oe(t.normalizedParentDir,i))})}handleNewDrawing({parentDir:e=""}={}){let t=this.getCreateContext(e);this.openActionDialog({title:"Create Excalidraw drawing",copy:t.normalizedParentDir?"Start a new drawing inside the selected folder.":"Start a new drawing file in the vault.",label:`Drawing ${t.inputLabelSuffix}`,hint:`${t.hintPrefix} ".excalidraw" is added automatically.`,note:t.note,placeholder:t.normalizedParentDir?"architecture":"diagrams/architecture",submitLabel:"Create drawing",emptyMessage:"Drawing path is required",onSubmit:i=>{let n=x(i);if(!n)return this.showToast("Drawing path is required"),!1;let r=this.ensureExtension(oe(t.normalizedParentDir,n),".excalidraw");return this.createVaultFile(r,rn(),{errorMessage:"Failed to create drawing",openAfterCreate:!0})}})}handleNewMermaid({parentDir:e=""}={}){let t=this.getCreateContext(e);this.openActionDialog({title:"Create Mermaid diagram",copy:t.normalizedParentDir?"Create a new `.mmd` or `.mermaid` file inside the selected folder.":"Create a new `.mmd` or `.mermaid` file with starter diagram content.",label:`Diagram ${t.inputLabelSuffix}`,hint:`${t.hintPrefix} ".mmd" is added automatically unless you enter ".mermaid".`,note:t.note,placeholder:t.normalizedParentDir?"flow":"diagrams/flow",submitLabel:"Create diagram",emptyMessage:"Diagram path is required",onSubmit:i=>{let n=x(i);if(!n)return this.showToast("Diagram path is required"),!1;let r=gi(oe(t.normalizedParentDir,n));return this.createVaultFile(r.path,r.content,{errorMessage:"Failed to create Mermaid diagram",openAfterCreate:!0})}})}handleNewPlantUml({parentDir:e=""}={}){let t=this.getCreateContext(e);this.openActionDialog({title:"Create PlantUML diagram",copy:t.normalizedParentDir?"Create a new `.puml` or `.plantuml` file inside the selected folder.":"Create a new `.puml` or `.plantuml` file with starter diagram content.",label:`Diagram ${t.inputLabelSuffix}`,hint:`${t.hintPrefix} ".puml" is added automatically unless you enter ".plantuml".`,note:t.note,placeholder:t.normalizedParentDir?"sequence-flow":"diagrams/sequence-flow",submitLabel:"Create diagram",emptyMessage:"Diagram path is required",onSubmit:i=>{let n=x(i);if(!n)return this.showToast("Diagram path is required"),!1;let r=yi(oe(t.normalizedParentDir,n));return this.createVaultFile(r.path,r.content,{errorMessage:"Failed to create PlantUML diagram",openAfterCreate:!0})}})}handleRename(e){let t=nn(e),i=Vt(t)??".md";this.openActionDialog({title:"Rename file",copy:"Update the file name without changing its current type.",label:"Name",hint:`${i} is kept automatically.`,value:K(t),submitLabel:"Rename file",emptyMessage:"File name is required",onSubmit:n=>this.renameVaultFile(e,n,i)})}handleDelete(e){this.openActionDialog({title:"Delete file",copy:"This permanently removes the file from the vault.",note:e,submitLabel:"Delete file",destructive:!0,requiresInput:!1,onSubmit:()=>this.deleteVaultFile(e)})}};function Gi(s,e=[]){for(let t of s){if(t.type==="file"||t.type==="excalidraw"||t.type==="mermaid"||t.type==="plantuml"||t.type==="image"){e.push(t.path);continue}t.type==="directory"&&Array.isArray(t.children)&&Gi(t.children,e)}return e}var rt=class{constructor(){this.tree=[],this.flatFiles=[],this.activeFilePath=null,this.expandedDirs=new Set,this.searchQuery=""}setTree(e){this.tree=Array.isArray(e)?e:[],this.flatFiles=Gi(this.tree,[])}setSearchQuery(e){this.searchQuery=String(e??"").trim().toLowerCase()}getSearchMatches(){return this.searchQuery?this.flatFiles.filter(e=>e.toLowerCase().includes(this.searchQuery)):[]}setActiveFile(e){this.activeFilePath=e||null,e&&this.expandDirectoryPath(e,{includeLeaf:!1})}toggleDirectory(e){return this.expandedDirs.has(e)?(this.expandedDirs.delete(e),!1):(this.expandedDirs.add(e),!0)}expandDirectoryPath(e,{includeLeaf:t=!0}={}){let i=x(e);if(!i)return;let n=i.split("/"),r=t?n.length:Math.max(n.length-1,0),o="";for(let a=0;a<r;a+=1)o=o?`${o}/${n[a]}`:n[a],this.expandedDirs.add(o)}};function on(s){return String(s??"").replace(/\/+$/u,"").split("/").filter(Boolean).pop()||""}function an(s){let e=String(s??"").replace(/\/+$/u,""),t=e.lastIndexOf("/");return t>=0?e.slice(0,t):""}function Ki(s=[],e=""){for(let t of s){if(t.path===e)return t;if(t.type==="directory"&&Array.isArray(t.children)){let i=Ki(t.children,e);if(i)return i}}return null}var ot=class{constructor({onDirectoryToggle:e,onFileContextMenu:t,onFileSelect:i,onSearchChange:n,onTreeContextMenu:r}){this.onDirectoryToggle=e,this.onFileContextMenu=t,this.onFileSelect=i,this.onSearchChange=n,this.onTreeContextMenu=r,this.treeContainer=document.getElementById("fileTree"),this.searchInput=document.getElementById("fileSearchInput"),this.renderedDirectoryWrappers=new Map,this.renderedChildContainers=new Map,this.lastRenderMode="tree"}initialize(){this.searchInput?.addEventListener("input",e=>{this.onSearchChange?.(e.target.value)}),this.treeContainer?.addEventListener("contextmenu",e=>{e.target.closest(".file-tree-item")||(e.preventDefault(),this.onTreeContextMenu?.(e))})}render({activeFilePath:e,changedPaths:t=null,expandedDirs:i,reset:n=!1,searchMatches:r,searchQuery:o,tree:a}){if(!this.treeContainer)return;if(o){this.lastRenderMode="search",this.renderSearchResults(r,e);return}if(n||this.lastRenderMode!=="tree"||!Array.isArray(t)||t.length===0){this.renderFullTree(a,{activeFilePath:e,expandedDirs:i}),this.lastRenderMode="tree";return}let c=Array.from(new Set(t.map(h=>an(h)))).sort((h,l)=>h.split("/").length-l.split("/").length).filter((h,l,u)=>!u.slice(0,l).some(m=>m&&h.startsWith(`${m}/`)));if(c.includes("")){this.renderFullTree(a,{activeFilePath:e,expandedDirs:i}),this.lastRenderMode="tree";return}for(let h of c)if(!this.rerenderDirectoryBranch(h,a,{activeFilePath:e,expandedDirs:i})){this.renderFullTree(a,{activeFilePath:e,expandedDirs:i}),this.lastRenderMode="tree";return}this.lastRenderMode="tree"}renderSearchResults(e,t){if(!this.treeContainer)return;if(this.resetTreeIndexes(),this.treeContainer.innerHTML="",e.length===0){this.treeContainer.innerHTML='<div class="file-tree-empty">No matches</div>';return}let i=document.createDocumentFragment();for(let n of e)i.appendChild(this.createFileItem({activeFilePath:t,depth:0,filePath:n,fileType:Kt(n)??"file",name:on(n)}));this.treeContainer.appendChild(i)}renderFullTree(e,{activeFilePath:t,expandedDirs:i}){if(this.resetTreeIndexes(),this.treeContainer.innerHTML="",e.length===0){this.treeContainer.innerHTML='<div class="file-tree-empty">No vault files found</div>';return}let n=document.createDocumentFragment();this.renderNodes(e,n,{activeFilePath:t,depth:0,expandedDirs:i}),this.treeContainer.appendChild(n)}resetTreeIndexes(){this.renderedDirectoryWrappers.clear(),this.renderedChildContainers.clear()}renderNodes(e,t,{activeFilePath:i,depth:n,expandedDirs:r}){for(let o of e){if(o.type==="directory"){t.appendChild(this.createDirectoryItem(o,{activeFilePath:i,depth:n,expandedDirs:r}));continue}t.appendChild(this.createFileItem({activeFilePath:i,depth:n,filePath:o.path,fileType:o.type,name:o.name}))}}createDirectoryItem(e,{activeFilePath:t,depth:i,expandedDirs:n}){let r=document.createElement("div");r.className="file-tree-group";let o=document.createElement("button");o.className="file-tree-item file-tree-dir",o.style.setProperty("--depth",i),o.dataset.depth=i;let a=n.has(e.path);if(o.setAttribute("aria-expanded",String(a)),o.innerHTML=`
|
|
48
|
+
<svg class="file-tree-chevron${a?" expanded":""}" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><polyline points="9 18 15 12 9 6"/></svg>
|
|
49
49
|
<svg class="file-tree-icon" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M22 19a2 2 0 0 1-2 2H4a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h5l2 3h9a2 2 0 0 1 2 2z"/></svg>
|
|
50
|
-
<span class="file-tree-name">${
|
|
51
|
-
`,
|
|
52
|
-
${this.getFileIconSvg({isExcalidraw:
|
|
53
|
-
<span class="file-tree-name">${
|
|
54
|
-
`,
|
|
50
|
+
<span class="file-tree-name">${p(e.name)}</span>
|
|
51
|
+
`,o.addEventListener("click",()=>{this.onDirectoryToggle?.(e.path)}),o.addEventListener("contextmenu",c=>{c.preventDefault(),this.onFileContextMenu?.(c,{directoryPath:e.path,type:"directory"})}),r.appendChild(o),this.renderedDirectoryWrappers.set(e.path,r),a&&Array.isArray(e.children)){let c=document.createElement("div");c.className="file-tree-children",this.renderedChildContainers.set(e.path,c),this.renderNodes(e.children,c,{activeFilePath:t,depth:i+1,expandedDirs:n}),r.appendChild(c)}else this.renderedChildContainers.delete(e.path);return r}rerenderDirectoryBranch(e,t,{activeFilePath:i,expandedDirs:n}){let r=this.renderedDirectoryWrappers.get(e),o=Ki(t,e);if(!r||o?.type!=="directory")return!1;let a=r.querySelector(".file-tree-dir"),c=n.has(e);a?.setAttribute("aria-expanded",String(c)),a?.querySelector(".file-tree-chevron")?.classList.toggle("expanded",c);let h=Number(a?.dataset.depth??0),l=this.renderedChildContainers.get(e)??r.querySelector(".file-tree-children");return this.clearRenderedDescendants(e),c?(l?l.innerHTML="":(l=document.createElement("div"),l.className="file-tree-children",r.appendChild(l)),this.renderedChildContainers.set(e,l),this.renderNodes(o.children??[],l,{activeFilePath:i,depth:h+1,expandedDirs:n}),!0):(l?.remove(),this.renderedChildContainers.delete(e),!0)}clearRenderedDescendants(e){let t=`${e}/`;Array.from(this.renderedDirectoryWrappers.keys()).forEach(i=>{i.startsWith(t)&&this.renderedDirectoryWrappers.delete(i)}),Array.from(this.renderedChildContainers.keys()).forEach(i=>{i.startsWith(t)&&this.renderedChildContainers.delete(i)})}createFileItem({activeFilePath:e,depth:t,filePath:i,fileType:n="file",name:r}){let o=document.createElement("button");o.className="file-tree-item file-tree-file";let a=n==="excalidraw",c=n==="image",h=n==="mermaid",l=n==="plantuml";return a&&o.classList.add("is-excalidraw"),c&&o.classList.add("is-image"),h&&o.classList.add("is-mermaid"),l&&o.classList.add("is-plantuml"),i===e&&o.classList.add("active"),o.style.setProperty("--depth",t),o.dataset.depth=t,o.dataset.path=i,o.innerHTML=`
|
|
52
|
+
${this.getFileIconSvg({isExcalidraw:a,isImage:c,isMermaid:h,isPlantUml:l})}
|
|
53
|
+
<span class="file-tree-name">${p(K(r))}</span>
|
|
54
|
+
`,o.addEventListener("click",()=>{this.onFileSelect?.(i)}),o.addEventListener("contextmenu",u=>{u.preventDefault(),this.onFileContextMenu?.(u,{filePath:i,type:"file"})}),o}getFileIconSvg({isExcalidraw:e,isImage:t,isMermaid:i,isPlantUml:n}){return e?'<svg class="file-tree-icon" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M12 19l7-7 3 3-7 7-3-3z"/><path d="M18 13l-1.5-7.5L2 2l3.5 14.5L13 18l5-5z"/><path d="M2 2l7.586 7.586"/><circle cx="11" cy="11" r="2"/></svg>':t?'<svg class="file-tree-icon" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><rect x="3" y="4" width="18" height="16" rx="2"/><circle cx="9" cy="10" r="1.5"/><path d="m21 16-5-5L7 20"/><path d="m14 14 2 2"/></svg>':i?'<svg class="file-tree-icon" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M5 7.5c0-1.38 1.12-2.5 2.5-2.5 1.04 0 1.93.64 2.3 1.56A2.5 2.5 0 0 1 14 8.5v1"/><path d="M19 16.5c0 1.38-1.12 2.5-2.5 2.5-1.04 0-1.93-.64-2.3-1.56A2.5 2.5 0 0 1 10 15.5v-1"/><path d="M8 10.5h8"/><path d="M8 13.5h8"/><path d="M10 8.5v7"/><path d="M14 8.5v7"/></svg>':n?'<svg class="file-tree-icon" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><rect x="3" y="4" width="7" height="6" rx="1"/><rect x="14" y="4" width="7" height="6" rx="1"/><rect x="8.5" y="14" width="7" height="6" rx="1"/><path d="M10 7h4"/><path d="M17.5 10v2.5"/><path d="M6.5 10v2.5"/><path d="M6.5 12.5h11"/></svg>':'<svg class="file-tree-icon" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z"/><polyline points="14 2 14 8 20 8"/></svg>'}showContextMenu(e,t){if(this.removeContextMenu(),!Array.isArray(t)||t.length===0)return;let i=document.createElement("div");i.className="file-context-menu";for(let c of t){let h=document.createElement("button");h.className=`file-context-item${c.danger?" file-context-danger":""}`,h.textContent=c.label,h.addEventListener("click",()=>{this.removeContextMenu(),c.onSelect?.()}),i.appendChild(h)}document.body.appendChild(i);let n=i.getBoundingClientRect(),r=Math.max(8,window.innerWidth-n.width-8),o=Math.max(8,window.innerHeight-n.height-8);i.style.left=`${Math.max(8,Math.min(e.clientX,r))}px`,i.style.top=`${Math.max(8,Math.min(e.clientY,o))}px`;let a=c=>{i.contains(c.target)||(this.removeContextMenu(),document.removeEventListener("click",a))};setTimeout(()=>document.addEventListener("click",a),0)}removeContextMenu(){document.querySelectorAll(".file-context-menu").forEach(e=>e.remove())}};var at=class{constructor({onFileSelect:e,onFileDelete:t,toastController:i,vaultClient:n=ue}){this.onFileSelect=e,this.onFileDelete=t,this.toastController=i,this.vaultClient=n,this.state=new rt,this.view=new ot({onDirectoryToggle:r=>{this.state.toggleDirectory(r),this.renderTree()},onFileContextMenu:(r,o)=>{if(o.type==="directory"){this.view.showContextMenu(r,this.actionController.createContextMenuItems(o.directoryPath));return}this.view.showContextMenu(r,this.actionController.getFileContextMenuItems(o.filePath))},onFileSelect:r=>{this.onFileSelect?.(r)},onSearchChange:r=>{this.state.setSearchQuery(r),this.renderTree()},onTreeContextMenu:r=>{this.view.showContextMenu(r,this.actionController.createContextMenuItems())}}),this.actionController=new nt({onFileDelete:this.onFileDelete,onFileSelect:this.onFileSelect,refresh:()=>this.refresh(),state:this.state,toastController:this.toastController,vaultClient:this.vaultClient,view:this.view})}initialize(){this.view.initialize(),this.actionController.initialize()}async refresh(){try{let e=await this.vaultClient.readTree();this.setTree(e.tree||[])}catch(e){console.error("[explorer] Failed to load file tree:",e.message)}}setTree(e,{changedPaths:t=null,reset:i=!1}={}){this.state.setTree(e),this.renderTree({changedPaths:t,reset:i})}setActiveFile(e){this.state.setActiveFile(e),this.renderTree()}get flatFiles(){return this.state.flatFiles}get flatDocumentFiles(){return this.state.flatFiles.filter(e=>!Ce(e))}renderTree({changedPaths:e=null,reset:t=!1}={}){this.view.render({activeFilePath:this.state.activeFilePath,changedPaths:e,expandedDirs:this.state.expandedDirs,reset:t,searchMatches:this.state.getSearchMatches(),searchQuery:this.state.searchQuery,tree:this.state.tree})}};var ln=30;function cn(s){return String(s??"").split("/").pop()||""}function hn(s){let e=String(s??"").split("/");return e.pop(),e.join("/")}function dn(s=""){let e=cn(s),t=hn(s);return t?`
|
|
55
|
+
<span class="file-history-path">${p(e)}</span>
|
|
56
|
+
<span class="file-history-dir">${p(t)}</span>
|
|
57
|
+
`:`<span class="file-history-path">${p(e)}</span>`}function Vi(s={}){let e=[String(s.authorName||"Unknown"),String(s.relativeDateLabel||"")];return s.status==="renamed"&&s.oldPath&&e.push(`Renamed from ${s.oldPath}`),e.filter(Boolean).map(t=>p(t)).join(" \xB7 ")}function ji(s={}){return s.type==="local"?"local":`commit:${String(s.hash||"").trim()}:${String(s.pathAtCommit||"").trim()}`}function pe(){return{commits:[],error:"",hasMore:!1,loaded:!1,loading:!1,loadingMore:!1,offset:0}}var lt=class{constructor({diffRenderer:e=null,onOpenCommitDiff:t=()=>{},onOpenFile:i=()=>{},onOpenPreview:n=()=>{},onOpenWorkspaceDiff:r=()=>{},toastController:o=null}={}){this.diffRenderer=e,this.onOpenCommitDiff=t,this.onOpenFile=i,this.onOpenPreview=n,this.onOpenWorkspaceDiff=r,this.toastController=o,this.page=document.getElementById("diff-page"),this.content=document.getElementById("diffContent"),this.fileIndicator=document.getElementById("diffFileIndicator"),this.openEditorButton=document.getElementById("diffOpenEditorBtn"),this.primaryActionButton=document.getElementById("diffPrimaryActionBtn"),this.commitButton=document.getElementById("diffCommitBtn"),this.backToHistoryButton=document.getElementById("diffBackToHistoryBtn"),this.gitActionsGroup=document.getElementById("diffGitActionsGroup"),this.editorActionsGroup=document.getElementById("diffEditorActionsGroup"),this.actionsDivider=document.getElementById("diffToolbarDivider"),this.stats=document.getElementById("diffStats"),this.prevButton=document.getElementById("diffPrevBtn"),this.nextButton=document.getElementById("diffNextBtn"),this.layoutToggle=document.getElementById("diffLayoutToggle"),this.modeButtons=Array.from(document.querySelectorAll("[data-diff-mode]")),this.currentFilePath=null,this.localChanges=null,this.history=pe(),this.diffMode="unified",this.selectedEntryKey=null,this.detailCache=new Map,this.detailErrors=new Map,this.historyListElement=null,this.historyListScrollTop=0,this.loadingEntryKey=null,this.selectionRequestToken=0}initialize(){this.openEditorButton?.addEventListener("click",()=>{this.currentFilePath&&this.onOpenFile?.(this.currentFilePath)}),this.modeButtons.forEach(e=>{e.addEventListener("click",()=>{let t=e.getAttribute("data-diff-mode");!t||t===this.diffMode||(this.diffMode=t,this.render())})}),this.content?.addEventListener("click",e=>{let t=e.target instanceof Element?e.target.closest("[data-file-history-select]"):null;if(t){let o=this.findEntryByKey(t.getAttribute("data-file-history-select"));o&&this.selectEntry(o);return}if(e.target instanceof Element?e.target.closest("[data-file-history-open-selected-diff]"):null){this.openSelectedDiff();return}if(e.target instanceof Element?e.target.closest("[data-file-history-open-selected-preview]"):null){this.openSelectedPreview();return}e.target instanceof Element&&e.target.closest("[data-file-history-load-more]")&&this.loadMore()})}hide(){this.page?.classList.add("hidden"),this.content?.classList.remove("diff-content--history"),this.content&&(this.content.innerHTML=""),this.currentFilePath=null,this.localChanges=null,this.history=pe(),this.selectedEntryKey=null,this.loadingEntryKey=null,this.detailCache.clear(),this.detailErrors.clear(),this.historyListElement=null,this.historyListScrollTop=0,this.selectionRequestToken=0,this.syncToolbar()}getEntries(){let e=[];this.localChanges&&e.push({...this.localChanges,key:"local",label:"Local changes",pathAtCommit:this.currentFilePath,type:"local"});for(let t of this.history.commits??[])e.push({...t,key:ji({...t,type:"commit"}),type:"commit"});return e}findEntryByKey(e){return this.getEntries().find(t=>t.key===e)??null}getSelectedEntry(){return this.findEntryByKey(this.selectedEntryKey)}getDefaultEntry(){return this.getEntries()[0]??null}getSelectedDetailState(){let e=this.getSelectedEntry();return e?{detail:this.detailCache.get(e.key)??null,entry:e,error:this.detailErrors.get(e.key)??"",loading:this.loadingEntryKey===e.key}:null}async openFileHistory({filePath:e}){this.currentFilePath=String(e??"").trim()||null,this.localChanges=null,this.history={...pe(),loading:!0},this.selectedEntryKey=null,this.loadingEntryKey=null,this.detailCache.clear(),this.detailErrors.clear(),this.historyListElement=null,this.historyListScrollTop=0,this.selectionRequestToken=0,this.renderLoading();try{let[t,i]=await Promise.all([this.loadLocalChanges().catch(()=>null),this.fetchHistoryPage({offset:0})]);this.localChanges=t,this.history=i;let n=this.getDefaultEntry();return n?(await this.selectEntry(n),{history:i,localChanges:t}):(this.render(),{history:i,localChanges:t})}catch(t){return console.error("[file-history] Failed to load file history:",t),this.toastController?.show("Failed to load file history"),this.localChanges=null,this.history={...pe(),error:"Failed to load file history",loaded:!0},this.render(),{history:this.history,localChanges:null}}}async loadLocalChanges(){if(!this.currentFilePath)return null;let e=new URLSearchParams;e.set("metaOnly","true"),e.set("path",this.currentFilePath),e.set("scope","all");let t=await fetch(b(`/git/diff?${e.toString()}`)),i=await t.json();if(!t.ok)throw new Error(i.error||"Failed to load local file changes");let n=i.files?.[0];return n?{...n,summary:i.summary??{additions:Number(n.stats?.additions||0),deletions:Number(n.stats?.deletions||0),filesChanged:1}}:null}async fetchHistoryPage({offset:e=0}={}){if(!this.currentFilePath)return{...pe(),loaded:!0};let t=new URLSearchParams;t.set("path",this.currentFilePath),t.set("limit",String(ln)),t.set("offset",String(e));let i=await fetch(b(`/git/file-history?${t.toString()}`)),n=await i.json();if(!i.ok)throw new Error(n.error||"Failed to load file history");let r=Array.isArray(n.commits)?n.commits:[];return{commits:r,error:"",hasMore:!!n.hasMore,loaded:!0,loading:!1,loadingMore:!1,offset:e+r.length}}async loadSelectedDetail(e){if(!e)return null;if(e.type==="local"){let r=new URLSearchParams;r.set("path",this.currentFilePath||""),r.set("scope","all");let o=await fetch(b(`/git/diff?${r.toString()}`)),a=await o.json();if(!o.ok)throw new Error(a.error||"Failed to load local diff");return{detail:a.files?.[0]??null,summary:a.summary??e.summary??null}}let t=new URLSearchParams;t.set("hash",e.hash||""),t.set("path",e.pathAtCommit||"");let i=await fetch(b(`/git/commit?${t.toString()}`)),n=await i.json();if(!i.ok)throw new Error(n.error||"Failed to load commit diff");return{commit:n.commit??null,detail:n.files?.[0]??null,summary:n.summary??null}}async selectEntry(e){if(!e)return null;let t=e.key||ji(e);this.selectedEntryKey=t,this.detailErrors.delete(t);let i=this.detailCache.get(t);if(i)return this.loadingEntryKey=null,this.render(),i;this.loadingEntryKey=t,this.render();let n=++this.selectionRequestToken;try{let r=await this.loadSelectedDetail(e);return this.detailCache.set(t,r),this.detailErrors.delete(t),n===this.selectionRequestToken&&this.selectedEntryKey===t&&(this.loadingEntryKey=null,this.render()),r}catch(r){return console.error("[file-history] Failed to load selected diff:",r),this.toastController?.show(e.type==="local"?"Failed to load local diff":"Failed to load commit diff"),this.detailErrors.set(t,e.type==="local"?"Failed to load local diff":"Failed to load commit diff"),n===this.selectionRequestToken&&this.selectedEntryKey===t&&(this.loadingEntryKey=null,this.render()),null}}async loadMore(){if(!(!this.currentFilePath||this.history.loading||this.history.loadingMore||!this.history.hasMore)){this.history={...this.history,error:"",loadingMore:!0},this.render();try{let e=await this.fetchHistoryPage({offset:this.history.offset});this.history={commits:[...this.history.commits,...e.commits],error:"",hasMore:e.hasMore,loaded:!0,loading:!1,loadingMore:!1,offset:e.offset},this.render()}catch(e){console.error("[file-history] Failed to load more history:",e),this.toastController?.show("Failed to load file history"),this.history={...this.history,error:"Failed to load file history",loadingMore:!1},this.render()}}}openSelectedDiff(){let e=this.getSelectedEntry();if(e){if(e.type==="local"){this.onOpenWorkspaceDiff?.(this.currentFilePath);return}this.onOpenCommitDiff?.(e.hash,{historyFilePath:this.currentFilePath,path:e.pathAtCommit})}}openSelectedPreview(){let e=this.getSelectedEntry();!e||e.type!=="commit"||this.onOpenPreview?.({currentFilePath:this.currentFilePath,hash:e.hash,path:e.pathAtCommit})}renderDiffFileHeader(e={}){return typeof this.diffRenderer?.renderFileHeader=="function"?this.diffRenderer.renderFileHeader(e):`
|
|
58
|
+
<div class="diff-file-header">
|
|
59
|
+
<span class="diff-file-path">${p(e.path||this.currentFilePath||"")}</span>
|
|
60
|
+
</div>
|
|
61
|
+
`}renderDiffMarkup(e={}){if(typeof this.diffRenderer?.renderDiffDetail=="function"){let t=this.diffRenderer.mode;this.diffRenderer.mode=this.diffMode;let i=this.diffRenderer.renderDiffDetail(e,0,{includeHeader:!0});return this.diffRenderer.mode=t,i}return`
|
|
62
|
+
${this.renderDiffFileHeader(e)}
|
|
63
|
+
<div class="diff-empty-state">Diff renderer unavailable.</div>
|
|
64
|
+
`}syncToolbar(){let e=this.getSelectedDetailState(),t=e?.entry??null,i=e?.detail?.summary??t?.summary??(t?{additions:Number(t.additions||0),deletions:Number(t.deletions||0)}:null),n=Number(i?.additions||0),r=Number(i?.deletions||0),o=!!t;this.fileIndicator&&(this.fileIndicator.textContent=t?.type==="commit"?t.shortHash||"Commit":t?.type==="local"?"Local changes":"History"),this.stats&&(this.stats.innerHTML=`
|
|
65
|
+
<span class="ui-stat-token ui-stat-token--add diff-stats-add">+${n}</span>
|
|
66
|
+
<span class="ui-stat-token ui-stat-token--del diff-stats-del">-${r}</span>
|
|
67
|
+
`,this.stats.classList.toggle("hidden",!o)),this.backToHistoryButton?.classList.add("hidden"),this.gitActionsGroup?.classList.add("hidden"),this.layoutToggle?.classList.add("hidden"),this.prevButton?.classList.add("hidden"),this.nextButton?.classList.add("hidden"),this.actionsDivider?.classList.add("hidden"),this.editorActionsGroup?.classList.remove("hidden"),this.modeButtons.forEach(a=>{a.classList.toggle("hidden",!o),a.classList.toggle("active",a.getAttribute("data-diff-mode")===this.diffMode)}),this.openEditorButton?.toggleAttribute("disabled",!this.currentFilePath),this.openEditorButton&&(this.openEditorButton.textContent="Open File"),this.primaryActionButton?.toggleAttribute("disabled",!0),this.commitButton?.toggleAttribute("disabled",!0)}renderLoading(){this.page?.classList.remove("hidden"),this.content&&(this.content.classList.add("diff-content--history"),this.content.innerHTML='<div class="git-panel-empty">Loading file history...</div>'),this.historyListElement=null,this.syncToolbar()}renderEmpty(e){this.page?.classList.remove("hidden"),this.content&&(this.content.classList.add("diff-content--history"),this.content.innerHTML=`<div class="git-panel-empty">${p(e)}</div>`),this.historyListElement=null,this.syncToolbar()}captureListScroll(){this.historyListElement&&(this.historyListScrollTop=Number(this.historyListElement.scrollTop||0))}restoreListScroll(){if(!this.content?.querySelector){this.historyListElement=null;return}let e=this.content.querySelector("[data-file-history-list]");this.historyListElement=e??null,e&&(e.scrollTop=this.historyListScrollTop,e.addEventListener("scroll",()=>{this.historyListScrollTop=Number(e.scrollTop||0)},{passive:!0}))}renderScopeLabels(e={}){let t=[];return e.hasStagedChanges&&t.push("staged"),e.hasWorkingTreeChanges&&t.push("working tree"),e.hasUntrackedChanges&&t.push("untracked"),t.length>0?t.join(" \xB7 "):"working tree"}renderHistoryItem(e={}){let t=e.key===this.selectedEntryKey,i=Number(e.additions??e.summary?.additions??0),n=Number(e.deletions??e.summary?.deletions??0),r=e.type==="local"?"Live workspace":Vi(e),o=e.type==="local"?"Local changes":e.subject||e.shortHash||"Commit",a=e.type==="local"?'<span class="ui-pill-badge ui-pill-badge--accent file-history-item-badge">Live</span>':`<span class="ui-pill-badge ui-pill-badge--code file-history-item-badge">${p(e.shortHash||"")}</span>`;return`
|
|
68
|
+
<button
|
|
69
|
+
class="ui-record-surface file-history-item${t?" active":""}${e.type==="local"?" file-history-item-local":""}"
|
|
70
|
+
type="button"
|
|
71
|
+
data-file-history-select="${p(e.key)}"
|
|
72
|
+
aria-current="${t?"true":"false"}"
|
|
73
|
+
>
|
|
74
|
+
<span class="file-history-item-top">
|
|
75
|
+
<span class="file-history-item-copy">
|
|
76
|
+
<span class="file-history-item-title">${p(o)}</span>
|
|
77
|
+
<span class="file-history-item-meta">${e.type==="local"?p(this.renderScopeLabels(e)):r}</span>
|
|
78
|
+
</span>
|
|
79
|
+
${a}
|
|
80
|
+
</span>
|
|
81
|
+
<span class="file-history-item-stats">
|
|
82
|
+
<span class="git-change-add">+${i}</span>
|
|
83
|
+
<span class="git-change-del">-${n}</span>
|
|
84
|
+
</span>
|
|
85
|
+
</button>
|
|
86
|
+
`}renderSelectedHeader(e){let t=e?.entry;if(!t)return`
|
|
87
|
+
<div class="file-history-detail-header">
|
|
88
|
+
<div class="file-history-detail-copy">
|
|
89
|
+
<span class="file-history-detail-kicker">History</span>
|
|
90
|
+
<h2 class="file-history-detail-title">No selection</h2>
|
|
91
|
+
<p class="file-history-detail-meta">Choose a history item to inspect the file diff.</p>
|
|
92
|
+
</div>
|
|
93
|
+
</div>
|
|
94
|
+
`;let i=t.type==="local"?"Live workspace":`Commit ${p(t.shortHash||"")}`,n=t.type==="local"?"Local changes":p(t.subject||t.shortHash||"Commit"),r=t.type==="local"?p(this.renderScopeLabels(t)):Vi(t);return`
|
|
95
|
+
<div class="file-history-detail-header">
|
|
96
|
+
<div class="file-history-detail-copy">
|
|
97
|
+
<span class="file-history-detail-kicker">${i}</span>
|
|
98
|
+
<h2 class="file-history-detail-title">${n}</h2>
|
|
99
|
+
<p class="file-history-detail-meta">${r}</p>
|
|
100
|
+
</div>
|
|
101
|
+
<div class="file-history-detail-actions">
|
|
102
|
+
<button
|
|
103
|
+
class="ui-button ui-action-button ui-action-button--surface btn btn-secondary"
|
|
104
|
+
type="button"
|
|
105
|
+
data-file-history-open-selected-diff
|
|
106
|
+
>
|
|
107
|
+
Open Standalone Diff
|
|
108
|
+
</button>
|
|
109
|
+
${t.type==="commit"?`
|
|
110
|
+
<button
|
|
111
|
+
class="ui-button ui-action-button btn btn-primary"
|
|
112
|
+
type="button"
|
|
113
|
+
data-file-history-open-selected-preview
|
|
114
|
+
>
|
|
115
|
+
Preview File
|
|
116
|
+
</button>
|
|
117
|
+
`:""}
|
|
118
|
+
</div>
|
|
119
|
+
</div>
|
|
120
|
+
`}renderSelectedBody(e){let t=e?.entry;return t?e.loading?`
|
|
121
|
+
<section class="diff-file-block file-history-diff-block">
|
|
122
|
+
${this.renderDiffFileHeader({path:t.pathAtCommit||this.currentFilePath||""})}
|
|
123
|
+
<div class="diff-empty-state">Loading diff...</div>
|
|
124
|
+
</section>
|
|
125
|
+
`:e.error?`
|
|
126
|
+
<section class="diff-file-block file-history-diff-block">
|
|
127
|
+
${this.renderDiffFileHeader({path:t.pathAtCommit||this.currentFilePath||""})}
|
|
128
|
+
<div class="diff-empty-state">${p(e.error)}</div>
|
|
129
|
+
</section>
|
|
130
|
+
`:e.detail?.detail?`
|
|
131
|
+
<section class="diff-file-block file-history-diff-block">
|
|
132
|
+
${this.renderDiffMarkup(e.detail.detail)}
|
|
133
|
+
</section>
|
|
134
|
+
`:'<div class="diff-empty-state">No diff available for this history item.</div>':'<div class="diff-empty-state">Select a history entry to inspect this file.</div>'}render(){if(this.page?.classList.remove("hidden"),this.captureListScroll(),this.syncToolbar(),!this.currentFilePath){this.renderEmpty("No file selected.");return}if(this.history.loading&&!this.history.loaded){this.renderLoading();return}if(!(!!this.localChanges||(this.history.commits?.length??0)>0)){this.renderEmpty(this.history.error||"No history found for this file.");return}if(!this.content)return;this.content.classList.add("diff-content--history");let t=this.getSelectedDetailState();this.content.innerHTML=`
|
|
135
|
+
<section class="file-history-shell">
|
|
136
|
+
<aside class="file-history-sidebar" aria-label="File history entries">
|
|
137
|
+
<header class="file-history-sidebar-header">
|
|
138
|
+
<span class="file-history-kicker">File history</span>
|
|
139
|
+
<div class="file-history-title">${dn(this.currentFilePath)}</div>
|
|
140
|
+
<p class="file-history-sidebar-copy">Select an entry to inspect the exact changes for this file.</p>
|
|
141
|
+
</header>
|
|
142
|
+
<div class="file-history-list" data-file-history-list>
|
|
143
|
+
${this.getEntries().map(i=>this.renderHistoryItem(i)).join("")}
|
|
144
|
+
</div>
|
|
145
|
+
${this.history.hasMore?`
|
|
146
|
+
<div class="git-history-footer file-history-footer">
|
|
147
|
+
<button
|
|
148
|
+
class="ui-button ui-button--compact ui-action-button ui-action-button--surface btn btn-secondary git-history-load-more"
|
|
149
|
+
type="button"
|
|
150
|
+
data-file-history-load-more
|
|
151
|
+
${this.history.loadingMore?"disabled":""}
|
|
152
|
+
>
|
|
153
|
+
${this.history.loadingMore?"Loading...":"Load More"}
|
|
154
|
+
</button>
|
|
155
|
+
</div>
|
|
156
|
+
`:""}
|
|
157
|
+
</aside>
|
|
158
|
+
<section class="file-history-detail">
|
|
159
|
+
${this.renderSelectedHeader(t)}
|
|
160
|
+
<div class="file-history-detail-body">
|
|
161
|
+
${this.renderSelectedBody(t)}
|
|
162
|
+
</div>
|
|
163
|
+
</section>
|
|
164
|
+
</section>
|
|
165
|
+
`,this.restoreListScroll()}};function fe(s){return String(s??"").split("/").pop()||""}function _t(s){let e=String(s??"").split("/");return e.pop(),e.join("/")}function Qi(s){return`diff-section-${encodeURIComponent(String(s??"")).replace(/%/g,"_")}`}function $t(s){switch(s){case"added":case"untracked":return"ui-status-badge--success";case"deleted":return"ui-status-badge--danger";case"renamed":return"ui-status-badge--accent";default:return"ui-status-badge--warning"}}function un(s=!1){return`<svg class="diff-section-chevron${s?" collapsed":""}" width="12" height="12" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" aria-hidden="true"><polyline points="6 9 12 15 18 9"/></svg>`}function mn(s,e){let t=0;for(;t<s.length&&t<e.length&&s[t]===e[t];)t+=1;return t}function pn(s,e,t){let i=0,n=Math.min(s.length,e.length)-t;for(;i<n;){let r=s.length-1-i,o=e.length-1-i;if(s[r]!==e[o])break;i+=1}return i}function Xi(s,e){let t=mn(s,e),i=pn(s,e,t),n=Math.max(t,s.length-i),r=Math.max(t,e.length-i),o=`${p(s.slice(0,t))}${n>t?`<span class="diff-highlight-del">${p(s.slice(t,n))}</span>`:""}${p(s.slice(n))}`,a=`${p(e.slice(0,t))}${r>t?`<span class="diff-highlight-add">${p(e.slice(t,r))}</span>`:""}${p(e.slice(r))}`;return{leftHtml:o,rightHtml:a}}function Zi(s=[]){let e=[];for(let t=0;t<s.length;t+=1){let i=s[t];if(i.type==="context"||i.type==="note"){e.push({additions:[],context:[i],deletions:[]});continue}if(i.type!=="deletion"&&i.type!=="addition")continue;let n=[],r=[];for(;t<s.length&&s[t].type==="deletion";)n.push(s[t]),t+=1;for(;t<s.length&&s[t].type==="addition";)r.push(s[t]),t+=1;t-=1,e.push({additions:r,context:[],deletions:n})}return e}function Ot(s,e,t){let i=Number.isInteger(s.oldLine)?s.oldLine:"",n=Number.isInteger(s.newLine)?s.newLine:"",r=s.type==="note"?"note":s.type,o=s.type==="context"||s.type==="note"?" ":e;return`
|
|
55
166
|
<div class="diff-line ${r}">
|
|
56
167
|
<div class="diff-line-numbers">
|
|
57
168
|
<span class="diff-line-num">${i}</span>
|
|
58
|
-
<span class="diff-line-num">${
|
|
169
|
+
<span class="diff-line-num">${n}</span>
|
|
59
170
|
</div>
|
|
60
|
-
<div class="diff-line-prefix">${
|
|
171
|
+
<div class="diff-line-prefix">${p(o)}</div>
|
|
61
172
|
<div class="diff-line-content">${t}</div>
|
|
62
173
|
</div>
|
|
63
|
-
`}function
|
|
174
|
+
`}function Yi(s,e){let t=s?p(s.content):"",i=e?p(e.content):"";if(s&&e&&s.type==="deletion"&&e.type==="addition"){let n=Xi(s.content,e.content);t=n.leftHtml,i=n.rightHtml}return`
|
|
64
175
|
<div class="diff-split-row">
|
|
65
|
-
<div class="diff-split-line ${
|
|
66
|
-
<span class="diff-split-num">${Number.isInteger(
|
|
176
|
+
<div class="diff-split-line ${s?.type||"empty"}">
|
|
177
|
+
<span class="diff-split-num">${Number.isInteger(s?.oldLine)?s.oldLine:""}</span>
|
|
67
178
|
<span class="diff-split-content">${t}</span>
|
|
68
179
|
</div>
|
|
69
180
|
<div class="diff-split-line ${e?.type||"empty"}">
|
|
@@ -71,210 +182,337 @@ ${r}`}getPreviewSource(e){let t=this.getSession()?.getText()??"";return this.isM
|
|
|
71
182
|
<span class="diff-split-content">${i}</span>
|
|
72
183
|
</div>
|
|
73
184
|
</div>
|
|
74
|
-
`}var
|
|
75
|
-
<div class="diff-hunk-header">${
|
|
185
|
+
`}var ct=class{constructor({onBackToHistory:e=null,onCommitStaged:t=null,onOpenFile:i=null,onStageFile:n=null,onUnstageFile:r=null,toastController:o=null}={}){this.onBackToHistory=e,this.onCommitStaged=t,this.onOpenFile=i,this.onStageFile=n,this.onUnstageFile=r,this.toastController=o,this.page=document.getElementById("diff-page"),this.content=document.getElementById("diffContent"),this.scrollContainer=document.getElementById("diffScroll"),this.fileIndicator=document.getElementById("diffFileIndicator"),this.openEditorButton=document.getElementById("diffOpenEditorBtn"),this.primaryActionButton=document.getElementById("diffPrimaryActionBtn"),this.commitButton=document.getElementById("diffCommitBtn"),this.backToHistoryButton=document.getElementById("diffBackToHistoryBtn"),this.gitActionsGroup=document.getElementById("diffGitActionsGroup"),this.editorActionsGroup=document.getElementById("diffEditorActionsGroup"),this.actionsDivider=document.getElementById("diffToolbarDivider"),this.stats=document.getElementById("diffStats"),this.prevButton=document.getElementById("diffPrevBtn"),this.nextButton=document.getElementById("diffNextBtn"),this.layoutToggle=document.getElementById("diffLayoutToggle"),this.modeButtons=Array.from(document.querySelectorAll("[data-diff-mode]")),this.layoutButtons=Array.from(document.querySelectorAll("[data-diff-layout]")),this.mode="unified",this.layoutMode="focused",this.source="workspace",this.data=null,this.currentIndex=0,this.activeFilePath=null,this.fileCache=new Map,this.fileErrors=new Map,this.loadingFiles=new Set,this.collapsedFiles=new Set,this.fileLoadPromises=new Map,this.requestScope="all",this.commitHash=null,this.commitMeta=null,this.historyFilePath=null,this.pendingAction=null,this.repoStatus=null}initialize(){this.prevButton?.addEventListener("click",()=>this.navigateFile(-1)),this.nextButton?.addEventListener("click",()=>this.navigateFile(1)),this.backToHistoryButton?.addEventListener("click",()=>{this.commitMeta?.hash&&this.onBackToHistory?.({hash:this.commitMeta.hash,historyFilePath:this.historyFilePath})}),this.openEditorButton?.addEventListener("click",()=>{if(this.source!=="workspace")return;let e=this.getCurrentFile();e?.path&&this.onOpenFile?.(e.path)}),this.primaryActionButton?.addEventListener("click",()=>{let e=this.getPrimaryAction();e&&this.handleFileAction(e)}),this.commitButton?.addEventListener("click",()=>{this.handleFileAction("commit")}),this.content?.addEventListener("click",e=>{let t=e.target instanceof Element?e.target.closest("[data-load-full-diff]"):null;if(t){let r=t.getAttribute("data-diff-file-path")||this.activeFilePath;r&&this.loadFileForPath(r,{forceFullPatch:!0});return}let i=e.target instanceof Element?e.target.closest("[data-diff-section-toggle]"):null;if(i){let r=i.getAttribute("data-diff-section-toggle");r&&this.toggleFileSection(r);return}let n=e.target instanceof Element?e.target.closest("[data-diff-index-path]"):null;if(n){let r=n.getAttribute("data-diff-index-path");r&&this.handleIndexSelection(r)}}),this.modeButtons.forEach(e=>{e.addEventListener("click",()=>{let t=e.getAttribute("data-diff-mode");!t||t===this.mode||(this.mode=t,this.render())})}),this.layoutButtons.forEach(e=>{e.addEventListener("click",()=>{let t=e.getAttribute("data-diff-layout");!t||t===this.layoutMode||this.setLayoutMode(t)})}),this.scrollContainer?.addEventListener("scroll",()=>{this.handleScrollSelection()})}hide(){this.page?.classList.add("hidden"),this.content&&(this.content.innerHTML=""),this.data=null,this.source="workspace",this.layoutMode="focused",this.currentIndex=0,this.activeFilePath=null,this.fileCache.clear(),this.fileErrors.clear(),this.loadingFiles.clear(),this.collapsedFiles.clear(),this.fileLoadPromises.clear(),this.requestScope="all",this.commitHash=null,this.commitMeta=null,this.historyFilePath=null,this.pendingAction=null,this.repoStatus=null,this.syncToolbar()}async openWorkspaceDiff({filePath:e=null,scope:t="all"}={}){this.source="workspace",this.layoutMode="focused",this.commitHash=null,this.commitMeta=null,this.historyFilePath=null,this.activeFilePath=e,this.fileCache.clear(),this.fileErrors.clear(),this.loadingFiles.clear(),this.collapsedFiles.clear(),this.fileLoadPromises.clear(),this.requestScope=t,this.renderLoading("Loading diff summary...");try{let i=new URLSearchParams;i.set("scope",t),e&&i.set("path",e),i.set("metaOnly","true");let n=await fetch(b(`/git/diff?${i.toString()}`)),r=await n.json();if(!n.ok)throw new Error(r.error||"Failed to load git diff");this.data=r;let o=e?Math.max(0,r.files.findIndex(a=>a.path===e)):0;return this.currentIndex=o,this.activeFilePath=r.files?.[o]?.path??null,(r.files?.length??0)===0?(this.render(),r):(await this.loadCurrentFile(),r)}catch(i){return console.error("[git-diff] Failed to load diff:",i),this.toastController?.show("Failed to load git diff"),this.data={files:[],metaOnly:!1,source:"workspace",summary:{additions:0,deletions:0,filesChanged:0}},this.renderEmpty("Failed to load git diff"),this.data}}async openCommitDiff({hash:e,path:t=null,historyFilePath:i=null}={}){this.source="commit",this.layoutMode="stacked",this.commitHash=String(e??"").trim()||null,this.commitMeta=null,this.historyFilePath=String(i??"").trim()||null,this.activeFilePath=t||null,this.fileCache.clear(),this.fileErrors.clear(),this.loadingFiles.clear(),this.collapsedFiles.clear(),this.fileLoadPromises.clear(),this.requestScope="all",this.renderLoading("Loading commit summary...");try{let n=new URLSearchParams;n.set("hash",this.commitHash||""),n.set("metaOnly","true");let r=await fetch(b(`/git/commit?${n.toString()}`)),o=await r.json();if(!r.ok)throw new Error(o.error||"Failed to load git commit");this.data=o,this.commitMeta=o.commit??null;let a=t?Math.max(0,o.files.findIndex(c=>c.path===t)):0;return this.currentIndex=a,this.activeFilePath=o.files?.[a]?.path??null,this.collapsedFiles=new Set((o.files??[]).map(c=>c.path).filter(c=>c&&c!==this.activeFilePath)),(o.files?.length??0)===0?(this.render(),o):(this.activeFilePath&&await this.loadFileForPath(this.activeFilePath,{render:!1}),this.render(),o)}catch(n){return console.error("[git-diff] Failed to load commit:",n),this.toastController?.show("Failed to load git commit"),this.data={commit:null,files:[],metaOnly:!1,source:"commit",summary:{additions:0,deletions:0,filesChanged:0}},this.commitMeta=null,this.renderEmpty("Failed to load git commit"),this.data}}async open(e={}){return this.openWorkspaceDiff(e)}async setLayoutMode(e){let t=e==="stacked"?"stacked":"focused";if(this.source!=="commit"){this.layoutMode="focused",this.render();return}if(this.layoutMode=t,this.activeFilePath&&this.setActiveFilePath(this.activeFilePath),this.layoutMode==="focused"){await this.loadCurrentFile();return}this.activeFilePath&&(this.collapsedFiles.delete(this.activeFilePath),await this.loadFileForPath(this.activeFilePath,{render:!1})),this.render()}navigateFile(e){if(!this.data?.files?.length||this.source==="commit"&&this.layoutMode==="stacked")return;let t=Math.max(0,Math.min(this.currentIndex+e,this.data.files.length-1));t!==this.currentIndex&&(this.currentIndex=t,this.activeFilePath=this.data.files[t]?.path??null,this.scrollContainer?.scrollTo({top:0,behavior:"auto"}),this.loadCurrentFile())}renderLoading(e="Loading git diff..."){this.page?.classList.remove("hidden"),this.content&&(this.content.innerHTML=`<div class="diff-empty-state">${p(e)}</div>`),this.data=null,this.syncToolbar()}renderEmpty(e){this.page?.classList.remove("hidden"),this.content&&(this.content.innerHTML=`<div class="diff-empty-state">${p(e)}</div>`),this.syncToolbar()}renderUnifiedHunk(e){let t=[];for(let i of Zi(e.lines)){if(i.context.length>0){for(let r of i.context)t.push(Ot(r," ",p(r.content)));continue}let n=Math.max(i.deletions.length,i.additions.length);for(let r=0;r<n;r+=1){let o=i.deletions[r]??null,a=i.additions[r]??null,c=o&&a?Xi(o.content,a.content):null;o&&t.push(Ot(o,"-",c?.leftHtml??p(o.content))),a&&t.push(Ot(a,"+",c?.rightHtml??p(a.content)))}}return`
|
|
186
|
+
<div class="diff-hunk-header">${p(e.header)}</div>
|
|
76
187
|
${t.join("")}
|
|
77
|
-
`}
|
|
78
|
-
<
|
|
79
|
-
<
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
<div class="diff-split-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
<span class="git-status-badge ${ue(e.status)}">${g(e.status)}</span>
|
|
95
|
-
<span class="diff-file-header-stats"><span class="diff-stats-add">+${e.stats?.additions??0}</span><span class="diff-stats-del">-${e.stats?.deletions??0}</span></span>
|
|
188
|
+
`}renderFileHeader(e){return`
|
|
189
|
+
<div class="diff-file-header">
|
|
190
|
+
<span class="diff-file-path">${p(e.path)}</span>
|
|
191
|
+
<span class="ui-status-badge ${$t(e.status)}">${p(e.status)}</span>
|
|
192
|
+
<span class="diff-file-header-stats"><span class="ui-stat-token ui-stat-token--add diff-stats-add">+${e.stats?.additions??0}</span><span class="ui-stat-token ui-stat-token--del diff-stats-del">-${e.stats?.deletions??0}</span></span>
|
|
193
|
+
</div>
|
|
194
|
+
`}renderUnifiedFileBody(e){return`
|
|
195
|
+
${e.isBinary?`<div class="diff-binary-message">${p(e.binaryMessage||"Binary file changed")}</div>`:""}
|
|
196
|
+
${e.hunks.map(t=>this.renderUnifiedHunk(t)).join("")}
|
|
197
|
+
`}renderSplitFileBody(e){return`
|
|
198
|
+
<div class="diff-split">
|
|
199
|
+
<div class="diff-split-pane">
|
|
200
|
+
<div class="diff-split-pane-header">Before</div>
|
|
201
|
+
${e.hunks.map(i=>{let n=[];for(let r of Zi(i.lines)){if(r.context.length>0){for(let a of r.context)n.push(Yi(a,a));continue}let o=Math.max(r.deletions.length,r.additions.length);for(let a=0;a<o;a+=1)n.push(Yi(r.deletions[a]??null,r.additions[a]??null))}return`
|
|
202
|
+
<div class="diff-split-hunk">${p(i.header)}</div>
|
|
203
|
+
${n.join("")}
|
|
204
|
+
`}).join("")}
|
|
96
205
|
</div>
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
</
|
|
206
|
+
</div>
|
|
207
|
+
`}renderDiffDetail(e,t,{includeHeader:i=!0}={}){if(!e)return'<div class="diff-empty-state">Select a file to load its diff.</div>';if(e.tooLarge)return`
|
|
208
|
+
${i?this.renderFileHeader(e):""}
|
|
209
|
+
<div class="diff-limit-card">
|
|
210
|
+
<strong>Large diff withheld</strong>
|
|
211
|
+
<span>This file diff is large enough to impact rendering performance.</span>
|
|
212
|
+
<button class="ui-button btn btn-secondary diff-load-full-btn" type="button" data-load-full-diff data-diff-file-path="${p(e.path)}">Load full diff</button>
|
|
102
213
|
</div>
|
|
103
|
-
|
|
104
|
-
`}getCurrentFile(){let e=this.data?.files??[];return e.length===0?null:e[this.currentIndex]??e[0]??null}getCurrentCacheKey(){let e=this.getCurrentFile();return e?.path?`${this.requestScope}:${e.path}`:null}getCurrentFileDetail(){let e=this.getCurrentCacheKey();return e?this.fileCache.get(e):null}getCurrentActionState(){let e=this.getCurrentFile(),t=this.getCurrentFileDetail()??e,i=Number(this.repoStatus?.summary?.staged||0);return t?.path?{canCommit:i>0,canStage:!!(t.hasWorkingTreeChanges||t.hasUntrackedChanges),canUnstage:!!t.hasStagedChanges}:{canCommit:i>0,canStage:!1,canUnstage:!1}}getPrimaryAction(){let e=this.getCurrentActionState();return e.canStage&&!e.canUnstage?"stage":e.canUnstage&&!e.canStage||this.requestScope==="staged"&&e.canUnstage?"unstage":e.canStage?"stage":e.canUnstage?"unstage":null}async handleFileAction(e){let t=this.getCurrentFile();if(!(!t?.path||this.pendingAction)){this.pendingAction=e,this.syncToolbar();try{e==="stage"?await this.onStageFile?.(t.path,{scope:this.requestScope}):e==="unstage"?await this.onUnstageFile?.(t.path,{scope:this.requestScope}):e==="commit"&&await this.onCommitStaged?.()}finally{this.pendingAction=null,this.syncToolbar()}}}setRepoStatus(e){this.repoStatus=e,this.syncToolbar()}async loadCurrentFile({forceFullPatch:e=!1}={}){let t=this.getCurrentFile();if(!t?.path)return this.render(),null;let i=this.getCurrentCacheKey(),s=i?this.fileCache.get(i):null;if(s&&(!s.tooLarge||!e))return this.loadingFilePath=null,this.render(),s;this.loadingFilePath=t.path,this.render();try{let r=new URLSearchParams;r.set("scope",this.requestScope),r.set("path",t.path),e&&r.set("allowLargePatch","true");let a=await fetch(C(`/git/diff?${r.toString()}`)),o=await a.json();if(!a.ok)throw new Error(o.error||"Failed to load file diff");let l={...t,...o.files?.[0]??{}};return i&&this.fileCache.set(i,l),this.loadingFilePath=null,this.render(),l}catch(r){return console.error("[git-diff] Failed to load file diff:",r),this.toastController?.show("Failed to load file diff"),this.loadingFilePath=null,this.render(),null}}renderCurrentFile(){let e=this.getCurrentFile();if(!e)return'<div class="diff-empty-state">No changes to display.</div>';let t=this.getCurrentFileDetail();return this.loadingFilePath===e.path?`
|
|
214
|
+
`;let n=this.mode==="split"?this.renderSplitFileBody(e,t):this.renderUnifiedFileBody(e,t);return`${i?this.renderFileHeader(e):""}${n}`}renderFocusedFileBody(){let e=this.getCurrentFile();if(!e)return'<div class="diff-empty-state">No changes to display.</div>';if(this.isFileLoading(e.path))return`
|
|
105
215
|
<section class="diff-file-block">
|
|
106
|
-
|
|
107
|
-
<span class="diff-file-path">${g(e.path)}</span>
|
|
108
|
-
<span class="git-status-badge ${ue(e.status)}">${g(e.status)}</span>
|
|
109
|
-
</div>
|
|
216
|
+
${this.renderFileHeader(e)}
|
|
110
217
|
<div class="diff-empty-state">Loading file diff...</div>
|
|
111
218
|
</section>
|
|
112
|
-
|
|
219
|
+
`;let t=this.fileErrors.get(e.path);return t?`
|
|
113
220
|
<section class="diff-file-block">
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
<span class="git-status-badge ${ue(t.status)}">${g(t.status)}</span>
|
|
117
|
-
<span class="diff-file-header-stats"><span class="diff-stats-add">+${t.stats?.additions??0}</span><span class="diff-stats-del">-${t.stats?.deletions??0}</span></span>
|
|
118
|
-
</div>
|
|
119
|
-
<div class="diff-limit-card">
|
|
120
|
-
<strong>Large diff withheld</strong>
|
|
121
|
-
<span>This file diff is large enough to impact rendering performance.</span>
|
|
122
|
-
<button class="btn btn-secondary diff-load-full-btn" type="button" data-load-full-diff>Load full diff</button>
|
|
123
|
-
</div>
|
|
221
|
+
${this.renderFileHeader(e)}
|
|
222
|
+
<div class="diff-empty-state">${p(t)}</div>
|
|
124
223
|
</section>
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
224
|
+
`:`
|
|
225
|
+
<section class="diff-file-block" data-diff-file-index="${this.currentIndex}">
|
|
226
|
+
${this.renderDiffDetail(this.getFileDetail(e.path)??e,this.currentIndex)}
|
|
227
|
+
</section>
|
|
228
|
+
`}renderCommitHeader(){return this.source!=="commit"||!this.commitMeta?"":`
|
|
229
|
+
<section class="diff-commit-header">
|
|
230
|
+
<div class="diff-commit-subject">${p(this.commitMeta.subject||this.commitMeta.shortHash||"Commit")}</div>
|
|
231
|
+
<div class="diff-commit-meta">
|
|
232
|
+
<span>${p(this.commitMeta.shortHash||"")}</span>
|
|
233
|
+
<span>${p(this.commitMeta.authorName||"Unknown")}</span>
|
|
234
|
+
<span title="${p(this.commitMeta.authoredAt||"")}">${p(this.commitMeta.relativeDateLabel||"")}</span>
|
|
235
|
+
${this.commitMeta.isMergeCommit?"<span>Merge commit</span>":""}
|
|
236
|
+
</div>
|
|
237
|
+
<div class="diff-commit-meta diff-commit-meta-secondary">
|
|
238
|
+
<span>${p(this.commitMeta.hash||"")}</span>
|
|
239
|
+
<span>${Number(this.data?.summary?.filesChanged||0)} file${Number(this.data?.summary?.filesChanged||0)===1?"":"s"}</span>
|
|
240
|
+
</div>
|
|
241
|
+
</section>
|
|
242
|
+
`}renderCommitIndex(){return`
|
|
243
|
+
<aside class="diff-commit-index" aria-label="Changed files in commit">
|
|
244
|
+
<div class="diff-commit-index-header">Changed Files</div>
|
|
245
|
+
<div class="diff-commit-index-list">
|
|
246
|
+
${(this.data?.files??[]).map((i,n)=>{let r=this.activeFilePath===i.path,o=_t(i.path);return`
|
|
247
|
+
<button
|
|
248
|
+
class="ui-record-surface diff-index-item${r?" active":""}"
|
|
249
|
+
type="button"
|
|
250
|
+
data-diff-index-path="${p(i.path)}"
|
|
251
|
+
aria-current="${r?"true":"false"}"
|
|
252
|
+
>
|
|
253
|
+
<span class="ui-record-header diff-index-item-top">
|
|
254
|
+
<span class="ui-record-title diff-index-item-name">${p(fe(i.path))}</span>
|
|
255
|
+
<span class="ui-status-badge ${$t(i.status)}">${p(i.status)}</span>
|
|
256
|
+
</span>
|
|
257
|
+
${o?`<span class="ui-record-subtitle diff-index-item-path">${p(o)}</span>`:""}
|
|
258
|
+
<span class="ui-record-meta diff-index-item-meta">
|
|
259
|
+
<span>${n+1}</span>
|
|
260
|
+
<span class="ui-stat-token ui-stat-token--add diff-stats-add">+${i.stats?.additions??0}</span>
|
|
261
|
+
<span class="ui-stat-token ui-stat-token--del diff-stats-del">-${i.stats?.deletions??0}</span>
|
|
262
|
+
</span>
|
|
263
|
+
</button>
|
|
264
|
+
`}).join("")}
|
|
265
|
+
</div>
|
|
266
|
+
</aside>
|
|
267
|
+
`}renderStackedSection(e,t){let i=this.isFileCollapsed(e.path),n=this.activeFilePath===e.path,r=this.isFileLoading(e.path),o=this.fileErrors.get(e.path),a=this.getFileDetail(e.path)??e,c="";return i?c="":r?c='<div class="diff-empty-state">Loading file diff...</div>':o?c=`<div class="diff-empty-state">${p(o)}</div>`:c=this.renderDiffDetail(a,t,{includeHeader:!1}),`
|
|
268
|
+
<section
|
|
269
|
+
class="diff-commit-section${n?" active":""}${i?" collapsed":""}"
|
|
270
|
+
id="${Qi(e.path)}"
|
|
271
|
+
data-diff-section-path="${p(e.path)}"
|
|
272
|
+
>
|
|
273
|
+
<button
|
|
274
|
+
class="diff-commit-section-header"
|
|
275
|
+
type="button"
|
|
276
|
+
data-diff-section-toggle="${p(e.path)}"
|
|
277
|
+
>
|
|
278
|
+
<span class="diff-commit-section-main">
|
|
279
|
+
${un(i)}
|
|
280
|
+
<span class="diff-commit-section-copy">
|
|
281
|
+
<span class="diff-commit-section-name">${p(fe(e.path))}</span>
|
|
282
|
+
${_t(e.path)?`<span class="diff-commit-section-path">${p(_t(e.path))}</span>`:""}
|
|
283
|
+
</span>
|
|
284
|
+
</span>
|
|
285
|
+
<span class="diff-commit-section-meta">
|
|
286
|
+
<span class="ui-status-badge ${$t(e.status)}">${p(e.status)}</span>
|
|
287
|
+
<span class="ui-stat-token ui-stat-token--add diff-stats-add">+${e.stats?.additions??0}</span>
|
|
288
|
+
<span class="ui-stat-token ui-stat-token--del diff-stats-del">-${e.stats?.deletions??0}</span>
|
|
289
|
+
</span>
|
|
290
|
+
</button>
|
|
291
|
+
<div class="diff-commit-section-body${i?" hidden":""}">
|
|
292
|
+
${c}
|
|
293
|
+
</div>
|
|
294
|
+
</section>
|
|
295
|
+
`}renderCommitBody(){return this.layoutMode==="focused"?`
|
|
296
|
+
<div class="diff-commit-shell diff-commit-shell-focused">
|
|
297
|
+
${this.renderCommitIndex()}
|
|
298
|
+
<div class="diff-commit-main">
|
|
299
|
+
${this.renderFocusedFileBody()}
|
|
130
300
|
</div>
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
<
|
|
136
|
-
|
|
301
|
+
</div>
|
|
302
|
+
`:`
|
|
303
|
+
<div class="diff-commit-shell diff-commit-shell-stacked">
|
|
304
|
+
${this.renderCommitIndex()}
|
|
305
|
+
<div class="diff-commit-main">
|
|
306
|
+
<div class="diff-commit-sections">
|
|
307
|
+
${(this.data?.files??[]).map((e,t)=>this.renderStackedSection(e,t)).join("")}
|
|
308
|
+
</div>
|
|
309
|
+
</div>
|
|
310
|
+
</div>
|
|
311
|
+
`}getCurrentFile(){let e=this.data?.files??[];return e.length===0?null:e[this.currentIndex]??e[0]??null}getFileByPath(e){return(this.data?.files??[]).find(t=>t.path===e)??null}setActiveFilePath(e,{syncIndex:t=!0}={}){if(this.activeFilePath=e,!t)return;let i=Math.max(0,(this.data?.files??[]).findIndex(n=>n.path===e));i>=0&&(this.currentIndex=i)}getCacheKeyForPath(e){return e?this.source==="commit"?`commit:${this.commitHash}:${e}`:`workspace:${this.requestScope}:${e}`:null}getCurrentCacheKey(){return this.getCacheKeyForPath(this.getCurrentFile()?.path??null)}getCurrentFileDetail(){let e=this.getCurrentCacheKey();return e?this.fileCache.get(e):null}getFileDetail(e){let t=this.getCacheKeyForPath(e);return t?this.fileCache.get(t):null}isFileCollapsed(e){return this.collapsedFiles.has(e)}isFileLoading(e){return this.loadingFiles.has(e)}getCurrentActionState(){if(this.source==="commit")return{canCommit:!1,canStage:!1,canUnstage:!1};let e=this.getCurrentFile(),t=this.getCurrentFileDetail()??e,i=Number(this.repoStatus?.summary?.staged||0);return t?.path?{canCommit:i>0,canStage:!!(t.hasWorkingTreeChanges||t.hasUntrackedChanges),canUnstage:!!t.hasStagedChanges}:{canCommit:i>0,canStage:!1,canUnstage:!1}}getPrimaryAction(){if(this.source==="commit")return null;let e=this.getCurrentActionState();return e.canStage&&!e.canUnstage?"stage":e.canUnstage&&!e.canStage||this.requestScope==="staged"&&e.canUnstage?"unstage":e.canStage?"stage":e.canUnstage?"unstage":null}async handleFileAction(e){if(this.source==="commit")return;let t=this.getCurrentFile();if(!(!t?.path||this.pendingAction)){this.pendingAction=e,this.syncToolbar();try{e==="stage"?await this.onStageFile?.(t.path,{scope:this.requestScope}):e==="unstage"?await this.onUnstageFile?.(t.path,{scope:this.requestScope}):e==="commit"&&await this.onCommitStaged?.()}finally{this.pendingAction=null,this.syncToolbar()}}}setRepoStatus(e){this.repoStatus=e,this.syncToolbar()}async handleIndexSelection(e){if(this.getFileByPath(e)){if(this.setActiveFilePath(e),this.source==="commit"&&this.layoutMode==="stacked"){this.collapsedFiles.delete(e),await this.loadFileForPath(e,{render:!1}),this.render(),this.scrollToFileSection(e);return}await this.loadFileForPath(e)}}async toggleFileSection(e){if(!(this.source!=="commit"||this.layoutMode!=="stacked")){if(this.setActiveFilePath(e),this.collapsedFiles.has(e)){this.collapsedFiles.delete(e),await this.loadFileForPath(e,{render:!1}),this.render(),this.scrollToFileSection(e);return}this.collapsedFiles.add(e),this.render()}}scrollToFileSection(e){if(!this.content)return;let t=Qi(e),i=()=>{let n=document.getElementById?.(t)??null;if(n){if(this.scrollContainer?.scrollTo&&this.scrollContainer.getBoundingClientRect&&n.getBoundingClientRect){let r=this.scrollContainer.getBoundingClientRect(),o=n.getBoundingClientRect(),a=Number(this.scrollContainer.scrollTop)||0,c=Math.max(0,a+(o.top-r.top)-8);this.scrollContainer.scrollTo({top:c,behavior:"smooth"});return}n.scrollIntoView?.({behavior:"smooth",block:"start"})}};if(typeof requestAnimationFrame=="function"){requestAnimationFrame(i);return}setTimeout(i,0)}handleScrollSelection(){if(this.source!=="commit"||this.layoutMode!=="stacked"||!this.scrollContainer||!this.content)return;let e=Array.from(this.content.querySelectorAll?.("[data-diff-section-path]")??[]);if(e.length===0)return;let t=this.scrollContainer.getBoundingClientRect?.();if(!t)return;let i=t.top+120,n=null;for(let r of e){let o=r.getBoundingClientRect?.();if(!o)continue;let a=r.getAttribute?.("data-diff-section-path");if(a)if(o.top<=i)n=a;else{if(n)break;n=a;break}}n&&n!==this.activeFilePath&&(this.setActiveFilePath(n),this.render())}async loadCurrentFile({forceFullPatch:e=!1}={}){let t=this.getCurrentFile();return t?.path?this.loadFileForPath(t.path,{forceFullPatch:e}):(this.render(),null)}async loadFileForPath(e,{forceFullPatch:t=!1,render:i=!0}={}){let n=this.getFileByPath(e);if(!n?.path)return i&&this.render(),null;this.setActiveFilePath(e);let r=this.getCacheKeyForPath(e),o=r?this.fileCache.get(r):null;if(o&&(!o.tooLarge||!t))return i&&this.render(),o;let a=`${e}:${t?"full":"partial"}`;if(this.fileLoadPromises.has(a))return this.fileLoadPromises.get(a);this.loadingFiles.add(e),this.fileErrors.delete(e),i&&this.render();let c=(async()=>{try{let h;if(this.source==="commit"){let l=new URLSearchParams;l.set("hash",this.commitHash||""),l.set("path",e),t&&l.set("allowLargePatch","true");let u=await fetch(b(`/git/commit?${l.toString()}`)),m=await u.json();if(!u.ok)throw new Error(m.error||"Failed to load commit file diff");h={...n,...m.files?.[0]??{}}}else{let l=new URLSearchParams;l.set("scope",this.requestScope),l.set("path",e),t&&l.set("allowLargePatch","true");let u=await fetch(b(`/git/diff?${l.toString()}`)),m=await u.json();if(!u.ok)throw new Error(m.error||"Failed to load file diff");h={...n,...m.files?.[0]??{}}}return r&&this.fileCache.set(r,h),this.fileErrors.delete(e),h}catch(h){console.error("[git-diff] Failed to load file diff:",h);let l=this.source==="commit"?"Failed to load commit file diff":"Failed to load file diff";return this.fileErrors.set(e,l),this.toastController?.show(l),null}finally{this.loadingFiles.delete(e),this.fileLoadPromises.delete(a),this.render()}})();return this.fileLoadPromises.set(a,c),c}syncToolbar(){let e=this.data?.files?.length??0,t=e===0?0:this.currentIndex+1,i=this.source==="commit",n=i&&this.layoutMode==="stacked";if(this.fileIndicator&&(n?this.fileIndicator.textContent=`${e} file${e===1?"":"s"}`:this.fileIndicator.textContent=e>0?`${t} / ${e} files`:"0 / 0 files"),this.stats){let c=this.data?.summary?.additions??0,h=this.data?.summary?.deletions??0;this.stats.innerHTML=`
|
|
312
|
+
<span class="ui-stat-token ui-stat-token--add diff-stats-add">+${c}</span>
|
|
313
|
+
<span class="ui-stat-token ui-stat-token--del diff-stats-del">-${h}</span>
|
|
314
|
+
`}this.modeButtons.forEach(c=>{c.classList.remove("hidden"),c.classList.toggle("active",c.getAttribute("data-diff-mode")===this.mode)}),this.layoutButtons.forEach(c=>{c.classList.toggle("active",c.getAttribute("data-diff-layout")===this.layoutMode)});let r=!!this.getCurrentFile()?.path,o=this.getCurrentActionState(),a=this.getPrimaryAction();this.backToHistoryButton?.classList.toggle("hidden",!i),this.gitActionsGroup?.classList.toggle("hidden",i),this.editorActionsGroup?.classList.toggle("hidden",i),this.actionsDivider?.classList.toggle("hidden",i),this.layoutToggle?.classList.toggle("hidden",!i),this.stats?.classList.remove("hidden"),this.openEditorButton&&(this.openEditorButton.textContent="Open in Editor"),this.openEditorButton?.toggleAttribute("disabled",!r||i),this.primaryActionButton&&(this.primaryActionButton.textContent=this.pendingAction===a?"Working...":a==="unstage"?"Unstage":"Stage",this.primaryActionButton.toggleAttribute("disabled",i||!r||!a||!!this.pendingAction)),this.commitButton&&(this.commitButton.textContent=this.pendingAction==="commit"?"Working...":"Commit Staged"),this.commitButton?.toggleAttribute("disabled",i||!o.canCommit||!!this.pendingAction),this.prevButton?.classList.remove("hidden"),this.nextButton?.classList.remove("hidden"),this.prevButton?.classList.toggle("hidden",n),this.nextButton?.classList.toggle("hidden",n),this.prevButton?.toggleAttribute("disabled",n||this.currentIndex<=0),this.nextButton?.toggleAttribute("disabled",n||e===0||this.currentIndex>=e-1)}render(){if(this.page?.classList.remove("hidden"),(this.data?.files??[]).length===0){this.renderEmpty(this.source==="commit"?"No commit changes to display.":"No changes to display.");return}this.content&&(this.source==="commit"?this.content.innerHTML=`${this.renderCommitHeader()}${this.renderCommitBody()}`:this.content.innerHTML=this.renderFocusedFileBody(),this.syncToolbar())}getToolbarTitle({commitHash:e=null,filePath:t=null,path:i=null,scope:n="all",source:r="workspace"}={}){return r==="commit"||this.source==="commit"?this.layoutMode==="stacked"?this.commitMeta?.shortHash?`Commit ${this.commitMeta.shortHash}`:e?`Commit ${String(e).slice(0,7)}`:"Commit Diff":i?fe(i):this.activeFilePath?fe(this.activeFilePath):this.commitMeta?.shortHash?`Commit ${this.commitMeta.shortHash}`:e?`Commit ${String(e).slice(0,7)}`:"Commit Diff":t?fe(t):n==="staged"?"Staged Changes":n==="working-tree"?"Working Tree Changes":"All Changes"}};var Ji=30,fn=1e4;function gn(s){let e=String(s??"").split("/");return e.pop(),e.join("/")}function yn(s){return String(s??"").split("/").pop()||""}function es(){return'<svg class="git-file-icon" width="12" height="12" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" aria-hidden="true"><path d="M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z"/><polyline points="14 2 14 8 20 8"/></svg>'}function wn(){return'<svg width="12" height="12" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><circle cx="18" cy="18" r="3"/><circle cx="6" cy="6" r="3"/><path d="M13 6h3a2 2 0 0 1 2 2v7"/><path d="M6 9v12"/></svg>'}function ts(s){return`<svg class="git-section-chevron${s?" collapsed":""}" width="10" height="10" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" aria-hidden="true"><polyline points="6 9 12 15 18 9"/></svg>`}function ht(s){switch(s){case"commit":return'<svg width="12" height="12" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M20 6 9 17l-5-5"/></svg>';case"pull":return'<svg width="12" height="12" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M12 5v14"/><path d="m18 13-6 6-6-6"/></svg>';case"push":return'<svg width="12" height="12" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M12 19V5"/><path d="m6 11 6-6 6 6"/></svg>';case"unstage":return'<svg width="12" height="12" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M20 12H8"/><path d="m12 16-4-4 4-4"/></svg>';case"reset":return'<svg width="12" height="12" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M3 12a9 9 0 1 0 3-6.7"/><path d="M3 4v5h5"/></svg>';default:return'<svg width="12" height="12" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M12 5v14"/><path d="M5 12h14"/></svg>'}}function vn(s){switch(s){case"added":return"ui-status-badge--success";case"deleted":return"ui-status-badge--danger";case"renamed":return"ui-status-badge--accent";case"untracked":return"ui-status-badge--muted";default:return"ui-status-badge--warning"}}function bn(s={},e={}){let t=Number(s.additions||0),i=Number(s.deletions||0);return Number(s.changedFiles||0)>0||t>0||i>0?`
|
|
137
315
|
<span class="git-change-stats" aria-label="Local diff summary">
|
|
138
316
|
<span class="git-change-add">+${t}</span>
|
|
139
317
|
<span class="git-change-del">-${i}</span>
|
|
140
318
|
</span>
|
|
141
319
|
`:e.upstream||Number(e.ahead||0)>0||Number(e.behind||0)>0?`
|
|
142
320
|
<span class="git-sync-info" aria-label="Remote sync status">
|
|
143
|
-
<span
|
|
144
|
-
<span
|
|
321
|
+
<span class="git-sync-metric git-sync-metric--ahead">↑${Number(e.ahead||0)}</span>
|
|
322
|
+
<span class="git-sync-metric git-sync-metric--behind">↓${Number(e.behind||0)}</span>
|
|
145
323
|
</span>
|
|
146
|
-
`:'<span class="git-sync-info git-sync-info-muted">Clean</span>'}var
|
|
324
|
+
`:'<span class="git-sync-info git-sync-info-muted">Clean</span>'}function Cn(s={}){let e=String(s.subject||"").trim()||s.shortHash||"Commit";return p(e)}var dt=class{constructor({enabled:e=!0,onCommitStaged:t=()=>{},onOpenPullBackup:i=()=>{},onPullBranch:n=()=>{},onPushBranch:r=()=>{},onRepoChange:o=()=>{},onResetFile:a=()=>{},onSelectCommit:c=()=>{},onSelectDiff:h=()=>{},onStageFile:l=()=>{},onUnstageFile:u=()=>{},onViewAllDiff:m=()=>{},searchInput:d=null,toastController:w=null}={}){this.enabled=e,this.onCommitStaged=t,this.onOpenPullBackup=i,this.onPullBranch=n,this.onPushBranch=r,this.onRepoChange=o,this.onResetFile=a,this.onSelectCommit=c,this.onSelectDiff=h,this.onStageFile=l,this.onUnstageFile=u,this.onViewAllDiff=m,this.searchInput=d,this.toastController=w,this.panel=document.getElementById("gitPanel"),this.pullBackups=[],this.status=null,this.active=!1,this.refreshTimer=null,this.searchQuery="",this.panelMode="changes",this.collapsedSections=new Set,this.selection={commitHash:null,path:null,scope:null,source:"workspace"},this.pendingActionKey=null,this.history={commits:[],error:"",hasMore:!1,loaded:!1,loading:!1,loadingMore:!1,offset:0}}initialize(){this.panel?.addEventListener("click",e=>{let t=e.target instanceof Element?e.target.closest("[data-git-panel-mode]"):null;if(t){let m=t.getAttribute("data-git-panel-mode");(m==="changes"||m==="history")&&this.setMode(m);return}let i=e.target instanceof Element?e.target.closest("[data-git-section-toggle]"):null;if(i){let m=i.getAttribute("data-git-section-toggle");this.toggleSection(m);return}let n=e.target instanceof Element?e.target.closest("[data-git-commit-hash]"):null;if(n&&!e.target.closest("[data-git-history-load-more]")){let m=n.getAttribute("data-git-commit-hash");if(!m)return;this.onSelectCommit(m,{path:this.selection.commitHash===m?this.selection.path:null});return}if(e.target instanceof Element?e.target.closest("[data-git-history-load-more]"):null){this.loadMoreHistory();return}let o=e.target instanceof Element?e.target.closest("[data-git-path]"):null;if(o&&!e.target.closest("[data-git-file-action]")){let m=o.getAttribute("data-git-path"),d=o.getAttribute("data-git-scope")||"working-tree";if(!m)return;this.onSelectDiff(m,{scope:d});return}let a=e.target instanceof Element?e.target.closest("[data-git-pull-backup-path]"):null;if(a){let m=a.getAttribute("data-git-pull-backup-path");if(!m)return;this.onOpenPullBackup(m);return}let c=e.target instanceof Element?e.target.closest("[data-git-file-action]"):null;if(c){let m=c.getAttribute("data-git-file-action"),d=c.getAttribute("data-git-path"),w=c.getAttribute("data-git-scope")||"working-tree";if(!m||!d)return;e.preventDefault(),e.stopPropagation(),this.handleFileAction(m,d,w);return}if(e.target instanceof Element?e.target.closest("[data-git-view-all]"):null){this.onViewAllDiff();return}if(e.target instanceof Element?e.target.closest("[data-git-commit-staged]"):null){this.handleCommitStaged();return}let u=e.target instanceof Element?e.target.closest("[data-git-sync-action]"):null;if(u){let m=u.getAttribute("data-git-sync-action");(m==="pull"||m==="push")&&this.handleSyncAction(m)}}),this.searchInput?.addEventListener("input",e=>{this.searchQuery=String(e.target?.value??"").trim().toLowerCase(),this.render()}),this.syncSearchUi()}setActive(e){let t=!!e;if(!(this.active===t&&(!t||this.refreshTimer||this.panelMode==="history"))){if(this.active=t,!this.active){this.stopStatusPolling();return}this.syncSearchUi(),this.refresh({force:!1,includeHistory:this.panelMode==="history"}),this.panelMode==="changes"?this.ensureStatusPolling():this.stopStatusPolling()}}async setMode(e,{forceHistoryRefresh:t=!1}={}){let i=e==="history"?"history":"changes",n=this.panelMode!==i;if(this.panelMode=i,this.syncSearchUi(),this.render(),!!this.active){if(this.panelMode==="changes"){this.ensureStatusPolling(),n&&await this.refresh({force:!1,includeHistory:!1});return}this.stopStatusPolling(),(t||n||!this.history.loaded)&&await this.refreshHistory({force:t||n})}}setSelection({commitHash:e=null,path:t=null,scope:i=null,source:n="workspace"}={}){this.selection={commitHash:e,path:t,scope:i,source:n},(n==="commit"||e)&&(this.panelMode="history",this.syncSearchUi()),this.render()}toggleSection(e){e&&(this.collapsedSections.has(e)?this.collapsedSections.delete(e):this.collapsedSections.add(e),this.render())}ensureStatusPolling(){this.refreshTimer||!this.active||this.panelMode!=="changes"||(this.refreshTimer=setInterval(()=>{this.refresh({force:!1,includeHistory:!1})},fn))}stopStatusPolling(){clearInterval(this.refreshTimer),this.refreshTimer=null}syncSearchUi(){this.searchInput&&(this.searchInput.setAttribute("placeholder",this.panelMode==="history"?"Filter loaded commits...":"Search changes..."),this.searchInput.setAttribute("aria-label",this.panelMode==="history"?"Filter loaded commits":"Search changed files"))}async refresh({force:e=!1,includeHistory:t=this.panelMode==="history"}={}){let i=await this.refreshStatus({force:e});return t&&i.isGitRepo&&await this.refreshHistory({force:e}),i}async refreshStatus({force:e=!1}={}){if(!this.enabled)return this.status={isGitRepo:!1,sections:[],summary:{changedFiles:0}},this.pullBackups=[],this.history={...this.history,commits:[],error:"",hasMore:!1,loaded:!1,loading:!1,loadingMore:!1,offset:0},this.onRepoChange(!1,this.status),this.render(),this.status;try{let t=await fetch(b(`/git/status${e?"?force=true":""}`)),i=await t.json();if(!t.ok)throw new Error(i.error||"Failed to load git status");if(this.status=i,this.pullBackups=[],i.isGitRepo)try{let n=await fetch(b("/git/pull-backups")),r=await n.json();if(!n.ok)throw new Error(r.error||"Failed to load pull backups");this.pullBackups=Array.isArray(r.backups)?r.backups:[]}catch(n){console.error("[git-panel] Failed to load pull backups:",n)}else this.history={...this.history,commits:[],error:"",hasMore:!1,loaded:!1,loading:!1,loadingMore:!1,offset:0};return this.onRepoChange(!!i.isGitRepo,i),this.render(),i}catch(t){return console.error("[git-panel] Failed to load git status:",t),this.toastController?.show("Failed to load git status"),this.status={isGitRepo:!1,sections:[],summary:{changedFiles:0}},this.pullBackups=[],this.history={...this.history,commits:[],error:"",hasMore:!1,loaded:!1,loading:!1,loadingMore:!1,offset:0},this.onRepoChange(!1,this.status),this.render(),this.status}}async refreshHistory({force:e=!1}={}){if(!this.status?.isGitRepo)return this.history={...this.history,commits:[],error:"",hasMore:!1,loaded:!1,loading:!1,loadingMore:!1,offset:0},this.render(),this.history;if(this.history.loading&&!e)return this.history;this.history={...this.history,error:"",loading:!0,loadingMore:!1},e&&(this.history={...this.history,commits:[],hasMore:!1,loaded:!1,offset:0}),this.render();try{let t=new URLSearchParams;t.set("limit",String(Ji)),t.set("offset","0");let i=await fetch(b(`/git/history?${t.toString()}`)),n=await i.json();if(!i.ok)throw new Error(n.error||"Failed to load git history");return this.history={commits:Array.isArray(n.commits)?n.commits:[],error:"",hasMore:!!n.hasMore,loaded:!0,loading:!1,loadingMore:!1,offset:Array.isArray(n.commits)?n.commits.length:0},this.render(),this.history}catch(t){return console.error("[git-panel] Failed to load git history:",t),this.toastController?.show("Failed to load git history"),this.history={...this.history,error:"Failed to load git history",loading:!1,loadingMore:!1},this.render(),this.history}}async loadMoreHistory(){if(!(!this.status?.isGitRepo||this.history.loading||this.history.loadingMore||!this.history.hasMore)){this.history={...this.history,error:"",loadingMore:!0},this.render();try{let e=new URLSearchParams;e.set("limit",String(Ji)),e.set("offset",String(this.history.offset));let t=await fetch(b(`/git/history?${e.toString()}`)),i=await t.json();if(!t.ok)throw new Error(i.error||"Failed to load git history");let n=Array.isArray(i.commits)?i.commits:[];this.history={commits:[...this.history.commits,...n],error:"",hasMore:!!i.hasMore,loaded:!0,loading:!1,loadingMore:!1,offset:this.history.offset+n.length},this.render()}catch(e){console.error("[git-panel] Failed to load more git history:",e),this.toastController?.show("Failed to load git history"),this.history={...this.history,error:"Failed to load git history",loadingMore:!1},this.render()}}}filterFiles(e=[]){return this.searchQuery?e.filter(t=>t.path.toLowerCase().includes(this.searchQuery)||String(t.oldPath||"").toLowerCase().includes(this.searchQuery)):e}filterCommits(e=[]){return this.searchQuery?e.filter(t=>String(t.subject||"").toLowerCase().includes(this.searchQuery)||String(t.shortHash||"").toLowerCase().includes(this.searchQuery)||String(t.authorName||"").toLowerCase().includes(this.searchQuery)):e}async handleFileAction(e,t,i){let n=`${e}:${i}:${t}`;if(this.pendingActionKey!==n){this.pendingActionKey=n,this.render();try{e==="stage"?await this.onStageFile(t,{scope:i}):e==="unstage"?await this.onUnstageFile(t,{scope:i}):e==="reset"&&await this.onResetFile(t,{scope:i})}finally{this.pendingActionKey=null,this.render()}}}async handleCommitStaged(){let e="commit-staged";if(this.pendingActionKey!==e){this.pendingActionKey=e,this.render();try{await this.onCommitStaged()}finally{this.pendingActionKey=null,this.render()}}}async handleSyncAction(e){let t=`sync:${e}`;if(this.pendingActionKey!==t){this.pendingActionKey=t,this.render();try{e==="pull"?await this.onPullBranch():e==="push"&&await this.onPushBranch()}finally{this.pendingActionKey=null,this.render()}}}renderSection(e){let t=this.filterFiles(e.files);if(t.length===0)return"";let i=this.collapsedSections.has(e.key);return`
|
|
147
325
|
<section class="git-section">
|
|
148
|
-
<button class="git-section-header" type="button" data-git-section-toggle="${
|
|
149
|
-
${
|
|
150
|
-
${
|
|
151
|
-
<span class="git-section-count">${t.length}</span>
|
|
326
|
+
<button class="git-section-header" type="button" data-git-section-toggle="${p(e.key)}">
|
|
327
|
+
${ts(i)}
|
|
328
|
+
${p(e.label)}
|
|
329
|
+
<span class="ui-pill-badge ui-pill-badge--count ui-pill-badge--muted git-section-count">${t.length}</span>
|
|
152
330
|
</button>
|
|
153
331
|
<div class="git-file-list${i?" hidden":""}">
|
|
154
|
-
${t.map(
|
|
332
|
+
${t.map(n=>this.renderFile(n)).join("")}
|
|
155
333
|
</div>
|
|
156
334
|
</section>
|
|
157
335
|
`}renderPullBackupsSection(){return!Array.isArray(this.pullBackups)||this.pullBackups.length===0?"":`
|
|
158
336
|
<section class="git-section">
|
|
159
337
|
<button class="git-section-header" type="button" data-git-section-toggle="pull-backups">
|
|
160
|
-
${
|
|
338
|
+
${ts(this.collapsedSections.has("pull-backups"))}
|
|
161
339
|
Pull Backups
|
|
162
|
-
<span class="git-section-count">${this.pullBackups.length}</span>
|
|
340
|
+
<span class="ui-pill-badge ui-pill-badge--count ui-pill-badge--muted git-section-count">${this.pullBackups.length}</span>
|
|
163
341
|
</button>
|
|
164
342
|
<div class="git-file-list${this.collapsedSections.has("pull-backups")?" hidden":""}">
|
|
165
343
|
${this.pullBackups.map(e=>this.renderPullBackup(e)).join("")}
|
|
166
344
|
</div>
|
|
167
345
|
</section>
|
|
168
346
|
`}renderPullBackup(e){let t=String(e?.createdAt||"").replace("T"," ").replace(/\.\d+Z?$/u,"Z"),i=Number(e?.fileCount||0);return`
|
|
169
|
-
<div class="git-file-row">
|
|
347
|
+
<div class="ui-item-row git-file-row">
|
|
170
348
|
<button
|
|
171
|
-
class="git-file-item"
|
|
349
|
+
class="ui-item-main git-file-item"
|
|
172
350
|
type="button"
|
|
173
|
-
data-git-pull-backup-path="${
|
|
351
|
+
data-git-pull-backup-path="${p(e.summaryPath||"")}"
|
|
174
352
|
>
|
|
175
|
-
${
|
|
176
|
-
<span class="git-file-copy">
|
|
177
|
-
<span class="git-file-name">Pull backup ${
|
|
178
|
-
<span class="git-file-path">${
|
|
353
|
+
${es()}
|
|
354
|
+
<span class="ui-item-copy git-file-copy">
|
|
355
|
+
<span class="ui-item-title git-file-name">Pull backup ${p(e.id||"")}</span>
|
|
356
|
+
<span class="ui-item-subtitle git-file-path">${p(`${t} \xB7 ${e.branch||"HEAD"} \xB7 ${i} file${i===1?"":"s"}`)}</span>
|
|
179
357
|
</span>
|
|
180
|
-
<span class="
|
|
358
|
+
<span class="ui-status-badge ui-status-badge--warning">BK</span>
|
|
181
359
|
</button>
|
|
182
360
|
</div>
|
|
183
|
-
`}renderFile(e){let t=this.selection.path===e.path&&this.selection.scope===e.scope,i=
|
|
184
|
-
<div class="git-file-row${t?" active":""}">
|
|
361
|
+
`}renderFile(e){let t=this.selection.source==="workspace"&&this.selection.path===e.path&&this.selection.scope===e.scope,i=gn(e.path),n=yn(e.path),r=vn(e.status),o=e.scope==="staged"?{label:"Unstage",value:"unstage"}:{label:"Stage",value:"stage"},a=`${o.value}:${e.scope}:${e.path}`,c=this.pendingActionKey===a,h=`reset:${e.scope}:${e.path}`,l=this.pendingActionKey===h;return`
|
|
362
|
+
<div class="ui-item-row git-file-row${t?" active":""}">
|
|
185
363
|
<button
|
|
186
|
-
class="git-file-item${t?" active":""}"
|
|
364
|
+
class="ui-item-main git-file-item${t?" active":""}"
|
|
187
365
|
type="button"
|
|
188
|
-
data-git-path="${
|
|
189
|
-
data-git-scope="${
|
|
366
|
+
data-git-path="${p(e.path)}"
|
|
367
|
+
data-git-scope="${p(e.scope)}"
|
|
190
368
|
>
|
|
191
|
-
${
|
|
192
|
-
<span class="git-file-copy">
|
|
193
|
-
<span class="git-file-name">${
|
|
194
|
-
${i?`<span class="git-file-path">${
|
|
369
|
+
${es()}
|
|
370
|
+
<span class="ui-item-copy git-file-copy">
|
|
371
|
+
<span class="ui-item-title git-file-name">${p(n)}</span>
|
|
372
|
+
${i?`<span class="ui-item-subtitle git-file-path">${p(i)}</span>`:""}
|
|
195
373
|
</span>
|
|
196
|
-
<span class="
|
|
374
|
+
<span class="ui-status-badge ${r}">${p(e.code)}</span>
|
|
197
375
|
</button>
|
|
198
|
-
<div class="git-file-actions">
|
|
376
|
+
<div class="ui-item-actions git-file-actions">
|
|
199
377
|
<button
|
|
200
|
-
class="
|
|
378
|
+
class="ui-icon-button ui-action-icon ui-action-icon--surface"
|
|
201
379
|
type="button"
|
|
202
380
|
data-git-file-action="reset"
|
|
203
|
-
data-git-path="${
|
|
204
|
-
data-git-scope="${
|
|
205
|
-
aria-label="Reset ${
|
|
381
|
+
data-git-path="${p(e.path)}"
|
|
382
|
+
data-git-scope="${p(e.scope)}"
|
|
383
|
+
aria-label="Reset ${p(n)}"
|
|
206
384
|
title="Reset to current branch"
|
|
207
|
-
${
|
|
385
|
+
${l?"disabled":""}
|
|
208
386
|
>
|
|
209
|
-
${
|
|
387
|
+
${l?"...":ht("reset")}
|
|
210
388
|
</button>
|
|
211
389
|
<button
|
|
212
|
-
class="
|
|
390
|
+
class="ui-icon-button ui-action-icon ui-action-icon--surface"
|
|
213
391
|
type="button"
|
|
214
|
-
data-git-file-action="${
|
|
215
|
-
data-git-path="${
|
|
216
|
-
data-git-scope="${
|
|
217
|
-
aria-label="${
|
|
218
|
-
title="${
|
|
219
|
-
${
|
|
392
|
+
data-git-file-action="${o.value}"
|
|
393
|
+
data-git-path="${p(e.path)}"
|
|
394
|
+
data-git-scope="${p(e.scope)}"
|
|
395
|
+
aria-label="${p(o.label)} ${p(n)}"
|
|
396
|
+
title="${p(o.label)}"
|
|
397
|
+
${c?"disabled":""}
|
|
220
398
|
>
|
|
221
|
-
${
|
|
399
|
+
${c?"...":ht(o.value)}
|
|
222
400
|
</button>
|
|
223
401
|
</div>
|
|
224
402
|
</div>
|
|
225
|
-
`}
|
|
403
|
+
`}renderPanelModes(){return`
|
|
404
|
+
<div class="ui-segmented-control ui-segmented-control--pill git-panel-mode-switch" role="tablist" aria-label="Git panel modes">
|
|
405
|
+
<button
|
|
406
|
+
class="ui-segmented-btn git-panel-mode-btn${this.panelMode==="changes"?" active":""}"
|
|
407
|
+
type="button"
|
|
408
|
+
data-git-panel-mode="changes"
|
|
409
|
+
aria-selected="${this.panelMode==="changes"}"
|
|
410
|
+
>
|
|
411
|
+
Changes
|
|
412
|
+
</button>
|
|
413
|
+
<button
|
|
414
|
+
class="ui-segmented-btn git-panel-mode-btn${this.panelMode==="history"?" active":""}"
|
|
415
|
+
type="button"
|
|
416
|
+
data-git-panel-mode="history"
|
|
417
|
+
aria-selected="${this.panelMode==="history"}"
|
|
418
|
+
>
|
|
419
|
+
History
|
|
420
|
+
</button>
|
|
421
|
+
</div>
|
|
422
|
+
`}renderHistoryRow(e){let t=this.selection.source==="commit"&&this.selection.commitHash===e.hash,i=Number(e.filesChanged||0);return`
|
|
423
|
+
<button
|
|
424
|
+
class="ui-record-surface git-history-row${t?" active":""}"
|
|
425
|
+
type="button"
|
|
426
|
+
data-git-commit-hash="${p(e.hash||"")}"
|
|
427
|
+
title="${p(e.authoredAt||"")}"
|
|
428
|
+
>
|
|
429
|
+
<span class="ui-record-header git-history-row-top">
|
|
430
|
+
<span class="ui-record-title git-history-subject">${Cn(e)}</span>
|
|
431
|
+
<span class="ui-pill-badge ui-pill-badge--code git-history-hash">${p(e.shortHash||"")}</span>
|
|
432
|
+
</span>
|
|
433
|
+
<span class="ui-record-meta git-history-row-meta">
|
|
434
|
+
<span>${p(e.authorName||"Unknown")}</span>
|
|
435
|
+
<span>${p(e.relativeDateLabel||"")}</span>
|
|
436
|
+
<span>${i} file${i===1?"":"s"}</span>
|
|
437
|
+
${e.isMergeCommit?"<span>Merge</span>":""}
|
|
438
|
+
</span>
|
|
439
|
+
<span class="ui-record-meta git-history-row-stats">
|
|
440
|
+
<span class="git-change-add">+${Number(e.additions||0)}</span>
|
|
441
|
+
<span class="git-change-del">-${Number(e.deletions||0)}</span>
|
|
442
|
+
</span>
|
|
443
|
+
</button>
|
|
444
|
+
`}renderHistoryPanel(){let e=this.filterCommits(this.history.commits);return this.history.loading&&!this.history.loaded?'<div class="git-panel-empty">Loading git history...</div>':this.history.error&&!this.history.loaded?`<div class="git-panel-empty">${p(this.history.error)}</div>`:this.history.loaded&&e.length===0&&this.history.commits.length===0?'<div class="git-panel-empty">No commits yet on this branch.</div>':this.history.loaded&&e.length===0?'<div class="git-panel-empty">No loaded commits match your filter.</div>':`
|
|
445
|
+
<div class="git-history-list">
|
|
446
|
+
${e.map(t=>this.renderHistoryRow(t)).join("")}
|
|
447
|
+
</div>
|
|
448
|
+
${this.history.hasMore?`
|
|
449
|
+
<div class="git-history-footer">
|
|
450
|
+
<button
|
|
451
|
+
class="ui-button ui-button--compact ui-action-button ui-action-button--surface btn btn-secondary git-history-load-more"
|
|
452
|
+
type="button"
|
|
453
|
+
data-git-history-load-more
|
|
454
|
+
${this.history.loadingMore?"disabled":""}
|
|
455
|
+
>
|
|
456
|
+
${this.history.loadingMore?"Loading...":"Load More"}
|
|
457
|
+
</button>
|
|
458
|
+
</div>
|
|
459
|
+
`:""}
|
|
460
|
+
`}renderChangesPanel(){let e=this.renderPullBackupsSection(),t=(this.status.sections??[]).map(o=>this.renderSection(o)).filter(Boolean).join(""),i=!!this.status.summary?.changedFiles,n=Number(this.status.summary?.staged||0)>0,r=this.pendingActionKey==="commit-staged";return`
|
|
461
|
+
${e}
|
|
462
|
+
${t||'<div class="git-panel-empty">No local changes</div>'}
|
|
463
|
+
${i?`
|
|
464
|
+
<div class="git-panel-footer">
|
|
465
|
+
<div class="git-panel-footer-actions">
|
|
466
|
+
<button class="ui-button ui-button--compact ui-action-button ui-action-button--surface btn btn-secondary" type="button" data-git-view-all>
|
|
467
|
+
<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" aria-hidden="true"><path d="M2 12s4-8 11-8 11 8 11 8-4 8-11 8-11-8-11-8z"/><circle cx="12" cy="12" r="3"/></svg>
|
|
468
|
+
View Full Diff
|
|
469
|
+
</button>
|
|
470
|
+
<button
|
|
471
|
+
class="ui-button ui-action-button ui-action-button--wide btn btn-primary git-footer-commit-btn"
|
|
472
|
+
type="button"
|
|
473
|
+
data-git-commit-staged
|
|
474
|
+
${!n||r?"disabled":""}
|
|
475
|
+
>
|
|
476
|
+
${r?"Working...":"Commit Staged"}
|
|
477
|
+
</button>
|
|
478
|
+
</div>
|
|
479
|
+
</div>
|
|
480
|
+
`:""}
|
|
481
|
+
`}renderEmpty(e){this.panel&&(this.panel.innerHTML=`<div class="git-panel-empty">${p(e)}</div>`)}render(){if(!this.panel)return;if(!this.status){this.renderEmpty("Loading git status...");return}if(!this.status.isGitRepo){this.renderEmpty("Git is unavailable for this vault.");return}let e=this.status.branch??{},t=!!e.upstream,i=this.pendingActionKey==="sync:pull",n=this.pendingActionKey==="sync:push";this.panel.innerHTML=`
|
|
226
482
|
<div class="git-branch-bar">
|
|
227
483
|
<div class="git-branch-meta">
|
|
228
484
|
<span class="git-branch-name">
|
|
229
|
-
${
|
|
230
|
-
${
|
|
485
|
+
${wn()}
|
|
486
|
+
${p(e.name||"HEAD")}
|
|
231
487
|
</span>
|
|
232
|
-
${
|
|
488
|
+
${bn(this.status.summary,e)}
|
|
233
489
|
</div>
|
|
234
490
|
<div class="git-branch-actions" role="group" aria-label="Remote sync actions">
|
|
235
491
|
<button
|
|
236
|
-
class="
|
|
492
|
+
class="ui-button ui-button--compact ui-pill-button ui-action-pill ui-action-pill--surface btn btn-secondary"
|
|
237
493
|
type="button"
|
|
238
494
|
data-git-sync-action="pull"
|
|
239
|
-
title="${
|
|
495
|
+
title="${t?"Pull remote changes (fast-forward only)":"No upstream branch configured"}"
|
|
240
496
|
aria-label="Pull branch"
|
|
241
|
-
${!
|
|
497
|
+
${!t||i?"disabled":""}
|
|
242
498
|
>
|
|
243
|
-
${
|
|
499
|
+
${i?"...":`${ht("pull")}<span>Pull</span>`}
|
|
244
500
|
</button>
|
|
245
501
|
<button
|
|
246
|
-
class="
|
|
502
|
+
class="ui-button ui-button--compact ui-pill-button ui-action-pill ui-action-pill--surface btn btn-secondary"
|
|
247
503
|
type="button"
|
|
248
504
|
data-git-sync-action="push"
|
|
249
|
-
title="${
|
|
505
|
+
title="${t?"Push local commits":"No upstream branch configured"}"
|
|
250
506
|
aria-label="Push branch"
|
|
251
|
-
${!
|
|
507
|
+
${!t||n?"disabled":""}
|
|
252
508
|
>
|
|
253
|
-
${
|
|
509
|
+
${n?"...":`${ht("push")}<span>Push</span>`}
|
|
254
510
|
</button>
|
|
255
511
|
</div>
|
|
512
|
+
${this.renderPanelModes()}
|
|
256
513
|
</div>
|
|
257
|
-
${
|
|
258
|
-
${i||'<div class="git-panel-empty">No local changes</div>'}
|
|
259
|
-
${s?`
|
|
260
|
-
<div class="git-panel-footer">
|
|
261
|
-
<div class="git-panel-footer-actions">
|
|
262
|
-
<button class="git-view-all-btn" type="button" data-git-view-all>
|
|
263
|
-
<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" aria-hidden="true"><path d="M2 12s4-8 11-8 11 8 11 8-4 8-11 8-11-8-11-8z"/><circle cx="12" cy="12" r="3"/></svg>
|
|
264
|
-
View Full Diff
|
|
265
|
-
</button>
|
|
266
|
-
<button
|
|
267
|
-
class="git-footer-commit-btn"
|
|
268
|
-
type="button"
|
|
269
|
-
data-git-commit-staged
|
|
270
|
-
${!r||a?"disabled":""}
|
|
271
|
-
>
|
|
272
|
-
${a?"Working...":"Commit Staged"}
|
|
273
|
-
</button>
|
|
274
|
-
</div>
|
|
275
|
-
</div>
|
|
276
|
-
`:""}
|
|
277
|
-
`}};var lt=class{constructor({mobileBreakpointQuery:e=window.matchMedia("(max-width: 768px)"),onMeasureEditor:t}){this.mobileBreakpointQuery=e,this.onMeasureEditor=t,this.preferredView="split",this.mobileShowsEditor=!this.isMobileViewport(),this.currentView=this.mobileShowsEditor?this.preferredView:"preview",this.editorLayout=document.getElementById("editorLayout"),this.editorPane=document.getElementById("editorPane"),this.previewPane=document.getElementById("previewPane"),this.mobileToggleButton=document.getElementById("mobileViewToggle"),this.resizer=document.getElementById("resizer"),this.viewButtons=Array.from(document.querySelectorAll(".view-btn"))}isMobileViewport(){return this.mobileBreakpointQuery.matches}initialize(){this.viewButtons.forEach(e=>{e.addEventListener("click",()=>this.setView(e.dataset.view))}),this.mobileToggleButton?.addEventListener("click",()=>this.toggleMobileView()),this.initializeResizer(),this.restorePreferredView()}reset(){this.restorePreferredView(),this.editorPane&&(this.editorPane.style.flex=""),this.previewPane&&(this.previewPane.style.flex=""),this.updateResizerValue()}restorePreferredView(){let e=this.isMobileViewport()?this.mobileShowsEditor?"split":"preview":this.preferredView;this.applyView(e),this.updateMobileToggleButton(this.mobileShowsEditor?"Preview":"Editor")}applyView(e){this.currentView=e,this.editorLayout?.setAttribute("data-view",e),this.syncViewButtons()}setView(e,{persist:t=!0}={}){e&&(t&&(this.preferredView=e),this.applyView(e),(e==="split"||e==="editor")&&this.scheduleEditorMeasure())}toggleMobileView(){this.mobileShowsEditor=!this.mobileShowsEditor,this.applyView(this.mobileShowsEditor?"split":"preview"),this.updateMobileToggleButton(this.mobileShowsEditor?"Preview":"Editor"),this.mobileShowsEditor&&this.scheduleEditorMeasure()}scheduleEditorMeasure(){this.onMeasureEditor&&setTimeout(()=>this.onMeasureEditor(),50)}updateMobileToggleButton(e){if(!this.mobileToggleButton)return;let t='<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M1 12s4-8 11-8 11 8 11 8-4 8-11 8-11-8-11-8z"/><circle cx="12" cy="12" r="3"/></svg>',i='<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><rect x="3" y="3" width="18" height="18" rx="2"/><line x1="8" y1="8" x2="16" y2="8"/><line x1="8" y1="12" x2="14" y2="12"/><line x1="8" y1="16" x2="12" y2="16"/></svg>';this.mobileToggleButton.innerHTML=`${e==="Editor"?i:t}<span class="toolbar-btn-label">${e}</span>`}syncViewButtons(){this.viewButtons.forEach(e=>{let t=e.dataset.view===this.currentView;e.classList.toggle("active",t),e.setAttribute("aria-pressed",String(t))})}updateResizerValue(){if(!this.resizer||!this.editorLayout||!this.editorPane)return;let e=this.editorLayout.offsetWidth;if(!Number.isFinite(e)||e<=0)return;let t=Math.round(this.editorPane.offsetWidth/e*100);this.resizer.setAttribute("aria-valuenow",String(Math.max(20,Math.min(80,t))))}applyEditorPaneWidth(e){if(!this.editorLayout||!this.editorPane||!this.previewPane)return;let t=this.editorLayout.offsetWidth;if(!Number.isFinite(t)||t<=0)return;let i=200,r=Math.max(i,Math.min(t-i,e))/t*100;this.editorPane.style.flex=`0 0 ${r}%`,this.previewPane.style.flex="1",this.updateResizerValue()}initializeResizer(){if(!this.resizer||!this.editorLayout||!this.editorPane||!this.previewPane)return;let e=!1,t=0,i=0;this.resizer.addEventListener("mousedown",s=>{e=!0,t=s.clientX,i=this.editorPane.offsetWidth,this.resizer.classList.add("dragging"),document.body.style.cursor="col-resize",document.body.style.userSelect="none",s.preventDefault()}),document.addEventListener("mousemove",s=>{if(!e)return;let r=s.clientX-t;this.applyEditorPaneWidth(i+r)}),document.addEventListener("mouseup",()=>{e&&(e=!1,this.resizer.classList.remove("dragging"),document.body.style.cursor="",document.body.style.userSelect="",this.scheduleEditorMeasure())}),this.resizer.addEventListener("keydown",s=>{let r=this.editorLayout.offsetWidth;if(!Number.isFinite(r)||r<=0)return;let a=Math.max(24,Math.round(r*.05));if(s.key==="ArrowLeft"){s.preventDefault(),this.applyEditorPaneWidth(this.editorPane.offsetWidth-a),this.scheduleEditorMeasure();return}if(s.key==="ArrowRight"){s.preventDefault(),this.applyEditorPaneWidth(this.editorPane.offsetWidth+a),this.scheduleEditorMeasure();return}if(s.key==="Home"){s.preventDefault(),this.applyEditorPaneWidth(r*.2),this.scheduleEditorMeasure();return}s.key==="End"&&(s.preventDefault(),this.applyEditorPaneWidth(r*.8),this.scheduleEditorMeasure())}),this.updateResizerValue()}};var ct=class{constructor({mobileBreakpointQuery:e=window.matchMedia("(max-width: 768px)"),onNavigateToHeading:t,onWillOpen:i}={}){this.outlineOpen=!1,this.activeHeadingFrame=null,this.activeHeadingId=null,this.headings=[],this.pinnedHeadingId=null,this.onNavigateToHeading=t,this.onWillOpen=i,this.panel=document.getElementById("outlinePanel"),this.navigation=document.getElementById("outlineNav"),this.previewContainer=document.getElementById("previewContainer"),this.toggleButton=document.getElementById("outlineToggle"),this.mobileBreakpointQuery=e,this.handlePreviewScroll=()=>this.scheduleActiveHeadingUpdate(),this.handleDocumentPointerDown=s=>{if(!this.outlineOpen)return;let r=s.target;r instanceof Node&&(this.panel?.contains(r)||this.toggleButton?.contains(r))||this.close()}}initialize(){this.toggleButton?.addEventListener("click",()=>this.toggle()),document.addEventListener("pointerdown",this.handleDocumentPointerDown)}toggle(){this.setOpenState(!this.outlineOpen)}close(){this.setOpenState(!1)}setOpenState(e){if(e&&!this.outlineOpen&&this.onWillOpen?.(),this.outlineOpen=e,this.panel?.classList.toggle("hidden",!this.outlineOpen),this.toggleButton?.classList.toggle("active",this.outlineOpen),this.outlineOpen){this.refresh();return}this.cleanup()}refresh(){if(!this.navigation)return;if(!this.outlineOpen){this.cleanup();return}let t=document.getElementById("previewContent")?.querySelectorAll("h1, h2, h3, h4, h5, h6")??[];if(t.length===0){this.navigation.innerHTML='<div class="outline-empty">No headings found</div>',this.cleanup();return}let i=Array.from(t).map((s,r)=>(s.id||(s.id=`heading-${r}-${s.textContent.trim().toLowerCase().replace(/[^a-z0-9]+/g,"-").replace(/^-|-$/g,"").slice(0,40)}`),{id:s.id,level:Number.parseInt(s.tagName[1],10),sourceLine:Number.parseInt(s.getAttribute("data-source-line")||"",10),text:s.textContent.trim()}));this.navigation.innerHTML=i.map(s=>`<button class="outline-item" data-level="${s.level}" data-target="${s.id}"${Number.isFinite(s.sourceLine)?` data-source-line="${s.sourceLine}"`:""} title="${s.text.replace(/"/g,""")}">${s.text}</button>`).join(""),this.navigation.querySelectorAll(".outline-item").forEach(s=>{s.addEventListener("click",()=>{let r=document.getElementById(s.dataset.target);this.pinnedHeadingId=s.dataset.target,this.notifyHeadingNavigation(r,s.dataset.target),this.scrollHeadingIntoView(r,{behavior:"auto"}),this.setActiveItem(s.dataset.target,{behavior:"auto"}),this.mobileBreakpointQuery.matches&&this.close()})}),this.observeHeadings(Array.from(t))}cleanup(){this.activeHeadingFrame&&(cancelAnimationFrame(this.activeHeadingFrame),this.activeHeadingFrame=null),this.previewContainer?.removeEventListener("scroll",this.handlePreviewScroll),this.headings=[],this.pinnedHeadingId=null}setActiveItem(e,{scrollIntoView:t=!0,behavior:i="smooth"}={}){this.activeHeadingId=e,this.navigation?.querySelectorAll(".outline-item").forEach(s=>{s.classList.toggle("active",s.dataset.target===e)}),t&&this.navigation?.querySelector(".outline-item.active")?.scrollIntoView({behavior:i,block:"nearest"})}observeHeadings(e){this.cleanup(),!(!this.previewContainer||e.length===0)&&(this.headings=e,this.previewContainer.addEventListener("scroll",this.handlePreviewScroll,{passive:!0}),this.updateActiveHeading())}scheduleActiveHeadingUpdate(){this.activeHeadingFrame||(this.activeHeadingFrame=requestAnimationFrame(()=>{this.activeHeadingFrame=null,this.updateActiveHeading()}))}updateActiveHeading(){if(!this.previewContainer||this.headings.length===0)return;let e=this.getPinnedHeading();if(e&&this.shouldKeepPinnedHeadingActive(e)){this.setActiveItem(e.id,{behavior:"auto",scrollIntoView:!0});return}this.pinnedHeadingId=null;let t=this.previewContainer.scrollTop,i=this.headings[0];for(let s of this.headings){if(this.getHeadingScrollTop(s)>t)break;i=s}this.setActiveItem(i.id,{behavior:"auto",scrollIntoView:!0})}getHeadingScrollTop(e){if(!this.previewContainer)return 0;let t=this.previewContainer.getBoundingClientRect(),i=e.getBoundingClientRect();return this.previewContainer.scrollTop+(i.top-t.top)}getPinnedHeading(){return this.pinnedHeadingId?this.headings.find(e=>e.id===this.pinnedHeadingId)??null:null}shouldKeepPinnedHeadingActive(e){if(!this.previewContainer||!e?.isConnected)return!1;let t=this.getHeadingScrollTop(e)-this.previewContainer.scrollTop,i=t+e.getBoundingClientRect().height,s=this.previewContainer.clientHeight*.45;return i>-48&&t<s}notifyHeadingNavigation(e,t){if(!e)return;let i=Number.parseInt(e.getAttribute("data-source-line")||"",10);this.onNavigateToHeading?.({headingId:t,sourceLine:Number.isFinite(i)?i:null})}scrollHeadingIntoView(e,{behavior:t="smooth"}={}){if(!e||!this.previewContainer)return;let i=this.previewContainer.getBoundingClientRect(),s=e.getBoundingClientRect(),r=this.previewContainer.scrollTop+(s.top-i.top);this.previewContainer.scrollTo({behavior:t,top:Math.max(r,0)})}};var Gi=.35,is=120,ns=12,ss=2;function ht(n){return Math.max(n.scrollHeight-n.clientHeight,0)}function rs(n){return Math.max(n,0)}function qi(n){return Math.max(n.clientHeight*Gi,ns)}function as(n){return(n?.scrollTop??0)<=ss}function os(n,e){let t=n.getBoundingClientRect();return e.getBoundingClientRect().top-t.top+n.scrollTop}function ls(n){return!n.querySelector("[data-source-line]")}function cs(n){return typeof window.requestIdleCallback=="function"?window.requestIdleCallback(n,{timeout:500}):window.setTimeout(()=>{n({didTimeout:!1,timeRemaining:()=>0})},1)}function Wi(n){if(n!==null){if(typeof window.cancelIdleCallback=="function"){window.cancelIdleCallback(n);return}window.clearTimeout(n)}}var dt=class{constructor({getEditorLineNumber:e,onEditorScrollActivityChange:t,previewContainer:i,previewElement:s,scrollEditorToLine:r}){this.getEditorLineNumber=e,this.onEditorScrollActivityChange=t,this.previewContainer=i,this.previewElement=s,this.scrollEditorToLine=r,this.editorScroller=null,this.editorScrollActive=!1,this.editorScrollIdleTimer=null,this.lockedElements=new Set,this.pendingSync=null,this.frameId=null,this.previewBlocks=null,this.previewBlocksWarmId=null,this.previewBlocksReadyCallbacks=[],this.largeDocumentMode=!1,this.lastInteractionSource="editor",this.suspendedUntil=0,this.handleEditorScroll=()=>{if(!(!this.editorScroller||this.lockedElements.has(this.editorScroller)||this.isSuspended())){if(this.lastInteractionSource="editor",this.largeDocumentMode){this.setEditorScrollActive(!0),this.scheduleEditorScrollIdle(),this.scheduleSync(this.editorScroller,this.previewContainer,{preferApproximateMapping:!0});return}this.scheduleSync(this.editorScroller,this.previewContainer)}},this.handlePreviewScroll=()=>{!this.previewContainer||this.lockedElements.has(this.previewContainer)||this.isSuspended()||(this.lastInteractionSource="preview",this.scheduleSync(this.previewContainer,this.editorScroller))}}initialize(){this.previewContainer?.addEventListener("scroll",this.handlePreviewScroll,{passive:!0})}attachEditorScroller(e){this.editorScroller!==e&&(this.editorScroller?.removeEventListener("scroll",this.handleEditorScroll),this.editorScroller=e,this.editorScroller?.addEventListener("scroll",this.handleEditorScroll,{passive:!0}))}syncPreviewToEditor(){this.lastInteractionSource="editor",this.sync(this.editorScroller,this.previewContainer)}syncEditorToPreview(){this.lastInteractionSource="preview",this.sync(this.previewContainer,this.editorScroller)}destroy(){this.previewContainer?.removeEventListener("scroll",this.handlePreviewScroll),this.editorScroller?.removeEventListener("scroll",this.handleEditorScroll),this.editorScroller=null,clearTimeout(this.editorScrollIdleTimer),this.editorScrollIdleTimer=null,this.pendingSync=null,this.previewBlocks=null,Wi(this.previewBlocksWarmId),this.previewBlocksWarmId=null,this.previewBlocksReadyCallbacks=[],this.lockedElements.clear(),this.editorScrollActive=!1,this.lastInteractionSource="editor",this.suspendedUntil=0,this.frameId&&(cancelAnimationFrame(this.frameId),this.frameId=null)}scheduleSync(e,t,{preferApproximateMapping:i=!1}={}){!e||!t||this.lockedElements.has(e)||this.isSuspended()||(this.pendingSync={preferApproximateMapping:i,source:e,target:t},!this.frameId&&(this.frameId=requestAnimationFrame(()=>{if(this.frameId=null,!this.pendingSync)return;let{preferApproximateMapping:s,source:r,target:a}=this.pendingSync;this.pendingSync=null,this.sync(r,a,{preferApproximateMapping:s})})))}invalidatePreviewBlocks(){this.previewBlocks=null,Wi(this.previewBlocksWarmId),this.previewBlocksWarmId=null,this.previewBlocksReadyCallbacks=[]}setLargeDocumentMode(e){this.largeDocumentMode=!!e,this.largeDocumentMode||(clearTimeout(this.editorScrollIdleTimer),this.editorScrollIdleTimer=null,this.setEditorScrollActive(!1))}warmPreviewBlocks({onReady:e}={}){if(typeof e=="function"&&(this.previewBlocks?e(this.previewBlocks):this.previewBlocksReadyCallbacks.push(e)),!this.largeDocumentMode){this.previewBlocks||(this.previewBlocks=this.buildPreviewBlocks()),this.flushPreviewBlocksReadyCallbacks();return}this.previewBlocks||this.previewBlocksWarmId!==null||(this.previewBlocksWarmId=cs(()=>{this.previewBlocksWarmId=null,this.previewBlocks=this.buildPreviewBlocks(),this.flushPreviewBlocksReadyCallbacks()}))}realignAfterLayoutChange(){let e=()=>{if(this.lastInteractionSource==="preview"){this.syncEditorToPreview();return}this.syncPreviewToEditor()};if(this.largeDocumentMode&&!this.previewBlocks){this.warmPreviewBlocks({onReady:()=>e()});return}e()}suspendSync(e=250){this.suspendedUntil=performance.now()+e}isSuspended(){return performance.now()<this.suspendedUntil}flushPreviewBlocksReadyCallbacks(){if(this.previewBlocksReadyCallbacks.length===0)return;this.previewBlocksReadyCallbacks.splice(0).forEach(t=>{try{t(this.previewBlocks??[])}catch(i){console.warn("[scroll-sync] Preview block callback failed:",i)}})}setEditorScrollActive(e){this.editorScrollActive!==e&&(this.editorScrollActive=e,this.onEditorScrollActivityChange?.(e))}scheduleEditorScrollIdle(){clearTimeout(this.editorScrollIdleTimer),this.editorScrollIdleTimer=setTimeout(()=>{this.editorScrollIdleTimer=null,this.setEditorScrollActive(!1),this.syncPreviewToEditor()},is)}sync(e,t,{preferApproximateMapping:i=!1}={}){if(!e||!t||this.lockedElements.has(e)||this.isSuspended())return;if(!i&&e===this.editorScroller&&t===this.previewContainer){let l=this.getPreviewScrollTopForEditorLine();if(l!==null){this.setScrollTop(t,l);return}}if(e===this.previewContainer&&t===this.editorScroller){let l=this.getEditorLineNumberForPreviewScroll();if(l!==null){this.lockedElements.add(t),this.scrollEditorToLine?.(l,Gi),requestAnimationFrame(()=>{this.lockedElements.delete(t)});return}}let s=ht(e),r=ht(t),a=s>0?e.scrollTop/s:0,o=r>0?r*a:0;this.setScrollTop(t,o)}setScrollTop(e,t){this.lockedElements.add(e),e.scrollTop=rs(t),requestAnimationFrame(()=>{this.lockedElements.delete(e)})}getPreviewScrollTopForEditorLine(){if(as(this.editorScroller))return 0;let e=this.getEditorLineNumber?.();if(!Number.isFinite(e))return null;let t=this.getPreviewBlocks();if(t.length===0||!this.previewContainer)return null;let{block:i,index:s}=this.findBlockForLine(t,e),r=this.getPreviewSpan(t,s),a=Math.max(i.end-i.start,1),o=x((e-i.start)/a,0,1),l=ht(this.previewContainer),h=qi(this.previewContainer);return x(i.top+r*o-h,0,l)}getEditorLineNumberForPreviewScroll(){if(!this.previewContainer)return null;let e=this.getPreviewBlocks();if(e.length===0)return null;let t=this.previewContainer.scrollTop+qi(this.previewContainer),{block:i,index:s}=this.findBlockForScrollTop(e,t),r=this.getPreviewSpan(e,s),a=Math.max(i.end-i.start,1),o=r>0?x((t-i.top)/r,0,1):0;return Math.round(i.start+a*o)}getPreviewBlocks(){return this.previewBlocks?this.previewBlocks:!this.previewContainer||!this.previewElement?[]:this.largeDocumentMode?[]:(this.previewBlocks=this.buildPreviewBlocks(),this.previewBlocks)}buildPreviewBlocks(){let e=Array.from(this.previewElement.querySelectorAll("[data-source-line]")).map(s=>{let r=Number.parseInt(s.getAttribute("data-source-line")||"",10),a=Number.parseInt(s.getAttribute("data-source-line-end")||"",10);return Number.isFinite(r)?{element:s,end:Number.isFinite(a)?Math.max(a,r+1):r+1,start:r,top:os(this.previewContainer,s)}:null}).filter(Boolean).sort((s,r)=>s.top-r.top||s.start-r.start||s.end-r.end),t=e.filter(s=>ls(s.element)),i=t.length>0?t:e;return i.filter((s,r)=>{let a=i[r-1];return!a||Math.abs(a.top-s.top)>1||a.start!==s.start||a.end!==s.end})}findBlockForLine(e,t){let i=null,s=-1;for(let a=0;a<e.length;a+=1){let o=e[a];if(t>=o.start&&t<o.end){if(!i){i=o,s=a;continue}let l=i.end-i.start,h=o.end-o.start;(h<l||h===l&&o.start>=i.start)&&(i=o,s=a)}}if(i)return{block:i,index:s};let r=0;for(let a=0;a<e.length&&!(e[a].start>t);a+=1)r=a;return{block:e[r],index:r}}findBlockForScrollTop(e,t){for(let s=0;s<e.length;s+=1){let r=this.getPreviewSpan(e,s)+e[s].top;if(t<r)return{block:e[s],index:s}}let i=e.length-1;return{block:e[i],index:i}}getPreviewSpan(e,t){if(!this.previewContainer)return 1;let i=e[t],s=e[t+1],r=i.element.getBoundingClientRect().height;if(!s){let a=ht(this.previewContainer);return Math.max(a-i.top+this.previewContainer.clientHeight,r,1)}return Math.max(s.top-i.top,r,1)}};var hs='<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><circle cx="12" cy="12" r="5"/><path d="M12 1v2M12 21v2M4.22 4.22l1.42 1.42M18.36 18.36l1.42 1.42M1 12h2M21 12h2M4.22 19.78l1.42-1.42M18.36 5.64l1.42-1.42"/></svg>',ds='<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M21 12.79A9 9 0 1 1 11.21 3 7 7 0 0 0 21 12.79z"/></svg>',ut=class{constructor({storageKey:e="collabmd-theme",onChange:t}){this.storageKey=e,this.onChange=t,this.currentTheme="dark"}initialize(){this.currentTheme=this.readPreferredTheme(),this.applyTheme(),document.querySelectorAll("[data-theme-toggle]").forEach(e=>{e.addEventListener("click",()=>this.toggle())})}getTheme(){return this.currentTheme}toggle(){this.currentTheme=this.currentTheme==="dark"?"light":"dark",this.persistTheme(),this.applyTheme()}readPreferredTheme(){try{let e=window.localStorage.getItem(this.storageKey);if(e==="light"||e==="dark")return e}catch{}return window.matchMedia("(prefers-color-scheme: dark)").matches?"dark":"light"}persistTheme(){try{window.localStorage.setItem(this.storageKey,this.currentTheme)}catch{}}applyTheme(){document.documentElement.setAttribute("data-theme",this.currentTheme),this.updateToggleIcons(),this.onChange?.(this.currentTheme)}updateToggleIcons(){let e=this.currentTheme==="dark"?hs:ds;document.querySelectorAll("[data-theme-toggle]").forEach(t=>{t.innerHTML=e})}};var me=class{constructor(e){this.container=e}show(e,t=3e3){if(!this.container)return;let i=document.createElement("div");i.className="toast",i.textContent=e,this.container.appendChild(i),setTimeout(()=>{i.classList.add("leaving"),i.addEventListener("animationend",()=>i.remove(),{once:!0})},t)}};var Vi=16/9,us=240,ms=720,ps=180;function fs(n){return Math.max(ps,Math.min(ms,Math.ceil(n||us)))}var mt=class{constructor({previewElement:e}){this.previewElement=e,this.embedEntries=new Map,this.overlayRoot=null}destroy(){this.embedEntries.forEach(e=>{e.hydrateFrameId&&(cancelAnimationFrame(e.hydrateFrameId),e.hydrateFrameId=null),e.wrapper?.remove(),e.placeholder=null}),this.embedEntries.clear(),this.overlayRoot?.remove(),this.overlayRoot=null}detachForCommit(){this.embedEntries.forEach(e=>{e.placeholder=null})}reconcileEmbeds(e=this.previewElement){if(this.previewElement=e,!e)return;let t=Array.from(e.querySelectorAll(".video-embed-placeholder[data-video-embed-key]")).map(r=>({filePath:r.dataset.videoEmbedSource,key:r.dataset.videoEmbedKey,label:r.dataset.videoEmbedLabel||"Embedded video",placeholder:r,source:r.dataset.videoEmbedSource||"",kind:r.dataset.videoEmbedKind||"",url:r.dataset.videoEmbedUrl||"",mimeType:r.dataset.videoEmbedMimeType||""})),{nextEntries:i,removedEntries:s}=Xe(this.embedEntries,t);s.forEach(r=>this._destroyEntry(r)),this.embedEntries=i,this.embedEntries.forEach(r=>{r.aspectRatio=r.aspectRatio||Vi,r.kind=r.placeholder?.dataset.videoEmbedKind||r.kind,r.label=r.placeholder?.dataset.videoEmbedLabel||r.label,r.mimeType=r.placeholder?.dataset.videoEmbedMimeType||r.mimeType,r.source=r.placeholder?.dataset.videoEmbedSource||r.source,r.url=r.placeholder?.dataset.videoEmbedUrl||r.url,r.wrapper||this._createEmbed(r),this._attachWrapper(r)}),this.syncLayout(),this.embedEntries.size===0&&(this.overlayRoot?.remove(),this.overlayRoot=null)}syncLayout(){this.embedEntries.forEach(e=>{e.wrapper&&this._syncEntryLayout(e)})}_destroyEntry(e){e.hydrateFrameId&&(cancelAnimationFrame(e.hydrateFrameId),e.hydrateFrameId=null),e.wrapper?.remove(),e.placeholder=null}_createEmbed(e){let t=document.createElement("div");if(t.className=`video-embed video-embed-shell diagram-preview-shell is-${e.kind}`,e.kind==="youtube"){let i=document.createElement("div");i.className="video-embed-frame video-embed-frame-youtube";let s=document.createElement("iframe");s.className="video-embed-iframe",s.title=e.label||"Embedded YouTube video",s.referrerPolicy="strict-origin-when-cross-origin",s.allow="accelerometer; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share",s.allowFullscreen=!0,i.appendChild(s),t.appendChild(i),e.mediaElement=s}else{let i=document.createElement("video");i.className="video-embed-player",i.controls=!0,i.preload="metadata",i.playsInline=!0,e.label&&(i.title=e.label,i.setAttribute("aria-label",e.label));let s=document.createElement("source");s.src=e.url,e.mimeType&&(s.type=e.mimeType),i.appendChild(s),i.addEventListener("loadedmetadata",()=>{Number.isFinite(i.videoWidth)&&Number.isFinite(i.videoHeight)&&i.videoWidth>0&&i.videoHeight>0&&(e.aspectRatio=i.videoWidth/i.videoHeight,this._syncEntryLayout(e))}),t.appendChild(i),e.mediaElement=i}e.wrapper=t}_attachWrapper(e){let t=e.placeholder?.isConnected?e.placeholder:this.previewElement?.querySelector(`.video-embed-placeholder[data-video-embed-key="${e.key}"]`);if(!t)return;e.placeholder=t,t.classList.add("is-hydrated"),t.dataset.videoEmbedHydrated="true",t.style.pointerEvents="none";let i=this._ensureOverlayRoot();e.wrapper?.parentElement!==i&&i.appendChild(e.wrapper)}_syncEntryLayout(e){let t=e.placeholder?.isConnected?e.placeholder:this.previewElement?.querySelector(`.video-embed-placeholder[data-video-embed-key="${e.key}"]`);if(!t||!e.wrapper)return;e.placeholder=t;let i=t.offsetWidth||t.clientWidth||0;if(i<=0&&e.inlineHeightPx)return;let s=fs(i>0?i/(e.aspectRatio||Vi):e.inlineHeightPx);e.inlineHeightPx=s,Q(t,"height",`${s}px`),Q(e.wrapper,"position","absolute"),Q(e.wrapper,"top",`${t.offsetTop}px`),Q(e.wrapper,"left",`${t.offsetLeft}px`),Q(e.wrapper,"width",`${t.offsetWidth}px`),Q(e.wrapper,"height",`${s}px`),Q(e.wrapper,"margin","0"),Q(e.wrapper,"pointerEvents","auto"),this._hydrateEntryMedia(e)}_ensureOverlayRoot(){let e=this.previewElement?.querySelector('[data-video-overlay-root="true"]');return e||(e=document.createElement("div"),e.dataset.videoOverlayRoot="true",e.className="video-embed-overlay-root",this.previewElement?.appendChild(e)),this.overlayRoot=e,e}_hydrateEntryMedia(e){if(e.kind!=="youtube")return;let t=e.mediaElement;t instanceof HTMLIFrameElement&&(!e.url||t.getAttribute("src")===e.url||e.wrapper?.offsetWidth<=0||e.wrapper?.offsetHeight<=0||e.hydrateFrameId||(e.hydrateFrameId=requestAnimationFrame(()=>{if(e.hydrateFrameId=null,!e.url||t.getAttribute("src")===e.url)return;let i=Math.round(e.wrapper?.offsetWidth||0),s=Math.round(e.wrapper?.offsetHeight||0);i<=0||s<=0||(t.width=String(i),t.height=String(s),t.src=e.url)})))}};function Q(n,e,t){!n||n.style[e]===t||(n.style[e]=t)}function gs(n){let e=Number(n);return Number.isFinite(e)?Math.min(6,Math.max(1,Math.round(e*100)/100)):1}function Ki(n,{contentSize:e=0,scale:t=1,viewportSize:i=0}={}){let s=Number(n),r=Number(e),a=Number(t),o=Number(i);if(!Number.isFinite(s)||!Number.isFinite(r)||!Number.isFinite(a)||!Number.isFinite(o))return 0;let l=(r*a-o)/2;return l<=0?0:Math.min(Math.max(s,-l),l)}var pt=class{constructor({previewElement:e,documentRef:t=document,windowRef:i=window}){this.previewElement=e,this.document=t,this.window=i,this.overlayRoot=null,this.viewport=null,this.imageElement=null,this.zoomLabel=null,this.titleElement=null,this.isOpen=!1,this.scale=1,this.offsetX=0,this.offsetY=0,this.activePointerId=null,this.dragStartX=0,this.dragStartY=0,this.dragOriginX=0,this.dragOriginY=0,this.didDrag=!1,this.resetButton=null,this.handlePreviewClick=s=>{let r=s.target;if(!(r instanceof this.window.Element))return;let a=r.closest("img");!a||!this.previewElement?.contains(a)||a.closest('[data-video-overlay-root="true"], [data-excalidraw-overlay-root="true"]')||(s.preventDefault(),s.stopImmediatePropagation?.(),this.openFromImage(a))},this.handleKeyDown=s=>{if(this.isOpen){if(s.key==="Escape"){s.preventDefault(),this.close();return}if(s.key==="+"||s.key==="="){s.preventDefault(),this.zoomBy(.25);return}if(s.key==="-"){s.preventDefault(),this.zoomBy(-.25);return}s.key==="0"&&(s.preventDefault(),this.resetView())}},this.handleWindowResize=()=>{this.isOpen&&(this.clampOffsets(),this.syncTransform())},this.previewElement?.addEventListener("click",this.handlePreviewClick),this.document.addEventListener("keydown",this.handleKeyDown),this.window.addEventListener("resize",this.handleWindowResize)}destroy(){this.previewElement?.removeEventListener("click",this.handlePreviewClick),this.document.removeEventListener("keydown",this.handleKeyDown),this.window.removeEventListener("resize",this.handleWindowResize),this.close(),this.overlayRoot?.remove(),this.overlayRoot=null,this.viewport=null,this.imageElement=null,this.zoomLabel=null,this.titleElement=null,this.resetButton=null}openFromImage(e){let t=e?.currentSrc||e?.getAttribute?.("src")||"";return t?(this.ensureOverlayRoot(),this.resetView(),this.titleElement.textContent=e.getAttribute("alt")||"Image preview",this.imageElement.src=t,this.imageElement.alt=e.getAttribute("alt")||"",this.overlayRoot.hidden=!1,this.isOpen=!0,this.document.body.classList.add("image-lightbox-open"),this.syncTransform(),this.overlayRoot.focus?.(),!0):!1}close(){!this.isOpen&&!this.overlayRoot||(this.activePointerId=null,this.didDrag=!1,this.viewport?.classList?.remove("is-dragging"),this.overlayRoot&&(this.overlayRoot.hidden=!0),this.isOpen=!1,this.document.body.classList.remove("image-lightbox-open"))}resetView(){this.scale=1,this.offsetX=0,this.offsetY=0,this.syncTransform()}zoomBy(e){this.setScale(this.scale+e)}setScale(e){this.scale=gs(e),this.clampOffsets(),this.syncTransform()}clampOffsets(){if(!this.viewport||!this.imageElement){this.offsetX=0,this.offsetY=0;return}this.offsetX=Ki(this.offsetX,{contentSize:this.imageElement.offsetWidth||0,scale:this.scale,viewportSize:this.viewport.clientWidth||0}),this.offsetY=Ki(this.offsetY,{contentSize:this.imageElement.offsetHeight||0,scale:this.scale,viewportSize:this.viewport.clientHeight||0})}syncTransform(){this.imageElement&&(this.imageElement.style.transform=`translate3d(${this.offsetX}px, ${this.offsetY}px, 0) scale(${this.scale})`,this.imageElement.style.cursor=this.scale>1?"grab":"zoom-in",this.zoomLabel&&(this.zoomLabel.textContent=`${Math.round(this.scale*100)}%`),this.resetButton&&(this.resetButton.disabled=this.scale<=1&&this.offsetX===0&&this.offsetY===0))}ensureOverlayRoot(){if(this.overlayRoot?.isConnected&&this.overlayRoot.parentElement===this.document.body)return this.overlayRoot;let e=this.document.createElement("div");e.className="image-lightbox-root",e.dataset.imageLightboxRoot="true",e.hidden=!0,e.tabIndex=-1;let t=this.document.createElement("button");t.className="image-lightbox-backdrop",t.type="button",t.setAttribute("aria-label","Close image preview"),t.addEventListener("click",d=>{d.preventDefault(),d.stopPropagation(),this.close()});let i=this.document.createElement("div");i.className="image-lightbox-shell",i.setAttribute("role","dialog"),i.setAttribute("aria-modal","true"),i.setAttribute("aria-label","Image preview"),i.addEventListener("click",d=>d.stopPropagation()),i.addEventListener("pointerdown",d=>d.stopPropagation());let s=this.document.createElement("div");s.className="image-lightbox-toolbar";let r=this.document.createElement("div");r.className="image-lightbox-title",r.textContent="Image preview";let a=this.document.createElement("div");a.className="image-lightbox-controls";let o=this.document.createElement("span");o.className="image-lightbox-zoom-label",o.textContent="100%";let l=this.createControlButton("Reset","Reset zoom and position",()=>this.resetView()),h=this.createControlButton("Close","Close image preview",()=>this.close());a.append(o,l,h),s.append(r,a);let c=this.document.createElement("div");c.className="image-lightbox-viewport";let u=this.document.createElement("img");u.className="image-lightbox-image",u.alt="",u.addEventListener("load",()=>{this.clampOffsets(),this.syncTransform()}),c.addEventListener("wheel",d=>{this.isOpen&&(d.preventDefault(),this.zoomBy(d.deltaY<0?.25:-.25))},{passive:!1}),c.addEventListener("pointerdown",d=>{!this.isOpen||this.scale<=1||d.button!==0||(this.activePointerId=d.pointerId,this.dragStartX=d.clientX,this.dragStartY=d.clientY,this.dragOriginX=this.offsetX,this.dragOriginY=this.offsetY,this.didDrag=!1,c.classList.add("is-dragging"),c.setPointerCapture?.(d.pointerId),d.preventDefault())}),c.addEventListener("pointermove",d=>{!this.isOpen||this.activePointerId!==d.pointerId||(!this.didDrag&&(Math.abs(d.clientX-this.dragStartX)>=6||Math.abs(d.clientY-this.dragStartY)>=6)&&(this.didDrag=!0),this.offsetX=this.dragOriginX+(d.clientX-this.dragStartX),this.offsetY=this.dragOriginY+(d.clientY-this.dragStartY),this.clampOffsets(),this.syncTransform())});let p=d=>{this.activePointerId===d.pointerId&&(this.activePointerId=null,c.classList.remove("is-dragging"),c.releasePointerCapture?.(d.pointerId),this.imageElement.style.cursor=this.scale>1?"grab":"zoom-in")};return c.addEventListener("pointerup",p),c.addEventListener("pointercancel",p),u.addEventListener("click",d=>{if(this.isOpen){if(d.preventDefault(),d.stopPropagation(),this.didDrag){this.didDrag=!1;return}this.scale<=1&&this.setScale(2)}}),c.appendChild(u),i.append(s,c),e.append(t,i),this.document.body.appendChild(e),this.overlayRoot=e,this.viewport=c,this.imageElement=u,this.zoomLabel=o,this.titleElement=r,this.resetButton=l,this.syncTransform(),e}createControlButton(e,t,i,{className:s=""}={}){let r=this.document.createElement("button");return r.className=`image-lightbox-btn ${s}`.trim(),r.type="button",r.setAttribute("aria-label",t),r.textContent=e,r.addEventListener("click",a=>{a.preventDefault(),a.stopPropagation(),i(a)}),r}};var ws=Object.freeze({chat:hi,comments:di,git:mi,presence:pi,ui:fi,workspace:gi});function ys(n){let e={};Object.entries(ws).forEach(([t,i])=>{Object.entries(i).forEach(([s,r])=>{if(typeof r=="function"){if(Object.hasOwn(e,s))throw new Error(`CollabMdAppShell feature method "${s}" is declared by both "${e[s]}" and "${t}".`);if(s in n)throw new Error(`CollabMdAppShell feature method "${s}" conflicts with an existing app shell member.`);Object.defineProperty(n,s,{configurable:!0,enumerable:!1,value:r.bind(n),writable:!1}),e[s]=t}})}),Object.defineProperty(n,"featureMethodOwners",{configurable:!1,enumerable:!1,value:Object.freeze(e),writable:!1})}var ft=class{constructor(){ys(this),this.elements=ci(document),this.runtimeConfig=Se(),this.stateStore=new _e,this.navigation=new Ue,this.preferences=new Oe({chatNotificationsKey:"collabmd-chat-notifications-enabled",lineWrappingKey:"collabmd-editor-line-wrap",sidebarVisibleKey:"collabmd-sidebar-visible",userNameKey:"collabmd-user-name"}),this.notifications=new $e,this.vaultApiClient=he,this._session=null,this._hasPromptedForDisplayName=!1,this._backlinkRefreshTimer=null,this._pendingPreviewLayoutSync=!1,this._previewHydrationPaused=!1,this._previewLayoutResizeObserver=null,this._previewLayoutSyncTimer=null,this.pendingGitResetPath=null,this.chatTimeFormatter=new Intl.DateTimeFormat(void 0,{hour:"numeric",minute:"2-digit"}),this.chatNotificationsEnabled=this.preferences.getChatNotificationsEnabled(),this.chatNotificationPermission=this.notifications.getPermission(),this.lobbyChatMessageMaxLength=Lt,this.quickSwitcher=null,this.quickSwitcherModulePromise=null,this.fileExplorerReadyPromise=Promise.resolve(),this.mobileBreakpointQuery=window.matchMedia("(max-width: 768px)"),this.pendingWorkspaceRequestIds=new Set,this.lobby=new ze({preferredUserName:this.getStoredUserName(),onChange:e=>this.updateGlobalUsers(e),onChatChange:(e,t)=>this.updateChatMessages(e,t)}),this.workspaceSync=new Ve({onTreeChange:(e,t={})=>{let i=this.fileExplorerReady;this.fileExplorer.setTree(e,t),this.fileExplorerReady=!0,!i&&this.isTabActive&&this.handleHashChange()},onWorkspaceEvent:e=>{this.handleIncomingWorkspaceEvent(e)}}),this.toastController=new me(this.elements.toastContainer),this.chatToastController=new me(this.elements.chatToastContainer),this.fileExplorer=new st({onFileDelete:()=>this.navigation.navigateToFile(null),onFileSelect:e=>this.handleFileSelection(e,{closeSidebarOnMobile:!0}),toastController:this.toastController}),this.gitPanel=new ot({enabled:this.runtimeConfig.gitEnabled!==!1,onCommitStaged:()=>this.openGitCommitDialog(),onOpenPullBackup:e=>e&&this.navigation.navigateToFile(e),onPullBranch:()=>this.pullGitBranch(),onPushBranch:()=>this.pushGitBranch(),onRepoChange:(e,t)=>this.handleGitRepoChange(e,t),onResetFile:(e,{scope:t})=>this.openGitResetDialog(e,{scope:t}),onSelectDiff:(e,{scope:t})=>this.handleGitDiffSelection(e,{closeSidebarOnMobile:!0,scope:t}),onStageFile:(e,{scope:t})=>this.stageGitFile(e,{scope:t}),onUnstageFile:(e,{scope:t})=>this.unstageGitFile(e,{scope:t}),onViewAllDiff:()=>this.handleGitDiffSelection(null,{closeSidebarOnMobile:!0,scope:"all"}),searchInput:this.elements.gitSearchInput,toastController:this.toastController}),this.outlineController=new ct({mobileBreakpointQuery:this.mobileBreakpointQuery,onNavigateToHeading:({sourceLine:e})=>{Number.isFinite(e)&&(this.scrollSyncController.suspendSync(250),this.session?.scrollToLine(e,0))},onWillOpen:()=>this.commentUi?.closeDrawer()}),this.videoEmbed=new mt({previewElement:this.elements.previewContent}),this.imageLightbox=new pt({previewElement:this.elements.previewContent}),this.previewRenderer=new Te({getContent:()=>this.getPreviewSource(),getFileList:()=>this.fileExplorer.flatDocumentFiles,getSourceFilePath:()=>this.currentFilePath,onAfterRenderCommit:(e,t)=>{this.videoEmbed.reconcileEmbeds(this.elements.previewContent),this.videoEmbed.syncLayout(),this.excalidrawEmbed.reconcileEmbeds(this.elements.previewContent,{isLargeDocument:t.isLargeDocument}),this.excalidrawEmbed.syncLayout(),this.scrollSyncController.setLargeDocumentMode(t.isLargeDocument),this.schedulePreviewLayoutSync({delayMs:0}),this.refreshCommentUiLayout()},onBeforeRenderCommit:()=>{this.videoEmbed.detachForCommit(),this.excalidrawEmbed.detachForCommit()},onRenderComplete:()=>{this.videoEmbed.syncLayout(),this.excalidrawEmbed.syncLayout(),this.schedulePreviewLayoutSync({delayMs:0}),this.refreshCommentUiLayout()},outlineController:this.outlineController,previewContainer:this.elements.previewContainer,previewElement:this.elements.previewContent}),this.themeController=new ut({onChange:e=>this.handleThemeChange(e)}),this.layoutController=new lt({mobileBreakpointQuery:this.mobileBreakpointQuery,onMeasureEditor:()=>this.session?.requestMeasure()}),this.scrollSyncController=new dt({getEditorLineNumber:()=>this.session?.getTopVisibleLineNumber(.35)??1,onEditorScrollActivityChange:e=>this.handleEditorScrollActivityChange(e),previewContainer:this.elements.previewContainer,previewElement:this.elements.previewContent,scrollEditorToLine:(e,t)=>this.session?.scrollToLine(e,t)}),this.backlinksPanel=new Ke({inlinePanelElement:this.elements.backlinksInlinePanel,onFileSelect:e=>this.handleFileSelection(e,{closeSidebarOnMobile:!0}),panelElement:this.elements.backlinksPanel}),this.excalidrawEmbed=new et({getLocalUser:()=>this.lobby.getLocalUser(),getTheme:()=>this.themeController.getTheme(),onOpenFile:e=>e&&this.navigation.navigateToFile(e),previewContainer:this.elements.previewContainer,previewElement:this.elements.previewContent,toastController:this.toastController}),this.commentUi=new Ze({commentSelectionButton:this.elements.commentSelectionButton,commentsDrawer:this.elements.commentsDrawer,commentsDrawerEmpty:this.elements.commentsDrawerEmpty,commentsDrawerList:this.elements.commentsDrawerList,commentsToggleButton:this.elements.commentsToggleButton,editorContainer:this.elements.editorContainer,onWillOpenDrawer:()=>this.outlineController.close(),previewContainer:this.elements.previewContainer,previewElement:this.elements.previewContent,onCreateThread:({anchor:e,body:t})=>this.session?.createCommentThread({anchor:e,body:t}),onNavigateToLine:e=>{this.scrollSyncController.suspendSync(250),this.session?.scrollToLine(e,.2)},onReplyToThread:(e,t)=>this.session?.replyToCommentThread(e,t),onToggleReaction:(e,t,i)=>this.session?.toggleCommentReaction(e,t,i),onResolveThread:e=>this.session?.deleteCommentThread(e)}),this.workspacePreviewController=new Be({backlinksPanel:this.backlinksPanel,elements:this.elements,excalidrawEmbed:this.excalidrawEmbed,getDisplayName:e=>this.getDisplayName(e),getSession:()=>this.session,isExcalidrawFile:e=>this.isExcalidrawFile(e),isImageFile:e=>this.isImageFile(e),isMermaidFile:e=>this.isMermaidFile(e),isPlantUmlFile:e=>this.isPlantUmlFile(e),layoutController:this.layoutController,outlineController:this.outlineController,previewRenderer:this.previewRenderer,schedulePreviewLayoutSync:e=>this.schedulePreviewLayoutSync(e),scrollSyncController:this.scrollSyncController,videoEmbed:this.videoEmbed}),this.wikiLinkFileController=new Re({getFileList:()=>this.fileExplorer.flatDocumentFiles,navigation:this.navigation,refreshExplorer:()=>this.fileExplorer.refresh(),toastController:this.toastController,vaultApiClient:this.vaultApiClient}),this.gitDiffView=new rt({onCommitStaged:()=>this.openGitCommitDialog(),onOpenFile:e=>e&&this.navigation.navigateToFile(e),onStageFile:(e,{scope:t})=>this.stageGitFile(e,{scope:t}),onUnstageFile:(e,{scope:t})=>this.unstageGitFile(e,{scope:t}),toastController:this.toastController}),this.tabActivityLock=new We({onActivated:({takeover:e})=>this.handleTabActivated({takeover:e}),onBlocked:()=>this.handleTabBlocked({reason:"active-elsewhere"}),onStolen:()=>this.handleTabBlocked({reason:"taken-over"})}),this.workspaceCoordinator=new He({attachEditorScroller:e=>this.scrollSyncController.attachEditorScroller(e),beginDocumentLoad:()=>this.previewRenderer.beginDocumentLoad(),cleanupAfterSessionDestroy:()=>{this.scrollSyncController.setLargeDocumentMode(!1),this.scrollSyncController.invalidatePreviewBlocks(),this.outlineController.cleanup(),this.followedCursorSignature="",clearTimeout(this._backlinkRefreshTimer)},createEditorSession:(e,t)=>new e({editorContainer:this.elements.editorContainer,getFileList:t.getFileList,initialTheme:t.theme,lineInfoElement:this.elements.lineInfo,lineWrappingEnabled:t.lineWrappingEnabled,localUser:t.localUser,onImagePaste:t.onImagePaste,onAwarenessChange:t.onAwarenessChange,onCommentsChange:t.onCommentsChange,onConnectionChange:t.onConnectionChange,onContentChange:t.onContentChange,onSelectionChange:t.onSelectionChange,preferredUserName:t.preferredUserName}),getDisplayName:e=>this.getDisplayName(e),getFileList:()=>this.fileExplorer.flatDocumentFiles,getLineWrappingEnabled:()=>this.getStoredLineWrapping(),getLocalUser:()=>this.lobby.getLocalUser(),getStoredUserName:()=>this.getStoredUserName(),getTheme:()=>this.themeController.getTheme(),isExcalidrawFile:e=>this.isExcalidrawFile(e),isImageFile:e=>this.isImageFile(e),isMermaidFile:e=>this.isMermaidFile(e),isPlantUmlFile:e=>this.isPlantUmlFile(e),isTabActive:()=>this.isTabActive,loadEditorSessionClass:()=>this.loadEditorSessionClass(),loadBacklinks:e=>this.backlinksPanel.load(e),onBeforeFileOpen:()=>{this.session=null,this.commentUi.attachSession(null),this.layoutController.reset(),this.resetPreviewMode(),this.elements.emptyState?.classList.add("hidden"),this.elements.editorPage?.classList.remove("hidden"),this.elements.diffPage?.classList.add("hidden"),this.clearInitialFileBootstrap()},onConnectionChange:e=>this.handleConnectionChange(e),onContentChange:({isMermaid:e,isPlantUml:t})=>{this.handleCommentEditorContentChange(),this.previewRenderer.queueRender(),!e&&!t&&this.scheduleBacklinkRefresh()},onCommentsChange:e=>this.handleCommentThreadsChange(e),onFileAwarenessChange:e=>this.updateFileAwareness(e),onFileOpenError:()=>{this.showEditorLoadError(),this.syncWrapToggle(),this.toastController.show("Failed to initialize editor")},onFileOpenReady:()=>{this.hideEditorLoading()},onSelectionChange:e=>this.handleCommentSelectionChange(e),onImagePaste:e=>this.handleEditorImageInsert(e),onSessionAssigned:e=>{this.session=e,this.commentUi.attachSession(e)},onRenderExcalidrawPreview:e=>this.renderExcalidrawFilePreview(e),onRenderImagePreview:e=>this.renderImageFilePreview(e),onSyncWrapToggle:()=>this.syncWrapToggle(),onUpdateActiveFile:e=>this.fileExplorer.setActiveFile(e),onUpdateCurrentFile:e=>{this.currentFilePath=e},onUpdateLobbyCurrentFile:e=>this.lobby.setCurrentFile(e),onUpdateVisibleChrome:(e,{displayName:t})=>{this.syncFileChrome(e),this.syncCommentChrome(e),this.elements.activeFileName&&(this.elements.activeFileName.textContent=t)},onViewModeReset:()=>this.resetPreviewMode(),renderPresence:()=>this.renderPresence(),scrollContainerForSession:e=>e.getScrollContainer(),showEditorLoading:()=>this.showEditorLoading(),stateStore:this.stateStore}),this.workspaceRouteController=new Ae({backlinksPanel:this.backlinksPanel,clearInitialFileBootstrap:()=>this.clearInitialFileBootstrap(),closeSidebarOnMobile:()=>this.closeSidebarOnMobile(),elements:this.elements,excalidrawEmbed:this.excalidrawEmbed,fileExplorer:this.fileExplorer,getIsTabActive:()=>this.isTabActive,getSessionLoadToken:()=>this.sessionLoadToken,gitDiffView:this.gitDiffView,gitPanel:this.gitPanel,imageLightbox:this.imageLightbox,layoutController:this.layoutController,lobby:this.lobby,navigation:this.navigation,previewRenderer:this.previewRenderer,renderAvatars:()=>this.renderAvatars(),renderPresence:()=>this.renderPresence(),resetPreviewMode:()=>this.resetPreviewMode(),scrollSyncController:this.scrollSyncController,setCurrentFilePath:e=>{this.currentFilePath=e,e||(this.commentUi.setCurrentFile(null,{supported:!1}),this.handleCommentThreadsChange([]),this.handleCommentSelectionChange(null))},setSession:e=>{this.session=e,this.commentUi.attachSession(e)},setSessionLoadToken:e=>{this.sessionLoadToken=e},setSidebarTab:e=>this.setSidebarTab(e),showGitDiff:e=>this.showGitDiff(e),syncMainChrome:e=>this.syncMainChrome(e),videoEmbed:this.videoEmbed,workspaceCoordinator:this.workspaceCoordinator}),this.chatNotificationPermission!=="granted"&&(this.chatNotificationsEnabled=!1)}get session(){return this._session}set session(e){this._session=e}get currentFilePath(){return this.stateStore.get("currentFilePath")}set currentFilePath(e){this.stateStore.set("currentFilePath",e)}get globalUsers(){return this.stateStore.get("globalUsers")}set globalUsers(e){this.stateStore.set("globalUsers",e)}get connectionState(){return this.stateStore.get("connectionState")}set connectionState(e){this.stateStore.set("connectionState",e)}get sessionLoadToken(){return this.stateStore.get("sessionLoadToken")}set sessionLoadToken(e){this.stateStore.set("sessionLoadToken",e)}get connectionHelpShown(){return this.stateStore.get("connectionHelpShown")}set connectionHelpShown(e){this.stateStore.set("connectionHelpShown",e)}get chatMessages(){return this.stateStore.get("chatMessages")}set chatMessages(e){this.stateStore.set("chatMessages",e)}get chatMessageIds(){return this.stateStore.get("chatMessageIds")}set chatMessageIds(e){this.stateStore.set("chatMessageIds",e)}get chatUnreadCount(){return this.stateStore.get("chatUnreadCount")}set chatUnreadCount(e){this.stateStore.set("chatUnreadCount",e)}get chatIsOpen(){return this.stateStore.get("chatIsOpen")}set chatIsOpen(e){this.stateStore.set("chatIsOpen",e)}get chatInitialSyncComplete(){return this.stateStore.get("chatInitialSyncComplete")}set chatInitialSyncComplete(e){this.stateStore.set("chatInitialSyncComplete",e)}get isTabActive(){return this.stateStore.get("isTabActive")}set isTabActive(e){this.stateStore.set("isTabActive",e)}get fileExplorerReady(){return this.stateStore.get("fileExplorerReady")}set fileExplorerReady(e){this.stateStore.set("fileExplorerReady",e)}get gitRepoAvailable(){return this.stateStore.get("gitRepoAvailable")}set gitRepoAvailable(e){this.stateStore.set("gitRepoAvailable",e)}get activeSidebarTab(){return this.stateStore.get("activeSidebarTab")}set activeSidebarTab(e){this.stateStore.set("activeSidebarTab",e)}get followedUserClientId(){return this.stateStore.get("followedUserClientId")}set followedUserClientId(e){this.stateStore.set("followedUserClientId",e)}get followedCursorSignature(){return this.stateStore.get("followedCursorSignature")}set followedCursorSignature(e){this.stateStore.set("followedCursorSignature",e)}loadEditorSessionClass(){return this._editorSessionModulePromise||(this._editorSessionModulePromise=import("./chunks/editor-session-EAUBJCHH.js").then(e=>e.EditorSession)),this._editorSessionModulePromise}scheduleEditorSessionPrewarm({timeout:e=1500}={}){if(this._editorSessionModulePromise||this._editorSessionPrewarmHandle)return;let t=()=>{this._editorSessionPrewarmHandle=null,this.loadEditorSessionClass()};if(typeof window.requestIdleCallback=="function"){this._editorSessionPrewarmHandle=window.requestIdleCallback(t,{timeout:e});return}this._editorSessionPrewarmHandle=window.setTimeout(t,0)}async ensureQuickSwitcher(){if(this.quickSwitcher)return this.quickSwitcher;this.quickSwitcherModulePromise||(this.quickSwitcherModulePromise=import("./chunks/quick-switcher-controller-A6SKH5HI.js").then(t=>t.QuickSwitcherController));let e=await this.quickSwitcherModulePromise;return this.quickSwitcher||(this.quickSwitcher=new e({getFileList:()=>this.fileExplorer.flatFiles,onFileSelect:t=>this.handleFileSelection(t,{closeSidebarOnMobile:!0})})),this.quickSwitcher}async toggleQuickSwitcher(){(await this.ensureQuickSwitcher()).toggle()}};var vs={enabled:!1,implemented:!0,passwordLabel:"Password",requiresLogin:!1,sessionEndpoint:"/api/auth/session",statusEndpoint:"/api/auth/status",strategy:"none",submitLabel:"Continue"},ji=!1;function bs(){if(ji||!document.head)return;let n=document.createElement("style");n.textContent=`
|
|
514
|
+
${this.panelMode==="history"?this.renderHistoryPanel():this.renderChangesPanel()}
|
|
515
|
+
`}};var ut=class{constructor({mobileBreakpointQuery:e=window.matchMedia("(max-width: 768px)"),onMeasureEditor:t}){this.mobileBreakpointQuery=e,this.onMeasureEditor=t,this.preferredView="split",this.mobileShowsEditor=!this.isMobileViewport(),this.currentView=this.mobileShowsEditor?this.preferredView:"preview",this.editorLayout=document.getElementById("editorLayout"),this.editorPane=document.getElementById("editorPane"),this.previewPane=document.getElementById("previewPane"),this.mobileToggleButton=document.getElementById("mobileViewToggle"),this.resizer=document.getElementById("resizer"),this.viewButtons=Array.from(document.querySelectorAll(".view-btn"))}isMobileViewport(){return this.mobileBreakpointQuery.matches}initialize(){this.viewButtons.forEach(e=>{e.addEventListener("click",()=>this.setView(e.dataset.view))}),this.mobileToggleButton?.addEventListener("click",()=>this.toggleMobileView()),this.initializeResizer(),this.restorePreferredView()}reset(){this.restorePreferredView(),this.editorPane&&(this.editorPane.style.flex=""),this.previewPane&&(this.previewPane.style.flex=""),this.updateResizerValue()}restorePreferredView(){let e=this.isMobileViewport()?this.mobileShowsEditor?"split":"preview":this.preferredView;this.applyView(e),this.updateMobileToggleButton(this.mobileShowsEditor?"Preview":"Editor")}applyView(e){this.currentView=e,this.editorLayout?.setAttribute("data-view",e),this.syncViewButtons()}setView(e,{persist:t=!0}={}){e&&(t&&(this.preferredView=e),this.applyView(e),(e==="split"||e==="editor")&&this.scheduleEditorMeasure())}toggleMobileView(){this.mobileShowsEditor=!this.mobileShowsEditor,this.applyView(this.mobileShowsEditor?"split":"preview"),this.updateMobileToggleButton(this.mobileShowsEditor?"Preview":"Editor"),this.mobileShowsEditor&&this.scheduleEditorMeasure()}scheduleEditorMeasure(){this.onMeasureEditor&&setTimeout(()=>this.onMeasureEditor(),50)}updateMobileToggleButton(e){if(!this.mobileToggleButton)return;let t='<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M1 12s4-8 11-8 11 8 11 8-4 8-11 8-11-8-11-8z"/><circle cx="12" cy="12" r="3"/></svg>',i='<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><rect x="3" y="3" width="18" height="18" rx="2"/><line x1="8" y1="8" x2="16" y2="8"/><line x1="8" y1="12" x2="14" y2="12"/><line x1="8" y1="16" x2="12" y2="16"/></svg>';this.mobileToggleButton.innerHTML=`${e==="Editor"?i:t}<span class="ui-toolbar-button-label">${e}</span>`}syncViewButtons(){this.viewButtons.forEach(e=>{let t=e.dataset.view===this.currentView;e.classList.toggle("active",t),e.setAttribute("aria-pressed",String(t))})}updateResizerValue(){if(!this.resizer||!this.editorLayout||!this.editorPane)return;let e=this.editorLayout.offsetWidth;if(!Number.isFinite(e)||e<=0)return;let t=Math.round(this.editorPane.offsetWidth/e*100);this.resizer.setAttribute("aria-valuenow",String(Math.max(20,Math.min(80,t))))}applyEditorPaneWidth(e){if(!this.editorLayout||!this.editorPane||!this.previewPane)return;let t=this.editorLayout.offsetWidth;if(!Number.isFinite(t)||t<=0)return;let i=200,r=Math.max(i,Math.min(t-i,e))/t*100;this.editorPane.style.flex=`0 0 ${r}%`,this.previewPane.style.flex="1",this.updateResizerValue()}initializeResizer(){if(!this.resizer||!this.editorLayout||!this.editorPane||!this.previewPane)return;let e=!1,t=0,i=0;this.resizer.addEventListener("mousedown",n=>{e=!0,t=n.clientX,i=this.editorPane.offsetWidth,this.resizer.classList.add("dragging"),document.body.style.cursor="col-resize",document.body.style.userSelect="none",n.preventDefault()}),document.addEventListener("mousemove",n=>{if(!e)return;let r=n.clientX-t;this.applyEditorPaneWidth(i+r)}),document.addEventListener("mouseup",()=>{e&&(e=!1,this.resizer.classList.remove("dragging"),document.body.style.cursor="",document.body.style.userSelect="",this.scheduleEditorMeasure())}),this.resizer.addEventListener("keydown",n=>{let r=this.editorLayout.offsetWidth;if(!Number.isFinite(r)||r<=0)return;let o=Math.max(24,Math.round(r*.05));if(n.key==="ArrowLeft"){n.preventDefault(),this.applyEditorPaneWidth(this.editorPane.offsetWidth-o),this.scheduleEditorMeasure();return}if(n.key==="ArrowRight"){n.preventDefault(),this.applyEditorPaneWidth(this.editorPane.offsetWidth+o),this.scheduleEditorMeasure();return}if(n.key==="Home"){n.preventDefault(),this.applyEditorPaneWidth(r*.2),this.scheduleEditorMeasure();return}n.key==="End"&&(n.preventDefault(),this.applyEditorPaneWidth(r*.8),this.scheduleEditorMeasure())}),this.updateResizerValue()}};var mt=class{constructor({mobileBreakpointQuery:e=window.matchMedia("(max-width: 768px)"),onNavigateToHeading:t,onWillOpen:i}={}){this.outlineOpen=!1,this.activeHeadingFrame=null,this.activeHeadingId=null,this.headings=[],this.pinnedHeadingId=null,this.onNavigateToHeading=t,this.onWillOpen=i,this.panel=document.getElementById("outlinePanel"),this.navigation=document.getElementById("outlineNav"),this.previewContainer=document.getElementById("previewContainer"),this.toggleButton=document.getElementById("outlineToggle"),this.mobileBreakpointQuery=e,this.handlePreviewScroll=()=>this.scheduleActiveHeadingUpdate(),this.handleDocumentPointerDown=n=>{if(!this.outlineOpen)return;let r=n.target;r instanceof Node&&(this.panel?.contains(r)||this.toggleButton?.contains(r))||this.close()}}initialize(){this.toggleButton?.addEventListener("click",()=>this.toggle()),document.addEventListener("pointerdown",this.handleDocumentPointerDown)}toggle(){this.setOpenState(!this.outlineOpen)}close(){this.setOpenState(!1)}setOpenState(e){if(e&&!this.outlineOpen&&this.onWillOpen?.(),this.outlineOpen=e,this.panel?.classList.toggle("hidden",!this.outlineOpen),this.toggleButton?.classList.toggle("active",this.outlineOpen),this.outlineOpen){this.refresh();return}this.cleanup()}refresh(){if(!this.navigation)return;if(!this.outlineOpen){this.cleanup();return}let t=document.getElementById("previewContent")?.querySelectorAll("h1, h2, h3, h4, h5, h6")??[];if(t.length===0){this.navigation.innerHTML='<div class="outline-empty">No headings found</div>',this.cleanup();return}let i=Array.from(t).map((n,r)=>(n.id||(n.id=`heading-${r}-${n.textContent.trim().toLowerCase().replace(/[^a-z0-9]+/g,"-").replace(/^-|-$/g,"").slice(0,40)}`),{id:n.id,level:Number.parseInt(n.tagName[1],10),sourceLine:Number.parseInt(n.getAttribute("data-source-line")||"",10),text:n.textContent.trim()}));this.navigation.innerHTML=i.map(n=>`<button class="outline-item" data-level="${n.level}" data-target="${n.id}"${Number.isFinite(n.sourceLine)?` data-source-line="${n.sourceLine}"`:""} title="${n.text.replace(/"/g,""")}">${n.text}</button>`).join(""),this.navigation.querySelectorAll(".outline-item").forEach(n=>{n.addEventListener("click",()=>{let r=document.getElementById(n.dataset.target);this.pinnedHeadingId=n.dataset.target,this.notifyHeadingNavigation(r,n.dataset.target),this.scrollHeadingIntoView(r,{behavior:"auto"}),this.setActiveItem(n.dataset.target,{behavior:"auto"}),this.mobileBreakpointQuery.matches&&this.close()})}),this.observeHeadings(Array.from(t))}cleanup(){this.activeHeadingFrame&&(cancelAnimationFrame(this.activeHeadingFrame),this.activeHeadingFrame=null),this.previewContainer?.removeEventListener("scroll",this.handlePreviewScroll),this.headings=[],this.pinnedHeadingId=null}setActiveItem(e,{scrollIntoView:t=!0,behavior:i="smooth"}={}){this.activeHeadingId=e,this.navigation?.querySelectorAll(".outline-item").forEach(n=>{n.classList.toggle("active",n.dataset.target===e)}),t&&this.navigation?.querySelector(".outline-item.active")?.scrollIntoView({behavior:i,block:"nearest"})}observeHeadings(e){this.cleanup(),!(!this.previewContainer||e.length===0)&&(this.headings=e,this.previewContainer.addEventListener("scroll",this.handlePreviewScroll,{passive:!0}),this.updateActiveHeading())}scheduleActiveHeadingUpdate(){this.activeHeadingFrame||(this.activeHeadingFrame=requestAnimationFrame(()=>{this.activeHeadingFrame=null,this.updateActiveHeading()}))}updateActiveHeading(){if(!this.previewContainer||this.headings.length===0)return;let e=this.getPinnedHeading();if(e&&this.shouldKeepPinnedHeadingActive(e)){this.setActiveItem(e.id,{behavior:"auto",scrollIntoView:!0});return}this.pinnedHeadingId=null;let t=this.previewContainer.scrollTop,i=this.headings[0];for(let n of this.headings){if(this.getHeadingScrollTop(n)>t)break;i=n}this.setActiveItem(i.id,{behavior:"auto",scrollIntoView:!0})}getHeadingScrollTop(e){if(!this.previewContainer)return 0;let t=this.previewContainer.getBoundingClientRect(),i=e.getBoundingClientRect();return this.previewContainer.scrollTop+(i.top-t.top)}getPinnedHeading(){return this.pinnedHeadingId?this.headings.find(e=>e.id===this.pinnedHeadingId)??null:null}shouldKeepPinnedHeadingActive(e){if(!this.previewContainer||!e?.isConnected)return!1;let t=this.getHeadingScrollTop(e)-this.previewContainer.scrollTop,i=t+e.getBoundingClientRect().height,n=this.previewContainer.clientHeight*.45;return i>-48&&t<n}notifyHeadingNavigation(e,t){if(!e)return;let i=Number.parseInt(e.getAttribute("data-source-line")||"",10);this.onNavigateToHeading?.({headingId:t,sourceLine:Number.isFinite(i)?i:null})}scrollHeadingIntoView(e,{behavior:t="smooth"}={}){if(!e||!this.previewContainer)return;let i=this.previewContainer.getBoundingClientRect(),n=e.getBoundingClientRect(),r=this.previewContainer.scrollTop+(n.top-i.top);this.previewContainer.scrollTo({behavior:t,top:Math.max(r,0)})}};var ns=.35,En=120,Sn=12,Pn=2;function pt(s){return Math.max(s.scrollHeight-s.clientHeight,0)}function kn(s){return Math.max(s,0)}function is(s){return Math.max(s.clientHeight*ns,Sn)}function Ln(s){return(s?.scrollTop??0)<=Pn}function Fn(s,e){let t=s.getBoundingClientRect();return e.getBoundingClientRect().top-t.top+s.scrollTop}function xn(s){return!s.querySelector("[data-source-line]")}function Mn(s){return typeof window.requestIdleCallback=="function"?window.requestIdleCallback(s,{timeout:500}):window.setTimeout(()=>{s({didTimeout:!1,timeRemaining:()=>0})},1)}function ss(s){if(s!==null){if(typeof window.cancelIdleCallback=="function"){window.cancelIdleCallback(s);return}window.clearTimeout(s)}}var ft=class{constructor({getEditorLineNumber:e,onEditorScrollActivityChange:t,previewContainer:i,previewElement:n,scrollEditorToLine:r}){this.getEditorLineNumber=e,this.onEditorScrollActivityChange=t,this.previewContainer=i,this.previewElement=n,this.scrollEditorToLine=r,this.editorScroller=null,this.editorScrollActive=!1,this.editorScrollIdleTimer=null,this.lockedElements=new Set,this.pendingSync=null,this.frameId=null,this.previewBlocks=null,this.previewBlocksWarmId=null,this.previewBlocksReadyCallbacks=[],this.largeDocumentMode=!1,this.lastInteractionSource="editor",this.suspendedUntil=0,this.handleEditorScroll=()=>{if(!(!this.editorScroller||this.lockedElements.has(this.editorScroller)||this.isSuspended())){if(this.lastInteractionSource="editor",this.largeDocumentMode){this.setEditorScrollActive(!0),this.scheduleEditorScrollIdle(),this.scheduleSync(this.editorScroller,this.previewContainer,{preferApproximateMapping:!0});return}this.scheduleSync(this.editorScroller,this.previewContainer)}},this.handlePreviewScroll=()=>{!this.previewContainer||this.lockedElements.has(this.previewContainer)||this.isSuspended()||(this.lastInteractionSource="preview",this.scheduleSync(this.previewContainer,this.editorScroller))}}initialize(){this.previewContainer?.addEventListener("scroll",this.handlePreviewScroll,{passive:!0})}attachEditorScroller(e){this.editorScroller!==e&&(this.editorScroller?.removeEventListener("scroll",this.handleEditorScroll),this.editorScroller=e,this.editorScroller?.addEventListener("scroll",this.handleEditorScroll,{passive:!0}))}syncPreviewToEditor(){this.lastInteractionSource="editor",this.sync(this.editorScroller,this.previewContainer)}syncEditorToPreview(){this.lastInteractionSource="preview",this.sync(this.previewContainer,this.editorScroller)}destroy(){this.previewContainer?.removeEventListener("scroll",this.handlePreviewScroll),this.editorScroller?.removeEventListener("scroll",this.handleEditorScroll),this.editorScroller=null,clearTimeout(this.editorScrollIdleTimer),this.editorScrollIdleTimer=null,this.pendingSync=null,this.previewBlocks=null,ss(this.previewBlocksWarmId),this.previewBlocksWarmId=null,this.previewBlocksReadyCallbacks=[],this.lockedElements.clear(),this.editorScrollActive=!1,this.lastInteractionSource="editor",this.suspendedUntil=0,this.frameId&&(cancelAnimationFrame(this.frameId),this.frameId=null)}scheduleSync(e,t,{preferApproximateMapping:i=!1}={}){!e||!t||this.lockedElements.has(e)||this.isSuspended()||(this.pendingSync={preferApproximateMapping:i,source:e,target:t},!this.frameId&&(this.frameId=requestAnimationFrame(()=>{if(this.frameId=null,!this.pendingSync)return;let{preferApproximateMapping:n,source:r,target:o}=this.pendingSync;this.pendingSync=null,this.sync(r,o,{preferApproximateMapping:n})})))}invalidatePreviewBlocks(){this.previewBlocks=null,ss(this.previewBlocksWarmId),this.previewBlocksWarmId=null,this.previewBlocksReadyCallbacks=[]}setLargeDocumentMode(e){this.largeDocumentMode=!!e,this.largeDocumentMode||(clearTimeout(this.editorScrollIdleTimer),this.editorScrollIdleTimer=null,this.setEditorScrollActive(!1))}warmPreviewBlocks({onReady:e}={}){if(typeof e=="function"&&(this.previewBlocks?e(this.previewBlocks):this.previewBlocksReadyCallbacks.push(e)),!this.largeDocumentMode){this.previewBlocks||(this.previewBlocks=this.buildPreviewBlocks()),this.flushPreviewBlocksReadyCallbacks();return}this.previewBlocks||this.previewBlocksWarmId!==null||(this.previewBlocksWarmId=Mn(()=>{this.previewBlocksWarmId=null,this.previewBlocks=this.buildPreviewBlocks(),this.flushPreviewBlocksReadyCallbacks()}))}realignAfterLayoutChange(){let e=()=>{if(this.lastInteractionSource==="preview"){this.syncEditorToPreview();return}this.syncPreviewToEditor()};if(this.largeDocumentMode&&!this.previewBlocks){this.warmPreviewBlocks({onReady:()=>e()});return}e()}suspendSync(e=250){this.suspendedUntil=performance.now()+e}isSuspended(){return performance.now()<this.suspendedUntil}flushPreviewBlocksReadyCallbacks(){if(this.previewBlocksReadyCallbacks.length===0)return;this.previewBlocksReadyCallbacks.splice(0).forEach(t=>{try{t(this.previewBlocks??[])}catch(i){console.warn("[scroll-sync] Preview block callback failed:",i)}})}setEditorScrollActive(e){this.editorScrollActive!==e&&(this.editorScrollActive=e,this.onEditorScrollActivityChange?.(e))}scheduleEditorScrollIdle(){clearTimeout(this.editorScrollIdleTimer),this.editorScrollIdleTimer=setTimeout(()=>{this.editorScrollIdleTimer=null,this.setEditorScrollActive(!1),this.syncPreviewToEditor()},En)}sync(e,t,{preferApproximateMapping:i=!1}={}){if(!e||!t||this.lockedElements.has(e)||this.isSuspended())return;if(!i&&e===this.editorScroller&&t===this.previewContainer){let c=this.getPreviewScrollTopForEditorLine();if(c!==null){this.setScrollTop(t,c);return}}if(e===this.previewContainer&&t===this.editorScroller){let c=this.getEditorLineNumberForPreviewScroll();if(c!==null){this.lockedElements.add(t),this.scrollEditorToLine?.(c,ns),requestAnimationFrame(()=>{this.lockedElements.delete(t)});return}}let n=pt(e),r=pt(t),o=n>0?e.scrollTop/n:0,a=r>0?r*o:0;this.setScrollTop(t,a)}setScrollTop(e,t){this.lockedElements.add(e),e.scrollTop=kn(t),requestAnimationFrame(()=>{this.lockedElements.delete(e)})}getPreviewScrollTopForEditorLine(){if(Ln(this.editorScroller))return 0;let e=this.getEditorLineNumber?.();if(!Number.isFinite(e))return null;let t=this.getPreviewBlocks();if(t.length===0||!this.previewContainer)return null;let{block:i,index:n}=this.findBlockForLine(t,e),r=this.getPreviewSpan(t,n),o=Math.max(i.end-i.start,1),a=T((e-i.start)/o,0,1),c=pt(this.previewContainer),h=is(this.previewContainer);return T(i.top+r*a-h,0,c)}getEditorLineNumberForPreviewScroll(){if(!this.previewContainer)return null;let e=this.getPreviewBlocks();if(e.length===0)return null;let t=this.previewContainer.scrollTop+is(this.previewContainer),{block:i,index:n}=this.findBlockForScrollTop(e,t),r=this.getPreviewSpan(e,n),o=Math.max(i.end-i.start,1),a=r>0?T((t-i.top)/r,0,1):0;return Math.round(i.start+o*a)}getPreviewBlocks(){return this.previewBlocks?this.previewBlocks:!this.previewContainer||!this.previewElement?[]:this.largeDocumentMode?[]:(this.previewBlocks=this.buildPreviewBlocks(),this.previewBlocks)}buildPreviewBlocks(){let e=Array.from(this.previewElement.querySelectorAll("[data-source-line]")).map(n=>{let r=Number.parseInt(n.getAttribute("data-source-line")||"",10),o=Number.parseInt(n.getAttribute("data-source-line-end")||"",10);return Number.isFinite(r)?{element:n,end:Number.isFinite(o)?Math.max(o,r+1):r+1,start:r,top:Fn(this.previewContainer,n)}:null}).filter(Boolean).sort((n,r)=>n.top-r.top||n.start-r.start||n.end-r.end),t=e.filter(n=>xn(n.element)),i=t.length>0?t:e;return i.filter((n,r)=>{let o=i[r-1];return!o||Math.abs(o.top-n.top)>1||o.start!==n.start||o.end!==n.end})}findBlockForLine(e,t){let i=null,n=-1;for(let o=0;o<e.length;o+=1){let a=e[o];if(t>=a.start&&t<a.end){if(!i){i=a,n=o;continue}let c=i.end-i.start,h=a.end-a.start;(h<c||h===c&&a.start>=i.start)&&(i=a,n=o)}}if(i)return{block:i,index:n};let r=0;for(let o=0;o<e.length&&!(e[o].start>t);o+=1)r=o;return{block:e[r],index:r}}findBlockForScrollTop(e,t){for(let n=0;n<e.length;n+=1){let r=this.getPreviewSpan(e,n)+e[n].top;if(t<r)return{block:e[n],index:n}}let i=e.length-1;return{block:e[i],index:i}}getPreviewSpan(e,t){if(!this.previewContainer)return 1;let i=e[t],n=e[t+1],r=i.element.getBoundingClientRect().height;if(!n){let o=pt(this.previewContainer);return Math.max(o-i.top+this.previewContainer.clientHeight,r,1)}return Math.max(n.top-i.top,r,1)}};var Tn='<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><circle cx="12" cy="12" r="5"/><path d="M12 1v2M12 21v2M4.22 4.22l1.42 1.42M18.36 18.36l1.42 1.42M1 12h2M21 12h2M4.22 19.78l1.42-1.42M18.36 5.64l1.42-1.42"/></svg>',In='<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M21 12.79A9 9 0 1 1 11.21 3 7 7 0 0 0 21 12.79z"/></svg>',gt=class{constructor({storageKey:e="collabmd-theme",onChange:t}){this.storageKey=e,this.onChange=t,this.currentTheme="dark"}initialize(){this.currentTheme=this.readPreferredTheme(),this.applyTheme(),document.querySelectorAll("[data-theme-toggle]").forEach(e=>{e.addEventListener("click",()=>this.toggle())})}getTheme(){return this.currentTheme}toggle(){this.currentTheme=this.currentTheme==="dark"?"light":"dark",this.persistTheme(),this.applyTheme()}readPreferredTheme(){try{let e=window.localStorage.getItem(this.storageKey);if(e==="light"||e==="dark")return e}catch{}return window.matchMedia("(prefers-color-scheme: dark)").matches?"dark":"light"}persistTheme(){try{window.localStorage.setItem(this.storageKey,this.currentTheme)}catch{}}applyTheme(){document.documentElement.setAttribute("data-theme",this.currentTheme),this.updateToggleIcons(),this.onChange?.(this.currentTheme)}updateToggleIcons(){let e=this.currentTheme==="dark"?Tn:In;document.querySelectorAll("[data-theme-toggle]").forEach(t=>{t.innerHTML=e})}};var ge=class{constructor(e){this.container=e}show(e,t=3e3){if(!this.container)return;let i=document.createElement("div");i.className="toast",i.textContent=e,this.container.appendChild(i),setTimeout(()=>{i.classList.add("leaving"),i.addEventListener("animationend",()=>i.remove(),{once:!0})},t)}};var rs=16/9,An=240,Bn=720,Rn=180;function Hn(s){return Math.max(Rn,Math.min(Bn,Math.ceil(s||An)))}var yt=class{constructor({previewElement:e}){this.previewElement=e,this.embedEntries=new Map,this.overlayRoot=null}destroy(){this.embedEntries.forEach(e=>{e.hydrateFrameId&&(cancelAnimationFrame(e.hydrateFrameId),e.hydrateFrameId=null),e.wrapper?.remove(),e.placeholder=null}),this.embedEntries.clear(),this.overlayRoot?.remove(),this.overlayRoot=null}detachForCommit(){this.embedEntries.forEach(e=>{e.placeholder=null})}reconcileEmbeds(e=this.previewElement){if(this.previewElement=e,!e)return;let t=Array.from(e.querySelectorAll(".video-embed-placeholder[data-video-embed-key]")).map(r=>({filePath:r.dataset.videoEmbedSource,key:r.dataset.videoEmbedKey,label:r.dataset.videoEmbedLabel||"Embedded video",placeholder:r,source:r.dataset.videoEmbedSource||"",kind:r.dataset.videoEmbedKind||"",url:r.dataset.videoEmbedUrl||"",mimeType:r.dataset.videoEmbedMimeType||""})),{nextEntries:i,removedEntries:n}=tt(this.embedEntries,t);n.forEach(r=>this._destroyEntry(r)),this.embedEntries=i,this.embedEntries.forEach(r=>{r.aspectRatio=r.aspectRatio||rs,r.kind=r.placeholder?.dataset.videoEmbedKind||r.kind,r.label=r.placeholder?.dataset.videoEmbedLabel||r.label,r.mimeType=r.placeholder?.dataset.videoEmbedMimeType||r.mimeType,r.source=r.placeholder?.dataset.videoEmbedSource||r.source,r.url=r.placeholder?.dataset.videoEmbedUrl||r.url,r.wrapper||this._createEmbed(r),this._attachWrapper(r)}),this.syncLayout(),this.embedEntries.size===0&&(this.overlayRoot?.remove(),this.overlayRoot=null)}syncLayout(){this.embedEntries.forEach(e=>{e.wrapper&&this._syncEntryLayout(e)})}_destroyEntry(e){e.hydrateFrameId&&(cancelAnimationFrame(e.hydrateFrameId),e.hydrateFrameId=null),e.wrapper?.remove(),e.placeholder=null}_createEmbed(e){let t=document.createElement("div");if(t.className=`video-embed video-embed-shell diagram-preview-shell is-${e.kind}`,e.kind==="youtube"){let i=document.createElement("div");i.className="video-embed-frame video-embed-frame-youtube";let n=document.createElement("iframe");n.className="video-embed-iframe",n.title=e.label||"Embedded YouTube video",n.referrerPolicy="strict-origin-when-cross-origin",n.allow="accelerometer; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share",n.allowFullscreen=!0,i.appendChild(n),t.appendChild(i),e.mediaElement=n}else{let i=document.createElement("video");i.className="video-embed-player",i.controls=!0,i.preload="metadata",i.playsInline=!0,e.label&&(i.title=e.label,i.setAttribute("aria-label",e.label));let n=document.createElement("source");n.src=e.url,e.mimeType&&(n.type=e.mimeType),i.appendChild(n),i.addEventListener("loadedmetadata",()=>{Number.isFinite(i.videoWidth)&&Number.isFinite(i.videoHeight)&&i.videoWidth>0&&i.videoHeight>0&&(e.aspectRatio=i.videoWidth/i.videoHeight,this._syncEntryLayout(e))}),t.appendChild(i),e.mediaElement=i}e.wrapper=t}_attachWrapper(e){let t=e.placeholder?.isConnected?e.placeholder:this.previewElement?.querySelector(`.video-embed-placeholder[data-video-embed-key="${e.key}"]`);if(!t)return;e.placeholder=t,t.classList.add("is-hydrated"),t.dataset.videoEmbedHydrated="true",t.style.pointerEvents="none";let i=this._ensureOverlayRoot();e.wrapper?.parentElement!==i&&i.appendChild(e.wrapper)}_syncEntryLayout(e){let t=e.placeholder?.isConnected?e.placeholder:this.previewElement?.querySelector(`.video-embed-placeholder[data-video-embed-key="${e.key}"]`);if(!t||!e.wrapper)return;e.placeholder=t;let i=t.offsetWidth||t.clientWidth||0;if(i<=0&&e.inlineHeightPx)return;let n=Hn(i>0?i/(e.aspectRatio||rs):e.inlineHeightPx);e.inlineHeightPx=n,Z(t,"height",`${n}px`),Z(e.wrapper,"position","absolute"),Z(e.wrapper,"top",`${t.offsetTop}px`),Z(e.wrapper,"left",`${t.offsetLeft}px`),Z(e.wrapper,"width",`${t.offsetWidth}px`),Z(e.wrapper,"height",`${n}px`),Z(e.wrapper,"margin","0"),Z(e.wrapper,"pointerEvents","auto"),this._hydrateEntryMedia(e)}_ensureOverlayRoot(){let e=this.previewElement?.querySelector('[data-video-overlay-root="true"]');return e||(e=document.createElement("div"),e.dataset.videoOverlayRoot="true",e.className="video-embed-overlay-root",this.previewElement?.appendChild(e)),this.overlayRoot=e,e}_hydrateEntryMedia(e){if(e.kind!=="youtube")return;let t=e.mediaElement;t instanceof HTMLIFrameElement&&(!e.url||t.getAttribute("src")===e.url||e.wrapper?.offsetWidth<=0||e.wrapper?.offsetHeight<=0||e.hydrateFrameId||(e.hydrateFrameId=requestAnimationFrame(()=>{if(e.hydrateFrameId=null,!e.url||t.getAttribute("src")===e.url)return;let i=Math.round(e.wrapper?.offsetWidth||0),n=Math.round(e.wrapper?.offsetHeight||0);i<=0||n<=0||(t.width=String(i),t.height=String(n),t.src=e.url)})))}};function Z(s,e,t){!s||s.style[e]===t||(s.style[e]=t)}function Nn(s){let e=Number(s);return Number.isFinite(e)?Math.min(6,Math.max(1,Math.round(e*100)/100)):1}function os(s,{contentSize:e=0,scale:t=1,viewportSize:i=0}={}){let n=Number(s),r=Number(e),o=Number(t),a=Number(i);if(!Number.isFinite(n)||!Number.isFinite(r)||!Number.isFinite(o)||!Number.isFinite(a))return 0;let c=(r*o-a)/2;return c<=0?0:Math.min(Math.max(n,-c),c)}var wt=class{constructor({previewElement:e,documentRef:t=document,windowRef:i=window}){this.previewElement=e,this.document=t,this.window=i,this.overlayRoot=null,this.viewport=null,this.imageElement=null,this.zoomLabel=null,this.titleElement=null,this.isOpen=!1,this.scale=1,this.offsetX=0,this.offsetY=0,this.activePointerId=null,this.dragStartX=0,this.dragStartY=0,this.dragOriginX=0,this.dragOriginY=0,this.didDrag=!1,this.resetButton=null,this.handlePreviewClick=n=>{let r=n.target;if(!(r instanceof this.window.Element))return;let o=r.closest("img");!o||!this.previewElement?.contains(o)||o.closest('[data-video-overlay-root="true"], [data-excalidraw-overlay-root="true"]')||(n.preventDefault(),n.stopImmediatePropagation?.(),this.openFromImage(o))},this.handleKeyDown=n=>{if(this.isOpen){if(n.key==="Escape"){n.preventDefault(),this.close();return}if(n.key==="+"||n.key==="="){n.preventDefault(),this.zoomBy(.25);return}if(n.key==="-"){n.preventDefault(),this.zoomBy(-.25);return}n.key==="0"&&(n.preventDefault(),this.resetView())}},this.handleWindowResize=()=>{this.isOpen&&(this.clampOffsets(),this.syncTransform())},this.previewElement?.addEventListener("click",this.handlePreviewClick),this.document.addEventListener("keydown",this.handleKeyDown),this.window.addEventListener("resize",this.handleWindowResize)}destroy(){this.previewElement?.removeEventListener("click",this.handlePreviewClick),this.document.removeEventListener("keydown",this.handleKeyDown),this.window.removeEventListener("resize",this.handleWindowResize),this.close(),this.overlayRoot?.remove(),this.overlayRoot=null,this.viewport=null,this.imageElement=null,this.zoomLabel=null,this.titleElement=null,this.resetButton=null}openFromImage(e){let t=e?.currentSrc||e?.getAttribute?.("src")||"";return t?(this.ensureOverlayRoot(),this.resetView(),this.titleElement.textContent=e.getAttribute("alt")||"Image preview",this.imageElement.src=t,this.imageElement.alt=e.getAttribute("alt")||"",this.overlayRoot.hidden=!1,this.isOpen=!0,this.document.body.classList.add("image-lightbox-open"),this.syncTransform(),this.overlayRoot.focus?.(),!0):!1}close(){!this.isOpen&&!this.overlayRoot||(this.activePointerId=null,this.didDrag=!1,this.viewport?.classList?.remove("is-dragging"),this.overlayRoot&&(this.overlayRoot.hidden=!0),this.isOpen=!1,this.document.body.classList.remove("image-lightbox-open"))}resetView(){this.scale=1,this.offsetX=0,this.offsetY=0,this.syncTransform()}zoomBy(e){this.setScale(this.scale+e)}setScale(e){this.scale=Nn(e),this.clampOffsets(),this.syncTransform()}clampOffsets(){if(!this.viewport||!this.imageElement){this.offsetX=0,this.offsetY=0;return}this.offsetX=os(this.offsetX,{contentSize:this.imageElement.offsetWidth||0,scale:this.scale,viewportSize:this.viewport.clientWidth||0}),this.offsetY=os(this.offsetY,{contentSize:this.imageElement.offsetHeight||0,scale:this.scale,viewportSize:this.viewport.clientHeight||0})}syncTransform(){this.imageElement&&(this.imageElement.style.transform=`translate3d(${this.offsetX}px, ${this.offsetY}px, 0) scale(${this.scale})`,this.imageElement.style.cursor=this.scale>1?"grab":"zoom-in",this.zoomLabel&&(this.zoomLabel.textContent=`${Math.round(this.scale*100)}%`),this.resetButton&&(this.resetButton.disabled=this.scale<=1&&this.offsetX===0&&this.offsetY===0))}ensureOverlayRoot(){if(this.overlayRoot?.isConnected&&this.overlayRoot.parentElement===this.document.body)return this.overlayRoot;let e=this.document.createElement("div");e.className="image-lightbox-root",e.dataset.imageLightboxRoot="true",e.hidden=!0,e.tabIndex=-1;let t=this.document.createElement("button");t.className="image-lightbox-backdrop",t.type="button",t.setAttribute("aria-label","Close image preview"),t.addEventListener("click",d=>{d.preventDefault(),d.stopPropagation(),this.close()});let i=this.document.createElement("div");i.className="image-lightbox-shell",i.setAttribute("role","dialog"),i.setAttribute("aria-modal","true"),i.setAttribute("aria-label","Image preview"),i.addEventListener("click",d=>d.stopPropagation()),i.addEventListener("pointerdown",d=>d.stopPropagation());let n=this.document.createElement("div");n.className="image-lightbox-toolbar";let r=this.document.createElement("div");r.className="image-lightbox-title",r.textContent="Image preview";let o=this.document.createElement("div");o.className="image-lightbox-controls";let a=this.document.createElement("span");a.className="image-lightbox-zoom-label",a.textContent="100%";let c=this.createControlButton("Reset","Reset zoom and position",()=>this.resetView()),h=this.createControlButton("Close","Close image preview",()=>this.close());o.append(a,c,h),n.append(r,o);let l=this.document.createElement("div");l.className="image-lightbox-viewport";let u=this.document.createElement("img");u.className="image-lightbox-image",u.alt="",u.addEventListener("load",()=>{this.clampOffsets(),this.syncTransform()}),l.addEventListener("wheel",d=>{this.isOpen&&(d.preventDefault(),this.zoomBy(d.deltaY<0?.25:-.25))},{passive:!1}),l.addEventListener("pointerdown",d=>{!this.isOpen||this.scale<=1||d.button!==0||(this.activePointerId=d.pointerId,this.dragStartX=d.clientX,this.dragStartY=d.clientY,this.dragOriginX=this.offsetX,this.dragOriginY=this.offsetY,this.didDrag=!1,l.classList.add("is-dragging"),l.setPointerCapture?.(d.pointerId),d.preventDefault())}),l.addEventListener("pointermove",d=>{!this.isOpen||this.activePointerId!==d.pointerId||(!this.didDrag&&(Math.abs(d.clientX-this.dragStartX)>=6||Math.abs(d.clientY-this.dragStartY)>=6)&&(this.didDrag=!0),this.offsetX=this.dragOriginX+(d.clientX-this.dragStartX),this.offsetY=this.dragOriginY+(d.clientY-this.dragStartY),this.clampOffsets(),this.syncTransform())});let m=d=>{this.activePointerId===d.pointerId&&(this.activePointerId=null,l.classList.remove("is-dragging"),l.releasePointerCapture?.(d.pointerId),this.imageElement.style.cursor=this.scale>1?"grab":"zoom-in")};return l.addEventListener("pointerup",m),l.addEventListener("pointercancel",m),u.addEventListener("click",d=>{if(this.isOpen){if(d.preventDefault(),d.stopPropagation(),this.didDrag){this.didDrag=!1;return}this.scale<=1&&this.setScale(2)}}),l.appendChild(u),i.append(n,l),e.append(t,i),this.document.body.appendChild(e),this.overlayRoot=e,this.viewport=l,this.imageElement=u,this.zoomLabel=a,this.titleElement=r,this.resetButton=c,this.syncTransform(),e}createControlButton(e,t,i,{className:n=""}={}){let r=this.document.createElement("button");return r.className=`image-lightbox-btn ${n}`.trim(),r.type="button",r.setAttribute("aria-label",t),r.textContent=e,r.addEventListener("click",o=>{o.preventDefault(),o.stopPropagation(),i(o)}),r}};var Dn=Object.freeze({chat:vi,comments:bi,git:Ei,presence:Si,ui:Pi,workspace:ki});function _n(s){let e={};Object.entries(Dn).forEach(([t,i])=>{Object.entries(i).forEach(([n,r])=>{if(typeof r=="function"){if(Object.hasOwn(e,n))throw new Error(`CollabMdAppShell feature method "${n}" is declared by both "${e[n]}" and "${t}".`);if(n in s)throw new Error(`CollabMdAppShell feature method "${n}" conflicts with an existing app shell member.`);Object.defineProperty(s,n,{configurable:!0,enumerable:!1,value:r.bind(s),writable:!1}),e[n]=t}})}),Object.defineProperty(s,"featureMethodOwners",{configurable:!1,enumerable:!1,value:Object.freeze(e),writable:!1})}var vt=class{constructor(){_n(this),this.elements=wi(document),this.runtimeConfig=Le(),this.stateStore=new ze,this.navigation=new qe,this.preferences=new Ge({chatNotificationsKey:"collabmd-chat-notifications-enabled",lineWrappingKey:"collabmd-editor-line-wrap",sidebarVisibleKey:"collabmd-sidebar-visible",userNameKey:"collabmd-user-name"}),this.notifications=new We,this.vaultApiClient=ue,this._session=null,this._hasPromptedForDisplayName=!1,this._backlinkRefreshTimer=null,this._pendingPreviewLayoutSync=!1,this._previewHydrationPaused=!1,this._previewLayoutResizeObserver=null,this._previewLayoutSyncTimer=null,this._staticPreviewDocument=null,this.pendingGitResetPath=null,this.chatTimeFormatter=new Intl.DateTimeFormat(void 0,{hour:"numeric",minute:"2-digit"}),this.chatNotificationsEnabled=this.preferences.getChatNotificationsEnabled(),this.chatNotificationPermission=this.notifications.getPermission(),this.lobbyChatMessageMaxLength=Mt,this.quickSwitcher=null,this.quickSwitcherModulePromise=null,this.fileExplorerReadyPromise=Promise.resolve(),this.mobileBreakpointQuery=window.matchMedia("(max-width: 768px)"),this.pendingWorkspaceRequestIds=new Set,this._fileOpenPerf=null,this.lobby=new Ue({preferredUserName:this.getStoredUserName(),onChange:e=>this.updateGlobalUsers(e),onChatChange:(e,t)=>this.updateChatMessages(e,t)}),this.workspaceSync=new Qe({onTreeChange:(e,t={})=>{let i=this.fileExplorerReady;this.fileExplorer.setTree(e,t),this.fileExplorerReady=!0,!i&&this.isTabActive&&this.handleHashChange()},onWorkspaceEvent:e=>{this.handleIncomingWorkspaceEvent(e)}}),this.toastController=new ge(this.elements.toastContainer),this.chatToastController=new ge(this.elements.chatToastContainer),this.fileExplorer=new at({onFileDelete:()=>this.navigation.navigateToFile(null),onFileSelect:e=>this.handleFileSelection(e,{closeSidebarOnMobile:!0}),toastController:this.toastController}),this.gitPanel=new dt({enabled:this.runtimeConfig.gitEnabled!==!1,onCommitStaged:()=>this.openGitCommitDialog(),onOpenPullBackup:e=>e&&this.navigation.navigateToFile(e),onPullBranch:()=>this.pullGitBranch(),onPushBranch:()=>this.pushGitBranch(),onRepoChange:(e,t)=>this.handleGitRepoChange(e,t),onResetFile:(e,{scope:t})=>this.openGitResetDialog(e,{scope:t}),onSelectCommit:(e,{path:t})=>this.handleGitCommitSelection(e,{closeSidebarOnMobile:!0,path:t}),onSelectDiff:(e,{scope:t})=>this.handleGitDiffSelection(e,{closeSidebarOnMobile:!0,scope:t}),onStageFile:(e,{scope:t})=>this.stageGitFile(e,{scope:t}),onUnstageFile:(e,{scope:t})=>this.unstageGitFile(e,{scope:t}),onViewAllDiff:()=>this.handleGitDiffSelection(null,{closeSidebarOnMobile:!0,scope:"all"}),searchInput:this.elements.gitSearchInput,toastController:this.toastController}),this.outlineController=new mt({mobileBreakpointQuery:this.mobileBreakpointQuery,onNavigateToHeading:({sourceLine:e})=>{Number.isFinite(e)&&(this.scrollSyncController.suspendSync(250),this.session?.scrollToLine(e,0))},onWillOpen:()=>this.commentUi?.closeDrawer()}),this.videoEmbed=new yt({previewElement:this.elements.previewContent}),this.imageLightbox=new wt({previewElement:this.elements.previewContent}),this.previewRenderer=new Be({getContent:()=>this.getPreviewSource(),getFileList:()=>this.fileExplorer.flatDocumentFiles,getSourceFilePath:()=>this.currentFilePath,onAfterRenderCommit:(e,t)=>{this.recordFileOpenMetric("preview_committed",{chars:t?.chars??0,renderVersion:t?.renderVersion??0}),this.videoEmbed.reconcileEmbeds(this.elements.previewContent),this.videoEmbed.syncLayout(),this.excalidrawEmbed.reconcileEmbeds(this.elements.previewContent,{isLargeDocument:t.isLargeDocument}),this.excalidrawEmbed.syncLayout(),this.scrollSyncController.setLargeDocumentMode(t.isLargeDocument),this.schedulePreviewLayoutSync({delayMs:0}),this.refreshCommentUiLayout()},onBeforeRenderCommit:()=>{this.videoEmbed.detachForCommit(),this.excalidrawEmbed.detachForCommit()},onRenderComplete:()=>{this.videoEmbed.syncLayout(),this.excalidrawEmbed.syncLayout(),this.schedulePreviewLayoutSync({delayMs:0}),this.refreshCommentUiLayout()},outlineController:this.outlineController,previewContainer:this.elements.previewContainer,previewElement:this.elements.previewContent}),this.themeController=new gt({onChange:e=>this.handleThemeChange(e)}),this.layoutController=new ut({mobileBreakpointQuery:this.mobileBreakpointQuery,onMeasureEditor:()=>this.session?.requestMeasure()}),this.scrollSyncController=new ft({getEditorLineNumber:()=>this.session?.getTopVisibleLineNumber(.35)??1,onEditorScrollActivityChange:e=>this.handleEditorScrollActivityChange(e),previewContainer:this.elements.previewContainer,previewElement:this.elements.previewContent,scrollEditorToLine:(e,t)=>this.session?.scrollToLine(e,t)}),this.backlinksPanel=new Ze({inlinePanelElement:this.elements.backlinksInlinePanel,onFileSelect:e=>this.handleFileSelection(e,{closeSidebarOnMobile:!0}),panelElement:this.elements.backlinksPanel}),this.excalidrawEmbed=new st({getLocalUser:()=>this.lobby.getLocalUser(),getTheme:()=>this.themeController.getTheme(),onOpenFile:e=>e&&this.navigation.navigateToFile(e),previewContainer:this.elements.previewContainer,previewElement:this.elements.previewContent,toastController:this.toastController}),this.commentUi=new et({commentSelectionButton:this.elements.commentSelectionButton,commentsDrawer:this.elements.commentsDrawer,commentsDrawerEmpty:this.elements.commentsDrawerEmpty,commentsDrawerList:this.elements.commentsDrawerList,commentsToggleButton:this.elements.commentsToggleButton,editorContainer:this.elements.editorContainer,onWillOpenDrawer:()=>this.outlineController.close(),previewContainer:this.elements.previewContainer,previewElement:this.elements.previewContent,onCreateThread:({anchor:e,body:t})=>this.session?.createCommentThread({anchor:e,body:t}),onNavigateToLine:e=>{this.scrollSyncController.suspendSync(250),this.session?.scrollToLine(e,.2)},onReplyToThread:(e,t)=>this.session?.replyToCommentThread(e,t),onToggleReaction:(e,t,i)=>this.session?.toggleCommentReaction(e,t,i),onResolveThread:e=>this.session?.deleteCommentThread(e)}),this.workspacePreviewController=new De({backlinksPanel:this.backlinksPanel,elements:this.elements,excalidrawEmbed:this.excalidrawEmbed,getDisplayName:e=>this.getDisplayName(e),getSession:()=>this.session,isExcalidrawFile:e=>this.isExcalidrawFile(e),isImageFile:e=>this.isImageFile(e),isMermaidFile:e=>this.isMermaidFile(e),isPlantUmlFile:e=>this.isPlantUmlFile(e),layoutController:this.layoutController,outlineController:this.outlineController,previewRenderer:this.previewRenderer,schedulePreviewLayoutSync:e=>this.schedulePreviewLayoutSync(e),scrollSyncController:this.scrollSyncController,videoEmbed:this.videoEmbed}),this.wikiLinkFileController=new Ne({getFileList:()=>this.fileExplorer.flatDocumentFiles,navigation:this.navigation,refreshExplorer:()=>this.fileExplorer.refresh(),toastController:this.toastController,vaultApiClient:this.vaultApiClient}),this.gitDiffView=new ct({onBackToHistory:({historyFilePath:e}={})=>{if(e){this.navigation.navigateToGitFileHistory({filePath:e});return}this.navigation.navigateToGitHistory()},onCommitStaged:()=>this.openGitCommitDialog(),onOpenFile:e=>e&&this.navigation.navigateToFile(e),onStageFile:(e,{scope:t})=>this.stageGitFile(e,{scope:t}),onUnstageFile:(e,{scope:t})=>this.unstageGitFile(e,{scope:t}),toastController:this.toastController}),this.fileHistoryView=new lt({diffRenderer:this.gitDiffView,onOpenCommitDiff:(e,{historyFilePath:t,path:i})=>this.handleGitCommitSelection(e,{closeSidebarOnMobile:!1,historyFilePath:t,path:i}),onOpenFile:e=>e&&this.navigation.navigateToFile(e),onOpenPreview:({hash:e,path:t,currentFilePath:i})=>this.handleGitFilePreviewSelection({hash:e,path:t,currentFilePath:i}),onOpenWorkspaceDiff:e=>this.handleGitDiffSelection(e,{closeSidebarOnMobile:!1,scope:"all"}),toastController:this.toastController}),this.tabActivityLock=new Ve({onActivated:({takeover:e})=>this.handleTabActivated({takeover:e}),onBlocked:()=>this.handleTabBlocked({reason:"active-elsewhere"}),onStolen:()=>this.handleTabBlocked({reason:"taken-over"})}),this.workspaceCoordinator=new Oe({attachEditorScroller:e=>this.scrollSyncController.attachEditorScroller(e),beginDocumentLoad:()=>this.previewRenderer.beginDocumentLoad(),cleanupAfterSessionDestroy:()=>{this.scrollSyncController.setLargeDocumentMode(!1),this.scrollSyncController.invalidatePreviewBlocks(),this.outlineController.cleanup(),this.followedCursorSignature="",clearTimeout(this._backlinkRefreshTimer)},createEditorSession:(e,t)=>new e({editorContainer:this.elements.editorContainer,getFileList:t.getFileList,initialTheme:t.theme,lineInfoElement:this.elements.lineInfo,lineWrappingEnabled:t.lineWrappingEnabled,localUser:t.localUser,onImagePaste:t.onImagePaste,onAwarenessChange:t.onAwarenessChange,onCommentsChange:t.onCommentsChange,onConnectionChange:t.onConnectionChange,onContentChange:t.onContentChange,onSelectionChange:t.onSelectionChange,preferredUserName:t.preferredUserName}),getDisplayName:e=>this.getDisplayName(e),getFileList:()=>this.fileExplorer.flatDocumentFiles,getLineWrappingEnabled:()=>this.getStoredLineWrapping(),getLocalUser:()=>this.lobby.getLocalUser(),getStoredUserName:()=>this.getStoredUserName(),getTheme:()=>this.themeController.getTheme(),isExcalidrawFile:e=>this.isExcalidrawFile(e),isImageFile:e=>this.isImageFile(e),isMermaidFile:e=>this.isMermaidFile(e),isPlantUmlFile:e=>this.isPlantUmlFile(e),isTabActive:()=>this.isTabActive,loadBootstrapContent:async e=>{let t=await this.vaultApiClient.readFile(e);return typeof t?.content=="string"?t.content:null},loadEditorSessionClass:()=>this.loadEditorSessionClass(),loadBacklinks:e=>this.backlinksPanel.load(e),onBeforeFileOpen:()=>{this.session=null,this.commentUi.attachSession(null),this.layoutController.reset(),this.resetPreviewMode(),this.elements.emptyState?.classList.add("hidden"),this.elements.editorPage?.classList.remove("hidden"),this.elements.diffPage?.classList.add("hidden"),this.clearInitialFileBootstrap()},onConnectionChange:e=>this.handleConnectionChange(e),onContentChange:({isMermaid:e,isPlantUml:t})=>{this.handleCommentEditorContentChange(),this.previewRenderer.queueRender(),!e&&!t&&this.scheduleBacklinkRefresh()},onCommentsChange:e=>this.handleCommentThreadsChange(e),onFileAwarenessChange:e=>this.updateFileAwareness(e),onFileOpenError:()=>{this.showEditorLoadError(),this.syncWrapToggle(),this.toastController.show("Failed to initialize editor")},onFileOpenReady:()=>{this.hideEditorLoading()},onSelectionChange:e=>this.handleCommentSelectionChange(e),onImagePaste:e=>this.handleEditorImageInsert(e),onFileOpenMetric:(e,t)=>this.recordFileOpenMetric(e,t),onSessionAssigned:e=>{this.session=e,this.commentUi.attachSession(e)},onRenderExcalidrawPreview:e=>this.renderExcalidrawFilePreview(e),onRenderImagePreview:e=>this.renderImageFilePreview(e),onSyncWrapToggle:()=>this.syncWrapToggle(),onUpdateActiveFile:e=>this.fileExplorer.setActiveFile(e),onUpdateCurrentFile:e=>{this.currentFilePath=e},onUpdateLobbyCurrentFile:e=>this.lobby.setCurrentFile(e),onUpdateVisibleChrome:(e,{displayName:t})=>{this.syncFileChrome(e),this.syncCommentChrome(e),this.syncFileHistoryButton({filePath:e,mode:"editor"}),this.elements.activeFileName&&(this.elements.activeFileName.textContent=t)},onViewModeReset:()=>this.resetPreviewMode(),renderPresence:()=>this.renderPresence(),scrollContainerForSession:e=>e.getScrollContainer(),showEditorLoading:()=>this.showEditorLoading(),stateStore:this.stateStore}),this.workspaceRouteController=new Re({backlinksPanel:this.backlinksPanel,clearInitialFileBootstrap:()=>this.clearInitialFileBootstrap(),clearStaticPreviewDocument:()=>this.clearStaticPreviewDocument(),closeSidebarOnMobile:()=>this.closeSidebarOnMobile(),elements:this.elements,excalidrawEmbed:this.excalidrawEmbed,fileHistoryView:this.fileHistoryView,fileExplorer:this.fileExplorer,getIsTabActive:()=>this.isTabActive,getSessionLoadToken:()=>this.sessionLoadToken,gitDiffView:this.gitDiffView,gitPanel:this.gitPanel,imageLightbox:this.imageLightbox,layoutController:this.layoutController,lobby:this.lobby,navigation:this.navigation,previewRenderer:this.previewRenderer,renderAvatars:()=>this.renderAvatars(),renderPresence:()=>this.renderPresence(),resetPreviewMode:()=>this.resetPreviewMode(),scrollSyncController:this.scrollSyncController,setCurrentFilePath:e=>{this.currentFilePath=e,e||(this.commentUi.setCurrentFile(null,{supported:!1}),this.handleCommentThreadsChange([]),this.handleCommentSelectionChange(null))},setSession:e=>{this.session=e,this.commentUi.attachSession(e)},setSessionLoadToken:e=>{this.sessionLoadToken=e},setSidebarTab:e=>this.setSidebarTab(e),showGitCommit:e=>this.showGitCommit(e),showGitDiff:e=>this.showGitDiff(e),showGitFileHistory:e=>this.showGitFileHistory(e),showGitFilePreview:e=>this.showGitFilePreview(e),showGitHistory:()=>this.showGitHistory(),syncMainChrome:e=>this.syncMainChrome(e),videoEmbed:this.videoEmbed,workspaceCoordinator:this.workspaceCoordinator}),this.chatNotificationPermission!=="granted"&&(this.chatNotificationsEnabled=!1)}get session(){return this._session}set session(e){this._session=e}get currentFilePath(){return this.stateStore.get("currentFilePath")}set currentFilePath(e){this.stateStore.set("currentFilePath",e)}get globalUsers(){return this.stateStore.get("globalUsers")}set globalUsers(e){this.stateStore.set("globalUsers",e)}get connectionState(){return this.stateStore.get("connectionState")}set connectionState(e){this.stateStore.set("connectionState",e)}get sessionLoadToken(){return this.stateStore.get("sessionLoadToken")}set sessionLoadToken(e){this.stateStore.set("sessionLoadToken",e)}get connectionHelpShown(){return this.stateStore.get("connectionHelpShown")}set connectionHelpShown(e){this.stateStore.set("connectionHelpShown",e)}get chatMessages(){return this.stateStore.get("chatMessages")}set chatMessages(e){this.stateStore.set("chatMessages",e)}get chatMessageIds(){return this.stateStore.get("chatMessageIds")}set chatMessageIds(e){this.stateStore.set("chatMessageIds",e)}get chatUnreadCount(){return this.stateStore.get("chatUnreadCount")}set chatUnreadCount(e){this.stateStore.set("chatUnreadCount",e)}get chatIsOpen(){return this.stateStore.get("chatIsOpen")}set chatIsOpen(e){this.stateStore.set("chatIsOpen",e)}get chatInitialSyncComplete(){return this.stateStore.get("chatInitialSyncComplete")}set chatInitialSyncComplete(e){this.stateStore.set("chatInitialSyncComplete",e)}get isTabActive(){return this.stateStore.get("isTabActive")}set isTabActive(e){this.stateStore.set("isTabActive",e)}get fileExplorerReady(){return this.stateStore.get("fileExplorerReady")}set fileExplorerReady(e){this.stateStore.set("fileExplorerReady",e)}get gitRepoAvailable(){return this.stateStore.get("gitRepoAvailable")}set gitRepoAvailable(e){this.stateStore.set("gitRepoAvailable",e)}get activeSidebarTab(){return this.stateStore.get("activeSidebarTab")}set activeSidebarTab(e){this.stateStore.set("activeSidebarTab",e)}get followedUserClientId(){return this.stateStore.get("followedUserClientId")}set followedUserClientId(e){this.stateStore.set("followedUserClientId",e)}get followedCursorSignature(){return this.stateStore.get("followedCursorSignature")}set followedCursorSignature(e){this.stateStore.set("followedCursorSignature",e)}publishFileOpenPerf(){typeof window>"u"||(window.__COLLABMD_PERF__??={},window.__COLLABMD_PERF__.fileOpen=this._fileOpenPerf?{...this._fileOpenPerf,details:{...this._fileOpenPerf.details},marks:{...this._fileOpenPerf.marks}}:null)}recordFileOpenMetric(e,t={}){if(e==="open_started"){this._fileOpenPerf={details:{filePath:t.filePath||this.currentFilePath||"",loadToken:t.loadToken??0},marks:{open_started:performance.now()}},this.publishFileOpenPerf();return}!this._fileOpenPerf||(t.loadToken??this._fileOpenPerf.details.loadToken)!==this._fileOpenPerf.details.loadToken||(this._fileOpenPerf.marks[e]=performance.now(),t.filePath&&(this._fileOpenPerf.details.filePath=t.filePath),Object.entries(t).forEach(([n,r])=>{n==="filePath"||n==="loadToken"||(this._fileOpenPerf.details[n]=r)}),this.publishFileOpenPerf())}loadEditorSessionClass(){return this._editorSessionModulePromise||(this._editorSessionModulePromise=import("./chunks/editor-session-S5AT7BMV.js").then(e=>e.EditorSession)),this._editorSessionModulePromise}scheduleEditorSessionPrewarm({timeout:e=1500}={}){if(this._editorSessionModulePromise||this._editorSessionPrewarmHandle)return;let t=()=>{this._editorSessionPrewarmHandle=null,this.loadEditorSessionClass()};if(typeof window.requestIdleCallback=="function"){this._editorSessionPrewarmHandle=window.requestIdleCallback(t,{timeout:e});return}this._editorSessionPrewarmHandle=window.setTimeout(t,0)}async ensureQuickSwitcher(){if(this.quickSwitcher)return this.quickSwitcher;this.quickSwitcherModulePromise||(this.quickSwitcherModulePromise=import("./chunks/quick-switcher-controller-A6SKH5HI.js").then(t=>t.QuickSwitcherController));let e=await this.quickSwitcherModulePromise;return this.quickSwitcher||(this.quickSwitcher=new e({getFileList:()=>this.fileExplorer.flatFiles,onFileSelect:t=>this.handleFileSelection(t,{closeSidebarOnMobile:!0})})),this.quickSwitcher}async toggleQuickSwitcher(){(await this.ensureQuickSwitcher()).toggle()}};var $n={enabled:!1,implemented:!0,loginEndpoint:"/api/auth/oidc/login",passwordLabel:"Password",provider:"",requiresLogin:!1,sessionEndpoint:"/api/auth/session",statusEndpoint:"/api/auth/status",strategy:"none",submitLabel:"Continue"},On="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAFAAAABQCAIAAAABc2X6AAAGsklEQVR4Ae3cA3jsShgG4Gvbtu1js7aObdu2bdbudmvbtu1VtUg2ydw7x95mstnt5rZ5voflG80/fzL72L89bOsF94J7wWgb2dSgiAzpPHmwbfPK1qWzxDNsRdb6Ar2BgtF9hSbDRbYG4mk2beuXwm+Q89yV+TmAILgHptrb5DyPtg3LhBZjBCP+RovewNZlc2TOl8nGel0HA4LA4qPhkRSM6XcHoEYk86fIfT2AQqFzYIBjMncHofkoZBWNCM1GSq+cpdpadQIMKEoRzIeXIroEkW08TObpDAiiO8F4Tga85TBnoEc8xVKZm9UNYECS0stnBCP/Ud+AnJH/SC+eAiShPTDZ3CRZPIN9CUokC6ZSYqE2wHhmKhw/2TegR2RnSFSUaRaMJccLxg7QsAQhktkTAACaAmOxkbA80h2taKIZKWzR1BFWRAQLRvXhphYdDEtcWDxxU4sOhjdDkdVYbmrRwYAgJIums3RTNWrftbHz/AmZh5MiLBAGVqOdZ4+1790inmrFvpYZuPPEATWdknmT5f7eZEN9V2N7o9zPu3XNInQte2BlcYE6tVTbltXw4kf9h5QlhW3rliBr1QcDAODsjPFlhmelqfNvKQty4S9B0KoPVgTxmWk7Tx0COMZCF6GzA3ZC0LWMwJSsTWiOXj+O6iP382KzowAAvMOhaxmAqw/Ijr4tGPsHgnbsACwxlpNNPABIIv5LIvxpzOVlkdXPNMGK8CCudi2pFi+ovRFlwLOtc7/uUgvnxhxu05LpIyD17nTu+EAw8q9HaVtXzgcAcBUMcAER/sx9YBj5pdeExr897NLtT9TVcLgRTzVcgbyHBuc9L5n8PdLJzAEwmWP1KDCMMvTp9jWf3tbC1gdQKDgMBhRBRL0GYaojO35zxOo8fZjbz5ZAZz700Anm9pLI9g+yoY7bYKrJBWJoRpk8SJ0/fDoc13QuRuNdgMmydfTBZPkGdcDDd0q1EDkOVIKzTOiDKVGY7oPLmylVYCKlL30wIKW6D44tJlSCE76nC45+CwHXfWDfdKVKcMwHdMEJ33MC7JqEqwRHvEgXnDaYE+ArMayBB3ECDAennnVKn4tUDU74gS446k1OgB3i8Z41LHmkKHtW4eGfpRpctv5/VlomlxOsTR6kKQN1H1wnptiZHpYFv27pMbqus4kxOChbySzTz8loakfukhIkYKEBEBzw6SBXk79cLQ5lXv5XuxtJAaMDdA/v+JMydVs8irBnDvB+g9QbGeY1SUFg2gTn1JD0z+cdPIVaTbym0JemeQ6FzrtzJtdFm+DT4Rh9MD9DybxNmxL03mg3g/u0MP3cbWo6GrWjbZMBg/0Id6wqAcWwEX+F/10fVzPIe2jmRW3VTiP+VBjC4bU6KgMAID9qaQt9frl3P6hSndOaP7HrxdSYPQiH92QYhvAwTRH7KdSWBL9h5j4GeugkqDpWc1oZBqaelSGNwMWNJMLjUkHxBn//zwZeH3topr+7bWxDmia0AID17gok7aTTMrTnw1KsfZTPVMhAyj9uVl5lIexqcQLs4KFpYXjpSjQw3HwrIqCBQQ5mXsZInBWtoIOac1GOqrU4IsUJwOSllsmha5iZTf3npzXnqXka+1dFmzo4D9vZgQp2TsAZvrZUIC7729WSmRlmVfz+HGExKpUCVGJj1oSQlTd+SZ9Lm4bubqKvtTkmk+OAIRhu+zMu3jEwyqTQ1d7lofWdzV0VyWSxpPJkjpOB76z7fsPfjjOHHMhBb0QzAhMUMS18nRrgOzHkz96YdPR4toNTMT+gKjq4OtatNPBCvgfcp9PD1w/wsFP14y7WA4/zu9SudVWw8HKpUC4Zw5uOLmQ//c4fGrZL8iit+WEpvMmxAIZbtrCor7uNLpj/ubpk6N6Kh059M6tINl8Qh4UUHGa73wzjNGHQ4dj7wC6JOPtLACLqkvq4WeuE2cWi/+nLt0csOKnQ1CKP+IYMWELqgPnGiLVh6O7Go8GYZpfxpDbnwkaHjpj3JfLRV7Wgb01SARxIupc6wntyfGOG9pbikRQJmzvodRg7mRq2tkkm7IbFlhktBdaBS7SsPZx1haDIbltOSwGKXxl5px7UZGaEb8gXlerEgmmMxB2KfEciTKHRAsvbmPo0nVsST1BEdH3Kyrh9bJVlQ7wmbk05USSu0PUPPWjDOtxLg5bF7h7tM42B08x//o7U0/AmrCSV3PtYiwZpS3B13MHMS/DIz4rYaBO0VM93JpwbwaJtqNfEsbwZFgEL50VtgcJLBV6wK9aKtfd+cEkvuBfcC37k9h8VGR+csPdltgAAAABJRU5ErkJggg==",as=!1;function zn(){if(as||!document.head)return;let s=document.createElement("style");s.textContent=`
|
|
278
516
|
.auth-gate-overlay {
|
|
279
517
|
position: fixed;
|
|
280
518
|
inset: 0;
|
|
@@ -284,98 +522,181 @@ ${r}`}getPreviewSource(e){let t=this.getSession()?.getText()??"";return this.isM
|
|
|
284
522
|
justify-content: center;
|
|
285
523
|
padding: 24px;
|
|
286
524
|
background:
|
|
287
|
-
radial-gradient(circle at
|
|
288
|
-
rgba(
|
|
289
|
-
|
|
525
|
+
radial-gradient(circle at 50% 8%, rgba(37, 99, 235, 0.18), transparent 28%),
|
|
526
|
+
radial-gradient(circle at 60% 45%, rgba(14, 165, 233, 0.08), transparent 18%),
|
|
527
|
+
linear-gradient(180deg, rgba(8, 12, 24, 0.9), rgba(6, 10, 22, 0.96));
|
|
528
|
+
backdrop-filter: blur(18px);
|
|
290
529
|
}
|
|
291
530
|
|
|
292
531
|
.auth-gate-card {
|
|
293
|
-
width: min(100%,
|
|
294
|
-
padding:
|
|
295
|
-
border-radius:
|
|
296
|
-
border: 1px solid rgba(148, 163, 184, 0.
|
|
297
|
-
background:
|
|
532
|
+
width: min(100%, 440px);
|
|
533
|
+
padding: 32px;
|
|
534
|
+
border-radius: 24px;
|
|
535
|
+
border: 1px solid rgba(148, 163, 184, 0.2);
|
|
536
|
+
background:
|
|
537
|
+
linear-gradient(180deg, rgba(17, 24, 39, 0.96), rgba(12, 18, 32, 0.96));
|
|
298
538
|
color: #e2e8f0;
|
|
299
|
-
box-shadow:
|
|
300
|
-
|
|
539
|
+
box-shadow:
|
|
540
|
+
0 28px 90px rgba(15, 23, 42, 0.42),
|
|
541
|
+
inset 0 1px 0 rgba(255, 255, 255, 0.04);
|
|
542
|
+
font-family: "Geist", "Inter", ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif;
|
|
301
543
|
}
|
|
302
544
|
|
|
303
545
|
.auth-gate-card h1 {
|
|
304
546
|
margin: 0 0 10px;
|
|
305
|
-
font-size:
|
|
306
|
-
line-height: 1.
|
|
547
|
+
font-size: 2rem;
|
|
548
|
+
line-height: 1.05;
|
|
549
|
+
letter-spacing: -0.04em;
|
|
307
550
|
}
|
|
308
551
|
|
|
309
552
|
.auth-gate-card p {
|
|
310
|
-
margin: 0 0
|
|
553
|
+
margin: 0 0 22px;
|
|
311
554
|
color: #cbd5e1;
|
|
312
555
|
line-height: 1.5;
|
|
556
|
+
font-size: 1rem;
|
|
313
557
|
}
|
|
314
558
|
|
|
315
559
|
.auth-gate-form {
|
|
316
560
|
display: grid;
|
|
317
|
-
gap:
|
|
561
|
+
gap: 14px;
|
|
318
562
|
}
|
|
319
563
|
|
|
320
564
|
.auth-gate-label {
|
|
321
565
|
display: grid;
|
|
322
|
-
gap:
|
|
566
|
+
gap: 10px;
|
|
323
567
|
font-size: 0.92rem;
|
|
568
|
+
font-weight: 500;
|
|
324
569
|
color: #cbd5e1;
|
|
325
570
|
}
|
|
326
571
|
|
|
327
572
|
.auth-gate-input {
|
|
328
573
|
width: 100%;
|
|
329
|
-
padding:
|
|
574
|
+
padding: 14px 16px;
|
|
330
575
|
border: 1px solid rgba(148, 163, 184, 0.28);
|
|
331
|
-
border-radius:
|
|
576
|
+
border-radius: 16px;
|
|
332
577
|
background: rgba(15, 23, 42, 0.72);
|
|
333
578
|
color: inherit;
|
|
334
579
|
font: inherit;
|
|
580
|
+
box-sizing: border-box;
|
|
335
581
|
}
|
|
336
582
|
|
|
337
583
|
.auth-gate-input:focus {
|
|
338
|
-
outline:
|
|
339
|
-
|
|
584
|
+
outline: none;
|
|
585
|
+
border-color: rgba(56, 189, 248, 0.72);
|
|
586
|
+
box-shadow: 0 0 0 4px rgba(56, 189, 248, 0.12);
|
|
340
587
|
}
|
|
341
588
|
|
|
342
589
|
.auth-gate-actions {
|
|
343
|
-
display:
|
|
344
|
-
align-items: center;
|
|
345
|
-
justify-content: space-between;
|
|
590
|
+
display: grid;
|
|
346
591
|
gap: 12px;
|
|
347
592
|
}
|
|
348
593
|
|
|
349
594
|
.auth-gate-button,
|
|
350
595
|
.auth-gate-secondary-button {
|
|
351
596
|
border: 0;
|
|
352
|
-
border-radius:
|
|
597
|
+
border-radius: 16px;
|
|
353
598
|
font: inherit;
|
|
354
599
|
cursor: pointer;
|
|
600
|
+
transition:
|
|
601
|
+
transform 160ms ease,
|
|
602
|
+
box-shadow 160ms ease,
|
|
603
|
+
border-color 160ms ease,
|
|
604
|
+
background-color 160ms ease;
|
|
605
|
+
}
|
|
606
|
+
|
|
607
|
+
.auth-gate-button:hover,
|
|
608
|
+
.auth-gate-secondary-button:hover {
|
|
609
|
+
transform: translateY(-1px);
|
|
610
|
+
}
|
|
611
|
+
|
|
612
|
+
.auth-gate-button:focus-visible,
|
|
613
|
+
.auth-gate-secondary-button:focus-visible {
|
|
614
|
+
outline: 3px solid rgba(125, 211, 252, 0.3);
|
|
615
|
+
outline-offset: 2px;
|
|
355
616
|
}
|
|
356
617
|
|
|
357
618
|
.auth-gate-button {
|
|
358
|
-
|
|
619
|
+
display: inline-flex;
|
|
620
|
+
align-items: center;
|
|
621
|
+
justify-content: center;
|
|
622
|
+
gap: 14px;
|
|
623
|
+
width: 100%;
|
|
624
|
+
padding: 14px 18px;
|
|
359
625
|
background: linear-gradient(135deg, #0f766e, #0284c7);
|
|
360
626
|
color: #f8fafc;
|
|
361
627
|
font-weight: 600;
|
|
628
|
+
box-shadow: 0 16px 40px rgba(2, 132, 199, 0.24);
|
|
629
|
+
}
|
|
630
|
+
|
|
631
|
+
.auth-gate-button:hover {
|
|
632
|
+
box-shadow: 0 18px 44px rgba(2, 132, 199, 0.28);
|
|
362
633
|
}
|
|
363
634
|
|
|
364
635
|
.auth-gate-secondary-button {
|
|
365
|
-
padding:
|
|
366
|
-
background:
|
|
367
|
-
color: #
|
|
636
|
+
padding: 13px 16px;
|
|
637
|
+
background: rgba(15, 23, 42, 0.48);
|
|
638
|
+
color: #cbd5e1;
|
|
639
|
+
border: 1px solid rgba(148, 163, 184, 0.22);
|
|
368
640
|
}
|
|
369
641
|
|
|
370
642
|
.auth-gate-button[disabled],
|
|
371
643
|
.auth-gate-secondary-button[disabled] {
|
|
372
644
|
opacity: 0.7;
|
|
373
645
|
cursor: wait;
|
|
646
|
+
transform: none;
|
|
647
|
+
}
|
|
648
|
+
|
|
649
|
+
.auth-gate-button--google {
|
|
650
|
+
background: rgba(255, 255, 255, 0.98);
|
|
651
|
+
color: #111827;
|
|
652
|
+
border: 1px solid rgba(148, 163, 184, 0.22);
|
|
653
|
+
box-shadow:
|
|
654
|
+
0 22px 40px rgba(15, 23, 42, 0.2),
|
|
655
|
+
inset 0 1px 0 rgba(255, 255, 255, 0.65);
|
|
656
|
+
}
|
|
657
|
+
|
|
658
|
+
.auth-gate-button--google:hover {
|
|
659
|
+
background: #ffffff;
|
|
660
|
+
box-shadow:
|
|
661
|
+
0 24px 44px rgba(15, 23, 42, 0.24),
|
|
662
|
+
inset 0 1px 0 rgba(255, 255, 255, 0.8);
|
|
663
|
+
}
|
|
664
|
+
|
|
665
|
+
.auth-gate-button__icon {
|
|
666
|
+
display: inline-flex;
|
|
667
|
+
align-items: center;
|
|
668
|
+
justify-content: center;
|
|
669
|
+
flex: 0 0 auto;
|
|
670
|
+
width: 22px;
|
|
671
|
+
height: 22px;
|
|
672
|
+
}
|
|
673
|
+
|
|
674
|
+
.auth-gate-button__icon img {
|
|
675
|
+
display: block;
|
|
676
|
+
width: 100%;
|
|
677
|
+
height: 100%;
|
|
678
|
+
object-fit: contain;
|
|
374
679
|
}
|
|
375
680
|
|
|
376
681
|
.auth-gate-error {
|
|
377
682
|
min-height: 1.25rem;
|
|
378
683
|
color: #fca5a5;
|
|
379
684
|
font-size: 0.92rem;
|
|
685
|
+
margin-bottom: 4px;
|
|
686
|
+
}
|
|
687
|
+
|
|
688
|
+
@media (max-width: 640px) {
|
|
689
|
+
.auth-gate-overlay {
|
|
690
|
+
padding: 16px;
|
|
691
|
+
}
|
|
692
|
+
|
|
693
|
+
.auth-gate-card {
|
|
694
|
+
padding: 24px;
|
|
695
|
+
border-radius: 20px;
|
|
696
|
+
}
|
|
697
|
+
|
|
698
|
+
.auth-gate-card h1 {
|
|
699
|
+
font-size: 1.7rem;
|
|
700
|
+
}
|
|
380
701
|
}
|
|
381
|
-
`,document.head.append(
|
|
702
|
+
`,document.head.append(s),as=!0}function Un(){return{...$n,...Le().auth??{}}}function Ut(){let s=window.location.hash.startsWith("#")?window.location.hash.slice(1):window.location.hash;return new URLSearchParams(s)}function qn(){return Ut().get("auth_password")||""}function ls(){let s=Ut();if(!s.has("auth_password"))return;s.delete("auth_password");let e=s.toString(),t=`${window.location.pathname}${window.location.search}${e?`#${e}`:""}`;window.history.replaceState(null,"",t)}function Wn(s){let e=Ut(),t=e.get(s)||"";if(!t)return"";e.delete(s);let i=e.toString(),n=`${window.location.pathname}${window.location.search}${i?`#${i}`:""}`;return window.history.replaceState(null,"",n),t}function Gn(){return`${window.location.pathname}${window.location.search}${window.location.hash}`}async function Kn(s){let e=await fetch(s.statusEndpoint,{headers:{Accept:"application/json"}}),t=await e.json().catch(()=>({}));if(!e.ok)throw new Error(t.error||"Failed to read auth status");return t}function Vn(s){let e=s?.auth??{};if(e.strategy!=="oidc"||e.provider!=="google")return;let t=String(s?.user?.name??"").trim();if(t)try{window.localStorage.setItem("collabmd-user-name",t)}catch{}}async function cs(s,e){let t=await fetch(s.sessionEndpoint,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({password:e})}),i=await t.json().catch(()=>({}));if(!t.ok)throw new Error(i.error||"Authentication failed");return i}function jn(){zn();let s=document.createElement("div");s.className="auth-gate-overlay";let e=document.createElement("section");return e.className="auth-gate-card",s.append(e),{card:e,overlay:s}}function Qn(){let s=document.createElement("span");s.className="auth-gate-button__icon",s.setAttribute("aria-hidden","true");let e=document.createElement("img");return e.alt="",e.decoding="async",e.height=20,e.loading="eager",e.src=On,e.width=20,s.append(e),s}function Zn(s,e,{errorMessage:t=""}){s.replaceChildren();let i=document.createElement("h1");i.textContent="Authentication required";let n=document.createElement("p");n.textContent="Sign in with Google to join this session.";let r=document.createElement("div");r.className="auth-gate-actions";let o=document.createElement("button");o.className="auth-gate-button auth-gate-button--google",o.type="button",o.append(Qn(),document.createTextNode(e.submitLabel||"Continue with Google"));let a=document.createElement("div");a.className="auth-gate-error",a.textContent=t,r.append(o),s.append(i,n,a,r),o.addEventListener("click",()=>{let c=new URL(e.loginEndpoint,window.location.origin);c.searchParams.set("returnTo",Gn()),window.location.assign(c.toString())})}function zt(s,{title:e,body:t,secondaryActionLabel:i="",onSecondaryAction:n=null}){s.replaceChildren();let r=document.createElement("h1");r.textContent=e;let o=document.createElement("p");if(o.textContent=t,s.append(r,o),i&&typeof n=="function"){let a=document.createElement("button");a.className="auth-gate-secondary-button",a.type="button",a.textContent=i,a.addEventListener("click",()=>{n()}),s.append(a)}}function Yn(s,e,{onSubmit:t}){s.replaceChildren();let i=document.createElement("h1");i.textContent="Authentication required";let n=document.createElement("p");n.textContent="Enter the host password to join this shared session.";let r=document.createElement("form");r.className="auth-gate-form";let o=document.createElement("label");o.className="auth-gate-label",o.textContent=e.passwordLabel;let a=document.createElement("input");a.className="auth-gate-input",a.type="password",a.name="password",a.autocomplete="current-password",a.required=!0;let c=document.createElement("div");c.className="auth-gate-error";let h=document.createElement("div");h.className="auth-gate-actions";let l=document.createElement("button");l.className="auth-gate-button",l.type="submit",l.textContent=e.submitLabel,h.append(l),o.append(a),r.append(i,n,o,c,h),s.append(r),r.addEventListener("submit",u=>{u.preventDefault();let m=a.value;a.disabled=!0,l.disabled=!0,c.textContent="",t(m).catch(d=>{c.textContent=d instanceof Error?d.message:"Authentication failed",a.disabled=!1,l.disabled=!1,a.select(),a.focus()})}),queueMicrotask(()=>{a.focus()})}async function hs(){let s=Un();if(!s.enabled||s.strategy==="none")return{authenticated:!0,auth:s};let{card:e,overlay:t}=jn();document.body.append(t);let i=Wn("auth_error");return new Promise(n=>{let r=(a=null)=>{ls(),Vn(a),t.remove(),n({authenticated:!0,auth:a?.auth??s,user:a?.user??null})};(async()=>{zt(e,{body:"Checking access to this session\u2026",title:"CollabMD"});try{let a=await Kn(s);if(a.authenticated){r(a);return}}catch(a){zt(e,{body:a instanceof Error?`${a.message} Refresh the page and try again.`:"Failed to contact the auth service. Refresh the page and try again.",title:"Cannot verify access"});return}if(s.strategy==="password"){let a=qn();if(a)try{ls(),await cs(s,a),r();return}catch{}Yn(e,s,{onSubmit:async c=>{await cs(s,c),r()}});return}if(s.strategy==="oidc"){Zn(e,s,{errorMessage:i}),i="";return}zt(e,{body:"This authentication strategy is not available.",title:"Authentication unavailable"})})()})}async function ds(){await hs(),new vt().initialize()}document.readyState==="loading"?document.addEventListener("DOMContentLoaded",()=>{ds()},{once:!0}):ds();
|