notemend 0.1.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +13 -0
- package/README.md +311 -0
- package/bin/init.mjs +34 -0
- package/bin/notemend.mjs +45 -0
- package/client.d.ts +3 -0
- package/hosting.d.ts +5 -0
- package/next.d.ts +7 -0
- package/package.json +75 -0
- package/presets.d.ts +8 -0
- package/src/client/api.js +1 -0
- package/src/client/boot.js +1 -0
- package/src/client/config.js +1 -0
- package/src/client/devices.js +1 -0
- package/src/client/index.js +1 -0
- package/src/client/markup.js +115 -0
- package/src/client/notemend.css +1 -0
- package/src/client/run.js +90 -0
- package/src/client/toplayer.js +1 -0
- package/src/devtools-devices.mjs +1 -0
- package/src/hosting.mjs +1 -0
- package/src/integration.mjs +1 -0
- package/src/next.mjs +1 -0
- package/src/presets.mjs +1 -0
- package/src/server/middleware.mjs +1 -0
- package/src/store/categories.mjs +1 -0
- package/src/store/cloud.mjs +3 -0
- package/src/store/comments.mjs +3 -0
- package/src/store/status.mjs +1 -0
- package/src/store/thread.mjs +1 -0
- package/thread.d.ts +5 -0
- package/types.d.ts +60 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
const v=t=>t.replace(/[&<>"]/g,s=>({"&":"&","<":"<",">":">",'"':"""})[s]),a={signal:'<svg viewBox="0 0 20 20" class="dt-i dt-i--fill"><rect x="1" y="12" width="3.2" height="5" rx="1"/><rect x="5.6" y="9" width="3.2" height="8" rx="1"/><rect x="10.2" y="6" width="3.2" height="11" rx="1"/><rect x="14.8" y="3" width="3.2" height="14" rx="1"/></svg>',wifi:'<svg viewBox="0 0 20 20" class="dt-i dt-i--fill"><path d="M10 16.6 7.4 13.8a3.7 3.7 0 0 1 5.2 0z"/><path d="M4.8 11.1a7.4 7.4 0 0 1 10.4 0l-1.3 1.4a5.5 5.5 0 0 0-7.8 0z"/><path d="M2.2 8.3a11.1 11.1 0 0 1 15.6 0l-1.3 1.4a9.2 9.2 0 0 0-13 0z"/></svg>',battery:'<svg viewBox="0 0 28 14" class="dt-i dt-i--batt"><rect x="1" y="1" width="23" height="12" rx="3.5" fill="none" stroke="currentColor" stroke-opacity=".4"/><rect x="3" y="3" width="17" height="8" rx="2" fill="currentColor"/><path d="M26 5v4a2 2 0 0 0 0-4z" fill="currentColor" fill-opacity=".4"/></svg>',back:'<svg viewBox="0 0 20 20" class="dt-i"><path d="M12.5 4 6.5 10l6 6"/></svg>',fwd:'<svg viewBox="0 0 20 20" class="dt-i"><path d="M7.5 4l6 6-6 6"/></svg>',reload:'<svg viewBox="0 0 20 20" class="dt-i"><path d="M15.5 10a5.5 5.5 0 1 1-1.6-3.9"/><path d="M14.2 3.2v3.2H11"/></svg>',dots:'<svg viewBox="0 0 20 20" class="dt-i dt-i--fill"><circle cx="4.5" cy="10" r="1.6"/><circle cx="10" cy="10" r="1.6"/><circle cx="15.5" cy="10" r="1.6"/></svg>',dotsV:'<svg viewBox="0 0 20 20" class="dt-i dt-i--fill"><circle cx="10" cy="4.5" r="1.6"/><circle cx="10" cy="10" r="1.6"/><circle cx="10" cy="15.5" r="1.6"/></svg>',share:'<svg viewBox="0 0 20 20" class="dt-i"><path d="M10 12.5V2.8M6.8 5.8 10 2.6l3.2 3.2"/><path d="M6.5 8.5H5a1.5 1.5 0 0 0-1.5 1.5v6A1.5 1.5 0 0 0 5 17.5h10a1.5 1.5 0 0 0 1.5-1.5v-6A1.5 1.5 0 0 0 15 8.5h-1.5"/></svg>',plus:'<svg viewBox="0 0 20 20" class="dt-i"><path d="M10 4v12M4 10h12"/></svg>',tabs:'<svg viewBox="0 0 20 20" class="dt-i"><rect x="3" y="6" width="11" height="11" rx="2"/><path d="M6 3.5h8.5A2.5 2.5 0 0 1 17 6v8.5"/></svg>',sidebar:'<svg viewBox="0 0 20 20" class="dt-i"><rect x="2.5" y="4" width="15" height="12" rx="2"/><path d="M8 4v12"/></svg>',lock:'<svg viewBox="0 0 20 20" class="dt-i"><rect x="5" y="9" width="10" height="8" rx="1.8"/><path d="M7 9V6.5a3 3 0 0 1 6 0V9"/></svg>',tune:'<svg viewBox="0 0 20 20" class="dt-i"><path d="M3 6.5h8M15 6.5h2M3 13.5h2M9 13.5h8"/><circle cx="13" cy="6.5" r="2"/><circle cx="7" cy="13.5" r="2"/></svg>',star:'<svg viewBox="0 0 20 20" class="dt-i"><path d="m10 3 2.1 4.4 4.8.6-3.5 3.3.9 4.7L10 13.7 5.7 16l.9-4.7L3.1 8l4.8-.6z" stroke-linejoin="round"/></svg>',user:'<svg viewBox="0 0 20 20" class="dt-i dt-i--fill"><circle cx="10" cy="10" r="8" fill-opacity=".25"/><circle cx="10" cy="8" r="3"/><path d="M4.8 15.3a6 6 0 0 1 10.4 0 7.9 7.9 0 0 1-10.4 0z"/></svg>',recent:'<svg viewBox="0 0 20 20" class="dt-i"><path d="M5.5 5v10M10 5v10M14.5 5v10"/></svg>',home:'<svg viewBox="0 0 20 20" class="dt-i"><rect x="4.5" y="4.5" width="11" height="11" rx="3.5"/></svg>',navBack:'<svg viewBox="0 0 20 20" class="dt-i"><path d="M12.5 4.5 7 10l5.5 5.5"/></svg>',close:'<svg viewBox="0 0 20 20" class="dt-i"><path d="m5.5 5.5 9 9m0-9-9 9"/></svg>',winMin:'<svg viewBox="0 0 20 20" class="dt-i"><path d="M5 10h10"/></svg>',winMax:'<svg viewBox="0 0 20 20" class="dt-i"><rect x="5" y="5" width="10" height="10" rx="1.5"/></svg>',chevUp:'<svg viewBox="0 0 20 20" class="dt-i"><path d="m6 12 4-4 4 4"/></svg>',volume:'<svg viewBox="0 0 20 20" class="dt-i"><path d="M3.5 8v4h3l4 3.5v-11l-4 3.5z" stroke-linejoin="round"/><path d="M13.5 7.5a3.5 3.5 0 0 1 0 5"/></svg>'},B=(t,s)=>t.toLocaleTimeString("en-US",s),k=t=>B(t,{hour:"numeric",minute:"2-digit",hour12:!0}).replace(/\s?[AP]M$/,""),D={island:t=>({side:12,top:12,bottom:12,r:t.w>=430?62:55,body:t.w>=430?74:67,extraW:6}),home:()=>({side:18,top:92,bottom:92,r:0,body:56,extraW:6}),punch:()=>({side:9,top:9,bottom:9,r:34,body:43,extraW:6}),tablet:()=>({side:26,top:26,bottom:26,r:18,body:44}),macbook:t=>({side:16,top:18,bottom:24,r:10,rb:0,body:20,extraW:Math.round((t.w+32)*.12),extraH:18}),laptop:t=>({side:12,top:14,bottom:28,r:4,rb:0,body:12,extraW:Math.round((t.w+24)*.08),extraH:16}),monitor:()=>({side:12,top:12,bottom:34,r:0,body:10,extraH:96})};function S(t,s,e,h,n){const i=t.w+2*s.side,b=t.h+s.top+s.bottom,c=(e-i)/2,d=`<rect class="dt-shell-screen" x="${n}" y="${s.top}" width="${t.w}" height="${t.h}" rx="${s.r}"/>`;let r="";if(t.shell==="island"||t.shell==="home"||t.shell==="punch"){const l=(p,m,o)=>`<rect class="dt-shell-btn" x="${p}" y="${m}" width="4" height="${o}" rx="2"/>`;r+=t.shell==="punch"?l(c+i-1,150,70)+l(c+i-1,240,44):l(c-3,120,28)+l(c-3,170,56)+l(c-3,236,56)+l(c+i-1,190,90),r+=`<rect class="dt-shell-body" x="${c}" y="0" width="${i}" height="${b}" rx="${s.body}"/>`,r+=`<rect class="dt-shell-bezel" x="${c+3}" y="3" width="${i-6}" height="${b-6}" rx="${s.body-3}"/>`,t.shell==="home"&&(r+=`<rect class="dt-shell-slot" x="${e/2-26}" y="44" width="52" height="6" rx="3"/>`,r+=`<circle class="dt-shell-slot" cx="${e/2-48}" cy="47" r="5"/>`,r+=`<circle class="dt-shell-homebtn" cx="${e/2}" cy="${b-46}" r="28"/>`)}else if(t.shell==="tablet")r+=`<rect class="dt-shell-body dt-shell-body--light" x="${c}" y="0" width="${i}" height="${b}" rx="${s.body}"/>`,r+=`<rect class="dt-shell-bezel" x="${c+4}" y="4" width="${i-8}" height="${b-8}" rx="${s.body-4}"/>`;else if(t.shell==="monitor"){const l=Math.round(i*.1);r+=`<path class="dt-shell-stand" d="M${e/2-l/2} ${b-2}h${l}l${l*.2} 84h${-l*1.4}z"/>`,r+=`<rect class="dt-shell-stand" x="${e/2-i*.15}" y="${b+80}" width="${i*.3}" height="14" rx="7"/>`,r+=`<rect class="dt-shell-body" x="${c}" y="0" width="${i}" height="${b}" rx="${s.body}"/>`}else{const l=i+(s.extraW??0),p=(e-l)/2,m=s.extraH??16;r+=`<path class="dt-shell-body" d="M${c} ${s.body}a${s.body} ${s.body} 0 0 1 ${s.body} ${-s.body}h${i-2*s.body}a${s.body} ${s.body} 0 0 1 ${s.body} ${s.body}V${b}H${c}z"/>`,r+=`<path class="dt-shell-base${t.shell==="macbook"?" dt-shell-base--silver":""}" d="M${p} ${b}h${l}v${m-8}a8 8 0 0 1-8 8H${p+8}a8 8 0 0 1-8-8z"/>`,r+=`<rect class="dt-shell-lip" x="${e/2-i*.07}" y="${b}" width="${i*.14}" height="5" rx="2.5"/>`}return`<svg viewBox="0 0 ${e} ${h}" width="${e}" height="${h}" aria-hidden="true">${r}${d}</svg>`}const z={"safari-ios":t=>{const s=t.shell==="home"?20:t.w>=400?62:59;return{top:s,bottom:98,topMin:s,bottomMin:58}},"chrome-android":()=>({top:92,bottom:48,topMin:36,bottomMin:48}),"safari-ipad":()=>({top:74,bottom:20}),"safari-mac":()=>({top:85,bottom:59}),"chrome-windows":()=>({top:87,bottom:48})},W=({d:t,now:s,cutout:e},h)=>{if(t.shell==="home")return`<div class="dt-sb dt-sb--mini" style="height:${h}px"><span class="dt-sb-l">${a.signal}${a.wifi}</span><b>${k(s)}</b><span class="dt-sb-r">${a.battery}</span></div>`;const n=e??{x:(t.w-125)/2,y:11,width:125,height:37};return`<div class="dt-sb" style="height:${h}px"><span class="dt-island" style="left:${n.x}px;top:${n.y}px;width:${n.width}px;height:${n.height}px"></span><b class="dt-sb-time" style="top:${n.y}px;height:${n.height}px">${k(s)}</b><span class="dt-sb-icons" style="top:${n.y}px;height:${n.height}px">${a.signal}${a.wifi}${a.battery}</span></div>`},F=({d:t,host:s,min:e},h)=>{const n=t.shell==="home"?"":'<i class="dt-home-ind"></i>';return e?`<div class="dt-ios-bar is-min" style="height:${h}px"><span class="dt-ios-mini">${v(s)}</span>${n}</div>`:`<div class="dt-ios-bar" style="height:${h}px"><div class="dt-ios-row"><button class="dt-glass dt-glass--round" data-nav="back">${a.back}</button><span class="dt-glass dt-ios-url"><span>${v(s)}</span><button data-nav="reload">${a.reload}</button></span><span class="dt-glass dt-glass--round">${a.dots}</span></div>${n}</div>`},R=({now:t,min:s},e)=>`<div class="dt-sb dt-sb--android" style="height:36px"><b>${B(t,{hour:"numeric",minute:"2-digit",hour12:!1})}</b><span class="dt-punch"></span><span class="dt-sb-r">${a.wifi}${a.signal}${a.battery}</span></div>`+(s?"":`<div class="dt-and-bar"><span class="dt-and-url">${a.tune}<span>${v(e)}</span></span><span class="dt-and-tabs">1</span>${a.dotsV}</div>`),L=()=>`<div class="dt-and-nav">${a.recent}${a.home}${a.navBack}</div>`,T=({now:t,host:s})=>`<div class="dt-sb dt-sb--flat" style="height:24px"><b>${k(t)} ${t.toLocaleDateString("en-US",{weekday:"short",month:"short",day:"numeric"})}</b><span class="dt-sb-r">${a.wifi}${a.battery}</span></div><div class="dt-ipad-bar"><span class="dt-bar-group">${a.sidebar}<button data-nav="back">${a.back}</button><button data-nav="fwd">${a.fwd}</button></span><span class="dt-ipad-url">${a.lock}<span>${v(s)}</span><button data-nav="reload">${a.reload}</button></span><span class="dt-bar-group">${a.share}${a.plus}${a.tabs}</span></div>`,V=({now:t,host:s},e)=>'<div class="dt-mac-menu"><span class="dt-mac-apps"><b>Safari</b><span>File</span><span>Edit</span><span>View</span><span>History</span><span>Bookmarks</span><span>Window</span><span>Help</span></span>'+(e?'<span class="dt-mac-notch"></span>':"")+`<span class="dt-sb-r">${a.wifi}${a.battery}<span>${t.toLocaleDateString("en-US",{weekday:"short",day:"numeric",month:"short"})} ${k(t)}</span></span></div><div class="dt-mac-bar"><span class="dt-lights"><i></i><i></i><i></i></span><span class="dt-bar-group">${a.sidebar}<button data-nav="back">${a.back}</button><button data-nav="fwd">${a.fwd}</button></span><span class="dt-mac-url">${a.lock}<span>${v(s)}</span><button data-nav="reload">${a.reload}</button></span><span class="dt-bar-group">${a.share}${a.plus}${a.tabs}</span></div>`,E=()=>`<div class="dt-mac-dock"><span class="dt-dock">${Array.from({length:9},(t,s)=>`<i style="--hue:${s*40}"></i>`).join("")}</span></div>`,A=({host:t,title:s})=>`<div class="dt-win-tabs"><span class="dt-win-tab"><i class="dt-fav"></i><span>${v(s||t)}</span>${a.close}</span><span class="dt-win-new">${a.plus}</span><span class="dt-win-ctrl">${a.winMin}${a.winMax}${a.close}</span></div><div class="dt-win-bar"><span class="dt-bar-group"><button data-nav="back">${a.back}</button><button data-nav="fwd">${a.fwd}</button><button data-nav="reload">${a.reload}</button></span><span class="dt-win-url">${a.tune}<span>${v(t)}</span>${a.star}</span><span class="dt-bar-group">${a.user}${a.dotsV}</span></div>`,U=({now:t})=>`<div class="dt-win-task"><span class="dt-win-apps">${Array.from({length:6},(s,e)=>`<i style="--hue:${200+e*30}"></i>`).join("")}</span><span class="dt-win-tray">${a.chevUp}${a.wifi}${a.volume}${a.battery}<span class="dt-win-clock">${B(t,{hour:"numeric",minute:"2-digit"})}<br>${t.toLocaleDateString("en-US")}</span></span></div>`;function j(t,s){const e=D[t.shell](t),h=t.w+2*e.side,n=t.h+e.top+e.bottom,i=h+(e.extraW??0),b=n+(t.shell==="monitor"||t.shell==="macbook"||t.shell==="laptop"?e.extraH??0:0),c=(i-h)/2+e.side,d=z[t.browser](t),r=s.min?d.topMin??d.top:d.top,l=s.min?d.bottomMin??d.bottom:d.bottom,p={...s,d:t};let m="",o="";switch(t.browser){case"safari-ios":m=W(p,r),o=F(p,l);break;case"chrome-android":m=R(p,s.host),o=L();break;case"safari-ipad":m=T(p),o='<div class="dt-ipad-foot"><i class="dt-home-ind"></i></div>';break;case"safari-mac":m=V(p,t.shell==="macbook"),o=E();break;case"chrome-windows":m=A(p),o=U(p);break}return{footprint:{w:i,h:b},screen:{x:c,y:e.top,w:t.w,h:t.h,r:e.r,rb:e.rb??e.r},topH:r,bottomH:l,shell:S(t,e,i,b,c),top:m,bottom:o,canMinimize:d.topMin!==void 0&&(d.topMin!==d.top||d.bottomMin!==d.bottom),scrollbar:t.browser==="chrome-windows"?"classic":"overlay"}}let g=null;function y(t){if(g??=Object.assign(document.createElement("canvas"),{width:1,height:1}).getContext("2d",{willReadFrequently:!0}),!g||!t)return[0,0,0,0];g.clearRect(0,0,1,1),g.fillStyle="rgba(0, 0, 0, 0)",g.fillStyle=t,g.fillRect(0,0,1,1);const[s,e,h,n]=g.getImageData(0,0,1,1).data;return[s,e,h,n/255]}const w=([t,s,e])=>`rgb(${t}, ${s}, ${e})`;function O(t){const s=t.defaultView,e=o=>!o||y(o)[3]===0,h=[t.body,t.documentElement].map(o=>o&&s.getComputedStyle(o).backgroundColor).find(o=>o&&!e(o)),[n,i,b,c]=h?y(h):[255,255,255,1],d=[n,i,b].map(o=>Math.round(o*c+255*(1-c))),r=o=>{const[u,$,M,x]=y(o);if(x>=.75)return w([u,$,M]);const f=(C,H)=>Math.round(C*x+H*(1-x));return w([f(u,d[0]),f($,d[1]),f(M,d[2])])},l=o=>{let u=t.elementFromPoint(s.innerWidth/2,o);for(;u&&u!==t.documentElement;u=u.parentElement){const $=s.getComputedStyle(u);if($.position!=="fixed"&&$.position!=="sticky")continue;const M=u.getBoundingClientRect().width>=s.innerWidth*.9,x=$.backdropFilter&&$.backdropFilter!=="none";return M&&!x&&!e($.backgroundColor)?r($.backgroundColor):null}return null},p=t.querySelector('meta[name="theme-color"]')?.content||"",m=p&&!e(p)?w(y(p)):"";return{top:l(4)??w(d),bottom:l(s.innerHeight-4)??w(d),theme:m}}function q(t){const[s,e,h]=y(t).map(n=>n/255).map(n=>n<=.04045?n/12.92:((n+.055)/1.055)**2.4);return .2126*s+.7152*e+.0722*h>.4?"#000":"#fff"}export{j as drawDevice,q as inkFor,O as pageTints,y as rgbaOf};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import"./notemend.css";import{start as t}from"./boot";t(),import.meta.hot&&import.meta.hot.accept(()=>location.reload());
|
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
import{DEVTOOLS_DEVICES as u,DEVTOOLS_GROUPS as b}from"../devtools-devices.mjs";const a=s=>s.replace(/[&<>"]/g,d=>({"&":"&","<":"<",">":">",'"':"""})[d]),i=(s,d=15)=>`<svg viewBox="0 0 20 20" width="${d}" height="${d}" aria-hidden="true">${s}</svg>`;function m(s){const d=location.pathname.replace(/\/$/,"")||"/",o=s.breakpoints.map(e=>["open","claude","done"].map(t=>`<b data-bp="${a(e.id)}" data-state="${t}" hidden>${i(e.icon,11)}<i></i></b>`).join("")).join(""),r=s.groups.map(e=>`<li class="dt-pages-group">${a(e)}</li>`+s.pages.filter(t=>t.group===e).map(t=>`<li><a href="${/^\/(?!\/)/.test(t.route)?a(t.route):"#"}"${t.route===d?' aria-current="page"':""}><span class="dt-menu-label">${a(t.label)}</span><em class="dt-pages-n" hidden>${o}</em></a></li>`).join("")).join(""),l=[...new Set(s.devices.map(e=>e.group))].map(e=>`<p class="dt-devices-group">${a(e)}</p>`+s.devices.filter(t=>t.group===e).map(t=>`<button type="button" data-device="${a(t.id)}" aria-pressed="false"${t.note?` title="${a(t.note)}"`:""}><span class="dt-menu-label">${a(t.label)}</span><em>${t.w}×${t.h}</em></button>`).join("")).join(""),p=b.map(e=>`<p class="dt-devices-group">${a(e)}</p>`+u.filter(t=>t.group===e).map(t=>`<button type="button" data-emu="${a(t.id)}" aria-pressed="false"><span class="dt-menu-label">${a(t.label)}</span><em>${t.w}×${t.h}</em></button>`).join("")).join(""),c=s.breakpoints.map(e=>`<button class="dt-icon dt-bp" type="button" data-bp="${a(e.id)}" aria-pressed="false" title="${a(e.label)}">${i(e.icon,16)}</button>`).join(""),h=Array.from({length:s.grid.columns},()=>'<div class="dt-overlay-col"></div>').join(""),n="Drag to resize inside this breakpoint. Double-click snaps to the band's edge";document.body.insertAdjacentHTML("beforeend",`
|
|
2
|
+
<!-- One bar, bottom-centre: pages | inspectors | comments | breakpoints \xB7 devices. -->
|
|
3
|
+
<div class="devtools">
|
|
4
|
+
<div class="dt-group dt-group--menus">
|
|
5
|
+
<details class="dt-pages" name="dt-menu">
|
|
6
|
+
<summary aria-label="Pages" title="Pages">
|
|
7
|
+
${i('<rect x="4.5" y="2.5" width="11" height="15" rx="1.5" /><path d="M7.5 6.6h5M7.5 10h5M7.5 13.4h3" />')}
|
|
8
|
+
<span class="dt-pages-name">${a(d)}</span>
|
|
9
|
+
</summary>
|
|
10
|
+
<ul>${r}</ul>
|
|
11
|
+
</details>
|
|
12
|
+
</div>
|
|
13
|
+
|
|
14
|
+
<div class="dt-group" role="group" aria-label="Inspect">
|
|
15
|
+
<button class="dt-icon dt-grid-btn" type="button" aria-pressed="false" title="Grid">
|
|
16
|
+
${i('<path d="M4 3v14M8 3v14M12 3v14M16 3v14" />')}
|
|
17
|
+
</button>
|
|
18
|
+
<button class="dt-icon dt-pad-btn" type="button" aria-pressed="false" title="Spacing">
|
|
19
|
+
${i('<rect x="2.5" y="2.5" width="15" height="15" rx="1.5" /><rect x="6.5" y="6.5" width="7" height="7" rx="1" stroke-dasharray="2 2" />')}
|
|
20
|
+
</button>
|
|
21
|
+
<button class="dt-icon dt-size-btn" type="button" aria-pressed="false" title="Size">
|
|
22
|
+
${i('<path d="M3 7V4h3M17 13v3h-3M3 4l6 6M17 16l-6-6" />')}
|
|
23
|
+
</button>
|
|
24
|
+
<button class="dt-icon dt-type-btn" type="button" aria-pressed="false" title="Typography">
|
|
25
|
+
${i('<path d="M2.5 15.5 6.5 5l4 10.5M3.9 12.6h5.2M15 4.5v11M13.2 6.3 15 4.5l1.8 1.8M13.2 13.7 15 15.5l1.8-1.8" />')}
|
|
26
|
+
</button>
|
|
27
|
+
<button class="dt-icon dt-studio-btn" type="button" aria-pressed="true" title="Sanity"${s.sanity?"":" hidden"}>
|
|
28
|
+
${i('<path d="M12.5 3.5 16.5 7.5 7 17H3v-4z" />')}
|
|
29
|
+
</button>
|
|
30
|
+
</div>
|
|
31
|
+
|
|
32
|
+
<div class="dt-group" role="group" aria-label="Comments">
|
|
33
|
+
<button class="dt-icon dt-notes-btn" type="button" aria-pressed="false" title="Comment">
|
|
34
|
+
${i('<path d="M4 3.5h12a2 2 0 0 1 2 2v6a2 2 0 0 1-2 2H9.5L5.5 16.5v-3H4a2 2 0 0 1-2-2v-6a2 2 0 0 1 2-2z" stroke-linejoin="round" />')}
|
|
35
|
+
<span class="dt-notes-count" hidden></span>
|
|
36
|
+
</button>
|
|
37
|
+
<button class="dt-icon dt-history-btn" type="button" aria-pressed="false" title="Panel">
|
|
38
|
+
${i('<rect x="2.5" y="3.5" width="15" height="13" rx="2" /><path d="M12 3.5v13M14 7.5h1.5M14 10h1.5" />')}
|
|
39
|
+
</button>
|
|
40
|
+
<button class="dt-icon dt-resolved-btn" type="button" aria-pressed="true" title="Resolved">
|
|
41
|
+
${i('<circle cx="10" cy="10" r="7.5" /><path d="M6.8 10.2 9 12.4l4-4.4" stroke-linejoin="round" />')}
|
|
42
|
+
</button>
|
|
43
|
+
</div>
|
|
44
|
+
|
|
45
|
+
<div class="dt-group dt-bps" role="group" aria-label="Breakpoint">${c}</div>
|
|
46
|
+
|
|
47
|
+
<div class="dt-group dt-group--menus">
|
|
48
|
+
<details class="dt-devices" name="dt-menu">
|
|
49
|
+
<summary title="Devices">
|
|
50
|
+
${i('<rect x="3" y="4" width="14" height="9" rx="1.5" /><path d="M7 16h6" />')}
|
|
51
|
+
<span class="dt-devices-name">Device</span>
|
|
52
|
+
</summary>
|
|
53
|
+
<div class="dt-devices-menu">
|
|
54
|
+
<div class="dt-menu-tabs" role="tablist" aria-label="Device lists">
|
|
55
|
+
<button type="button" role="tab" data-tab="preview" aria-selected="true">Preview</button>
|
|
56
|
+
<button type="button" role="tab" data-tab="devtools" aria-selected="false">DevTools</button>
|
|
57
|
+
</div>
|
|
58
|
+
<div class="dt-menu-panel" role="tabpanel" data-panel="preview">
|
|
59
|
+
<p class="dt-menu-note">The screens most visitors use, with the browser around the page. Comments go to the breakpoint its width falls in, with the device named.</p>
|
|
60
|
+
${l}
|
|
61
|
+
</div>
|
|
62
|
+
<div class="dt-menu-panel" role="tabpanel" data-panel="devtools" hidden>
|
|
63
|
+
<p class="dt-menu-note">Opens the canvas at the device's size. Comments go to its breakpoint.</p>
|
|
64
|
+
<input class="dt-emu-search" type="search" placeholder="Find a device" aria-label="Find a device" />
|
|
65
|
+
${p}
|
|
66
|
+
</div>
|
|
67
|
+
</div>
|
|
68
|
+
</details>
|
|
69
|
+
<!-- the list is written by the script, from the same table that runs the keys -->
|
|
70
|
+
<details class="dt-keys" name="dt-menu"${s.shortcuts?"":" hidden"}>
|
|
71
|
+
<summary class="dt-icon" title="Shortcuts">
|
|
72
|
+
${i('<rect x="2" y="5" width="16" height="10" rx="2" /><path d="M5.5 8.5h.01M8.5 8.5h.01M11.5 8.5h.01M14.5 8.5h.01M6.5 12h7" />')}
|
|
73
|
+
</summary>
|
|
74
|
+
<div class="dt-keys-menu"></div>
|
|
75
|
+
</details>
|
|
76
|
+
</div>
|
|
77
|
+
</div>
|
|
78
|
+
|
|
79
|
+
<!-- The handle under the bar, on the window's bottom edge. Its own element, not the
|
|
80
|
+
bar's child: it stays put while the bar slides away. -->
|
|
81
|
+
<button class="dt-tab" type="button" aria-expanded="true" aria-label="Hide the bar">
|
|
82
|
+
<svg viewBox="0 0 20 20" width="12" height="12" aria-hidden="true"><path d="M5.5 8 10 12.5 14.5 8" /></svg>
|
|
83
|
+
</button>
|
|
84
|
+
|
|
85
|
+
<div class="dt-frame" hidden role="region" aria-label="Breakpoint preview">
|
|
86
|
+
<div class="dt-stage">
|
|
87
|
+
<span class="dt-frame-handle" data-edge="l" title="${n}"></span>
|
|
88
|
+
<div class="dt-device">
|
|
89
|
+
<div class="dt-shell"></div>
|
|
90
|
+
<iframe title="Breakpoint preview"></iframe>
|
|
91
|
+
<div class="dt-chrome" data-at="top"></div>
|
|
92
|
+
<div class="dt-chrome" data-at="bottom"></div>
|
|
93
|
+
</div>
|
|
94
|
+
<span class="dt-frame-handle" data-edge="r" title="${n}"></span>
|
|
95
|
+
</div>
|
|
96
|
+
<div class="dt-ruler"></div>
|
|
97
|
+
<span class="dt-frame-size"></span>
|
|
98
|
+
<button class="dt-frame-bars dt-frame-btn" type="button" hidden title="Browser bars: shown / folded on scroll">
|
|
99
|
+
<svg viewBox="0 0 20 20" width="14" height="14" aria-hidden="true"><path d="M10 3v14M6.5 6.5 10 3l3.5 3.5M6.5 13.5 10 17l3.5-3.5" /></svg>
|
|
100
|
+
</button>
|
|
101
|
+
<button class="dt-frame-rotate dt-frame-btn" type="button" hidden title="Rotate">
|
|
102
|
+
<svg viewBox="0 0 20 20" width="14" height="14" aria-hidden="true"><path d="M14.5 5.5A6.5 6.5 0 1 0 16.5 10" /><path d="M16.8 3.6v3.4h-3.4" /></svg>
|
|
103
|
+
</button>
|
|
104
|
+
</div>
|
|
105
|
+
|
|
106
|
+
<aside class="dt-history" hidden aria-label="Comment history"></aside>
|
|
107
|
+
<div class="dt-notes-hi" hidden aria-hidden="true"><span class="dt-hi-box"></span><span class="dt-hi-tag"></span></div>
|
|
108
|
+
<div class="dt-notes-overlay" hidden role="region" aria-label="Comments on this page"></div>
|
|
109
|
+
<div class="dt-grid-overlay" hidden aria-hidden="true">
|
|
110
|
+
<div class="${a(s.grid.container)} dt-overlay-container">
|
|
111
|
+
<div class="${a(s.grid.grid)} dt-overlay-grid">${h}</div>
|
|
112
|
+
</div>
|
|
113
|
+
</div>
|
|
114
|
+
<div class="dt-pad-overlay" hidden aria-hidden="true"></div>
|
|
115
|
+
`)}export{m as mount};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
:root{--dt-bg: #121212;--dt-panel: #171717;--dt-raised: #1d1d1d;--dt-ink: #ffffff;--dt-ink-2: #d6d6d6;--dt-muted: #afafaf;--dt-faint: #717171;--dt-accent: #ff5a00;--dt-accent-ink: #000000}.devtools{position:fixed;bottom:16px;left:50%;transform:translate(-50%);z-index:calc(var(--dt-z) + 2);display:flex;align-items:center;gap:6px;padding:5px;background:var(--dt-bg);border:1px solid rgb(255 255 255 / .08);border-radius:999px;box-shadow:0 1px #ffffff0f inset,0 10px 34px #00000080;font:500 11px/1 ui-sans-serif,system-ui,sans-serif}.devtools[data-ready]{transition:transform .24s cubic-bezier(.22,1,.36,1)}.devtools[data-collapsed]{transform:translate(-50%,calc(100% + 16px))}.dt-tab{position:fixed;bottom:0;left:50%;z-index:calc(var(--dt-z) + 3);transform:translate(-50%);display:grid;place-items:center;width:44px;height:12px;padding:0;background:var(--dt-bg);border:1px solid rgb(255 255 255 / .1);border-bottom:0;border-radius:8px 8px 0 0;color:var(--dt-muted);cursor:pointer;transition:color .14s cubic-bezier(.22,1,.36,1),height .14s cubic-bezier(.22,1,.36,1)}.dt-tab:hover{height:14px;color:#fff}.dt-tab:focus-visible{outline:2px solid var(--dt-accent);outline-offset:1px}html.dt-in-frame .dt-tab{display:none}.dt-tab svg{display:block;width:12px;height:12px;fill:none;stroke:currentColor;stroke-width:1.8;stroke-linecap:round;stroke-linejoin:round;transition:transform .24s cubic-bezier(.22,1,.36,1)}.dt-tab[data-collapsed] svg{transform:rotate(180deg)}@media(prefers-reduced-motion:reduce){.devtools[data-ready],.dt-tab svg{transition:none}}.dt-group{position:relative;display:flex;align-items:center;gap:2px;padding:2px;background:#ffffff0d;border-radius:999px}.dt-group--menus{background:transparent;padding:0;gap:4px}.dt-icon[data-tip]:after{content:attr(data-tip);position:absolute;bottom:calc(100% + 10px);left:50%;transform:translate(-50%);z-index:1;width:max-content;max-width:220px;padding:6px 8px;background:var(--dt-bg);border:1px solid rgb(255 255 255 / .12);border-radius:6px;box-shadow:0 6px 18px #00000080;color:var(--dt-ink-2);font:400 11px/1.4 ui-sans-serif,system-ui,sans-serif;text-align:left;white-space:normal;pointer-events:none;opacity:0;transition:opacity .12s cubic-bezier(.22,1,.36,1)}.dt-icon[data-tip]:hover:after,.dt-icon[data-tip]:focus-visible:after{opacity:1}.dt-icon{display:inline-flex;align-items:center;justify-content:center;position:relative;width:28px;height:28px;padding:0;background:transparent;border:0;border-radius:999px;color:var(--dt-muted);cursor:pointer;transition:color .16s cubic-bezier(.22,1,.36,1),background-color .16s cubic-bezier(.22,1,.36,1)}.dt-icon svg,.dt-devices summary svg,.dt-pages summary svg{flex:none;max-width:none;width:15px;height:15px;fill:none;stroke:currentColor;stroke-width:1.5;stroke-linecap:round}.dt-bp svg{width:16px;height:16px}.dt-icon:hover{color:var(--dt-ink);background:#ffffff1a}.dt-icon:focus-visible{outline:2px solid var(--dt-accent);outline-offset:1px}.dt-icon:active{transform:scale(.94)}.dt-icon[aria-pressed=true]{color:var(--dt-accent-ink);background:var(--dt-accent)}.dt-icon[hidden]{display:none}@media(prefers-reduced-motion:reduce){.dt-icon{transition:none}.dt-icon:active{transform:none}}.dt-pages summary::-webkit-details-marker,.dt-devices summary::-webkit-details-marker{display:none}.dt-pages{position:relative}.dt-pages ul,.dt-devices-menu,.dt-keys-menu{color-scheme:dark;scrollbar-width:thin;scrollbar-color:rgb(255 255 255 / .22) transparent}.dt-pages ul{position:absolute;left:0;bottom:calc(100% + 10px);width:320px;max-height:60vh;padding:8px 4px 12px;background:var(--dt-panel);border:1px solid rgb(255 255 255 / .1);border-radius:12px;box-shadow:0 12px 40px #0000008c;overflow-y:auto;overscroll-behavior:contain}.dt-pages-group,.dt-devices-group{margin:12px -4px;padding:12px 16px 0;border-top:1px solid rgb(255 255 255 / .08);color:var(--dt-muted);font:600 9px/1.2 ui-sans-serif,system-ui,sans-serif;letter-spacing:.5px;text-transform:uppercase}.dt-pages-group:first-child,.dt-devices-group:first-child{margin-top:0;padding-top:4px;border-top:0}.dt-pages a{display:flex;align-items:center;justify-content:space-between;gap:10px;padding:4px 12px;border-radius:8px;color:var(--dt-ink-2);font:500 11px/1.3 ui-sans-serif,system-ui,sans-serif;transition:background-color .14s cubic-bezier(.22,1,.36,1)}.dt-pages a:hover{background:#ffffff14;color:#fff}.dt-pages a[aria-current]{color:#fff}.dt-notes-count{position:absolute;top:-3px;right:-3px;pointer-events:none;display:grid;place-items:center;min-width:14px;height:14px;padding:0;box-sizing:border-box;background:#f5c451;border:2px solid var(--dt-bg);border-radius:999px;color:#121212;font:700 9px/10px ui-sans-serif,system-ui,sans-serif;text-align:center}.dt-notes-count[data-state=claude]{background:#d97757;color:#fff}.dt-notes-count[data-state=done]{background:#4f8f41;color:#fff}.dt-notes-count svg{display:block;width:8px;height:8px}.dt-notes-count[hidden]{display:none}.dt-host{position:fixed;inset:0 auto auto 0;width:0;height:0;margin:0;padding:0;border:0;background:none;color:inherit;overflow:visible}.dt-frame[hidden]{display:none}html.dt-framing,html.dt-framing body{overflow:hidden}.dt-frame{position:fixed;inset:0;z-index:var(--dt-z);cursor:default;display:grid;place-items:center;place-content:center;background:var(--dt-bg)}.dt-frame[data-mode=device] .dt-ruler{display:none}.dt-device{max-height:calc(100vh - 32px);border-radius:4px;overflow:hidden}.dt-frame iframe{display:block;max-height:calc(100vh - 64px);border:0;background:#fff}.dt-device[data-shell]{position:relative;overflow:visible;max-height:none;border-radius:0;transform-origin:center}.dt-device[data-shell] iframe{z-index:1;max-height:none}.dt-shell{position:absolute;inset:0;pointer-events:none}.dt-shell svg{display:block}.dt-shell-body{fill:#1c1c1e;stroke:#4a4a4e;stroke-width:1.5}.dt-shell-body--light{fill:#d8d8dd;stroke:#aeaeb2}.dt-shell-bezel{fill:#050505}.dt-shell-btn{fill:#3a3a3c}.dt-shell-slot{fill:#2c2c2e}.dt-shell-homebtn{fill:#0c0c0d;stroke:#3a3a3c;stroke-width:2}.dt-shell-screen{fill:var(--dt-top, #fff)}.dt-shell-base{fill:#2c2c2e}.dt-shell-base--silver{fill:#c9c9ce}.dt-shell-lip{fill:#8e8e93}.dt-shell-stand{fill:#c7c7cc}.dt-chrome{position:absolute;z-index:2;box-sizing:border-box;overflow:hidden;pointer-events:none;font-family:-apple-system,system-ui,Segoe UI,Roboto,sans-serif;-webkit-font-smoothing:antialiased}.dt-chrome:empty{display:none}.dt-chrome[data-at=top]{border-radius:var(--dt-r) var(--dt-r) 0 0;background:var(--dt-top, #fff);color:var(--dt-top-ink, #000)}.dt-chrome[data-at=bottom]{border-radius:0 0 var(--dt-rb) var(--dt-rb);background:var(--dt-bottom, #fff);color:var(--dt-bottom-ink, #000)}.dt-chrome button{display:grid;place-items:center;padding:0;background:none;border:0;color:inherit;cursor:pointer;pointer-events:auto}.dt-i{flex:none;width:18px;height:18px;fill:none;stroke:currentColor;stroke-width:1.7;stroke-linecap:round;stroke-linejoin:round}.dt-i--fill{fill:currentColor;stroke:none}.dt-i--batt{width:26px;height:13px;stroke:none}.dt-bar-group{display:flex;align-items:center;gap:14px}.dt-sb{position:relative}.dt-island{position:absolute;background:#000;border-radius:19px}.dt-sb-time,.dt-sb-icons{position:absolute;display:flex;align-items:center;justify-content:center}.dt-sb-time{left:0;right:calc(50% + 64px);font:600 17px/1 -apple-system,system-ui,sans-serif}.dt-sb-icons{left:calc(50% + 64px);right:0;gap:6px}.dt-sb-icons .dt-i{width:17px;height:17px}.dt-sb--mini{display:flex;align-items:center;justify-content:space-between;padding:0 6px;font:600 12px/1 -apple-system,system-ui,sans-serif}.dt-sb--mini .dt-i{width:13px;height:13px}.dt-sb--mini .dt-i--batt{width:22px;height:11px}.dt-sb-l,.dt-sb-r{display:flex;align-items:center;gap:5px}.dt-ios-bar{position:relative}.dt-ios-row{position:absolute;top:8px;left:14px;right:14px;display:flex;align-items:center;gap:8px;height:48px}.dt-device[data-shell=home] .dt-ios-row{top:auto;bottom:22px}.dt-chrome .dt-glass{background:#ffffffbd;-webkit-backdrop-filter:blur(16px) saturate(180%);backdrop-filter:blur(16px) saturate(180%);box-shadow:0 2px 12px #00000024,inset 0 0 0 .5px #ffffffb3;color:#111}.dt-glass--round{display:grid;place-items:center;flex:none;width:48px;height:48px;border-radius:50%}.dt-ios-url{position:relative;display:flex;align-items:center;justify-content:center;flex:1;min-width:0;height:48px;border-radius:24px;font:500 15px/1 -apple-system,system-ui,sans-serif}.dt-ios-url>span{overflow:hidden;padding:0 34px;white-space:nowrap;text-overflow:ellipsis}.dt-ios-url button{position:absolute;right:12px}.dt-ios-mini{position:absolute;top:6px;left:50%;transform:translate(-50%);max-width:70%;padding:7px 14px;overflow:hidden;border-radius:14px;font:500 12px/1 -apple-system,system-ui,sans-serif;white-space:nowrap;text-overflow:ellipsis;background:#ffffffbd;box-shadow:0 1px 8px #0000001f;color:#111}.dt-home-ind{position:absolute;bottom:8px;left:50%;width:134px;height:5px;transform:translate(-50%);border-radius:3px;background:currentColor}.dt-sb--android{display:flex;align-items:center;justify-content:space-between;padding:0 18px;font:500 13px/1 Roboto,system-ui,sans-serif}.dt-sb--android .dt-i{width:14px;height:14px}.dt-sb--android .dt-i--batt{width:22px;height:11px}.dt-punch{position:absolute;top:12px;left:50%;width:12px;height:12px;transform:translate(-50%);border-radius:50%;background:#000}.dt-and-bar{display:flex;align-items:center;gap:10px;height:56px;padding:0 8px 0 10px}.dt-and-url{display:flex;align-items:center;gap:10px;flex:1;min-width:0;height:40px;padding:0 14px;border-radius:24px;background:color-mix(in srgb,currentColor 8%,transparent);font:400 15px/1 Roboto,system-ui,sans-serif}.dt-and-url span{overflow:hidden;white-space:nowrap;text-overflow:ellipsis}.dt-and-tabs{display:grid;place-items:center;width:18px;height:18px;border:2px solid currentColor;border-radius:4px;font:700 10px/1 Roboto,system-ui,sans-serif}.dt-and-nav{display:flex;align-items:center;justify-content:space-around;height:48px;color:#3c3c3c}.dt-device[data-browser=chrome-android] .dt-chrome[data-at=bottom]{background:#fff}.dt-sb--flat{display:flex;align-items:center;justify-content:space-between;padding:0 22px;font:600 12px/1 -apple-system,system-ui,sans-serif}.dt-sb--flat .dt-i{width:14px;height:14px}.dt-ipad-bar{display:flex;align-items:center;justify-content:space-between;height:50px;padding:0 18px}.dt-ipad-url,.dt-mac-url{position:relative;display:flex;align-items:center;justify-content:center;gap:6px;width:44%;height:34px;border-radius:10px;background:color-mix(in srgb,currentColor 8%,transparent);font:500 13px/1 -apple-system,system-ui,sans-serif}.dt-ipad-url .dt-i,.dt-mac-url .dt-i{width:13px;height:13px}.dt-ipad-url button,.dt-mac-url button{position:absolute;right:10px}.dt-ipad-foot{position:relative;height:100%}.dt-ipad-foot .dt-home-ind{bottom:6px;width:180px}.dt-device[data-browser=safari-mac] .dt-chrome[data-at=top]{background:#f6f6f6;color:#1d1d1f}.dt-mac-menu{position:relative;display:flex;align-items:center;justify-content:space-between;height:33px;padding:0 18px;background:#ececec;font:400 13px/1 -apple-system,system-ui,sans-serif}.dt-mac-apps{display:flex;gap:20px}.dt-mac-notch{position:absolute;top:0;left:50%;width:196px;height:33px;transform:translate(-50%);border-radius:0 0 10px 10px;background:#000}.dt-mac-menu .dt-sb-r{gap:12px}.dt-mac-menu .dt-i{width:15px;height:15px}.dt-mac-bar{display:flex;align-items:center;gap:18px;height:52px;padding:0 18px;border-bottom:1px solid #d9d9d9;color:#555}.dt-mac-url{margin:0 auto;background:#fff;box-shadow:inset 0 0 0 1px #dcdcdc;color:#1d1d1f}.dt-lights{display:flex;gap:9px}.dt-lights i{width:14px;height:14px;border-radius:50%;background:#ff5f57}.dt-lights i:nth-child(2){background:#febc2e}.dt-lights i:nth-child(3){background:#28c840}.dt-mac-dock{display:grid;place-items:center;height:100%;background:linear-gradient(135deg,#5b7fd1,#8a4fd0 55%,#d06a8a)}.dt-dock,.dt-win-apps{display:flex;align-items:center;gap:6px}.dt-dock{padding:5px 8px;border-radius:16px;background:#ffffff4d;box-shadow:inset 0 0 0 .5px #ffffff80}.dt-dock i,.dt-win-apps i{width:40px;height:40px;border-radius:10px;background:linear-gradient(160deg,hsl(var(--hue) 75% 62%),hsl(var(--hue) 70% 45%))}.dt-device[data-browser=chrome-windows] .dt-chrome[data-at=top]{background:#dfe3e8;color:#202124}.dt-device[data-browser=chrome-windows] .dt-chrome[data-at=bottom]{background:#eef1f5;color:#1d1d1f}.dt-win-tabs{display:flex;align-items:flex-end;height:41px;padding-left:8px}.dt-win-tab{display:flex;align-items:center;gap:8px;width:240px;height:34px;box-sizing:border-box;padding:0 10px;border-radius:8px 8px 0 0;background:#fff;font:400 12px/1 Segoe UI,system-ui,sans-serif}.dt-win-tab span{flex:1;overflow:hidden;white-space:nowrap;text-overflow:ellipsis}.dt-win-tab .dt-i{width:14px;height:14px}.dt-fav{flex:none;width:16px;height:16px;border-radius:50%;background:#9aa0a6}.dt-win-new{display:grid;place-items:center;align-self:center;width:28px;height:28px;margin-left:6px}.dt-win-ctrl{display:flex;align-self:stretch;margin-left:auto}.dt-win-ctrl .dt-i{width:46px;height:41px;padding:12px 14px;box-sizing:border-box;stroke-width:1.2}.dt-win-bar{display:flex;align-items:center;gap:12px;height:46px;padding:0 12px;border-bottom:1px solid #dadce0;background:#fff;color:#5f6368}.dt-win-url{display:flex;align-items:center;gap:10px;flex:1;height:34px;padding:0 14px;border-radius:17px;background:#f1f3f4;color:#202124;font:400 14px/1 Segoe UI,system-ui,sans-serif}.dt-win-url span{flex:1}.dt-win-task{position:relative;display:flex;align-items:center;justify-content:center;height:100%;border-top:1px solid #d3d7dd}.dt-win-apps i{width:32px;height:32px;border-radius:6px}.dt-win-tray{position:absolute;right:14px;display:flex;align-items:center;gap:10px;font:400 11px/1.35 Segoe UI,system-ui,sans-serif;text-align:right}.dt-win-tray .dt-i{width:15px;height:15px}html.dt-in-frame .devtools{display:none}html.dt-in-frame,html.dt-in-frame body{scrollbar-width:none}html.dt-in-frame::-webkit-scrollbar,html.dt-in-frame body::-webkit-scrollbar{display:none}html.dt-in-frame.dt-sb-classic{scrollbar-width:auto}html.dt-in-frame.dt-sb-classic::-webkit-scrollbar{display:block;width:15px;background:#f1f1f1}html.dt-in-frame.dt-sb-classic::-webkit-scrollbar-thumb{background:#c1c1c1;border:4px solid #f1f1f1;border-radius:8px}html.dt-in-frame astro-dev-toolbar,html.dt-in-frame sanity-visual-editing{display:none}.dt-ruler{position:relative;height:22px;margin-top:6px;border-top:1px solid rgb(255 255 255 / .14)}.dt-ruler span{position:absolute;top:0}.dt-tick{width:1px;height:5px;background:#ffffff40}.dt-tick.is-major{height:9px;background:#ffffff73}.dt-edge{width:1px;height:22px;background:#0d99ff;opacity:.7}.dt-frame-size{position:fixed;top:12px;left:50%;transform:translate(-50%);padding:4px 10px;background:#0009;border:1px solid rgb(255 255 255 / .12);border-radius:999px;color:var(--dt-ink);font:500 11px/1 ui-sans-serif,system-ui,sans-serif;pointer-events:none}.dt-frame-btn{position:fixed;top:12px;left:calc(50% + var(--dt-badge-w, 0px) / 2 + 8px);display:grid;place-items:center;width:24px;height:24px;padding:0;background:#0009;border:1px solid rgb(255 255 255 / .12);border-radius:50%;color:var(--dt-ink);cursor:pointer}.dt-frame-btn:hover,.dt-frame-btn[aria-pressed=true]{background:var(--dt-accent);border-color:var(--dt-accent);color:var(--dt-accent-ink)}.dt-frame-btn[hidden]{display:none}.dt-frame-btn svg{display:block;fill:none;stroke:currentColor;stroke-width:1.6;stroke-linecap:round;stroke-linejoin:round}.dt-stage{display:flex;align-items:stretch;gap:6px}.dt-frame-handle{flex:none;align-self:center;width:6px;height:72px;background:#ffffff47;border-radius:999px;cursor:ew-resize;touch-action:none;transition:background-color .12s,height .12s}.dt-frame[data-mode=device] .dt-frame-handle{visibility:hidden}.dt-frame-handle:hover,.dt-frame[data-dragging] .dt-frame-handle{background:var(--dt-accent);height:120px}.dt-devices,.dt-keys{position:relative}.dt-devices summary,.dt-pages summary{display:inline-flex;align-items:center;gap:6px;height:28px;padding-inline:10px;background:#ffffff0d;border-radius:999px;color:var(--dt-ink);font:500 11px/1 ui-sans-serif,system-ui,sans-serif;white-space:nowrap;list-style:none;cursor:pointer;transition:background-color .16s cubic-bezier(.22,1,.36,1)}.dt-devices summary:hover,.dt-pages summary:hover,.dt-devices[open] summary,.dt-pages[open] summary{background:#ffffff1f}.dt-devices-menu,.dt-keys-menu{position:absolute;right:0;bottom:calc(100% + 10px);width:264px;max-height:60vh;padding:8px 4px 12px;background:var(--dt-panel);border:1px solid rgb(255 255 255 / .1);border-radius:12px;box-shadow:0 12px 40px #0000008c;overflow-y:auto;overscroll-behavior:contain}.dt-keys summary{list-style:none}.dt-keys summary::-webkit-details-marker{display:none}.dt-keys[open] summary{color:var(--dt-accent-ink);background:var(--dt-accent)}.dt-keys[open] summary:after{display:none}.dt-key-row{display:flex;align-items:center;justify-content:space-between;gap:10px;padding:4px 12px;color:var(--dt-ink-2);font:500 11px/1.3 ui-sans-serif,system-ui,sans-serif}.dt-key-row kbd{flex:none;min-width:12px;padding:2px 5px;background:#ffffff14;border:1px solid rgb(255 255 255 / .12);border-radius:4px;color:var(--dt-ink);font:500 10px/1.2 ui-monospace,monospace;text-align:center}.dt-menu-tabs{display:flex;gap:2px;margin:0 4px 8px;padding:2px;background:#ffffff0f;border-radius:8px}.dt-devices-menu .dt-menu-tabs button{flex:1;justify-content:center;width:auto;padding:5px 8px;border-radius:6px;color:var(--dt-muted);font-weight:600}.dt-devices-menu .dt-menu-tabs button:hover{background:#ffffff0f;color:var(--dt-ink)}.dt-devices-menu .dt-menu-tabs button[aria-selected=true]{background:#ffffff24;color:#fff}.dt-menu-panel[hidden]{display:none}.dt-menu-note{margin:0 12px 10px;color:var(--dt-muted);font:400 10px/1.4 ui-sans-serif,system-ui,sans-serif}.dt-emu-search{display:block;box-sizing:border-box;width:calc(100% - 8px);margin:0 4px 6px;padding:6px 10px;background:#ffffff0f;border:1px solid rgb(255 255 255 / .1);border-radius:8px;outline:none;color:var(--dt-ink);font:500 11px/1.3 ui-sans-serif,system-ui,sans-serif}.dt-emu-search:focus{border-color:var(--dt-accent)}.dt-emu-search::placeholder{color:var(--dt-muted)}.dt-devices-menu [data-emu][hidden],.dt-devices-menu .dt-devices-group[hidden]{display:none}.dt-devices-menu button{display:flex;align-items:center;justify-content:space-between;gap:10px;width:100%;padding:4px 12px;background:transparent;border:0;border-radius:8px;color:var(--dt-ink-2);font:500 11px/1.3 ui-sans-serif,system-ui,sans-serif;text-align:left;cursor:pointer;transition:background-color .14s cubic-bezier(.22,1,.36,1)}.dt-devices-menu button em{flex:none;color:var(--dt-muted);font:500 10px/1 ui-monospace,monospace;font-style:normal}.dt-devices-menu button:hover{background:#ffffff14;color:#fff}.dt-devices-menu button:focus-visible{outline:2px solid var(--dt-accent);outline-offset:-2px}.dt-devices-menu button[aria-pressed=true]{color:#fff}.dt-pages-n{flex:none;display:flex;gap:3px;font-style:normal}.dt-pages-n b{display:inline-flex;align-items:center;gap:3px;padding:2px 5px 2px 4px;border-radius:999px;font:600 9px/1.4 ui-sans-serif,system-ui,sans-serif;font-variant-numeric:tabular-nums}.dt-pages-n b i{font-style:normal}.dt-pages-n[hidden],.dt-pages-n b[hidden]{display:none}.dt-pages-n svg{display:block;fill:none;stroke:currentColor;stroke-width:1.5;stroke-linecap:round;stroke-linejoin:round}.dt-pages-n b[data-state=open]{background:#0d99ff;color:#fff}.dt-pages-n b[data-state=claude]{background:#d97757;color:#fff}.dt-pages-n b[data-state=done]{background:#4f8f4138;color:#8fd07f}.dt-menu-label{min-width:0;overflow:hidden;white-space:nowrap;text-overflow:ellipsis}.dt-devices-menu button[aria-pressed=true] .dt-menu-label:after,.dt-pages a[aria-current] .dt-menu-label:after{content:"";display:inline-block;width:5px;height:9px;margin-left:8px;border-right:1.5px solid var(--dt-accent);border-bottom:1.5px solid var(--dt-accent);transform:rotate(45deg) translate(-1px,-1px)}.dt-notes-overlay{position:fixed;inset:0;z-index:calc(var(--dt-z) + 1);pointer-events:none}.dt-notes-overlay>*{pointer-events:auto}html.dt-noting body{cursor:crosshair}.dt-notes-hi{position:fixed;inset:0;z-index:calc(var(--dt-z) + 1);pointer-events:none}.dt-hi-box{position:fixed;box-sizing:border-box;border:1px solid #0d99ff;background:#0d99ff14}.dt-hi-tag{position:fixed;padding:2px 5px;background:#0d99ff;border-radius:3px;color:#fff;font:500 10px/1.4 ui-monospace,monospace;white-space:pre}html.dt-no-studio sanity-visual-editing{display:none}.dt-pad-overlay{position:fixed;inset:0;z-index:calc(var(--dt-z) - 5);pointer-events:none}.dt-pad-overlay .dt-pad-zone{position:fixed;background:#22a06b47}.dt-pad-overlay .dt-pad-outline{position:fixed;outline:1px dashed rgba(34,160,107,.9);outline-offset:-1px}.dt-pad-overlay .dt-pad-zone--m{background:#ec962e4d}.dt-pad-overlay .dt-pad-chip--m{background:#b5691c}.dt-pad-overlay .dt-pad-zone--g{background:#0d99ff4d}.dt-pad-overlay .dt-pad-chip--g{background:#0d6ec4}.dt-pad-overlay .dt-pad-chip{position:fixed;transform:translate(-50%,-50%);background:#4f8f41;color:#fff;font-size:11px;font-weight:500;line-height:1;padding:3px 6px;border-radius:4px;white-space:nowrap}.dt-pad-overlay .dt-type-card{position:fixed;display:grid;gap:3px;width:200px;box-sizing:border-box;padding:8px 10px;background:var(--dt-panel);border:1px solid rgb(255 255 255 / .12);border-radius:8px;box-shadow:0 8px 24px #00000073;color:var(--dt-ink);font:400 11px/1.35 ui-sans-serif,system-ui,sans-serif}.dt-pad-overlay .dt-type-row{display:flex;gap:8px}.dt-pad-overlay .dt-type-row b{flex:none;width:44px;color:var(--dt-muted);font-weight:400}.dt-pad-overlay .dt-type-row span{display:flex;align-items:center;gap:5px;min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.dt-pad-overlay .dt-type-row em{color:var(--dt-muted);font-style:normal}.dt-pad-overlay .dt-type-sw{flex:none;width:10px;height:10px;border:1px solid rgb(255 255 255 / .25);border-radius:2px}.dt-pad-overlay .dt-pad-tag{position:fixed;background:var(--dt-panel);color:var(--dt-ink);font-size:11px;line-height:1;padding:4px 7px;border-radius:4px;white-space:nowrap}.dt-grid-overlay{position:fixed;inset:0;z-index:calc(var(--dt-z) - 10);pointer-events:none}.dt-overlay-container,.dt-overlay-grid{height:100%}.dt-overlay-col{background:#ff000014}@media(max-width:767px){.devtools{flex-wrap:wrap;justify-content:center;box-sizing:border-box;width:max-content;max-width:calc(100vw - 24px);border-radius:24px}}.dt-pin{position:absolute;z-index:1;display:grid;place-items:center;width:18px;height:18px;margin:-18px 0 0;padding:0;border:0;border-radius:50%;background:var(--cat, #0d99ff);box-shadow:0 0 0 2px #ffffffe6,0 2px 8px #00000059;color:#fff;font:600 10px/1 ui-sans-serif,system-ui,sans-serif;cursor:pointer}.dt-pin--claude{background:#d97757}.dt-pin--done{background:var(--dt-faint);color:var(--dt-ink);box-shadow:0 0 0 2px #ffffff80;opacity:.55}.dt-pin--done:hover{opacity:1}.dt-pin--draft{background:#f0f0f0;color:#121212}.dt-pin--draft svg{display:block;fill:none;stroke:currentColor;stroke-width:1.8;stroke-linecap:round}.dt-note-draft{flex:none;padding:2px 6px;background:#ffffff1a;border-radius:4px;color:var(--dt-ink-2);font:600 10px/1.2 ui-sans-serif,system-ui,sans-serif}.dt-note{position:absolute;z-index:2;box-sizing:border-box;width:288px;margin:6px 0 0 14px;background:var(--dt-panel);border:1px solid rgb(255 255 255 / .08);border-radius:12px;box-shadow:0 12px 40px #0000008c;color:var(--dt-ink);font:12px/1.45 ui-sans-serif,system-ui,sans-serif;cursor:default;overflow:hidden}.dt-note[data-flip]{margin-top:0;transform:translateY(calc(-100% - 24px))}.dt-note[data-flipx]{margin-left:0;transform:translate(calc(-100% - 6px))}.dt-note[data-flip][data-flipx]{transform:translate(calc(-100% - 6px),calc(-100% - 24px))}@media(max-width:479px){.dt-note{left:50%!important;margin-left:0;transform:translate(-50%)}.dt-note[data-flipx],.dt-note[data-flip][data-flipx],.dt-note[data-flip]{margin-left:0;transform:translate(-50%)}.dt-note[data-flip],.dt-note[data-flip][data-flipx]{margin-top:0;transform:translate(-50%,calc(-100% - 24px))}}.dt-note-el{min-width:0;overflow:hidden;white-space:nowrap;text-overflow:ellipsis;font-family:ui-monospace,monospace;font-size:11px;color:var(--dt-muted)}.dt-note p{margin:0}.dt-note-bar{position:relative;display:flex;align-items:center;gap:6px;padding:12px;border-bottom:1px solid rgb(255 255 255 / .08);font-weight:600}.dt-note-tools{margin-left:auto;display:flex;gap:2px}.dt-note-tools button{display:grid;place-items:center;width:22px;height:22px;padding:0;background:transparent;border:0;border-radius:50%;color:var(--dt-muted);font:12px/1 ui-sans-serif,system-ui,sans-serif;cursor:pointer}.dt-note-tools button svg{display:block;fill:none;stroke:currentColor;stroke-width:1.6;stroke-linecap:round}.dt-note-tools button:hover{background:#ffffff1a;color:#fff}.dt-note-resolve.is-on{color:#5fa850}.dt-note-tools .dt-note-state,.dt-note-tools .dt-note-state:hover{color:#d97757}.dt-note-tools .dt-note-resolve.is-on:hover{color:#5fa850}.dt-note-sep{flex:none;align-self:center;width:1px;height:14px;margin:0 4px;background:#ffffff24}.dt-msg p:after{content:none}.dt-note-info:after{content:attr(data-tip);position:absolute;left:12px;right:12px;top:calc(100% + 6px);z-index:2;padding:6px 8px;background:var(--dt-bg);border:1px solid rgb(255 255 255 / .12);border-radius:6px;box-shadow:0 6px 18px #00000080;color:var(--dt-ink-2);font:400 11px/1.4 ui-sans-serif,system-ui,sans-serif;white-space:normal;pointer-events:none;opacity:0;transition:opacity .12s cubic-bezier(.22,1,.36,1)}.dt-note-info:hover:after{opacity:1}.dt-note-info{display:grid;place-items:center;flex:none;width:16px;height:16px;margin-left:2px;color:var(--dt-faint);cursor:help}.dt-note-state svg{display:block;fill:none;stroke:currentColor;stroke-width:1.6;stroke-linecap:round}.dt-note-info:hover{color:var(--dt-ink-2)}.dt-note-info svg{display:block;fill:none;stroke:currentColor;stroke-width:1.4;stroke-linecap:round}.dt-note-cats{display:flex;flex-wrap:wrap;gap:4px;margin:12px 12px 4px}.dt-cat{padding:3px 8px;background:transparent;border:0;border-radius:999px;box-shadow:inset 0 0 0 1px #ffffff1f;color:var(--dt-muted);font:600 10px/1.4 ui-sans-serif,system-ui,sans-serif;cursor:pointer;transition:color .14s cubic-bezier(.22,1,.36,1),background-color .14s cubic-bezier(.22,1,.36,1)}.dt-cat:hover{color:var(--cat);box-shadow:inset 0 0 0 1px color-mix(in srgb,var(--cat) 45%,transparent)}.dt-cat.is-on{background:color-mix(in srgb,var(--cat) 16%,transparent);box-shadow:inset 0 0 0 1px var(--cat);color:var(--cat)}.dt-note-thread,.dt-hist-list,.dt-note-input,.dt-note-reply-input{color-scheme:dark;scrollbar-width:thin;scrollbar-color:rgb(255 255 255 / .22) transparent}.dt-note-thread{max-height:260px;padding:12px 12px 2px;overflow-y:auto}.dt-msg+.dt-msg{margin-top:12px}.dt-msg-head{display:flex;align-items:baseline;gap:6px}.dt-msg-edit{align-self:center;display:grid;place-items:center;width:20px;height:20px;margin-left:auto;padding:0;background:transparent;border:0;border-radius:50%;color:var(--dt-muted);cursor:pointer}.dt-msg-edit:hover{background:#ffffff1a;color:#fff}.dt-msg-edit:focus-visible,.dt-edit-cancel:focus-visible{outline:2px solid var(--dt-accent);outline-offset:1px}.dt-msg-edit svg{display:block;fill:none;stroke:currentColor;stroke-width:1.5;stroke-linecap:round}.dt-msg .dt-compose{margin-top:6px}.dt-edit-cancel{height:28px;padding:0 10px;background:transparent;border:0;border-radius:14px;color:var(--dt-ink-2);font:12px/1 ui-sans-serif,system-ui,sans-serif;cursor:pointer}.dt-edit-cancel:hover{background:#ffffff1a;color:#fff}.dt-msg-face{width:16px;height:16px;border-radius:50%;object-fit:cover;align-self:center}.dt-msg-head b{color:var(--dt-muted);font-size:11px;font-weight:600}.dt-msg-head time{color:var(--dt-muted);font-size:11px}.dt-msg p{margin-top:2px!important;color:var(--dt-ink);font-size:13px;line-height:1.5;cursor:text;user-select:text}.dt-note--orphan{left:50%!important;top:72px!important;margin:0;transform:translate(-50%)!important}.dt-note-orphan{margin:12px 12px 0;padding:6px 8px;background:#e5402c24;border-radius:5px;color:#ff8a7a;font-size:11px}.dt-note-shots{display:flex;flex-wrap:wrap;gap:6px;margin:10px 12px 0}.dt-msg .dt-note-shots{margin:8px 0 0}.dt-shot{position:relative;display:inline-flex}.dt-shot-rm{position:absolute;top:4px;right:4px;display:grid;place-items:center;width:17px;height:17px;padding:0;background:#141414d1;border:1px solid rgb(255 255 255 / .22);border-radius:50%;color:var(--dt-ink);cursor:pointer;transition:background-color .12s cubic-bezier(.22,1,.36,1)}.dt-shot-rm:hover{background:#e5402c;border-color:#e5402c}.dt-shot-rm svg{display:block;fill:none;stroke:currentColor;stroke-width:2;stroke-linecap:round}.dt-note-shots img{display:block;width:76px;height:56px;object-fit:cover;background:var(--dt-bg);border:1px solid rgb(255 255 255 / .12);border-radius:6px}.dt-note-shots a:hover img{border-color:var(--dt-accent)}.dt-note-foot{padding:12px}.dt-compose{background:var(--dt-raised);border:1px solid rgb(255 255 255 / .14);border-radius:10px;transition:border-color .14s cubic-bezier(.22,1,.36,1),box-shadow .14s cubic-bezier(.22,1,.36,1)}.dt-compose:focus-within,.dt-compose[data-drop]{border-color:var(--dt-accent);box-shadow:0 0 0 3px #ff5a0033}.dt-compose .dt-note-shots{margin:2px 12px 10px}.dt-note-input,.dt-note-reply-input,.dt-note-edit-input{display:block;width:100%;box-sizing:border-box;min-height:38px;max-height:50vh;overflow-y:hidden;margin:0;padding:10px 12px 6px;background:transparent;border:0;outline:none;color:var(--dt-ink);font:13px/1.45 ui-sans-serif,system-ui,sans-serif;resize:none}.dt-note-input::placeholder,.dt-note-reply-input::placeholder,.dt-note-edit-input::placeholder{color:var(--dt-muted)}.dt-compose-bar{display:flex;align-items:center;justify-content:space-between;padding:6px;border-top:1px solid rgb(255 255 255 / .08)}.dt-attach,.dt-send{display:grid;place-items:center;flex:none;width:28px;height:28px;padding:0;border:0;border-radius:50%;cursor:pointer;transition:background-color .14s cubic-bezier(.22,1,.36,1),color .14s}.dt-attach{background:transparent;color:var(--dt-muted)}.dt-attach:hover{background:#ffffff1a;color:#fff}.dt-send{background:#ffffff24;color:var(--dt-ink-2)}.dt-send.is-ready,.dt-send:hover{background:var(--dt-accent);color:var(--dt-accent-ink)}.dt-attach svg,.dt-send svg{display:block;fill:none;stroke:currentColor;stroke-width:1.6;stroke-linecap:round;stroke-linejoin:round}.dt-attach:focus-visible,.dt-send:focus-visible{outline:2px solid var(--dt-accent);outline-offset:1px}.dt-history{position:fixed;top:12px;right:12px;bottom:68px;z-index:calc(var(--dt-z) + 2);display:flex;flex-direction:column;box-sizing:border-box;width:300px;background:var(--dt-panel);border:1px solid rgb(255 255 255 / .08);border-radius:12px;box-shadow:0 12px 40px #0000008c;color:var(--dt-ink);font:12px/1.45 ui-sans-serif,system-ui,sans-serif;cursor:default;overflow:hidden}.dt-history[hidden],html.dt-in-frame .dt-history{display:none}.dt-history[data-collapsed]{bottom:auto}.dt-history[data-collapsed] .dt-hist-list,.dt-history[data-collapsed] .dt-hist-empty{display:none}.dt-history[data-collapsed] .dt-hist-head{border-bottom:0}.dt-history:not([data-collapsed]) .dt-hist-fold svg{transform:rotate(180deg)}.dt-hist-head{flex:none;display:flex;align-items:center;gap:8px;padding:10px 12px;border-bottom:1px solid rgb(255 255 255 / .08)}.dt-hist-refresh,.dt-hist-fold{display:grid;place-items:center;width:20px;height:20px;padding:0;background:transparent;border:0;border-radius:5px;color:var(--dt-muted);cursor:pointer}.dt-hist-refresh{margin-left:auto}.dt-hist-refresh:hover,.dt-hist-fold:hover{background:#ffffff14;color:#fff}.dt-hist-refresh[data-spin] svg{animation:dt-spin .5s cubic-bezier(.22,1,.36,1)}@keyframes dt-spin{to{transform:rotate(360deg)}}.dt-hist-refresh svg,.dt-hist-fold svg{display:block;fill:none;stroke:currentColor;stroke-width:1.6;stroke-linecap:round;stroke-linejoin:round;transition:transform .16s cubic-bezier(.22,1,.36,1)}.dt-hist-list{flex:1;min-height:0;padding:6px;overflow-y:auto}.dt-hist-row{position:relative;display:flex;align-items:flex-start;border-radius:8px}.dt-hist-row:hover{background:#ffffff0f}.dt-hist-tools{position:absolute;top:-8px;right:8px;z-index:1;padding:2px;background:var(--dt-raised);border:1px solid rgb(255 255 255 / .12);border-radius:8px;box-shadow:0 4px 12px #0006;opacity:0;transition:opacity .14s cubic-bezier(.22,1,.36,1)}.dt-hist-row:hover .dt-hist-tools,.dt-hist-tools:focus-within{opacity:1}.dt-hist-tools [data-rm]:hover,.dt-hist-tools [data-draft-rm]:hover{color:#e5402c}.dt-hist-go{display:flex;gap:8px;flex:1;min-width:0;padding:8px;background:transparent;border:0;border-radius:8px;color:inherit;font:inherit;text-align:left;cursor:pointer}.dt-hist-here{display:grid;place-items:center;flex:none;color:var(--dt-ink)}.dt-hist-here svg{display:block;fill:none;stroke:currentColor;stroke-width:1.5;stroke-linecap:round;stroke-linejoin:round}.dt-hist-title{color:var(--dt-ink);font-weight:600}.dt-hist-sep{flex:none;align-self:center;width:1px;height:14px;margin:0 2px;background:#ffffff24}.dt-hist-bands{display:flex;flex-wrap:wrap;gap:4px}.dt-hist-bands button{display:inline-flex;align-items:center;gap:3px;padding:2px 6px 2px 5px;background:transparent;border:1px solid rgb(255 255 255 / .16);border-radius:999px;color:var(--dt-muted);font:600 9px/1.4 ui-sans-serif,system-ui,sans-serif;font-variant-numeric:tabular-nums;cursor:pointer}.dt-hist-bands button svg{display:block;fill:none;stroke:currentColor;stroke-width:1.5;stroke-linecap:round;stroke-linejoin:round}.dt-hist-bands button i{font-style:normal}.dt-hist-bands button[data-state=open]{background:#0d99ff;border-color:#0d99ff;color:#fff}.dt-hist-bands button[data-state=claude]{background:#d97757;border-color:#d97757;color:#fff}.dt-hist-group{display:flex;gap:6px;margin:0;padding:10px 12px 4px;color:var(--dt-muted);font-size:10px;font-weight:600;letter-spacing:.06em;text-transform:uppercase}.dt-hist-group:first-child{padding-top:4px}.dt-hist-group em{color:var(--dt-faint);font-style:normal}.dt-hist-row.is-done{opacity:.5}.dt-hist-row.is-done:hover{opacity:1}.dt-hist-n{flex:none;display:grid;place-items:center;width:12px;height:12px;margin-top:4px;background:var(--cat, #0d99ff);border-radius:50%;color:#fff;font:600 8px/1 ui-sans-serif,system-ui,sans-serif}.dt-hist-row.is-done .dt-hist-n{background:var(--dt-faint)}.dt-hist-row.is-claude .dt-hist-n{background:#d97757}.dt-hist-row.is-draft .dt-hist-n{background:#f0f0f0;color:#121212}.dt-hist-n svg:not(.dt-claude){width:8px;height:8px;fill:none;stroke:currentColor;stroke-width:2.2;stroke-linecap:round}.dt-hist-orphan{color:var(--dt-muted);font-weight:500;font-style:italic}.dt-hist-claude{display:inline-flex;align-items:center;gap:3px;color:#d97757;font-weight:600}.dt-claude{fill:none;stroke:currentColor;stroke-width:2.2;stroke-linecap:round}.dt-hist-n .dt-claude{stroke:#fff}.dt-hist-body{display:grid;gap:2px;min-width:0}.dt-hist-id{display:flex;gap:6px;color:var(--dt-muted);font-size:11px}.dt-hist-id em{color:var(--dt-faint);font-style:normal}.dt-hist-text b{color:#d97757;font-weight:600}.dt-hist-text{display:-webkit-box;-webkit-box-orient:vertical;-webkit-line-clamp:2;overflow:hidden}.dt-hist-meta{color:var(--dt-muted);font-size:11px}.dt-hist-empty{margin:0;padding:16px 12px;color:var(--dt-muted)}.dt-toast{position:fixed;left:50%;bottom:68px;transform:translate(-50%);z-index:calc(var(--dt-z) + 5);padding:8px 12px;background:var(--dt-panel);border:1px solid rgb(255 255 255 / .14);border-radius:8px;box-shadow:0 8px 24px #00000073;color:var(--dt-ink);font:400 12px/1.4 ui-sans-serif,system-ui,sans-serif}.dt-mentions{display:grid;margin:0 8px 6px;padding:4px;background:var(--dt-panel);border:1px solid rgb(255 255 255 / .1);border-radius:8px}.dt-mentions button{all:unset;display:flex;gap:6px;align-items:baseline;padding:6px 8px;border-radius:6px;color:var(--dt-ink);font-size:12px;cursor:pointer}.dt-mentions button span{color:var(--dt-faint);font-size:11px}.dt-mentions button:hover,.dt-mentions button:focus-visible,.dt-mentions button[aria-selected=true]{background:#ffffff14}
|
|
@@ -0,0 +1,90 @@
|
|
|
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
|
+
><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>`:"",Xe=(t,e)=>`<span class="dt-note-cats">${Me.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>`,oo='<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>',Ze=(t,e)=>`<span class="dt-shot"><a href="${t}" target="_blank"
|
|
3
|
+
><img src="${t}" alt="" loading="lazy" /></a
|
|
4
|
+
>${e===void 0?"":`<button class="dt-shot-rm" data-act="unshot" ${e} aria-label="Remove screenshot">${oo}</button>`}</span>`,Qe=(t=[],e)=>t.length?`<div class="dt-note-shots">${t.map(n=>{const o=n.split("/").pop(),s=ko(o);return Ze(s,e===void 0?void 0:`data-id="${e}" data-img="${E(o)}"`)}).join("")}</div>`:"",tn=(t=[])=>t.length?`<div class="dt-note-shots">${t.map((e,n)=>Ze(e,`data-i="${n}"`)).join("")}</div>`:"",so='<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>',en=(t,e,n,o,s="")=>`<div class="dt-note-foot"><div class="dt-compose">
|
|
5
|
+
<textarea class="${t}" rows="1" placeholder="${e}">${E(n)}</textarea>
|
|
6
|
+
${s}
|
|
7
|
+
<div class="dt-compose-bar">
|
|
8
|
+
<button class="dt-attach" data-act="attach" title="Attach a screenshot \u2014 or paste or drop one">${so}</button>
|
|
9
|
+
<button class="dt-send${n.trim()?" is-ready":""}" ${o} title="Send (Enter)"
|
|
10
|
+
><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
|
+
</div>
|
|
12
|
+
</div></div>`,ae=(t,e)=>(t||"element")+(e?.[0]?"."+e[0]:""),nn=()=>A.map((t,e)=>({i:e,el:ae(t.tag,t.classes),text:it(t.text??""),shots:t.images?.length??0,orphan:!W(t)}));let re=[],on="";const ao=(t,e)=>t!=="claude"?"":`<button class="dt-note-state" data-act="reopen" data-id="${e}"
|
|
13
|
+
title="Resolved by Claude \u2014 click to clear">${wt(13)}</button>`,sn=(t,e)=>{const n=t==="done";return`${ao(t,e)}<button data-act="${n?"reopen":"done"}" data-id="${e}"
|
|
14
|
+
class="dt-note-resolve${n?" is-on":""}" title="${n?"Reopen":t==="claude"?"Looks right \u2014 mark it resolved":"Resolve"}">${Ue}</button>`},an=(t,e)=>j("comments",{method:"PATCH",headers:{"content-type":"application/json"},body:JSON.stringify(e?{id:t,status:"done",doneBy:"you"}:{id:t,status:"open",doneBy:null})}),E=t=>t.replace(/[&<>"]/g,e=>({"&":"&","<":"<",">":">",'"':"""})[e]),ro=t=>{const e=B.filter(s=>gt(s)===t),n=e.filter(s=>_(s)==="open").length,o=e.filter(s=>_(s)==="claude").length;te.innerHTML=n?String(n):o?wt(9):"\u2713",te.dataset.state=n?"open":o?"claude":"done",te.hidden=e.length===0},h=()=>{if(ze(),w){const a=nn(),l=JSON.stringify(a);l!==on&&(on=l,parent.postMessage({dt:!0,drafts:a},location.origin))}Et(),y!==$t&&(D="",ot=[],$t=y),$&&$.id!==y&&($=null);const t=oe();if(ro(t),!M){m.innerHTML="";return}const e=t;let n="";const o=B.filter(a=>gt(a)===e&&(V||_(a)!=="done"));for(const a of o){const l=W(a);if(!l&&y!==a.id)continue;const d=_(a),c=d==="done",S=!l,H=l??{x:0,y:0},i=Te(a.category);if(S||(n+=`<button class="dt-pin dt-pin--${d}" data-id="${a.id}" aria-label="Comment ${a.id}, ${d==="open"?"open":d==="claude"?"resolved by Claude":"resolved"}" aria-expanded="${y===a.id}"
|
|
15
|
+
style="left:${H.x}px;top:${H.y}px;--cat:${i.color}"
|
|
16
|
+
title="${E(a.text.slice(0,80))} \xB7 ${i.label}${d==="claude"?" \xB7 resolved by Claude \u2014 tick to confirm":d==="done"?" \xB7 resolved":""}">${d==="done"?"\u2713":d==="claude"?wt(11):""}</button>`),y===a.id){const b=Mo(a);n+=`<div class="dt-note${S?" dt-note--orphan":""}" data-id="${a.id}" role="dialog" aria-label="Comment ${a.id}"
|
|
17
|
+
style="left:${H.x}px;top:${H.y}px">
|
|
18
|
+
<div class="dt-note-bar">
|
|
19
|
+
<span class="dt-note-el">${E(ae(a.tag,a.classes))}</span>
|
|
20
|
+
${Je(a.label)}
|
|
21
|
+
<span class="dt-note-tools">
|
|
22
|
+
${sn(d,a.id)}
|
|
23
|
+
<i class="dt-note-sep"></i>
|
|
24
|
+
<button data-act="rm" data-id="${a.id}" title="Delete this thread">${It}</button>
|
|
25
|
+
<button data-act="close" data-id="${a.id}" title="Close">${Ve}</button>
|
|
26
|
+
</span>
|
|
27
|
+
</div>
|
|
28
|
+
${S?'<p class="dt-note-orphan">The element this was pinned to is not on the page right now.</p>':""}
|
|
29
|
+
${Xe(Te(a.category).id,a.id)}
|
|
30
|
+
<div class="dt-note-thread">
|
|
31
|
+
${b.map((p,K)=>{const Y=K===0?null:p.at??null,mt=p.author==="you"&&(!p.by||p.by===N.me?.email),Mt=mt&&$?.id===a.id&&$.at===Y,Le=p.author==="claude"?null:N.team?.find(xe=>xe.email===p.by),Lo=p.author==="claude"?"Claude":mt?"You":Le?.name||p.byName||p.by||"You",Rn=`<div class="dt-msg-head">${Le?.avatar_url?`<img class="dt-msg-face" src="${E(Le.avatar_url)}" alt="">`:""}<b>${E(Lo)}</b><time>${_e(p.at)}</time>${mt&&!Mt?`<button class="dt-msg-edit" data-act="edit" data-id="${a.id}" data-at="${E(Y??"")}" title="Edit">${se}</button>`:""}</div>`;return Mt?`<div class="dt-msg">${Rn}<div class="dt-compose">
|
|
32
|
+
<textarea class="dt-note-edit-input" rows="1">${E($.text)}</textarea>
|
|
33
|
+
${Qe(p.images.filter(xe=>!$.drop.includes(xe.split("/").pop())),a.id)}
|
|
34
|
+
<div class="dt-compose-bar">
|
|
35
|
+
<button class="dt-edit-cancel" data-act="edit-cancel">Cancel</button>
|
|
36
|
+
<button class="dt-send${$.text.trim()?" is-ready":""}" data-act="edit-save" title="Save (Enter)">${Ue}</button>
|
|
37
|
+
</div>
|
|
38
|
+
</div></div>`:`<div class="dt-msg">${Rn}<p>${E(p.text)}</p>${Qe(p.images)}</div>`}).join("")}
|
|
39
|
+
</div>
|
|
40
|
+
${en("dt-note-reply-input","Reply",D,`data-act="reply" data-id="${a.id}"`,tn(ot))}
|
|
41
|
+
</div>`}}A.forEach((a,l)=>{const d=W(a);d&&(n+=`<button class="dt-pin dt-pin--draft" data-parked="${l}" data-act="draft-open" data-i="${l}"
|
|
42
|
+
style="left:${d.x}px;top:${d.y}px" title="Draft, not sent \u2014 click to finish it">${se}</button>`)});const s=u&&W(u);if(u){const a=s?.x??0,l=s?.y??0;n+=`${s?`<span class="dt-pin dt-pin--draft" data-draft style="left:${a}px;top:${l}px"></span>`:""}
|
|
43
|
+
<div class="dt-note${s?"":" dt-note--orphan"}" data-draft style="left:${a}px;top:${l}px">
|
|
44
|
+
<div class="dt-note-bar">
|
|
45
|
+
<span class="dt-note-el">${E(ae(u.tag,u.classes))}</span>
|
|
46
|
+
${Je(u.label)}
|
|
47
|
+
${qt()?'<span class="dt-note-draft">Draft</span>':""}
|
|
48
|
+
<span class="dt-note-tools">
|
|
49
|
+
<button data-act="discard" title="Discard this draft">${It}</button>
|
|
50
|
+
<button data-act="cancel" title="Close \u2014 the draft stays">${Ve}</button>
|
|
51
|
+
</span>
|
|
52
|
+
</div>
|
|
53
|
+
${s?"":'<p class="dt-note-orphan">The element this was pinned to is not on the page right now.</p>'}
|
|
54
|
+
${Xe(u.category)}
|
|
55
|
+
${en("dt-note-input","Comment",u.text??"",'data-act="save"',tn(u.images))}
|
|
56
|
+
</div>`}m.innerHTML=n;for(const a of m.querySelectorAll(".dt-note")){const l=a.getBoundingClientRect();l.bottom>innerHeight-8&&(a.dataset.flip="1"),l.right>innerWidth-8&&(a.dataset.flipx="1")}rn(e);for(const a of m.querySelectorAll(".dt-note-input, .dt-note-reply-input, .dt-note-edit-input"))$n(a);const r=m.querySelector(".dt-note-input");r&&(r.focus(),r.setSelectionRange(r.value.length,r.value.length))},io=()=>{for(const t of m.querySelectorAll(".dt-pin[data-id], .dt-note[data-id]")){if(t.classList.contains("dt-note--orphan"))continue;const e=B.find(o=>o.id===Number(t.dataset.id)),n=e&&W(e);if(!n){t.style.visibility="hidden";continue}t.style.visibility="",t.style.left=`${n.x}px`,t.style.top=`${n.y}px`}for(const t of m.querySelectorAll("[data-draft], [data-parked]")){if(t.classList.contains("dt-note--orphan"))continue;const e=t.dataset.parked?A[Number(t.dataset.parked)]:u,n=e&&W(e);if(!n){t.style.visibility="hidden";continue}t.style.visibility="",t.style.left=`${n.x}px`,t.style.top=`${n.y}px`}},rn=t=>{if(I.hidden)return;const e=B.filter(i=>gt(i)===t),n=new Map(e.map((i,b)=>[i.id,b+1])),o={open:[],claude:[],done:[]};for(const i of e)o[_(i)].push(i);const s=i=>{const b=(i.replies?.length??0)+(i.note?1:0),p=Te(i.category),K=_(i),Y=K==="claude",mt=!W(i),Mt=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-${K}${mt?" is-orphan":""}">
|
|
57
|
+
<button class="dt-hist-go" data-go="${i.id}">
|
|
58
|
+
<span class="dt-hist-n" style="--cat:${p.color}">${Y?wt(8):""}</span>
|
|
59
|
+
<span class="dt-hist-body">
|
|
60
|
+
<span class="dt-hist-id">#${n.get(i.id)}<em>${p.label}</em>${Y?`<b class="dt-hist-claude">${wt(9)}Claude</b>`:""}${mt?'<b class="dt-hist-orphan" title="The element this was pinned to is not on the page right now">no pin</b>':""}</span>
|
|
61
|
+
<span class="dt-hist-text">${Mt.author==="claude"?"<b>Claude:</b> ":""}${E(Mt.text)}</span>
|
|
62
|
+
<span class="dt-hist-meta">${_e(i.updatedAt||i.createdAt)}${i.device?` \xB7 ${E(i.device)}`:i.browser?` \xB7 ${E(i.browser)}`:""}${b?` \xB7 ${b} repl${b===1?"y":"ies"}`:""}</span>
|
|
63
|
+
</span>
|
|
64
|
+
</button>
|
|
65
|
+
<span class="dt-note-tools dt-hist-tools">${sn(K,i.id)}<i class="dt-note-sep"></i
|
|
66
|
+
><button data-rm="${i.id}" title="Delete this comment">${It}</button></span>
|
|
67
|
+
</div>`},r=k.find(i=>i.id===t),a=k.map(i=>{const b=B.filter(p=>gt(p)===i.id&&_(p)!=="done");return{band:i,open:b.filter(p=>_(p)==="open").length,total:b.length}}).filter(i=>i.total&&i.band.id!==t),l=a.length?`<i class="dt-hist-sep"></i><div class="dt-hist-bands">${a.map(({band:i,open:b,total:p})=>`<button data-bp="${i.id}" data-state="${b?"open":"claude"}"
|
|
68
|
+
title="${i.label}: ${b} open \xB7 ${p-b} to check"
|
|
69
|
+
><svg viewBox="0 0 20 20" width="11" height="11" aria-hidden="true">${i.icon}</svg><i>${p}</i></button>`).join("")}</div>`:"",c=["open","claude","done"].filter(i=>o[i].length&&(i!=="done"||V)),S=T.hidden?nn():re,H=i=>`<div class="dt-hist-row is-draft">
|
|
70
|
+
<button class="dt-hist-go" data-draft-go="${i.i}">
|
|
71
|
+
<span class="dt-hist-n">${se}</span>
|
|
72
|
+
<span class="dt-hist-body">
|
|
73
|
+
<span class="dt-hist-id">${E(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>
|
|
74
|
+
<span class="dt-hist-text">${i.text?E(i.text):`${i.shots} screenshot${i.shots===1?"":"s"}`}</span>
|
|
75
|
+
</span>
|
|
76
|
+
</button>
|
|
77
|
+
<span class="dt-note-tools dt-hist-tools"><button data-draft-rm="${i.i}" title="Discard this draft">${It}</button></span>
|
|
78
|
+
</div>`;I.innerHTML=`<div class="dt-hist-head">
|
|
79
|
+
<span class="dt-hist-here" title="${r?.label??t}"
|
|
80
|
+
><svg viewBox="0 0 20 20" width="13" height="13" aria-hidden="true">${r?.icon??""}</svg></span>
|
|
81
|
+
<span class="dt-hist-title">Comments</span>
|
|
82
|
+
${l}
|
|
83
|
+
<button class="dt-hist-refresh" data-refresh aria-label="Reload comments from the file">
|
|
84
|
+
<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
|
+
</button>
|
|
86
|
+
<button class="dt-hist-fold" data-fold aria-label="Collapse or expand the panel">
|
|
87
|
+
<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
|
+
</button>
|
|
89
|
+
</div>`+(c.length||S.length?`<div class="dt-hist-list">${S.length?`<p class="dt-hist-group">Drafts<em>${S.length}</em></p>${S.map(H).join("")}`:""}${c.map(i=>`<p class="dt-hist-group">${xo[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>`)},ie=t=>I.toggleAttribute("data-collapsed",t);I.addEventListener("click",async t=>{const e=t.target.closest("[data-refresh]");if(e){e.dataset.spin="1",await X(),setTimeout(()=>delete e.dataset.spin,500);return}if(I.hasAttribute("data-collapsed")&&t.target.closest(".dt-hist-head")){ie(!1);return}if(t.target.closest("[data-fold]")){ie(!I.hasAttribute("data-collapsed"));return}const n=t.target.closest(".dt-hist-bands [data-bp]");if(n){Tn(n.dataset.bp);return}const o=t.target.closest("[data-draft-go], [data-draft-rm]");if(o){const d=o.dataset.draftRm!==void 0,c=Number(d?o.dataset.draftRm:o.dataset.draftGo);T.hidden?d?dn(c):le(c):q(d?{dropDraft:c}:{openDraft:c});return}const s=t.target.closest(".dt-hist-tools [data-act]");if(s){await an(Number(s.dataset.id),s.dataset.act==="done"),await X();return}const r=t.target.closest("[data-rm]");if(r){await j(`comments?id=${r.dataset.rm}`,{method:"DELETE"}),y=null,await X();return}const a=t.target.closest("[data-go]");if(!a)return;const l=Number(a.dataset.go);if(!T.hidden){q({open:l});return}ln(l)});const ln=t=>{y=t,P(),h();const e=B.find(o=>o.id===t),n=e&&W(e);n?scrollTo({top:scrollY+n.y-innerHeight/2,behavior:"smooth"}):e&&Ye(e)?.scrollIntoView({block:"center",behavior:"smooth"}),m.querySelector(`.dt-pin[data-id="${t}"]`)?.animate([{transform:"scale(1)"},{transform:"scale(1.5)"},{transform:"scale(1)"}],400)},le=t=>{const[e]=A.splice(t,1);if(!e)return;P(),u=e,y=null;const n=W(e);n&&(n.y<0||n.y>innerHeight)&&scrollTo({top:scrollY+n.y-innerHeight/3,behavior:"instant"}),h()},dn=t=>{A.splice(t,1),h()},lo=t=>{I.hidden=!t,Ct.setAttribute("aria-pressed",String(t)),R("dt-history",t?"1":"0"),h()},de=document.querySelector(".dt-resolved-btn"),cn=t=>{V=t,de.setAttribute("aria-pressed",String(t)),R("dt-resolved",t?"1":"0"),q({resolved:t}),h(),Dt()};de.addEventListener("click",()=>cn(!V)),de.setAttribute("aria-pressed",String(V)),Ct.addEventListener("click",()=>{const t=I.hidden===!0;t&&!M&&at(!0),t&&ie(!1),lo(t)});const lt=()=>{ee||!M||(ee=requestAnimationFrame(()=>{ee=0,io()}))},un=new MutationObserver(t=>{t.every(e=>e.target.closest?.(".dt-notes-overlay"))||lt()}),pn=new ResizeObserver(()=>lt()),mn=t=>{const e=()=>({open:0,claude:0,done:0}),n={};for(const l of t){const d=_(l),c=n[l.route??""]??={...e(),bands:{}};c[d]++;const S=gt(l);(c.bands[S]??=e())[d]++}const o=["open","claude","done"],s={open:"open",claude:"resolved by Claude, to check",done:"resolved"},r=l=>o.map(d=>[d,d==="done"&&!V?0:l[d]]),a=l=>r(l).reduce((d,[,c])=>d+c,0);for(const l of document.querySelectorAll(".dt-pages a")){const d=l.querySelector(".dt-pages-n");if(!d)continue;const c=n[new URL(l.href).pathname.replace(/\/+$/,"")||"/"];for(const i of k){const b=c?.bands[i.id];for(const[p,K]of r(b??e())){const Y=d.querySelector(`[data-bp="${i.id}"][data-state="${p}"]`);Y.hidden=!K,K&&(Y.querySelector("i").textContent=String(K),Y.title=`${i.label}: ${K} ${s[p]}`)}}const S=c?a(c):0;d.hidden=!S;const H=c?k.filter(i=>c.bands[i.id]&&a(c.bands[i.id])).map(i=>`${i.label} ${a(c.bands[i.id])}`).join(" \xB7 "):"";d.title=S?`${c.open} open \xB7 ${c.claude} resolved by Claude, to check \xB7 ${c.done} resolved
|
|
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};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
function c(t){if(!("showPopover"in HTMLElement.prototype)||typeof HTMLDialogElement>"u")return;const n=HTMLDialogElement.prototype,a=n.showModal;let e=null;const l=()=>{if(e){for(const o of t)document.body.append(o);try{e.hidePopover()}catch{}e.remove(),e=null}},i=o=>{l(),e=document.createElement("div"),e.className="dt-host",e.setAttribute("popover","manual"),e.append(...t),o.append(e);try{e.showPopover()}catch{}o.addEventListener("close",()=>{l();const s=document.querySelector("dialog:modal");s&&i(s)},{once:!0})};n.showModal=function(){a.call(this),this.isConnected&&i(this)}}export{c as keepAboveModals};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
const e=["iPhone","Android","Foldable","Tablet","Laptop & display"],t=[{id:"iphone-se",label:"iPhone SE",group:"iPhone",w:375,h:667,dpr:2,rotates:!0,mobile:!0},{id:"iphone-xr",label:"iPhone XR",group:"iPhone",w:414,h:896,dpr:2,rotates:!0,mobile:!0,insets:{left:0,top:44,right:0,bottom:34},cutout:{shape:"notch",x:92,y:0,width:231,height:33,"upper-radius":6,"lower-radius":25}},{id:"iphone-12-pro",label:"iPhone 12 Pro",group:"iPhone",w:390,h:844,dpr:3,rotates:!0,mobile:!0,insets:{left:0,top:47,right:0,bottom:34},cutout:{shape:"notch",x:90,y:0,width:210,height:32,"upper-radius":6,"lower-radius":23}},{id:"iphone-14",label:"iPhone 14",group:"iPhone",w:390,h:844,dpr:3,rotates:!0,mobile:!0,insets:{left:0,top:47,right:0,bottom:34},cutout:{shape:"notch",x:114,y:0,width:162,height:34,"upper-radius":5,"lower-radius":22}},{id:"iphone-14-plus",label:"iPhone 14 Plus",group:"iPhone",w:428,h:926,dpr:3,rotates:!0,mobile:!0,insets:{left:0,top:47,right:0,bottom:34},cutout:{shape:"notch",x:133,y:0,width:161,height:34,"upper-radius":5,"lower-radius":22}},{id:"iphone-14-pro",label:"iPhone 14 Pro",group:"iPhone",w:393,h:852,dpr:3,rotates:!0,mobile:!0,insets:{left:0,top:59,right:0,bottom:34},cutout:{shape:"pill",x:134,y:11,width:125,height:37,"border-radius":19}},{id:"iphone-14-pro-max",label:"iPhone 14 Pro Max",group:"iPhone",w:430,h:932,dpr:3,rotates:!0,mobile:!0,insets:{left:0,top:59,right:0,bottom:34},cutout:{shape:"pill",x:153,y:11,width:125,height:37,"border-radius":19}},{id:"iphone-15",label:"iPhone 15",group:"iPhone",w:393,h:852,dpr:3,rotates:!0,mobile:!0,insets:{left:0,top:59,right:0,bottom:34},cutout:{shape:"pill",x:134,y:11,width:125,height:37,"border-radius":19}},{id:"iphone-15-plus",label:"iPhone 15 Plus",group:"iPhone",w:430,h:932,dpr:3,rotates:!0,mobile:!0,insets:{left:0,top:59,right:0,bottom:34},cutout:{shape:"pill",x:153,y:11,width:125,height:37,"border-radius":19}},{id:"iphone-15-pro",label:"iPhone 15 Pro",group:"iPhone",w:393,h:852,dpr:3,rotates:!0,mobile:!0,insets:{left:0,top:59,right:0,bottom:34},cutout:{shape:"pill",x:134,y:11,width:125,height:37,"border-radius":19}},{id:"iphone-15-pro-max",label:"iPhone 15 Pro Max",group:"iPhone",w:430,h:932,dpr:3,rotates:!0,mobile:!0,insets:{left:0,top:59,right:0,bottom:34},cutout:{shape:"pill",x:153,y:11,width:125,height:37,"border-radius":19}},{id:"iphone-16e",label:"iPhone 16e",group:"iPhone",w:390,h:844,dpr:3,rotates:!0,mobile:!0,insets:{left:0,top:47,right:0,bottom:34},cutout:{shape:"notch",x:114,y:0,width:162,height:34,"upper-radius":5,"lower-radius":22}},{id:"iphone-16",label:"iPhone 16",group:"iPhone",w:393,h:852,dpr:3,rotates:!0,mobile:!0,insets:{left:0,top:59,right:0,bottom:34},cutout:{shape:"pill",x:134,y:11,width:125,height:37,"border-radius":19}},{id:"iphone-16-plus",label:"iPhone 16 Plus",group:"iPhone",w:430,h:932,dpr:3,rotates:!0,mobile:!0,insets:{left:0,top:59,right:0,bottom:34},cutout:{shape:"pill",x:153,y:11,width:125,height:37,"border-radius":19}},{id:"iphone-16-pro",label:"iPhone 16 Pro",group:"iPhone",w:402,h:874,dpr:3,rotates:!0,mobile:!0,insets:{left:0,top:62,right:0,bottom:34},cutout:{shape:"pill",x:139,y:14,width:125,height:37,"border-radius":19}},{id:"iphone-16-pro-max",label:"iPhone 16 Pro Max",group:"iPhone",w:440,h:956,dpr:3,rotates:!0,mobile:!0,insets:{left:0,top:62,right:0,bottom:34},cutout:{shape:"pill",x:158,y:14,width:125,height:37,"border-radius":19}},{id:"jiophone-2",label:"JioPhone 2",group:"Android",w:240,h:320,dpr:1,rotates:!0,mobile:!0},{id:"pixel-7",label:"Pixel 7",group:"Android",w:412,h:915,dpr:2.625,rotates:!0,mobile:!0,insets:{left:0,top:52,right:0,bottom:0},cutout:{shape:"circle",x:183,y:0,width:55,height:52,cx:206,cy:26,radius:13}},{id:"pixel-8",label:"Pixel 8",group:"Android",w:412,h:915,dpr:2.625,rotates:!0,mobile:!0,insets:{left:0,top:50,right:0,bottom:0},cutout:{shape:"circle",x:182,y:0,width:46,height:50,cx:206,cy:25,radius:14}},{id:"pixel-8-pro",label:"Pixel 8 Pro",group:"Android",w:448,h:997,dpr:3,rotates:!0,mobile:!0,insets:{left:0,top:50,right:0,bottom:0},cutout:{shape:"circle",x:205,y:0,width:37,height:50,cx:224,cy:25,radius:14}},{id:"pixel-8a",label:"Pixel 8a",group:"Android",w:412,h:915,dpr:2.625,rotates:!0,mobile:!0,insets:{left:0,top:46,right:0,bottom:0},cutout:{shape:"circle",x:185,y:0,width:42,height:46,cx:206,cy:26,radius:13}},{id:"pixel-9",label:"Pixel 9",group:"Android",w:412,h:924,dpr:2.625,rotates:!0,mobile:!0,insets:{left:0,top:58,right:0,bottom:0},cutout:{shape:"circle",x:188,y:0,width:37,height:58,cx:206,cy:29,radius:14}},{id:"pixel-9-pro",label:"Pixel 9 Pro",group:"Android",w:427,h:952,dpr:3,rotates:!0,mobile:!0,insets:{left:0,top:68,right:0,bottom:0},cutout:{shape:"circle",x:195,y:0,width:36,height:68,cx:213,cy:34,radius:16}},{id:"pixel-9-pro-xl",label:"Pixel 9 Pro XL",group:"Android",w:448,h:997,dpr:3,rotates:!0,mobile:!0,insets:{left:0,top:66,right:0,bottom:0},cutout:{shape:"circle",x:205,y:0,width:38,height:66,cx:224,cy:33,radius:16}},{id:"pixel-10",label:"Pixel 10",group:"Android",w:412,h:924,dpr:2.625,rotates:!0,mobile:!0,insets:{left:0,top:58,right:0,bottom:0},cutout:{shape:"circle",x:188,y:0,width:37,height:58,cx:206,cy:29,radius:14}},{id:"samsung-galaxy-s8",label:"Samsung Galaxy S8+",group:"Android",w:360,h:740,dpr:4,rotates:!0,mobile:!0},{id:"samsung-galaxy-a55",label:"Samsung Galaxy A55",group:"Android",w:360,h:800,dpr:2.25,rotates:!0,mobile:!0},{id:"samsung-galaxy-s20-ultra",label:"Samsung Galaxy S20 Ultra",group:"Android",w:412,h:915,dpr:3.5,rotates:!0,mobile:!0},{id:"samsung-galaxy-a51-71",label:"Samsung Galaxy A51/71",group:"Android",w:412,h:914,dpr:2.625,rotates:!0,mobile:!0},{id:"facebook-on-android",label:"Facebook on Android",group:"Android",w:412,h:892,dpr:3.5,rotates:!0,mobile:!0},{id:"moto-g4",label:"Moto G4",group:"Android",w:360,h:640,dpr:3,rotates:!0,mobile:!0},{id:"moto-g-power",label:"Moto G Power",group:"Android",w:412,h:823,dpr:1.75,rotates:!0,mobile:!0},{id:"surface-duo",label:"Surface Duo",group:"Foldable",w:540,h:720,dpr:2.5,rotates:!0,mobile:!0},{id:"pixel-9-pro-fold",label:"Pixel 9 Pro Fold",group:"Foldable",w:412,h:922,dpr:2.625,rotates:!0,mobile:!0},{id:"galaxy-z-fold-6",label:"Galaxy Z Fold 6",group:"Foldable",w:412,h:968,dpr:2.625,rotates:!0,mobile:!0},{id:"galaxy-z-fold-5",label:"Galaxy Z Fold 5",group:"Foldable",w:344,h:882,dpr:2.625,rotates:!0,mobile:!0},{id:"asus-zenbook-fold",label:"Asus Zenbook Fold",group:"Foldable",w:853,h:1280,dpr:1.5,rotates:!0,mobile:!1},{id:"ipad-mini",label:"iPad Mini",group:"Tablet",w:768,h:1024,dpr:2,rotates:!0,mobile:!0},{id:"ipad-pro-13",label:"iPad Pro 13",group:"Tablet",w:1032,h:1376,dpr:2,rotates:!0,mobile:!0},{id:"surface-pro-7",label:"Surface Pro 7",group:"Tablet",w:912,h:1368,dpr:2,rotates:!0,mobile:!0},{id:"surface-pro-10",label:"Surface Pro 10",group:"Tablet",w:960,h:1440,dpr:2,rotates:!0,mobile:!0},{id:"galaxy-tab-s4",label:"Galaxy Tab S4",group:"Tablet",w:712,h:1138,dpr:2.25,rotates:!0,mobile:!0},{id:"nest-hub-max",label:"Nest Hub Max",group:"Laptop & display",w:1280,h:800,dpr:2,rotates:!1,mobile:!0},{id:"laptop-with-touch",label:"Laptop with touch",group:"Laptop & display",w:1280,h:950,dpr:1,rotates:!1,mobile:!1},{id:"laptop-with-hidpi-screen",label:"Laptop with HiDPI screen",group:"Laptop & display",w:1440,h:900,dpr:2,rotates:!1,mobile:!1},{id:"laptop-with-mdpi-screen",label:"Laptop with MDPI screen",group:"Laptop & display",w:1280,h:800,dpr:1,rotates:!1,mobile:!1}];export{t as DEVTOOLS_DEVICES,e as DEVTOOLS_GROUPS};
|
package/src/hosting.mjs
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{tmpdir as p}from"node:os";import{join as l}from"node:path";import{notemendHandler as u,titled as h}from"./server/middleware.mjs";import{BACKEND as g,cloudStore as y}from"./store/cloud.mjs";function w({project:e,token:c,email:a,sitemap:m=[],backend:n}){n&&Object.assign(g,n);const r=l(p(),"notemend",e),s=y(r,e,{access_token:c,email:a}),d=t=>t==="/"?"Home":h(t.split("/").filter(Boolean).pop());return async t=>{const i=new Set(m);if(t.url.startsWith("/__devbar/config"))try{for(const o of(await s.load()).comments)/^\/(?!\/)/.test(o.route)&&i.add(o.route)}catch{}const f=Object.fromEntries([...i].map(o=>[o,[d(o)]]));return u({root:r,options:{pages:f},routes:()=>[],open:async()=>s,crossOrigin:!0})(t)}}export{w as hostedHandler};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{fileURLToPath as n}from"node:url";import{notemendMiddleware as l}from"./server/middleware.mjs";const u=n(new URL("..",import.meta.url));function a(o={}){let t=[];return{name:"notemend",hooks:{"astro:config:setup":({command:e,config:m,injectScript:s,updateConfig:d})=>{if(e!=="dev"||o.enabled===!1)return;const r=n(m.root);s("page",'import "notemend/client";'),d({vite:{optimizeDeps:{exclude:["notemend"]},server:{fs:{allow:[r,u]}},plugins:[{name:"notemend",configureServer(i){i.middlewares.use(l({root:r,options:o,routes:()=>t}))}}]}})},"astro:routes:resolved":({routes:e})=>{t=e}}}}export{a as default};
|
package/src/next.mjs
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
let n;async function t(e){if(process.env.NODE_ENV!=="development")return new Response("Not found",{status:404});if(!n){const{notemendHandler:r,scanApp:c}=await import("./server/middleware.mjs"),a=process.cwd();n=r({root:a,options:{},routes:()=>c(a)})}const s=new URL(e.url),o=await n({method:e.method,url:s.pathname+s.search,headers:Object.fromEntries(e.headers),body:async()=>Buffer.from(await e.arrayBuffer())});return new Response(o.body,{status:o.status,headers:{"content-type":o.type,"cache-control":"no-store"}})}export{t as DELETE,t as GET,t as PATCH,t as POST};
|
package/src/presets.mjs
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
const o={desktop:'<rect x="2" y="4" width="16" height="10" rx="1.5"/><path d="M7 17h6M10 14v3"/>',laptop:'<rect x="3" y="5" width="14" height="9" rx="1.5"/><path d="M1.5 16.5h17"/>',tablet:'<rect x="3.5" y="2.5" width="13" height="15" rx="1.5"/><path d="M9 15h2"/>',landscape:'<rect x="2" y="6" width="16" height="9" rx="1.5"/><path d="M15.5 9v3"/>',portrait:'<rect x="6" y="2" width="8" height="16" rx="1.5"/><path d="M9 15.5h2"/>'};o.mobile=o.portrait;const e=[{id:"desktop",label:"Desktop",min:992,max:1/0,ideal:1440},{id:"tablet",label:"Tablet",min:768,max:991,ideal:834},{id:"landscape",label:"Mobile landscape",min:480,max:767,ideal:667},{id:"portrait",label:"Mobile portrait",min:0,max:479,ideal:390}],a=["island","home","punch","tablet","macbook","laptop","monitor"],t=["safari-ios","chrome-android","safari-ipad","safari-mac","chrome-windows"],i=[{id:"iphone-16",label:"iPhone 15 / 16",group:"Phone",w:393,h:852,shell:"island",browser:"safari-ios",note:"iPhone 14 Pro\u201316; 390 and 402 are within 9px"},{id:"iphone-17-pro-max",label:"iPhone 17 Pro Max",group:"Phone",w:440,h:956,shell:"island",browser:"safari-ios",note:"16/17 Pro Max; 430\xD7932 Plus/Pro Max nearby"},{id:"iphone-se",label:"iPhone SE",group:"Phone",w:375,h:667,shell:"home",browser:"safari-ios",note:"the shortest common screen"},{id:"galaxy-s25",label:"Galaxy S25",group:"Phone",w:360,h:780,shell:"punch",browser:"chrome-android",note:"Galaxy S22\u2013S26; the narrowest common width"},{id:"ipad",label:"iPad",group:"Tablet",w:820,h:1180,shell:"tablet",browser:"safari-ipad",note:'iPad 10th/11th gen, iPad Air 11"'},{id:"macbook-air",label:'MacBook Air 13"',group:"Laptop",w:1470,h:956,shell:"macbook",browser:"safari-mac",note:"M2\u2013M4 at the default scale; 1440 and 1512 nearby"},{id:"windows-laptop",label:'Windows laptop 15.6"',group:"Laptop",w:1536,h:864,shell:"laptop",browser:"chrome-windows",note:"1920\xD71080 at 125% \u2014 the most common laptop"},{id:"desktop-1080",label:"Desktop 1080p",group:"Desktop",w:1920,h:1080,shell:"monitor",browser:"chrome-windows",note:"the most common screen of any kind"}];export{e as BREAKPOINTS,t as BROWSERS,i as DEVICES,o as ICONS,a as SHELLS};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{readFileSync as L,existsSync as P,statSync as G,readdirSync as J}from"node:fs";import{join as b,isAbsolute as U}from"node:path";import{isIP as F}from"node:net";import{pathToFileURL as W}from"node:url";import{openStore as z,retry as K}from"../store/cloud.mjs";import{mentionsIn as V}from"../store/thread.mjs";import{CATEGORIES as Z}from"../store/categories.mjs";import{BREAKPOINTS as Q,DEVICES as X,ICONS as _,SHELLS as R,BROWSERS as D}from"../presets.mjs";const H={png:"image/png",jpg:"image/jpeg",jpeg:"image/jpeg",webp:"image/webp",gif:"image/gif",svg:"image/svg+xml"},M=e=>e.split(".").slice(0,2).map(Number).reduce((r,l)=>r*100+(Number.isNaN(l)?9999:l),0),Y=(e,r)=>{try{const u=L(U(r)?r:b(e,r),"utf8").match(/title="([^"]+)"|\btitle:\s*["'`]([^"'`]+)["'`]/);return(u?.[1]??u?.[2])?.split("\u2014").pop()?.trim()||null}catch{return null}};function ht(e){const r=["app","src/app"].map(i=>b(e,i)).find(P),l=[],u=(i,f)=>{for(const c of J(i,{withFileTypes:!0})){const a=c.name;if(c.isDirectory()){if(/^[_@]|^\(\./.test(a))continue;u(b(i,a),/^\(.+\)$/.test(a)?f:[...f,a])}else/^page\.(jsx?|tsx?|mdx?)$/.test(a)&&l.push({origin:"project",type:"page",pattern:"/"+f.join("/"),entrypoint:b(i,a)})}};return r&&u(r,[]),l}const q=e=>e[0].toUpperCase()+e.slice(1).replace(/[-_]+/g," ");function tt({root:e,options:r,routes:l}){const u=r.pages??{},i=(t,d,p)=>({route:t,name:d,label:d.replace(/^[\d.]+[A-Z]?\.\s*/,""),group:p}),f=l.filter(t=>t.origin==="project"&&t.type==="page"&&!t.pattern.includes("[")).map(t=>({route:t.pattern.replace(/\/+$/,"")||"/",entrypoint:t.entrypoint})),c=new Set(f.map(t=>t.route)),a=[...f,...Object.keys(u).filter(t=>!c.has(t)).map(t=>({route:t}))],j={};for(const{route:t}of a){const d=t.split("/")[1];d&&(j[d]=(j[d]||0)+1)}const E=t=>{const d=t.split("/")[1];return d&&j[d]>1?q(d):"Pages"},k=r.groups?()=>r.groups[r.groups.length-1]:E,$=a.map(({route:t,entrypoint:d})=>{const[p,g]=u[t]??[];return i(t,p??(d&&Y(e,d))??t,g??k(t))}),n=r.groups??[...new Set([...Object.values(u).map(([,t])=>t).filter(Boolean),"Pages",...$.map(t=>t.group).sort()])],m=$.sort((t,d)=>n.indexOf(t.group)-n.indexOf(d.group)||M(t.name)-M(d.name)||t.route.localeCompare(d.route)),o=(r.breakpoints??Q).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??_[t.id]??_.desktop})),s=(r.devices??X).filter(t=>t.w>0&&t.h>0&&R.includes(t.shell)&&D.includes(t.browser)?!0:(console.warn(`[notemend] device "${t.id}" skipped: it needs w and h, shell (${R.join(", ")}) and browser (${D.join(", ")})${t.frame?"; `frame` pictures were replaced by shell + browser in 0.3":""}`),!1));return{pages:m,groups:n.filter(t=>m.some(d=>d.group===t)),breakpoints:o,devices:s,categories:Z,sanity:!!r.sanity,shortcuts:r.shortcuts!==!1,ignore:r.ignore??[],grid:{container:"container",grid:"grid",columns:12,...r.grid},zIndex:r.zIndex??2000000020}}const et=e=>{const r=b(e,"notemend.config.mjs");let l=0,u={};return async()=>{if(!P(r))return{};const i=G(r).mtimeMs;if(i===l)return u;l=i;try{const{default:f,...c}=await import(/* webpackIgnore: true */ /* turbopackIgnore: true */ `${W(r).href}?t=${i}`);u={...c,...f}}catch(f){console.warn(`[notemend] notemend.config.mjs: ${f.message}`)}return u}},rt=e=>{const r=String(e.headers.host||"").toLowerCase(),l=r.startsWith("[")?r.slice(1,r.indexOf("]")):r.replace(/:\d+$/,"");return l.includes(":")?F(l)===6:!l||!l.includes(".")||F(l)===4||/\.(localhost|local|test|internal|lan|home\.arpa)$/.test(l)},w=(e,r)=>String(e??"").replace(/[\u0000-\u001f\u007f]+/g," ").trim().slice(0,r),nt=e=>({route:w(e.route,500),text:String(e.text??"").slice(0,1e4),selector:w(e.selector,2e3),rx:Number.isFinite(e.rx)?e.rx:0,ry:Number.isFinite(e.ry)?e.ry:0,label:w(e.label,200),breakpoint:w(e.breakpoint,40),browser:w(e.browser,80),device:w(e.device,80),tag:w(e.tag,40),classes:Array.isArray(e.classes)?e.classes.slice(0,20).map(r=>w(r,80)):[],nth:Number.isInteger(e.nth)?e.nth:null,category:w(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}),ot=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=w(e.category,40)),r},st=e=>{const r=e.headers.origin;if(!r)return!1;try{return new URL(r).host!==e.headers.host}catch{return!0}};function at({root:e,options:r,routes:l,open:u=()=>z(e),crossOrigin:i=!1}){const f=et(e),c=(n,m=200)=>({status:m,type:"application/json",body:JSON.stringify(n)}),a=(n,m)=>({status:n,type:"text/plain",body:m}),j=async n=>{const m=await n.body();if(m.length>1e6)throw Object.assign(new Error("too large"),{status:413});try{return m.length?JSON.parse(m.toString("utf8")):{}}catch{throw Object.assign(new Error("not JSON"),{status:400})}},E=async(n,m)=>{const o=async s=>{const t=await m(s);if(t.status>=400)throw Object.assign(new Error("not written"),{out:t});return t};try{if(n.cloud)return await K(n,o);const s=n.load(),t=await o(s);return n.save(s),t}catch(s){if(s.out)return s.out;throw s}},k=async(n,m)=>{if(n.method!=="GET"&&!i&&st(n))return a(403,"Cross-origin write refused");const o=await u();if(n.method==="GET"){const p=m.searchParams.get("route"),g=o.version?String(await o.version()):null;if(g&&m.searchParams.get("since")===g)return{status:204,type:"text/plain",body:""};const x=await o.load();return c({version:g,comments:p?x.comments.filter(S=>S.route===p):x.comments})}const s=o.cloud&&n.method!=="DELETE"?await o.people():null,t=s?.me??null,d=p=>{if(t&&p){p.by=t.email,p.byName=t.name;const g=V(p.text,s.team.filter(x=>x.email!==t.email));g.length&&(p.mentions=g)}return p};if(n.method==="POST"){const{image:p,images:g,...x}=await j(n),S=nt(x);return S.text.trim()?S.route.startsWith("/")?E(o,async I=>{const y=d(o.add(I,S));for(const C of[].concat(g??p??[]))await o.attach(I,y.id,C);return c(y,201)}):c({error:"route must be a path"},400):c({error:"empty comment"},400)}if(n.method==="PATCH"){const{id:p,reply:g,image:x,images:S,removeImage:I,edit:y,...C}=await j(n),h=Number(p);if(!Number.isInteger(h))return c({error:"bad id"},400);const O=ot(C);return E(o,async N=>{if(y){const v=N.comments.find(B=>B.id===Number(h)),A=y.at?v?.replies?.find(B=>B.at===y.at):v;if(t&&A?.by&&A.by!==t.email||!(y.text?.trim?.()&&o.edit(N,h,y.at??null,y.text.trim().slice(0,1e4))))return c({error:`no message of yours to edit in #${h}`},404)}g?.trim?.()&&d(o.reply(N,h,"you",g.trim().slice(0,1e4))?.replies.at(-1));for(const v of[].concat(S??x??[]))await o.attach(N,h,v);for(const v of[].concat(I||[]))await o.detach(N,h,v);t&&O.status==="done"&&Object.assign(O,{confirmedBy:t.email,confirmedAt:new Date().toISOString()}),t&&O.status==="open"&&Object.assign(O,{confirmedBy:null,confirmedAt:null});const T=Object.keys(O).length||!g?o.patch(N,h,O):N.comments.find(v=>v.id===Number(h));return T?c(T):c({error:`no comment #${h}`},404)})}if(n.method==="DELETE"){const p=Number(m.searchParams.get("id"));return E(o,async g=>await o.remove(g,p)?c({ok:!0,id:p}):c({error:`no comment #${p}`},404))}return a(405,"Method not allowed")},$=(n,m)=>{const o=m.replace(/^.*[/\\]/,""),s=o.split(".").pop()?.toLowerCase()??"";if(!/^[\w.-]+$/.test(o)||!H[s])return a(400,"Bad name");const t=b(n,o);return P(t)?{status:200,type:H[s],body:L(t)}:a(404,"Not found")};return async n=>{const m=new URL(n.url,"http://devbar"),o=m.pathname.slice(10);if(!i&&!rt(n))return a(403,"Notemend answers local addresses only");try{if(o==="config"){const s=tt({root:e,options:{...await f(),...r},routes:l()}),t=await u();return t.cloud&&Object.assign(s,await t.people().catch(()=>({}))),c(s)}if(o==="comments")return await k(n,m);if(o==="image"){const s=await u(),t=(m.searchParams.get("name")||"").replace(/^.*[/\\]/,"");return s.cloud&&/^[\w.-]+$/.test(t)&&await s.fetchImage(t).catch(()=>null),$(s.imageDir,t)}return a(404,"Not found")}catch(s){return s.status===400||s.status===413?a(s.status,s.message):(console.error("[notemend]",s),a(500,"Something went wrong \u2014 the dev server log says what."))}}}function wt(e){const r=at(e),l=u=>new Promise((i,f)=>{const c=[];u.on("data",a=>c.push(a)),u.on("end",()=>i(Buffer.concat(c))),u.on("error",f)});return async function(i,f,c){if(!i.url||!i.url.startsWith("/__devbar/"))return c();const a=await r({method:i.method,url:i.url,headers:i.headers,body:()=>l(i)});f.statusCode=a.status,f.setHeader("content-type",a.type),f.setHeader("cache-control","no-store"),f.end(a.body)}}export{tt as buildConfig,at as notemendHandler,wt as notemendMiddleware,ht as scanApp,Y as titleOf,q as titled};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
const o=[{id:"general",label:"General",color:"#0d99ff"},{id:"text",label:"Text",color:"#f5c451"},{id:"bug",label:"Bug",color:"#e5484d"},{id:"motion",label:"Motion",color:"#a475f9"}],t=e=>o.find(l=>l.id===e)||o[0];export{o as CATEGORIES,t as categoryOf};
|
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
import{readFileSync as A,writeFileSync as j,existsSync as H,mkdirSync as O,rmSync as T}from"node:fs";import{homedir as q}from"node:os";import{dirname as F,join as g}from"node:path";import{createStore as K,add as R,reply as W,edit as z,patch as Y,shotName as _}from"./comments.mjs";const Z=process.env.NOTEMEND_APP||"https://app.notemend.com",S={url:process.env.NOTEMEND_URL||"https://xzhnjldvkirrydbyrdnm.supabase.co",key:process.env.NOTEMEND_KEY||"sb_publishable_b8h8jTHZ9KtbPvMuroLhqA_-yBqZwd6"},E=g(process.env.NOTEMEND_HOME||g(q(),".config","notemend"),"session.json"),P=e=>g(e,".notemend.json"),G=e=>{try{return JSON.parse(A(P(e),"utf8")).project||null}catch{return null}},se=(e,n)=>j(P(e),JSON.stringify({project:n},null,2)+`
|
|
2
|
+
`),ae=e=>T(P(e),{force:!0}),U=()=>{try{const e=JSON.parse(A(E,"utf8"));return e.url===S.url?e:null}catch{return null}},Q=e=>{O(F(E),{recursive:!0}),j(E,JSON.stringify(e,null,2)+`
|
|
3
|
+
`,{mode:384})},ie=()=>T(E,{force:!0});async function x(e,{method:n="GET",token:l,body:o,headers:d={},raw:a=!1}={}){const i=await fetch(`${S.url}${e}`,{method:n,headers:{apikey:S.key,authorization:`Bearer ${l||S.key}`,...o&&!a?{"content-type":"application/json"}:{},...d},body:a?o:o&&JSON.stringify(o)});if(!i.ok){const m=await i.text();let h=m;try{const u=JSON.parse(m);h=u.msg||u.message||u.error_description||u.error||m}catch{}const w=new Error(`${h} (${i.status})`);throw w.status=i.status,w}return i}const D=e=>{const n={url:S.url,email:e.user.email,user:e.user.id,access_token:e.access_token,refresh_token:e.refresh_token,expires_at:e.expires_at??Math.floor(Date.now()/1e3)+e.expires_in};return Q(n),n},ce=e=>x("/auth/v1/otp",{method:"POST",body:{email:e,create_user:!0}}),ue=async(e,n)=>D(await(await x("/auth/v1/verify",{method:"POST",body:{email:e,token:n,type:"email"}})).json());async function le(e){const{createServer:n}=await import("node:http"),{randomBytes:l}=await import("node:crypto"),o=l(16).toString("hex"),d=(a,i)=>`<!doctype html><meta charset="utf-8"><title>${a}</title><body style="font:15px system-ui;display:grid;place-items:center;height:90vh;background:#0b0b0b;color:#ededed"><div style="text-align:center"><h2>${a}</h2><p style="color:#8f8f8f">${i}</p></div>`;return new Promise((a,i)=>{const m=n(async(u,v)=>{if(u.method!=="POST"||!u.url.startsWith("/callback")){v.writeHead(404).end();return}let $="";for await(const k of u)$+=k;const y=new URLSearchParams($);if(y.get("state")!==o){v.writeHead(403,{"content-type":"text/html"}).end(d("Not this run","Run npx notemend login again."));return}try{const k=await(await x("/auth/v1/user",{token:y.get("access_token")})).json(),C=D({user:k,access_token:y.get("access_token"),refresh_token:y.get("refresh_token"),expires_at:Number(y.get("expires_at"))});v.writeHead(200,{"content-type":"text/html"}).end(d("You are signed in","Back to the terminal \u2014 you can close this tab.")),w(),a(C)}catch(k){v.writeHead(400,{"content-type":"text/html"}).end(d("Could not sign in",k.message)),w(),i(k)}}),h=setTimeout(()=>{w(),i(new Error("No answer from the browser in 5 minutes."))},300*1e3),w=()=>{clearTimeout(h),m.close()};m.listen(0,"127.0.0.1",()=>{const u=m.address().port;console.log(`Waiting on 127.0.0.1:${u} \u2014 the browser page should show the same port.`),e(`${Z}/cli?port=${u}&state=${o}`)})})}async function me(e,n){const l=await B();if(!l)throw new Error("Sign in first: npx notemend login");return(await(await x("/rest/v1/projects",{method:"POST",token:l.access_token,headers:{prefer:"return=representation"},body:{name:e,...n?{site_url:n}:{}}})).json())[0]}async function B(){const e=U();if(!e)return null;if(e.expires_at-60>Date.now()/1e3)return e;try{const n=await x("/auth/v1/token?grant_type=refresh_token",{method:"POST",body:{refresh_token:e.refresh_token}});return D(await n.json())}catch(n){if(n.status===400||n.status===401)return null;throw n}}class J extends Error{}function V(e,n,l=null){const o=g(e,"feedback","images"),d=t=>`feedback/images/${t}`,a=new WeakMap,i=l?async()=>l:async()=>{const t=await B();if(!t)throw new Error("Not signed in to Notemend \u2014 run `npx notemend login`.");return t},m=async(t,r={})=>x(`/rest/v1/${t}`,{...r,token:(await i()).access_token}),h=async(t,r={})=>x(`/storage/v1/object/shots/${n}/${t}`,{...r,token:(await i()).access_token}),w=async()=>{const t=await(await m(`stores?project_id=eq.${n}&select=doc,version`)).json();if(!t.length)throw new Error(`Project ${n} is not there, or you are not in it. Check \`npx notemend link\`.`);const r=t[0].doc;return a.set(r,t[0].version),r},u=async()=>(await(await m(`stores?project_id=eq.${n}&select=version`)).json())[0]?.version??null,v=async t=>{const r=a.get(t),c=await(await m(`stores?project_id=eq.${n}&version=eq.${r}`,{method:"PATCH",body:{doc:t},headers:{prefer:"return=representation"}})).json();if(!c.length)throw new J("Someone else wrote first");a.set(t,c[0].version)},$=async(t,r,c)=>{const s=t.comments.find(L=>L.id===Number(r)),f=/^data:image\/(png|jpeg|webp|gif);base64,(.+)$/s.exec(c||"");if(!s||!f)return null;const b=f[1]==="jpeg"?"jpg":f[1];let p=Date.now();for(;H(g(o,`${s.id}-${p}.${b}`));)p++;const N=`${s.id}-${p}.${b}`,M=Buffer.from(f[2],"base64");return await h(N,{method:"POST",body:M,raw:!0,headers:{"content-type":`image/${f[1]}`,"x-upsert":"true"}}),O(o,{recursive:!0}),j(g(o,N),M),(s.images||=[]).push(d(N)),s.updatedAt=new Date().toISOString(),d(N)},y=async t=>{_(t)&&(T(g(o,t),{force:!0}),await h(t,{method:"DELETE"}).catch(()=>{}))};return{cloud:!0,project:n,root:e,imageDir:o,load:w,version:u,save:v,attach:$,detach:async(t,r,c)=>{const s=t.comments.find(p=>p.id===Number(r)),f=_(c),b=f&&s?.images?.find(p=>_(p)===f);return b?(await y(f),s.images=s.images.filter(p=>p!==b),s.updatedAt=new Date().toISOString(),!0):!1},remove:async(t,r)=>{const c=t.comments.find(s=>s.id===Number(r));if(!c)return!1;for(const s of c.images||[])await y(_(s));return t.comments=t.comments.filter(s=>s.id!==Number(r)),!0},fetchImage:async t=>{if(!_(t)||_(t)!==t)return null;const r=g(o,t);if(H(r))return r;const c=await h(t).catch(()=>null);return c?(O(o,{recursive:!0}),j(r,Buffer.from(await c.arrayBuffer())),r):null},people:async()=>{const t=await i(),r=await(await m("profiles?select=email,name,nickname,avatar_url")).json();return{me:r.find(c=>c.email===t.email)??{email:t.email,name:"",avatar_url:null},team:r}},add:R,reply:W,edit:z,patch:Y}}let I=!1;async function de(e){const n=G(e);return n&&await B()?V(e,n):(n&&!I&&(I=!0,console.warn("[notemend] this site is linked to a Notemend project, but this computer is not signed in \u2014 comments stay in feedback/ until you run `npx notemend login`.")),K(e))}async function fe(e,n){for(let l=0;;l++){const o=await e.load(),d=await n(o);try{return await e.save(o),d}catch(a){if(!(a instanceof J)||l>=4)throw a}}}export{S as BACKEND,Z as CABINET,J as Conflict,le as browserLogin,V as cloudStore,me as createProject,se as link,G as linkedProject,ie as logout,de as openStore,fe as retry,ce as sendCode,B as session,ae as unlink,ue as verifyCode};
|