notemend 0.1.1 → 0.1.2
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 +34 -1
- package/bin/init.mjs +66 -24
- package/bin/notemend.mjs +20 -12
- package/package.json +1 -1
- package/src/client/api.js +1 -1
- package/src/client/notemend.css +1 -1
- package/src/client/run.js +66 -55
- package/src/server/middleware.mjs +1 -1
- package/src/store/cloud.mjs +3 -3
- package/src/store/comments.mjs +3 -3
- package/src/store/status.mjs +1 -1
- package/src/store/thread.mjs +1 -1
- package/thread.d.ts +4 -0
package/src/client/run.js
CHANGED
|
@@ -1,90 +1,101 @@
|
|
|
1
|
-
import{categoryOf as Te}from"../store/categories.mjs";import{stateOf as _,STATE_LABEL as xo}from"../store/status.mjs";import{handleOf as To,threadOf as Mo}from"../store/thread.mjs";import{api as j,canvasCopy as Ho,imageUrl as ko}from"./api";import{DEVTOOLS_DEVICES as On}from"../devtools-devices.mjs";import{drawDevice as Ao,pageTints as Co,inkFor as Fn}from"./devices";function Fo(N){const k=N.breakpoints,Me=N.categories,jt=(k.find(t=>!Number.isFinite(t.max))??k[0]).id,ht=t=>k.find(e=>t>=e.min&&t<=e.max)?.id??jt,gt=t=>t.breakpoint||jt,Ht=t=>N.devices.find(e=>e.id===t),w=Ho,R=(t,e)=>{w||localStorage.setItem(t,e)},zt=t=>t.replace(/\/+$/,"")||"/";let tt=zt(location.pathname);for(const t of document.querySelectorAll(".devtools .dt-icon[title]"))t.dataset.tip=t.title,t.getAttribute("aria-label")||t.setAttribute("aria-label",t.title),t.removeAttribute("title");const He=document.querySelector(".dt-grid-btn"),kt=document.querySelector(".dt-grid-overlay"),ke="dt-grid",Wt=t=>{kt.hidden=!t,He.setAttribute("aria-pressed",String(t)),R(ke,t?"1":"0"),q({grid:t})};He.addEventListener("click",()=>Wt(kt.hidden===!0));const Ae=document.querySelector(".dt-pages-name"),Ce=()=>{let t=null;for(const o of document.querySelectorAll(".dt-pages a"))zt(new URL(o.href).pathname)===tt?(o.setAttribute("aria-current","page"),t=o):o.removeAttribute("aria-current");const e=document.title.split("\u2014").pop()?.trim(),n=t?.querySelector(".dt-menu-label")?.textContent?.trim();Ae.textContent=n||e||Ae.textContent};Ce();const Be=[...document.querySelectorAll(".devtools details")];let Gt=!1;const ft=()=>{const t=Be.filter(e=>e.open);for(const e of t)e.open=!1;return t};document.addEventListener("keydown",t=>{if(t.key!=="Escape")return;const[e]=ft();e&&(e.querySelector("summary")?.focus(),t.preventDefault(),t.stopImmediatePropagation())},!0),document.addEventListener("pointerdown",t=>{Gt=Be.some(e=>e.open&&!e.contains(t.target))&&ft().length>0},!0),addEventListener("blur",ft);const U=document.querySelector(".dt-pad-overlay"),qe="dt-inspect",Pn=[".devtools",".dt-pad-overlay",".dt-grid-overlay",".dt-frame",".dt-history",...N.ignore].join(", "),Ne=[".devtools",".dt-notes-overlay",".dt-history",".dt-frame",...N.ignore].join(", "),Yt={pads:document.querySelector(".dt-pad-btn"),sizes:document.querySelector(".dt-size-btn"),type:document.querySelector(".dt-type-btn")};let et="",_t=0;const L=t=>{const e=parseFloat(getComputedStyle(document.documentElement).fontSize)/16,n=t/e;return Math.round(n*10)%10===0?String(Math.round(n)):n.toFixed(1)},O=(t,e,n,o,s,r="p")=>{if(n<=0||o<=0)return"";const a=s!==""?`<span class="dt-pad-chip dt-pad-chip--${r}" style="left:${t+n/2}px;top:${e+o/2}px">${s}</span>`:"";return`<span class="dt-pad-zone dt-pad-zone--${r}" style="left:${t}px;top:${e}px;width:${n}px;height:${o}px"></span>${a}`},Kn=["paddingTop","paddingRight","paddingBottom","paddingLeft","marginTop","marginRight","marginBottom","marginLeft","columnGap","rowGap"],jn=t=>{let e=t;for(let n=0;e&&n<6;n++,e=e.parentElement){const o=getComputedStyle(e);if(Kn.some(s=>parseFloat(o[s])>=2))return e}return t},zn=(t,e)=>{const n=parseFloat(e.columnGap)||0,o=parseFloat(e.rowGap)||0;if(!(e.display.includes("flex")||e.display.includes("grid"))||!n&&!o)return"";const s=[...t.children].map(a=>a.getBoundingClientRect()).filter(a=>a.width||a.height);let r="";for(let a=1;a<s.length;a++){const l=s[a-1],d=s[a];if(n&&d.left>=l.right-1){const c=Math.max(l.top,d.top);r+=O(l.right,c,d.left-l.right,Math.min(l.bottom,d.bottom)-c,L(n),"g")}else if(o&&d.top>=l.bottom-1){const c=Math.min(l.left,d.left);r+=O(c,l.bottom,Math.max(l.right,d.right)-c,d.top-l.bottom,L(o),"g")}}return r},Ut=t=>`<span class="dt-pad-outline" style="left:${t.left}px;top:${t.top}px;width:${t.width}px;height:${t.height}px"></span>`,Vt=(t,e,n="")=>`<span class="dt-pad-tag" style="left:${e.left}px;top:${Math.max(2,e.top-22)}px">${t.tagName.toLowerCase()+(t.classList[0]?"."+t.classList[0]:"")}${n}</span>`,Wn=t=>{const e=t.getBoundingClientRect(),n=getComputedStyle(t),o=parseFloat(n.paddingTop),s=parseFloat(n.paddingRight),r=parseFloat(n.paddingBottom),a=parseFloat(n.paddingLeft);let l=Ut(e);l+=O(e.left,e.top,e.width,o,o>=2?L(o):""),l+=O(e.left,e.bottom-r,e.width,r,r>=2?L(r):""),l+=O(e.left,e.top+o,a,e.height-o-r,a>=2?L(a):""),l+=O(e.right-s,e.top+o,s,e.height-o-r,s>=2?L(s):"");const d=parseFloat(n.marginTop),c=parseFloat(n.marginRight),S=parseFloat(n.marginBottom),H=parseFloat(n.marginLeft);l+=O(e.left,e.top-d,e.width,d,d>=2?L(d):"","m"),l+=O(e.left,e.bottom,e.width,S,S>=2?L(S):"","m"),l+=O(e.left-H,e.top,H,e.height,H>=2?L(H):"","m"),l+=O(e.right,e.top,c,e.height,c>=2?L(c):"","m"),l+=zn(t,n);const i=parseFloat(n.columnGap)||0,b=parseFloat(n.rowGap)||0,p=(n.display.includes("flex")||n.display.includes("grid"))&&(i||b)?` \xB7 gap ${L(i)}${b&&b!==i?"/"+L(b):""}`:"";U.innerHTML=l+Vt(t,e,p)},Gn=t=>{const e=t.getBoundingClientRect();U.innerHTML=Ut(e)+`<span class="dt-pad-chip" style="left:${e.left+e.width/2}px;top:${e.top+e.height/2}px">${L(e.width)} \xD7 ${L(e.height)}</span>`+Vt(t,e)},Ie=t=>{const e=(t.match(/[\d.]+/g)||[]).map(Number);if(e.length<3)return t;const n="#"+e.slice(0,3).map(o=>Math.round(o).toString(16).padStart(2,"0")).join("");return e[3]!==void 0&&e[3]<1?`${n} \xB7 ${Math.round(e[3]*100)}%`:n};let Jt=null;const Yn=()=>{if(Jt)return Jt;const t=getComputedStyle(document.documentElement),e=document.createElement("span");e.style.display="none",document.body.append(e);const n=[];for(const o of Array.from(t)){if(!o.startsWith("--"))continue;const s=t.getPropertyValue(o).trim();if(!/^(#|rgb|hsl|oklch|lab|color\()/i.test(s))continue;e.style.color="rgb(1, 2, 3)",e.style.color=s;const r=getComputedStyle(e).color;r&&r!=="rgb(1, 2, 3)"&&n.push([r,o])}return e.remove(),n.sort((o,s)=>o[1].length-s[1].length),Jt=n,n},_n=t=>Yn().find(([e])=>e===t)?.[1]??"",Un={100:"Thin",200:"Extra Light",300:"Light",400:"Regular",500:"Medium",600:"Semi Bold",700:"Bold",800:"Extra Bold",900:"Black"},Vn=t=>{const e=t.getBoundingClientRect(),n=getComputedStyle(t),o=parseFloat(n.fontSize),s=n.lineHeight==="normal"?0:parseFloat(n.lineHeight),r=parseFloat(n.letterSpacing)||0,a=_n(n.color),l=i=>`${(i*100).toFixed(1).replace(/\.0$/,"")}%`,d=[["Font",n.fontFamily.split(",")[0].replace(/["']/g,"")+(n.fontStyle!=="normal"?` ${n.fontStyle}`:"")],["Weight",`${Un[n.fontWeight]??""} <em>${n.fontWeight}</em>`],["Size",`${L(o)}px`],["Line",s?`${l(s/o)} <em>${L(s)}px</em>`:"normal"],["Letter",r?`${l(r/o)} <em>${r.toFixed(2).replace(/\.?0+$/,"")}px</em>`:"0"],["Color",`<i class="dt-type-sw" style="background:${n.color}"></i>${a?`${a} <em>${Ie(n.color)}</em>`:Ie(n.color)}`]],S=e.bottom+130<innerHeight?e.bottom+8:Math.max(8,e.top-138),H=Math.min(Math.max(8,e.left),innerWidth-210);U.innerHTML=Ut(e)+Vt(t,e)+`<div class="dt-type-card" style="left:${H}px;top:${S}px">${d.map(([i,b])=>`<span class="dt-type-row"><b>${i}</b><span>${b}</span></span>`).join("")}</div>`},De=t=>{_t||(_t=requestAnimationFrame(()=>{_t=0,U.hidden=!0;let e=document.elementFromPoint(t.clientX,t.clientY);if(U.hidden=!1,!e||e.closest(Pn)){U.innerHTML="";return}t.altKey&&e.parentElement&&e.parentElement!==document.body&&(e=e.parentElement),et==="sizes"?Gn(e):et==="type"?Vn(e):Wn(t.altKey?e:jn(e))}))},At=t=>{et=t;for(const[e,n]of Object.entries(Yt))n.setAttribute("aria-pressed",String(e===t));R(qe,t),q({inspect:t}),U.hidden=!t,U.innerHTML="",t?document.addEventListener("mousemove",De):document.removeEventListener("mousemove",De)};for(const[t,e]of Object.entries(Yt))e.addEventListener("click",()=>{t!==et&&at(!1),At(et===t?"":t)});const Re=document.querySelector(".dt-notes-btn"),Xt=[...document.querySelectorAll(".dt-bp")],Ct=document.querySelector(".dt-history-btn"),I=document.querySelector(".dt-history"),Zt=document.querySelector(".dt-studio-btn"),f=document.querySelector(".dt-device"),Oe=document.querySelector(".dt-shell"),bt=document.querySelector('.dt-chrome[data-at="top"]'),Bt=document.querySelector('.dt-chrome[data-at="bottom"]'),yt=document.querySelector(".dt-ruler"),F=document.querySelector(".dt-devices"),nt=document.querySelector(".dt-notes-hi"),Jn=nt.querySelector(".dt-hi-box"),Fe=nt.querySelector(".dt-hi-tag"),Xn=[...document.querySelectorAll(".dt-frame-handle")],Pe=document.querySelector(".dt-frame-size"),Qt=document.querySelector(".dt-frame-rotate"),vt=document.querySelector(".dt-frame-bars"),T=document.querySelector(".dt-frame"),v=T.querySelector("iframe"),te=document.querySelector(".dt-notes-count"),m=document.querySelector(".dt-notes-overlay"),Ke="dt-notes";let B=[],M=!1,y=null,u=null,ee=0,D="",ot=[],$=null,A=[];const qt=(t=u)=>!!(t&&(t.text?.trim()||t.images?.length)),P=()=>{u&&qt()&&A.push(u),u=null};let $t=null,z=null;const je=()=>`dt-draft:${tt}${w?":canvas":""}`;let rt=je(),Nt=0;const ne=()=>{if(!u&&!A.length&&!D){localStorage.removeItem(rt);return}const t={draft:u,parked:A,reply:D?{for:$t,text:D}:null};try{localStorage.setItem(rt,JSON.stringify(t))}catch{const e=n=>({...n,images:void 0});try{localStorage.setItem(rt,JSON.stringify({...t,draft:u&&e(u),parked:A.map(e)}))}catch{}}},ze=()=>{clearTimeout(Nt),Nt=setTimeout(ne,200)};addEventListener("pagehide",()=>{clearTimeout(Nt),ne()});let V=localStorage.getItem("dt-resolved")!=="0";const Zn=[[/Edg\/(\d+)/,"Edge"],[/OPR\/(\d+)/,"Opera"],[/Firefox\/(\d+)/,"Firefox"],[/Chrome\/(\d+)/,"Chrome"],[/Version\/(\d+).*Safari/,"Safari"]],Qn=[[/iPhone|iPad/,"iOS"],[/Android/,"Android"],[/Mac OS X/,"macOS"],[/Windows/,"Windows"],[/Linux/,"Linux"]],to=()=>{const t=navigator.userAgent,e=r=>r.find(([a])=>a.test(t)),n=e(Zn),o=e(Qn),s=n?n[0].exec(t)?.[1]:null;return[n?`${n[1]}${s?" "+s:""}`:"unknown browser",o?.[1]].filter(Boolean).join(" \xB7 ")},J=()=>ht(innerWidth),oe=()=>z??J(),Et=()=>{const t=oe();for(const e of Xt)e.setAttribute("aria-pressed",String(e.dataset.bp===t))},eo=t=>{const e=[];let n=t;for(;n&&n.tagName!=="HTML"&&e.length<8;){if(n.id){e.unshift("#"+CSS.escape(n.id));break}const o=n.parentElement,s=n.tagName.toLowerCase(),r=o?[...o.children].filter(a=>a.tagName===n.tagName):[];e.unshift(r.length>1?`${s}:nth-of-type(${r.indexOf(n)+1})`:s),n=o}return e.join(">")},We=(t,e)=>!e||it(t.textContent||"").slice(0,60)===e,no=(t,e)=>[t||"*",...(e||[]).map(n=>"."+CSS.escape(n))].join(""),Ge=t=>{try{return[...document.querySelectorAll(no(t.tag,t.classes))]}catch{return[]}},Ye=t=>{let e=null;try{e=document.querySelector(t.selector)}catch{e=null}if(e&&We(e,t.label))return e;const n=Ge(t);return(it(t.label)?n.find(s=>We(s,t.label)):null)||(t.nth!=null?n[t.nth]:null)||n[0]||e},W=t=>{const e=Ye(t);if(!e)return null;const n=e.getBoundingClientRect();return!n.width&&!n.height?null:{x:n.left+n.width*t.rx,y:n.top+n.height*t.ry}},_e=t=>t?new Date(t).toLocaleString(void 0,{day:"numeric",month:"short",hour:"2-digit",minute:"2-digit"}):"",It='<svg viewBox="0 0 20 20" width="13" height="13" aria-hidden="true"><path d="M4 6h12M8 6V4.2h4V6M6.6 6l.55 9.8h5.7L13.4 6"/></svg>',Ue='<svg viewBox="0 0 20 20" width="13" height="13" aria-hidden="true"><path d="M4.8 10.4 8.2 13.8l7-7.6" stroke-linejoin="round"/></svg>',se='<svg viewBox="0 0 20 20" width="12" height="12" aria-hidden="true"><path d="M12.6 4.4l3 3-8.4 8.4H4.2v-3z" stroke-linejoin="round"/></svg>',Ve='<svg viewBox="0 0 20 20" width="13" height="13" aria-hidden="true"><path d="M5.4 5.4l9.2 9.2M14.6 5.4l-9.2 9.2"/></svg>',wt=t=>`<svg viewBox="0 0 20 20" width="${t}" height="${t}" aria-hidden="true" class="dt-claude"><path d="M10 2.6v14.8M2.6 10h14.8M4.8 4.8l10.4 10.4M15.2 4.8L4.8 15.2"/></svg>`,it=t=>t.replace(/[\u200B-\u200D\uFEFF\u2060]/g,"").trim(),Je=t=>it(t)?`<span class="dt-note-info" data-tip="${E(it(t))}"
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
1
|
+
import{categoryOf as Ve}from"../store/categories.mjs";import{stateOf as j,STATE_LABEL as rs}from"../store/status.mjs";import{agentName as vt,handleOf as is,threadOf as ls}from"../store/thread.mjs";import{api as V,canvasCopy as ds,host as cs,imageUrl as us}from"./api";import{DEVTOOLS_DEVICES as io}from"../devtools-devices.mjs";import{drawDevice as ms,pageTints as ps,inkFor as lo}from"./devices";function Es(M){const B=M.breakpoints,Ue=M.categories,ee=(B.find(t=>!Number.isFinite(t.max))??B[0]).id,$t=t=>B.find(e=>t>=e.min&&t<=e.max)?.id??ee,lt=t=>t.breakpoint||ee,Rt=t=>M.devices.find(e=>e.id===t),$=ds,K=(t,e)=>{$||localStorage.setItem(t,e)},ne=t=>t.replace(/\/+$/,"")||"/";let D=ne(location.pathname);for(const t of document.querySelectorAll(".devtools .dt-icon[title]"))t.dataset.tip=t.title,t.getAttribute("aria-label")||t.setAttribute("aria-label",t.title),t.removeAttribute("title");const Je=document.querySelector(".dt-grid-btn"),Dt=document.querySelector(".dt-grid-overlay"),Xe="dt-grid",oe=t=>{Dt.hidden=!t,Je.setAttribute("aria-pressed",String(t)),K(Xe,t?"1":"0"),I({grid:t})};Je.addEventListener("click",()=>oe(Dt.hidden===!0));const Ze=document.querySelector(".dt-pages-name"),Qe=()=>{let t=null;for(const o of document.querySelectorAll(".dt-pages a"))ne(new URL(o.href).pathname)===D?(o.setAttribute("aria-current","page"),t=o):o.removeAttribute("aria-current");const e=document.title.split("\u2014").pop()?.trim(),n=t?.querySelector(".dt-menu-label")?.textContent?.trim();Ze.textContent=n||e||Ze.textContent};Qe();const tn=[...document.querySelectorAll(".devtools details")];let se=!1;const Et=()=>{const t=tn.filter(e=>e.open);for(const e of t)e.open=!1;return t};document.addEventListener("keydown",t=>{if(t.key!=="Escape")return;const[e]=Et();e&&(e.querySelector("summary")?.focus(),t.preventDefault(),t.stopImmediatePropagation())},!0),document.addEventListener("pointerdown",t=>{se=tn.some(e=>e.open&&!e.contains(t.target))&&Et().length>0},!0),addEventListener("blur",Et);const Z=document.querySelector(".dt-pad-overlay"),en="dt-inspect",co=[".devtools",".dt-pad-overlay",".dt-grid-overlay",".dt-frame",".dt-history",".dt-review",...M.ignore].join(", "),nn=[".devtools",".dt-notes-overlay",".dt-history",".dt-frame",".dt-review",...M.ignore].join(", "),ae={pads:document.querySelector(".dt-pad-btn"),sizes:document.querySelector(".dt-size-btn"),type:document.querySelector(".dt-type-btn")};let dt="",re=0;const k=t=>{const e=parseFloat(getComputedStyle(document.documentElement).fontSize)/16,n=t/e;return Math.round(n*10)%10===0?String(Math.round(n)):n.toFixed(1)},W=(t,e,n,o,s,a="p")=>{if(n<=0||o<=0)return"";const d=s!==""?`<span class="dt-pad-chip dt-pad-chip--${a}" style="left:${t+n/2}px;top:${e+o/2}px">${s}</span>`:"";return`<span class="dt-pad-zone dt-pad-zone--${a}" style="left:${t}px;top:${e}px;width:${n}px;height:${o}px"></span>${d}`},uo=["paddingTop","paddingRight","paddingBottom","paddingLeft","marginTop","marginRight","marginBottom","marginLeft","columnGap","rowGap"],mo=t=>{let e=t;for(let n=0;e&&n<6;n++,e=e.parentElement){const o=getComputedStyle(e);if(uo.some(s=>parseFloat(o[s])>=2))return e}return t},po=(t,e)=>{const n=parseFloat(e.columnGap)||0,o=parseFloat(e.rowGap)||0;if(!(e.display.includes("flex")||e.display.includes("grid"))||!n&&!o)return"";const s=[...t.children].map(d=>d.getBoundingClientRect()).filter(d=>d.width||d.height);let a="";for(let d=1;d<s.length;d++){const c=s[d-1],r=s[d];if(n&&r.left>=c.right-1){const l=Math.max(c.top,r.top);a+=W(c.right,l,r.left-c.right,Math.min(c.bottom,r.bottom)-l,k(n),"g")}else if(o&&r.top>=c.bottom-1){const l=Math.min(c.left,r.left);a+=W(l,c.bottom,Math.max(c.right,r.right)-l,r.top-c.bottom,k(o),"g")}}return a},ie=t=>`<span class="dt-pad-outline" style="left:${t.left}px;top:${t.top}px;width:${t.width}px;height:${t.height}px"></span>`,le=(t,e,n="")=>`<span class="dt-pad-tag" style="left:${e.left}px;top:${Math.max(2,e.top-22)}px">${t.tagName.toLowerCase()+(t.classList[0]?"."+t.classList[0]:"")}${n}</span>`,go=t=>{const e=t.getBoundingClientRect(),n=getComputedStyle(t),o=parseFloat(n.paddingTop),s=parseFloat(n.paddingRight),a=parseFloat(n.paddingBottom),d=parseFloat(n.paddingLeft);let c=ie(e);c+=W(e.left,e.top,e.width,o,o>=2?k(o):""),c+=W(e.left,e.bottom-a,e.width,a,a>=2?k(a):""),c+=W(e.left,e.top+o,d,e.height-o-a,d>=2?k(d):""),c+=W(e.right-s,e.top+o,s,e.height-o-a,s>=2?k(s):"");const r=parseFloat(n.marginTop),l=parseFloat(n.marginRight),m=parseFloat(n.marginBottom),v=parseFloat(n.marginLeft);c+=W(e.left,e.top-r,e.width,r,r>=2?k(r):"","m"),c+=W(e.left,e.bottom,e.width,m,m>=2?k(m):"","m"),c+=W(e.left-v,e.top,v,e.height,v>=2?k(v):"","m"),c+=W(e.right,e.top,l,e.height,l>=2?k(l):"","m"),c+=po(t,n);const i=parseFloat(n.columnGap)||0,y=parseFloat(n.rowGap)||0,T=(n.display.includes("flex")||n.display.includes("grid"))&&(i||y)?` \xB7 gap ${k(i)}${y&&y!==i?"/"+k(y):""}`:"";Z.innerHTML=c+le(t,e,T)},fo=t=>{const e=t.getBoundingClientRect();Z.innerHTML=ie(e)+`<span class="dt-pad-chip" style="left:${e.left+e.width/2}px;top:${e.top+e.height/2}px">${k(e.width)} \xD7 ${k(e.height)}</span>`+le(t,e)},on=t=>{const e=(t.match(/[\d.]+/g)||[]).map(Number);if(e.length<3)return t;const n="#"+e.slice(0,3).map(o=>Math.round(o).toString(16).padStart(2,"0")).join("");return e[3]!==void 0&&e[3]<1?`${n} \xB7 ${Math.round(e[3]*100)}%`:n};let de=null;const ho=()=>{if(de)return de;const t=getComputedStyle(document.documentElement),e=document.createElement("span");e.style.display="none",document.body.append(e);const n=[];for(const o of Array.from(t)){if(!o.startsWith("--"))continue;const s=t.getPropertyValue(o).trim();if(!/^(#|rgb|hsl|oklch|lab|color\()/i.test(s))continue;e.style.color="rgb(1, 2, 3)",e.style.color=s;const a=getComputedStyle(e).color;a&&a!=="rgb(1, 2, 3)"&&n.push([a,o])}return e.remove(),n.sort((o,s)=>o[1].length-s[1].length),de=n,n},bo=t=>ho().find(([e])=>e===t)?.[1]??"",yo={100:"Thin",200:"Extra Light",300:"Light",400:"Regular",500:"Medium",600:"Semi Bold",700:"Bold",800:"Extra Bold",900:"Black"},sn=t=>(t.match(/[\d.]+/g)??[]).map(Number).concat([1]).slice(0,4),an=(t,e)=>t.slice(0,3).map((n,o)=>n*t[3]+e[o]*(1-t[3])).concat([1]),vo=t=>{const e=[];for(let n=t;n;n=n.parentElement){const o=getComputedStyle(n);if(o.backgroundImage!=="none")return null;const s=sn(o.backgroundColor);if(s[3]>0&&(e.push(s),s[3]>=1))break}return e.reduceRight((n,o)=>an(o,n),[255,255,255,1])},rn=t=>{const[e,n,o]=t.slice(0,3).map(s=>(s/=255,s<=.03928?s/12.92:((s+.055)/1.055)**2.4));return .2126*e+.7152*n+.0722*o},$o=(t,e,n)=>{const o=vo(t);if(!o)return["Contrast","<em>on an image</em>"];const s=an(sn(e.color),o),[a,d]=[rn(s),rn(o)].sort((m,v)=>v-m),c=(a+.05)/(d+.05),r=n>=24||n>=18.66&&Number(e.fontWeight)>=700,l=c>=(r?4.5:7)?"AAA":c>=(r?3:4.5)?"AA":"fails AA";return["Contrast",`${c.toFixed(2)}:1 <em class="${l==="fails AA"?"dt-type-bad":""}">${l}${r?" \xB7 large":""}</em>`]},Eo=t=>{const e=t.getBoundingClientRect(),n=getComputedStyle(t),o=parseFloat(n.fontSize),s=n.lineHeight==="normal"?0:parseFloat(n.lineHeight),a=parseFloat(n.letterSpacing)||0,d=bo(n.color),c=i=>`${(i*100).toFixed(1).replace(/\.0$/,"")}%`,r=[["Font",n.fontFamily.split(",")[0].replace(/["']/g,"")+(n.fontStyle!=="normal"?` ${n.fontStyle}`:"")],["Weight",`${yo[n.fontWeight]??""} <em>${n.fontWeight}</em>`],["Size",`${k(o)}px`],["Line",s?`${c(s/o)} <em>${k(s)}px</em>`:"normal"],["Letter",a?`${c(a/o)} <em>${a.toFixed(2).replace(/\.?0+$/,"")}px</em>`:"0"],["Color",`<i class="dt-type-sw" style="background:${n.color}"></i>${d?`${d} <em>${on(n.color)}</em>`:on(n.color)}`],$o(t,n,o)],m=e.bottom+150<innerHeight?e.bottom+8:Math.max(8,e.top-158),v=Math.min(Math.max(8,e.left),innerWidth-210);Z.innerHTML=ie(e)+le(t,e)+`<div class="dt-type-card" style="left:${v}px;top:${m}px">${r.map(([i,y])=>`<span class="dt-type-row"><b>${i}</b><span>${y}</span></span>`).join("")}</div>`},ln=t=>{re||(re=requestAnimationFrame(()=>{re=0,Z.hidden=!0;let e=document.elementFromPoint(t.clientX,t.clientY);if(Z.hidden=!1,!e||e.closest(co)){Z.innerHTML="";return}t.altKey&&e.parentElement&&e.parentElement!==document.body&&(e=e.parentElement),dt==="sizes"?fo(e):dt==="type"?Eo(e):go(t.altKey?e:mo(e))}))},Ot=t=>{dt=t;for(const[e,n]of Object.entries(ae))n.setAttribute("aria-pressed",String(e===t));K(en,t),I({inspect:t}),Z.hidden=!t,Z.innerHTML="",t?document.addEventListener("mousemove",ln):document.removeEventListener("mousemove",ln)};for(const[t,e]of Object.entries(ae))e.addEventListener("click",()=>{t!==dt&&at(!1),Ot(dt===t?"":t)});const dn=document.querySelector(".dt-notes-btn"),ce=[...document.querySelectorAll(".dt-bp")],Ft=document.querySelector(".dt-history-btn"),R=document.querySelector(".dt-history"),ue=document.querySelector(".dt-studio-btn"),w=document.querySelector(".dt-device"),cn=document.querySelector(".dt-shell"),wt=document.querySelector('.dt-chrome[data-at="top"]'),Pt=document.querySelector('.dt-chrome[data-at="bottom"]'),St=document.querySelector(".dt-ruler"),z=document.querySelector(".dt-devices"),ct=document.querySelector(".dt-notes-hi"),wo=ct.querySelector(".dt-hi-box"),un=ct.querySelector(".dt-hi-tag"),So=[...document.querySelectorAll(".dt-frame-handle")],mn=document.querySelector(".dt-frame-size"),me=document.querySelector(".dt-frame-rotate"),Lt=document.querySelector(".dt-frame-bars"),C=document.querySelector(".dt-frame"),L=C.querySelector("iframe"),pe=document.querySelector(".dt-notes-count"),f=document.querySelector(".dt-notes-overlay"),pn="dt-notes";let h=[],H=!1,b=null,u=null,ge=0,O="",Q=[],x=null,N=[];const jt=(t=u)=>!!(t&&(t.text?.trim()||t.images?.length)),_=()=>{u&&jt()&&N.push(u),u=null};let xt=null,U=null;const gn=()=>`dt-draft:${D}${$?":canvas":""}`;let pt=gn(),Kt=0;const fe=()=>{if(!u&&!N.length&&!O){localStorage.removeItem(pt);return}const t={draft:u,parked:N,reply:O?{for:xt,text:O}:null};try{localStorage.setItem(pt,JSON.stringify(t))}catch{const e=n=>({...n,images:void 0});try{localStorage.setItem(pt,JSON.stringify({...t,draft:u&&e(u),parked:N.map(e)}))}catch{}}},Wt=()=>{clearTimeout(Kt),Kt=setTimeout(fe,200)};addEventListener("pagehide",()=>{clearTimeout(Kt),fe()});let tt=localStorage.getItem("dt-resolved")!=="0";const Lo=[[/Edg\/(\d+)/,"Edge"],[/OPR\/(\d+)/,"Opera"],[/Firefox\/(\d+)/,"Firefox"],[/Chrome\/(\d+)/,"Chrome"],[/Version\/(\d+).*Safari/,"Safari"]],xo=[[/iPhone|iPad/,"iOS"],[/Android/,"Android"],[/Mac OS X/,"macOS"],[/Windows/,"Windows"],[/Linux/,"Linux"]],To=()=>{const t=navigator.userAgent,e=a=>a.find(([d])=>d.test(t)),n=e(Lo),o=e(xo),s=n?n[0].exec(t)?.[1]:null;return[n?`${n[1]}${s?" "+s:""}`:"unknown browser",o?.[1]].filter(Boolean).join(" \xB7 ")},et=()=>$t(innerWidth),zt=()=>U??et(),Tt=()=>{const t=zt();for(const e of ce)e.setAttribute("aria-pressed",String(e.dataset.bp===t))},Mo=t=>{const e=[];let n=t;for(;n&&n.tagName!=="HTML"&&e.length<8;){if(n.id){e.unshift("#"+CSS.escape(n.id));break}const o=n.parentElement,s=n.tagName.toLowerCase(),a=o?[...o.children].filter(d=>d.tagName===n.tagName):[];e.unshift(a.length>1?`${s}:nth-of-type(${a.indexOf(n)+1})`:s),n=o}return e.join(">")},he=(t,e)=>!e||F(t.textContent||"").slice(0,60)===e,ko=(t,e)=>[t||"*",...(e||[]).map(n=>"."+CSS.escape(n))].join(""),fn=t=>{try{return[...document.querySelectorAll(ko(t.tag,t.classes))]}catch{return[]}},hn=t=>{const e=F(t.textContent||"").replace(/\s+/g," ");for(let n=t.parentElement,o=0;n&&n!==document.body&&o<4;n=n.parentElement,o++){const s=F(n.textContent||"").replace(/\s+/g," ");if(s&&s!==e)return s}return""},Ho=t=>hn(t).slice(0,80),be=(t,e)=>!e||hn(t).startsWith(e),nt=t=>{let e=null;try{e=document.querySelector(t.selector)}catch{e=null}if(e&&he(e,t.label)&&be(e,t.ctx))return e;const n=fn(t),o=F(t.label)?n.filter(a=>he(a,t.label)):[];return(o.find(a=>be(a,t.ctx))??n.find(a=>t.ctx&&be(a,t.ctx)&&!F(t.label)))||o[0]||(e&&he(e,t.label)?e:null)||(t.nth!=null?n[t.nth]:null)||n[0]||e},Ao=t=>{let e=null;for(let n=t.parentElement;n&&n!==document.body;n=n.parentElement){const o=getComputedStyle(n);if(o.overflowX==="visible"&&o.overflowY==="visible")continue;const s=n.getBoundingClientRect();e=e?{l:Math.max(e.l,s.left),t:Math.max(e.t,s.top),r:Math.min(e.r,s.right),b:Math.min(e.b,s.bottom)}:{l:s.left,t:s.top,r:s.right,b:s.bottom}}return e},G=t=>{const e=nt(t);if(!e)return null;const n=e.getBoundingClientRect();if(!n.width&&!n.height)return null;const o=n.left+n.width*t.rx,s=n.top+n.height*t.ry,a=Ao(e);if(!a)return{x:o,y:s,off:""};if(a.r-a.l<18||a.b-a.t<18)return null;const d=Math.min(Math.max(o,a.l),a.r-18),c=Math.min(Math.max(s,a.t+18),a.b),r=o<a.l?"l":o>a.r-18?"r":s<a.t+18?"t":s>a.b?"b":"";return{x:d,y:c,off:r}},bn=t=>{for(let e=t;e&&e!==document.body;e=e.parentElement)if(e.getAnimations().some(n=>n.playState==="running"))return!0;return!1};let _t=[];const ye=t=>{for(const e of _t)e.play();_t=[];for(let e=t;e&&e!==document.body;e=e.parentElement)for(const n of e.getAnimations())n.playState==="running"&&(n.pause(),_t.push(n))},yn=()=>{if(u)return nt(u);const t=b!=null?h.find(n=>n.id===b):null;if(!t)return null;const e=G(t);return e&&!e.off?nt(t):null},vn=t=>t?new Date(t).toLocaleString(void 0,{day:"numeric",month:"short",hour:"2-digit",minute:"2-digit"}):"",Gt='<svg viewBox="0 0 20 20" width="13" height="13" aria-hidden="true"><path d="M4 6h12M8 6V4.2h4V6M6.6 6l.55 9.8h5.7L13.4 6"/></svg>',ve='<svg viewBox="0 0 20 20" width="13" height="13" aria-hidden="true"><path d="M4.8 10.4 8.2 13.8l7-7.6" stroke-linejoin="round"/></svg>',$e='<svg viewBox="0 0 20 20" width="12" height="12" aria-hidden="true"><path d="M12.6 4.4l3 3-8.4 8.4H4.2v-3z" stroke-linejoin="round"/></svg>',Yt='<svg viewBox="0 0 20 20" width="13" height="13" aria-hidden="true"><path d="M5.4 5.4l9.2 9.2M14.6 5.4l-9.2 9.2"/></svg>',Mt=t=>`<svg viewBox="0 0 20 20" width="${t}" height="${t}" aria-hidden="true" class="dt-claude"><path d="M10 2.6v14.8M2.6 10h14.8M4.8 4.8l10.4 10.4M15.2 4.8L4.8 15.2"/></svg>`,$n=()=>{try{return localStorage.getItem("nm-for")??"claude"}catch{return"claude"}},Co=t=>t?t==="claude"?"AI agent":M.team?.find(e=>e.email===t)?.name||t:"Anyone",Bo=t=>`<label class="dt-for">For <select class="dt-for-select" aria-label="Who this is for">
|
|
2
|
+
<option value="claude"${t==="claude"?" selected":""}>AI agent</option>
|
|
3
|
+
<option value=""${t?"":" selected"}>Anyone</option>
|
|
4
|
+
${(M.team??[]).filter(e=>e.email!==M.me?.email).map(e=>`<option value="${g(e.email)}"${t===e.email?" selected":""}>${g(e.name||e.email)}</option>`).join("")}
|
|
5
|
+
</select></label>`,En=t=>{const e=F(t?.textContent).replace(/\s+/g," ");return e&&e.length<=2e3?e:""},No=t=>`<div class="dt-suggest dt-suggest--read"><del>${g(t.from)}</del><ins>${g(t.to)}</ins></div>`,F=t=>(t??"").replace(/[\u200B-\u200D\uFEFF\u2060]/g,"").trim(),wn=t=>F(t)?`<span class="dt-note-info" data-tip="${g(F(t))}"
|
|
6
|
+
><svg viewBox="0 0 20 20" width="13" height="13" aria-hidden="true"><circle cx="10" cy="10" r="7.4"/><path d="M10 9.2v4.4M10 6.4v.6"/></svg></span>`:"",Sn=(t,e)=>`<span class="dt-note-cats">${Ue.map(n=>`<button class="dt-cat${n.id===t?" is-on":""}" data-act="cat" data-cat="${n.id}"${e?` data-id="${e}"`:""} style="--cat:${n.color}">${n.label}</button>`).join("")}</span>`,Io='<svg viewBox="0 0 20 20" width="9" height="9" aria-hidden="true"><path d="M5.5 5.5l9 9M14.5 5.5l-9 9"/></svg>',Ln=t=>t.startsWith("data:video/")||/\.webm(\?|$)/i.test(t),xn=(t,e,n=t)=>`<span class="dt-shot${Ln(n)?" dt-shot--video":""}">${Ln(n)?`<video src="${t}" controls preload="metadata" playsinline></video>`:`<a href="${t}" target="_blank"><img src="${t}" alt="" loading="lazy" /></a>`}${e===void 0?"":`<button class="dt-shot-rm" data-act="unshot" ${e} aria-label="Remove">${Io}</button>`}</span>`,Tn=(t=[],e)=>t.length?`<div class="dt-note-shots">${t.map(n=>{const o=n.split("/").pop(),s=us(o);return xn(s,e===void 0?void 0:`data-id="${e}" data-img="${g(o)}"`,o)}).join("")}</div>`:"",Mn=(t=[])=>t.length?`<div class="dt-note-shots">${t.map((e,n)=>xn(e,`data-i="${n}"`)).join("")}</div>`:"",qo='<svg viewBox="0 0 20 20" width="15" height="15" aria-hidden="true"><rect x="2.5" y="5.5" width="11" height="9" rx="2"/><path d="m13.5 9 4-2.5v7l-4-2.5"/></svg>',Ro=!!navigator.mediaDevices?.getDisplayMedia&&typeof MediaRecorder<"u";let ut=null;const Do=async t=>{if(ut){ut.stop();return}let e;try{e=await navigator.mediaDevices.getDisplayMedia({video:{frameRate:12},audio:!1})}catch{return}const n=await navigator.mediaDevices.getUserMedia({audio:!0}).catch(()=>null),o=new MediaStream([...e.getVideoTracks(),...n?.getAudioTracks()??[]]),s=["video/webm;codecs=vp9,opus","video/webm;codecs=vp8,opus","video/webm"].find(l=>MediaRecorder.isTypeSupported(l));if(!s){for(const l of e.getTracks())l.stop();st("This browser cannot record WebM video.");return}const a=new MediaRecorder(o,{mimeType:s,videoBitsPerSecond:6e5,audioBitsPerSecond:32e3}),d=[],c=!!Number(t?.dataset.id);a.ondataavailable=l=>{l.data.size&&d.push(l.data)};const r=setTimeout(()=>{a.state!=="inactive"&&a.stop()},3e4);a.onstop=async()=>{clearTimeout(r);for(const v of[...e.getTracks(),...n?.getTracks()??[]])v.stop();ut=null;const l=new Blob(d,{type:"video/webm"});if(l.size>32e5){st("That recording is too big to send \u2014 keep it shorter."),p();return}const m=await new Promise(v=>{const i=new FileReader;i.onload=()=>v(String(i.result)),i.readAsDataURL(l)});c?Q.push(m):u&&(u.images??=[]).push(m),p()},e.getVideoTracks()[0]?.addEventListener("ended",()=>{a.state!=="inactive"&&a.stop()}),ut=a,a.start(1e3),p()},Oo='<svg viewBox="0 0 20 20" width="15" height="15" aria-hidden="true"><rect x="3" y="4" width="14" height="12" rx="2"/><circle cx="7.5" cy="8.5" r="1.4"/><path d="m3.5 14.5 4-4 3 3 2-2 4 4"/></svg>',kn=(t,e,n,o,s="")=>`<div class="dt-note-foot"><div class="dt-compose">
|
|
7
|
+
<textarea class="${t}" rows="1" placeholder="${e}">${g(n)}</textarea>
|
|
6
8
|
${s}
|
|
7
9
|
<div class="dt-compose-bar">
|
|
8
|
-
<button class="dt-attach" data-act="attach" title="Attach a screenshot \u2014 or paste or drop one">${
|
|
10
|
+
<span class="dt-compose-tools"><button class="dt-attach" data-act="attach" title="Attach a screenshot \u2014 or paste or drop one">${Oo}</button>
|
|
11
|
+
${Ro?`<button class="dt-record${ut?" is-on":""}" data-act="record" title="${ut?"Stop recording":"Record the screen, up to 30 seconds"}">${ut?"Stop":qo}</button>`:""}</span>
|
|
9
12
|
<button class="dt-send${n.trim()?" is-ready":""}" ${o} title="Send (Enter)"
|
|
10
13
|
><svg viewBox="0 0 20 20" width="14" height="14" aria-hidden="true"><path d="M10 15.5v-11M5.5 9 10 4.5 14.5 9"/></svg></button>
|
|
11
14
|
</div>
|
|
12
|
-
</div></div>`,
|
|
13
|
-
title="Resolved by
|
|
14
|
-
class="dt-note-resolve${n?" is-on":""}" title="${n?"Reopen":t==="claude"?"Looks right \u2014 mark it resolved":"Resolve"}">${
|
|
15
|
-
style="left:${
|
|
16
|
-
title="${
|
|
17
|
-
style="left:${
|
|
15
|
+
</div></div>`,Ee=(t,e)=>(t||"element")+(e?.[0]?"."+e[0]:""),Hn=()=>N.map((t,e)=>({i:e,el:Ee(t.tag,t.classes),text:F(t.text??""),shots:t.images?.length??0,orphan:!G(t)}));let we=[],An="";const Fo=(t,e)=>t!=="claude"?"":`<button class="dt-note-state" data-act="reopen" data-id="${e}"
|
|
16
|
+
title="Resolved by ${g(vt(h.find(n=>n.id===e)?.doneAgent))} \u2014 click to clear">${Mt(13)}</button>`,Cn=(t,e)=>{const n=t==="done";return`${Fo(t,e)}<button data-act="${n?"reopen":"done"}" data-id="${e}"
|
|
17
|
+
class="dt-note-resolve${n?" is-on":""}" title="${n?"Reopen":t==="claude"?"Looks right \u2014 mark it resolved":"Resolve"}">${ve}</button>`},Vt=(t,e)=>V("comments",{method:"PATCH",headers:{"content-type":"application/json"},body:JSON.stringify(e?{id:t,status:"done",doneBy:"you"}:{id:t,status:"open",doneBy:null})}),g=t=>t.replace(/[&<>"]/g,e=>({"&":"&","<":"<",">":">",'"':"""})[e]),Po=t=>{const e=h.filter(s=>lt(s)===t),n=e.filter(s=>j(s)==="open").length,o=e.filter(s=>j(s)==="claude").length;pe.innerHTML=n?String(n):o?Mt(9):"\u2713",pe.dataset.state=n?"open":o?"claude":"done",pe.hidden=e.length===0},p=()=>{if(Wt(),$){const r=Hn(),l=JSON.stringify(r);l!==An&&(An=l,parent.postMessage({dt:!0,drafts:r},location.origin))}Tt(),b!==xt&&(O="",Q=[],xt=b),x&&x.id!==b&&(x=null);const t=zt();if(Po(t),!H){f.innerHTML="",ye(null);return}const e=t;let n="";const o=h.filter(r=>lt(r)===e&&(tt||j(r)!=="done"));for(const r of o){const l=G(r);if(!l&&b!==r.id)continue;const m=j(r),v=m==="done",i=!l,y=l??{x:0,y:0},T=Ve(r.category);if(i||(n+=`<button class="dt-pin dt-pin--${m}" data-id="${r.id}"${l?.off?` data-off="${l.off}"`:""} aria-label="Comment ${r.id}, ${m==="open"?"open":m==="claude"?`resolved by ${g(vt(r.doneAgent))}`:"resolved"}" aria-expanded="${b===r.id}"
|
|
18
|
+
style="left:${y.x}px;top:${y.y}px;--cat:${T.color}"
|
|
19
|
+
title="${g(r.text.slice(0,80))} \xB7 ${T.label}${m==="claude"?` \xB7 resolved by ${g(vt(r.doneAgent))} \u2014 tick to confirm`:m==="done"?" \xB7 resolved":""}">${m==="done"?"\u2713":m==="claude"?Mt(11):""}</button>`),b===r.id){const Y=ls(r);n+=`<div class="dt-note${i?" dt-note--orphan":""}" data-id="${r.id}" role="dialog" aria-label="Comment ${r.id}"
|
|
20
|
+
style="left:${y.x}px;top:${y.y}px">
|
|
18
21
|
<div class="dt-note-bar">
|
|
19
|
-
<span class="dt-note-el">${
|
|
20
|
-
${
|
|
22
|
+
<span class="dt-note-el">${g(Ee(r.tag,r.classes))}</span>
|
|
23
|
+
${wn(r.label)}
|
|
21
24
|
<span class="dt-note-tools">
|
|
22
|
-
${
|
|
25
|
+
${Cn(m,r.id)}
|
|
23
26
|
<i class="dt-note-sep"></i>
|
|
24
|
-
<button data-act="rm" data-id="${
|
|
25
|
-
<button data-act="close" data-id="${
|
|
27
|
+
<button data-act="rm" data-id="${r.id}" title="Delete this thread">${Gt}</button>
|
|
28
|
+
<button data-act="close" data-id="${r.id}" title="Close">${Yt}</button>
|
|
26
29
|
</span>
|
|
27
30
|
</div>
|
|
28
|
-
${
|
|
29
|
-
${
|
|
31
|
+
${i?'<p class="dt-note-orphan">The element this was pinned to is not on the page right now.</p>':""}
|
|
32
|
+
${Sn(Ve(r.category).id,r.id)}
|
|
33
|
+
${r.assignee?`<p class="dt-for dt-for--read">For <b>${g(Co(r.assignee))}</b></p>`:""}
|
|
30
34
|
<div class="dt-note-thread">
|
|
31
|
-
${
|
|
32
|
-
<textarea class="dt-note-edit-input" rows="1">${
|
|
33
|
-
${
|
|
35
|
+
${Y.map((S,qt)=>{const yt=qt===0?null:S.at??null,_e=S.author==="you"&&(!S.by||S.by===M.me?.email),ao=_e&&x?.id===r.id&&x.at===yt,Ge=S.author==="claude"?null:M.team?.find(Ye=>Ye.email===S.by),as=S.author==="claude"?vt(S.agent):_e?"You":Ge?.name||S.byName||S.by||"You",ro=`<div class="dt-msg-head">${Ge?.avatar_url?`<img class="dt-msg-face" src="${g(Ge.avatar_url)}" alt="">`:""}<b>${g(as)}</b><time>${vn(S.at)}</time>${_e&&!ao?`<button class="dt-msg-edit" data-act="edit" data-id="${r.id}" data-at="${g(yt??"")}" title="Edit">${$e}</button>`:""}</div>`;return ao?`<div class="dt-msg">${ro}<div class="dt-compose">
|
|
36
|
+
<textarea class="dt-note-edit-input" rows="1">${g(x.text)}</textarea>
|
|
37
|
+
${Tn(S.images.filter(Ye=>!x.drop.includes(Ye.split("/").pop())),r.id)}
|
|
34
38
|
<div class="dt-compose-bar">
|
|
35
39
|
<button class="dt-edit-cancel" data-act="edit-cancel">Cancel</button>
|
|
36
|
-
<button class="dt-send${
|
|
40
|
+
<button class="dt-send${x.text.trim()?" is-ready":""}" data-act="edit-save" title="Save (Enter)">${ve}</button>
|
|
37
41
|
</div>
|
|
38
|
-
</div></div>`:`<div class="dt-msg">${
|
|
42
|
+
</div></div>`:`<div class="dt-msg" data-msg="${r.id}:${g(S.at??"0")}">${ro}<p>${g(S.text)}</p>${qt===0&&r.suggest?No(r.suggest):""}${Tn(S.images)}</div>`}).join("")}
|
|
39
43
|
</div>
|
|
40
|
-
${
|
|
41
|
-
</div>`}}
|
|
42
|
-
style="left:${
|
|
43
|
-
<div class="dt-note${s?"":" dt-note--orphan"}" data-draft style="left:${
|
|
44
|
+
${kn("dt-note-reply-input","Reply",O,`data-act="reply" data-id="${r.id}"`,Mn(Q))}
|
|
45
|
+
</div>`}}N.forEach((r,l)=>{const m=G(r);m&&(n+=`<button class="dt-pin dt-pin--draft" data-parked="${l}" data-act="draft-open" data-i="${l}"
|
|
46
|
+
style="left:${m.x}px;top:${m.y}px" title="Draft, not sent \u2014 click to finish it">${$e}</button>`)});const s=u&&G(u);if(u){const r=s?.x??0,l=s?.y??0;n+=`${s?`<span class="dt-pin dt-pin--draft" data-draft style="left:${r}px;top:${l}px"></span>`:""}
|
|
47
|
+
<div class="dt-note${s?"":" dt-note--orphan"}" data-draft style="left:${r}px;top:${l}px">
|
|
44
48
|
<div class="dt-note-bar">
|
|
45
|
-
<span class="dt-note-el">${
|
|
46
|
-
${
|
|
47
|
-
${
|
|
49
|
+
<span class="dt-note-el">${g(Ee(u.tag,u.classes))}</span>
|
|
50
|
+
${wn(u.label)}
|
|
51
|
+
${jt()?'<span class="dt-note-draft">Draft</span>':""}
|
|
48
52
|
<span class="dt-note-tools">
|
|
49
|
-
<button data-act="discard" title="Discard this draft">${
|
|
50
|
-
<button data-act="cancel" title="Close \u2014 the draft stays">${
|
|
53
|
+
<button data-act="discard" title="Discard this draft">${Gt}</button>
|
|
54
|
+
<button data-act="cancel" title="Close \u2014 the draft stays">${Yt}</button>
|
|
51
55
|
</span>
|
|
52
56
|
</div>
|
|
53
57
|
${s?"":'<p class="dt-note-orphan">The element this was pinned to is not on the page right now.</p>'}
|
|
54
|
-
${
|
|
55
|
-
${
|
|
56
|
-
|
|
58
|
+
${Sn(u.category)}
|
|
59
|
+
${Bo(u.assignee??$n())}
|
|
60
|
+
${u.suggest?`<div class="dt-suggest"><span class="dt-suggest-head">Should read<button data-act="unsuggest" title="No text change">${Yt}</button></span>
|
|
61
|
+
<textarea class="dt-suggest-input" rows="2">${g(u.suggest.to)}</textarea></div>`:En(s?nt(u):null)?'<button class="dt-suggest-btn" data-act="suggest">Suggest the text</button>':""}
|
|
62
|
+
${kn("dt-note-input",u.suggest?"Why (optional)":"Comment",u.text??"",'data-act="save"',Mn(u.images))}
|
|
63
|
+
</div>`}const a=new Map([...f.querySelectorAll(".dt-note[data-id] .dt-note-thread")].map(r=>[r.closest(".dt-note").dataset.id,{top:r.scrollTop,end:r.scrollTop+r.clientHeight>=r.scrollHeight-4}])),d=new Set([...f.querySelectorAll("[data-msg]")].map(r=>r.dataset.msg));f.innerHTML=n;for(const r of f.querySelectorAll(".dt-note[data-id] .dt-note-thread")){const l=r.closest(".dt-note").dataset.id,m=a.get(l);if(!m)continue;const v=[...r.querySelectorAll("[data-msg]")].filter(i=>!d.has(i.dataset.msg));for(const i of v)i.classList.add("dt-msg--new");r.scrollTop=m.end&&v.length?r.scrollHeight:m.top}for(const r of f.querySelectorAll(".dt-note")){const l=r.getBoundingClientRect();l.bottom>innerHeight-8&&(r.dataset.flip="1"),l.right>innerWidth-8&&(r.dataset.flipx="1")}Bn(e),ye(yn()),ot();for(const r of f.querySelectorAll(".dt-note-input, .dt-note-reply-input, .dt-note-edit-input"))Ie(r);const c=f.querySelector(".dt-note-input");c&&(c.focus(),c.setSelectionRange(c.value.length,c.value.length))},jo=()=>{let t=!1;for(const e of f.querySelectorAll(".dt-pin[data-id], .dt-note[data-id]")){if(e.classList.contains("dt-note--orphan"))continue;const n=h.find(s=>s.id===Number(e.dataset.id)),o=n&&G(n);if(!o){e.style.visibility="hidden";continue}e.style.visibility="",e.style.left=`${o.x}px`,e.style.top=`${o.y}px`,e.classList.contains("dt-pin")&&(o.off?e.dataset.off=o.off:delete e.dataset.off),n&&bn(nt(n))&&(t=!0)}for(const e of f.querySelectorAll("[data-draft], [data-parked]")){if(e.classList.contains("dt-note--orphan"))continue;const n=e.dataset.parked?N[Number(e.dataset.parked)]:u,o=n&&G(n);if(!o){e.style.visibility="hidden";continue}e.style.visibility="",e.style.left=`${o.x}px`,e.style.top=`${o.y}px`}if(!_t.length&&(u||b!=null)){const e=yn();e&&bn(e)&&ye(e)}t&&ot()},Bn=t=>{if(R.hidden)return;const e=h.filter(i=>lt(i)===t),n=new Map(e.map((i,y)=>[i.id,y+1])),o={open:[],claude:[],done:[]};for(const i of e)o[j(i)].push(i);const s=i=>{const y=(i.replies?.length??0)+(i.note?1:0),T=Ve(i.category),Y=j(i),S=Y==="claude",qt=!G(i),yt=i.replies?.length?i.replies[i.replies.length-1]:i.note?{author:"claude",text:i.note}:{author:"you",text:i.text};return`<div class="dt-hist-row is-${Y}${qt?" is-orphan":""}">
|
|
57
64
|
<button class="dt-hist-go" data-go="${i.id}">
|
|
58
|
-
<span class="dt-hist-n" style="--cat:${
|
|
65
|
+
<span class="dt-hist-n" style="--cat:${T.color}">${S?Mt(8):""}</span>
|
|
59
66
|
<span class="dt-hist-body">
|
|
60
|
-
<span class="dt-hist-id">#${n.get(i.id)}<em>${
|
|
61
|
-
<span class="dt-hist-text">${
|
|
62
|
-
<span class="dt-hist-meta">${
|
|
67
|
+
<span class="dt-hist-id">#${n.get(i.id)}<em>${T.label}</em>${S?`<b class="dt-hist-claude">${Mt(9)}${g(vt(i.doneAgent))}</b>`:""}${qt?'<b class="dt-hist-orphan" title="The element this was pinned to is not on the page right now">no pin</b>':""}</span>
|
|
68
|
+
<span class="dt-hist-text">${yt.author==="claude"?`<b>${g(vt(yt.agent))}:</b> `:""}${g(yt.text)}</span>
|
|
69
|
+
<span class="dt-hist-meta">${vn(i.updatedAt||i.createdAt)}${i.device?` \xB7 ${g(i.device)}`:i.browser?` \xB7 ${g(i.browser)}`:""}${y?` \xB7 ${y} repl${y===1?"y":"ies"}`:""}</span>
|
|
63
70
|
</span>
|
|
64
71
|
</button>
|
|
65
|
-
<span class="dt-note-tools dt-hist-tools">${
|
|
66
|
-
><button data-rm="${i.id}" title="Delete this comment">${
|
|
67
|
-
</div>`},
|
|
68
|
-
title="${i.label}: ${
|
|
69
|
-
><svg viewBox="0 0 20 20" width="11" height="11" aria-hidden="true">${i.icon}</svg><i>${
|
|
72
|
+
<span class="dt-note-tools dt-hist-tools">${Cn(Y,i.id)}<i class="dt-note-sep"></i
|
|
73
|
+
><button data-rm="${i.id}" title="Delete this comment">${Gt}</button></span>
|
|
74
|
+
</div>`},a=B.find(i=>i.id===t),d=B.map(i=>{const y=h.filter(T=>lt(T)===i.id&&j(T)!=="done");return{band:i,open:y.filter(T=>j(T)==="open").length,total:y.length}}).filter(i=>i.total&&i.band.id!==t),c=d.length?`<i class="dt-hist-sep"></i><div class="dt-hist-bands">${d.map(({band:i,open:y,total:T})=>`<button data-bp="${i.id}" data-state="${y?"open":"claude"}"
|
|
75
|
+
title="${i.label}: ${y} open \xB7 ${T-y} to check"
|
|
76
|
+
><svg viewBox="0 0 20 20" width="11" height="11" aria-hidden="true">${i.icon}</svg><i>${T}</i></button>`).join("")}</div>`:"",l=["open","claude","done"].filter(i=>o[i].length&&(i!=="done"||tt)),m=C.hidden?Hn():we,v=i=>`<div class="dt-hist-row is-draft">
|
|
70
77
|
<button class="dt-hist-go" data-draft-go="${i.i}">
|
|
71
|
-
<span class="dt-hist-n">${
|
|
78
|
+
<span class="dt-hist-n">${$e}</span>
|
|
72
79
|
<span class="dt-hist-body">
|
|
73
|
-
<span class="dt-hist-id">${
|
|
74
|
-
<span class="dt-hist-text">${i.text?
|
|
80
|
+
<span class="dt-hist-id">${g(i.el)}${i.orphan?'<b class="dt-hist-orphan" title="The element this was pinned to is not on the page right now">no pin</b>':""}</span>
|
|
81
|
+
<span class="dt-hist-text">${i.text?g(i.text):`${i.shots} screenshot${i.shots===1?"":"s"}`}</span>
|
|
75
82
|
</span>
|
|
76
83
|
</button>
|
|
77
|
-
<span class="dt-note-tools dt-hist-tools"><button data-draft-rm="${i.i}" title="Discard this draft">${
|
|
78
|
-
</div>`;
|
|
79
|
-
<span class="dt-hist-here" title="${
|
|
80
|
-
><svg viewBox="0 0 20 20" width="13" height="13" aria-hidden="true">${
|
|
84
|
+
<span class="dt-note-tools dt-hist-tools"><button data-draft-rm="${i.i}" title="Discard this draft">${Gt}</button></span>
|
|
85
|
+
</div>`;R.innerHTML=`<div class="dt-hist-head">
|
|
86
|
+
<span class="dt-hist-here" title="${a?.label??t}"
|
|
87
|
+
><svg viewBox="0 0 20 20" width="13" height="13" aria-hidden="true">${a?.icon??""}</svg></span>
|
|
81
88
|
<span class="dt-hist-title">Comments</span>
|
|
82
|
-
${
|
|
89
|
+
${c}
|
|
90
|
+
${ke().length&&!$?`<button class="dt-review-btn" data-review title="Walk through every fix waiting for a look">Check ${ke().length}</button>`:""}
|
|
83
91
|
<button class="dt-hist-refresh" data-refresh aria-label="Reload comments from the file">
|
|
84
92
|
<svg viewBox="0 0 20 20" width="13" height="13" aria-hidden="true"><path d="M16 10a6 6 0 1 1-1.8-4.3"/><path d="M16.3 3.4v3.4h-3.4"/></svg>
|
|
85
93
|
</button>
|
|
86
94
|
<button class="dt-hist-fold" data-fold aria-label="Collapse or expand the panel">
|
|
87
95
|
<svg viewBox="0 0 20 20" width="13" height="13" aria-hidden="true"><path d="M5.5 8.5 10 12.5l4.5-4"/></svg>
|
|
88
96
|
</button>
|
|
89
|
-
</div>`+(
|
|
90
|
-
${H}`:""}},ce=t=>(Array.isArray(t)?t:[]).filter(e=>e&&Number.isInteger(Number(e.id))&&typeof e.text=="string").map(e=>({...e,id:Number(e.id),rx:Number(e.rx)||0,ry:Number(e.ry)||0,route:typeof e.route=="string"&&/^\/(?!\/)/.test(e.route)?e.route:"/",replies:Array.isArray(e.replies)?e.replies.filter(n=>typeof n?.text=="string"):[],images:Array.isArray(e.images)?e.images.filter(n=>typeof n=="string"):[]})),Dt=async()=>{try{mn(ce((await(await j("comments")).json()).comments))}catch{}};let Rt="",ue=!1;const pe=async()=>{if(!(document.hidden||ue)){ue=!0;try{const t=await j(`comments${Rt?`?since=${Rt}`:""}`);if(t.status!==200)return;const e=await t.json();Rt=e.version??"";const n=ce(e.comments);mn(n);const o=n.filter(s=>s.route===tt);if(JSON.stringify(o)===JSON.stringify(B))return;if(m.contains(document.activeElement)&&document.activeElement.matches("textarea, input")){Rt="";return}B=o,h(),q({reload:!0})}catch{}finally{ue=!1}}},st=async()=>{try{const t=await j(`comments?route=${encodeURIComponent(tt)}`);B=ce((await t.json()).comments)}catch{B=[]}h()};let me=0;const hn=t=>{me||(me=requestAnimationFrame(()=>{me=0;const e=t.target;if(!M||e.closest(Ne)){nt.hidden=!0;return}nt.hidden=!0;const n=document.elementFromPoint(t.clientX,t.clientY);if(nt.hidden=!1,!n)return;const o=n.getBoundingClientRect();Jn.style.cssText=`left:${o.left}px;top:${o.top}px;width:${o.width}px;height:${o.height}px`,Fe.textContent=n.tagName.toLowerCase()+([...n.classList].find(s=>!/^(astro|svelte)-/.test(s))?"."+[...n.classList].find(s=>!/^(astro|svelte)-/.test(s)):"")+` ${Math.round(o.width)}\xD7${Math.round(o.height)}`,Fe.style.cssText=`left:${o.left}px;top:${Math.max(2,o.top-20)}px`}))},gn=t=>{if(!(t.key!=="Escape"||t.isComposing)){if(t.preventDefault(),$){$=null,h();return}if(u){P(),h();return}if(y!==null){y=null,h();return}at(!1)}},fn=t=>{if(t.target.closest(Ne))return;if(t.preventDefault(),t.stopPropagation(),Gt){Gt=!1;return}if(!getSelection()?.isCollapsed)return;m.hidden=!0;const n=document.elementFromPoint(t.clientX,t.clientY);if(m.hidden=!1,!n)return;P();const o=n.getBoundingClientRect(),s=n.tagName.toLowerCase(),r=[...n.classList].filter(a=>!/^(astro|svelte|css)-/.test(a)).slice(0,2);u={selector:eo(n),tag:s,classes:r,nth:Ge({tag:s,classes:r}).indexOf(n),rx:o.width?(t.clientX-o.left)/o.width:.5,ry:o.height?(t.clientY-o.top)/o.height:.5,label:it(n.textContent||"").slice(0,60),category:Me[0].id},y=null,nt.hidden=!0,h()},co=2200,uo=900*1024,po=8*1024*1024,St=t=>{const e=document.createElement("div");e.className="dt-toast",e.textContent=t,document.body.append(e),setTimeout(()=>e.remove(),2800)},mo=t=>new Promise(e=>{const n=new FileReader;n.onload=()=>e(String(n.result)),n.readAsDataURL(t)}),ho=async t=>{const e=await createImageBitmap(t),n=Math.min(1,co/Math.max(e.width,e.height));if(n===1&&t.size<=uo)return e.close(),mo(t);const o=document.createElement("canvas");return o.width=Math.round(e.width*n),o.height=Math.round(e.height*n),o.getContext("2d").drawImage(e,0,0,o.width,o.height),e.close(),o.toDataURL("image/jpeg",.85)},he=async(t,e)=>{const n=[];for(const o of t){let s;try{s=await ho(o)}catch{St("That image could not be read.");continue}if(s.length>po){St("Screenshot is too large even after shrinking.");continue}n.push(s)}if(n.length){if(!Number(e?.dataset.id)){u&&((u.images??=[]).push(...n),h());return}ot.push(...n),h(),yn(".dt-note-reply-input")}},bn=t=>[...t??[]].filter(e=>e.kind==="file"&&e.type.startsWith("image/")).map(e=>e.getAsFile()).filter(Boolean);m.addEventListener("paste",t=>{const e=bn(t.clipboardData?.items);e.length&&(t.preventDefault(),he(e,t.target.closest(".dt-note")))}),m.addEventListener("dragover",t=>{t.target.closest(".dt-note")&&(t.preventDefault(),t.target.closest(".dt-note").querySelector(".dt-compose")?.setAttribute("data-drop",""))}),m.addEventListener("dragleave",t=>{t.target.closest(".dt-note")?.querySelector(".dt-compose")?.removeAttribute("data-drop")}),m.addEventListener("drop",t=>{const e=t.target.closest(".dt-note");if(!e)return;t.preventDefault(),e.querySelector(".dt-compose")?.removeAttribute("data-drop");const n=bn(t.dataTransfer?.items);n.length&&he(n,e)});const yn=t=>{const e=m.querySelector(t);e?.focus(),e?.setSelectionRange(e.value.length,e.value.length)},vn=()=>{yn(".dt-note-edit-input"),m.querySelector(".dt-msg .dt-compose")?.scrollIntoView({block:"nearest"})},$n=t=>{t.style.overflowY="hidden",t.style.height="auto",t.style.height=`${t.scrollHeight}px`,t.style.overflowY=t.scrollHeight>t.clientHeight?"auto":"hidden"},go=t=>/(?:^|\s)@([^\s@]*)$/.exec(t.value.slice(0,t.selectionStart??t.value.length)),fo=t=>{t.closest(".dt-compose").querySelector(".dt-mentions")?.remove();const n=go(t);if(!n||!N.team?.length)return;const o=n[1].toLowerCase(),s=N.team.filter(r=>[r.name,r.nickname,r.email].some(a=>a?.toLowerCase().startsWith(o))).slice(0,5);s.length&&t.insertAdjacentHTML("afterend",`<div class="dt-mentions" role="listbox" aria-label="Mention someone">${s.map((r,a)=>`<button type="button" role="option" aria-selected="${a===0}" data-act="mention" data-handle="${E(To(r))}">${E(r.name||r.email)}${r.name?` <span>${E(r.email)}</span>`:""}</button>`).join("")}</div>`)},En=(t,e)=>{const n=t.selectionStart??t.value.length,o=t.value.slice(0,n).lastIndexOf("@");t.value=`${t.value.slice(0,o)}@${e} ${t.value.slice(n)}`,t.selectionStart=t.selectionEnd=o+e.length+2,t.closest(".dt-compose")?.querySelector(".dt-mentions")?.remove(),t.dispatchEvent(new Event("input",{bubbles:!0})),t.focus()};m.addEventListener("input",t=>{const e=t.target.closest(".dt-note-input, .dt-note-reply-input, .dt-note-edit-input");e&&(fo(e),e.classList.contains("dt-note-input")?u&&(u.text=e.value):e.classList.contains("dt-note-edit-input")?$&&($.text=e.value):D=e.value,ze(),e.closest(".dt-compose")?.querySelector(".dt-send")?.classList.toggle("is-ready",e.value.trim()!==""),$n(e))}),m.addEventListener("keydown",t=>{const e=t.target.closest(".dt-note-input, .dt-note-reply-input, .dt-note-edit-input");if(!e)return;const n=e.closest(".dt-compose")?.querySelector(".dt-mentions button");if(n&&(t.key==="Enter"||t.key==="Tab")&&!t.isComposing){t.preventDefault(),En(e,n.dataset.handle);return}if(n&&t.key==="Escape"){t.stopPropagation(),n.parentElement.remove();return}t.key!=="Enter"||t.shiftKey||t.isComposing||(t.preventDefault(),e.closest(".dt-compose")?.querySelector(".dt-send")?.click())}),m.addEventListener("click",async t=>{const e=t.target.closest("button");if(!e)return;const n=e.dataset.act,o=Number(e.dataset.id);if(n==="mention"){const s=e.closest(".dt-compose")?.querySelector("textarea");s&&En(s,e.dataset.handle);return}if(!n){y=y===o?null:o,P(),h();return}if(n==="attach"){const s=Object.assign(document.createElement("input"),{type:"file",accept:"image/*",multiple:!0}),r=e.closest(".dt-note");s.addEventListener("change",()=>{s.files?.length&&he([...s.files],r)}),s.click();return}if(n==="unshot"){o?$&&$.drop.push(e.dataset.img):(e.closest("[data-draft]")?u?.images??[]:ot).splice(Number(e.dataset.i),1),h(),$&&vn();return}if(n==="edit"){const s=B.find(l=>l.id===o),r=e.dataset.at||null,a=r?s?.replies?.find(l=>l.at===r)?.text:s?.text;if(a===void 0)return;$={id:o,at:r,text:a,drop:[]},h(),vn();return}if(n==="edit-cancel"){$=null,h();return}if(n==="edit-save"){const s=$;if(!s)return;const r=s.text.trim();if(!r){m.querySelector(".dt-note-edit-input")?.focus();return}$=null;const a=await j("comments",{method:"PATCH",headers:{"content-type":"application/json"},body:JSON.stringify({id:s.id,edit:{at:s.at,text:r},...s.drop.length?{removeImage:s.drop}:{}})});a.ok||($=s,St(`Edit was not saved (${a.status}).`)),await X();return}if(n==="cancel"){P(),h();return}if(n==="discard"){u=null,h();return}if(n==="draft-open"){le(Number(e.dataset.i));return}if(n==="close"){y=null,h();return}if(n==="cat"){const s=e.dataset.cat;if(!o){u&&(u.category=s),h();return}await j("comments",{method:"PATCH",headers:{"content-type":"application/json"},body:JSON.stringify({id:o,category:s})}),await X();return}if(n==="save"){const s=m.querySelector(".dt-note-input").value.trim();if(!u)return;if(!s){m.querySelector(".dt-note-input")?.focus();return}const r=await j("comments",{method:"POST",headers:{"content-type":"application/json"},body:JSON.stringify({...u,route:tt,text:s,breakpoint:J(),browser:to(),device:w?wn:"",viewport:{w:innerWidth,h:innerHeight}})});if(!r.ok){St(`Comment was not saved (${r.status}).`);return}u=null,await X();return}if(n==="reply"){const s=m.querySelector(".dt-note-reply-input"),r=s.value.trim();if(!r){s.focus();return}const a=ot;D="",ot=[];const l=await j("comments",{method:"PATCH",headers:{"content-type":"application/json"},body:JSON.stringify({id:o,reply:r,images:a})});l.ok||(D=r,ot=a,St(`Reply was not sent (${l.status}).`)),await X();return}n==="rm"?await j(`comments?id=${o}`,{method:"DELETE"}):await an(o,n==="done"),y=null,await X()});let Lt="overlay",dt="",wn="";const q=t=>{T.hidden||v.contentWindow?.postMessage({dt:!0,...t},location.origin)},bo=()=>({notes:M,grid:!kt.hidden,inspect:et,resolved:V,scrollbar:Lt,device:dt});addEventListener("message",t=>{if(t.origin!==location.origin||!t.data?.dt)return;const e=t.data;if(!w&&t.source===v.contentWindow){if(e.key){Nn(e.key[0],e.key[1])?.run();return}if(e.closeMenus){ft();return}if(e.drafts){re=e.drafts,rn(oe());return}}if(w&&typeof e.openDraft=="number"){le(e.openDraft);return}if(w&&typeof e.dropDraft=="number"){dn(e.dropDraft);return}if(w&&typeof e.device=="string"&&(wn=e.device),w&&e.scrollbar&&document.documentElement.classList.toggle("dt-sb-classic",e.scrollbar==="classic"),e.hello&&t.source===v.contentWindow){q(bo());return}typeof e.notes=="boolean"&&e.notes!==M&&at(e.notes,!1),typeof e.open=="number"&&ln(e.open),typeof e.grid=="boolean"&&e.grid===kt.hidden&&Wt(e.grid),typeof e.inspect=="string"&&e.inspect!==et&&At(e.inspect),typeof e.resolved=="boolean"&&e.resolved!==V&&cn(e.resolved),e.reload&&(st(),Dt())});const X=async()=>{await st(),Dt(),q({reload:!0}),w&&parent.postMessage({dt:!0,reload:!0},location.origin)},at=(t,e=!0)=>{M=t,Re.setAttribute("aria-pressed",String(t)),t?!w&&I.hidden&&localStorage.getItem("dt-history")!=="0"&&(I.hidden=!1,Ct.setAttribute("aria-pressed","true")):(I.hidden=!0,Ct.setAttribute("aria-pressed","false")),R(Ke,t?"1":"0"),q({notes:t}),w&&e&&parent.postMessage({dt:!0,notes:t},location.origin),m.hidden=!t||!T.hidden,document.documentElement.classList.toggle("dt-noting",t),t?(At(""),document.addEventListener("click",fn,!0),document.addEventListener("keydown",gn),document.addEventListener("mousemove",hn),addEventListener("scroll",lt,!0),addEventListener("resize",lt),un.observe(document.body,{childList:!0,subtree:!0,characterData:!0}),pn.observe(document.body),st()):(P(),y=null,document.removeEventListener("click",fn,!0),document.removeEventListener("keydown",gn),document.removeEventListener("mousemove",hn),nt.hidden=!0,removeEventListener("scroll",lt,!0),removeEventListener("resize",lt),un.disconnect(),pn.disconnect(),m.innerHTML="")},Ot="dt-w",ge="dt-canvas",ct="dt-device";let Z=localStorage.getItem(ge)==="1",g=localStorage.getItem(ct)||"";g&&!Ht(g)&&(g="",localStorage.setItem(ct,""));let x=Number(localStorage.getItem(Ot))||0;const Sn="dt-emu";let C=(()=>{try{return JSON.parse(localStorage.getItem(Sn)||"null")}catch{return null}})();const Ft=()=>C?On.find(t=>t.id===C.id)??null:null,yo=()=>{const t=Ft();return t?C.turned?{w:t.h,h:t.w}:{w:t.w,h:t.h}:null};let xt=localStorage.getItem("dt-bars-min")==="1";const ut=t=>{C=t,R(Sn,t?JSON.stringify(t):"")},fe=t=>{Pe.textContent=t,T.style.setProperty("--dt-badge-w",`${Pe.offsetWidth}px`)},Ln=t=>{if(!t){yt.innerHTML="";return}let e="";for(let n=0;n<=t;n+=50)e+=`<span class="dt-tick${n%200===0?" is-major":""}" style="left:${n}px"></span>`;for(const n of k)for(const o of[n.min,n.max])o>0&&Number.isFinite(o)&&o<=t&&(e+=`<span class="dt-edge" style="left:${o}px" title="${n.label} edge"></span>`);yt.innerHTML=e,yt.style.width=`${t}px`},be=()=>{const t=parseFloat(f.style.width)||0,e=parseFloat(f.style.height)||0;if(!t||!e){f.style.transform="",delete f.dataset.scaled;return}const n=g||C?Math.min(1,(innerWidth-80)/t,(innerHeight-120)/e):Math.min(1,(innerWidth-80)/t);f.style.transform=n<1?`scale(${n})`:"",f.dataset.scaled=n<1?String(Math.round(n*100)):""},vo=t=>On.find(e=>e.w===t.w&&e.h===t.h&&e.cutout?.shape==="pill")?.cutout,Pt=()=>{try{return v.contentDocument}catch{return null}},xn=()=>Pt()?.title.split("\u2014").pop()?.trim()||"",ye=()=>{const t=Pt(),e=g?Ht(g):null;if(!t?.body||!e)return;const n=Co(t),o=e.browser==="chrome-android"?n.theme||"rgb(255, 255, 255)":n.top,s=e.browser==="chrome-android"?"rgb(255, 255, 255)":n.bottom;f.style.setProperty("--dt-top",o),f.style.setProperty("--dt-top-ink",Fn(o)),f.style.setProperty("--dt-bottom",s),f.style.setProperty("--dt-bottom-ink",Fn(s));const r=bt.querySelector(".dt-win-tab > span");r&&(r.textContent=xn()||location.host)};let ve=0;v.addEventListener("load",()=>{Pt()&&(ye(),v.contentWindow?.addEventListener("scroll",()=>{ve||(ve=requestAnimationFrame(()=>{ve=0,ye()}))},{passive:!0}))});for(const t of[bt,Bt])t.addEventListener("click",e=>{const n=e.target.closest("[data-nav]")?.dataset.nav;if(n)try{const o=v.contentWindow?.navigation;if(!Pt()||!o)throw new Error("foreign");n==="back"?o.canGoBack&&o.back():n==="fwd"?o.canGoForward&&o.forward():o.reload()}catch{(n==="reload"||n==="back")&&(v.src=location.href)}});vt.addEventListener("click",()=>{xt=!xt,R("dt-bars-min",xt?"1":"0"),G()});const G=()=>{if(w)return;const t=g?Ht(g)??null:null;if(g&&!t&&(g="",localStorage.setItem(ct,"")),!t&&!Z){T.hidden=!0,v.removeAttribute("src"),document.documentElement.classList.remove("dt-framing"),m.hidden=!M,yt.innerHTML="",Et(),Qt.hidden=!0,vt.hidden=!0,z=null,dt="",re=[],Et(),Ee(),M?st():h();return}if(T.hidden=!1,document.documentElement.classList.add("dt-framing"),m.hidden=!0,v.src||(v.src=location.href),t){const e=Ao(t,{host:location.host,title:xn(),now:new Date,min:xt,cutout:vo(t)}),{screen:n}=e;T.dataset.mode="device",f.dataset.shell=t.shell,f.dataset.browser=t.browser,f.style.width=`${e.footprint.w}px`,f.style.height=`${e.footprint.h}px`,f.style.setProperty("--dt-r",`${n.r}px`),f.style.setProperty("--dt-rb",`${n.rb}px`),Oe.innerHTML=e.shell;const o=(a,l,d,c)=>{a.innerHTML=c,a.style.cssText=`left:${n.x}px;top:${l}px;width:${n.w}px;height:${d}px`};o(bt,n.y,e.topH,e.top),o(Bt,n.y+n.h-e.bottomH,e.bottomH,e.bottom);const s=n.h-e.topH-e.bottomH;v.style.position="absolute",v.style.left=`${n.x}px`,v.style.top=`${n.y+e.topH}px`,v.style.width=`${n.w}px`,v.style.height=`${s}px`,yt.innerHTML="";const r=xt&&e.canMinimize;Lt=e.scrollbar,dt=`${t.label}${r?" \xB7 bars folded":""}`,z=ht(t.w),q({notes:M,scrollbar:Lt,device:dt}),vt.hidden=!e.canMinimize,vt.setAttribute("aria-pressed",String(r)),fe(`${t.label} \xB7 page ${t.w}\xD7${s} of ${t.w}\xD7${t.h}${r?" \xB7 bars folded":""} \xB7 ${k.find(a=>a.id===z)?.label??""}`),ye()}else{const e=yo();e||ut(null);const n=e?.w||x||k.find(r=>r.id===J()).ideal;x=n,T.dataset.mode="canvas",delete f.dataset.shell,delete f.dataset.browser,Oe.innerHTML=bt.innerHTML=Bt.innerHTML="",bt.style.cssText=Bt.style.cssText="",vt.hidden=!0,Lt="overlay",f.style.width=`${n}px`,f.style.height=`${e?.h??innerHeight-84}px`,v.style.position="",v.style.left=v.style.top="",v.style.width="100%",v.style.height="100%",Ln(n),q({notes:M});const o=k.find(r=>r.id===ht(n)),s=Ft();dt=s?`${s.label}${C?.turned?" \xB7 landscape":""}`:"",q({scrollbar:Lt,device:dt}),fe(s&&e?`${s.label} \xB7 ${e.w}\xD7${e.h} \xB7 ${o.label}`:`${n}px \xB7 ${o.label}`),z=ht(n)}Qt.hidden=!(Ft()?.rotates&&!t),Ee(),be(),Et(),M?st():h()},Tn=t=>{const e=k.find(n=>n.id===t);g="",localStorage.setItem(ct,""),ut(null),Z=t!==jt,x=Z?e.ideal:0,z=Z?t:null,localStorage.setItem(ge,Z?"1":"0"),localStorage.setItem(Ot,String(x)),y=null,P(),G()};for(const t of Xt)t.addEventListener("click",()=>Tn(t.dataset.bp));for(const t of document.querySelectorAll("[data-device]"))t.addEventListener("click",()=>{g=t.dataset.device===g?"":t.dataset.device,localStorage.setItem(ct,g),F.open=!1,G()});for(const t of document.querySelectorAll("[data-emu]"))t.addEventListener("click",()=>{const e=C?.id===t.dataset.emu&&!g;g="",localStorage.setItem(ct,""),ut(e?null:{id:t.dataset.emu,turned:!1}),Z=!e,x=0,localStorage.setItem(ge,Z?"1":"0"),z=null,y=null,P(),F.open=!1,G()});Qt.addEventListener("click",()=>{C&&(ut({...C,turned:!C.turned}),y=null,P(),G())});const Mn=[...F.querySelectorAll("[data-tab]")],$o=[...F.querySelectorAll("[data-panel]")],Hn=t=>{for(const e of Mn)e.setAttribute("aria-selected",String(e.dataset.tab===t));for(const e of $o)e.hidden=e.dataset.panel!==t;R("dt-devices-tab",t)};for(const t of Mn)t.addEventListener("click",()=>Hn(t.dataset.tab));Hn(localStorage.getItem("dt-devices-tab")==="devtools"?"devtools":"preview");const $e=F.querySelector(".dt-emu-search");$e.addEventListener("input",()=>{const t=$e.value.trim().toLowerCase();let e=null,n=!1;const o=()=>{e&&(e.hidden=!n)};for(const s of $e.parentElement.children){if(s.classList.contains("dt-devices-group")){o(),e=s,n=!1;continue}s.dataset.emu&&(s.hidden=!!t&&!s.textContent.toLowerCase().includes(t),n||=!s.hidden)}o()});const Eo=F.querySelector(".dt-devices-name");function Ee(){for(const e of F.querySelectorAll("[data-device]"))e.setAttribute("aria-pressed",String(e.dataset.device===g));const t=!g&&!T.hidden?C?.id:void 0;for(const e of F.querySelectorAll("[data-emu]"))e.setAttribute("aria-pressed",String(e.dataset.emu===t));Eo.textContent=g&&Ht(g)?.label||t&&Ft()?.label||"Device"}const we=t=>k.find(e=>e.id===t),wo=t=>{const e=we(z??J());return Math.max(e.min||320,Math.min(Number.isFinite(e.max)?e.max:2560,Math.round(t)))};for(const t of Xn){const e=t.dataset.edge==="l"?-1:1;t.addEventListener("pointerdown",n=>{if(g)return;n.preventDefault(),C&&(ut(null),G()),t.setPointerCapture(n.pointerId);const o=n.clientX,s=x,r=Number(f.dataset.scaled||100)/100;T.dataset.dragging="1";const a=d=>{x=wo(s+e*(d.clientX-o)*2/r),f.style.width=`${x}px`,Ln(x),fe(`${x}px \xB7 ${we(ht(x)).label}`),be()},l=()=>{t.removeEventListener("pointermove",a),t.removeEventListener("pointerup",l),delete T.dataset.dragging,localStorage.setItem(Ot,String(x)),G()};t.addEventListener("pointermove",a),t.addEventListener("pointerup",l)}),t.addEventListener("dblclick",()=>{if(g)return;ut(null);const n=we(z??J()),o=[n.min||320,Number.isFinite(n.max)?n.max:n.ideal];x=Math.abs(x-o[0])<Math.abs(x-o[1])?o[0]:o[1],localStorage.setItem(Ot,String(x)),G()})}let kn=J();addEventListener("resize",()=>{Et(),J()!==kn&&(kn=J(),h()),T.hidden||(!g&&!C&&(f.style.height=`${innerHeight-84}px`),be())});const An="dt-studio",Cn=t=>{Zt.setAttribute("aria-pressed",String(t)),document.documentElement.classList.toggle("dt-no-studio",!t),R(An,t?"1":"0")};Zt.addEventListener("click",()=>Cn(Zt.getAttribute("aria-pressed")!=="true")),Cn(localStorage.getItem(An)!=="0"),Re.addEventListener("click",()=>at(!M));const pt=document.querySelector(".devtools"),Tt=document.querySelector(".dt-tab"),Bn=t=>{pt.toggleAttribute("data-collapsed",t),Tt.toggleAttribute("data-collapsed",t),Tt.setAttribute("aria-expanded",String(!t)),Tt.setAttribute("aria-label",t?"Show the bar":"Hide the bar");for(const e of pt.querySelectorAll(".dt-group"))e.inert=t;t&&ft(),R("dt-collapsed",t?"1":"0")};Tt.addEventListener("click",()=>Bn(!pt.hasAttribute("data-collapsed")));const Se=document.querySelector(".dt-keys"),Q=t=>()=>pt.querySelector(t)?.click(),qn=t=>()=>{const e=[...document.querySelectorAll(".dt-pages a")];e[e.findIndex(n=>n.hasAttribute("aria-current"))+t]?.click()},Kt=[{group:"Comments",code:"KeyC",hint:"C",label:"Comment mode",el:".dt-notes-btn",run:Q(".dt-notes-btn")},{group:"Comments",code:"KeyC",shift:!0,hint:"\u21E7C",label:"Comments panel",el:".dt-history-btn",run:Q(".dt-history-btn")},{group:"Comments",code:"KeyR",hint:"R",label:"Show resolved",el:".dt-resolved-btn",run:Q(".dt-resolved-btn")},{group:"Inspect",code:"KeyG",hint:"G",label:"Grid",el:".dt-grid-btn",run:Q(".dt-grid-btn")},{group:"Inspect",code:"KeyP",hint:"P",label:"Spacing",el:".dt-pad-btn",run:Q(".dt-pad-btn")},{group:"Inspect",code:"KeyS",hint:"S",label:"Size",el:".dt-size-btn",run:Q(".dt-size-btn")},{group:"Inspect",code:"KeyT",hint:"T",label:"Typography",el:".dt-type-btn",run:Q(".dt-type-btn")},...N.sanity?[{group:"Inspect",code:"KeyE",hint:"E",label:"Sanity overlay",el:".dt-studio-btn",run:Q(".dt-studio-btn")}]:[],...Xt.slice(0,9).map((t,e)=>({group:"Breakpoints",code:`Digit${e+1}`,hint:String(e+1),label:t.dataset.tip??t.title,el:`.dt-bp[data-bp="${t.dataset.bp}"]`,run:()=>t.click()})),{group:"View",code:"KeyD",hint:"D",label:"Devices",run:()=>{F.open=!F.open}},{group:"View",code:"BracketLeft",hint:"[",label:"Previous page",run:qn(-1)},{group:"View",code:"BracketRight",hint:"]",label:"Next page",run:qn(1)},{group:"View",code:"Backslash",hint:"\\",label:"Hide the bar",run:()=>Tt.click()},{group:"View",code:"Slash",shift:!0,hint:"?",label:"This list",el:".dt-keys summary",run:()=>{Se.open=!Se.open}}],Nn=(t,e)=>Kt.find(n=>n.code===t&&!n.shift==!e),So=t=>t instanceof HTMLElement&&(t.isContentEditable||/^(INPUT|TEXTAREA|SELECT)$/.test(t.tagName));if(N.shortcuts){for(const e of Kt){const n=e.el&&pt.querySelector(e.el);n&&(n.dataset.tip=`${n.dataset.tip??e.label} \xB7 ${e.hint}`,n.setAttribute("aria-keyshortcuts",e.hint.startsWith("\u21E7")?`Shift+${e.hint.slice(1)}`:e.hint))}const t=(e,n)=>`<div class="dt-key-row"><span>${E(e)}</span><kbd>${E(n)}</kbd></div>`;if(Se.querySelector(".dt-keys-menu").innerHTML='<p class="dt-menu-note">One key, no modifier, in any keyboard layout. Not while you type.</p>'+[...new Set(Kt.map(e=>e.group))].map(e=>`<p class="dt-devices-group">${e}</p>`+Kt.filter(n=>n.group===e).map(n=>t(n.label,n.hint)).join("")).join("")+'<p class="dt-devices-group">In a comment</p>'+t("Send","Enter")+t("New line","\u21E7Enter")+t("Close, cancel, back out","Esc"),document.addEventListener("keydown",e=>{if(e.repeat||e.isComposing||e.metaKey||e.ctrlKey||e.altKey||e.defaultPrevented||So(e.target))return;const n=Nn(e.code,e.shiftKey);n&&(e.preventDefault(),w?parent.postMessage({dt:!0,key:[e.code,e.shiftKey]},location.origin):n.run())}),w){const e=()=>parent.postMessage({dt:!0,closeMenus:!0},location.origin);document.addEventListener("pointerdown",e,!0),document.addEventListener("keydown",n=>{n.key==="Escape"&&e()})}}if(!w){Bn(localStorage.getItem("dt-collapsed")==="1"),requestAnimationFrame(()=>requestAnimationFrame(()=>pt.setAttribute("data-ready",""))),Z||g?G():Ee(),Wt(localStorage.getItem(ke)==="1");const t=localStorage.getItem(qe);t&&t in Yt&&At(t),at(localStorage.getItem(Ke)==="1")}const In=()=>{try{const t=JSON.parse(localStorage.getItem(rt)||"null");A=(t?.parked??[]).filter(e=>qt(e)),t?.draft&&document.querySelector(t.draft.selector)?(u=t.draft,!M&&!w&&at(!0)):qt(t?.draft)&&A.push(t.draft),t?.reply?.text&&(D=t.reply.text,$t=y=t.reply.for??null),(u||A.length||D)&&h()}catch{localStorage.removeItem(rt)}};In();const Dn=()=>setTimeout(()=>{const t=zt(location.pathname);t!==tt&&(clearTimeout(Nt),ne(),tt=t,rt=je(),u=null,A=[],D="",$t=null,y=null,$=null,B=[],Ce(),In(),st())});for(const t of["pushState","replaceState"]){const e=window.history[t];window.history[t]=function(...n){e.apply(this,n),Dn()}}addEventListener("popstate",Dn),M||st(),Dt(),document.addEventListener("visibilitychange",()=>{document.hidden||pe()}),addEventListener("focus",pe),w||setInterval(pe,2e4),w&&parent.postMessage({dt:!0,hello:!0},location.origin)}export{Fo as run};
|
|
97
|
+
</div>`+(l.length||m.length?`<div class="dt-hist-list">${m.length?`<p class="dt-hist-group">Drafts<em>${m.length}</em></p>${m.map(v).join("")}`:""}${l.map(i=>`<p class="dt-hist-group">${rs[i]}<em>${o[i].length}</em></p>`+o[i].map(s).join("")).join("")}</div>`:`<p class="dt-hist-empty">${o.done.length?"Everything here is resolved.":"No comments at this breakpoint yet. Click anything on the page to leave one."}</p>`)},Se=t=>R.toggleAttribute("data-collapsed",t);R.addEventListener("click",async t=>{const e=t.target.closest("[data-refresh]");if(e){e.dataset.spin="1",await J(),setTimeout(()=>delete e.dataset.spin,500);return}if(R.hasAttribute("data-collapsed")&&t.target.closest(".dt-hist-head")){Se(!1);return}if(t.target.closest("[data-fold]")){Se(!R.hasAttribute("data-collapsed"));return}const n=t.target.closest(".dt-hist-bands [data-bp]");if(n){Pe(n.dataset.bp);return}const o=t.target.closest("[data-draft-go], [data-draft-rm]");if(o){const r=o.dataset.draftRm!==void 0,l=Number(r?o.dataset.draftRm:o.dataset.draftGo);C.hidden?r?Nn(l):xe(l):I(r?{dropDraft:l}:{openDraft:l});return}const s=t.target.closest(".dt-hist-tools [data-act]");if(s){await Vt(Number(s.dataset.id),s.dataset.act==="done"),await J();return}const a=t.target.closest("[data-rm]");if(a){await V(`comments?id=${a.dataset.rm}`,{method:"DELETE"}),b=null,await J();return}if(t.target.closest("[data-review]")){Ko();return}const d=t.target.closest("[data-go]");if(!d)return;const c=Number(d.dataset.go);if(!C.hidden){I({open:c});return}Le(c)});const Le=t=>{b=t,_(),p();const e=h.find(o=>o.id===t),n=e&&G(e);n?scrollTo({top:scrollY+n.y-innerHeight/2,behavior:"smooth"}):e&&nt(e)?.scrollIntoView({block:"center",behavior:"smooth"}),f.querySelector(`.dt-pin[data-id="${t}"]`)?.animate([{transform:"scale(1)"},{transform:"scale(1.5)"},{transform:"scale(1)"}],400)},xe=t=>{const[e]=N.splice(t,1);if(!e)return;_(),u=e,b=null;const n=G(e);n&&(n.y<0||n.y>innerHeight)&&scrollTo({top:scrollY+n.y-innerHeight/3,behavior:"instant"}),p()},Nn=t=>{N.splice(t,1),p()},Te="nm-review",Me=()=>{try{return JSON.parse(sessionStorage.getItem(Te)||"null")}catch{return null}},kt=t=>{try{t?sessionStorage.setItem(Te,JSON.stringify(t)):sessionStorage.removeItem(Te)}catch{}},P=document.createElement("div");P.className="dt-review",P.setAttribute("role","region"),P.setAttribute("aria-label","Checking fixes"),P.hidden=!0,$||document.body.append(P);const ke=()=>Ut.filter(t=>j(t)==="claude"),Ko=()=>{const t=ke().sort((e,n)=>+(n.route===D)-+(e.route===D)||String(e.route).localeCompare(String(n.route))||e.id-n.id).map(e=>e.id);t.length&&(kt({ids:t,i:0}),He())},He=()=>{const t=Me();if(!t||$){P.hidden=!0;return}for(;t.i<t.ids.length&&j(Ut.find(n=>n.id===t.ids[t.i])??{status:"done"})!=="claude";)t.i++;if(t.i>=t.ids.length){kt(null),P.hidden=!0,st("Every fix is checked.");return}kt(t);const e=Ut.find(n=>n.id===t.ids[t.i]);if(e.route&&e.route!==D){location.assign(e.route+location.search);return}if(H||at(!0),lt(e)!==zt()){Pe(lt(e));for(const n of[600,1500])setTimeout(()=>I({open:e.id}),n)}else Le(e.id);P.innerHTML=`<b>Check fixes</b><span class="dt-review-n">${t.i+1} of ${t.ids.length}</span>
|
|
98
|
+
<span class="dt-review-text">${g(F(e.text).slice(0,90))}</span>
|
|
99
|
+
<button data-r="ok" class="dt-review-ok">${ve} Looks right</button><button data-r="no">Reopen</button>
|
|
100
|
+
<button data-r="skip">Skip</button><button data-r="stop" aria-label="Stop checking" title="Stop">${Yt}</button>`,P.hidden=!1};P.addEventListener("click",async t=>{const e=t.target.closest("[data-r]"),n=Me();if(!e||!n)return;if(e.dataset.r==="stop"){kt(null),P.hidden=!0;return}const o=n.ids[n.i];e.dataset.r==="ok"&&await Vt(o,!0),e.dataset.r==="no"&&await Vt(o,!1),kt({...n,i:n.i+1}),await J(),await At(),He()});const Wo=t=>{R.hidden=!t,Ft.setAttribute("aria-pressed",String(t)),K("dt-history",t?"1":"0"),p()},Ae=document.querySelector(".dt-resolved-btn"),In=t=>{tt=t,Ae.setAttribute("aria-pressed",String(t)),K("dt-resolved",t?"1":"0"),I({resolved:t}),p(),At()};Ae.addEventListener("click",()=>In(!tt)),Ae.setAttribute("aria-pressed",String(tt)),Ft.addEventListener("click",()=>{const t=R.hidden===!0;t&&!H&&at(!0),t&&Se(!1),Wo(t)});const ot=()=>{ge||!H||(ge=requestAnimationFrame(()=>{ge=0,jo()}))},qn=new MutationObserver(t=>{t.every(e=>e.target.closest?.(".dt-notes-overlay"))||ot()}),Rn=new ResizeObserver(()=>ot());let Ut=[];const Dn=t=>{Ut=t;const e=()=>({open:0,claude:0,done:0}),n={};for(const c of t){const r=j(c),l=n[c.route??""]??={...e(),bands:{}};l[r]++;const m=lt(c);(l.bands[m]??=e())[r]++}const o=["open","claude","done"],s={open:"open",claude:"resolved by an agent, to check",done:"resolved"},a=c=>o.map(r=>[r,r==="done"&&!tt?0:c[r]]),d=c=>a(c).reduce((r,[,l])=>r+l,0);for(const c of document.querySelectorAll(".dt-pages a")){const r=c.querySelector(".dt-pages-n");if(!r)continue;const l=n[new URL(c.href).pathname.replace(/\/+$/,"")||"/"];for(const i of B){const y=l?.bands[i.id];for(const[T,Y]of a(y??e())){const S=r.querySelector(`[data-bp="${i.id}"][data-state="${T}"]`);S.hidden=!Y,Y&&(S.querySelector("i").textContent=String(Y),S.title=`${i.label}: ${Y} ${s[T]}`)}}const m=l?d(l):0;r.hidden=!m;const v=l?B.filter(i=>l.bands[i.id]&&d(l.bands[i.id])).map(i=>`${i.label} ${d(l.bands[i.id])}`).join(" \xB7 "):"";r.title=m?`${l.open} open \xB7 ${l.claude} resolved by an agent, to check \xB7 ${l.done} resolved
|
|
101
|
+
${v}`:""}},Ht=t=>(Array.isArray(t)?t:[]).filter(e=>e&&Number.isInteger(Number(e.id))&&typeof e.text=="string").map(e=>({...e,id:Number(e.id),rx:Number(e.rx)||0,ry:Number(e.ry)||0,route:typeof e.route=="string"&&/^\/(?!\/)/.test(e.route)?e.route:"/",replies:Array.isArray(e.replies)?e.replies.filter(n=>typeof n?.text=="string"):[],images:Array.isArray(e.images)?e.images.filter(n=>typeof n=="string"):[]})),At=async()=>{try{Dn(Ht((await(await V("comments")).json()).comments)),!R.hidden&&!$&&p()}catch{}};let Jt="",Ce=!1;const Ct=async()=>{if(!(document.hidden||Ce)){Ce=!0;try{const t=await V(`comments${Jt?`?since=${Jt}`:""}`);if(t.status!==200)return;const e=await t.json();Jt=e.version??"";const n=Ht(e.comments);Dn(n);const o=n.filter(s=>s.route===D);if(JSON.stringify(o)===JSON.stringify(h))return;if(f.contains(document.activeElement)&&document.activeElement.matches("textarea, input")){Jt="",setTimeout(Ct,5e3);return}h=o,p(),I({reload:!0})}catch{}finally{Ce=!1}}},mt=async()=>{try{const t=await V(`comments?route=${encodeURIComponent(D)}`);h=Ht((await t.json()).comments)}catch{h=[]}p()};let Be=0;const On=t=>{Be||(Be=requestAnimationFrame(()=>{Be=0;const e=t.target;if(!H||e.closest(nn)){ct.hidden=!0;return}ct.hidden=!0;const n=document.elementFromPoint(t.clientX,t.clientY);if(ct.hidden=!1,!n)return;const o=n.getBoundingClientRect();wo.style.cssText=`left:${o.left}px;top:${o.top}px;width:${o.width}px;height:${o.height}px`,un.textContent=n.tagName.toLowerCase()+([...n.classList].find(s=>!/^(astro|svelte)-/.test(s))?"."+[...n.classList].find(s=>!/^(astro|svelte)-/.test(s)):"")+` ${Math.round(o.width)}\xD7${Math.round(o.height)}`,un.style.cssText=`left:${o.left}px;top:${Math.max(2,o.top-20)}px`}))},Fn=t=>{if(!(t.key!=="Escape"||t.isComposing)){if(t.preventDefault(),x){x=null,p();return}if(u){_(),p();return}if(b!==null){b=null,p();return}at(!1)}},Pn=t=>{if(t.target.closest(nn))return;if(t.preventDefault(),t.stopPropagation(),se){se=!1;return}if(!getSelection()?.isCollapsed)return;f.hidden=!0;const n=document.elementFromPoint(t.clientX,t.clientY);if(f.hidden=!1,!n)return;_();const o=n.getBoundingClientRect(),s=n.tagName.toLowerCase(),a=[...n.classList].filter(d=>!/^(astro|svelte|css)-/.test(d)).slice(0,2);u={selector:Mo(n),tag:s,classes:a,nth:fn({tag:s,classes:a}).indexOf(n),rx:o.width?(t.clientX-o.left)/o.width:.5,ry:o.height?(t.clientY-o.top)/o.height:.5,label:F(n.textContent||"").slice(0,60),ctx:Ho(n),category:Ue[0].id},b=null,ct.hidden=!0,p()},zo=2200,_o=900*1024,Go=8*1024*1024,st=t=>{const e=document.createElement("div");e.className="dt-toast",e.textContent=t,document.body.append(e),setTimeout(()=>e.remove(),2800)},Yo=t=>new Promise(e=>{const n=new FileReader;n.onload=()=>e(String(n.result)),n.readAsDataURL(t)}),Vo=async t=>{const e=await createImageBitmap(t),n=Math.min(1,zo/Math.max(e.width,e.height));if(n===1&&t.size<=_o)return e.close(),Yo(t);const o=document.createElement("canvas");return o.width=Math.round(e.width*n),o.height=Math.round(e.height*n),o.getContext("2d").drawImage(e,0,0,o.width,o.height),e.close(),o.toDataURL("image/jpeg",.85)},Ne=async(t,e)=>{const n=[];for(const o of t){let s;try{s=await Vo(o)}catch{st("That image could not be read.");continue}if(s.length>Go){st("Screenshot is too large even after shrinking.");continue}n.push(s)}if(n.length){if(!Number(e?.dataset.id)){u&&((u.images??=[]).push(...n),p());return}Q.push(...n),p(),Kn(".dt-note-reply-input")}},jn=t=>[...t??[]].filter(e=>e.kind==="file"&&e.type.startsWith("image/")).map(e=>e.getAsFile()).filter(Boolean);f.addEventListener("paste",t=>{const e=jn(t.clipboardData?.items);e.length&&(t.preventDefault(),Ne(e,t.target.closest(".dt-note")))}),f.addEventListener("dragover",t=>{t.target.closest(".dt-note")&&(t.preventDefault(),t.target.closest(".dt-note").querySelector(".dt-compose")?.setAttribute("data-drop",""))}),f.addEventListener("dragleave",t=>{t.target.closest(".dt-note")?.querySelector(".dt-compose")?.removeAttribute("data-drop")}),f.addEventListener("drop",t=>{const e=t.target.closest(".dt-note");if(!e)return;t.preventDefault(),e.querySelector(".dt-compose")?.removeAttribute("data-drop");const n=jn(t.dataTransfer?.items);n.length&&Ne(n,e)});const Kn=t=>{const e=f.querySelector(t);e?.focus(),e?.setSelectionRange(e.value.length,e.value.length)},Wn=()=>{Kn(".dt-note-edit-input"),f.querySelector(".dt-msg .dt-compose")?.scrollIntoView({block:"nearest"})},Ie=t=>{t.style.overflowY="hidden",t.style.height="auto",t.style.height=`${t.scrollHeight}px`,t.style.overflowY=t.scrollHeight>t.clientHeight?"auto":"hidden"},Uo=t=>/(?:^|\s)@([^\s@]*)$/.exec(t.value.slice(0,t.selectionStart??t.value.length)),Jo=t=>{t.closest(".dt-compose").querySelector(".dt-mentions")?.remove();const n=Uo(t);if(!n||!M.team?.length)return;const o=n[1].toLowerCase(),s=M.team.filter(a=>[a.name,a.nickname,a.email].some(d=>d?.toLowerCase().startsWith(o))).slice(0,5);s.length&&t.insertAdjacentHTML("afterend",`<div class="dt-mentions" role="listbox" aria-label="Mention someone">${s.map((a,d)=>`<button type="button" role="option" aria-selected="${d===0}" data-act="mention" data-handle="${g(is(a))}">${g(a.name||a.email)}${a.name?` <span>${g(a.email)}</span>`:""}</button>`).join("")}</div>`)},zn=(t,e)=>{const n=t.selectionStart??t.value.length,o=t.value.slice(0,n).lastIndexOf("@");t.value=`${t.value.slice(0,o)}@${e} ${t.value.slice(n)}`,t.selectionStart=t.selectionEnd=o+e.length+2,t.closest(".dt-compose")?.querySelector(".dt-mentions")?.remove(),t.dispatchEvent(new Event("input",{bubbles:!0})),t.focus()};f.addEventListener("change",t=>{const e=t.target.closest(".dt-for-select");if(!(!e||!u)){u.assignee=e.value;try{localStorage.setItem("nm-for",e.value)}catch{}Wt()}}),f.addEventListener("input",t=>{const e=t.target.closest(".dt-suggest-input");if(e&&u?.suggest){u.suggest.to=e.value,Wt(),Ie(e);return}const n=t.target.closest(".dt-note-input, .dt-note-reply-input, .dt-note-edit-input");n&&(Jo(n),n.classList.contains("dt-note-input")?u&&(u.text=n.value):n.classList.contains("dt-note-edit-input")?x&&(x.text=n.value):O=n.value,Wt(),n.closest(".dt-compose")?.querySelector(".dt-send")?.classList.toggle("is-ready",n.value.trim()!==""),Ie(n))}),f.addEventListener("keydown",t=>{const e=t.target.closest(".dt-note-input, .dt-note-reply-input, .dt-note-edit-input");if(!e)return;const n=e.closest(".dt-compose")?.querySelector(".dt-mentions button");if(n&&(t.key==="Enter"||t.key==="Tab")&&!t.isComposing){t.preventDefault(),zn(e,n.dataset.handle);return}if(n&&t.key==="Escape"){t.stopPropagation(),n.parentElement.remove();return}t.key!=="Enter"||t.shiftKey||t.isComposing||(t.preventDefault(),e.closest(".dt-compose")?.querySelector(".dt-send")?.click())}),f.addEventListener("click",async t=>{const e=t.target.closest("button");if(!e)return;const n=e.dataset.act,o=Number(e.dataset.id);if(n==="mention"){const s=e.closest(".dt-compose")?.querySelector("textarea");s&&zn(s,e.dataset.handle);return}if(!n){if(b=b===o?null:o,b!=null&&e.dataset.off){const s=h.find(d=>d.id===o);(s&&nt(s))?.scrollIntoView({block:"nearest",inline:"center",behavior:"smooth"})}_(),p();return}if(n==="record"){Do(e.closest(".dt-note"));return}if(n==="attach"){const s=Object.assign(document.createElement("input"),{type:"file",accept:"image/*",multiple:!0}),a=e.closest(".dt-note");s.addEventListener("change",()=>{s.files?.length&&Ne([...s.files],a)}),s.click();return}if(n==="unshot"){o?x&&x.drop.push(e.dataset.img):(e.closest("[data-draft]")?u?.images??[]:Q).splice(Number(e.dataset.i),1),p(),x&&Wn();return}if(n==="edit"){const s=h.find(c=>c.id===o),a=e.dataset.at||null,d=a?s?.replies?.find(c=>c.at===a)?.text:s?.text;if(d===void 0)return;x={id:o,at:a,text:d,drop:[]},p(),Wn();return}if(n==="edit-cancel"){x=null,p();return}if(n==="edit-save"){const s=x;if(!s)return;const a=s.text.trim();if(!a){f.querySelector(".dt-note-edit-input")?.focus();return}x=null;const d=await V("comments",{method:"PATCH",headers:{"content-type":"application/json"},body:JSON.stringify({id:s.id,edit:{at:s.at,text:a},...s.drop.length?{removeImage:s.drop}:{}})});d.ok||(x=s,st(`Edit was not saved (${d.status}).`)),await J();return}if(n==="cancel"){_(),p();return}if(n==="discard"){u=null,p();return}if(n==="draft-open"){xe(Number(e.dataset.i));return}if(n==="close"){b=null,p();return}if(n==="cat"){const s=e.dataset.cat;if(!o){u&&(u.category=s),p();return}await V("comments",{method:"PATCH",headers:{"content-type":"application/json"},body:JSON.stringify({id:o,category:s})}),await J();return}if(n==="suggest"&&u){const s=En(nt(u));u.suggest={from:s,to:s},p();const a=f.querySelector(".dt-suggest-input");a?.focus(),a?.select();return}if(n==="unsuggest"&&u){u.suggest=null,p();return}if(n==="save"){if(!u)return;const s=u.suggest&&u.suggest.to.trim()!==u.suggest.from?{from:u.suggest.from,to:u.suggest.to.trim()}:null,a=f.querySelector(".dt-note-input").value.trim()||(s?"Change the text":"");if(!a){f.querySelector(".dt-note-input")?.focus();return}const d=u,c={...d,route:D,text:a,suggest:s,assignee:d.assignee??$n(),breakpoint:et(),browser:To(),device:$?_n:"",viewport:{w:innerWidth,h:innerHeight}},r={...d,id:-Date.now(),text:a,route:D,status:"open",note:"",doneBy:null,breakpoint:c.breakpoint,replies:[],images:[],createdAt:new Date().toISOString(),...s?{suggest:s}:{},by:M.me?.email,byName:M.me?.name};h=[...h,r],u=null,p();const l=await V("comments",{method:"POST",headers:{"content-type":"application/json"},body:JSON.stringify(c)});if(!l.ok){h=h.filter(v=>v!==r),u=d,p(),st(`Comment was not saved (${l.status}).`);return}const m=Ht([await l.json().catch(()=>null)])[0];h=h.map(v=>v===r&&m?m:v),p(),J();return}if(n==="reply"){const s=f.querySelector(".dt-note-reply-input"),a=s.value.trim();if(!a){s.focus();return}const d=Q;O="",Q=[];const c=h;h=h.map(m=>m.id===o?{...m,replies:[...m.replies??[],{author:"you",text:a,at:new Date().toISOString(),by:M.me?.email}]}:m),p();const r=await V("comments",{method:"PATCH",headers:{"content-type":"application/json"},body:JSON.stringify({id:o,reply:a,images:d})});if(!r.ok){h=c,O=a,Q=d,p(),st(`Reply was not sent (${r.status}).`);return}const l=Ht([await r.json().catch(()=>null)])[0];l&&(h=h.map(m=>m.id===l.id?l:m),p()),J();return}n==="rm"?await V(`comments?id=${o}`,{method:"DELETE"}):await Vt(o,n==="done"),b=null,await J()});let Bt="overlay",gt="",_n="";const I=t=>{C.hidden||L.contentWindow?.postMessage({dt:!0,...t},location.origin)},Xo=()=>({notes:H,grid:!Dt.hidden,inspect:dt,resolved:tt,scrollbar:Bt,device:gt});addEventListener("message",t=>{if(t.origin!==location.origin||!t.data?.dt)return;const e=t.data;if(!$&&t.source===L.contentWindow){if(e.key){no(e.key[0],e.key[1])?.run();return}if(e.closeMenus){Et();return}if(e.drafts){we=e.drafts,Bn(zt());return}}if($&&typeof e.openDraft=="number"){xe(e.openDraft);return}if($&&typeof e.dropDraft=="number"){Nn(e.dropDraft);return}if($&&typeof e.device=="string"&&(_n=e.device),$&&e.scrollbar&&document.documentElement.classList.toggle("dt-sb-classic",e.scrollbar==="classic"),e.hello&&t.source===L.contentWindow){I(Xo());return}typeof e.notes=="boolean"&&e.notes!==H&&at(e.notes,!1),typeof e.open=="number"&&Le(e.open),typeof e.grid=="boolean"&&e.grid===Dt.hidden&&oe(e.grid),typeof e.inspect=="string"&&e.inspect!==dt&&Ot(e.inspect),typeof e.resolved=="boolean"&&e.resolved!==tt&&In(e.resolved),e.reload&&(mt(),At())});const J=async()=>{await mt(),At(),I({reload:!0}),$&&parent.postMessage({dt:!0,reload:!0},location.origin)},at=(t,e=!0)=>{H=t,dn.setAttribute("aria-pressed",String(t)),t?!$&&R.hidden&&localStorage.getItem("dt-history")!=="0"&&(R.hidden=!1,Ft.setAttribute("aria-pressed","true")):(R.hidden=!0,Ft.setAttribute("aria-pressed","false")),K(pn,t?"1":"0"),I({notes:t}),$&&e&&parent.postMessage({dt:!0,notes:t},location.origin),f.hidden=!t||!C.hidden,document.documentElement.classList.toggle("dt-noting",t),t?(Ot(""),document.addEventListener("click",Pn,!0),document.addEventListener("keydown",Fn),document.addEventListener("mousemove",On),addEventListener("scroll",ot,!0),addEventListener("resize",ot),qn.observe(document.body,{childList:!0,subtree:!0,characterData:!0}),Rn.observe(document.body),mt()):(_(),b=null,document.removeEventListener("click",Pn,!0),document.removeEventListener("keydown",Fn),document.removeEventListener("mousemove",On),ct.hidden=!0,removeEventListener("scroll",ot,!0),removeEventListener("resize",ot),qn.disconnect(),Rn.disconnect(),f.innerHTML="")},Xt="dt-w",qe="dt-canvas",ft="dt-device";let rt=localStorage.getItem(qe)==="1",E=localStorage.getItem(ft)||"";E&&!Rt(E)&&(E="",localStorage.setItem(ft,""));let A=Number(localStorage.getItem(Xt))||0;const Gn="dt-emu";let q=(()=>{try{return JSON.parse(localStorage.getItem(Gn)||"null")}catch{return null}})();const Zt=()=>q?io.find(t=>t.id===q.id)??null:null,Zo=()=>{const t=Zt();return t?q.turned?{w:t.h,h:t.w}:{w:t.w,h:t.h}:null};let Nt=localStorage.getItem("dt-bars-min")==="1";const ht=t=>{q=t,K(Gn,t?JSON.stringify(t):"")},Re=t=>{mn.textContent=t,C.style.setProperty("--dt-badge-w",`${mn.offsetWidth}px`)},Yn=t=>{if(!t){St.innerHTML="";return}let e="";for(let n=0;n<=t;n+=50)e+=`<span class="dt-tick${n%200===0?" is-major":""}" style="left:${n}px"></span>`;for(const n of B)for(const o of[n.min,n.max])o>0&&Number.isFinite(o)&&o<=t&&(e+=`<span class="dt-edge" style="left:${o}px" title="${n.label} edge"></span>`);St.innerHTML=e,St.style.width=`${t}px`},De=()=>{const t=parseFloat(w.style.width)||0,e=parseFloat(w.style.height)||0;if(!t||!e){w.style.transform="",delete w.dataset.scaled;return}const n=E||q?Math.min(1,(innerWidth-80)/t,(innerHeight-120)/e):Math.min(1,(innerWidth-80)/t);w.style.transform=n<1?`scale(${n})`:"",w.dataset.scaled=n<1?String(Math.round(n*100)):""},Qo=t=>io.find(e=>e.w===t.w&&e.h===t.h&&e.cutout?.shape==="pill")?.cutout,Qt=()=>{try{return L.contentDocument}catch{return null}},Vn=()=>Qt()?.title.split("\u2014").pop()?.trim()||"",Oe=()=>{const t=Qt(),e=E?Rt(E):null;if(!t?.body||!e)return;const n=ps(t),o=e.browser==="chrome-android"?n.theme||"rgb(255, 255, 255)":n.top,s=e.browser==="chrome-android"?"rgb(255, 255, 255)":n.bottom;w.style.setProperty("--dt-top",o),w.style.setProperty("--dt-top-ink",lo(o)),w.style.setProperty("--dt-bottom",s),w.style.setProperty("--dt-bottom-ink",lo(s));const a=wt.querySelector(".dt-win-tab > span");a&&(a.textContent=Vn()||location.host)};let Fe=0;L.addEventListener("load",()=>{Qt()&&(Oe(),L.contentWindow?.addEventListener("scroll",()=>{Fe||(Fe=requestAnimationFrame(()=>{Fe=0,Oe()}))},{passive:!0}))});for(const t of[wt,Pt])t.addEventListener("click",e=>{const n=e.target.closest("[data-nav]")?.dataset.nav;if(n)try{const o=L.contentWindow?.navigation;if(!Qt()||!o)throw new Error("foreign");n==="back"?o.canGoBack&&o.back():n==="fwd"?o.canGoForward&&o.forward():o.reload()}catch{(n==="reload"||n==="back")&&(L.src=location.href)}});Lt.addEventListener("click",()=>{Nt=!Nt,K("dt-bars-min",Nt?"1":"0"),X()});const X=()=>{if($)return;const t=E?Rt(E)??null:null;if(E&&!t&&(E="",localStorage.setItem(ft,"")),!t&&!rt){C.hidden=!0,L.removeAttribute("src"),document.documentElement.classList.remove("dt-framing"),f.hidden=!H,St.innerHTML="",Tt(),me.hidden=!0,Lt.hidden=!0,U=null,gt="",we=[],Tt(),Ke(),H?mt():p();return}if(C.hidden=!1,document.documentElement.classList.add("dt-framing"),f.hidden=!0,L.src||(L.src=location.href),t){const e=ms(t,{host:location.host,title:Vn(),now:new Date,min:Nt,cutout:Qo(t)}),{screen:n}=e;C.dataset.mode="device",w.dataset.shell=t.shell,w.dataset.browser=t.browser,w.style.width=`${e.footprint.w}px`,w.style.height=`${e.footprint.h}px`,w.style.setProperty("--dt-r",`${n.r}px`),w.style.setProperty("--dt-rb",`${n.rb}px`),cn.innerHTML=e.shell;const o=(d,c,r,l)=>{d.innerHTML=l,d.style.cssText=`left:${n.x}px;top:${c}px;width:${n.w}px;height:${r}px`};o(wt,n.y,e.topH,e.top),o(Pt,n.y+n.h-e.bottomH,e.bottomH,e.bottom);const s=n.h-e.topH-e.bottomH;L.style.position="absolute",L.style.left=`${n.x}px`,L.style.top=`${n.y+e.topH}px`,L.style.width=`${n.w}px`,L.style.height=`${s}px`,St.innerHTML="";const a=Nt&&e.canMinimize;Bt=e.scrollbar,gt=`${t.label}${a?" \xB7 bars folded":""}`,U=$t(t.w),I({notes:H,scrollbar:Bt,device:gt}),Lt.hidden=!e.canMinimize,Lt.setAttribute("aria-pressed",String(a)),Re(`${t.label} \xB7 page ${t.w}\xD7${s} of ${t.w}\xD7${t.h}${a?" \xB7 bars folded":""} \xB7 ${B.find(d=>d.id===U)?.label??""}`),Oe()}else{const e=Zo();e||ht(null);const n=e?.w||A||B.find(a=>a.id===et()).ideal;A=n,C.dataset.mode="canvas",delete w.dataset.shell,delete w.dataset.browser,cn.innerHTML=wt.innerHTML=Pt.innerHTML="",wt.style.cssText=Pt.style.cssText="",Lt.hidden=!0,Bt="overlay",w.style.width=`${n}px`,w.style.height=`${e?.h??innerHeight-84}px`,L.style.position="",L.style.left=L.style.top="",L.style.width="100%",L.style.height="100%",Yn(n),I({notes:H});const o=B.find(a=>a.id===$t(n)),s=Zt();gt=s?`${s.label}${q?.turned?" \xB7 landscape":""}`:"",I({scrollbar:Bt,device:gt}),Re(s&&e?`${s.label} \xB7 ${e.w}\xD7${e.h} \xB7 ${o.label}`:`${n}px \xB7 ${o.label}`),U=$t(n)}me.hidden=!(Zt()?.rotates&&!t),Ke(),De(),Tt(),H?mt():p()},Pe=t=>{const e=B.find(n=>n.id===t);E="",localStorage.setItem(ft,""),ht(null),rt=t!==ee,A=rt?e.ideal:0,U=rt?t:null,localStorage.setItem(qe,rt?"1":"0"),localStorage.setItem(Xt,String(A)),b=null,_(),X()};for(const t of ce)t.addEventListener("click",()=>Pe(t.dataset.bp));for(const t of document.querySelectorAll("[data-device]"))t.addEventListener("click",()=>{E=t.dataset.device===E?"":t.dataset.device,localStorage.setItem(ft,E),z.open=!1,X()});for(const t of document.querySelectorAll("[data-emu]"))t.addEventListener("click",()=>{const e=q?.id===t.dataset.emu&&!E;E="",localStorage.setItem(ft,""),ht(e?null:{id:t.dataset.emu,turned:!1}),rt=!e,A=0,localStorage.setItem(qe,rt?"1":"0"),U=null,b=null,_(),z.open=!1,X()});me.addEventListener("click",()=>{q&&(ht({...q,turned:!q.turned}),b=null,_(),X())});const Un=[...z.querySelectorAll("[data-tab]")],ts=[...z.querySelectorAll("[data-panel]")],Jn=t=>{for(const e of Un)e.setAttribute("aria-selected",String(e.dataset.tab===t));for(const e of ts)e.hidden=e.dataset.panel!==t;K("dt-devices-tab",t)};for(const t of Un)t.addEventListener("click",()=>Jn(t.dataset.tab));Jn(localStorage.getItem("dt-devices-tab")==="devtools"?"devtools":"preview");const je=z.querySelector(".dt-emu-search");je.addEventListener("input",()=>{const t=je.value.trim().toLowerCase();let e=null,n=!1;const o=()=>{e&&(e.hidden=!n)};for(const s of je.parentElement.children){if(s.classList.contains("dt-devices-group")){o(),e=s,n=!1;continue}s.dataset.emu&&(s.hidden=!!t&&!s.textContent.toLowerCase().includes(t),n||=!s.hidden)}o()});const es=z.querySelector(".dt-devices-name");function Ke(){for(const e of z.querySelectorAll("[data-device]"))e.setAttribute("aria-pressed",String(e.dataset.device===E));const t=!E&&!C.hidden?q?.id:void 0;for(const e of z.querySelectorAll("[data-emu]"))e.setAttribute("aria-pressed",String(e.dataset.emu===t));es.textContent=E&&Rt(E)?.label||t&&Zt()?.label||"Device"}const We=t=>B.find(e=>e.id===t),ns=t=>{const e=We(U??et());return Math.max(e.min||320,Math.min(Number.isFinite(e.max)?e.max:2560,Math.round(t)))};for(const t of So){const e=t.dataset.edge==="l"?-1:1;t.addEventListener("pointerdown",n=>{if(E)return;n.preventDefault(),q&&(ht(null),X()),t.setPointerCapture(n.pointerId);const o=n.clientX,s=A,a=Number(w.dataset.scaled||100)/100;C.dataset.dragging="1";const d=r=>{A=ns(s+e*(r.clientX-o)*2/a),w.style.width=`${A}px`,Yn(A),Re(`${A}px \xB7 ${We($t(A)).label}`),De()},c=()=>{t.removeEventListener("pointermove",d),t.removeEventListener("pointerup",c),delete C.dataset.dragging,localStorage.setItem(Xt,String(A)),X()};t.addEventListener("pointermove",d),t.addEventListener("pointerup",c)}),t.addEventListener("dblclick",()=>{if(E)return;ht(null);const n=We(U??et()),o=[n.min||320,Number.isFinite(n.max)?n.max:n.ideal];A=Math.abs(A-o[0])<Math.abs(A-o[1])?o[0]:o[1],localStorage.setItem(Xt,String(A)),X()})}let Xn=et();addEventListener("resize",()=>{Tt(),et()!==Xn&&(Xn=et(),p()),C.hidden||(!E&&!q&&(w.style.height=`${innerHeight-84}px`),De())});const Zn="dt-studio",Qn=t=>{ue.setAttribute("aria-pressed",String(t)),document.documentElement.classList.toggle("dt-no-studio",!t),K(Zn,t?"1":"0")};ue.addEventListener("click",()=>Qn(ue.getAttribute("aria-pressed")!=="true")),Qn(localStorage.getItem(Zn)!=="0"),dn.addEventListener("click",()=>at(!H));const bt=document.querySelector(".devtools"),It=document.querySelector(".dt-tab"),to=t=>{bt.toggleAttribute("data-collapsed",t),It.toggleAttribute("data-collapsed",t),It.setAttribute("aria-expanded",String(!t)),It.setAttribute("aria-label",t?"Show the bar":"Hide the bar");for(const e of bt.querySelectorAll(".dt-group"))e.inert=t;t&&Et(),K("dt-collapsed",t?"1":"0")};It.addEventListener("click",()=>to(!bt.hasAttribute("data-collapsed")));const ze=document.querySelector(".dt-keys"),it=t=>()=>bt.querySelector(t)?.click(),eo=t=>()=>{const e=[...document.querySelectorAll(".dt-pages a")];e[e.findIndex(n=>n.hasAttribute("aria-current"))+t]?.click()},te=[{group:"Comments",code:"KeyC",hint:"C",label:"Comment mode",el:".dt-notes-btn",run:it(".dt-notes-btn")},{group:"Comments",code:"KeyC",shift:!0,hint:"\u21E7C",label:"Comments panel",el:".dt-history-btn",run:it(".dt-history-btn")},{group:"Comments",code:"KeyR",hint:"R",label:"Show resolved",el:".dt-resolved-btn",run:it(".dt-resolved-btn")},{group:"Inspect",code:"KeyG",hint:"G",label:"Grid",el:".dt-grid-btn",run:it(".dt-grid-btn")},{group:"Inspect",code:"KeyP",hint:"P",label:"Spacing",el:".dt-pad-btn",run:it(".dt-pad-btn")},{group:"Inspect",code:"KeyS",hint:"S",label:"Size",el:".dt-size-btn",run:it(".dt-size-btn")},{group:"Inspect",code:"KeyT",hint:"T",label:"Typography",el:".dt-type-btn",run:it(".dt-type-btn")},...M.sanity?[{group:"Inspect",code:"KeyE",hint:"E",label:"Sanity overlay",el:".dt-studio-btn",run:it(".dt-studio-btn")}]:[],...ce.slice(0,9).map((t,e)=>({group:"Breakpoints",code:`Digit${e+1}`,hint:String(e+1),label:t.dataset.tip??t.title,el:`.dt-bp[data-bp="${t.dataset.bp}"]`,run:()=>t.click()})),{group:"View",code:"KeyD",hint:"D",label:"Devices",run:()=>{z.open=!z.open}},{group:"View",code:"BracketLeft",hint:"[",label:"Previous page",run:eo(-1)},{group:"View",code:"BracketRight",hint:"]",label:"Next page",run:eo(1)},{group:"View",code:"Backslash",hint:"\\",label:"Hide the bar",run:()=>It.click()},{group:"View",code:"Slash",shift:!0,hint:"?",label:"This list",el:".dt-keys summary",run:()=>{ze.open=!ze.open}}],no=(t,e)=>te.find(n=>n.code===t&&!n.shift==!e),os=t=>t instanceof HTMLElement&&(t.isContentEditable||/^(INPUT|TEXTAREA|SELECT)$/.test(t.tagName));if(M.shortcuts){for(const e of te){const n=e.el&&bt.querySelector(e.el);n&&(n.dataset.tip=`${n.dataset.tip??e.label} \xB7 ${e.hint}`,n.setAttribute("aria-keyshortcuts",e.hint.startsWith("\u21E7")?`Shift+${e.hint.slice(1)}`:e.hint))}const t=(e,n)=>`<div class="dt-key-row"><span>${g(e)}</span><kbd>${g(n)}</kbd></div>`;if(ze.querySelector(".dt-keys-menu").innerHTML='<p class="dt-menu-note">One key, no modifier, in any keyboard layout. Not while you type.</p>'+[...new Set(te.map(e=>e.group))].map(e=>`<p class="dt-devices-group">${e}</p>`+te.filter(n=>n.group===e).map(n=>t(n.label,n.hint)).join("")).join("")+'<p class="dt-devices-group">In a comment</p>'+t("Send","Enter")+t("New line","\u21E7Enter")+t("Close, cancel, back out","Esc"),document.addEventListener("keydown",e=>{if(e.repeat||e.isComposing||e.metaKey||e.ctrlKey||e.altKey||e.defaultPrevented||os(e.target))return;const n=no(e.code,e.shiftKey);n&&(e.preventDefault(),$?parent.postMessage({dt:!0,key:[e.code,e.shiftKey]},location.origin):n.run())}),$){const e=()=>parent.postMessage({dt:!0,closeMenus:!0},location.origin);document.addEventListener("pointerdown",e,!0),document.addEventListener("keydown",n=>{n.key==="Escape"&&e()})}}if(!$){to(localStorage.getItem("dt-collapsed")==="1"),requestAnimationFrame(()=>requestAnimationFrame(()=>bt.setAttribute("data-ready",""))),rt||E?X():Ke(),oe(localStorage.getItem(Xe)==="1");const t=localStorage.getItem(en);t&&t in ae&&Ot(t),at(localStorage.getItem(pn)==="1")}const oo=()=>{try{const t=JSON.parse(localStorage.getItem(pt)||"null");N=(t?.parked??[]).filter(e=>jt(e)),t?.draft&&document.querySelector(t.draft.selector)?(u=t.draft,!H&&!$&&at(!0)):jt(t?.draft)&&N.push(t.draft),t?.reply?.text&&(O=t.reply.text,xt=b=t.reply.for??null),(u||N.length||O)&&p()}catch{localStorage.removeItem(pt)}};oo();const so=()=>setTimeout(()=>{const t=ne(location.pathname);t!==D&&(clearTimeout(Kt),fe(),D=t,pt=gn(),u=null,N=[],O="",xt=null,b=null,x=null,h=[],Qe(),oo(),mt())});for(const t of["pushState","replaceState"]){const e=window.history[t];window.history[t]=function(...n){e.apply(this,n),so()}}addEventListener("popstate",so),H||mt(),At().then(()=>{Me()&&He()}),document.addEventListener("visibilitychange",()=>{document.hidden||Ct()}),addEventListener("focus",Ct),addEventListener("notemend:changed",()=>{$||Ct()});let ss=0;$||setInterval(()=>{(!cs.live||++ss%6===0)&&Ct()},2e4),$&&parent.postMessage({dt:!0,hello:!0},location.origin)}export{Es as run};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{readFileSync as
|
|
1
|
+
import{readFileSync as _,existsSync as b,statSync as U,readdirSync as W}from"node:fs";import{join as $,isAbsolute as z}from"node:path";import{isIP as R}from"node:net";import{pathToFileURL as K}from"node:url";import{openStore as V,retry as Z}from"../store/cloud.mjs";import{mentionsIn as Q}from"../store/thread.mjs";import{CATEGORIES as X}from"../store/categories.mjs";import{BREAKPOINTS as Y,DEVICES as q,ICONS as D,SHELLS as H,BROWSERS as M}from"../presets.mjs";const G={png:"image/png",jpg:"image/jpeg",jpeg:"image/jpeg",webp:"image/webp",gif:"image/gif",svg:"image/svg+xml",webm:"video/webm"},J=e=>e.split(".").slice(0,2).map(Number).reduce((r,u)=>r*100+(Number.isNaN(u)?9999:u),0),tt=(e,r)=>{try{const m=_(z(r)?r:$(e,r),"utf8").match(/title="([^"]+)"|\btitle:\s*["'`]([^"'`]+)["'`]/);return(m?.[1]??m?.[2])?.split("\u2014").pop()?.trim()||null}catch{return null}};function yt(e){const r=["app","src/app"].map(c=>$(e,c)).find(b),u=[],m=(c,g)=>{for(const l of W(c,{withFileTypes:!0})){const i=l.name;if(l.isDirectory()){if(/^[_@]|^\(\./.test(i))continue;m($(c,i),/^\(.+\)$/.test(i)?g:[...g,i])}else/^page\.(jsx?|tsx?|mdx?)$/.test(i)&&u.push({origin:"project",type:"page",pattern:"/"+g.join("/"),entrypoint:$(c,i)})}};return r&&m(r,[]),u}const et=e=>e[0].toUpperCase()+e.slice(1).replace(/[-_]+/g," ");function rt({root:e,options:r,routes:u}){const m=r.pages??{},c=(t,d,O)=>({route:t,name:d,label:d.replace(/^[\d.]+[A-Z]?\.\s*/,""),group:O}),g=u.filter(t=>t.origin==="project"&&t.type==="page"&&!t.pattern.includes("[")).map(t=>({route:t.pattern.replace(/\/+$/,"")||"/",entrypoint:t.entrypoint})),l=new Set(g.map(t=>t.route)),i=[...g,...Object.keys(m).filter(t=>!l.has(t)).map(t=>({route:t}))],j={};for(const{route:t}of i){const d=t.split("/")[1];d&&(j[d]=(j[d]||0)+1)}const I=t=>{const d=t.split("/")[1];return d&&j[d]>1?et(d):"Pages"},B=r.groups?()=>r.groups[r.groups.length-1]:I,C=i.map(({route:t,entrypoint:d})=>{const[O,k]=m[t]??[];return c(t,O??(d&&tt(e,d))??t,k??B(t))}),n=r.groups??[...new Set([...Object.values(m).map(([,t])=>t).filter(Boolean),"Pages",...C.map(t=>t.group).sort()])],f=C.sort((t,d)=>n.indexOf(t.group)-n.indexOf(d.group)||J(t.name)-J(d.name)||t.route.localeCompare(d.route)),s=(r.breakpoints??Y).map(t=>({id:t.id,label:t.label,min:t.min,ideal:t.ideal,max:Number.isFinite(t.max)?t.max:null,icon:t.icon??D[t.id]??D.desktop})),o=(r.devices??q).filter(t=>t.w>0&&t.h>0&&H.includes(t.shell)&&M.includes(t.browser)?!0:(console.warn(`[notemend] device "${t.id}" skipped: it needs w and h, shell (${H.join(", ")}) and browser (${M.join(", ")})${t.frame?"; `frame` pictures were replaced by shell + browser in 0.3":""}`),!1));return{pages:f,groups:n.filter(t=>f.some(d=>d.group===t)),breakpoints:s,devices:o,categories:X,sanity:!!r.sanity,shortcuts:r.shortcuts!==!1,ignore:r.ignore??[],grid:{container:"container",grid:"grid",columns:12,...r.grid},zIndex:r.zIndex??2000000020}}const nt=e=>{const r=$(e,"notemend.config.mjs");let u=0,m={};return async()=>{if(!b(r))return{};const c=U(r).mtimeMs;if(c===u)return m;u=c;try{const{default:g,...l}=await import(/* webpackIgnore: true */ /* turbopackIgnore: true */ `${K(r).href}?t=${c}`);m={...l,...g}}catch(g){console.warn(`[notemend] notemend.config.mjs: ${g.message}`)}return m}},st=e=>{const r=String(e.headers.host||"").toLowerCase(),u=r.startsWith("[")?r.slice(1,r.indexOf("]")):r.replace(/:\d+$/,"");return u.includes(":")?R(u)===6:!u||!u.includes(".")||R(u)===4||/\.(localhost|local|test|internal|lan|home\.arpa)$/.test(u)},h=(e,r)=>String(e??"").replace(/[\u0000-\u001f\u007f]+/g," ").trim().slice(0,r),ot=e=>({route:h(e.route,500),text:String(e.text??"").slice(0,1e4),selector:h(e.selector,2e3),rx:Number.isFinite(e.rx)?e.rx:0,ry:Number.isFinite(e.ry)?e.ry:0,label:h(e.label,200),ctx:h(e.ctx,120),breakpoint:h(e.breakpoint,40),browser:h(e.browser,80),device:h(e.device,80),tag:h(e.tag,40),classes:Array.isArray(e.classes)?e.classes.slice(0,20).map(r=>h(r,80)):[],nth:Number.isInteger(e.nth)?e.nth:null,category:h(e.category,40),viewport:e.viewport&&Number.isFinite(e.viewport.w)&&Number.isFinite(e.viewport.h)?{w:e.viewport.w,h:e.viewport.h}:null,...e.assignee==="claude"||typeof e.assignee=="string"&&/^[^\s@]+@[^\s@]+$/.test(e.assignee)&&e.assignee.length<=200?{assignee:e.assignee.toLowerCase()}:{},...e.suggest&&typeof e.suggest.from=="string"&&typeof e.suggest.to=="string"&&e.suggest.to.trim()?{suggest:{from:e.suggest.from.slice(0,2e3),to:e.suggest.to.slice(0,2e3)}}:{}}),at=e=>{const r={};return(e.status==="open"||e.status==="done")&&(r.status=e.status),"doneBy"in e&&(r.doneBy=e.doneBy==="you"?"you":null),typeof e.category=="string"&&(r.category=h(e.category,40)),r},it=e=>{const r=e.headers.origin;if(!r)return!1;try{return new URL(r).host!==e.headers.host}catch{return!0}};function ct({root:e,options:r,routes:u,open:m=()=>V(e),crossOrigin:c=!1}){const g=nt(e),l=(n,f=200)=>({status:f,type:"application/json",body:JSON.stringify(n)}),i=(n,f)=>({status:n,type:"text/plain",body:f}),j=async n=>{const f=await n.body();if(f.length>45e5)throw Object.assign(new Error("too large"),{status:413});try{return f.length?JSON.parse(f.toString("utf8")):{}}catch{throw Object.assign(new Error("not JSON"),{status:400})}},I=async(n,f)=>{const s=async o=>{const t=await f(o);if(t.status>=400)throw Object.assign(new Error("not written"),{out:t});return t};try{if(n.cloud)return await Z(n,s);const o=n.load(),t=await s(o);return n.save(o),t}catch(o){if(o.out)return o.out;throw o}},B=async(n,f)=>{if(n.method!=="GET"&&!c&&it(n))return i(403,"Cross-origin write refused");const s=await m();if(n.method==="GET"){const a=f.searchParams.get("route"),p=s.version?String(await s.version()):null;if(p&&f.searchParams.get("since")===p)return{status:204,type:"text/plain",body:""};const x=await s.load();return l({version:p,comments:a?x.comments.filter(S=>S.route===a):x.comments})}let o=null,t=null;const d=s.cloud&&n.method!=="DELETE"?s.people().then(a=>{o=a,t=a.me},a=>{throw a}).catch(a=>a):Promise.resolve(),O=async()=>{const a=await d;if(a instanceof Error)throw a},k=a=>{if(t&&a){a.by=t.email,a.byName=t.name;const p=Q(a.text,o.team.filter(x=>x.email!==t.email));p.length&&(a.mentions=p)}return a};if(n.method==="POST"){const{image:a,images:p,...x}=await j(n),S=ot(x);return S.text.trim()?S.route.startsWith("/")?I(s,async P=>{await O();const y=k(s.add(P,S));for(const L of[].concat(p??a??[]))await s.attach(P,y.id,L);return l(y,201)}):l({error:"route must be a path"},400):l({error:"empty comment"},400)}if(n.method==="PATCH"){const{id:a,reply:p,image:x,images:S,removeImage:P,edit:y,...L}=await j(n),w=Number(a);if(!Number.isInteger(w))return l({error:"bad id"},400);const E=at(L);return I(s,async N=>{if(await O(),y){const v=N.comments.find(T=>T.id===Number(w)),F=y.at?v?.replies?.find(T=>T.at===y.at):v;if(t&&F?.by&&F.by!==t.email||!(y.text?.trim?.()&&s.edit(N,w,y.at??null,y.text.trim().slice(0,1e4))))return l({error:`no message of yours to edit in #${w}`},404)}p?.trim?.()&&k(s.reply(N,w,"you",p.trim().slice(0,1e4))?.replies.at(-1));for(const v of[].concat(S??x??[]))await s.attach(N,w,v);for(const v of[].concat(P||[]))await s.detach(N,w,v);t&&E.status==="done"&&Object.assign(E,{confirmedBy:t.email,confirmedAt:new Date().toISOString()}),t&&E.status==="open"&&Object.assign(E,{confirmedBy:null,confirmedAt:null});const A=Object.keys(E).length||!p?s.patch(N,w,E):N.comments.find(v=>v.id===Number(w));return A?l(A):l({error:`no comment #${w}`},404)})}if(n.method==="DELETE"){const a=Number(f.searchParams.get("id"));return I(s,async p=>await s.remove(p,a)?l({ok:!0,id:a}):l({error:`no comment #${a}`},404))}return i(405,"Method not allowed")},C=(n,f)=>{const s=f.replace(/^.*[/\\]/,""),o=s.split(".").pop()?.toLowerCase()??"";if(!/^[\w.-]+$/.test(s)||!G[o])return i(400,"Bad name");const t=$(n,s);return b(t)?{status:200,type:G[o],body:_(t)}:i(404,"Not found")};return async n=>{const f=new URL(n.url,"http://devbar"),s=f.pathname.slice(10);if(!c&&!st(n))return i(403,"Notemend answers local addresses only");try{if(s==="config"){const o=rt({root:e,options:{...await g(),...r},routes:u()}),t=await m();return t.cloud&&Object.assign(o,await t.people().catch(()=>({}))),l(o)}if(s==="comments")return await B(n,f);if(s==="image"){const o=await m(),t=(f.searchParams.get("name")||"").replace(/^.*[/\\]/,"");return o.cloud&&/^[\w.-]+$/.test(t)&&await o.fetchImage(t).catch(()=>null),C(o.imageDir,t)}return i(404,"Not found")}catch(o){return o.status===400||o.status===413?i(o.status,o.message):(console.error("[notemend]",o),i(500,"Something went wrong \u2014 the dev server log says what."))}}}function xt(e){const r=ct(e),u=m=>new Promise((c,g)=>{const l=[];m.on("data",i=>l.push(i)),m.on("end",()=>c(Buffer.concat(l))),m.on("error",g)});return async function(c,g,l){if(!c.url||!c.url.startsWith("/__devbar/"))return l();const i=await r({method:c.method,url:c.url,headers:c.headers,body:()=>u(c)});g.statusCode=i.status,g.setHeader("content-type",i.type),g.setHeader("cache-control","no-store"),g.end(i.body)}}export{rt as buildConfig,ct as notemendHandler,xt as notemendMiddleware,yt as scanApp,tt as titleOf,et as titled};
|