@nuniapp/widget 0.1.0 → 0.1.1
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/dist/index.js +1 -1
- package/dist/nuni.global.js +1 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
package/dist/nuni.global.js
CHANGED
|
@@ -324,4 +324,4 @@ a.item { color: inherit; text-decoration: none; }
|
|
|
324
324
|
@media (prefers-reduced-motion: reduce) {
|
|
325
325
|
* { transition: none !important; animation: none !important; }
|
|
326
326
|
}
|
|
327
|
-
`,this.pinLayer=q(`div`,{class:`pins`}),this.overlayLayer=q(`div`,{class:`overlay`}),this.uiLayer=q(`div`,{class:`ui`}),this.root.append(n,this.pinLayer,this.overlayLayer,this.uiLayer),this.api=new $n(e)}start(){document.body.appendChild(this.host),or(this.secret).then(e=>{this.secretHash=e,this.render()}),this.api.touch(location.origin),this.cleanups.push(this.api.onStatus(e=>{this.status=e,this.render()})),this.cleanups.push(this.api.onPages(e=>{this.pages=e,this.render()})),this.ownerToken&&this.watchSession(this.ownerToken),this.readDeepLink(),this.subscribePage(),this.cleanups.push(ar(()=>{this.readDeepLink(),this.subscribePage()}));let e=e=>this.onKeyDown(e),t=()=>this.scheduleLayout(),n=e=>this.onMessage(e);window.addEventListener(`keydown`,e,!0),window.addEventListener(`scroll`,t,{capture:!0,passive:!0}),window.addEventListener(`resize`,t,{passive:!0}),window.addEventListener(`message`,n),this.cleanups.push(()=>{window.removeEventListener(`keydown`,e,!0),window.removeEventListener(`scroll`,t,!0),window.removeEventListener(`resize`,t),window.removeEventListener(`message`,n)});let r=new MutationObserver(e=>{e.every(e=>this.host.contains(e.target)||e.target===this.host)||this.scheduleResolve()});r.observe(document.body,{childList:!0,subtree:!0,characterData:!0,attributes:!0,attributeFilter:[`class`,`style`,`hidden`,`open`,`id`]});let i=new ResizeObserver(()=>this.scheduleLayout());i.observe(document.documentElement),this.cleanups.push(()=>{r.disconnect(),i.disconnect()}),this.render()}destroy(){this.setPicking(!1),this.pageUnsub?.(),this.sessionUnsub?.();for(let e of this.cleanups)e();cancelAnimationFrame(this.layoutFrame),clearTimeout(this.resolveTimer),clearTimeout(this.toastTimer),this.host.remove(),this.api.close()}currentPageKey(){let e=new URL(location.href);return this.config.getPageKey?.(e)??o(e)}subscribePage(){let e=this.currentPageKey();e===this.pageKey&&this.pageUnsub||(this.pageKey=e,this.pageUnsub?.(),this.comments=[],this.extraComment=null,this.loaded=!1,this.placements.clear(),this.card=null,this.activeId=null,this.pageUnsub=this.api.onPage(e,e=>{let t=this.extraComment,n=t&&!e.some(e=>e._id===t._id)?[...e,t]:e;this.comments=n.sort((e,t)=>e.createdAt-t.createdAt),this.loaded=!0,this.resolvePlacements(!1),this.openDeepLink(),this.render()},()=>{}),this.render())}watchSession(e){this.sessionUnsub?.(),this.sessionUnsub=this.api.onSession(e,e=>{e.valid?this.ownerName=e.ownerName??`Owner`:(this.ownerName=null,this.ownerToken=null,Z(Q.session(this.config.project),null),this.sessionUnsub?.(),this.sessionUnsub=null),this.render()})}get isOwner(){return!!(this.ownerToken&&this.ownerName)}isMine(e){return!!this.secretHash&&e.authorKeyHash===this.secretHash}visibleComments(){return this.comments.filter(e=>e.status===`open`||this.showResolved)}scheduleResolve(){clearTimeout(this.resolveTimer),this.resolveTimer=window.setTimeout(()=>this.resolvePlacements(!0),200)}resolvePlacements(e){let t=new Set(this.comments.map(e=>e._id));for(let e of this.placements.keys())t.has(e)||this.placements.delete(e);for(let t of this.comments){let n=this.placements.get(t._id);if(e&&n?.element&&n.element.isConnected){let e=C(n.element),r=t.anchor.text;if(!r||e===r||be(e,r)>.8)continue}let r=Ie(t.anchor,document,{isIgnored:this.isIgnored});this.placements.set(t._id,{element:r.element,confidence:r.confidence})}this.renderPins(),this.layout(),e&&this.panelOpen&&this.render()}pinPoint(e){let t=this.placements.get(e._id)?.element;if(!t||!m(t))return null;let n=t.getBoundingClientRect();return{x:n.left+e.anchor.offset.x*n.width,y:n.top+e.anchor.offset.y*n.height}}scheduleLayout(){this.layoutFrame||(this.layoutFrame=requestAnimationFrame(()=>{this.layoutFrame=0,this.layout()}))}layout(){let e=window.innerWidth,t=window.innerHeight,n=[];this.pinPositions.clear();for(let r of this.visibleComments()){let i=this.pins.get(r._id);if(!i)continue;let a=this.pinPoint(r);if(i.hidden=!(a&&a.x>=-10&&a.y>=-10&&a.x<=e+10&&a.y<=t+10),!a)continue;let o=a.y,s=a.x;for(;n.some(e=>Math.abs(e.x-s)<14&&Math.abs(e.y-o)<14);)s+=18;n.push({x:s,y:o}),this.pinPositions.set(r._id,{x:s,y:o}),i.style.transform=`translate(${Math.round(s)}px, ${Math.round(o)}px)`}this.positionCard(),this.picking&&this.hoverEl&&this.renderHighlight()}setPicking(e){if(this.picking===e)return;this.picking=e;let t=document.documentElement;if(e){this.card=null,window.matchMedia(pr).matches&&(this.panelOpen=!1),t.classList.add(fr),this.injectCursorStyle(),document.addEventListener(`pointermove`,this.onPickMove,!0),document.addEventListener(`click`,this.onPickClick,!0);for(let e of[`pointerdown`,`mousedown`,`pointerup`,`mouseup`])document.addEventListener(e,this.swallow,{capture:!0,passive:!1})}else{t.classList.remove(fr),this.hoverEl=null,document.removeEventListener(`pointermove`,this.onPickMove,!0),document.removeEventListener(`click`,this.onPickClick,!0);for(let e of[`pointerdown`,`mousedown`,`pointerup`,`mouseup`])document.removeEventListener(e,this.swallow,!0)}this.render()}injectCursorStyle(){if(document.getElementById(`nuni-cursor-style`))return;let e=document.createElement(`style`);e.id=`nuni-cursor-style`,e.textContent=`html.${fr}, html.${fr} * { cursor: crosshair !important; }`,document.head.appendChild(e),this.cleanups.push(()=>e.remove())}fromPage(e){if(e.composedPath().includes(this.host))return null;let t=e.target;return t instanceof Element?t:null}renderHighlight(){if(this.overlayLayer.replaceChildren(),!this.picking)return;this.overlayLayer.append(q(`div`,{class:`pick-hint`},`Click anything to comment · Esc to cancel`));let e=this.hoverEl;if(!e||e===document.documentElement)return;let t=e.getBoundingClientRect(),n=q(`div`,{class:`highlight`},q(`span`,{class:`highlight-label`},hr(e)));Object.assign(n.style,{left:`${t.left-2}px`,top:`${t.top-2}px`,width:`${t.width+4}px`,height:`${t.height+4}px`}),this.overlayLayer.append(n)}onKeyDown(e){let t=e.composedPath().includes(this.host);if(e.key===`Escape`){if(this.picking)this.setPicking(!1);else if(this.card)this.closeCard();else if(this.panelOpen)this.togglePanel(!1);else return;e.stopPropagation();return}t||mr(e.target)||e.metaKey||e.ctrlKey||e.altKey||e.repeat||(e.key===`c`||e.key===`C`)&&(e.preventDefault(),this.setPicking(!this.picking))}openClaim(){let e=new URL(`${this.config.appUrl}/dashboard/claim`);e.searchParams.set(`project`,this.config.project),e.searchParams.set(`origin`,location.origin),window.open(e.toString(),`nuni-claim`,`popup,width=480,height=680`)||(location.href=e.toString())}onMessage(e){let t;try{t=new URL(this.config.appUrl).origin}catch{return}if(e.origin!==t)return;let n=e.data;n&&n.type===`nuni:session`&&n.project===this.config.project&&typeof n.token==`string`&&n.token.startsWith(`nuni_s_`)&&(this.ownerToken=n.token,Z(Q.session(this.config.project),n.token),this.watchSession(n.token),this.showToast(`You're signed in as the owner`))}signOut(){this.ownerToken&&this.api.signOut(this.ownerToken),Z(Q.session(this.config.project),null),this.ownerToken=null,this.ownerName=null,this.sessionUnsub?.(),this.sessionUnsub=null,this.render()}readDeepLink(){let e=new URL(location.href),t=e.searchParams.get(`nuni`);t&&(this.deepLinkId=t,e.searchParams.delete(`nuni`),history.replaceState(history.state,``,e.toString()))}openDeepLink(){let e=this.deepLinkId;if(!e||!this.loaded)return;this.deepLinkId=null;let t=this.comments.find(t=>t._id===e);if(t){this.focusDeepLinked(t);return}this.api.getComment(e).then(e=>{if(!e||e.page.path!==this.pageKey){this.showToast(`That comment was deleted or is on another page`);return}this.extraComment=e,this.comments=[...this.comments.filter(t=>t._id!==e._id),e],this.resolvePlacements(!1),this.focusDeepLinked(e)})}focusDeepLinked(e){e.status===`resolved`&&!this.showResolved&&(this.showResolved=!0,this.renderPins()),this.focusComment(e._id)}focusComment(e){this.placements.get(e)?.element?.scrollIntoView({block:`center`,behavior:`smooth`}),this.activeId=e,this.card={kind:`thread`,id:e},window.matchMedia(pr).matches&&(this.panelOpen=!1),this.render(),setTimeout(()=>this.scheduleLayout(),400)}async submitDraft(e,t,n){let r=n.trim().slice(0,a.nameMaxLength),i=t.trim();if(!r)return this.setDraftError(e,`Enter your name`);if(!i)return this.setDraftError(e,`Write a comment first`);if(i.length>a.bodyMaxLength)return this.setDraftError(e,`Comments are limited to ${a.bodyMaxLength} characters`);this.name=r,Z(Q.name,r),e.sending=!0,e.error=void 0,this.render();let o=c(location.href);try{let t=await this.api.createComment({body:i,authorName:r,authorSecret:this.secret,page:{...o,path:this.pageKey,title:document.title.slice(0,300)},anchor:e.anchor,viewport:{w:window.innerWidth,h:window.innerHeight,dpr:window.devicePixelRatio||1}});this.placements.set(t,{element:e.element,confidence:`exact`}),this.card?.kind===`composer`&&this.card.draft===e&&(this.card=null),this.showToast(`Comment added`)}catch(t){e.sending=!1,e.error=t instanceof Zn?t.message:`Couldn't post the comment`}this.render()}setDraftError(e,t){e.error=t,this.render()}async act(e,t,n){let r=this.card;r?.kind===`thread`&&(r.busy=!0,r.error=void 0,this.render());try{return await t(),n&&this.showToast(n),this.card?.kind===`thread`&&this.card.id===e&&(this.card.busy=!1,this.card.editing=!1),this.render(),!0}catch(t){return this.card?.kind===`thread`&&this.card.id===e&&(this.card.busy=!1,this.card.error=t instanceof Error?t.message:`Something went wrong`),this.render(),!1}}resolveComment(e){let t=this.ownerToken;t&&this.act(e._id,()=>this.api.resolve(e._id,t),`Resolved`).then(t=>{t&&!this.showResolved&&this.card?.kind===`thread`&&this.card.id===e._id&&this.closeCard()})}reopenComment(e){let t=this.ownerToken;t&&this.act(e._id,()=>this.api.reopen(e._id,t),`Reopened`)}deleteComment(e){if(!window.confirm(`Delete this comment? This can't be undone.`))return;let t=this.ownerToken,n=this.isMine(e)?()=>this.api.deleteOwn(e._id,this.secret):t?()=>this.api.remove(e._id,t):null;n&&this.act(e._id,n,`Deleted`).then(t=>{t&&(this.extraComment?._id===e._id&&(this.extraComment=null),this.comments=this.comments.filter(t=>t._id!==e._id),this.placements.delete(e._id),this.closeCard())})}saveEdit(e,t){this.act(e._id,()=>this.api.editOwn(e._id,this.secret,t),`Saved`)}showToast(e){this.toast=e,clearTimeout(this.toastTimer),this.toastTimer=window.setTimeout(()=>{this.toast=null,this.render()},2400),this.render()}togglePanel(e=!this.panelOpen){this.panelOpen=e,e&&window.matchMedia(pr).matches&&(this.card=null),this.render()}closeCard(){this.card=null,this.activeId=null,this.render()}render(){this.renderPins(),this.renderUi(),this.renderHighlight(),this.layout()}renderPins(){let e=this.visibleComments(),t=new Set(e.map(e=>e._id));for(let[e,n]of this.pins)t.has(e)||(n.remove(),this.pins.delete(e));for(let t of e){let e=this.pins.get(t._id);if(!e){e=q(`button`,{class:`pin`,type:`button`,hidden:!0});let n=t._id;e.addEventListener(`click`,e=>{e.stopPropagation(),this.card?.kind===`thread`&&this.card.id===n?this.closeCard():(this.activeId=n,this.card={kind:`thread`,id:n},this.render())}),this.pins.set(t._id,e),this.pinLayer.append(e)}e.textContent=tr(t.authorName),e.style.background=nr(t.authorName),e.setAttribute(`aria-label`,`Comment by ${t.authorName}: ${t.body.slice(0,80)}`),e.dataset.status=t.status,e.dataset.active=String(this.activeId===t._id),e.dataset.confidence=this.placements.get(t._id)?.confidence??`lost`}if(this.pinLayer.querySelector(`.pin-draft`)?.remove(),this.card?.kind===`composer`){let{draft:e}=this.card,t=e.element.getBoundingClientRect(),n=t.left+e.anchor.offset.x*t.width,r=t.top+e.anchor.offset.y*t.height,i=q(`div`,{class:`pin pin-draft pin-pending`,"aria-hidden":`true`},this.name?tr(this.name):`+`);i.style.background=this.name?nr(this.name):`var(--n-accent)`,i.style.transform=`translate(${Math.round(n)}px, ${Math.round(r)}px)`,this.pinLayer.append(i)}}renderUi(){let e=[this.renderToolbar()];this.panelOpen&&e.push(this.renderPanel());let t=this.renderCard();t&&e.push(t),this.toast&&e.push(q(`div`,{class:`toast`,role:`status`},this.toast));let n=this.root.activeElement,r=n?.dataset.focusKey,i=n instanceof HTMLTextAreaElement||n instanceof HTMLInputElement?{start:n.selectionStart,end:n.selectionEnd}:null;if(this.uiLayer.replaceChildren(...e),r){let e=this.uiLayer.querySelector(`[data-focus-key="${r}"]`);e?.focus(),i&&(e instanceof HTMLTextAreaElement||e instanceof HTMLInputElement)&&e.setSelectionRange(i.start,i.end)}this.positionCard()}renderToolbar(){let e=this.comments.filter(e=>e.status===`open`).length;return q(`div`,{class:`toolbar`,role:`toolbar`,"aria-label":`Nuni comments`},q(`button`,{class:`tb-btn`,type:`button`,"aria-pressed":String(this.picking),"aria-label":this.picking?`Cancel adding a comment`:`Add a comment`,title:`Add a comment (C)`,onclick:()=>this.setPicking(!this.picking)},J(X.comment),q(`span`,{class:`tb-label`},this.picking?`Pick an element`:`Comment`)),q(`button`,{class:`tb-btn`,type:`button`,"aria-pressed":String(this.panelOpen),"aria-label":`Comments on this page: ${e} open`,title:`All comments`,onclick:()=>this.togglePanel()},J(X.list),q(`span`,{class:`tb-count`},String(e))))}renderPanel(){let e=this.comments.filter(e=>e.status===`open`),t=this.comments.filter(e=>e.status===`resolved`),n=this.tab===`open`?e:t,r=n.filter(e=>this.placements.get(e._id)?.element),i=n.filter(e=>!this.placements.get(e._id)?.element),a=this.pages.filter(e=>e.path!==this.pageKey),o=e=>q(`button`,{class:`item`,type:`button`,onclick:()=>{e.status===`resolved`&&!this.showResolved&&(this.showResolved=!0,Z(Q.showResolved,`1`)),this.focusComment(e._id)}},q(`div`,{class:`row`},q(`span`,{class:`avatar`,style:`background:${nr(e.authorName)}`},tr(e.authorName)),q(`span`,{class:`author`},e.authorName),q(`span`,{class:`meta`},er(e.createdAt)),e.page.origin===location.origin?null:q(`span`,{class:`badge`,title:e.page.origin},new URL(e.page.origin).host)),q(`div`,{class:`item-text`},e.body)),s=[];if(this.loaded?n.length?(s.push(...r.map(o)),i.length&&(s.push(q(`div`,{class:`section-label`},`Couldn't find on this page`)),s.push(...i.map(o)))):s.push(q(`div`,{class:`empty`},this.tab===`open`?`No open comments on this page. Press C to add one.`:`Nothing resolved yet.`)):s.push(q(`div`,{class:`empty`},`Loading…`)),a.length){s.push(q(`div`,{class:`section-label`},`Other pages`));for(let e of a.slice(0,20)){let t=e.path.includes(`#`)?location.origin+e.path:location.origin+e.path+location.search;s.push(q(`a`,{class:`item`,href:t},q(`div`,{class:`row`},q(`span`,{class:`author`},e.path),q(`span`,{class:`spacer`}),q(`span`,{class:`badge`},`${e.count} open`))))}}return q(`div`,{class:`panel`,role:`dialog`,"aria-label":`Comments`},q(`div`,{class:`panel-head`},q(`div`,{class:`panel-title`},`Comments`),q(`button`,{class:`btn btn-ghost btn-icon`,type:`button`,"aria-label":`Close`,onclick:()=>this.togglePanel(!1)},J(X.close))),q(`div`,{class:`tabs`,role:`tablist`},q(`button`,{class:`tab`,role:`tab`,type:`button`,"aria-selected":String(this.tab===`open`),onclick:()=>{this.tab=`open`,this.render()}},`Open (${e.length})`),q(`button`,{class:`tab`,role:`tab`,type:`button`,"aria-selected":String(this.tab===`resolved`),onclick:()=>{this.tab=`resolved`,this.render()}},`Resolved (${t.length})`)),q(`div`,{class:`panel-list`},...s),this.renderPanelFooter())}renderPanelFooter(){let e=q(`label`,{class:`toggle`},q(`input`,{type:`checkbox`,checked:this.showResolved,onchange:e=>{this.showResolved=e.target.checked,Z(Q.showResolved,this.showResolved?`1`:null),this.render()}}),`Show resolved pins`),t;return t=this.isOwner?q(`div`,{class:`row`},q(`span`,{class:`badge badge-ok`},J(X.check),`Owner`),q(`span`,{class:`meta`},this.ownerName??``),q(`span`,{class:`spacer`}),q(`a`,{class:`link`,href:`${this.config.appUrl}/dashboard/p/${this.config.project}`,target:`_blank`,rel:`noopener`},`Dashboard`),q(`button`,{class:`link`,type:`button`,onclick:()=>this.signOut()},`Sign out`)):this.status.claimed?q(`div`,{class:`row`},q(`span`,{class:`meta`},`Managed by ${this.status.ownerName??`the owner`}`),q(`span`,{class:`spacer`}),q(`button`,{class:`link`,type:`button`,onclick:()=>this.openClaim()},`Owner sign in`)):q(`div`,{class:`row`},q(`span`,{class:`meta`},`Own this website?`),q(`span`,{class:`spacer`}),q(`button`,{class:`btn`,type:`button`,onclick:()=>this.openClaim()},J(X.github),`Claim Nuni`)),q(`div`,{class:`panel-foot`},e,t)}renderCard(){let e=this.card;if(!e)return null;let t=`card${window.matchMedia(pr).matches?` sheet`:``}`;if(e.kind===`composer`){let{draft:n}=e,r=!this.name,i=q(`input`,{class:`field`,placeholder:`Your name`,value:this.name,maxlength:a.nameMaxLength,autocomplete:`name`,"data-focus-key":`name`,"aria-label":`Your name`}),o=q(`textarea`,{class:`field`,placeholder:`Leave a comment`,maxlength:a.bodyMaxLength,"data-focus-key":`body`,"aria-label":`Comment`}),s=this.uiLayer.querySelector(`[data-focus-key="body"]`);s&&(o.value=s.value);let c=this.uiLayer.querySelector(`[data-focus-key="name"]`);c&&(i.value=c.value);let l=()=>void this.submitDraft(n,o.value,r?i.value:this.name);return o.addEventListener(`keydown`,e=>{e.key===`Enter`&&(e.metaKey||e.ctrlKey)&&(e.preventDefault(),l())}),q(`form`,{class:t,"data-card":`composer`,onsubmit:e=>{e.preventDefault(),l()}},q(`div`,{class:`card-body`},r?i:q(`div`,{class:`row`},q(`span`,{class:`avatar`,style:`background:${nr(this.name)}`},tr(this.name)),q(`span`,{class:`author`},this.name),q(`span`,{class:`spacer`}),q(`button`,{class:`link`,type:`button`,onclick:()=>{this.name=``,this.render()}},`Not you?`)),o,n.error?q(`div`,{class:`error`,role:`alert`},n.error):null,q(`div`,{class:`row`},q(`span`,{class:`kbd`},`⌘ + Enter`),q(`span`,{class:`spacer`}),q(`button`,{class:`btn btn-ghost`,type:`button`,onclick:()=>this.closeCard()},`Cancel`),q(`button`,{class:`btn btn-primary`,type:`submit`,disabled:!!n.sending},J(X.send),n.sending?`Posting…`:`Post`))))}let n=this.comments.find(t=>t._id===e.id);if(!n)return null;let r=this.isMine(n),i=this.isOwner,o=this.placements.get(n._id),s;if(e.editing){let t=q(`textarea`,{class:`field`,maxlength:a.bodyMaxLength,"data-focus-key":`edit`}),r=this.uiLayer.querySelector(`[data-focus-key="edit"]`);t.value=r?r.value:n.body,s=q(`div`,{class:`card-body`},t,q(`div`,{class:`row`},q(`span`,{class:`spacer`}),q(`button`,{class:`btn btn-ghost`,type:`button`,onclick:()=>{e.editing=!1,this.render()}},`Cancel`),q(`button`,{class:`btn btn-primary`,type:`button`,disabled:!!e.busy,onclick:()=>this.saveEdit(n,t.value)},`Save`)))}else s=q(`div`,{class:`card-body`},q(`div`,{class:`card-head`},q(`span`,{class:`avatar`,style:`background:${nr(n.authorName)}`},tr(n.authorName)),q(`span`,{class:`author`},n.authorName),q(`span`,{class:`meta`},er(n.createdAt)+(n.editedAt?` · edited`:``)),q(`span`,{class:`spacer`}),q(`button`,{class:`btn btn-ghost btn-icon`,type:`button`,"aria-label":`Close`,onclick:()=>this.closeCard()},J(X.close))),q(`div`,{class:`comment-body`},n.body),q(`div`,{class:`row`},n.status===`resolved`?q(`span`,{class:`badge badge-ok`},J(X.check),`Resolved`):null,n.page.origin===location.origin?null:q(`span`,{class:`badge`,title:`Left on ${n.page.origin}`},new URL(n.page.origin).host),o?.confidence===`low`?q(`span`,{class:`badge`,title:`The page changed; this pin is a best guess`},`Approximate`):null,o?.element?null:q(`span`,{class:`badge`,title:`Originally on: ${n.anchor.text||n.anchor.tag}`},`Element not found`)),e.error?q(`div`,{class:`error`,role:`alert`},e.error):null);let c=[];return e.editing||(i&&c.push(n.status===`open`?q(`button`,{class:`btn`,type:`button`,disabled:!!e.busy,onclick:()=>this.resolveComment(n)},J(X.check),`Resolve`):q(`button`,{class:`btn`,type:`button`,disabled:!!e.busy,onclick:()=>this.reopenComment(n)},J(X.undo),`Reopen`)),c.push(q(`span`,{class:`spacer`})),r&&c.push(q(`button`,{class:`btn btn-ghost btn-icon`,type:`button`,"aria-label":`Edit`,title:`Edit`,onclick:()=>{e.editing=!0,this.render()}},J(X.edit))),(r||i)&&c.push(q(`button`,{class:`btn btn-ghost btn-icon btn-danger`,type:`button`,"aria-label":`Delete`,title:`Delete`,disabled:!!e.busy,onclick:()=>this.deleteComment(n)},J(X.trash)))),q(`div`,{class:t,"data-card":`thread`,role:`dialog`,"aria-label":`Comment by ${n.authorName}`},s,c.length>1||i?q(`div`,{class:`actions`},...c):null)}positionCard(){let e=this.uiLayer.querySelector(`[data-card]`);if(!e||e.classList.contains(`sheet`))return;let t=null;if(this.card?.kind===`composer`){let{draft:e}=this.card,n=e.element.getBoundingClientRect();t={x:n.left+e.anchor.offset.x*n.width,y:n.top+e.anchor.offset.y*n.height}}else if(this.card?.kind===`thread`){let e=this.comments.find(e=>this.card?.kind===`thread`&&e._id===this.card.id);t=e?this.pinPositions.get(e._id)??this.pinPoint(e):null}let n=e.offsetWidth||320,r=e.offsetHeight||160,i=window.innerWidth,a=window.innerHeight,o,s;t?(o=t.x+36,s=t.y-28,o+n>i-12&&(o=t.x-n-12)):(o=i-n-16,s=a-r-72),o=Math.max(12,Math.min(o,i-n-12)),s=Math.max(12,Math.min(s,a-r-12)),e.style.left=`${Math.round(o)}px`,e.style.top=`${Math.round(s)}px`}focusComposer(){requestAnimationFrame(()=>{this.uiLayer.querySelector(this.name?`[data-focus-key="body"]`:`[data-focus-key="name"]`)?.focus()})}};let $=null;function _r(e){let t={destroy(){}};if(typeof window>`u`||typeof document>`u`)return t;if(!r(e.project))return console.warn(`[nuni] "${e.project}" is not a valid project ID. Run \`npx @nuniapp/cli init\` to get one.`),t;if($?.project===e.project)return vr($);$&&yr($);let n=l(e),i={project:e.project,widget:null,timer:0,handles:0};$=i;let a=()=>{if($===i){if(!document.body){i.timer=window.setTimeout(a,50);return}i.widget=new gr(n),i.widget.start()}},o=window.requestIdleCallback;return o?o(a,{timeout:1500}):i.timer=window.setTimeout(a,1),vr(i)}function vr(e){e.handles++;let t=!1;return{destroy(){t||(t=!0,e.handles--,e.handles<=0&&$===e&&yr(e))}}}function yr(e){clearTimeout(e.timer),e.widget?.destroy(),e.widget=null,$===e&&($=null)}window.Nuni={init:_r,version:`0.1.0`};let br=document.currentScript??document.querySelector(`script[data-project][src*='nuni']`),xr=br?.dataset.project;xr&&_r({project:xr,convexUrl:br?.dataset.convexUrl,convexSiteUrl:br?.dataset.convexSiteUrl,appUrl:br?.dataset.appUrl})})();
|
|
327
|
+
`,this.pinLayer=q(`div`,{class:`pins`}),this.overlayLayer=q(`div`,{class:`overlay`}),this.uiLayer=q(`div`,{class:`ui`}),this.root.append(n,this.pinLayer,this.overlayLayer,this.uiLayer),this.api=new $n(e)}start(){document.body.appendChild(this.host),or(this.secret).then(e=>{this.secretHash=e,this.render()}),this.api.touch(location.origin),this.cleanups.push(this.api.onStatus(e=>{this.status=e,this.render()})),this.cleanups.push(this.api.onPages(e=>{this.pages=e,this.render()})),this.ownerToken&&this.watchSession(this.ownerToken),this.readDeepLink(),this.subscribePage(),this.cleanups.push(ar(()=>{this.readDeepLink(),this.subscribePage()}));let e=e=>this.onKeyDown(e),t=()=>this.scheduleLayout(),n=e=>this.onMessage(e);window.addEventListener(`keydown`,e,!0),window.addEventListener(`scroll`,t,{capture:!0,passive:!0}),window.addEventListener(`resize`,t,{passive:!0}),window.addEventListener(`message`,n),this.cleanups.push(()=>{window.removeEventListener(`keydown`,e,!0),window.removeEventListener(`scroll`,t,!0),window.removeEventListener(`resize`,t),window.removeEventListener(`message`,n)});let r=new MutationObserver(e=>{e.every(e=>this.host.contains(e.target)||e.target===this.host)||this.scheduleResolve()});r.observe(document.body,{childList:!0,subtree:!0,characterData:!0,attributes:!0,attributeFilter:[`class`,`style`,`hidden`,`open`,`id`]});let i=new ResizeObserver(()=>this.scheduleLayout());i.observe(document.documentElement),this.cleanups.push(()=>{r.disconnect(),i.disconnect()}),this.render()}destroy(){this.setPicking(!1),this.pageUnsub?.(),this.sessionUnsub?.();for(let e of this.cleanups)e();cancelAnimationFrame(this.layoutFrame),clearTimeout(this.resolveTimer),clearTimeout(this.toastTimer),this.host.remove(),this.api.close()}currentPageKey(){let e=new URL(location.href);return this.config.getPageKey?.(e)??o(e)}subscribePage(){let e=this.currentPageKey();e===this.pageKey&&this.pageUnsub||(this.pageKey=e,this.pageUnsub?.(),this.comments=[],this.extraComment=null,this.loaded=!1,this.placements.clear(),this.card=null,this.activeId=null,this.pageUnsub=this.api.onPage(e,e=>{let t=this.extraComment,n=t&&!e.some(e=>e._id===t._id)?[...e,t]:e;this.comments=n.sort((e,t)=>e.createdAt-t.createdAt),this.loaded=!0,this.resolvePlacements(!1),this.openDeepLink(),this.render()},()=>{}),this.render())}watchSession(e){this.sessionUnsub?.(),this.sessionUnsub=this.api.onSession(e,e=>{e.valid?this.ownerName=e.ownerName??`Owner`:(this.ownerName=null,this.ownerToken=null,Z(Q.session(this.config.project),null),this.sessionUnsub?.(),this.sessionUnsub=null),this.render()})}get isOwner(){return!!(this.ownerToken&&this.ownerName)}isMine(e){return!!this.secretHash&&e.authorKeyHash===this.secretHash}visibleComments(){return this.comments.filter(e=>e.status===`open`||this.showResolved)}scheduleResolve(){clearTimeout(this.resolveTimer),this.resolveTimer=window.setTimeout(()=>this.resolvePlacements(!0),200)}resolvePlacements(e){let t=new Set(this.comments.map(e=>e._id));for(let e of this.placements.keys())t.has(e)||this.placements.delete(e);for(let t of this.comments){let n=this.placements.get(t._id);if(e&&n?.element&&n.element.isConnected){let e=C(n.element),r=t.anchor.text;if(!r||e===r||be(e,r)>.8)continue}let r=Ie(t.anchor,document,{isIgnored:this.isIgnored});this.placements.set(t._id,{element:r.element,confidence:r.confidence})}this.renderPins(),this.layout(),e&&this.panelOpen&&this.render()}pinPoint(e){let t=this.placements.get(e._id)?.element;if(!t||!m(t))return null;let n=t.getBoundingClientRect();return{x:n.left+e.anchor.offset.x*n.width,y:n.top+e.anchor.offset.y*n.height}}scheduleLayout(){this.layoutFrame||(this.layoutFrame=requestAnimationFrame(()=>{this.layoutFrame=0,this.layout()}))}layout(){let e=window.innerWidth,t=window.innerHeight,n=[];this.pinPositions.clear();for(let r of this.visibleComments()){let i=this.pins.get(r._id);if(!i)continue;let a=this.pinPoint(r);if(i.hidden=!(a&&a.x>=-10&&a.y>=-10&&a.x<=e+10&&a.y<=t+10),!a)continue;let o=a.y,s=a.x;for(;n.some(e=>Math.abs(e.x-s)<14&&Math.abs(e.y-o)<14);)s+=18;n.push({x:s,y:o}),this.pinPositions.set(r._id,{x:s,y:o}),i.style.transform=`translate(${Math.round(s)}px, ${Math.round(o)}px)`}this.positionCard(),this.picking&&this.hoverEl&&this.renderHighlight()}setPicking(e){if(this.picking===e)return;this.picking=e;let t=document.documentElement;if(e){this.card=null,window.matchMedia(pr).matches&&(this.panelOpen=!1),t.classList.add(fr),this.injectCursorStyle(),document.addEventListener(`pointermove`,this.onPickMove,!0),document.addEventListener(`click`,this.onPickClick,!0);for(let e of[`pointerdown`,`mousedown`,`pointerup`,`mouseup`])document.addEventListener(e,this.swallow,{capture:!0,passive:!1})}else{t.classList.remove(fr),this.hoverEl=null,document.removeEventListener(`pointermove`,this.onPickMove,!0),document.removeEventListener(`click`,this.onPickClick,!0);for(let e of[`pointerdown`,`mousedown`,`pointerup`,`mouseup`])document.removeEventListener(e,this.swallow,!0)}this.render()}injectCursorStyle(){if(document.getElementById(`nuni-cursor-style`))return;let e=document.createElement(`style`);e.id=`nuni-cursor-style`,e.textContent=`html.${fr}, html.${fr} * { cursor: crosshair !important; }`,document.head.appendChild(e),this.cleanups.push(()=>e.remove())}fromPage(e){if(e.composedPath().includes(this.host))return null;let t=e.target;return t instanceof Element?t:null}renderHighlight(){if(this.overlayLayer.replaceChildren(),!this.picking)return;this.overlayLayer.append(q(`div`,{class:`pick-hint`},`Click anything to comment · Esc to cancel`));let e=this.hoverEl;if(!e||e===document.documentElement)return;let t=e.getBoundingClientRect(),n=q(`div`,{class:`highlight`},q(`span`,{class:`highlight-label`},hr(e)));Object.assign(n.style,{left:`${t.left-2}px`,top:`${t.top-2}px`,width:`${t.width+4}px`,height:`${t.height+4}px`}),this.overlayLayer.append(n)}onKeyDown(e){let t=e.composedPath().includes(this.host);if(e.key===`Escape`){if(this.picking)this.setPicking(!1);else if(this.card)this.closeCard();else if(this.panelOpen)this.togglePanel(!1);else return;e.stopPropagation();return}t||mr(e.target)||e.metaKey||e.ctrlKey||e.altKey||e.repeat||(e.key===`c`||e.key===`C`)&&(e.preventDefault(),this.setPicking(!this.picking))}openClaim(){let e=new URL(`${this.config.appUrl}/dashboard/claim`);e.searchParams.set(`project`,this.config.project),e.searchParams.set(`origin`,location.origin),window.open(e.toString(),`nuni-claim`,`popup,width=480,height=680`)||(location.href=e.toString())}onMessage(e){let t;try{t=new URL(this.config.appUrl).origin}catch{return}if(e.origin!==t)return;let n=e.data;n&&n.type===`nuni:session`&&n.project===this.config.project&&typeof n.token==`string`&&n.token.startsWith(`nuni_s_`)&&(this.ownerToken=n.token,Z(Q.session(this.config.project),n.token),this.watchSession(n.token),this.showToast(`You're signed in as the owner`))}signOut(){this.ownerToken&&this.api.signOut(this.ownerToken),Z(Q.session(this.config.project),null),this.ownerToken=null,this.ownerName=null,this.sessionUnsub?.(),this.sessionUnsub=null,this.render()}readDeepLink(){let e=new URL(location.href),t=e.searchParams.get(`nuni`);t&&(this.deepLinkId=t,e.searchParams.delete(`nuni`),history.replaceState(history.state,``,e.toString()))}openDeepLink(){let e=this.deepLinkId;if(!e||!this.loaded)return;this.deepLinkId=null;let t=this.comments.find(t=>t._id===e);if(t){this.focusDeepLinked(t);return}this.api.getComment(e).then(e=>{if(!e||e.page.path!==this.pageKey){this.showToast(`That comment was deleted or is on another page`);return}this.extraComment=e,this.comments=[...this.comments.filter(t=>t._id!==e._id),e],this.resolvePlacements(!1),this.focusDeepLinked(e)})}focusDeepLinked(e){e.status===`resolved`&&!this.showResolved&&(this.showResolved=!0,this.renderPins()),this.focusComment(e._id)}focusComment(e){this.placements.get(e)?.element?.scrollIntoView({block:`center`,behavior:`smooth`}),this.activeId=e,this.card={kind:`thread`,id:e},window.matchMedia(pr).matches&&(this.panelOpen=!1),this.render(),setTimeout(()=>this.scheduleLayout(),400)}async submitDraft(e,t,n){let r=n.trim().slice(0,a.nameMaxLength),i=t.trim();if(!r)return this.setDraftError(e,`Enter your name`);if(!i)return this.setDraftError(e,`Write a comment first`);if(i.length>a.bodyMaxLength)return this.setDraftError(e,`Comments are limited to ${a.bodyMaxLength} characters`);this.name=r,Z(Q.name,r),e.sending=!0,e.error=void 0,this.render();let o=c(location.href);try{let t=await this.api.createComment({body:i,authorName:r,authorSecret:this.secret,page:{...o,path:this.pageKey,title:document.title.slice(0,300)},anchor:e.anchor,viewport:{w:window.innerWidth,h:window.innerHeight,dpr:window.devicePixelRatio||1}});this.placements.set(t,{element:e.element,confidence:`exact`}),this.card?.kind===`composer`&&this.card.draft===e&&(this.card=null),this.showToast(`Comment added`)}catch(t){e.sending=!1,e.error=t instanceof Zn?t.message:`Couldn't post the comment`}this.render()}setDraftError(e,t){e.error=t,this.render()}async act(e,t,n){let r=this.card;r?.kind===`thread`&&(r.busy=!0,r.error=void 0,this.render());try{return await t(),n&&this.showToast(n),this.card?.kind===`thread`&&this.card.id===e&&(this.card.busy=!1,this.card.editing=!1),this.render(),!0}catch(t){return this.card?.kind===`thread`&&this.card.id===e&&(this.card.busy=!1,this.card.error=t instanceof Error?t.message:`Something went wrong`),this.render(),!1}}resolveComment(e){let t=this.ownerToken;t&&this.act(e._id,()=>this.api.resolve(e._id,t),`Resolved`).then(t=>{t&&!this.showResolved&&this.card?.kind===`thread`&&this.card.id===e._id&&this.closeCard()})}reopenComment(e){let t=this.ownerToken;t&&this.act(e._id,()=>this.api.reopen(e._id,t),`Reopened`)}deleteComment(e){if(!window.confirm(`Delete this comment? This can't be undone.`))return;let t=this.ownerToken,n=this.isMine(e)?()=>this.api.deleteOwn(e._id,this.secret):t?()=>this.api.remove(e._id,t):null;n&&this.act(e._id,n,`Deleted`).then(t=>{t&&(this.extraComment?._id===e._id&&(this.extraComment=null),this.comments=this.comments.filter(t=>t._id!==e._id),this.placements.delete(e._id),this.closeCard())})}saveEdit(e,t){this.act(e._id,()=>this.api.editOwn(e._id,this.secret,t),`Saved`)}showToast(e){this.toast=e,clearTimeout(this.toastTimer),this.toastTimer=window.setTimeout(()=>{this.toast=null,this.render()},2400),this.render()}togglePanel(e=!this.panelOpen){this.panelOpen=e,e&&window.matchMedia(pr).matches&&(this.card=null),this.render()}closeCard(){this.card=null,this.activeId=null,this.render()}render(){this.renderPins(),this.renderUi(),this.renderHighlight(),this.layout()}renderPins(){let e=this.visibleComments(),t=new Set(e.map(e=>e._id));for(let[e,n]of this.pins)t.has(e)||(n.remove(),this.pins.delete(e));for(let t of e){let e=this.pins.get(t._id);if(!e){e=q(`button`,{class:`pin`,type:`button`,hidden:!0});let n=t._id;e.addEventListener(`click`,e=>{e.stopPropagation(),this.card?.kind===`thread`&&this.card.id===n?this.closeCard():(this.activeId=n,this.card={kind:`thread`,id:n},this.render())}),this.pins.set(t._id,e),this.pinLayer.append(e)}e.textContent=tr(t.authorName),e.style.background=nr(t.authorName),e.setAttribute(`aria-label`,`Comment by ${t.authorName}: ${t.body.slice(0,80)}`),e.dataset.status=t.status,e.dataset.active=String(this.activeId===t._id),e.dataset.confidence=this.placements.get(t._id)?.confidence??`lost`}if(this.pinLayer.querySelector(`.pin-draft`)?.remove(),this.card?.kind===`composer`){let{draft:e}=this.card,t=e.element.getBoundingClientRect(),n=t.left+e.anchor.offset.x*t.width,r=t.top+e.anchor.offset.y*t.height,i=q(`div`,{class:`pin pin-draft pin-pending`,"aria-hidden":`true`},this.name?tr(this.name):`+`);i.style.background=this.name?nr(this.name):`var(--n-accent)`,i.style.transform=`translate(${Math.round(n)}px, ${Math.round(r)}px)`,this.pinLayer.append(i)}}renderUi(){let e=[this.renderToolbar()];this.panelOpen&&e.push(this.renderPanel());let t=this.renderCard();t&&e.push(t),this.toast&&e.push(q(`div`,{class:`toast`,role:`status`},this.toast));let n=this.root.activeElement,r=n?.dataset.focusKey,i=n instanceof HTMLTextAreaElement||n instanceof HTMLInputElement?{start:n.selectionStart,end:n.selectionEnd}:null;if(this.uiLayer.replaceChildren(...e),r){let e=this.uiLayer.querySelector(`[data-focus-key="${r}"]`);e?.focus(),i&&(e instanceof HTMLTextAreaElement||e instanceof HTMLInputElement)&&e.setSelectionRange(i.start,i.end)}this.positionCard()}renderToolbar(){let e=this.comments.filter(e=>e.status===`open`).length;return q(`div`,{class:`toolbar`,role:`toolbar`,"aria-label":`Nuni comments`},q(`button`,{class:`tb-btn`,type:`button`,"aria-pressed":String(this.picking),"aria-label":this.picking?`Cancel adding a comment`:`Add a comment`,title:`Add a comment (C)`,onclick:()=>this.setPicking(!this.picking)},J(X.comment),q(`span`,{class:`tb-label`},this.picking?`Pick an element`:`Comment`)),q(`button`,{class:`tb-btn`,type:`button`,"aria-pressed":String(this.panelOpen),"aria-label":`Comments on this page: ${e} open`,title:`All comments`,onclick:()=>this.togglePanel()},J(X.list),q(`span`,{class:`tb-count`},String(e))))}renderPanel(){let e=this.comments.filter(e=>e.status===`open`),t=this.comments.filter(e=>e.status===`resolved`),n=this.tab===`open`?e:t,r=n.filter(e=>this.placements.get(e._id)?.element),i=n.filter(e=>!this.placements.get(e._id)?.element),a=this.pages.filter(e=>e.path!==this.pageKey),o=e=>q(`button`,{class:`item`,type:`button`,onclick:()=>{e.status===`resolved`&&!this.showResolved&&(this.showResolved=!0,Z(Q.showResolved,`1`)),this.focusComment(e._id)}},q(`div`,{class:`row`},q(`span`,{class:`avatar`,style:`background:${nr(e.authorName)}`},tr(e.authorName)),q(`span`,{class:`author`},e.authorName),q(`span`,{class:`meta`},er(e.createdAt)),e.page.origin===location.origin?null:q(`span`,{class:`badge`,title:e.page.origin},new URL(e.page.origin).host)),q(`div`,{class:`item-text`},e.body)),s=[];if(this.loaded?n.length?(s.push(...r.map(o)),i.length&&(s.push(q(`div`,{class:`section-label`},`Couldn't find on this page`)),s.push(...i.map(o)))):s.push(q(`div`,{class:`empty`},this.tab===`open`?`No open comments on this page. Press C to add one.`:`Nothing resolved yet.`)):s.push(q(`div`,{class:`empty`},`Loading…`)),a.length){s.push(q(`div`,{class:`section-label`},`Other pages`));for(let e of a.slice(0,20)){let t=e.path.includes(`#`)?location.origin+e.path:location.origin+e.path+location.search;s.push(q(`a`,{class:`item`,href:t},q(`div`,{class:`row`},q(`span`,{class:`author`},e.path),q(`span`,{class:`spacer`}),q(`span`,{class:`badge`},`${e.count} open`))))}}return q(`div`,{class:`panel`,role:`dialog`,"aria-label":`Comments`},q(`div`,{class:`panel-head`},q(`div`,{class:`panel-title`},`Comments`),q(`button`,{class:`btn btn-ghost btn-icon`,type:`button`,"aria-label":`Close`,onclick:()=>this.togglePanel(!1)},J(X.close))),q(`div`,{class:`tabs`,role:`tablist`},q(`button`,{class:`tab`,role:`tab`,type:`button`,"aria-selected":String(this.tab===`open`),onclick:()=>{this.tab=`open`,this.render()}},`Open (${e.length})`),q(`button`,{class:`tab`,role:`tab`,type:`button`,"aria-selected":String(this.tab===`resolved`),onclick:()=>{this.tab=`resolved`,this.render()}},`Resolved (${t.length})`)),q(`div`,{class:`panel-list`},...s),this.renderPanelFooter())}renderPanelFooter(){let e=q(`label`,{class:`toggle`},q(`input`,{type:`checkbox`,checked:this.showResolved,onchange:e=>{this.showResolved=e.target.checked,Z(Q.showResolved,this.showResolved?`1`:null),this.render()}}),`Show resolved pins`),t;return t=this.isOwner?q(`div`,{class:`row`},q(`span`,{class:`badge badge-ok`},J(X.check),`Owner`),q(`span`,{class:`meta`},this.ownerName??``),q(`span`,{class:`spacer`}),q(`a`,{class:`link`,href:`${this.config.appUrl}/dashboard/p/${this.config.project}`,target:`_blank`,rel:`noopener`},`Dashboard`),q(`button`,{class:`link`,type:`button`,onclick:()=>this.signOut()},`Sign out`)):this.status.claimed?q(`div`,{class:`row`},q(`span`,{class:`meta`},`Managed by ${this.status.ownerName??`the owner`}`),q(`span`,{class:`spacer`}),q(`button`,{class:`link`,type:`button`,onclick:()=>this.openClaim()},`Owner sign in`)):q(`div`,{class:`row`},q(`span`,{class:`meta`},`Own this website?`),q(`span`,{class:`spacer`}),q(`button`,{class:`btn`,type:`button`,onclick:()=>this.openClaim()},J(X.github),`Claim Nuni`)),q(`div`,{class:`panel-foot`},e,t)}renderCard(){let e=this.card;if(!e)return null;let t=`card${window.matchMedia(pr).matches?` sheet`:``}`;if(e.kind===`composer`){let{draft:n}=e,r=!this.name,i=q(`input`,{class:`field`,placeholder:`Your name`,value:this.name,maxlength:a.nameMaxLength,autocomplete:`name`,"data-focus-key":`name`,"aria-label":`Your name`}),o=q(`textarea`,{class:`field`,placeholder:`Leave a comment`,maxlength:a.bodyMaxLength,"data-focus-key":`body`,"aria-label":`Comment`}),s=this.uiLayer.querySelector(`[data-focus-key="body"]`);s&&(o.value=s.value);let c=this.uiLayer.querySelector(`[data-focus-key="name"]`);c&&(i.value=c.value);let l=()=>void this.submitDraft(n,o.value,r?i.value:this.name);return o.addEventListener(`keydown`,e=>{e.key===`Enter`&&(e.metaKey||e.ctrlKey)&&(e.preventDefault(),l())}),q(`form`,{class:t,"data-card":`composer`,onsubmit:e=>{e.preventDefault(),l()}},q(`div`,{class:`card-body`},r?i:q(`div`,{class:`row`},q(`span`,{class:`avatar`,style:`background:${nr(this.name)}`},tr(this.name)),q(`span`,{class:`author`},this.name),q(`span`,{class:`spacer`}),q(`button`,{class:`link`,type:`button`,onclick:()=>{this.name=``,this.render()}},`Not you?`)),o,n.error?q(`div`,{class:`error`,role:`alert`},n.error):null,q(`div`,{class:`row`},q(`span`,{class:`kbd`},`⌘ + Enter`),q(`span`,{class:`spacer`}),q(`button`,{class:`btn btn-ghost`,type:`button`,onclick:()=>this.closeCard()},`Cancel`),q(`button`,{class:`btn btn-primary`,type:`submit`,disabled:!!n.sending},J(X.send),n.sending?`Posting…`:`Post`))))}let n=this.comments.find(t=>t._id===e.id);if(!n)return null;let r=this.isMine(n),i=this.isOwner,o=this.placements.get(n._id),s;if(e.editing){let t=q(`textarea`,{class:`field`,maxlength:a.bodyMaxLength,"data-focus-key":`edit`}),r=this.uiLayer.querySelector(`[data-focus-key="edit"]`);t.value=r?r.value:n.body,s=q(`div`,{class:`card-body`},t,q(`div`,{class:`row`},q(`span`,{class:`spacer`}),q(`button`,{class:`btn btn-ghost`,type:`button`,onclick:()=>{e.editing=!1,this.render()}},`Cancel`),q(`button`,{class:`btn btn-primary`,type:`button`,disabled:!!e.busy,onclick:()=>this.saveEdit(n,t.value)},`Save`)))}else s=q(`div`,{class:`card-body`},q(`div`,{class:`card-head`},q(`span`,{class:`avatar`,style:`background:${nr(n.authorName)}`},tr(n.authorName)),q(`span`,{class:`author`},n.authorName),q(`span`,{class:`meta`},er(n.createdAt)+(n.editedAt?` · edited`:``)),q(`span`,{class:`spacer`}),q(`button`,{class:`btn btn-ghost btn-icon`,type:`button`,"aria-label":`Close`,onclick:()=>this.closeCard()},J(X.close))),q(`div`,{class:`comment-body`},n.body),q(`div`,{class:`row`},n.status===`resolved`?q(`span`,{class:`badge badge-ok`},J(X.check),`Resolved`):null,n.page.origin===location.origin?null:q(`span`,{class:`badge`,title:`Left on ${n.page.origin}`},new URL(n.page.origin).host),o?.confidence===`low`?q(`span`,{class:`badge`,title:`The page changed; this pin is a best guess`},`Approximate`):null,o?.element?null:q(`span`,{class:`badge`,title:`Originally on: ${n.anchor.text||n.anchor.tag}`},`Element not found`)),e.error?q(`div`,{class:`error`,role:`alert`},e.error):null);let c=[];return e.editing||(i&&c.push(n.status===`open`?q(`button`,{class:`btn`,type:`button`,disabled:!!e.busy,onclick:()=>this.resolveComment(n)},J(X.check),`Resolve`):q(`button`,{class:`btn`,type:`button`,disabled:!!e.busy,onclick:()=>this.reopenComment(n)},J(X.undo),`Reopen`)),c.push(q(`span`,{class:`spacer`})),r&&c.push(q(`button`,{class:`btn btn-ghost btn-icon`,type:`button`,"aria-label":`Edit`,title:`Edit`,onclick:()=>{e.editing=!0,this.render()}},J(X.edit))),(r||i)&&c.push(q(`button`,{class:`btn btn-ghost btn-icon btn-danger`,type:`button`,"aria-label":`Delete`,title:`Delete`,disabled:!!e.busy,onclick:()=>this.deleteComment(n)},J(X.trash)))),q(`div`,{class:t,"data-card":`thread`,role:`dialog`,"aria-label":`Comment by ${n.authorName}`},s,c.length>1||i?q(`div`,{class:`actions`},...c):null)}positionCard(){let e=this.uiLayer.querySelector(`[data-card]`);if(!e||e.classList.contains(`sheet`))return;let t=null;if(this.card?.kind===`composer`){let{draft:e}=this.card,n=e.element.getBoundingClientRect();t={x:n.left+e.anchor.offset.x*n.width,y:n.top+e.anchor.offset.y*n.height}}else if(this.card?.kind===`thread`){let e=this.comments.find(e=>this.card?.kind===`thread`&&e._id===this.card.id);t=e?this.pinPositions.get(e._id)??this.pinPoint(e):null}let n=e.offsetWidth||320,r=e.offsetHeight||160,i=window.innerWidth,a=window.innerHeight,o,s;t?(o=t.x+36,s=t.y-28,o+n>i-12&&(o=t.x-n-12)):(o=i-n-16,s=a-r-72),o=Math.max(12,Math.min(o,i-n-12)),s=Math.max(12,Math.min(s,a-r-12)),e.style.left=`${Math.round(o)}px`,e.style.top=`${Math.round(s)}px`}focusComposer(){requestAnimationFrame(()=>{this.uiLayer.querySelector(this.name?`[data-focus-key="body"]`:`[data-focus-key="name"]`)?.focus()})}};let $=null;function _r(e){let t={destroy(){}};if(typeof window>`u`||typeof document>`u`)return t;if(!r(e.project))return console.warn(`[nuni] "${e.project}" is not a valid project ID. Run \`npx @nuniapp/cli init\` to get one.`),t;if($?.project===e.project)return vr($);$&&yr($);let n=l(e),i={project:e.project,widget:null,timer:0,handles:0};$=i;let a=()=>{if($===i){if(!document.body){i.timer=window.setTimeout(a,50);return}i.widget=new gr(n),i.widget.start()}},o=window.requestIdleCallback;return o?o(a,{timeout:1500}):i.timer=window.setTimeout(a,1),vr(i)}function vr(e){e.handles++;let t=!1;return{destroy(){t||(t=!0,e.handles--,e.handles<=0&&$===e&&yr(e))}}}function yr(e){clearTimeout(e.timer),e.widget?.destroy(),e.widget=null,$===e&&($=null)}window.Nuni={init:_r,version:`0.1.1`};let br=document.currentScript??document.querySelector(`script[data-project][src*='nuni']`),xr=br?.dataset.project;xr&&_r({project:xr,convexUrl:br?.dataset.convexUrl,convexSiteUrl:br?.dataset.convexSiteUrl,appUrl:br?.dataset.appUrl})})();
|