collabmd 0.1.18 → 0.1.19
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 +99 -17
- package/package.json +1 -1
- package/public/assets/css/style.css +1 -1
- package/public/assets/js/chunks/{preview-render-compiler-WD3A76I6.js → chunk-5QRWYPYT.js} +18 -18
- package/public/assets/js/chunks/chunk-HEWVH67U.js +9 -0
- package/public/assets/js/chunks/chunk-R3DDMJHH.js +1 -0
- package/public/assets/js/chunks/editor-session-AH6Z3MXW.js +22 -0
- package/public/assets/js/chunks/preview-render-compiler-UZ4SZDQQ.js +1 -0
- package/public/assets/js/chunks/quick-switcher-controller-J7I3CUET.js +5 -0
- package/public/assets/js/{excalidraw-editor-LKW2AZBU.js → excalidraw-editor-ZDYKMZOL.js} +33 -33
- package/public/assets/js/excalidraw-editor.js +1 -1
- package/public/assets/js/main.js +59 -59
- package/public/assets/js/preview-render-worker.js +19 -19
- package/src/client/application/app-shell/presence-feature.js +2 -1
- package/src/client/application/app-shell/ui-feature.js +113 -1
- package/src/client/application/app-shell/workspace-feature.js +9 -0
- package/src/client/application/preview-render-compiler.js +55 -5
- package/src/client/application/preview-render-executor.js +8 -0
- package/src/client/application/preview-render-worker.js +13 -2
- package/src/client/application/preview-renderer.js +5 -0
- package/src/client/application/workspace-chrome-controller.js +12 -1
- package/src/client/application/workspace-coordinator.js +16 -7
- package/src/client/application/workspace-preview-controller.js +45 -5
- package/src/client/application/workspace-route-controller.js +4 -0
- package/src/client/bootstrap/collabmd-app-shell.js +15 -3
- package/src/client/domain/room.js +37 -0
- package/src/client/domain/vault-utils.js +46 -0
- package/src/client/infrastructure/comment-thread-store.js +98 -0
- package/src/client/infrastructure/editor-paste-utils.js +45 -0
- package/src/client/infrastructure/editor-session.js +10 -0
- package/src/client/infrastructure/editor-view-adapter.js +34 -1
- package/src/client/infrastructure/vault-api-client.js +17 -0
- package/src/client/presentation/comment-markdown-renderer.js +68 -0
- package/src/client/presentation/comment-ui-controller.js +311 -15
- package/src/client/presentation/file-explorer-controller.js +5 -0
- package/src/client/presentation/file-explorer-view.js +10 -2
- package/src/client/presentation/file-tree-state.js +7 -1
- package/src/client/presentation/image-lightbox-controller.js +394 -0
- package/src/client/styles/style.css +539 -14
- package/src/domain/comment-threads.js +95 -13
- package/src/domain/file-kind.js +16 -1
- package/src/server/infrastructure/http/create-vault-api-command-handler.js +48 -2
- package/src/server/infrastructure/http/create-vault-api-query-handler.js +67 -1
- package/src/server/infrastructure/http/request-body.js +11 -2
- package/src/server/infrastructure/persistence/path-utils.js +1 -1
- package/src/server/infrastructure/persistence/vault-file-store.js +187 -2
- package/public/assets/js/chunks/chunk-BBHPYU2R.js +0 -1
- package/public/assets/js/chunks/chunk-OG2TNZEU.js +0 -9
- package/public/assets/js/chunks/chunk-QSTBGTWJ.js +0 -1
- package/public/assets/js/chunks/chunk-SR3U53EQ.js +0 -1
- package/public/assets/js/chunks/editor-session-IHFTYG5D.js +0 -22
- package/public/assets/js/chunks/quick-switcher-controller-JYDIJVAJ.js +0 -5
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{a as z,b as T,c as O}from"./chunk-5QRWYPYT.js";import{a as l,b as A,d as R,l as V}from"./chunk-R3DDMJHH.js";import"./chunk-775E65SU.js";var B=Object.freeze({".mp4":"video/mp4",".ogg":"video/ogg",".webm":"video/webm"}),D=new Set(["youtube.com","www.youtube.com","m.youtube.com","youtu.be","www.youtu.be","youtube-nocookie.com","www.youtube-nocookie.com"]);function S(t,e,a,r,c,d){return t?.(e,a,r,c,d)??d.renderToken(e,a,r)}function _(t=""){let e=2166136261;for(let a=0;a<t.length;a+=1)e^=t.charCodeAt(a),e=Math.imul(e,16777619);return(e>>>0).toString(36)}function k(t=""){return String(t).replace(/<->/g,"\u2194").replace(/<=>/g,"\u21D4").replace(/->/g,"\u2192").replace(/<-/g,"\u2190").replace(/=>/g,"\u21D2")}function P(t=""){return l(k(t))}function G(t=""){let e=String(t).split(/<br\s*\/?>/i);return e.length===1?P(t):e.map(a=>P(a)).join("<br>")}function H({key:t,sourceAttributes:e,sourceHash:a,sourceText:r}){return`<div class="mermaid-shell diagram-preview-shell"${e} data-mermaid-key="${l(t)}" data-mermaid-source-hash="${l(a)}"><div class="mermaid-placeholder-card diagram-preview-placeholder-card"><div class="mermaid-placeholder-copy diagram-preview-placeholder-copy"><strong>Mermaid diagram</strong><span>Loads when visible</span></div><button type="button" class="mermaid-placeholder-btn diagram-preview-placeholder-btn" data-mermaid-key="${l(t)}">Render</button></div><pre class="mermaid-source" hidden>${l(r)}</pre></div>`}function j({embedKey:t,label:e,target:a}){return`<span class="mermaid-shell diagram-preview-shell" data-mermaid-key="${l(t)}" data-mermaid-target="${l(a)}" data-mermaid-label="${l(e)}"><span class="mermaid-placeholder-card diagram-preview-placeholder-card"><span class="mermaid-placeholder-copy diagram-preview-placeholder-copy"><strong>${l(e)}</strong><span>Loads when visible</span></span><button type="button" class="mermaid-placeholder-btn diagram-preview-placeholder-btn" data-mermaid-key="${l(t)}">Render</button></span><span class="mermaid-source" hidden></span></span>`}function Z({key:t,sourceAttributes:e,sourceHash:a,sourceText:r}){return`<div class="plantuml-shell diagram-preview-shell"${e} data-plantuml-key="${l(t)}" data-plantuml-source-hash="${l(a)}"><div class="plantuml-placeholder-card diagram-preview-placeholder-card"><div class="plantuml-placeholder-copy diagram-preview-placeholder-copy"><strong>PlantUML diagram</strong><span>Renders server-side when visible</span></div><button type="button" class="plantuml-placeholder-btn diagram-preview-placeholder-btn" data-plantuml-key="${l(t)}">Render</button></div><pre class="plantuml-source" hidden>${l(r)}</pre></div>`}function X({embedKey:t,label:e,target:a}){return`<span class="plantuml-shell diagram-preview-shell" data-plantuml-key="${l(t)}" data-plantuml-target="${l(a)}" data-plantuml-label="${l(e)}"><span class="plantuml-placeholder-card diagram-preview-placeholder-card"><span class="plantuml-placeholder-copy diagram-preview-placeholder-copy"><strong>${l(e)}</strong><span>Renders server-side when visible</span></span><button type="button" class="plantuml-placeholder-btn diagram-preview-placeholder-btn" data-plantuml-key="${l(t)}">Render</button></span><span class="plantuml-source" hidden></span></span>`}function F({embedKey:t,label:e,target:a}){return`<span class="excalidraw-embed-placeholder diagram-preview-shell" data-embed-key="${l(t)}" data-embed-target="${l(a)}" data-embed-label="${l(e)}"><span class="excalidraw-embed-placeholder-card diagram-preview-placeholder-card"><span class="excalidraw-embed-placeholder-copy diagram-preview-placeholder-copy"><strong>${l(e)}</strong><span>Loads when visible</span></span><button type="button" class="excalidraw-embed-placeholder-btn diagram-preview-placeholder-btn" data-embed-key="${l(t)}">Load diagram</button></span></span>`}function J(t=""){let e=t.toLowerCase().match(/\.(mp4|ogg|webm)$/i);return e&&B[`.${e[1].toLowerCase()}`]||null}function U(t=""){let e=String(t||"").trim();return/^[A-Za-z0-9_-]{11}$/.test(e)?e:null}function K(t){let e=t.hostname.toLowerCase(),a=null;return e==="youtu.be"||e==="www.youtu.be"?a=U(t.pathname.split("/").filter(Boolean)[0]||""):(e.includes("youtube")||e.includes("youtube-nocookie"))&&(t.pathname==="/watch"?a=U(t.searchParams.get("v")||""):t.pathname.startsWith("/embed/")&&(a=U(t.pathname.split("/").filter(Boolean)[1]||""))),a?`https://www.youtube-nocookie.com/embed/${a}`:null}function q(t=""){let e;try{e=new URL(String(t||"").trim())}catch{return null}if(e.protocol!=="https:")return null;let a=e.hostname.toLowerCase();if(D.has(a)){let c=K(e);return c?{embedUrl:c,type:"youtube"}:null}let r=J(e.pathname);return r?{mimeType:r,sourceUrl:e.toString(),type:"direct-video"}:null}function N({embedKey:t,kind:e,label:a,mimeType:r="",source:c,url:d}){let m=e==="youtube"?"YouTube video":"Video file",u=r?` data-video-embed-mime-type="${l(r)}"`:"";return`<span class="video-embed-placeholder video-embed-shell diagram-preview-shell" data-video-embed-key="${l(t)}" data-video-embed-kind="${l(e)}" data-video-embed-label="${l(a)}" data-video-embed-source="${l(c)}" data-video-embed-url="${l(d)}"${u}><span class="video-embed-placeholder-card diagram-preview-placeholder-card"><span class="video-embed-placeholder-copy diagram-preview-placeholder-copy"><strong>${l(a)}</strong><span>${l(m)}</span></span></span></span>`}function Q(t,e){let a=t.attrGet("src")||"",r=q(a);if(!r)return null;let c=k(t.content||t.attrGet("title")||""),d=r.type==="youtube"?r.embedUrl:r.sourceUrl,m=e.get(d)??0;e.set(d,m+1);let u=`video-${_(d)}-${m}`;return N({embedKey:u,kind:r.type,label:c||"Embedded video",mimeType:r.mimeType,source:d,url:r.type==="youtube"?r.embedUrl:r.sourceUrl})}function ee(t=""){let e=String(t??"").trim();return!e||e.startsWith("data:")||e.startsWith("blob:")||e.startsWith("#")||e.startsWith("//")||/^[a-zA-Z][a-zA-Z\d+.-]*:/u.test(e)||e.startsWith("/")}function te(t="",{attachmentApiPath:e,sourceFilePath:a}={}){if(!a||ee(t))return null;let r=R(a,t);return!r||!V(r)?null:`${e}?path=${encodeURIComponent(r)}`}function E(t,{excalidrawEmbedCounts:e,fileList:a,mermaidEmbedCounts:r,plantUmlEmbedCounts:c}){let d=/!\[\[([^\]|]+\.(?:excalidraw|mmd|mermaid|puml|plantuml))(?:\|([^\]]+))?\]\]|\[\[([^\]|]+)(?:\|([^\]]+))?\]\]/gi,m=0,u="",h;for(;(h=d.exec(t))!==null;){if(h.index>m&&(u+=G(t.slice(m,h.index))),h[1]){let s=h[1].trim(),y=(h[2]||s).trim();if(/\.excalidraw$/i.test(s)){let b=e.get(s)??0;e.set(s,b+1),u+=F({embedKey:`${s}#${b}`,label:k(y.replace(/\.excalidraw$/i,"")),target:s})}else if(/\.(?:mmd|mermaid)$/i.test(s)){let b=r.get(s)??0;r.set(s,b+1),u+=j({embedKey:`${s}#${b}`,label:k(y.replace(/\.(?:mmd|mermaid)$/i,"")),target:s})}else{let b=c.get(s)??0;c.set(s,b+1),u+=X({embedKey:`${s}#${b}`,label:k(y.replace(/\.(?:puml|plantuml)$/i,"")),target:s})}}else{let s=h[3].trim(),y=(h[4]||h[3]).trim(),b=A(s,a),I=b?"wiki-link":"wiki-link wiki-link-new",M=b?k(y):`Create "${s}"`;u+=`<a class="${I}" href="#" data-wiki-target="${l(s)}" title="${l(M)}">${P(y)}</a>`}m=d.lastIndex}return m<t.length&&(u+=G(t.slice(m))),u}function re(t=[],{attachmentApiPath:e="/api/attachment",sourceFilePath:a=""}={}){let r=z({highlight(o,n){if(n==="mermaid"||n==="plantuml"||n==="puml")return"";try{return n&&T.getLanguage(n)?T.highlight(o,{language:n}).value:T.highlightAuto(o).value}catch{return""}},html:!1,linkify:!0,typographer:!0});r.core.ruler.push("collabmd-source-lines",o=>{o.tokens.forEach(n=>{if(!n.map)return;let[i,w]=n.map,g=i+1,p=Math.max(w,i+1);(n.nesting===1||n.type==="fence"||n.type==="code_block"||n.type==="html_block")&&(n.attrSet("data-source-line",String(g)),n.attrSet("data-source-line-end",String(p)))})});let c=new Map,d=new Map,m=new Map,u=new Map,h=new Map,s=new Map,y=r.renderer.rules.fence,b=r.renderer.rules.image,I=r.renderer.rules.link_open,M=r.renderer.rules.table_open,Y=r.renderer.rules.table_close;return r.renderer.rules.fence=(o,n,i,w,g)=>{let p=o[n],f=p.info?p.info.trim().toLowerCase():"",$=p.attrGet("data-source-line"),C=p.attrGet("data-source-line-end"),L=$?` data-source-line="${$}" data-source-line-end="${C}"`:"";if(f==="mermaid"){let v=_(p.content),x=d.get(v)??0;return d.set(v,x+1),H({key:`mermaid-${v}-${x}`,sourceAttributes:L,sourceHash:v,sourceText:p.content})}if(f==="plantuml"||f==="puml"){let v=_(p.content),x=u.get(v)??0;return u.set(v,x+1),Z({key:`plantuml-${v}-${x}`,sourceAttributes:L,sourceHash:v,sourceText:p.content})}let W=S(y,o,n,i,w,g);return $?W.replace(/^<pre/,`<pre data-source-line="${$}" data-source-line-end="${C}"`):W},r.renderer.rules.list_item_open=(o,n,i,w,g)=>{let f=o[n+2]?.content??"";return(f.startsWith("[ ] ")||f.startsWith("[x] ")||f.startsWith("[X] "))&&o[n].attrJoin("class","task-list-item"),g.renderToken(o,n,i)},r.renderer.rules.text=(o,n)=>{let i=o[n].content;return i.startsWith("[x] ")||i.startsWith("[X] ")?`<input type="checkbox" checked disabled> ${E(i.slice(4),{excalidrawEmbedCounts:c,fileList:t,mermaidEmbedCounts:m,plantUmlEmbedCounts:h})}`:i.startsWith("[ ] ")?`<input type="checkbox" disabled> ${E(i.slice(4),{excalidrawEmbedCounts:c,fileList:t,mermaidEmbedCounts:m,plantUmlEmbedCounts:h})}`:E(i,{excalidrawEmbedCounts:c,fileList:t,mermaidEmbedCounts:m,plantUmlEmbedCounts:h})},r.renderer.rules.link_open=(o,n,i,w,g)=>(o[n].attrSet("target","_blank"),o[n].attrSet("rel","noopener noreferrer"),S(I,o,n,i,w,g)),r.renderer.rules.image=(o,n,i,w,g)=>{let p=o[n],f=te(p.attrGet("src")||"",{attachmentApiPath:e,sourceFilePath:a});f&&p.attrSet("src",f);let $=Q(p,s);return $||S(b,o,n,i,w,g)},r.renderer.rules.table_open=(o,n,i,w,g)=>`<div class="table-wrapper">${S(M,o,n,i,w,g)}`,r.renderer.rules.table_close=(o,n,i,w,g)=>`${S(Y,o,n,i,w,g)}</div>`,r}function ie({attachmentApiPath:t="/api/attachment",fileList:e=[],markdownText:a="",sourceFilePath:r=""}={}){let c=String(a);return{html:re(e,{attachmentApiPath:t,sourceFilePath:r}).render(c),stats:O(c)}}export{ie as compilePreviewDocument};
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
import{a as c,p as a}from"./chunk-R3DDMJHH.js";import"./chunk-775E65SU.js";var d=12;function u(h){return a(h)}var f=class{constructor({getFileList:e,onFileSelect:t}){this.getFileList=e,this.onFileSelect=t,this.overlay=document.getElementById("quickSwitcher"),this.input=document.getElementById("quickSwitcherInput"),this.resultsList=document.getElementById("quickSwitcherResults"),this.hint=document.getElementById("quickSwitcherHint"),this.filteredFiles=[],this.selectedIndex=0,this.isOpen=!1,this.bindEvents()}bindEvents(){this.overlay?.addEventListener("mousedown",e=>{e.target===this.overlay&&this.close()}),this.input?.addEventListener("input",()=>{this.filterFiles()}),this.input?.addEventListener("keydown",e=>{switch(e.key){case"ArrowDown":e.preventDefault(),this.moveSelection(1);break;case"ArrowUp":e.preventDefault(),this.moveSelection(-1);break;case"Enter":e.preventDefault(),this.confirmSelection();break;case"Escape":e.preventDefault(),this.close();break;case"Tab":e.preventDefault(),this.moveSelection(e.shiftKey?-1:1);break}})}open(){this.overlay&&(this.isOpen=!0,this.input.value="",this.selectedIndex=0,this.overlay.classList.add("visible"),this.filterFiles(),this._focusAfterTransition())}_focusAfterTransition(){this._cancelPendingFocus();let e=()=>{this._focusCleanup=null,this.input?.focus(),this.isOpen&&this.input&&document.activeElement!==this.input&&setTimeout(()=>this.input?.focus(),50)},t=i=>{(i.propertyName==="visibility"||i.propertyName==="opacity")&&(this.overlay.removeEventListener("transitionend",t),clearTimeout(s),e())};this.overlay.addEventListener("transitionend",t);let s=setTimeout(()=>{this.overlay.removeEventListener("transitionend",t),e()},160);this._focusCleanup=()=>{this.overlay.removeEventListener("transitionend",t),clearTimeout(s)}}_cancelPendingFocus(){this._focusCleanup&&(this._focusCleanup(),this._focusCleanup=null)}close(){this.overlay&&(this._cancelPendingFocus(),this.isOpen=!1,this.overlay.classList.remove("visible"),this.input.value="",this.resultsList.innerHTML="")}toggle(){this.isOpen?this.close():this.open()}filterFiles(){let e=this.input?.value.trim().toLowerCase()??"",t=this.getFileList?.()??[];e?this.filteredFiles=t.map(s=>{let i=this.fuzzyScore(s.toLowerCase(),e);return{filePath:s,score:i}}).filter(s=>s.score>0).sort((s,i)=>i.score-s.score).slice(0,d).map(s=>s.filePath):this.filteredFiles=t.slice(0,d),this.selectedIndex=0,this.renderResults(e)}fuzzyScore(e,t){let s=u(e),i=s.split("/").pop();if(i.includes(t))return 100+1/i.length;if(s.includes(t))return 50+1/s.length;let n=0,o=0,l=0;for(let r=0;r<s.length&&n<t.length;r++)s[r]===t[n]?(n++,l+=1,o+=l,(r===0||s[r-1]==="/"||s[r-1]==="-"||s[r-1]==="_"||s[r-1]===" ")&&(o+=5)):l=0;return n===t.length?o:0}renderResults(e){if(!this.resultsList)return;if(this.resultsList.innerHTML="",this.filteredFiles.length===0){this.hint&&(this.hint.textContent=e?"No files found":"No files in vault",this.hint.classList.remove("hidden"));return}this.hint&&this.hint.classList.add("hidden");let t=document.createDocumentFragment();this.filteredFiles.forEach((s,i)=>{let n=document.createElement("button");n.type="button",n.className="qs-result-item",i===this.selectedIndex&&n.classList.add("selected"),n.dataset.index=String(i);let o=u(s),l=o.split("/").pop(),r=o.includes("/")?o.substring(0,o.lastIndexOf("/")):"";n.innerHTML=`
|
|
2
|
+
<svg class="qs-result-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>
|
|
3
|
+
<span class="qs-result-name">${this.highlightMatch(l,e)}</span>
|
|
4
|
+
${r?`<span class="qs-result-path">${c(r)}</span>`:""}
|
|
5
|
+
`,n.addEventListener("click",()=>{this.selectedIndex=i,this.confirmSelection()}),n.addEventListener("mouseenter",()=>{this.selectedIndex=i,this.updateSelection()}),t.appendChild(n)}),this.resultsList.appendChild(t)}highlightMatch(e,t){if(!t)return c(e);let i=e.toLowerCase().indexOf(t);if(i>=0){let l=e.slice(0,i),r=e.slice(i,i+t.length),p=e.slice(i+t.length);return`${c(l)}<mark>${c(r)}</mark>${c(p)}`}let n="",o=0;for(let l=0;l<e.length;l++)o<t.length&&e[l].toLowerCase()===t[o]?(n+=`<mark>${c(e[l])}</mark>`,o++):n+=c(e[l]);return n}moveSelection(e){this.filteredFiles.length!==0&&(this.selectedIndex=(this.selectedIndex+e+this.filteredFiles.length)%this.filteredFiles.length,this.updateSelection())}updateSelection(){if(!this.resultsList)return;let e=this.resultsList.querySelectorAll(".qs-result-item");e.forEach((s,i)=>{s.classList.toggle("selected",i===this.selectedIndex)}),e[this.selectedIndex]?.scrollIntoView({block:"nearest"})}confirmSelection(){let e=this.filteredFiles[this.selectedIndex];e&&(this.close(),this.onFileSelect?.(e))}};export{f as QuickSwitcherController};
|