loop-canvas 0.1.6 → 0.1.7
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/cli.mjs +6 -6
- package/package.json +1 -1
- package/public/app.css +1 -1
- package/public/app.js +111 -89
- package/public/duo3d.js +4259 -0
- package/public/fflate.LICENSE.txt +21 -0
- package/public/index.html +4 -2
- package/public/three.LICENSE.txt +21 -0
- package/server.mjs +28 -25
package/public/app.js
CHANGED
|
@@ -1,122 +1,144 @@
|
|
|
1
|
-
const m=e=>document.querySelector(e),I=m("#viewport"),xt=m("#world"),Vr=m("#frames"),kt=m("#ink"),xi=m("#cursors"),V=m("#hover-box"),H=m("#composer"),W=m("#composer-input"),z=m("#thread"),L=e=>String(e??"").replace(/[&<>"']/g,t=>({"&":"&","<":"<",">":">",'"':""","'":"'"})[t]),ha=()=>Math.random().toString(36).slice(2,10),ga=()=>(ha()+ha()).slice(0,8),Ae={get(e,t){try{const n=localStorage.getItem(e);return n==null?t:JSON.parse(n)}catch{return t}},set(e,t){try{localStorage.setItem(e,JSON.stringify(t))}catch{}}},Xr={select:'<path d="M9.80282 4.62973L15.8364 6.99069C19.3164 8.35243 21.0564 9.03329 20.9987 10.1133C20.941 11.1934 19.1251 11.6886 15.4933 12.6791C14.412 12.974 13.8713 13.1215 13.4964 13.4963C13.1215 13.8712 12.9741 14.4119 12.6791 15.4933C11.6887 19.125 11.1934 20.9409 10.1134 20.9986C9.03335 21.0563 8.35249 19.3163 6.99075 15.8363L4.62979 9.80276C3.20411 6.15934 2.49127 4.33764 3.41448 3.41442C4.3377 2.49121 6.15941 3.20405 9.80282 4.62973Z"/>',pen:'<path d="M3.49977 18.9853V20.5H5.01449C6.24074 20.5 6.85387 20.5 7.40518 20.2716C7.9565 20.0433 8.39004 19.6097 9.25713 18.7426L19.1211 8.87868C20.0037 7.99612 20.4449 7.55483 20.4937 7.01325C20.5018 6.92372 20.5018 6.83364 20.4937 6.74411C20.4449 6.20253 20.0037 5.76124 19.1211 4.87868C18.2385 3.99612 17.7972 3.55483 17.2557 3.50605C17.1661 3.49798 17.0761 3.49798 16.9865 3.50605C16.4449 3.55483 16.0037 3.99612 15.1211 4.87868L5.25713 14.7426C4.39004 15.6097 3.9565 16.0433 3.72813 16.5946C3.49977 17.1459 3.49977 17.759 3.49977 18.9853Z"/><path d="M13.5 6.5L17.5 10.5"/>',erase:'<path d="M8.73792 7.78021L4.84693 11.7574C3.67722 12.953 3.09236 13.5508 3.01263 14.2802C2.99579 14.4343 2.99579 14.5899 3.01263 14.744C3.09236 15.4733 3.67722 16.0711 4.84693 17.2668L4.99601 17.4191C5.62049 18.0575 5.93274 18.3766 6.30638 18.5911C6.5236 18.7157 6.75482 18.8134 6.99505 18.882C7.40827 19 7.85149 19 8.73792 19C9.62436 19 10.0676 19 10.4808 18.882C10.721 18.8134 10.9522 18.7157 11.1695 18.5911C11.5431 18.3766 11.8554 18.0575 12.4798 17.4191L15.3239 14.5121M8.73792 7.78021L12.3199 4.12313C13.7065 2.70754 14.3997 1.99974 15.2627 2C16.1256 2.00026 16.8185 2.70846 18.2042 4.12487L18.9473 4.8845C20.3159 6.28342 21.0002 6.98288 21 7.85008C20.9997 8.71728 20.315 9.41633 18.9456 10.8144L15.3239 14.5121M8.73792 7.78021L15.3239 14.5121"/><path d="M10 22L21 22"/>',comment:'<path d="M12 18.0012H15C18.2998 18.0012 19.9497 18.0012 20.9749 16.9761C22 15.951 22 14.3011 22 11.0012V9.50122C22 6.20139 22 4.55147 20.9749 3.52635C19.9497 2.50122 18.2998 2.50122 15 2.50122H9C5.70017 2.50122 4.05025 2.50122 3.02513 3.52635C2 4.55147 2 6.20139 2 9.50122V14.0012C2 14.4656 2 14.6978 2.02201 14.8931C2.20484 16.5158 3.48545 17.7964 5.10812 17.9792C5.30344 18.0012 5.53563 18.0012 6 18.0012V20.0819C6 20.9044 6 21.3157 6.26407 21.457C6.52814 21.5983 6.87033 21.3702 7.5547 20.914L12 18.0012Z"/>',frame:'<path d="M2 6H22M2 18H22"/><path d="M6 22L6 2M18 22V2"/>',comments:'<path d="M8 13.0012H16M8 8.00122H12"/><path d="M12 18.0012H15C18.2998 18.0012 19.9497 18.0012 20.9749 16.9761C22 15.951 22 14.3011 22 11.0012V9.50122C22 6.20139 22 4.55147 20.9749 3.52635C19.9497 2.50122 18.2998 2.50122 15 2.50122H9C5.70017 2.50122 4.05025 2.50122 3.02513 3.52635C2 4.55147 2 6.20139 2 9.50122V14.0012C2 14.4656 2 14.6978 2.02201 14.8931C2.20484 16.5158 3.48545 17.7964 5.10812 17.9792C5.30344 18.0012 5.53563 18.0012 6 18.0012V20.0819C6 20.9044 6 21.3157 6.26407 21.457C6.52814 21.5983 6.87033 21.3702 7.5547 20.914L12 18.0012Z"/>',undo:'<path d="M3 8H15C18.3137 8 21 10.6863 21 14C21 17.3137 18.3137 20 15 20H11"/><path d="M7 4L5.8462 4.87652C3.94873 6.31801 3 7.03875 3 8C3 8.96125 3.94873 9.68199 5.8462 11.1235L7 12"/>',redo:'<path d="M21 8H9C5.68629 8 3 10.6863 3 14C3 17.3137 5.68629 20 9 20H13"/><path d="M17 4L18.1538 4.87652C20.0513 6.31801 21 7.03875 21 8C21 8.96125 20.0513 9.68199 18.1538 11.1235L17 12"/>',before:'<path d="M3.49902 14.9656C4.72475 18.4791 8.06749 21 11.999 21C16.9696 21 20.999 16.9706 20.999 12C20.999 7.02944 16.9696 3 11.999 3C8.29827 3 4.8984 5.6756 3.68943 8.5"/><path d="M11.999 7V12L14.999 14"/><path d="M7.49751 8.74363C7.49751 8.74363 3.81388 9.3026 3.25487 8.7436C2.69585 8.1846 3.25488 4.50098 3.25488 4.50098"/>',copy:'<path d="M7.5 14.5C7.5 11.2002 7.5 9.55025 8.52513 8.52513C9.55025 7.5 11.2002 7.5 14.5 7.5C17.7998 7.5 19.4497 7.5 20.4749 8.52513C21.5 9.55025 21.5 11.2002 21.5 14.5C21.5 17.7998 21.5 19.4497 20.4749 20.4749C19.4497 21.5 17.7998 21.5 14.5 21.5C11.2002 21.5 9.55025 21.5 8.52513 20.4749C7.5 19.4497 7.5 17.7998 7.5 14.5Z"/><path d="M7.5 16.5C6.10355 16.5 5.40533 16.5 4.84402 16.3036C3.83866 15.9518 3.0482 15.1613 2.69641 14.156C2.5 13.5947 2.5 12.8964 2.5 11.5V9.5C2.5 6.20017 2.5 4.55025 3.52513 3.52513C4.55025 2.5 6.20017 2.5 9.5 2.5H11.5C12.8964 2.5 13.5947 2.5 14.156 2.69641C15.1613 3.0482 15.9518 3.83866 16.3036 4.84402C16.5 5.40533 16.5 6.10355 16.5 7.5"/>',check:'<path d="M5 14L8.5 17.5L19 6.5"/>',stop:'<path d="M4 12C4 8.72077 4 7.08116 4.81382 5.91891C5.1149 5.48891 5.48891 5.1149 5.91891 4.81382C7.08116 4 8.72077 4 12 4C15.2792 4 16.9188 4 18.0811 4.81382C18.5111 5.1149 18.8851 5.48891 19.1862 5.91891C20 7.08116 20 8.72077 20 12C20 15.2792 20 16.9188 19.1862 18.0811C18.8851 18.5111 18.5111 18.8851 18.0811 19.1862C16.9188 20 15.2792 20 12 20C8.72077 20 7.08116 20 5.91891 19.1862C5.48891 18.8851 5.1149 18.5111 4.81382 18.0811C4 16.9188 4 15.2792 4 12Z"/>',up:'<path d="M12 5.5V19"/><path d="M18 11C18 11 13.5811 5.00001 12 5C10.4188 4.99999 6 11 6 11"/>',retry:'<path d="M20.4879 15C19.2524 18.4956 15.9187 21 12 21C7.02943 21 3 16.9706 3 12C3 7.02943 7.02943 3 12 3C15.7292 3 18.9286 5.26806 20.2941 8.5"/><path d="M15 9H18C19.4142 9 20.1213 9 20.5607 8.56066C21 8.12132 21 7.41421 21 6V3"/>',steer:'<path d="M13 6H8.5C6.01472 6 4 8.01472 4 10.5C4 12.9853 6.01472 15 8.5 15H20"/><path d="M17 12C17 12 20 14.2095 20 15C20 15.7906 17 18 17 18"/>',play:'<path d="M18.8906 12.846C18.5371 14.189 16.8667 15.138 13.5257 17.0361C10.296 18.8709 8.6812 19.7884 7.37983 19.4196C6.8418 19.2671 6.35159 18.9776 5.95624 18.5787C5 17.6139 5 15.7426 5 12C5 8.2574 5 6.3861 5.95624 5.42132C6.35159 5.02245 6.8418 4.73288 7.37983 4.58042C8.6812 4.21165 10.296 5.12907 13.5257 6.96393C16.8667 8.86197 18.5371 9.811 18.8906 11.154C19.0365 11.7084 19.0365 12.2916 18.8906 12.846Z"/>',x:'<path d="M18.9991 19L5 5.00098"/><path d="M19 5L5.00092 18.999"/>',plus:'<path d="M12.001 4.00101V20.001"/><path d="M20.001 12.001L4.00098 12.001"/>',mic:'<path d="M7 6.5C7 4.01472 9.01472 2 11.5 2C13.9853 2 16 4.01472 16 6.5V11.5C16 13.9853 13.9853 16 11.5 16C9.01472 16 7 13.9853 7 11.5V6.5Z"/><path d="M11.5 19H11.0828C7.57267 19 4.57706 16.4623 4 13M11.5 19H11.9172C15.4273 19 18.4229 16.4623 19 13M11.5 19V22"/>',file:'<path d="M8 17H16"/><path d="M8 13H12"/><path d="M13 2.5V3C13 5.82843 13 7.24264 13.8787 8.12132C14.7574 9 16.1716 9 19 9H19.5M20 10.6569V14C20 17.7712 20 19.6569 18.8284 20.8284C17.6569 22 15.7712 22 12 22C8.22876 22 6.34315 22 5.17157 20.8284C4 19.6569 4 17.7712 4 14V9.45584C4 6.21082 4 4.58831 4.88607 3.48933C5.06508 3.26731 5.26731 3.06508 5.48933 2.88607C6.58831 2 8.21082 2 11.4558 2C12.1614 2 12.5141 2 12.8372 2.11401C12.9044 2.13772 12.9702 2.165 13.0345 2.19575C13.3436 2.34355 13.593 2.593 14.0919 3.09188L18.8284 7.82843C19.4065 8.40649 19.6955 8.69552 19.8478 9.06306C20 9.4306 20 9.83935 20 10.6569Z"/>',clip:'<path d="M9.5 8V14.5C9.5 15.8807 10.6193 17 12 17C13.3807 17 14.5 15.8807 14.5 14.5V6.5C14.5 4.01472 12.4853 2 10 2C7.51472 2 5.5 4.01472 5.5 6.5V15.5C5.5 19.0899 8.41015 22 12 22C15.5899 22 18.5 19.0899 18.5 15.5V6"/>',read:'<path d="M8 17H16"/><path d="M8 13H12"/><path d="M13 2.5V3C13 5.82843 13 7.24264 13.8787 8.12132C14.7574 9 16.1716 9 19 9H19.5M20 10.6569V14C20 17.7712 20 19.6569 18.8284 20.8284C17.6569 22 15.7712 22 12 22C8.22876 22 6.34315 22 5.17157 20.8284C4 19.6569 4 17.7712 4 14V9.45584C4 6.21082 4 4.58831 4.88607 3.48933C5.06508 3.26731 5.26731 3.06508 5.48933 2.88607C6.58831 2 8.21082 2 11.4558 2C12.1614 2 12.5141 2 12.8372 2.11401C12.9044 2.13772 12.9702 2.165 13.0345 2.19575C13.3436 2.34355 13.593 2.593 14.0919 3.09188L18.8284 7.82843C19.4065 8.40649 19.6955 8.69552 19.8478 9.06306C20 9.4306 20 9.83935 20 10.6569Z"/>',edit:'<path d="M16.4249 4.60509L17.4149 3.6151C18.2351 2.79497 19.5648 2.79497 20.3849 3.6151C21.205 4.43524 21.205 5.76493 20.3849 6.58507L19.3949 7.57506M16.4249 4.60509L9.76558 11.2644C9.25807 11.772 8.89804 12.4078 8.72397 13.1041L8 16L10.8959 15.276C11.5922 15.102 12.228 14.7419 12.7356 14.2344L19.3949 7.57506M16.4249 4.60509L19.3949 7.57506"/><path d="M18.9999 13.5C18.9999 16.7875 18.9999 18.4312 18.092 19.5376C17.9258 19.7401 17.7401 19.9258 17.5375 20.092C16.4312 21 14.7874 21 11.4999 21H11C7.22876 21 5.34316 21 4.17159 19.8284C3.00003 18.6569 3 16.7712 3 13V12.5C3 9.21252 3 7.56879 3.90794 6.46244C4.07417 6.2599 4.2599 6.07417 4.46244 5.90794C5.56879 5 7.21252 5 10.5 5"/>',find:'<path d="M17 17L21 21"/><path d="M19 11C19 6.58172 15.4183 3 11 3C6.58172 3 3 6.58172 3 11C3 15.4183 6.58172 19 11 19C15.4183 19 19 15.4183 19 11Z"/>',look:'<path d="M21.544 11.045C21.848 11.4713 22 11.6845 22 12C22 12.3155 21.848 12.5287 21.544 12.955C20.1779 14.8706 16.6892 19 12 19C7.31078 19 3.8221 14.8706 2.45604 12.955C2.15201 12.5287 2 12.3155 2 12C2 11.6845 2.15201 11.4713 2.45604 11.045C3.8221 9.12944 7.31078 5 12 5C16.6892 5 20.1779 9.12944 21.544 11.045Z"/><path d="M15 12C15 10.3431 13.6569 9 12 9C10.3431 9 9 10.3431 9 12C9 13.6569 10.3431 15 12 15C13.6569 15 15 13.6569 15 12Z"/>',run:'<path d="M14 4H10C6.22876 4 4.34315 4 3.17157 5.17157C2 6.34315 2 8.22876 2 12C2 15.7712 2 17.6569 3.17157 18.8284C4.34315 20 6.22876 20 10 20H14C17.7712 20 19.6569 20 20.8284 18.8284C22 17.6569 22 15.7712 22 12C22 8.22876 22 6.34315 20.8284 5.17157C19.6569 4 17.7712 4 14 4Z"/><path d="M7 9L8.83981 10.5858C9.61327 11.2525 10 11.5858 10 12C10 12.4142 9.61327 12.7475 8.83981 13.4142L7 15"/><path d="M13 16H17"/>',think:'<path d="M8 16.4998C6.7725 15.4011 6 13.7768 6 11.9998C6 8.68605 8.68629 5.99976 12 5.99976C15.3137 5.99976 18 8.68605 18 11.9998C18 13.7768 17.2275 15.4011 16 16.4998"/><path d="M12 11.9998V16.4998"/><path d="M9.5 18.9998H14.5"/><path d="M10.5 21.4998H13.5"/><path d="M3.5 11.9998H2.5M5.98438 5.97632L5.23438 5.23022M18.0195 5.97632L18.7695 5.23022M21.5 11.9998H20.5M12 2.49976V3.49976"/>',add:'<path d="M12 3.00005C16.2426 3.00005 18.364 3.00005 19.682 4.31807C21 5.63609 21 7.75741 21 12.0001C21 16.2427 21 18.364 19.682 19.682C18.364 21.0001 16.2426 21.0001 12 21.0001C7.75736 21.0001 5.63604 21.0001 4.31802 19.682C3 18.364 3 16.2427 3 12.0001C3 7.75741 3 5.63609 4.31802 4.31807C5.63604 3.00005 7.75736 3.00005 12 3.00005Z"/><path d="M12.0001 8.00005V12.0001M12.0001 12.0001V16.0001M12.0001 12.0001H16.0001M12.0001 12.0001H8.00006"/>',expand:'<path d="M16.4999 3.26621C17.3443 3.25421 20.1408 2.67328 20.7337 3.26621C21.3266 3.85913 20.7457 6.65559 20.7337 7.5M20.5059 3.49097L13.5021 10.4961"/><path d="M3.26636 16.5001C3.25436 17.3445 2.67343 20.141 3.26636 20.7339C3.85928 21.3268 6.65574 20.7459 7.50015 20.7339M10.502 13.4976L3.49824 20.5027"/>',collapse:'<path d="M6.5023 10.7365C7.34671 10.7485 10.1432 11.3294 10.7361 10.7365C11.329 10.1436 10.7481 7.34708 10.7361 6.50267M13.2685 17.5027C13.2565 16.6583 12.6756 13.8618 13.2685 13.2689C13.8614 12.676 16.6579 13.2569 17.5023 13.2689M20.9991 21.001L13.6102 13.6188M10.3691 10.3763L2.99998 2.99902"/>',resolve:'<path d="M22 12C22 6.47715 17.5228 2 12 2C6.47715 2 2 6.47715 2 12C2 17.5228 6.47715 22 12 22C17.5228 22 22 17.5228 22 12Z"/><path d="M8 12.5L10.5 15L16 9"/>',reopen:'<path d="M11 6H15.5C17.9853 6 20 8.01472 20 10.5C20 12.9853 17.9853 15 15.5 15H4"/><path d="M6.99998 12C6.99998 12 4.00001 14.2095 4 15C3.99999 15.7906 7 18 7 18"/>',more:'<path d="M6.00449 12.5V12M18.0045 12.5V12M12.0045 12.5V12M7.00449 12.5C7.00449 11.9477 6.55677 11.5 6.00449 11.5C5.4522 11.5 5.00449 11.9477 5.00449 12.5C5.00449 13.0523 5.4522 13.5 6.00449 13.5C6.55677 13.5 7.00449 13.0523 7.00449 12.5ZM19.0045 12.5C19.0045 11.9477 18.5568 11.5 18.0045 11.5C17.4522 11.5 17.0045 11.9477 17.0045 12.5C17.0045 13.0523 17.4522 13.5 18.0045 13.5C18.5568 13.5 19.0045 13.0523 19.0045 12.5ZM13.0045 12.5C13.0045 11.9477 12.5568 11.5 12.0045 11.5C11.4522 11.5 11.0045 11.9477 11.0045 12.5C11.0045 13.0523 11.4522 13.5 12.0045 13.5C12.5568 13.5 13.0045 13.0523 13.0045 12.5Z"/>',reply:'<path d="M3.99219 10H11.9922C13.8521 10 14.7821 10 15.5451 10.2044C17.6157 10.7592 19.2329 12.3765 19.7877 14.4471C19.9922 15.2101 19.9922 16.1401 19.9922 18"/><path d="M7.99219 6L6.83839 6.87652C4.94092 8.31801 3.99219 9.03875 3.99219 10C3.99219 10.9612 4.94092 11.682 6.83839 13.1235L7.99219 14"/>',trash:'<path d="M18.8516 16.3743L19.5 6H4.5L5.14839 16.3743C5.315 19.0401 5.39831 20.373 6.26426 21.1865C7.13021 22 8.46571 22 11.1367 22H12.8633C15.5343 22 16.8698 22 17.7357 21.1865C18.6017 20.373 18.685 19.0401 18.8516 16.3743Z"/><path d="M16 6H21M16 6L15.3778 4.34082C15.0007 3.33524 14.8122 2.83245 14.4402 2.50292C14.3213 2.39765 14.1904 2.3069 14.0501 2.2326C13.6109 2 13.074 2 12 2C10.926 2 10.3891 2 9.9499 2.2326C9.8096 2.3069 9.67865 2.39765 9.55982 2.50292C9.18783 2.83245 8.99928 3.33524 8.62219 4.34082L8 6M16 6H8M3 6H8"/><path d="M9.5 11V17M14.5 11V17"/>',phone:'<path d="M13.5 2H10.5C8.14298 2 6.96447 2 6.23223 2.73223C5.5 3.46447 5.5 4.64298 5.5 7V17C5.5 19.357 5.5 20.5355 6.23223 21.2678C6.96447 22 8.14298 22 10.5 22H13.5C15.857 22 17.0355 22 17.7678 21.2678C18.5 20.5355 18.5 19.357 18.5 17V7C18.5 4.64298 18.5 3.46447 17.7678 2.73223C17.0355 2 15.857 2 13.5 2Z"/><path d="M12.125 19H12M12.25 19C12.25 19.1381 12.1381 19.25 12 19.25C11.8619 19.25 11.75 19.1381 11.75 19C11.75 18.8619 11.8619 18.75 12 18.75C12.1381 18.75 12.25 18.8619 12.25 19Z"/>',tablet:'<path d="M14.5 2H9.5C6.67157 2 5.25736 2 4.37868 2.87868C3.5 3.75736 3.5 5.17157 3.5 8V16C3.5 18.8284 3.5 20.2426 4.37868 21.1213C5.25736 22 6.67157 22 9.5 22H14.5C17.3284 22 18.7426 22 19.6213 21.1213C20.5 20.2426 20.5 18.8284 20.5 16V8C20.5 5.17157 20.5 3.75736 19.6213 2.87868C18.7426 2 17.3284 2 14.5 2Z"/><path d="M12.125 19H12M12.25 19C12.25 19.1381 12.1381 19.25 12 19.25C11.8619 19.25 11.75 19.1381 11.75 19C11.75 18.8619 11.8619 18.75 12 18.75C12.1381 18.75 12.25 18.8619 12.25 19Z"/>',desktop:'<path d="M14 21H16M14 21C13.1716 21 12.5 20.3284 12.5 19.5V17L12 17M14 21H10M10 21H8M10 21C10.8284 21 11.5 20.3284 11.5 19.5V17L12 17M12 17V21"/><path d="M16 3H8C5.17157 3 3.75736 3 2.87868 3.87868C2 4.75736 2 6.17157 2 9V11C2 13.8284 2 15.2426 2.87868 16.1213C3.75736 17 5.17157 17 8 17H16C18.8284 17 20.2426 17 21.1213 16.1213C22 15.2426 22 13.8284 22 11V9C22 6.17157 22 4.75736 21.1213 3.87868C20.2426 3 18.8284 3 16 3Z"/>',keyboard:'<path d="M14.5 7H9.5C6.21252 7 4.56878 7 3.46243 7.90796C3.25989 8.07418 3.07418 8.25989 2.90796 8.46243C2 9.56878 2 11.2125 2 14.5C2 17.7875 2 19.4312 2.90796 20.5376C3.07418 20.7401 3.25989 20.9258 3.46243 21.092C4.56878 22 6.21252 22 9.5 22H14.5C17.7875 22 19.4312 22 20.5376 21.092C20.7401 20.9258 20.9258 20.7401 21.092 20.5376C22 19.4312 22 17.7875 22 14.5C22 11.2125 22 9.56878 21.092 8.46243C20.9258 8.25989 20.7401 8.07418 20.5376 7.90796C19.4312 7 17.7875 7 14.5 7Z"/><path d="M12 7V5C12 4.44772 12.4477 4 13 4C13.5523 4 14 3.55228 14 3V2"/><path d="M7 12L8 12"/><path d="M11.5 12L12.5 12"/><path d="M16 12L17 12"/><path d="M7 17L17 17"/>',freeze:'<path d="M14.244 3.00632C13.801 3.40963 12.6212 5.00086 11.991 5C11.3608 4.99909 10.1858 3.40451 9.744 3"/><path d="M14.244 20.9937C13.801 20.5904 12.6212 18.9991 11.991 19C11.3608 19.0009 10.1858 20.5955 9.744 21"/><path d="M20.9077 9.45191C20.337 9.26993 18.3691 9.04383 18.0547 8.4976C17.7404 7.9514 18.5338 6.13651 18.6632 5.55164"/><path d="M5.33024 18.4456C5.45802 17.8603 6.24618 16.043 5.93032 15.4976C5.61445 14.9523 3.64599 14.732 3.07477 14.5516"/><path d="M3.07602 9.45203C3.64679 9.27005 5.61472 9.04395 5.9291 8.49772C6.2434 7.95152 5.44996 6.13663 5.32055 5.55176"/><path d="M18.6529 18.4457C18.5252 17.8604 17.737 16.0431 18.0529 15.4977C18.3687 14.9524 20.3372 14.7321 20.9084 14.5518"/><path d="M15.4581 9.97911L17.994 8.49982M11.9937 8.02071L11.9937 4.99982M17.9937 15.4998L15.458 14.0206M5.99424 15.4998L8.56579 13.9997M11.9937 18.9998L11.9937 15.9789M8.56579 10.0001L5.994 8.49982"/><path d="M15.4957 11.7313C15.4955 10.8861 15.4955 10.4635 15.2945 10.1155C15.0935 9.76744 14.7275 9.55617 13.9955 9.13361L13.5316 8.86583C12.7996 8.44326 12.4336 8.23198 12.0317 8.23199C11.6298 8.23201 11.2638 8.44332 10.5318 8.86593L10.0679 9.13379C9.33581 9.55644 8.96978 9.76777 8.76882 10.1158C8.56786 10.4639 8.56786 10.8866 8.56786 11.7319L8.56786 12.2677C8.56786 13.113 8.56786 13.5356 8.76881 13.8837C8.96976 14.2318 9.33578 14.4431 10.0678 14.8658L10.5319 15.1337C11.264 15.5564 11.63 15.7678 12.032 15.7678C12.4339 15.7678 12.7999 15.5564 13.532 15.1338L13.9958 14.866C14.728 14.4433 15.0941 14.2319 15.295 13.8838C15.496 13.5356 15.4959 13.1129 15.4958 12.2674L15.4957 11.7313Z"/>',stage:'<path d="M15.5 21C16.8956 21 17.5933 21 18.1611 20.8278C19.4395 20.44 20.44 19.4395 20.8278 18.1611C21 17.5933 21 16.8956 21 15.5M21 8.5C21 7.10444 21 6.40666 20.8278 5.83886C20.44 4.56046 19.4395 3.56004 18.1611 3.17224C17.5933 3 16.8956 3 15.5 3M8.5 21C7.10444 21 6.40666 21 5.83886 20.8278C4.56046 20.44 3.56004 19.4395 3.17224 18.1611C3 17.5933 3 16.8956 3 15.5M3 8.5C3 7.10444 3 6.40666 3.17224 5.83886C3.56004 4.56046 4.56046 3.56004 5.83886 3.17224C6.40666 3 7.10444 3 8.5 3"/>',layers:'<path d="M8.64298 3.14559L6.93816 3.93362C4.31272 5.14719 3 5.75397 3 6.75C3 7.74603 4.31272 8.35281 6.93817 9.56638L8.64298 10.3544C10.2952 11.1181 11.1214 11.5 12 11.5C12.8786 11.5 13.7048 11.1181 15.357 10.3544L17.0618 9.56638C19.6873 8.35281 21 7.74603 21 6.75C21 5.75397 19.6873 5.14719 17.0618 3.93362L15.357 3.14559C13.7048 2.38186 12.8786 2 12 2C11.1214 2 10.2952 2.38186 8.64298 3.14559Z"/><path d="M20.788 11.0972C20.9293 11.2959 21 11.5031 21 11.7309C21 12.7127 19.6873 13.3109 17.0618 14.5072L15.357 15.284C13.7048 16.0368 12.8786 16.4133 12 16.4133C11.1214 16.4133 10.2952 16.0368 8.64298 15.284L6.93817 14.5072C4.31272 13.3109 3 12.7127 3 11.7309C3 11.5031 3.07067 11.2959 3.212 11.0972"/><path d="M20.3767 16.2661C20.7922 16.5971 21 16.927 21 17.3176C21 18.2995 19.6873 18.8976 17.0618 20.0939L15.357 20.8707C13.7048 21.6236 12.8786 22 12 22C11.1214 22 10.2952 21.6236 8.64298 20.8707L6.93817 20.0939C4.31272 18.8976 3 18.2995 3 17.3176C3 16.927 3.20778 16.5971 3.62334 16.2661"/>',sun:'<path d="M17 12C17 14.7614 14.7614 17 12 17C9.23858 17 7 14.7614 7 12C7 9.23858 9.23858 7 12 7C14.7614 7 17 9.23858 17 12Z"/><path d="M12 2V3.5M12 20.5V22M19.0708 19.0713L18.0101 18.0106M5.98926 5.98926L4.9286 4.9286M22 12H20.5M3.5 12H2M19.0713 4.92871L18.0106 5.98937M5.98975 18.0107L4.92909 19.0714"/>',moon:'<path d="M21.5 14.0784C20.3003 14.7189 18.9301 15.0821 17.4751 15.0821C12.7491 15.0821 8.91792 11.2509 8.91792 6.52485C8.91792 5.06986 9.28105 3.69968 9.92163 2.5C5.66765 3.49698 2.5 7.31513 2.5 11.8731C2.5 17.1899 6.8101 21.5 12.1269 21.5C16.6849 21.5 20.503 18.3324 21.5 14.0784Z"/>',left:'<path d="M15 6C15 6 9.00001 10.4189 9 12C8.99999 13.5812 15 18 15 18"/>',right:'<path d="M9.00005 6C9.00005 6 15 10.4189 15 12C15 13.5812 9 18 9 18"/>',down:'<path d="M18 9.00005C18 9.00005 13.5811 15 12 15C10.4188 15 6 9 6 9"/>',point:'<path d="M9 14.5V4.5a1.5 1.5 0 0 1 3 0v6"/><path d="M12 10a1.5 1.5 0 0 1 3 0v1.5"/><path d="M15 11a1.5 1.5 0 0 1 3 0v1"/><path d="M18 12a1.5 1.5 0 0 1 3 0v3.5a6.5 6.5 0 0 1-6.5 6.5h-1.6a6 6 0 0 1-4.7-2.3l-3.4-4.4a1.7 1.7 0 0 1 2.6-2.2L9 14.5"/>',hand:'<path d="M18 11V6a2 2 0 0 0-4 0"/><path d="M14 10V4a2 2 0 0 0-4 0v2"/><path d="M10 10.5V6a2 2 0 0 0-4 0v8"/><path d="M18 8a2 2 0 1 1 4 0v6a8 8 0 0 1-8 8h-2c-2.8 0-4.5-.86-6-2.34l-3.6-3.6a2 2 0 0 1 2.83-2.83L7 15"/>'},A=(e,t="")=>`<svg class="hi${t?" "+t:""}" viewBox="0 0 24 24" aria-hidden="true">${Xr[e]||""}</svg>`;document.querySelectorAll("i[data-i]").forEach(e=>{e.outerHTML=A(e.dataset.i)});function ki(e){e?document.documentElement.dataset.theme=e:delete document.documentElement.dataset.theme;const t=e?e==="dark":matchMedia("(prefers-color-scheme: dark)").matches,n=document.getElementById("theme-btn");n&&(n.innerHTML=A(t?"sun":"moon"),n.title=t?"Light mode (\u21E7D)":"Dark mode (\u21E7D)")}function Ts(){const t=(document.documentElement.dataset.theme?document.documentElement.dataset.theme==="dark":matchMedia("(prefers-color-scheme: dark)").matches)?"light":"dark";try{localStorage.setItem("loop.theme",t)}catch{}ki(t)}ki((()=>{try{return localStorage.getItem("loop.theme")}catch{return null}})()),matchMedia("(prefers-color-scheme: dark)").addEventListener("change",()=>ki(document.documentElement.dataset.theme)),document.getElementById("theme-btn").addEventListener("click",Ts);const $i=["#5B6AD0","#D2575C","#3B9A6C","#B98A2C","#8A63C4","#2E93A6","#CC6E3C"],Ur=["#2F5BFF","#E5484D","#1F9D55","#D9A100","#8E4EC6","#0E9AA7","#E8590C"],Zr=e=>{const t=Ur.indexOf(String(e||"").toUpperCase());return t>=0?$i[t]:/^#[0-9a-f]{6}$/i.test(e||"")?e:"#88888F"},As=(e,t,n="",a="")=>`<span class="av${n?" "+n:""}" style="--c:${Zr(t)}">${a?`<img src="${L(a)}" alt="" referrerpolicy="no-referrer">`:L(Zs(e).slice(0,1))}</span>`,Li="#E5484D";let f=null,b={x:120,y:140,z:.5},Ci=!1,K="select",Yt=!1,_=null,j=null,B=null,Ue=null;const Y=new Set;let ya=null,Ze=null;const _s=new Set,D=new Map,ze=new Map,ln=new Map,X=window.LOOP_ADAPTER||null,U=Ae.get("loop.me",null)||{id:ha(),name:"",color:$i[Math.floor(Math.random()*$i.length)]};X?.me&&Object.assign(U,X.me),U.id=U.id||ha();async function w(e,t,n){if(X)return X.api(e,t,n);const a=await fetch(t,{method:e,headers:{"content-type":"application/json"},body:n?JSON.stringify(n):void 0}),i=await a.json().catch(()=>({}));if(!a.ok)throw new Error(i.error||`HTTP ${a.status}`);return i}function y(e,t=2200){const n=m("#toast");n.textContent=e,n.hidden=!1,clearTimeout(y.t),y.t=setTimeout(()=>n.hidden=!0,t)}const $=()=>f?.role==="owner";function Gr(){if(X)return X.connect(ba);const e=new EventSource("/__loop/api/events");e.onmessage=t=>ba(JSON.parse(t.data)),e.onerror=()=>{m("#agent-pill").classList.add("offline")},e.onopen=()=>{m("#agent-pill").classList.remove("offline")}}function Ps(){if(!Ot()&&!se)return location.reload();setTimeout(Ps,1500)}function ba(e){if(e.type==="state"){if(f?.version&&e.state.version&&e.state.version!==f.version){location.reload();return}f?.codeId&&e.state.codeId&&e.state.codeId!==f.codeId&&Ps();const t=!f;f=e.state,t&&al(),wa()}else if(e.type==="patch"){if(!f)return;Object.assign(f,e.set||{}),!se&&(e.lists?.frames?.up?.length>1||e.lists?.sections?.up?.length)&&(xt.classList.add("gliding"),clearTimeout(ba.glide),ba.glide=setTimeout(()=>xt.classList.remove("gliding"),520));const t=$()&&(e.lists?.sections?.up||[]).find(n=>n.optionsFor&&!(f.sections||[]).some(a=>a.id===n.id));for(const[n,a]of Object.entries(e.lists||{})){const i=new Map((f[n]||[]).map(s=>[s.id,s]));for(const s of a.up||[])i.set(s.id,s);f[n]=a.order?a.order.map(s=>i.get(s)).filter(Boolean):(f[n]||[]).map(s=>i.get(s.id))}wa(),t&&Dr(t.id)}else if(e.type==="activity"){if(!f)return;const t=f.live[e.frameId];t&&(t.step=e.step,t.partial=e.partial||"");const n=e.partial==null&&f.comments.find(i=>i.id===e.commentId);if(n&&e.step&&!/^(Writing…|Reading your comment…|Your chat picked this up|Working…)$/.test(e.step)){const i=n.steps||=[],s=i[i.length-1];!/^(Reading the code|Editing|Writing|Setting up an option)$/.test(e.step)&&(!s||s.s!==e.step)&&i.push({t:Date.now(),s:e.step}),wo(e.commentId)}const a=D.get(e.frameId);a&&t&&$e(a.step,e.step),document.querySelectorAll(`[data-step-for="${e.commentId}"]`).forEach(i=>$e(i,e.step)),ro(e.commentId,e.partial||""),Sl(e.frameId)}else if(e.type==="frame-changed"){{const t=D.get(e.frameId);if(t?.quietN>0&&Date.now()<t.quietT&&!e.done&&!e.live){t.quietN--;return}t&&(t.quietN=0)}ul(e.frameId),e.done&&hl(e.frameId,e.status==="done"?f.frames.find(t=>t.id===e.frameId)?.kind==="frozen"?"Changed in the app":"Updated":e.status==="error"?"Failed":"",e.status!=="done"),e.done&&e.status==="done"&&hc(e.frameId),e.done&&(e.status==="done"||e.status==="error")&&ml(e.frameId,e.commentId,e.status)}else if(e.type==="presence"){if(e.id===U.id)return;e.leave?ln.delete(e.id):ln.set(e.id,{...e,t:Date.now()}),Gs(),$a()}}function $e(e,t){e&&e.textContent!==t&&(e.textContent=t)}const $t={at:0,ids:new Set};function Qr(){const e=Ae.get(`loop.seen.${f.name}`,null);e?($t.at=e.at,$t.ids=new Set(e.ids)):($t.at=Date.now(),qs())}function qs(){Ae.set(`loop.seen.${f.name}`,{at:$t.at,ids:[...$t.ids].slice(-400)})}function Jr(e){const t=Xt(e).filter(a=>a.kind!=="note"),n=t[t.length-1];return!!n&&n.status==="done"&&(n.finishedAt||0)>$t.at&&!$t.ids.has(n.id)}function Ds(e){let t=!1;for(const n of Xt(e))n.finishedAt&&!$t.ids.has(n.id)&&($t.ids.add(n.id),t=!0);return t&&qs(),t}const el=[0,8,2,10,12,4,14,6,3,11,1,9,15,7,13,5],Mi=[64,148,255];let va=0,Is=0;const Hs=matchMedia("(prefers-reduced-motion: reduce)");function tl(){va||(va=requestAnimationFrame(zs))}function zs(e){va=0;const t=[...document.querySelectorAll(".area.working")];if(!t.length||(Hs.matches||(va=requestAnimationFrame(zs)),e-Is<33))return;Is=e;const n=Hs.matches?.35:e%5200/5200,a=Math.min(1,n/.8),s=-.2+a*a*(3-2*a)*1.45,o=1,r=.119;for(const c of t){const l=c.getBoundingClientRect();if(l.right<0||l.bottom<0||l.left>innerWidth||l.top>innerHeight||l.width<12||l.height<12)continue;let d=3;for(;l.width/d*(l.height/d)>6e4;)d++;const u=Math.ceil(l.width/d),p=Math.ceil(l.height/d);let h=c.querySelector(":scope > canvas.dz");h||(h=document.createElement("canvas"),h.className="dz",c.appendChild(h)),(h.width!==u||h.height!==p)&&(h.width=u,h.height=p,h.style.setProperty("--cols",u),h.style.setProperty("--rows",p));const g=h.getContext("2d"),v=g.createImageData(u,p),T=v.data,C=Math.hypot(u,p),k=Math.min(u,p),M=Math.max(2.4,k*.05+Math.max(0,k-40)*.03)*(c.classList.contains("whole")?1.5:1),E=M*4.5;for(let N=0;N<p;N++)for(let q=0;q<u;q++){const ne=Math.min(q,N,u-1-q,p-1-N);if(ne>E)continue;const R=Math.hypot(q,N)/C-s,ce=o*Math.exp(-R*R/r)*Math.exp(-ne/M);if(ce>(el[(N&3)*4+(q&3)]+.5)/16){const rn=(N*u+q)*4;T[rn]=Mi[0],T[rn+1]=Mi[1],T[rn+2]=Mi[2],T[rn+3]=255*(.3+.7*ce)|0}}g.putImageData(v,0,0)}}const nl='<svg viewBox="0 0 24 24" aria-hidden="true"><path pathLength="14" d="M5 14L8.5 17.5L19 6.5"/></svg>';function al(){setTimeout(sr,400),Qr();const e=Ae.get(`loop.view.${f.name}`,null);e?(b=e,ie()):Oe(!1),Ci=!0,$()?U.name=f.hostName||U.name||"You":U.name||Ro(),Ae.set("loop.me",U),document.body.classList.toggle("guest",!$()),m("#new-frame-btn").hidden=!$(),m("#section-btn").hidden=!$(),document.querySelector("#toolbar .tb-sep").hidden=!$()}function ie(){b.z>=.02||(b.z=.04),Bs=performance.now(),xt.style.transform=`translate(${b.x}px, ${b.y}px) scale(${b.z})`,xt.style.setProperty("--z",b.z),ie.lastZ!==b.z&&(ie.lastZ=b.z,xt.style.willChange!=="transform"&&(xt.style.willChange="transform"),clearTimeout(ie.crisp),ie.crisp=setTimeout(()=>{xt.style.willChange="auto"},160));const e=Math.min(1.5,Math.max(1,Math.pow(b.z,.42)));document.documentElement.style.setProperty("--lz",e.toFixed(3)),document.body.classList.toggle("zoom-tiny",b.z<.12);const t=`${Math.round(b.z*100)}%`,n=m("#zoom-level");if(n.textContent!==t){n.textContent=t;const a=m("#zoom");a.classList.add("awake"),clearTimeout(ie.zt),ie.zt=setTimeout(()=>a.classList.remove("awake"),1200)}Hn(),cn(),_e(),fa(),ye&&Re(),V.hidden=!0,Ci&&f&&(clearTimeout(ie.t),ie.t=setTimeout(()=>Ae.set(`loop.view.${f.name}`,b),300)),f&&ie.z!==b.z&&(ie.z=b.z,ie.lq||(ie.lq=requestAnimationFrame(()=>{ie.lq=0,Hr()})),clearTimeout(ie.pt),ie.pt=setTimeout(()=>{for(const a of f.frames)ut(a.id)},120))}function Lt(e,t,n){const a=Math.min(4,Math.max(.04,b.z*n));b.x=e-(e-b.x)*(a/b.z),b.y=t-(t-b.y)*(a/b.z),b.z=a,Si()}let Ei=!1;function Si(){Ei||(Ei=!0,requestAnimationFrame(()=>{Ei=!1,ie()}))}function Os(e,t,n){e.preventDefault();const a=Math.max(-30,Math.min(30,e.deltaMode===1?e.deltaY*16:e.deltaY));Lt(t,n,Math.exp(-a*(e.ctrlKey&&!e.metaKey?.01:.004)))}const re=(e,t)=>({x:(e-b.x)/b.z,y:(t-b.y)/b.z});function Oe(e=!0,t){const n=(f?.frames||[]).filter(r=>!t||t.includes(r.id));if(!n.length)return b={x:innerWidth/2,y:innerHeight/2,z:.5},ie();const a=Math.min(...n.map(r=>r.x)),i=Math.min(...n.map(r=>r.y)),s=Math.max(...n.map(r=>r.x+r.w)),o=Math.max(...n.map(r=>r.y+r.h));return Rs({x:a,y:i,w:s-a,h:o-i},1,e)}function Rs(e,t=1,n=!0){const a=e.x,i=e.y,s=e.x+Math.max(1,e.w),o=e.y+Math.max(1,e.h),r=80,c=110,l=110,d=Math.max(.04,Math.min(t,(innerWidth-r*2)/(s-a),(innerHeight-c-l)/(o-i))),u={z:d,x:(innerWidth-(s-a)*d)/2-a*d,y:c+(innerHeight-c-l-(o-i)*d)/2-i*d};if(!n)return b=u,ie();const p={...b},h=performance.now(),g=v=>{const T=Math.min(1,(v-h)/280),C=1-Math.pow(1-T,3);b={x:p.x+(u.x-p.x)*C,y:p.y+(u.y-p.y)*C,z:p.z+(u.z-p.z)*C},ie(),T<1&&requestAnimationFrame(g)};requestAnimationFrame(g)}function wa(){if(!f)return;m("#canvas-name").querySelector("input")||(m("#canvas-name").textContent=f.name),m("#canvas-name").classList.toggle("editable",$()&&!X),m("#history-btn").hidden=!$()||!!X,document.title=`${f.name} \u2014 Loop`,m("#empty").hidden=f.frames.length>0,m("#empty").classList.toggle("guest",!$()),$()&&!X&&f.hostName&&U.name!==f.hostName&&Ci&&(U.name=f.hostName,Ae.set("loop.me",U)),vl(),$a();const e=new Set(f.frames.map(t=>t.id));for(const[t,n]of D)e.has(t)||(n.el.contains(H)&&te(),n.el.remove(),D.delete(t));for(const t of f.frames)J(t);f.sections||=[],wt(),_&&!e.has(_)&&(_=null),qt(),Nn(),j&&Ia(),ye&&Ml(),B&&B.frameId!==le&&!e.has(B.frameId)&&te();for(const t of[...Y])e.has(t)||Y.delete(t);Fe(),oa(),Ul(),Kl(),S&&da(),F&&Fr(),P&&(Pn(),pa()),Hn(),ui()}function Dn(e){try{const t=e.iframe.contentWindow.location;return t.href==="about:blank"?null:t.pathname+t.search+t.hash}catch{return null}}let Ti=0,Ai=0,In=null;const il=/[?&]nosleep\b/.test(location.search);let Ns=new Set;function sl(e){const t=jt(e),n=Math.max(0,Math.min(t.l+t.w,innerWidth)-Math.max(t.l,0)),a=Math.max(0,Math.min(t.t+t.h,innerHeight)-Math.max(t.t,0));return{shown:n*a,of:t.w*t.h,r:t}}function ol(){const e=new Set;if(!f)return e;if(S)return e.add(S.fid),e;const t=[];for(const n of f.frames){const{shown:a,of:i,r:s}=sl(n);if(!(a<400||a<i*.1)){if(il||n.id===In||n.id===_||n.id===fe||x?.frameId===n.id||xe?.fid===n.id||Y.has(n.id)){e.add(n.id);continue}(a>=innerWidth*innerHeight*.25||a>=i*.5&&(s.h>=innerHeight*.55||s.w>=innerWidth*.55))&&t.push([n.id,a])}}return t.sort((n,a)=>a[1]-n[1]).slice(0,2).forEach(([n])=>e.add(n)),e}const rl=e=>Ns.has(e);function ll(e,t,n){const a=e.requestAnimationFrame.bind(e),i=new Map;let s=0;t.waking=Date.now(),e.requestAnimationFrame=r=>{if(!t.asleep)return a(r);const c=-++s;return i.set(c,r),c};const o=e.cancelAnimationFrame.bind(e);e.cancelAnimationFrame=r=>r<0?i.delete(r):o(r),t.sleepTo=r=>{if(t.asleep!==r){t.asleep=r;try{const c=e.document;let l=c.getElementById("__loop-sleep");r&&!l&&(l=c.createElement("style"),l.id="__loop-sleep",l.textContent="*, *::before, *::after { animation-play-state: paused !important; }",(c.head||c.documentElement).appendChild(l)),!r&&l&&l.remove(),c.querySelectorAll("video").forEach(d=>{try{r?(d._loopPlay=!d.paused,d.pause()):d._loopPlay&&d.play()}catch{}})}catch{}if(!r){const c=[...i.values()];i.clear(),c.forEach(l=>a(l))}}},t.asleep=!1,cn()}function cn(){Ai||!f||(Ai=setTimeout(()=>{Ai=0,Ns=ol();for(const[e,t]of D){if(!t.sleepTo)continue;const n=Date.now()-(t.waking||0)<700;t.sleepTo(!n&&!rl(e))}},120))}setInterval(()=>cn(),1500);function Hn(){Ti||!f||(Ti=requestAnimationFrame(()=>{Ti=0;const e=innerWidth,t=innerHeight,n=f.frames.length>6,a=[];for(const i of f.frames){const s=D.get(i.id);if(!s?.iframe)continue;const o=De(i),r=b.z,c=b.x+o.x*r,l=b.y+o.y*r,d=o.w*r,u=o.h*r,p=g=>Math.max(0,c-e-g,-(c+d)-g,l-t-g,-(l+u)-g),h=!n||f.live[o.id]||_===o.id||fe===o.id||S?.fid===o.id||Y.has(o.id);if(s.el.classList.toggle("narrow",d<200),s.el.classList.toggle("far",Tn(i)),f.live[o.id]){const g=Math.max(0,Math.min(c+d,e)-Math.max(c,0)),v=Math.max(0,Math.min(l+u,t)-Math.max(l,0)),T=g*v>=e*t*.2&&g*v>=d*u*.5;s.wedge||(s.wedge=document.createElement("i"),s.wedge.className="work-edge",s.el.appendChild(s.wedge)),s.el.classList.toggle("work-far",!T)}else s.el.classList.contains("work-far")&&s.el.classList.remove("work-far");s.parked?(h||p(e*.5)===0&&Math.max(d,u)>160)&&a.push({fe:s,keep:h,on:p(0)===0,d:Math.hypot(c+d/2-e/2,l+u/2-t/2)}):!h&&(p(e)>0||Math.max(d,u)<110)&&(s.resume=Dn(s),s.parked=!0,s.el.classList.add("parked"),s.iframe.src="about:blank"),s.parked&&Ws(s)}if(a.length){const i=performance.now()-Bs>140;a.sort((o,r)=>r.keep-o.keep||r.on-o.on||o.d-r.d);const s=i?a.slice(0,2):a.filter(o=>o.keep).slice(0,2);for(const{fe:o}of s)o.parked=!1,o.el.classList.remove("parked"),o.el.classList.add("waking"),clearTimeout(o.wakeT),o.wakeT=setTimeout(()=>Fs(o),8e3),o.iframe.src=o.resume||o.iframe.dataset.src||"about:blank",o.resume=null;a.length>s.length&&setTimeout(Hn,i?90:160)}}))}let Bs=0;function Fs(e){clearTimeout(e.wakeT),requestAnimationFrame(()=>requestAnimationFrame(()=>e.el.classList.remove("waking")))}function Ws(e){if(X)return;const t=e.hint.querySelector("img"),n=`/__loop/poster/${e.id}?v=${e.rev||0}`;if(t.dataset.src===n)return;t.dataset.src=n;const a=new Image;a.onload=()=>{t.dataset.src===n&&(t.src=n,t.hidden=!1,e.hint.classList.add("has-pic"))},a.src=n}function De(e){return{...e,...ze.get(e.id)||{}}}function cl(e){const t=document.createElement("div");t.className="frame",t.dataset.id=e.id,t.innerHTML=`
|
|
1
|
+
const m=e=>document.querySelector(e),q=m("#viewport"),Tt=m("#world"),Gl=m("#frames"),At=m("#ink"),Xs=m("#cursors"),G=m("#hover-box"),H=m("#composer"),j=m("#composer-input"),R=m("#thread"),C=e=>String(e??"").replace(/[&<>"']/g,t=>({"&":"&","<":"<",">":">",'"':""","'":"'"})[t]),qa=()=>Math.random().toString(36).slice(2,10),Ia=()=>(qa()+qa()).slice(0,8),K={get(e,t){try{const n=localStorage.getItem(e);return n==null?t:JSON.parse(n)}catch{return t}},set(e,t){try{localStorage.setItem(e,JSON.stringify(t))}catch{}}},Zl={select:'<path d="M9.80282 4.62973L15.8364 6.99069C19.3164 8.35243 21.0564 9.03329 20.9987 10.1133C20.941 11.1934 19.1251 11.6886 15.4933 12.6791C14.412 12.974 13.8713 13.1215 13.4964 13.4963C13.1215 13.8712 12.9741 14.4119 12.6791 15.4933C11.6887 19.125 11.1934 20.9409 10.1134 20.9986C9.03335 21.0563 8.35249 19.3163 6.99075 15.8363L4.62979 9.80276C3.20411 6.15934 2.49127 4.33764 3.41448 3.41442C4.3377 2.49121 6.15941 3.20405 9.80282 4.62973Z"/>',pen:'<path d="M3.49977 18.9853V20.5H5.01449C6.24074 20.5 6.85387 20.5 7.40518 20.2716C7.9565 20.0433 8.39004 19.6097 9.25713 18.7426L19.1211 8.87868C20.0037 7.99612 20.4449 7.55483 20.4937 7.01325C20.5018 6.92372 20.5018 6.83364 20.4937 6.74411C20.4449 6.20253 20.0037 5.76124 19.1211 4.87868C18.2385 3.99612 17.7972 3.55483 17.2557 3.50605C17.1661 3.49798 17.0761 3.49798 16.9865 3.50605C16.4449 3.55483 16.0037 3.99612 15.1211 4.87868L5.25713 14.7426C4.39004 15.6097 3.9565 16.0433 3.72813 16.5946C3.49977 17.1459 3.49977 17.759 3.49977 18.9853Z"/><path d="M13.5 6.5L17.5 10.5"/>',erase:'<path d="M8.73792 7.78021L4.84693 11.7574C3.67722 12.953 3.09236 13.5508 3.01263 14.2802C2.99579 14.4343 2.99579 14.5899 3.01263 14.744C3.09236 15.4733 3.67722 16.0711 4.84693 17.2668L4.99601 17.4191C5.62049 18.0575 5.93274 18.3766 6.30638 18.5911C6.5236 18.7157 6.75482 18.8134 6.99505 18.882C7.40827 19 7.85149 19 8.73792 19C9.62436 19 10.0676 19 10.4808 18.882C10.721 18.8134 10.9522 18.7157 11.1695 18.5911C11.5431 18.3766 11.8554 18.0575 12.4798 17.4191L15.3239 14.5121M8.73792 7.78021L12.3199 4.12313C13.7065 2.70754 14.3997 1.99974 15.2627 2C16.1256 2.00026 16.8185 2.70846 18.2042 4.12487L18.9473 4.8845C20.3159 6.28342 21.0002 6.98288 21 7.85008C20.9997 8.71728 20.315 9.41633 18.9456 10.8144L15.3239 14.5121M8.73792 7.78021L15.3239 14.5121"/><path d="M10 22L21 22"/>',comment:'<path d="M12 18.0012H15C18.2998 18.0012 19.9497 18.0012 20.9749 16.9761C22 15.951 22 14.3011 22 11.0012V9.50122C22 6.20139 22 4.55147 20.9749 3.52635C19.9497 2.50122 18.2998 2.50122 15 2.50122H9C5.70017 2.50122 4.05025 2.50122 3.02513 3.52635C2 4.55147 2 6.20139 2 9.50122V14.0012C2 14.4656 2 14.6978 2.02201 14.8931C2.20484 16.5158 3.48545 17.7964 5.10812 17.9792C5.30344 18.0012 5.53563 18.0012 6 18.0012V20.0819C6 20.9044 6 21.3157 6.26407 21.457C6.52814 21.5983 6.87033 21.3702 7.5547 20.914L12 18.0012Z"/>',frame:'<path d="M2 6H22M2 18H22"/><path d="M6 22L6 2M18 22V2"/>',comments:'<path d="M8 13.0012H16M8 8.00122H12"/><path d="M12 18.0012H15C18.2998 18.0012 19.9497 18.0012 20.9749 16.9761C22 15.951 22 14.3011 22 11.0012V9.50122C22 6.20139 22 4.55147 20.9749 3.52635C19.9497 2.50122 18.2998 2.50122 15 2.50122H9C5.70017 2.50122 4.05025 2.50122 3.02513 3.52635C2 4.55147 2 6.20139 2 9.50122V14.0012C2 14.4656 2 14.6978 2.02201 14.8931C2.20484 16.5158 3.48545 17.7964 5.10812 17.9792C5.30344 18.0012 5.53563 18.0012 6 18.0012V20.0819C6 20.9044 6 21.3157 6.26407 21.457C6.52814 21.5983 6.87033 21.3702 7.5547 20.914L12 18.0012Z"/>',undo:'<path d="M3 8H15C18.3137 8 21 10.6863 21 14C21 17.3137 18.3137 20 15 20H11"/><path d="M7 4L5.8462 4.87652C3.94873 6.31801 3 7.03875 3 8C3 8.96125 3.94873 9.68199 5.8462 11.1235L7 12"/>',redo:'<path d="M21 8H9C5.68629 8 3 10.6863 3 14C3 17.3137 5.68629 20 9 20H13"/><path d="M17 4L18.1538 4.87652C20.0513 6.31801 21 7.03875 21 8C21 8.96125 20.0513 9.68199 18.1538 11.1235L17 12"/>',before:'<path d="M3.49902 14.9656C4.72475 18.4791 8.06749 21 11.999 21C16.9696 21 20.999 16.9706 20.999 12C20.999 7.02944 16.9696 3 11.999 3C8.29827 3 4.8984 5.6756 3.68943 8.5"/><path d="M11.999 7V12L14.999 14"/><path d="M7.49751 8.74363C7.49751 8.74363 3.81388 9.3026 3.25487 8.7436C2.69585 8.1846 3.25488 4.50098 3.25488 4.50098"/>',copy:'<path d="M7.5 14.5C7.5 11.2002 7.5 9.55025 8.52513 8.52513C9.55025 7.5 11.2002 7.5 14.5 7.5C17.7998 7.5 19.4497 7.5 20.4749 8.52513C21.5 9.55025 21.5 11.2002 21.5 14.5C21.5 17.7998 21.5 19.4497 20.4749 20.4749C19.4497 21.5 17.7998 21.5 14.5 21.5C11.2002 21.5 9.55025 21.5 8.52513 20.4749C7.5 19.4497 7.5 17.7998 7.5 14.5Z"/><path d="M7.5 16.5C6.10355 16.5 5.40533 16.5 4.84402 16.3036C3.83866 15.9518 3.0482 15.1613 2.69641 14.156C2.5 13.5947 2.5 12.8964 2.5 11.5V9.5C2.5 6.20017 2.5 4.55025 3.52513 3.52513C4.55025 2.5 6.20017 2.5 9.5 2.5H11.5C12.8964 2.5 13.5947 2.5 14.156 2.69641C15.1613 3.0482 15.9518 3.83866 16.3036 4.84402C16.5 5.40533 16.5 6.10355 16.5 7.5"/>',check:'<path d="M5 14L8.5 17.5L19 6.5"/>',stop:'<path d="M4 12C4 8.72077 4 7.08116 4.81382 5.91891C5.1149 5.48891 5.48891 5.1149 5.91891 4.81382C7.08116 4 8.72077 4 12 4C15.2792 4 16.9188 4 18.0811 4.81382C18.5111 5.1149 18.8851 5.48891 19.1862 5.91891C20 7.08116 20 8.72077 20 12C20 15.2792 20 16.9188 19.1862 18.0811C18.8851 18.5111 18.5111 18.8851 18.0811 19.1862C16.9188 20 15.2792 20 12 20C8.72077 20 7.08116 20 5.91891 19.1862C5.48891 18.8851 5.1149 18.5111 4.81382 18.0811C4 16.9188 4 15.2792 4 12Z"/>',up:'<path d="M12 5.5V19"/><path d="M18 11C18 11 13.5811 5.00001 12 5C10.4188 4.99999 6 11 6 11"/>',retry:'<path d="M20.4879 15C19.2524 18.4956 15.9187 21 12 21C7.02943 21 3 16.9706 3 12C3 7.02943 7.02943 3 12 3C15.7292 3 18.9286 5.26806 20.2941 8.5"/><path d="M15 9H18C19.4142 9 20.1213 9 20.5607 8.56066C21 8.12132 21 7.41421 21 6V3"/>',steer:'<path d="M13 6H8.5C6.01472 6 4 8.01472 4 10.5C4 12.9853 6.01472 15 8.5 15H20"/><path d="M17 12C17 12 20 14.2095 20 15C20 15.7906 17 18 17 18"/>',play:'<path d="M18.8906 12.846C18.5371 14.189 16.8667 15.138 13.5257 17.0361C10.296 18.8709 8.6812 19.7884 7.37983 19.4196C6.8418 19.2671 6.35159 18.9776 5.95624 18.5787C5 17.6139 5 15.7426 5 12C5 8.2574 5 6.3861 5.95624 5.42132C6.35159 5.02245 6.8418 4.73288 7.37983 4.58042C8.6812 4.21165 10.296 5.12907 13.5257 6.96393C16.8667 8.86197 18.5371 9.811 18.8906 11.154C19.0365 11.7084 19.0365 12.2916 18.8906 12.846Z"/>',x:'<path d="M18.9991 19L5 5.00098"/><path d="M19 5L5.00092 18.999"/>',plus:'<path d="M12.001 4.00101V20.001"/><path d="M20.001 12.001L4.00098 12.001"/>',mic:'<path d="M7 6.5C7 4.01472 9.01472 2 11.5 2C13.9853 2 16 4.01472 16 6.5V11.5C16 13.9853 13.9853 16 11.5 16C9.01472 16 7 13.9853 7 11.5V6.5Z"/><path d="M11.5 19H11.0828C7.57267 19 4.57706 16.4623 4 13M11.5 19H11.9172C15.4273 19 18.4229 16.4623 19 13M11.5 19V22"/>',file:'<path d="M8 17H16"/><path d="M8 13H12"/><path d="M13 2.5V3C13 5.82843 13 7.24264 13.8787 8.12132C14.7574 9 16.1716 9 19 9H19.5M20 10.6569V14C20 17.7712 20 19.6569 18.8284 20.8284C17.6569 22 15.7712 22 12 22C8.22876 22 6.34315 22 5.17157 20.8284C4 19.6569 4 17.7712 4 14V9.45584C4 6.21082 4 4.58831 4.88607 3.48933C5.06508 3.26731 5.26731 3.06508 5.48933 2.88607C6.58831 2 8.21082 2 11.4558 2C12.1614 2 12.5141 2 12.8372 2.11401C12.9044 2.13772 12.9702 2.165 13.0345 2.19575C13.3436 2.34355 13.593 2.593 14.0919 3.09188L18.8284 7.82843C19.4065 8.40649 19.6955 8.69552 19.8478 9.06306C20 9.4306 20 9.83935 20 10.6569Z"/>',clip:'<path d="M9.5 8V14.5C9.5 15.8807 10.6193 17 12 17C13.3807 17 14.5 15.8807 14.5 14.5V6.5C14.5 4.01472 12.4853 2 10 2C7.51472 2 5.5 4.01472 5.5 6.5V15.5C5.5 19.0899 8.41015 22 12 22C15.5899 22 18.5 19.0899 18.5 15.5V6"/>',read:'<path d="M8 17H16"/><path d="M8 13H12"/><path d="M13 2.5V3C13 5.82843 13 7.24264 13.8787 8.12132C14.7574 9 16.1716 9 19 9H19.5M20 10.6569V14C20 17.7712 20 19.6569 18.8284 20.8284C17.6569 22 15.7712 22 12 22C8.22876 22 6.34315 22 5.17157 20.8284C4 19.6569 4 17.7712 4 14V9.45584C4 6.21082 4 4.58831 4.88607 3.48933C5.06508 3.26731 5.26731 3.06508 5.48933 2.88607C6.58831 2 8.21082 2 11.4558 2C12.1614 2 12.5141 2 12.8372 2.11401C12.9044 2.13772 12.9702 2.165 13.0345 2.19575C13.3436 2.34355 13.593 2.593 14.0919 3.09188L18.8284 7.82843C19.4065 8.40649 19.6955 8.69552 19.8478 9.06306C20 9.4306 20 9.83935 20 10.6569Z"/>',edit:'<path d="M16.4249 4.60509L17.4149 3.6151C18.2351 2.79497 19.5648 2.79497 20.3849 3.6151C21.205 4.43524 21.205 5.76493 20.3849 6.58507L19.3949 7.57506M16.4249 4.60509L9.76558 11.2644C9.25807 11.772 8.89804 12.4078 8.72397 13.1041L8 16L10.8959 15.276C11.5922 15.102 12.228 14.7419 12.7356 14.2344L19.3949 7.57506M16.4249 4.60509L19.3949 7.57506"/><path d="M18.9999 13.5C18.9999 16.7875 18.9999 18.4312 18.092 19.5376C17.9258 19.7401 17.7401 19.9258 17.5375 20.092C16.4312 21 14.7874 21 11.4999 21H11C7.22876 21 5.34316 21 4.17159 19.8284C3.00003 18.6569 3 16.7712 3 13V12.5C3 9.21252 3 7.56879 3.90794 6.46244C4.07417 6.2599 4.2599 6.07417 4.46244 5.90794C5.56879 5 7.21252 5 10.5 5"/>',find:'<path d="M17 17L21 21"/><path d="M19 11C19 6.58172 15.4183 3 11 3C6.58172 3 3 6.58172 3 11C3 15.4183 6.58172 19 11 19C15.4183 19 19 15.4183 19 11Z"/>',look:'<path d="M21.544 11.045C21.848 11.4713 22 11.6845 22 12C22 12.3155 21.848 12.5287 21.544 12.955C20.1779 14.8706 16.6892 19 12 19C7.31078 19 3.8221 14.8706 2.45604 12.955C2.15201 12.5287 2 12.3155 2 12C2 11.6845 2.15201 11.4713 2.45604 11.045C3.8221 9.12944 7.31078 5 12 5C16.6892 5 20.1779 9.12944 21.544 11.045Z"/><path d="M15 12C15 10.3431 13.6569 9 12 9C10.3431 9 9 10.3431 9 12C9 13.6569 10.3431 15 12 15C13.6569 15 15 13.6569 15 12Z"/>',run:'<path d="M14 4H10C6.22876 4 4.34315 4 3.17157 5.17157C2 6.34315 2 8.22876 2 12C2 15.7712 2 17.6569 3.17157 18.8284C4.34315 20 6.22876 20 10 20H14C17.7712 20 19.6569 20 20.8284 18.8284C22 17.6569 22 15.7712 22 12C22 8.22876 22 6.34315 20.8284 5.17157C19.6569 4 17.7712 4 14 4Z"/><path d="M7 9L8.83981 10.5858C9.61327 11.2525 10 11.5858 10 12C10 12.4142 9.61327 12.7475 8.83981 13.4142L7 15"/><path d="M13 16H17"/>',think:'<path d="M8 16.4998C6.7725 15.4011 6 13.7768 6 11.9998C6 8.68605 8.68629 5.99976 12 5.99976C15.3137 5.99976 18 8.68605 18 11.9998C18 13.7768 17.2275 15.4011 16 16.4998"/><path d="M12 11.9998V16.4998"/><path d="M9.5 18.9998H14.5"/><path d="M10.5 21.4998H13.5"/><path d="M3.5 11.9998H2.5M5.98438 5.97632L5.23438 5.23022M18.0195 5.97632L18.7695 5.23022M21.5 11.9998H20.5M12 2.49976V3.49976"/>',add:'<path d="M12 3.00005C16.2426 3.00005 18.364 3.00005 19.682 4.31807C21 5.63609 21 7.75741 21 12.0001C21 16.2427 21 18.364 19.682 19.682C18.364 21.0001 16.2426 21.0001 12 21.0001C7.75736 21.0001 5.63604 21.0001 4.31802 19.682C3 18.364 3 16.2427 3 12.0001C3 7.75741 3 5.63609 4.31802 4.31807C5.63604 3.00005 7.75736 3.00005 12 3.00005Z"/><path d="M12.0001 8.00005V12.0001M12.0001 12.0001V16.0001M12.0001 12.0001H16.0001M12.0001 12.0001H8.00006"/>',expand:'<path d="M16.4999 3.26621C17.3443 3.25421 20.1408 2.67328 20.7337 3.26621C21.3266 3.85913 20.7457 6.65559 20.7337 7.5M20.5059 3.49097L13.5021 10.4961"/><path d="M3.26636 16.5001C3.25436 17.3445 2.67343 20.141 3.26636 20.7339C3.85928 21.3268 6.65574 20.7459 7.50015 20.7339M10.502 13.4976L3.49824 20.5027"/>',collapse:'<path d="M6.5023 10.7365C7.34671 10.7485 10.1432 11.3294 10.7361 10.7365C11.329 10.1436 10.7481 7.34708 10.7361 6.50267M13.2685 17.5027C13.2565 16.6583 12.6756 13.8618 13.2685 13.2689C13.8614 12.676 16.6579 13.2569 17.5023 13.2689M20.9991 21.001L13.6102 13.6188M10.3691 10.3763L2.99998 2.99902"/>',resolve:'<path d="M22 12C22 6.47715 17.5228 2 12 2C6.47715 2 2 6.47715 2 12C2 17.5228 6.47715 22 12 22C17.5228 22 22 17.5228 22 12Z"/><path d="M8 12.5L10.5 15L16 9"/>',reopen:'<path d="M11 6H15.5C17.9853 6 20 8.01472 20 10.5C20 12.9853 17.9853 15 15.5 15H4"/><path d="M6.99998 12C6.99998 12 4.00001 14.2095 4 15C3.99999 15.7906 7 18 7 18"/>',more:'<path d="M6.00449 12.5V12M18.0045 12.5V12M12.0045 12.5V12M7.00449 12.5C7.00449 11.9477 6.55677 11.5 6.00449 11.5C5.4522 11.5 5.00449 11.9477 5.00449 12.5C5.00449 13.0523 5.4522 13.5 6.00449 13.5C6.55677 13.5 7.00449 13.0523 7.00449 12.5ZM19.0045 12.5C19.0045 11.9477 18.5568 11.5 18.0045 11.5C17.4522 11.5 17.0045 11.9477 17.0045 12.5C17.0045 13.0523 17.4522 13.5 18.0045 13.5C18.5568 13.5 19.0045 13.0523 19.0045 12.5ZM13.0045 12.5C13.0045 11.9477 12.5568 11.5 12.0045 11.5C11.4522 11.5 11.0045 11.9477 11.0045 12.5C11.0045 13.0523 11.4522 13.5 12.0045 13.5C12.5568 13.5 13.0045 13.0523 13.0045 12.5Z"/>',reply:'<path d="M3.99219 10H11.9922C13.8521 10 14.7821 10 15.5451 10.2044C17.6157 10.7592 19.2329 12.3765 19.7877 14.4471C19.9922 15.2101 19.9922 16.1401 19.9922 18"/><path d="M7.99219 6L6.83839 6.87652C4.94092 8.31801 3.99219 9.03875 3.99219 10C3.99219 10.9612 4.94092 11.682 6.83839 13.1235L7.99219 14"/>',trash:'<path d="M18.8516 16.3743L19.5 6H4.5L5.14839 16.3743C5.315 19.0401 5.39831 20.373 6.26426 21.1865C7.13021 22 8.46571 22 11.1367 22H12.8633C15.5343 22 16.8698 22 17.7357 21.1865C18.6017 20.373 18.685 19.0401 18.8516 16.3743Z"/><path d="M16 6H21M16 6L15.3778 4.34082C15.0007 3.33524 14.8122 2.83245 14.4402 2.50292C14.3213 2.39765 14.1904 2.3069 14.0501 2.2326C13.6109 2 13.074 2 12 2C10.926 2 10.3891 2 9.9499 2.2326C9.8096 2.3069 9.67865 2.39765 9.55982 2.50292C9.18783 2.83245 8.99928 3.33524 8.62219 4.34082L8 6M16 6H8M3 6H8"/><path d="M9.5 11V17M14.5 11V17"/>',phone:'<path d="M13.5 2H10.5C8.14298 2 6.96447 2 6.23223 2.73223C5.5 3.46447 5.5 4.64298 5.5 7V17C5.5 19.357 5.5 20.5355 6.23223 21.2678C6.96447 22 8.14298 22 10.5 22H13.5C15.857 22 17.0355 22 17.7678 21.2678C18.5 20.5355 18.5 19.357 18.5 17V7C18.5 4.64298 18.5 3.46447 17.7678 2.73223C17.0355 2 15.857 2 13.5 2Z"/><path d="M12.125 19H12M12.25 19C12.25 19.1381 12.1381 19.25 12 19.25C11.8619 19.25 11.75 19.1381 11.75 19C11.75 18.8619 11.8619 18.75 12 18.75C12.1381 18.75 12.25 18.8619 12.25 19Z"/>',tablet:'<path d="M14.5 2H9.5C6.67157 2 5.25736 2 4.37868 2.87868C3.5 3.75736 3.5 5.17157 3.5 8V16C3.5 18.8284 3.5 20.2426 4.37868 21.1213C5.25736 22 6.67157 22 9.5 22H14.5C17.3284 22 18.7426 22 19.6213 21.1213C20.5 20.2426 20.5 18.8284 20.5 16V8C20.5 5.17157 20.5 3.75736 19.6213 2.87868C18.7426 2 17.3284 2 14.5 2Z"/><path d="M12.125 19H12M12.25 19C12.25 19.1381 12.1381 19.25 12 19.25C11.8619 19.25 11.75 19.1381 11.75 19C11.75 18.8619 11.8619 18.75 12 18.75C12.1381 18.75 12.25 18.8619 12.25 19Z"/>',desktop:'<path d="M14 21H16M14 21C13.1716 21 12.5 20.3284 12.5 19.5V17L12 17M14 21H10M10 21H8M10 21C10.8284 21 11.5 20.3284 11.5 19.5V17L12 17M12 17V21"/><path d="M16 3H8C5.17157 3 3.75736 3 2.87868 3.87868C2 4.75736 2 6.17157 2 9V11C2 13.8284 2 15.2426 2.87868 16.1213C3.75736 17 5.17157 17 8 17H16C18.8284 17 20.2426 17 21.1213 16.1213C22 15.2426 22 13.8284 22 11V9C22 6.17157 22 4.75736 21.1213 3.87868C20.2426 3 18.8284 3 16 3Z"/>',keyboard:'<path d="M14.5 7H9.5C6.21252 7 4.56878 7 3.46243 7.90796C3.25989 8.07418 3.07418 8.25989 2.90796 8.46243C2 9.56878 2 11.2125 2 14.5C2 17.7875 2 19.4312 2.90796 20.5376C3.07418 20.7401 3.25989 20.9258 3.46243 21.092C4.56878 22 6.21252 22 9.5 22H14.5C17.7875 22 19.4312 22 20.5376 21.092C20.7401 20.9258 20.9258 20.7401 21.092 20.5376C22 19.4312 22 17.7875 22 14.5C22 11.2125 22 9.56878 21.092 8.46243C20.9258 8.25989 20.7401 8.07418 20.5376 7.90796C19.4312 7 17.7875 7 14.5 7Z"/><path d="M12 7V5C12 4.44772 12.4477 4 13 4C13.5523 4 14 3.55228 14 3V2"/><path d="M7 12L8 12"/><path d="M11.5 12L12.5 12"/><path d="M16 12L17 12"/><path d="M7 17L17 17"/>',freeze:'<path d="M14.244 3.00632C13.801 3.40963 12.6212 5.00086 11.991 5C11.3608 4.99909 10.1858 3.40451 9.744 3"/><path d="M14.244 20.9937C13.801 20.5904 12.6212 18.9991 11.991 19C11.3608 19.0009 10.1858 20.5955 9.744 21"/><path d="M20.9077 9.45191C20.337 9.26993 18.3691 9.04383 18.0547 8.4976C17.7404 7.9514 18.5338 6.13651 18.6632 5.55164"/><path d="M5.33024 18.4456C5.45802 17.8603 6.24618 16.043 5.93032 15.4976C5.61445 14.9523 3.64599 14.732 3.07477 14.5516"/><path d="M3.07602 9.45203C3.64679 9.27005 5.61472 9.04395 5.9291 8.49772C6.2434 7.95152 5.44996 6.13663 5.32055 5.55176"/><path d="M18.6529 18.4457C18.5252 17.8604 17.737 16.0431 18.0529 15.4977C18.3687 14.9524 20.3372 14.7321 20.9084 14.5518"/><path d="M15.4581 9.97911L17.994 8.49982M11.9937 8.02071L11.9937 4.99982M17.9937 15.4998L15.458 14.0206M5.99424 15.4998L8.56579 13.9997M11.9937 18.9998L11.9937 15.9789M8.56579 10.0001L5.994 8.49982"/><path d="M15.4957 11.7313C15.4955 10.8861 15.4955 10.4635 15.2945 10.1155C15.0935 9.76744 14.7275 9.55617 13.9955 9.13361L13.5316 8.86583C12.7996 8.44326 12.4336 8.23198 12.0317 8.23199C11.6298 8.23201 11.2638 8.44332 10.5318 8.86593L10.0679 9.13379C9.33581 9.55644 8.96978 9.76777 8.76882 10.1158C8.56786 10.4639 8.56786 10.8866 8.56786 11.7319L8.56786 12.2677C8.56786 13.113 8.56786 13.5356 8.76881 13.8837C8.96976 14.2318 9.33578 14.4431 10.0678 14.8658L10.5319 15.1337C11.264 15.5564 11.63 15.7678 12.032 15.7678C12.4339 15.7678 12.7999 15.5564 13.532 15.1338L13.9958 14.866C14.728 14.4433 15.0941 14.2319 15.295 13.8838C15.496 13.5356 15.4959 13.1129 15.4958 12.2674L15.4957 11.7313Z"/>',stage:'<path d="M15.5 21C16.8956 21 17.5933 21 18.1611 20.8278C19.4395 20.44 20.44 19.4395 20.8278 18.1611C21 17.5933 21 16.8956 21 15.5M21 8.5C21 7.10444 21 6.40666 20.8278 5.83886C20.44 4.56046 19.4395 3.56004 18.1611 3.17224C17.5933 3 16.8956 3 15.5 3M8.5 21C7.10444 21 6.40666 21 5.83886 20.8278C4.56046 20.44 3.56004 19.4395 3.17224 18.1611C3 17.5933 3 16.8956 3 15.5M3 8.5C3 7.10444 3 6.40666 3.17224 5.83886C3.56004 4.56046 4.56046 3.56004 5.83886 3.17224C6.40666 3 7.10444 3 8.5 3"/>',layers:'<path d="M8.64298 3.14559L6.93816 3.93362C4.31272 5.14719 3 5.75397 3 6.75C3 7.74603 4.31272 8.35281 6.93817 9.56638L8.64298 10.3544C10.2952 11.1181 11.1214 11.5 12 11.5C12.8786 11.5 13.7048 11.1181 15.357 10.3544L17.0618 9.56638C19.6873 8.35281 21 7.74603 21 6.75C21 5.75397 19.6873 5.14719 17.0618 3.93362L15.357 3.14559C13.7048 2.38186 12.8786 2 12 2C11.1214 2 10.2952 2.38186 8.64298 3.14559Z"/><path d="M20.788 11.0972C20.9293 11.2959 21 11.5031 21 11.7309C21 12.7127 19.6873 13.3109 17.0618 14.5072L15.357 15.284C13.7048 16.0368 12.8786 16.4133 12 16.4133C11.1214 16.4133 10.2952 16.0368 8.64298 15.284L6.93817 14.5072C4.31272 13.3109 3 12.7127 3 11.7309C3 11.5031 3.07067 11.2959 3.212 11.0972"/><path d="M20.3767 16.2661C20.7922 16.5971 21 16.927 21 17.3176C21 18.2995 19.6873 18.8976 17.0618 20.0939L15.357 20.8707C13.7048 21.6236 12.8786 22 12 22C11.1214 22 10.2952 21.6236 8.64298 20.8707L6.93817 20.0939C4.31272 18.8976 3 18.2995 3 17.3176C3 16.927 3.20778 16.5971 3.62334 16.2661"/>',sun:'<path d="M17 12C17 14.7614 14.7614 17 12 17C9.23858 17 7 14.7614 7 12C7 9.23858 9.23858 7 12 7C14.7614 7 17 9.23858 17 12Z"/><path d="M12 2V3.5M12 20.5V22M19.0708 19.0713L18.0101 18.0106M5.98926 5.98926L4.9286 4.9286M22 12H20.5M3.5 12H2M19.0713 4.92871L18.0106 5.98937M5.98975 18.0107L4.92909 19.0714"/>',moon:'<path d="M21.5 14.0784C20.3003 14.7189 18.9301 15.0821 17.4751 15.0821C12.7491 15.0821 8.91792 11.2509 8.91792 6.52485C8.91792 5.06986 9.28105 3.69968 9.92163 2.5C5.66765 3.49698 2.5 7.31513 2.5 11.8731C2.5 17.1899 6.8101 21.5 12.1269 21.5C16.6849 21.5 20.503 18.3324 21.5 14.0784Z"/>',left:'<path d="M15 6C15 6 9.00001 10.4189 9 12C8.99999 13.5812 15 18 15 18"/>',right:'<path d="M9.00005 6C9.00005 6 15 10.4189 15 12C15 13.5812 9 18 9 18"/>',down:'<path d="M18 9.00005C18 9.00005 13.5811 15 12 15C10.4188 15 6 9 6 9"/>',point:'<path d="M9 14.5V4.5a1.5 1.5 0 0 1 3 0v6"/><path d="M12 10a1.5 1.5 0 0 1 3 0v1.5"/><path d="M15 11a1.5 1.5 0 0 1 3 0v1"/><path d="M18 12a1.5 1.5 0 0 1 3 0v3.5a6.5 6.5 0 0 1-6.5 6.5h-1.6a6 6 0 0 1-4.7-2.3l-3.4-4.4a1.7 1.7 0 0 1 2.6-2.2L9 14.5"/>',hand:'<path d="M18 11V6a2 2 0 0 0-4 0"/><path d="M14 10V4a2 2 0 0 0-4 0v2"/><path d="M10 10.5V6a2 2 0 0 0-4 0v8"/><path d="M18 8a2 2 0 1 1 4 0v6a8 8 0 0 1-8 8h-2c-2.8 0-4.5-.86-6-2.34l-3.6-3.6a2 2 0 0 1 2.83-2.83L7 15"/>'},A=(e,t="")=>`<svg class="hi${t?" "+t:""}" viewBox="0 0 24 24" aria-hidden="true">${Zl[e]||""}</svg>`;document.querySelectorAll("i[data-i]").forEach(e=>{e.outerHTML=A(e.dataset.i)});function Gs(e){e?document.documentElement.dataset.theme=e:delete document.documentElement.dataset.theme;const t=e?e==="dark":matchMedia("(prefers-color-scheme: dark)").matches,n=document.getElementById("theme-btn");n&&(n.innerHTML=A(t?"sun":"moon"),n.title=t?"Light mode (\u21E7D)":"Dark mode (\u21E7D)")}function po(){const t=(document.documentElement.dataset.theme?document.documentElement.dataset.theme==="dark":matchMedia("(prefers-color-scheme: dark)").matches)?"light":"dark";try{localStorage.setItem("loop.theme",t)}catch{}Gs(t)}Gs((()=>{try{return localStorage.getItem("loop.theme")}catch{return null}})()),matchMedia("(prefers-color-scheme: dark)").addEventListener("change",()=>Gs(document.documentElement.dataset.theme)),document.getElementById("theme-btn").addEventListener("click",po);const Zs=["#5B6AD0","#D2575C","#3B9A6C","#B98A2C","#8A63C4","#2E93A6","#CC6E3C"],Jl=["#2F5BFF","#E5484D","#1F9D55","#D9A100","#8E4EC6","#0E9AA7","#E8590C"],Ql=e=>{const t=Jl.indexOf(String(e||"").toUpperCase());return t>=0?Zs[t]:/^#[0-9a-f]{6}$/i.test(e||"")?e:"#88888F"},mo=(e,t,n="",a="")=>`<span class="av${n?" "+n:""}" style="--c:${Ql(t)}">${a?`<img src="${C(a)}" alt="" referrerpolicy="no-referrer">`:C(Do(e).slice(0,1))}</span>`,Js="#E5484D";let f=null,v={x:120,y:140,z:.5},Qs=!1,U="select",nn=!1,D=null,V=null,O=null,Ze=null;const W=new Set;let za=null,Je=null;const ho=new Set,P=new Map,He=new Map,yn=new Map,X=window.LOOP_ADAPTER||null,Z=K.get("loop.me",null)||{id:qa(),name:"",color:Zs[Math.floor(Math.random()*Zs.length)]};X?.me&&Object.assign(Z,X.me),Z.id=Z.id||qa();async function x(e,t,n){if(X)return X.api(e,t,n);const a=await fetch(t,{method:e,headers:{"content-type":"application/json"},body:n?JSON.stringify(n):void 0}),s=await a.json().catch(()=>({}));if(!a.ok)throw new Error(s.error||`HTTP ${a.status}`);return s}function y(e,t=2200){const n=m("#toast");n.textContent=e,n.hidden=!1,clearTimeout(y.t),y.t=setTimeout(()=>n.hidden=!0,t)}const k=()=>f?.role==="owner";function ec(){if(X)return X.connect(Ha);const e=new EventSource("/__loop/api/events");e.onmessage=t=>Ha(JSON.parse(t.data)),e.onerror=()=>{m("#agent-pill").classList.add("offline")},e.onopen=()=>{m("#agent-pill").classList.remove("offline")}}function go(){if(!It()&&!oe)return location.reload();setTimeout(go,1500)}function Ha(e){if(e.type==="state"){if(f?.version&&e.state.version&&e.state.version!==f.version){location.reload();return}f?.codeId&&e.state.codeId&&e.state.codeId!==f.codeId&&go();const t=!f;f=e.state,t&&ic(),Ra()}else if(e.type==="patch"){if(!f)return;Object.assign(f,e.set||{}),!oe&&(e.lists?.frames?.up?.length>1||e.lists?.sections?.up?.length)&&(Tt.classList.add("gliding"),clearTimeout(Ha.glide),Ha.glide=setTimeout(()=>Tt.classList.remove("gliding"),520));const t=k()&&(e.lists?.sections?.up||[]).find(n=>n.optionsFor&&!(f.sections||[]).some(a=>a.id===n.id));for(const[n,a]of Object.entries(e.lists||{})){const s=new Map((f[n]||[]).map(i=>[i.id,i]));for(const i of a.up||[])s.set(i.id,i);f[n]=a.order?a.order.map(i=>s.get(i)).filter(Boolean):(f[n]||[]).map(i=>s.get(i.id))}Ra(),t&&Ll(t.id)}else if(e.type==="activity"){if(!f)return;const t=f.live[e.frameId];t&&(t.step=e.step,t.partial=e.partial||"");const n=e.partial==null&&f.comments.find(s=>s.id===e.commentId);if(n&&e.step&&!/^(Writing…|Reading your comment…|Your chat picked this up|Working…)$/.test(e.step)){const s=n.steps||=[],i=s[s.length-1];!/^(Reading the code|Editing|Writing|Setting up an option)$/.test(e.step)&&(!i||i.s!==e.step)&&s.push({t:Date.now(),s:e.step}),ar(e.commentId)}const a=P.get(e.frameId);a&&t&&$e(a.step,e.step),document.querySelectorAll(`[data-step-for="${e.commentId}"]`).forEach(s=>$e(s,e.step)),jo(e.commentId,e.partial||""),Ac(e.frameId)}else if(e.type==="frame-changed"){{const t=P.get(e.frameId);if(t?.quietN>0&&Date.now()<t.quietT&&!e.done&&!e.live){t.quietN--;return}t&&(t.quietN=0)}mc(e.frameId),e.done&&yc(e.frameId,e.status==="done"?f.frames.find(t=>t.id===e.frameId)?.kind==="frozen"?"Changed in the app":"Updated":e.status==="error"?"Failed":"",e.status!=="done"),e.done&&e.status==="done"&&bd(e.frameId),e.done&&(e.status==="done"||e.status==="error")&&gc(e.frameId,e.commentId,e.status)}else if(e.type==="presence"){if(e.id===Z.id)return;e.leave?yn.delete(e.id):yn.set(e.id,{...e,t:Date.now()}),qo(),Fa()}}function $e(e,t){e&&e.textContent!==t&&(e.textContent=t)}const _t={at:0,ids:new Set};function tc(){const e=K.get(`loop.seen.${f.name}`,null);e?(_t.at=e.at,_t.ids=new Set(e.ids)):(_t.at=Date.now(),yo())}function yo(){K.set(`loop.seen.${f.name}`,{at:_t.at,ids:[..._t.ids].slice(-400)})}function nc(e){const t=sn(e).filter(a=>a.kind!=="note"),n=t[t.length-1];return!!n&&n.status==="done"&&(n.finishedAt||0)>_t.at&&!_t.ids.has(n.id)}function bo(e){let t=!1;for(const n of sn(e))n.finishedAt&&!_t.ids.has(n.id)&&(_t.ids.add(n.id),t=!0);return t&&yo(),t}const ac=[0,8,2,10,12,4,14,6,3,11,1,9,15,7,13,5],ei=[64,148,255];let Oa=0,vo=0;const ti=matchMedia("(prefers-reduced-motion: reduce)");function ni(){Oa||(Oa=requestAnimationFrame(wo))}function wo(e){Oa=0;const t=[...document.querySelectorAll(".area.working")];if(!t.length||(ti.matches||(Oa=requestAnimationFrame(wo)),e-vo<33))return;vo=e;const n=ti.matches?.35:e%5200/5200,a=Math.min(1,n/.8),i=-.2+a*a*(3-2*a)*1.45,o=1,r=.119;for(const l of t){const c=l.getBoundingClientRect();if(c.right<0||c.bottom<0||c.left>innerWidth||c.top>innerHeight||c.width<12||c.height<12)continue;let d=3;for(;c.width/d*(c.height/d)>6e4;)d++;const u=Math.ceil(c.width/d),p=Math.ceil(c.height/d);let h=l.querySelector(":scope > canvas.dz");h||(h=document.createElement("canvas"),h.className="dz",l.appendChild(h)),(h.width!==u||h.height!==p)&&(h.width=u,h.height=p,h.style.setProperty("--cols",u),h.style.setProperty("--rows",p));const g=h.getContext("2d"),w=g.createImageData(u,p),T=w.data,$=Math.hypot(u,p),b=Math.min(u,p),M=Math.max(2.4,b*.05+Math.max(0,b-40)*.03)*(l.classList.contains("whole")?1.5:1),E=M*4.5;for(let z=0;z<p;z++)for(let _=0;_<u;_++){const se=Math.min(_,z,u-1-_,p-1-z);if(se>E)continue;const F=Math.hypot(_,z)/$-i,pe=o*Math.exp(-F*F/r)*Math.exp(-se/M);if(pe>(ac[(z&3)*4+(_&3)]+.5)/16){const gn=(z*u+_)*4;T[gn]=ei[0],T[gn+1]=ei[1],T[gn+2]=ei[2],T[gn+3]=255*(.3+.7*pe)|0}}g.putImageData(w,0,0)}}const sc='<svg viewBox="0 0 24 24" aria-hidden="true"><path pathLength="14" d="M5 14L8.5 17.5L19 6.5"/></svg>';function ic(){setTimeout(Kr,400),tc();const e=K.get(`loop.view.${f.name}`,null);e?(v=e,re()):Oe(!1),Qs=!0,k()?Z.name=f.hostName||Z.name||"You":Z.name||Mr(),K.set("loop.me",Z),document.body.classList.toggle("guest",!k()),m("#new-frame-btn").hidden=!k(),m("#section-btn").hidden=!k(),document.querySelector("#toolbar .tb-sep").hidden=!k()}function re(){v.z>=.02||(v.z=.04),Lo=performance.now(),Tt.style.transform=`translate(${v.x}px, ${v.y}px) scale(${v.z})`,Tt.style.setProperty("--z",v.z),re.lastZ!==v.z&&(re.lastZ=v.z,Tt.style.willChange!=="transform"&&(Tt.style.willChange="transform"),clearTimeout(re.crisp),re.crisp=setTimeout(()=>{Tt.style.willChange="auto"},160));const e=Math.min(1.5,Math.max(1,Math.pow(v.z,.42)));document.documentElement.style.setProperty("--lz",e.toFixed(3)),document.body.classList.toggle("zoom-tiny",v.z<.12);const t=`${Math.round(v.z*100)}%`,n=m("#zoom-level");if(n.textContent!==t){n.textContent=t;const a=m("#zoom");a.classList.add("awake"),clearTimeout(re.zt),re.zt=setTimeout(()=>a.classList.remove("awake"),1200)}Xn(),bn(),Te(),Ma(),xe&&Re(),G.hidden=!0,Qs&&f&&(clearTimeout(re.t),re.t=setTimeout(()=>K.set(`loop.view.${f.name}`,v),300)),f&&re.z!==v.z&&(re.z=v.z,re.lq||(re.lq=requestAnimationFrame(()=>{re.lq=0,Ml()})),clearTimeout(re.pt),re.pt=setTimeout(()=>{for(const a of f.frames)wt(a.id)},120))}function Pt(e,t,n){const a=Math.min(4,Math.max(.04,v.z*n));v.x=e-(e-v.x)*(a/v.z),v.y=t-(t-v.y)*(a/v.z),v.z=a,si()}let ai=!1;function si(){ai||(ai=!0,requestAnimationFrame(()=>{ai=!1,re()}))}function xo(e,t,n){e.preventDefault();const a=Math.max(-30,Math.min(30,e.deltaMode===1?e.deltaY*16:e.deltaY));Pt(t,n,Math.exp(-a*(e.ctrlKey&&!e.metaKey?.01:.004)))}const fe=(e,t)=>({x:(e-v.x)/v.z,y:(t-v.y)/v.z});function Oe(e=!0,t){const n=(f?.frames||[]).filter(r=>!t||t.includes(r.id));if(!n.length)return v={x:innerWidth/2,y:innerHeight/2,z:.5},re();const a=Math.min(...n.map(r=>r.x)),s=Math.min(...n.map(r=>r.y)),i=Math.max(...n.map(r=>r.x+r.w)),o=Math.max(...n.map(r=>r.y+r.h));return ko({x:a,y:s,w:i-a,h:o-s},1,e)}function ko(e,t=1,n=!0){const a=e.x,s=e.y,i=e.x+Math.max(1,e.w),o=e.y+Math.max(1,e.h),r=80,l=110,c=110,d=Math.max(.04,Math.min(t,(innerWidth-r*2)/(i-a),(innerHeight-l-c)/(o-s))),u={z:d,x:(innerWidth-(i-a)*d)/2-a*d,y:l+(innerHeight-l-c-(o-s)*d)/2-s*d};if(!n)return v=u,re();const p={...v},h=performance.now(),g=w=>{const T=Math.min(1,(w-h)/280),$=1-Math.pow(1-T,3);v={x:p.x+(u.x-p.x)*$,y:p.y+(u.y-p.y)*$,z:p.z+(u.z-p.z)*$},re(),T<1&&requestAnimationFrame(g)};requestAnimationFrame(g)}function Ra(){if(!f)return;m("#canvas-name").querySelector("input")||(m("#canvas-name").textContent=f.name),m("#canvas-name").classList.toggle("editable",k()&&!X),m("#history-btn").hidden=!k()||!!X,document.title=`${f.name} \u2014 Loop`,m("#empty").hidden=f.frames.length>0,m("#empty").classList.toggle("guest",!k()),k()&&!X&&f.hostName&&Z.name!==f.hostName&&Qs&&(Z.name=f.hostName,K.set("loop.me",Z)),xc(),Fa();const e=new Set(f.frames.map(t=>t.id));for(const[t,n]of P)e.has(t)||(n.el.contains(H)&&ae(),n.el.remove(),P.delete(t));for(const t of f.frames)ee(t);f.sections||=[],yt(),D&&!e.has(D)&&(D=null),Wt(),Qn(),V&&Qa(),xe&&Sc(),O&&O.frameId!==le&&!e.has(O.frameId)&&ae();for(const t of[...W])e.has(t)||W.delete(t);Fe(),va(),Jc(),Uc(),S&&Xe(),Y&&Rl(),I&&(Wn(),Ta()),Xn(),Ps()}function Vn(e){try{const t=e.iframe.contentWindow.location;return t.href==="about:blank"?null:t.pathname+t.search+t.hash}catch{return null}}let ii=0,oi=0,Un=null;const oc=/[?&]nosleep\b/.test(location.search);let $o=new Set;function rc(e){const t=en(e),n=Math.max(0,Math.min(t.l+t.w,innerWidth)-Math.max(t.l,0)),a=Math.max(0,Math.min(t.t+t.h,innerHeight)-Math.max(t.t,0));return{shown:n*a,of:t.w*t.h,r:t}}function lc(){const e=new Set;if(!f)return e;if(S)return e.add(S.fid),e;const t=[];for(const n of f.frames){const{shown:a,of:s,r:i}=rc(n);if(!(a<400||a<s*.1)){if(oc||n.id===Un||n.id===D||n.id===me||L?.frameId===n.id||Ce?.fid===n.id||W.has(n.id)){e.add(n.id);continue}(a>=innerWidth*innerHeight*.25||a>=s*.5&&(i.h>=innerHeight*.55||i.w>=innerWidth*.55))&&t.push([n.id,a])}}return t.sort((n,a)=>a[1]-n[1]).slice(0,2).forEach(([n])=>e.add(n)),e}const cc=e=>$o.has(e);function dc(e,t,n){const a=e.requestAnimationFrame.bind(e),s=new Map;let i=0;t.waking=Date.now(),e.requestAnimationFrame=r=>{if(!t.asleep)return a(r);const l=-++i;return s.set(l,r),l};const o=e.cancelAnimationFrame.bind(e);e.cancelAnimationFrame=r=>r<0?s.delete(r):o(r),t.sleepTo=r=>{if(t.asleep!==r){t.asleep=r;try{const l=e.document;let c=l.getElementById("__loop-sleep");r&&!c&&(c=l.createElement("style"),c.id="__loop-sleep",c.textContent="*, *::before, *::after { animation-play-state: paused !important; }",(l.head||l.documentElement).appendChild(c)),!r&&c&&c.remove(),l.querySelectorAll("video").forEach(d=>{try{r?(d._loopPlay=!d.paused,d.pause()):d._loopPlay&&d.play()}catch{}})}catch{}if(!r){const l=[...s.values()];s.clear(),l.forEach(c=>a(c))}}},t.asleep=!1,bn()}function bn(){oi||!f||(oi=setTimeout(()=>{oi=0,$o=lc();for(const[e,t]of P){if(!t.sleepTo)continue;const n=Date.now()-(t.waking||0)<700;t.sleepTo(!n&&!cc(e))}},120))}setInterval(()=>bn(),1500);function Xn(){ii||!f||(ii=requestAnimationFrame(()=>{ii=0;const e=innerWidth,t=innerHeight,n=f.frames.length>6,a=[];for(const s of f.frames){const i=P.get(s.id);if(!i?.iframe)continue;const o=qe(s),r=v.z,l=v.x+o.x*r,c=v.y+o.y*r,d=o.w*r,u=o.h*r,p=g=>Math.max(0,l-e-g,-(l+d)-g,c-t-g,-(c+u)-g),h=!n||f.live[o.id]||D===o.id||me===o.id||S?.fid===o.id||W.has(o.id);if(i.el.classList.toggle("narrow",d<200),i.el.classList.toggle("far",Nn(s)),f.live[o.id]){const g=Math.max(0,Math.min(l+d,e)-Math.max(l,0)),w=Math.max(0,Math.min(c+u,t)-Math.max(c,0)),T=g*w>=e*t*.2&&g*w>=d*u*.5;i.wedge||(i.wedge=document.createElement("i"),i.wedge.className="work-edge",i.el.appendChild(i.wedge)),i.el.classList.toggle("work-far",!T)}else i.el.classList.contains("work-far")&&i.el.classList.remove("work-far");i.parked?(h||p(e*.5)===0&&Math.max(d,u)>160)&&a.push({fe:i,keep:h,on:p(0)===0,d:Math.hypot(l+d/2-e/2,c+u/2-t/2)}):!h&&(p(e)>0||Math.max(d,u)<110)&&(i.resume=Vn(i),i.parked=!0,i.el.classList.add("parked"),i.iframe.src="about:blank"),i.parked&&Mo(i)}if(a.length){const s=performance.now()-Lo>140;a.sort((o,r)=>r.keep-o.keep||r.on-o.on||o.d-r.d);const i=s?a.slice(0,2):a.filter(o=>o.keep).slice(0,2);for(const{fe:o}of i)o.parked=!1,o.el.classList.remove("parked"),o.el.classList.add("waking"),clearTimeout(o.wakeT),o.wakeT=setTimeout(()=>Co(o),8e3),o.iframe.src=o.resume||o.iframe.dataset.src||"about:blank",o.resume=null;a.length>i.length&&setTimeout(Xn,s?90:160)}}))}let Lo=0;function Co(e){clearTimeout(e.wakeT),requestAnimationFrame(()=>requestAnimationFrame(()=>e.el.classList.remove("waking")))}function Mo(e){if(X)return;const t=e.hint.querySelector("img"),n=`/__loop/poster/${e.id}?v=${e.rev||0}`;if(t.dataset.src===n)return;t.dataset.src=n;const a=new Image;a.onload=()=>{t.dataset.src===n&&(t.src=n,t.hidden=!1,e.hint.classList.add("has-pic"))},a.src=n}function qe(e){return{...e,...He.get(e.id)||{}}}function fc(e){const t=document.createElement("div");t.className="frame",t.dataset.id=e.id,t.innerHTML=`
|
|
2
2
|
<div class="frame-label">
|
|
3
3
|
<span class="spinner"></span><span class="ic"></span><span class="name"></span><span class="kind" hidden></span><button class="count" title="Versions: look back through this frame's changes" hidden>${A("layers")}<span></span></button>
|
|
4
4
|
<span class="step"></span><span class="elapsed"></span><span class="updated"></span>
|
|
5
5
|
<button class="stop" title="Stop the agent">Stop</button>
|
|
6
6
|
</div>
|
|
7
|
-
<div class="frame-body"><iframe title="${
|
|
8
|
-
${["n","s","e","w","ne","nw","se","sw"].map(a=>`<div class="resize rz-${a}" data-dir="${a}"></div>`).join("")}`,
|
|
7
|
+
<div class="frame-body"><iframe title="${C(e.name)}"></iframe><div class="parked-hint"><span></span><img alt="" draggable="false" hidden></div><div class="empty-hint"></div><div class="down-hint"><b></b><span>Start it again and this frame comes back by itself.</span></div><div class="shield"></div><div class="areas"></div><div class="progress"></div></div><div class="edge-zone"></div><div class="pins"></div><button class="dims" tabindex="-1"></button>
|
|
8
|
+
${["n","s","e","w","ne","nw","se","sw"].map(a=>`<div class="resize rz-${a}" data-dir="${a}"></div>`).join("")}`,Gl.appendChild(t);const n={id:e.id,el:t,iframe:t.querySelector("iframe"),label:t.querySelector(".frame-label"),name:t.querySelector(".name"),dims:t.querySelector(".dims"),kind:t.querySelector(".kind"),count:t.querySelector(".count"),step:t.querySelector(".step"),elapsed:t.querySelector(".elapsed"),updated:t.querySelector(".updated"),ic:t.querySelector(".ic"),pins:t.querySelector(".pins"),restore:null,parked:!0,hint:t.querySelector(".parked-hint")};return t.classList.add("parked"),Eo(n,e,n.iframe),t.querySelector(".stop").addEventListener("pointerdown",a=>a.stopPropagation()),t.querySelector(".stop").addEventListener("click",()=>{const a=Object.values(f.live),s=f.live[e.id];for(const i of a.length>1?a:s?[s]:[])x("POST",`/__loop/api/comments/${i.commentId}/cancel`).catch(o=>y(o.message))}),n.label.addEventListener("dblclick",a=>{!a.target.closest(".count")&&k()&&!n.renaming&&ri(e.id)}),n.dims.addEventListener("pointerdown",a=>a.stopPropagation()),n.dims.innerHTML='<button class="fill-dot" data-pick="frame-fill" title="Fill"><i></i></button><span class="dz"></span>',n.dims.addEventListener("click",a=>{if(a.stopPropagation(),!k())return;const s=a.target.closest(".fill-dot");if(s){const i=f.frames.find(o=>o.id===e.id);return s.dataset.val=i?.fill&&i.fill!=="none"?i.fill:"#ffffff",$s(s)}Ye=Ye===e.id?null:e.id,Fe()}),n.count.addEventListener("pointerdown",a=>a.stopPropagation()),n.count.addEventListener("click",a=>{a.stopPropagation(),ro(e.id)}),P.set(e.id,n),n}function Eo(e,t,n){n.addEventListener("load",()=>{if(setTimeout(()=>{const a=f?.frames.find(s=>s.id===t.id);a&&(Po(e,a,f.live[t.id]),vc(e,a))},30),e.el.classList.contains("waking")&&n.src!=="about:blank"&&Co(e),n._incoming){const a=e.iframe,s=document.activeElement===a;n._incoming=!1,e.iframe=n;try{e.restore&&n.contentWindow.scrollTo(e.restore.sx,e.restore.sy)}catch{}requestAnimationFrame(()=>requestAnimationFrame(()=>{if(n.classList.remove("incoming"),a.remove(),s)try{n.focus()}catch{}if(e.swapping=!1,clearTimeout(e.swapT),e.swapNext){const i=e.swapNext;e.swapNext=null,So(e,t,i)}}))}if(n===e.iframe){try{const a=n.contentWindow;if(e.parked)return;const s=()=>{e.cur=Vn(e);const c=f?.frames.find(d=>d.id===t.id);c?.kind==="route"&&!c.optionOf&&(e.kind.textContent=(e.cur||c.src).split("?")[0])};s();for(const c of["pushState","replaceState"]){const d=a.history[c];a.history[c]=function(...u){const p=d.apply(this,u);return setTimeout(s),p}}a.addEventListener("popstate",s),a.addEventListener("hashchange",s),e.restore&&(a.scrollTo(e.restore.sx,e.restore.sy),e.restore=null),e.el.classList.toggle("empty",!!a.document.querySelector('meta[name="loop-empty"]')&&!li(f.frames.find(c=>c.id===t.id)||t)),e.rev=(e.rev||0)+1,e.sbarAt=0,S?.fid===t.id&&setTimeout(()=>oo(e,f.frames.find(c=>c.id===t.id)||t),60);let i=0;a.addEventListener("scroll",()=>{i||(i=requestAnimationFrame(()=>{i=0,wt(t.id)}))},{passive:!0,capture:!0}),a.addEventListener("resize",()=>wt(t.id));const o=c=>{const d=n.getBoundingClientRect(),u=d.width/(n.offsetWidth||1);return[d.left+c.clientX*u,d.top+c.clientY*u]};ef(a,t.id,o),cf(t.id),dc(a,e,t.id);let r=null,l=0;a.addEventListener("wheel",c=>{if(S){(c.ctrlKey||c.metaKey)&&c.preventDefault();return}if(c.ctrlKey||c.metaKey)return xo(c,...o(c));const d=performance.now();if(!r||d-l>140){const p=Math.abs(c.deltaX)>Math.abs(c.deltaY);r=pr(c.target,p?"x":"y",p?c.deltaX:c.deltaY)?"page":"canvas"}if(l=d,r==="page")return;c.preventDefault();const u=c.deltaMode===1?16:1;v.x-=c.deltaX*u,v.y-=c.deltaY*u,si()},{passive:!1}),uc(a,t.id),a.addEventListener("pointerdown",()=>{Be&&!S&&me!==t.id&&Si(t.id)},!0),a.addEventListener("contextmenu",c=>{if(c.shiftKey)return;c.preventDefault();const[d,u]=o(c);Xr(d,u,e.el.querySelector(".frame-body"))}),e.autoKb=null,bf(a,e,t.id),a.addEventListener("gesturestart",c=>{c.preventDefault(),ns=v.z}),a.addEventListener("gesturechange",c=>{if(c.preventDefault(),S)return;const[d,u]=o(c);Pt(d,u,ns*c.scale/v.z)}),a.addEventListener("keydown",c=>{if(c.key==="Escape"){me=null,$t(),Q(null);for(const g of f.frames)ee(g);return}const d=c.target;!(d&&(d.isContentEditable||/^(INPUT|TEXTAREA|SELECT)$/.test(d.tagName)))&&!c.metaKey&&!c.ctrlKey&&/^[vhpecdfnksx?]$/i.test(c.key)&&setTimeout(()=>{c.defaultPrevented||($t(),window.dispatchEvent(new KeyboardEvent("keydown",{key:c.key,code:c.code,shiftKey:c.shiftKey,altKey:c.altKey})))},0);const p=c.target,h=p&&(p.isContentEditable||/^(INPUT|TEXTAREA|SELECT)$/.test(p.tagName));(c.metaKey||c.ctrlKey)&&!h&&(c.key.toLowerCase()==="z"||c.ctrlKey&&c.key.toLowerCase()==="y")&&(c.preventDefault(),c.shiftKey||c.key.toLowerCase()==="y"?fa():us())})}catch{}setTimeout(()=>wt(t.id),60)}})}function uc(e,t){const n=e.document;let a=null,s=0;const i=()=>{const d=f?.frames.find(u=>u.id===t);return hl(d)};try{const d=n.createElement("style");d.dataset.loop="touch";const u=`url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='28' height='28'%3E%3Ccircle cx='14' cy='14' r='11' fill='rgba(120,120,128,.38)' stroke='rgba(255,255,255,.75)' stroke-width='1.5'/%3E%3C/svg%3E") 14 14, default`;d.textContent=`html.loop-touch, html.loop-touch * { -webkit-user-select: none !important; user-select: none !important; -webkit-touch-callout: none; cursor: ${u} !important; }
|
|
9
9
|
html.loop-touch input, html.loop-touch textarea, html.loop-touch [contenteditable] { -webkit-user-select: text !important; user-select: text !important; }
|
|
10
|
-
html.loop-touch img, html.loop-touch a { -webkit-user-drag: none; }`,(n.head||n.documentElement).appendChild(d),n.documentElement.classList.toggle("loop-touch",s())}catch{}const o=(d,u)=>{const p=n.scrollingElement||n.documentElement;for(let h=d?.nodeType===1?d:d?.parentElement;h&&h!==p&&h!==n.body;h=h.parentElement){const g=e.getComputedStyle(h),v=u==="x"?g.overflowX:g.overflowY;if(/(auto|scroll|overlay)/.test(v)&&(u==="x"?h.scrollWidth-h.clientWidth:h.scrollHeight-h.clientHeight)>1)return h}return p},r=(d,u,p)=>{d&&(u||p)&&d.scrollTo({left:d.scrollLeft+u,top:d.scrollTop+p,behavior:"instant"})},c=d=>{try{return e.getComputedStyle(d).scrollSnapType!=="none"}catch{return!1}};e.addEventListener("pointerdown",d=>{if(cancelAnimationFrame(i),!s()||d.pointerType!=="mouse"||d.button!==0||d.target.closest?.('input, textarea, select, [contenteditable=""], [contenteditable="true"], [draggable="true"]'))return;let u="auto";for(let p=d.target;p&&p.nodeType===1;p=p.parentElement){const h=e.getComputedStyle(p).touchAction;if(h&&h!=="auto"){u=h;break}}u!=="none"&&(a={x:d.clientX,y:d.clientY,lx:d.clientX,ly:d.clientY,lt:performance.now(),vx:0,vy:0,moved:!1,target:d.target,sx:null,sy:null,ax:!/pan-y/.test(u)||/pan-x/.test(u),ay:!/pan-x/.test(u)||/pan-y/.test(u)})},!0),e.addEventListener("pointermove",d=>{if(!a)return;if(!(d.buttons&1))return l();if(!a.moved){if(Math.hypot(d.clientX-a.x,d.clientY-a.y)<6)return;a.moved=!0,a.sx=o(a.target,"x"),a.sy=o(a.target,"y"),e.getSelection?.()?.removeAllRanges()}const u=a.ax?d.clientX-a.lx:0,p=a.ay?d.clientY-a.ly:0,h=performance.now(),g=Math.max(1,h-a.lt);a.sx===a.sy?r(a.sx,-u,-p):(r(a.sx,-u,0),r(a.sy,0,-p)),a.vx=.7*(u/g*16)+.3*a.vx,a.vy=.7*(p/g*16)+.3*a.vy,a.lx=d.clientX,a.ly=d.clientY,a.lt=h,(u||p)&&d.preventDefault()},!0);const l=()=>{const d=a;if(a=null,!d?.moved)return;const u=v=>{v.stopPropagation(),v.preventDefault()};if(e.addEventListener("click",u,{capture:!0,once:!0}),setTimeout(()=>e.removeEventListener("click",u,!0),80),performance.now()-d.lt>90)return;let p=c(d.sx)?0:d.vx,h=c(d.sy)?0:d.vy;const g=()=>{p*=.95,h*=.95,!(Math.abs(p)<.4&&Math.abs(h)<.4)&&(d.sx===d.sy?r(d.sx,-p,-h):(r(d.sx,-p,0),r(d.sy,0,-h)),i=requestAnimationFrame(g))};i=requestAnimationFrame(g)};e.addEventListener("pointerup",l,!0),e.addEventListener("pointercancel",l,!0),e.addEventListener("blur",l),n.addEventListener("selectstart",d=>{a&&s()&&d.preventDefault()},!0),n.addEventListener("dragstart",d=>{s()&&!d.target.closest?.('[draggable="true"]')&&d.preventDefault()},!0)}function Ks(e,t,n){if(e.swapping){e.swapNext=n;return}e.swapping=!0;const a=document.createElement("iframe");a.title=e.iframe.title,a.dataset.src=e.iframe.dataset.src,a.className="incoming",a._incoming=!0,js(e,t,a),e.iframe.after(a),a.src=n,e.swapT=setTimeout(()=>{a._incoming&&a.dispatchEvent(new Event("load"))},5e3)}function fl(e){try{const t=e.iframe.contentWindow;return!!(t.document.querySelector('script[src*="/@vite/client"], nextjs-portal, script[src*="webpack-dev-server"], script[src*="hot-update"]')||t.__vite_plugin_react_preamble_installed__||t.$RefreshReg$||t.__webpack_hmr||t.parcelHotUpdate||Object.keys(t).some(a=>a.startsWith("webpackHotUpdate")))}catch{return!1}}function J(e){if(!e)return;const t=De(e),n=D.get(t.id)||cl(t),a=n.el.style,i=t.fill==="none"?"transparent":t.fill||"";(a.getPropertyValue("--fill")||"")!==i&&(i?a.setProperty("--fill",i):a.removeProperty("--fill")),n.el.classList.toggle("nofill",t.fill==="none"),a.left=`${t.x}px`,a.top=`${t.y}px`,a.width=`${t.w}px`,a.height=`${t.h}px`,a.setProperty("--fw",`${t.w}px`);{const l=Ri(t),d=`Describe this ${l.what}`;a.setProperty("--pfs",`${l.fs}px`),a.setProperty("--pk",(l.fs/27).toFixed(3)),a.setProperty("--plx",`${l.lx*100}%`),a.setProperty("--pty",`${l.ty*100}%`),n.el.dataset.on!==l.on&&(n.el.dataset.on=l.on),n.hintB||=n.el.querySelector(".empty-hint b"),n.hintB&&n.hintB.textContent!==d&&(n.hintB.textContent=d)}n.inkAt!==`${t.x},${t.y}`&&(n.inkAt=`${t.x},${t.y}`,eo(t.id));const s=X?.frameSrc?.(t)||(t.kind==="folder"||t.kind==="frozen"?`/__loop/f/${t.id}/${encodeURIComponent(t.entry||"index.html")}`:t.src);n.iframe.dataset.src!==s&&(n.iframe.dataset.src=s,n.resume=null,n.parked||(n.iframe.src=s)),$e(n.hint.firstChild,t.name),n.el.classList.toggle("narrow",t.w*b.z<200),n.renaming||(n.name.textContent=t.name),n.kind.hidden=t.kind==="folder"||t.kind==="static"||t.kind==="frozen";const o=t.kind==="frozen";n.ic.dataset.k!==(o?"frozen":"live")&&(n.ic.dataset.k=o?"frozen":"live",n.ic.innerHTML=o?ci:""),n.ic.dataset.tip=o?`Frozen ${new Date(t.frozenAt||t.createdAt).toLocaleString([],{month:"short",day:"numeric",hour:"numeric",minute:"2-digit"})}${t.from?` \xB7 from ${t.from.split("?")[0]}`:""}`:"Live",n.el.classList.toggle("is-frozen",o),Mr(n,t),n.kind.textContent=t.kind==="route"&&!t.optionOf?(n.cur||t.src).split("?")[0]:"Live";{let l=null;if(t.kind==="url")try{l=new URL(t.src).origin}catch{}const d=!!l&&!!f.down?.includes(l);d!==!!n.down&&(n.down=d,n.el.classList.toggle("down",d),d?(n.downB||=n.el.querySelector(".down-hint b"),n.downB.textContent=`${l.replace(/^https?:\/\//,"")} isn\u2019t running`):!n.parked&&n.iframe.dataset.src&&(n.iframe.src=n.iframe.dataset.src))}const r=f.live[t.id],c=t.kind==="folder"&&!X?vi(t.id).length:0;if($e(n.count.lastChild,c&&!r?String(c+1):""),n.count.hidden=!c||!!r,n.el.classList.toggle("working",!!r),r){n.stopB||=n.el.querySelector(".frame-label .stop");const l=Object.keys(f.live).length>1;$e(n.stopB,l?"Stop all agents":"Stop"),n.stopB.title=l?"Stop every agent that is working":"Stop the agent"}n.el.classList.toggle("building",!!t.building),Us(n,t,r);{const l=$()&&!X&&f.agent.mode==="inbox"&&!f.chatListening&&f.comments.find(u=>u.frameId===t.id&&u.kind==="create"&&u.status==="queued"&&!u.background);let d=n.el.querySelector(":scope > .frame-body > .wait-pill");l&&!d&&(d=document.createElement("div"),d.className="wait-pill",n.el.querySelector(".frame-body").appendChild(d),d.addEventListener("pointerdown",u=>u.stopPropagation()),d.addEventListener("click",async u=>{const p=u.target.closest("button");if(p){p.disabled=!0,p.textContent="Starting\u2026";try{await w("POST",`/__loop/api/comments/${d.dataset.cid}/background`)}catch(h){y(h.message)}}})),d&&!l?d.remove():d&&d.dataset.cid!==l.id&&(d.dataset.cid=l.id,d.innerHTML=`<span>Chat isn\u2019t listening</span><button class="pin-act" title="Build it now in the background${f.chatHistory?", carrying on from a copy of that chat":" in a new session"}">${f.chatHistory?"Carry on here":"Run in new chat"}<kbd>${rt==="metaKey"?"\u2318":"Ctrl"}\u21B5</kbd></button>`)}if(n.el.classList.toggle("filling",t.building==="filling"),n.el.classList.toggle("in-section",(f.sections||[]).some(l=>An($s(l),t))),r){const l=f.comments.find(d=>d.id===r.commentId);$e(n.step,r.step||(l?.kind==="create"?"Building the frame\u2026":"Working\u2026")),$e(n.elapsed,xa(r.startedAt))}n.el.classList.toggle("selected",_===t.id||Y.has(t.id)),n.el.classList.toggle("live",xe?.fid===t.id||K==="select"&&Be&&!Yt&&x?.frameId!==t.id),$e(n.dims.querySelector(".dz"),`${Math.round(t.w)} \xD7 ${Math.round(t.h)}`),n.dims.dataset.tip="Fill \xB7 size & device presets";{const l=n.dims.querySelector(".fill-dot i");l&&(l.style.background=t.fill&&t.fill!=="none"?t.fill:"",l.parentElement.classList.toggle("is-none",t.fill==="none"))}if(Ue===t.id){const l=ya===t.id;Ue=ya=null,queueMicrotask(()=>{S||(Z(t.id),St(t.id),l&&setTimeout(()=>_a(t.id),340))})}}function xa(e){const t=Math.max(0,Math.round((Date.now()-e)/1e3));return t<60?`${t}s`:`${Math.floor(t/60)}m ${String(t%60).padStart(2,"0")}s`}setInterval(()=>{if(!f)return;for(const[n,a]of Object.entries(f.live)){const i=D.get(n);i&&(i.elapsed.textContent=xa(a.startedAt))}document.querySelectorAll("[data-elapsed-from]").forEach(n=>$e(n,xa(+n.dataset.elapsedFrom)));const e=Date.now();let t=!1;for(const[n,a]of ln)e-a.t>15e3&&(ln.delete(n),t=!0);t&&(Gs(),$a())},1e3);function ul(e){const t=D.get(e);if(!t)return;try{const i=t.iframe.contentWindow;t.restore={sx:i.scrollX,sy:i.scrollY}}catch{t.restore=null}if(t.rev=(t.rev||0)+1,t.parked){t.resume=null,Ws(t);return}const n=t.iframe.dataset.src,a=f.frames.find(i=>i.id===e);if(!(a?.kind==="static"||a?.kind==="frozen"))if(a?.kind==="folder")Ks(t,a,`${n}?_m=${Date.now()}`);else if(a?.kind==="route"){if(fl(t))return;try{t.iframe.contentWindow.location.reload()}catch{t.iframe.src=n}}else try{t.iframe.contentWindow.location.reload()}catch{t.iframe.src=n}}const he=document.createElement("div");he.id="done",he.hidden=!0,document.body.appendChild(he);let ka=0;const Ys=document.title;function Vs(e){try{const t=Vs.ac||=new(window.AudioContext||window.webkitAudioContext),n=t.currentTime;for(const[a,i]of(e?[440,330]:[660,990]).entries()){const s=t.createOscillator(),o=t.createGain();s.type="sine",s.frequency.value=i,s.connect(o),o.connect(t.destination),o.gain.setValueAtTime(0,n+a*.11),o.gain.linearRampToValueAtTime(.06,n+a*.11+.02),o.gain.exponentialRampToValueAtTime(1e-4,n+a*.11+.5),s.start(n+a*.11),s.stop(n+a*.11+.55)}}catch{}}function pl(e){const t=f.frames.find(i=>i.id===e);if(!t)return!1;const n=jt(t);return Math.max(0,Math.min(n.l+n.w,innerWidth)-Math.max(n.l,0))*Math.max(0,Math.min(n.t+n.h,innerHeight)-Math.max(n.t,0))>n.w*n.h*.4&&n.w>120}function ml(e,t,n){if(!$()||X||!f)return;const a=document.hidden;if(!a&&pl(e))return;const s=f.frames.find(l=>l.id===e),o=f.comments.find(l=>l.id===t),r=n==="error",c=e===le?"the canvas":s?.name||"a frame";Vs(r),a&&(ka++,document.title=`(${ka}) ${Ys}`),he.innerHTML=`<span class="dn-ic${r?" err":""}">${A(r?"x":"check","s")}</span><span class="dn-text"><b>${r?"Failed":"Done"}</b> \xB7 ${L(c)}</span><button class="dn-go">Go there</button><button class="dn-x" title="Dismiss">${A("x","s")}</button>`,he.dataset.fid=e,he.dataset.cid=t||"",he.hidden=!1,he.classList.remove("in"),he.offsetWidth,he.classList.add("in"),clearTimeout(he._t),he._t=setTimeout(()=>{he.hidden=!0},9e3)}he.addEventListener("click",e=>{if(e.target.closest(".dn-x")){he.hidden=!0;return}if(!e.target.closest(".dn-go"))return;he.hidden=!0;const t=f.comments.find(n=>n.id===he.dataset.cid);t?Yi(f.comments.find(n=>n.id===(t.parentId||t.id))||t,!0):he.dataset.fid&&he.dataset.fid!==le&&(Z(he.dataset.fid),Oe(!0,[he.dataset.fid]))}),document.addEventListener("visibilitychange",()=>{!document.hidden&&ka&&(ka=0,document.title=Ys)});function hl(e,t,n){const a=D.get(e);!a||!t||(a.updated.textContent=t,a.el.classList.remove("updated","failed"),a.el.offsetWidth,a.el.classList.add(n?"failed":"updated"),clearTimeout(a.flashT),a.flashT=setTimeout(()=>a.el.classList.remove("updated","failed"),4200))}function Xs(e,t,n){e.textContent=t;try{e.contentEditable="plaintext-only"}catch{}e.contentEditable!=="plaintext-only"&&(e.contentEditable="true"),e.classList.add("editing-name"),e.spellcheck=!1,e.focus();const a=document.createRange();a.selectNodeContents(e);const i=getSelection();i.removeAllRanges(),i.addRange(a);let s=!1;const o=c=>{if(s)return;s=!0;const l=e.textContent.replace(/\s+/g," ").trim();e.contentEditable="false",e.removeAttribute("contenteditable"),e.classList.remove("editing-name"),e.textContent=c&&l?l:t,getSelection().removeAllRanges(),n(c&&l&&l!==t?l:null)},r=c=>c.stopPropagation();e.addEventListener("pointerdown",r),e.addEventListener("dblclick",r),e.addEventListener("keydown",c=>{c.stopPropagation(),c.key==="Enter"&&(c.preventDefault(),o(!0)),c.key==="Escape"&&(c.preventDefault(),o(!1))}),e.addEventListener("paste",c=>{c.preventDefault(),document.execCommand("insertText",!1,(c.clipboardData?.getData("text/plain")||"").replace(/\s+/g," "))}),e.addEventListener("blur",()=>{o(!0),e.removeEventListener("pointerdown",r),e.removeEventListener("dblclick",r)},{once:!0})}function _i(e){const t=D.get(e),n=f.frames.find(a=>a.id===e);!t||!n||(t.renaming=!0,Xs(t.name,n.name,a=>{if(t.renaming=!1,a){const i=n.name;w("PATCH",`/__loop/api/frames/${e}`,{name:a}),G("Rename frame",()=>Rt(e,{name:i}),()=>Rt(e,{name:a}))}}))}function gl(e){try{const t=e.iframe.contentDocument;return!!t?.querySelector('meta[name="loop-placeholder"], meta[name="loop-empty"]')||!!t&&t.readyState==="complete"&&!t.body?.children.length&&/waiting for the agent/.test(t.body?.textContent||"")}catch{return!1}}const Pi=e=>f.comments.find(t=>t.frameId===e.id&&(t.status==="working"||t.status==="queued")&&!t.inBatch);function Us(e,t,n){const a=Pi(t),i=t.kind==="folder"&&gl(e),s=!!a&&i;e.el.classList.toggle("empty",i&&!a&&!!(()=>{try{return e.iframe.contentDocument?.querySelector('meta[name="loop-empty"]')}catch{return null}})()),s&&(e.fromEmpty=!0,B?.prompt&&B.frameId===t.id&&te()),a||(e.fromEmpty=!1);let o=e.el.querySelector(":scope > .frame-body > .making");if(!s){o&&!o.classList.contains("out")&&(o.classList.add("out"),setTimeout(()=>o.remove(),400));return}if(!o){o=document.createElement("div"),o.className="making";const r=t.source?`/__loop/api/site-icon?u=${encodeURIComponent(t.source)}`:null;o.innerHTML=`<div class="mk-mid"><span class="mk-icon">${r?`<img src="${r}" alt="" onerror="this.replaceWith(Object.assign(document.createElement('i'),{className:'mk-spark'}))">`:'<i class="mk-spark"></i>'}</span><span class="mk-step"></span>${t.source?`<span class="mk-from">${L(cs(t.source))}</span>`:""}</div>`,e.el.querySelector(".frame-body").appendChild(o)}$e(o.querySelector(".mk-step"),n?.step&&!/^(Working…|Reading your comment…|Your chat picked this up)$/.test(n.step)?n.step:a.status==="queued"?"Waiting to start":t.source?"Reading the design":"Designing the screen")}function yl(e,t){if(t.kind!=="folder")return;if(!e.fromEmpty||!Pi(t)){e.seen=null;return}let n;try{n=e.iframe.contentDocument}catch{return}if(!n?.body)return;e.seen||=new Set;const a=r=>{const c=[];for(let l=r;l&&l!==n.body;l=l.parentElement)c.unshift(l.tagName+[...l.parentElement?.children||[]].indexOf(l));return c.join("/")},i=[];for(const r of n.body.querySelectorAll("body > *, body > * > *, body > * > * > *")){if(/^(SCRIPT|STYLE|LINK|META)$/.test(r.tagName))continue;const c=a(r);e.seen.has(c)||(e.seen.add(c),i.push(r))}const s=i.filter(r=>!i.includes(r.parentElement)).slice(0,40);if(!s.length)return;const o=n.createElement("style");o.textContent="@keyframes loopIn{from{opacity:0;transform:translateY(6px)}}.loop-in{animation:loopIn .45s cubic-bezier(.2,.8,.2,1) both}",n.head?.appendChild(o),s.forEach((r,c)=>{r.classList.add("loop-in"),r.style.animationDelay=`${Math.min(c*70,1400)}ms`,setTimeout(()=>{r.classList.remove("loop-in"),r.style.animationDelay="",r.getAttribute("style")||r.removeAttribute("style"),r.getAttribute("class")||r.removeAttribute("class")},600+Math.min(c*70,1400))})}const qi={claude:'<svg viewBox="0 0 24 24" aria-hidden="true"><path fill="#D97757" d="m4.7144 15.9555 4.7174-2.6471.079-.2307-.079-.1275h-.2307l-.7893-.0486-2.6956-.0729-2.3375-.0971-2.2646-.1214-.5707-.1215-.5343-.7042.0546-.3522.4797-.3218.686.0608 1.5179.1032 2.2767.1578 1.6514.0972 2.4468.255h.3886l.0546-.1579-.1336-.0971-.1032-.0972L6.973 9.8356l-2.55-1.6879-1.3356-.9714-.7225-.4918-.3643-.4614-.1578-1.0078.6557-.7225.8803.0607.2246.0607.8925.686 1.9064 1.4754 2.4893 1.8336.3643.3035.1457-.1032.0182-.0728-.164-.2733-1.3539-2.4467-1.445-2.4893-.6435-1.032-.17-.6194c-.0607-.255-.1032-.4674-.1032-.7285L6.287.1335 6.6997 0l.9957.1336.419.3642.6192 1.4147 1.0018 2.2282 1.5543 3.0296.4553.8985.2429.8318.091.255h.1579v-.1457l.1275-1.706.2368-2.0947.2307-2.6957.0789-.7589.3764-.9107.7468-.4918.5828.2793.4797.686-.0668.4433-.2853 1.8517-.5586 2.9021-.3643 1.9429h.2125l.2429-.2429.9835-1.3053 1.6514-2.0643.7286-.8196.85-.9046.5464-.4311h1.0321l.759 1.1293-.34 1.1657-1.0625 1.3478-.8804 1.1414-1.2628 1.7-.7893 1.36.0729.1093.1882-.0183 2.8535-.607 1.5421-.2794 1.8396-.3157.8318.3886.091.3946-.3278.8075-1.967.4857-2.3072.4614-3.4364.8136-.0425.0304.0486.0607 1.5482.1457.6618.0364h1.621l3.0175.2247.7892.522.4736.6376-.079.4857-1.2142.6193-1.6393-.3886-3.825-.9107-1.3113-.3279h-.1822v.1093l1.0929 1.0686 2.0035 1.8092 2.5075 2.3314.1275.5768-.3218.4554-.34-.0486-2.2039-1.6575-.85-.7468-1.9246-1.621h-.1275v.17l.4432.6496 2.3436 3.5214.1214 1.0807-.17.3521-.6071.2125-.6679-.1214-1.3721-1.9246L14.38 17.959l-1.1414-1.9428-.1397.079-.674 7.2552-.3156.3703-.7286.2793-.6071-.4614-.3218-.7468.3218-1.4753.3886-1.9246.3157-1.53.2853-1.9004.17-.6314-.0121-.0425-.1397.0182-1.4328 1.9672-2.1796 2.9446-1.7243 1.8456-.4128.164-.7164-.3704.0667-.6618.4008-.5889 2.386-3.0357 1.4389-1.882.929-1.0868-.0062-.1579h-.0546l-6.3385 4.1164-1.1293.1457-.4857-.4554.0608-.7467.2307-.2429 1.9064-1.3114Z"/></svg>',codex:'<svg viewBox="0 0 24 24" aria-hidden="true"><path fill="currentColor" d="M22.2819 9.8211a5.9847 5.9847 0 0 0-.5157-4.9108 6.0462 6.0462 0 0 0-6.5098-2.9A6.0651 6.0651 0 0 0 4.9807 4.1818a5.9847 5.9847 0 0 0-3.9977 2.9 6.0462 6.0462 0 0 0 .7427 7.0966 5.98 5.98 0 0 0 .511 4.9107 6.051 6.051 0 0 0 6.5146 2.9001A5.9847 5.9847 0 0 0 13.2599 24a6.0557 6.0557 0 0 0 5.7718-4.2058 5.9894 5.9894 0 0 0 3.9977-2.9001 6.0557 6.0557 0 0 0-.7475-7.0729zm-9.022 12.6081a4.4755 4.4755 0 0 1-2.8764-1.0408l.1419-.0804 4.7783-2.7582a.7948.7948 0 0 0 .3927-.6813v-6.7369l2.02 1.1686a.071.071 0 0 1 .038.052v5.5826a4.504 4.504 0 0 1-4.4945 4.4944zm-9.6607-4.1254a4.4708 4.4708 0 0 1-.5346-3.0137l.142.0852 4.783 2.7582a.7712.7712 0 0 0 .7806 0l5.8428-3.3685v2.3324a.0804.0804 0 0 1-.0332.0615L9.74 19.9502a4.4992 4.4992 0 0 1-6.1408-1.6464zM2.3408 7.8956a4.485 4.485 0 0 1 2.3655-1.9728V11.6a.7664.7664 0 0 0 .3879.6765l5.8144 3.3543-2.0201 1.1685a.0757.0757 0 0 1-.071 0l-4.8303-2.7865A4.504 4.504 0 0 1 2.3408 7.872zm16.5963 3.8558L13.1038 8.364 15.1192 7.2a.0757.0757 0 0 1 .071 0l4.8303 2.7913a4.4944 4.4944 0 0 1-.6765 8.1042v-5.6772a.79.79 0 0 0-.407-.667zm2.0107-3.0231l-.142-.0852-4.7735-2.7818a.7759.7759 0 0 0-.7854 0L9.409 9.2297V6.8974a.0662.0662 0 0 1 .0284-.0615l4.8303-2.7866a4.4992 4.4992 0 0 1 6.6802 4.66zM8.3065 12.863l-2.02-1.1638a.0804.0804 0 0 1-.038-.0567V6.0742a4.4992 4.4992 0 0 1 7.3757-3.4537l-.142.0805L8.704 5.459a.7948.7948 0 0 0-.3927.6813zm1.0976-2.3654l2.602-1.4998 2.6069 1.4998v2.9994l-2.5974 1.4997-2.6067-1.4997Z"/></svg>'};function bl(){return f.hostOnline===!1?"offline":f.agent.mode==="inbox"&&!f.chatListening?"away":"on"}function vl(){const e=m("#agent-pill"),t=Object.keys(f.live).length,n=f.agentBin==="codex"?"codex":"claude",a=f.comments.filter(C=>C.status==="queued").length,i=f.comments.filter(C=>C.status==="waiting").length,s=bl(),o=$()&&!X,r=f.agent.lastModel&&(n==="codex"?!/^claude/.test(f.agent.lastModel):/^claude/.test(f.agent.lastModel)),c=f.agentLabel||(n==="codex"?"Codex":"Claude Code"),l=e.querySelector(".agent-logo");l._r!==n&&(l._r=n,l.innerHTML=qi[n]);let d=s==="offline"?`${f.hostName||"Host"} is offline`:s==="away"?"Disconnected":t?`Working${t>1?` \xB7 ${t}`:""}`:a?`${a} queued`:f.agent.mode==="inbox"?"Connected":c;i&&$()&&!t&&(d=`${i} to review`),$e(m("#agent-label"),d),e.classList.toggle("busy",t>0),e.classList.toggle("away",s==="away"),e.classList.toggle("offline",s==="offline"),e.classList.toggle("say",s!=="on"||t>0||a>0||i>0&&$()),e._info={state:s,n:t,queued:a,waiting:i,who:c,runner:n,model:r?Zt(f.agent.lastModel):f.agent.chat?.model?Zt(f.agent.chat.model):null},delete e.dataset.tip;const u=s==="away"?`Your chat isn\u2019t listening. Comments run in the background meanwhile${t?` (${t} working)`:""}.`:s==="offline"?"Comments wait until the host is back":f.agent.mode==="inbox"?`Comments go to your chat \xB7 ${c}`:`${c} runs your comments${r?` \xB7 ${Zt(f.agent.lastModel)}`:""}`;e.classList.remove("inbox");{const C=f.agent.mode==="inbox"&&$()?f.chatContext:null,k=e.querySelector(".ctx-ring");if(k.toggleAttribute("hidden",!C),!C&&e._info&&delete e._info.ctx,C){const M=Math.max(0,Math.min(100,Math.round(C.used/C.window*100))),E=N=>N>=1e6?`${(N/1e6).toFixed(N%1e6?1:0)}M`:`${Math.round(N/1e3)}k`;k.querySelector(".cr-fill").style.strokeDasharray=`${M} 100`,e.classList.toggle("ctx-high",M>=80),e.classList.toggle("ctx-full",M>=95),e._info.ctx={pct:M,used:E(C.used),window:E(C.window)}}}const p=m("#reconnect-btn");p.hidden=!(s==="away"&&o),cc(s),Le&&!Le.hidden&&Ra(),document.querySelectorAll("#agent-menu .am-opt").forEach(C=>{C.classList.toggle("on",C.dataset.mode===f.agent.mode&&(!C.dataset.runner||C.dataset.runner===f.agentBin)),C.dataset.runner&&(C.hidden=f.runners&&!f.runners[C.dataset.runner]);const k=C.querySelector("[data-logo]");k&&!k.innerHTML&&(k.innerHTML=qi[k.dataset.logo])}),m("#agent-menu").hidden||Ra(),Ui(),wl();const h=m("#agent-allowed"),g=f.agent.allow||[],v=C=>C.startsWith("dir:")?`Files in ${C.slice(4)}`:/^Bash\((.*):\*\)$/.exec(C)?.[1]??C.replace(/^mcp__/,"").replace(/__/g," \xB7 "),T=g.length?`<button class="al-head" aria-expanded="${gn}"><span>Allowed on this canvas</span><span class="al-count">${g.length}</span><svg class="al-chev" viewBox="0 0 16 16" aria-hidden="true"><path d="M6 4l4 4-4 4"/></svg></button><div class="al-body"${gn?"":" hidden"}><div class="al-note">Reading files, copying them and making folders are always allowed.</div>${g.map(C=>`<div class="al-row"><code title="${L(C)}">${L(v(C))}</code><button data-disallow="${L(C)}" title="Stop allowing this">${Wn.x}</button></div>`).join("")}</div>`:"";h._h!==T&&(h._h=T,h.innerHTML=T,h.hidden=!g.length),m("#share-menu").hidden||Na()}function wl(){const e=m("#update-pill"),t=f.update;if(e.hidden=!t||!$()||!!X,e.hidden)return;const n=t.state==="updating"?'<span class="up-spin"></span>Updating\u2026':t.state==="queued"?"Updates when the agent finishes":t.state==="failed"?"Update failed \xB7 Retry":t.how==="next-start"?`Loop ${L(t.latest)} is ready next start`:`${A("up")}Update to ${L(t.latest)}`;e._h!==n&&(e._h=n,e.innerHTML=n),e.disabled=t.state==="updating"||t.state==="queued"||t.how==="next-start",e.classList.toggle("failed",t.state==="failed"),e.title=t.state==="failed"?`Couldn\u2019t update: ${t.error||"unknown error"}`:t.how==="next-start"?"Loop runs through npx here, so the new version is used the next time it starts":`Loop ${t.latest} is out (you have ${f.version}). Installs it and restarts Loop; your canvas stays exactly as it is.`}m("#update-pill").addEventListener("click",async()=>{try{await w("POST","/__loop/api/update")}catch(e){y(e.message)}});function Zs(e){return(e||"?").trim().split(/\s+/).map(t=>t[0]).join("").slice(0,2).toUpperCase()}function $a(){const e=[{name:U.name||"You",color:U.color},...ln.values()];m("#presence").innerHTML=e.length>1?e.slice(0,6).map((t,n)=>`<span class="avatar${n?"":" me"}" title="${L(n?t.name:`${t.name} (you) \xB7 click to change your name`)}">${As(t.name,t.color,"",t.avatar)}</span>`).join(""):""}function Gs(){const e=new Set;for(const t of ln.values()){e.add(t.id);let n=xi.querySelector(`[data-id="${CSS.escape(t.id)}"]`);n||(n=document.createElement("div"),n.className="cursor",n.dataset.id=t.id,n.innerHTML=`<div class="cursor-inner"><svg viewBox="0 0 18 18"><path d="M2 1.5l13 6.2-5.6 1.5-2.4 5.6z" fill="${L(t.color)}" stroke="#fff" stroke-width="1.4" stroke-linejoin="round"/></svg><span style="background:${L(t.color)}">${L(t.name)}</span></div>`,xi.appendChild(n)),n.style.transform=`translate(${t.x}px, ${t.y}px)`}xi.querySelectorAll(".cursor").forEach(t=>{e.has(t.dataset.id)||t.remove()})}let Qs=0;function xl(e,t){const n=Date.now();if(n-Qs<70||!f)return;Qs=n;const a=re(e,t);w("POST","/__loop/api/presence",{id:U.id,name:U.name||"Guest",color:U.color,avatar:U.avatar,x:a.x,y:a.y}).catch(()=>{})}addEventListener("beforeunload",()=>!X&&navigator.sendBeacon?.("/__loop/api/presence",new Blob([JSON.stringify({id:U.id,leave:!0})],{type:"application/json"})));function Di(e){if(e.length<4)return`M${e[0]} ${e[1]}l.01 0`;let t=`M${e[0]} ${e[1]}`;for(let n=2;n<e.length-2;n+=2)t+=`Q${e[n]} ${e[n+1]} ${(e[n]+e[n+2])/2} ${(e[n+1]+e[n+3])/2}`;return t+`L${e[e.length-2]} ${e[e.length-1]}`}const Vt=new Set;let dn=null;function Ii(e){const t=new Set(f.comments.find(n=>n.id===e)?.inkStrokes||[]);for(const n of Object.values(f.live||{})){const a=f.comments.find(i=>i.id===n.commentId);if(a&&(a.parentId||a.id)===e)for(const i of a.inkStrokes||[])t.add(i)}return[...t].filter(n=>f.strokes.some(a=>a.id===n))}function kl(){const e=new Set(B?.inkStrokes||[]);for(const t of Object.values(f.live||{}))for(const n of f.comments.find(a=>a.id===t.commentId)?.inkStrokes||[])e.add(n);for(const t of Object.values(f.live||{})){const n=f.comments.find(i=>i.id===t.commentId),a=n&&f.comments.find(i=>i.id===n.parentId);for(const i of a?.inkStrokes||[])e.add(i)}return e}function Js(e){if(e.fx==null||!e.frameId)return{dx:0,dy:0};const t=f.frames.find(a=>a.id===e.frameId);if(!t)return{dx:0,dy:0};const n=De(t);return{dx:n.x-e.fx,dy:n.y-e.fy}}const fn=e=>{const{dx:t,dy:n}=Js(e);return t||n?e.points.map((a,i)=>a+(i%2?n:t)):e.points};function eo(e){for(const t of f.strokes){if(e&&t.frameId!==e)continue;const{dx:n,dy:a}=Js(t),i=n||a?`translate(${n} ${a})`:"";kt.querySelectorAll(`path[data-id="${t.id}"], path[data-for="${t.id}"]`).forEach(s=>{(s.getAttribute("transform")||"")!==i&&(i?s.setAttribute("transform",i):s.removeAttribute("transform"))})}}function qt(){kt.querySelector("defs")||kt.insertAdjacentHTML("afterbegin",`<defs>
|
|
10
|
+
html.loop-touch img, html.loop-touch a { -webkit-user-drag: none; }`,(n.head||n.documentElement).appendChild(d),n.documentElement.classList.toggle("loop-touch",i())}catch{}const o=(d,u)=>{const p=n.scrollingElement||n.documentElement;for(let h=d?.nodeType===1?d:d?.parentElement;h&&h!==p&&h!==n.body;h=h.parentElement){const g=e.getComputedStyle(h),w=u==="x"?g.overflowX:g.overflowY;if(/(auto|scroll|overlay)/.test(w)&&(u==="x"?h.scrollWidth-h.clientWidth:h.scrollHeight-h.clientHeight)>1)return h}return p},r=(d,u,p)=>{d&&(u||p)&&d.scrollTo({left:d.scrollLeft+u,top:d.scrollTop+p,behavior:"instant"})},l=d=>{try{return e.getComputedStyle(d).scrollSnapType!=="none"}catch{return!1}};e.addEventListener("pointerdown",d=>{if(cancelAnimationFrame(s),!i()||d.pointerType!=="mouse"||d.button!==0||d.target.closest?.('input, textarea, select, [contenteditable=""], [contenteditable="true"], [draggable="true"]'))return;let u="auto";for(let p=d.target;p&&p.nodeType===1;p=p.parentElement){const h=e.getComputedStyle(p).touchAction;if(h&&h!=="auto"){u=h;break}}u!=="none"&&(a={x:d.clientX,y:d.clientY,lx:d.clientX,ly:d.clientY,lt:performance.now(),vx:0,vy:0,moved:!1,target:d.target,sx:null,sy:null,ax:!/pan-y/.test(u)||/pan-x/.test(u),ay:!/pan-x/.test(u)||/pan-y/.test(u)})},!0),e.addEventListener("pointermove",d=>{if(!a)return;if(!(d.buttons&1))return c();if(!a.moved){if(Math.hypot(d.clientX-a.x,d.clientY-a.y)<6)return;a.moved=!0,a.sx=o(a.target,"x"),a.sy=o(a.target,"y"),e.getSelection?.()?.removeAllRanges()}const u=a.ax?d.clientX-a.lx:0,p=a.ay?d.clientY-a.ly:0,h=performance.now(),g=Math.max(1,h-a.lt);a.sx===a.sy?r(a.sx,-u,-p):(r(a.sx,-u,0),r(a.sy,0,-p)),a.vx=.7*(u/g*16)+.3*a.vx,a.vy=.7*(p/g*16)+.3*a.vy,a.lx=d.clientX,a.ly=d.clientY,a.lt=h,(u||p)&&d.preventDefault()},!0);const c=()=>{const d=a;if(a=null,!d?.moved)return;const u=w=>{w.stopPropagation(),w.preventDefault()};if(e.addEventListener("click",u,{capture:!0,once:!0}),setTimeout(()=>e.removeEventListener("click",u,!0),80),performance.now()-d.lt>90)return;let p=l(d.sx)?0:d.vx,h=l(d.sy)?0:d.vy;const g=()=>{p*=.95,h*=.95,!(Math.abs(p)<.4&&Math.abs(h)<.4)&&(d.sx===d.sy?r(d.sx,-p,-h):(r(d.sx,-p,0),r(d.sy,0,-h)),s=requestAnimationFrame(g))};s=requestAnimationFrame(g)};e.addEventListener("pointerup",c,!0),e.addEventListener("pointercancel",c,!0),e.addEventListener("blur",c),n.addEventListener("selectstart",d=>{a&&i()&&d.preventDefault()},!0),n.addEventListener("dragstart",d=>{i()&&!d.target.closest?.('[draggable="true"]')&&d.preventDefault()},!0)}function So(e,t,n){if(e.swapping){e.swapNext=n;return}e.swapping=!0;const a=document.createElement("iframe");a.title=e.iframe.title,a.dataset.src=e.iframe.dataset.src,a.className="incoming",a._incoming=!0,Eo(e,t,a),e.iframe.after(a),a.src=n,e.swapT=setTimeout(()=>{a._incoming&&a.dispatchEvent(new Event("load"))},5e3)}function pc(e){try{const t=e.iframe.contentWindow;return!!(t.document.querySelector('script[src*="/@vite/client"], nextjs-portal, script[src*="webpack-dev-server"], script[src*="hot-update"]')||t.__vite_plugin_react_preamble_installed__||t.$RefreshReg$||t.__webpack_hmr||t.parcelHotUpdate||Object.keys(t).some(a=>a.startsWith("webpackHotUpdate")))}catch{return!1}}function ee(e){if(!e)return;const t=qe(e),n=P.get(t.id)||fc(t),a=n.el.style,s=t.fill==="none"?"transparent":t.fill||"";(a.getPropertyValue("--fill")||"")!==s&&(s?a.setProperty("--fill",s):a.removeProperty("--fill")),n.el.classList.toggle("nofill",t.fill==="none"),a.left=`${t.x}px`,a.top=`${t.y}px`,a.width=`${t.w}px`,a.height=`${t.h}px`,a.setProperty("--fw",`${t.w}px`),a.setProperty("--fwn",t.w),a.setProperty("--fhn",t.h);{const c=hi(t),d=`Describe this ${c.what}`;a.setProperty("--pfs",`${c.fs}px`),a.setProperty("--pk",(c.fs/27).toFixed(3)),a.setProperty("--plx",`${c.lx*100}%`),a.setProperty("--pty",`${c.ty*100}%`),n.el.dataset.on!==c.on&&(n.el.dataset.on=c.on),Hc(n,t,c,d)}n.inkAt!==`${t.x},${t.y}`&&(n.inkAt=`${t.x},${t.y}`,Ho(t.id));const i=X?.frameSrc?.(t)||(t.kind==="folder"||t.kind==="frozen"?`/__loop/f/${t.id}/${encodeURIComponent(t.entry||"index.html")}`:t.src);n.iframe.dataset.src!==i&&(n.iframe.dataset.src=i,n.resume=null,n.parked||(n.iframe.src=i)),$e(n.hint.firstChild,t.name),n.el.classList.toggle("narrow",t.w*v.z<200),n.renaming||(n.name.textContent=t.name);{const c=Wf(t.id);n.builtTag||=Object.assign(document.createElement("span"),{className:"built-tag",textContent:"Built",title:"Built into the project"}),c&&!n.builtTag.isConnected?n.name.after(n.builtTag):!c&&n.builtTag.isConnected&&n.builtTag.remove()}n.kind.hidden=t.kind==="folder"||t.kind==="static"||t.kind==="frozen";const o=t.kind==="frozen";n.ic.dataset.k!==(o?"frozen":"live")&&(n.ic.dataset.k=o?"frozen":"live",n.ic.innerHTML=o?Ss:""),n.ic.dataset.tip=o?`Frozen ${new Date(t.frozenAt||t.createdAt).toLocaleString([],{month:"short",day:"numeric",hour:"numeric",minute:"2-digit"})}${t.from?` \xB7 from ${t.from.split("?")[0]}`:""}`:"Live",n.el.classList.toggle("is-frozen",o),ul(n,t),n.kind.textContent=t.kind==="route"&&!t.optionOf?(n.cur||t.src).split("?")[0]:"Live";{let c=null;if(t.kind==="url")try{c=new URL(t.src).origin}catch{}const d=!!c&&!!f.down?.includes(c);d!==!!n.down&&(n.down=d,n.el.classList.toggle("down",d),d?(n.downB||=n.el.querySelector(".down-hint b"),n.downB.textContent=`${c.replace(/^https?:\/\//,"")} isn\u2019t running`):!n.parked&&n.iframe.dataset.src&&(n.iframe.src=n.iframe.dataset.src))}const r=f.live[t.id],l=t.kind==="folder"&&!X?Ws(t.id).length:0;$e(n.count.lastChild,l&&!r?String(l+1):""),n.count.hidden=!l||!!r,n.el.classList.toggle("working",!!r),Tl(n,t);{const c=n.el.classList.contains("shapeless"),d=!!t.shapeless;c&&!d&&(n.el.classList.add("unfolding"),setTimeout(()=>n.el.classList.remove("unfolding"),900)),n.el.classList.toggle("shapeless",d)}if(Af(n,t),r){n.stopB||=n.el.querySelector(".frame-label .stop");const c=Object.keys(f.live).length>1;$e(n.stopB,c?"Stop all agents":"Stop"),n.stopB.title=c?"Stop every agent that is working":"Stop the agent"}n.el.classList.toggle("building",!!t.building),Po(n,t,r);{const c=k()&&!X&&f.agent.mode==="inbox"&&!f.chatListening&&f.comments.find(u=>u.frameId===t.id&&u.kind==="create"&&u.status==="queued"&&!u.background);let d=n.el.querySelector(":scope > .frame-body > .wait-pill");c&&!d&&(d=document.createElement("div"),d.className="wait-pill",n.el.querySelector(".frame-body").appendChild(d),d.addEventListener("pointerdown",u=>u.stopPropagation()),d.addEventListener("click",async u=>{const p=u.target.closest("button");if(p){p.disabled=!0,p.textContent="Starting\u2026";try{await x("POST",`/__loop/api/comments/${d.dataset.cid}/background`)}catch(h){y(h.message)}}})),d&&!c?d.remove():d&&d.dataset.cid!==c.id&&(d.dataset.cid=c.id,d.innerHTML=`<span>Chat isn\u2019t listening</span><button class="pin-act" title="Build it now in the background${f.chatHistory?", carrying on from a copy of that chat":" in a new session"}">${f.chatHistory?"Carry on here":"Run in new chat"}<kbd>${pt==="metaKey"?"\u2318":"Ctrl"}\u21B5</kbd></button>`)}if(n.el.classList.toggle("filling",t.building==="filling"),n.el.classList.toggle("in-section",(f.sections||[]).some(c=>Bn(so(c),t))),r){const c=f.comments.find(d=>d.id===r.commentId);$e(n.step,r.step||(c?.kind==="create"?"Building the frame\u2026":"Working\u2026")),$e(n.elapsed,Na(r.startedAt))}n.el.classList.toggle("selected",D===t.id||W.has(t.id)),n.el.classList.toggle("live",Ce?.fid===t.id||U==="select"&&Be&&!nn&&L?.frameId!==t.id),$e(n.dims.querySelector(".dz"),`${Math.round(t.w)} \xD7 ${Math.round(t.h)}`),n.dims.dataset.tip="Fill \xB7 size & device presets";{const c=n.dims.querySelector(".fill-dot i");c&&(c.style.background=t.fill&&t.fill!=="none"?t.fill:"",c.parentElement.classList.toggle("is-none",t.fill==="none"))}if(Ze===t.id){const c=za===t.id;Ze=za=null,queueMicrotask(()=>{S||(Q(t.id),zt(t.id),c&&setTimeout(()=>ea(t.id),340))})}}function Na(e){const t=Math.max(0,Math.round((Date.now()-e)/1e3));return t<60?`${t}s`:`${Math.floor(t/60)}m ${String(t%60).padStart(2,"0")}s`}setInterval(()=>{if(!f)return;for(const[n,a]of Object.entries(f.live)){const s=P.get(n);s&&(s.elapsed.textContent=Na(a.startedAt))}document.querySelectorAll("[data-elapsed-from]").forEach(n=>$e(n,Na(+n.dataset.elapsedFrom)));const e=Date.now();let t=!1;for(const[n,a]of yn)e-a.t>15e3&&(yn.delete(n),t=!0);t&&(qo(),Fa())},1e3);function mc(e){const t=P.get(e);if(!t)return;try{const s=t.iframe.contentWindow;t.restore={sx:s.scrollX,sy:s.scrollY}}catch{t.restore=null}if(t.rev=(t.rev||0)+1,t.parked){t.resume=null,Mo(t);return}const n=t.iframe.dataset.src,a=f.frames.find(s=>s.id===e);if(!(a?.kind==="static"||a?.kind==="frozen"))if(a?.kind==="folder")So(t,a,`${n}?_m=${Date.now()}`);else if(a?.kind==="route"){if(pc(t))return;try{t.iframe.contentWindow.location.reload()}catch{t.iframe.src=n}}else try{t.iframe.contentWindow.location.reload()}catch{t.iframe.src=n}}const ve=document.createElement("div");ve.id="done",ve.hidden=!0,document.body.appendChild(ve);let Ba=0;const To=document.title;function Ao(e){try{const t=Ao.ac||=new(window.AudioContext||window.webkitAudioContext),n=t.currentTime;for(const[a,s]of(e?[440,330]:[660,990]).entries()){const i=t.createOscillator(),o=t.createGain();i.type="sine",i.frequency.value=s,i.connect(o),o.connect(t.destination),o.gain.setValueAtTime(0,n+a*.11),o.gain.linearRampToValueAtTime(.06,n+a*.11+.02),o.gain.exponentialRampToValueAtTime(1e-4,n+a*.11+.5),i.start(n+a*.11),i.stop(n+a*.11+.55)}}catch{}}function hc(e){const t=f.frames.find(s=>s.id===e);if(!t)return!1;const n=en(t);return Math.max(0,Math.min(n.l+n.w,innerWidth)-Math.max(n.l,0))*Math.max(0,Math.min(n.t+n.h,innerHeight)-Math.max(n.t,0))>n.w*n.h*.4&&n.w>120}function gc(e,t,n){if(!k()||X||!f)return;const a=document.hidden;if(!a&&hc(e))return;const i=f.frames.find(c=>c.id===e),o=f.comments.find(c=>c.id===t),r=n==="error",l=e===le?"the canvas":i?.name||"a frame";Ao(r),a&&(Ba++,document.title=`(${Ba}) ${To}`),ve.innerHTML=`<span class="dn-ic${r?" err":""}">${A(r?"x":"check","s")}</span><span class="dn-text"><b>${r?"Failed":"Done"}</b> \xB7 ${C(l)}</span><button class="dn-go">Go there</button><button class="dn-x" title="Dismiss">${A("x","s")}</button>`,ve.dataset.fid=e,ve.dataset.cid=t||"",ve.hidden=!1,ve.classList.remove("in"),ve.offsetWidth,ve.classList.add("in"),clearTimeout(ve._t),ve._t=setTimeout(()=>{ve.hidden=!0},9e3)}ve.addEventListener("click",e=>{if(e.target.closest(".dn-x")){ve.hidden=!0;return}if(!e.target.closest(".dn-go"))return;ve.hidden=!0;const t=f.comments.find(n=>n.id===ve.dataset.cid);t?$i(f.comments.find(n=>n.id===(t.parentId||t.id))||t,!0):ve.dataset.fid&&ve.dataset.fid!==le&&(Q(ve.dataset.fid),Oe(!0,[ve.dataset.fid]))}),document.addEventListener("visibilitychange",()=>{!document.hidden&&Ba&&(Ba=0,document.title=To)});function yc(e,t,n){const a=P.get(e);!a||!t||(a.updated.textContent=t,a.el.classList.remove("updated","failed"),a.el.offsetWidth,a.el.classList.add(n?"failed":"updated"),clearTimeout(a.flashT),a.flashT=setTimeout(()=>a.el.classList.remove("updated","failed"),4200))}function _o(e,t,n){e.textContent=t;try{e.contentEditable="plaintext-only"}catch{}e.contentEditable!=="plaintext-only"&&(e.contentEditable="true"),e.classList.add("editing-name"),e.spellcheck=!1,e.focus();const a=document.createRange();a.selectNodeContents(e);const s=getSelection();s.removeAllRanges(),s.addRange(a);let i=!1;const o=l=>{if(i)return;i=!0;const c=e.textContent.replace(/\s+/g," ").trim();e.contentEditable="false",e.removeAttribute("contenteditable"),e.classList.remove("editing-name"),e.textContent=l&&c?c:t,getSelection().removeAllRanges(),n(l&&c&&c!==t?c:null)},r=l=>l.stopPropagation();e.addEventListener("pointerdown",r),e.addEventListener("dblclick",r),e.addEventListener("keydown",l=>{l.stopPropagation(),l.key==="Enter"&&(l.preventDefault(),o(!0)),l.key==="Escape"&&(l.preventDefault(),o(!1))}),e.addEventListener("paste",l=>{l.preventDefault(),document.execCommand("insertText",!1,(l.clipboardData?.getData("text/plain")||"").replace(/\s+/g," "))}),e.addEventListener("blur",()=>{o(!0),e.removeEventListener("pointerdown",r),e.removeEventListener("dblclick",r)},{once:!0})}function ri(e){const t=P.get(e),n=f.frames.find(a=>a.id===e);!t||!n||(t.renaming=!0,_o(t.name,n.name,a=>{if(t.renaming=!1,a){const s=n.name;x("PATCH",`/__loop/api/frames/${e}`,{name:a}),J("Rename frame",()=>Ut(e,{name:s}),()=>Ut(e,{name:a}))}}))}function bc(e){try{const t=e.iframe.contentDocument;return!!t?.querySelector('meta[name="loop-placeholder"], meta[name="loop-empty"]')||!!t&&t.readyState==="complete"&&!t.body?.children.length&&/waiting for the agent/.test(t.body?.textContent||"")}catch{return!1}}const li=e=>f.comments.find(t=>t.frameId===e.id&&(t.status==="working"||t.status==="queued")&&!t.inBatch);function Po(e,t,n){const a=li(t),s=t.kind==="folder"&&bc(e),i=!!a&&s;e.el.classList.toggle("empty",s&&!a&&!!(()=>{try{return e.iframe.contentDocument?.querySelector('meta[name="loop-empty"]')}catch{return null}})()),i&&(e.fromEmpty=!0,O?.prompt&&O.frameId===t.id&&ae()),a||(e.fromEmpty=!1);let o=e.el.querySelector(":scope > .frame-body > .making");if(e.el.classList.toggle("is-making",i),!i){o&&!o.classList.contains("out")&&(o.classList.add("out"),setTimeout(()=>o.remove(),400));return}if(!o){o=document.createElement("div"),o.className="making";const r=t.source?`/__loop/api/site-icon?u=${encodeURIComponent(t.source)}`:null;o.innerHTML=`<div class="mk-mid">${r?`<img class="mk-icon" src="${r}&v=2" alt="" onerror="this.remove()">`:""}<span class="mk-step"></span>${t.source?`<span class="mk-from">${C(Wi(t.source))}</span>`:""}</div>`,o.insertAdjacentHTML("afterbegin",'<div class="area working whole show mk-work"></div>'),e.el.querySelector(".frame-body").appendChild(o),ni()}$e(o.querySelector(".mk-step"),n?.step&&!/^(Working…|Reading your comment…|Your chat picked this up)$/.test(n.step)?n.step:a.status==="queued"?"Waiting to start":t.source?"Reading the design":"Designing the screen")}function vc(e,t){if(t.kind!=="folder")return;if(!e.fromEmpty||!li(t)){e.seen=null;return}let n;try{n=e.iframe.contentDocument}catch{return}if(!n?.body)return;e.seen||=new Set;const a=r=>{const l=[];for(let c=r;c&&c!==n.body;c=c.parentElement)l.unshift(c.tagName+[...c.parentElement?.children||[]].indexOf(c));return l.join("/")},s=[];for(const r of n.body.querySelectorAll("body > *, body > * > *, body > * > * > *")){if(/^(SCRIPT|STYLE|LINK|META)$/.test(r.tagName))continue;const l=a(r);e.seen.has(l)||(e.seen.add(l),s.push(r))}const i=s.filter(r=>!s.includes(r.parentElement)).slice(0,40);if(!i.length)return;const o=n.createElement("style");o.textContent="@keyframes loopIn{from{opacity:0;transform:translateY(6px)}}.loop-in{animation:loopIn .45s cubic-bezier(.2,.8,.2,1) both}",n.head?.appendChild(o),i.forEach((r,l)=>{r.classList.add("loop-in"),r.style.animationDelay=`${Math.min(l*70,1400)}ms`,setTimeout(()=>{r.classList.remove("loop-in"),r.style.animationDelay="",r.getAttribute("style")||r.removeAttribute("style"),r.getAttribute("class")||r.removeAttribute("class")},600+Math.min(l*70,1400))})}const ci={claude:'<svg viewBox="0 0 24 24" aria-hidden="true"><path fill="#D97757" d="m4.7144 15.9555 4.7174-2.6471.079-.2307-.079-.1275h-.2307l-.7893-.0486-2.6956-.0729-2.3375-.0971-2.2646-.1214-.5707-.1215-.5343-.7042.0546-.3522.4797-.3218.686.0608 1.5179.1032 2.2767.1578 1.6514.0972 2.4468.255h.3886l.0546-.1579-.1336-.0971-.1032-.0972L6.973 9.8356l-2.55-1.6879-1.3356-.9714-.7225-.4918-.3643-.4614-.1578-1.0078.6557-.7225.8803.0607.2246.0607.8925.686 1.9064 1.4754 2.4893 1.8336.3643.3035.1457-.1032.0182-.0728-.164-.2733-1.3539-2.4467-1.445-2.4893-.6435-1.032-.17-.6194c-.0607-.255-.1032-.4674-.1032-.7285L6.287.1335 6.6997 0l.9957.1336.419.3642.6192 1.4147 1.0018 2.2282 1.5543 3.0296.4553.8985.2429.8318.091.255h.1579v-.1457l.1275-1.706.2368-2.0947.2307-2.6957.0789-.7589.3764-.9107.7468-.4918.5828.2793.4797.686-.0668.4433-.2853 1.8517-.5586 2.9021-.3643 1.9429h.2125l.2429-.2429.9835-1.3053 1.6514-2.0643.7286-.8196.85-.9046.5464-.4311h1.0321l.759 1.1293-.34 1.1657-1.0625 1.3478-.8804 1.1414-1.2628 1.7-.7893 1.36.0729.1093.1882-.0183 2.8535-.607 1.5421-.2794 1.8396-.3157.8318.3886.091.3946-.3278.8075-1.967.4857-2.3072.4614-3.4364.8136-.0425.0304.0486.0607 1.5482.1457.6618.0364h1.621l3.0175.2247.7892.522.4736.6376-.079.4857-1.2142.6193-1.6393-.3886-3.825-.9107-1.3113-.3279h-.1822v.1093l1.0929 1.0686 2.0035 1.8092 2.5075 2.3314.1275.5768-.3218.4554-.34-.0486-2.2039-1.6575-.85-.7468-1.9246-1.621h-.1275v.17l.4432.6496 2.3436 3.5214.1214 1.0807-.17.3521-.6071.2125-.6679-.1214-1.3721-1.9246L14.38 17.959l-1.1414-1.9428-.1397.079-.674 7.2552-.3156.3703-.7286.2793-.6071-.4614-.3218-.7468.3218-1.4753.3886-1.9246.3157-1.53.2853-1.9004.17-.6314-.0121-.0425-.1397.0182-1.4328 1.9672-2.1796 2.9446-1.7243 1.8456-.4128.164-.7164-.3704.0667-.6618.4008-.5889 2.386-3.0357 1.4389-1.882.929-1.0868-.0062-.1579h-.0546l-6.3385 4.1164-1.1293.1457-.4857-.4554.0608-.7467.2307-.2429 1.9064-1.3114Z"/></svg>',codex:'<svg viewBox="0 0 24 24" aria-hidden="true"><path fill="currentColor" d="M22.2819 9.8211a5.9847 5.9847 0 0 0-.5157-4.9108 6.0462 6.0462 0 0 0-6.5098-2.9A6.0651 6.0651 0 0 0 4.9807 4.1818a5.9847 5.9847 0 0 0-3.9977 2.9 6.0462 6.0462 0 0 0 .7427 7.0966 5.98 5.98 0 0 0 .511 4.9107 6.051 6.051 0 0 0 6.5146 2.9001A5.9847 5.9847 0 0 0 13.2599 24a6.0557 6.0557 0 0 0 5.7718-4.2058 5.9894 5.9894 0 0 0 3.9977-2.9001 6.0557 6.0557 0 0 0-.7475-7.0729zm-9.022 12.6081a4.4755 4.4755 0 0 1-2.8764-1.0408l.1419-.0804 4.7783-2.7582a.7948.7948 0 0 0 .3927-.6813v-6.7369l2.02 1.1686a.071.071 0 0 1 .038.052v5.5826a4.504 4.504 0 0 1-4.4945 4.4944zm-9.6607-4.1254a4.4708 4.4708 0 0 1-.5346-3.0137l.142.0852 4.783 2.7582a.7712.7712 0 0 0 .7806 0l5.8428-3.3685v2.3324a.0804.0804 0 0 1-.0332.0615L9.74 19.9502a4.4992 4.4992 0 0 1-6.1408-1.6464zM2.3408 7.8956a4.485 4.485 0 0 1 2.3655-1.9728V11.6a.7664.7664 0 0 0 .3879.6765l5.8144 3.3543-2.0201 1.1685a.0757.0757 0 0 1-.071 0l-4.8303-2.7865A4.504 4.504 0 0 1 2.3408 7.872zm16.5963 3.8558L13.1038 8.364 15.1192 7.2a.0757.0757 0 0 1 .071 0l4.8303 2.7913a4.4944 4.4944 0 0 1-.6765 8.1042v-5.6772a.79.79 0 0 0-.407-.667zm2.0107-3.0231l-.142-.0852-4.7735-2.7818a.7759.7759 0 0 0-.7854 0L9.409 9.2297V6.8974a.0662.0662 0 0 1 .0284-.0615l4.8303-2.7866a4.4992 4.4992 0 0 1 6.6802 4.66zM8.3065 12.863l-2.02-1.1638a.0804.0804 0 0 1-.038-.0567V6.0742a4.4992 4.4992 0 0 1 7.3757-3.4537l-.142.0805L8.704 5.459a.7948.7948 0 0 0-.3927.6813zm1.0976-2.3654l2.602-1.4998 2.6069 1.4998v2.9994l-2.5974 1.4997-2.6067-1.4997Z"/></svg>'};function wc(){return f.hostOnline===!1?"offline":f.agent.mode==="inbox"&&!f.chatListening?"away":"on"}function xc(){const e=m("#agent-pill"),t=Object.keys(f.live).length,n=f.agentBin==="codex"?"codex":"claude",a=f.comments.filter($=>$.status==="queued").length,s=f.comments.filter($=>$.status==="waiting").length,i=wc(),o=k()&&!X,r=f.agent.lastModel&&(n==="codex"?!/^claude/.test(f.agent.lastModel):/^claude/.test(f.agent.lastModel)),l=f.agentLabel||(n==="codex"?"Codex":"Claude Code"),c=e.querySelector(".agent-logo");c._r!==n&&(c._r=n,c.innerHTML=ci[n]);let d=i==="offline"?`${f.hostName||"Host"} is offline`:i==="away"?"Disconnected":t?`Working${t>1?` \xB7 ${t}`:""}`:a?`${a} queued`:f.agent.mode==="inbox"?"Connected":l;s&&k()&&!t&&(d=`${s} to review`),$e(m("#agent-label"),d),e.classList.toggle("busy",t>0),e.classList.toggle("away",i==="away"),e.classList.toggle("offline",i==="offline"),e.classList.toggle("say",i!=="on"||t>0||a>0||s>0&&k()),e._info={state:i,n:t,queued:a,waiting:s,who:l,runner:n,model:f.agent.mode==="inbox"?rn(f.chatContext?.model||f.agent.chat?.model)||null:rn(f.models?.model||r&&f.agent.lastModel)||null},delete e.dataset.tip;const u=i==="away"?`Your chat isn\u2019t listening. Comments run in the background meanwhile${t?` (${t} working)`:""}.`:i==="offline"?"Comments wait until the host is back":f.agent.mode==="inbox"?`Comments go to your chat \xB7 ${l}`:`${l} runs your comments${r?` \xB7 ${rn(f.agent.lastModel)}`:""}`;e.classList.remove("inbox");{const $=f.agent.mode==="inbox"&&k()?f.chatContext:null,b=e.querySelector(".ctx-ring");if(b.toggleAttribute("hidden",!$),!$&&e._info&&delete e._info.ctx,$){const M=$.compacted?0:Math.max(0,Math.min(100,Math.round($.used/$.window*100))),E=z=>z>=1e6?`${(z/1e6).toFixed(z%1e6?1:0)}M`:`${Math.round(z/1e3)}k`;b.querySelector(".cr-fill").style.strokeDasharray=`${M} 100`,e.classList.toggle("ctx-high",M>=80),e.classList.toggle("ctx-full",M>=95),e._info.ctx={pct:M,used:E($.used),window:E($.window),compacted:!!$.compacted}}else e.classList.remove("ctx-high","ctx-full")}ss();const p=m("#reconnect-btn");p.hidden=!(i==="away"&&o),pd(i),document.querySelectorAll("#agent-menu .am-opt").forEach($=>{$.classList.toggle("on",$.dataset.mode===f.agent.mode&&(!$.dataset.runner||$.dataset.runner===f.agentBin)),$.dataset.runner&&($.hidden=f.runners&&!f.runners[$.dataset.runner]);const b=$.querySelector("[data-logo]");b&&!b.innerHTML&&(b.innerHTML=ci[b.dataset.logo])}),m("#agent-menu").hidden||Ti(),Mi(),kc();const h=m("#agent-allowed"),g=f.agent.allow||[],w=$=>$.startsWith("dir:")?`Files in ${$.slice(4)}`:/^Bash\((.*):\*\)$/.exec($)?.[1]??$.replace(/^mcp__/,"").replace(/__/g," \xB7 "),T=g.length?`<button class="al-head" aria-expanded="${En}"><span>Allowed on this canvas</span><span class="al-count">${g.length}</span><svg class="al-chev" viewBox="0 0 16 16" aria-hidden="true"><path d="M6 4l4 4-4 4"/></svg></button><div class="al-body"${En?"":" hidden"}><div class="al-note">Reading files, copying them and making folders are always allowed.</div>${g.map($=>`<div class="al-row"><code title="${C($)}">${C(w($))}</code><button data-disallow="${C($)}" title="Stop allowing this">${aa.x}</button></div>`).join("")}</div>`:"";h._h!==T&&(h._h=T,h.innerHTML=T,h.hidden=!g.length),m("#share-menu").hidden||is()}function kc(){const e=m("#update-pill"),t=f.update;if(e.hidden=!t||!k()||!!X,e.hidden)return;const n=t.state==="updating"?'<span class="up-spin"></span>Updating\u2026':t.state==="queued"?"Updates when the agent finishes":t.state==="failed"?"Update failed \xB7 Retry":t.how==="next-start"?`Loop ${C(t.latest)} is ready next start`:`${A("up")}Update to ${C(t.latest)}`;e._h!==n&&(e._h=n,e.innerHTML=n),e.disabled=t.state==="updating"||t.state==="queued"||t.how==="next-start",e.classList.toggle("failed",t.state==="failed"),e.title=t.state==="failed"?`Couldn\u2019t update: ${t.error||"unknown error"}`:t.how==="next-start"?"Loop runs through npx here, so the new version is used the next time it starts":`Loop ${t.latest} is out (you have ${f.version}). Installs it and restarts Loop; your canvas stays exactly as it is.`}m("#update-pill").addEventListener("click",async()=>{try{await x("POST","/__loop/api/update")}catch(e){y(e.message)}});function Do(e){return(e||"?").trim().split(/\s+/).map(t=>t[0]).join("").slice(0,2).toUpperCase()}function Fa(){const e=[{name:Z.name||"You",color:Z.color},...yn.values()];m("#presence").innerHTML=e.length>1?e.slice(0,6).map((t,n)=>`<span class="avatar${n?"":" me"}" title="${C(n?t.name:`${t.name} (you) \xB7 click to change your name`)}">${mo(t.name,t.color,"",t.avatar)}</span>`).join(""):""}function qo(){const e=new Set;for(const t of yn.values()){e.add(t.id);let n=Xs.querySelector(`[data-id="${CSS.escape(t.id)}"]`);n||(n=document.createElement("div"),n.className="cursor",n.dataset.id=t.id,n.innerHTML=`<div class="cursor-inner"><svg viewBox="0 0 18 18"><path d="M2 1.5l13 6.2-5.6 1.5-2.4 5.6z" fill="${C(t.color)}" stroke="#fff" stroke-width="1.4" stroke-linejoin="round"/></svg><span style="background:${C(t.color)}">${C(t.name)}</span></div>`,Xs.appendChild(n)),n.style.transform=`translate(${t.x}px, ${t.y}px)`}Xs.querySelectorAll(".cursor").forEach(t=>{e.has(t.dataset.id)||t.remove()})}let Io=0;function $c(e,t){const n=Date.now();if(n-Io<70||!f)return;Io=n;const a=fe(e,t);x("POST","/__loop/api/presence",{id:Z.id,name:Z.name||"Guest",color:Z.color,avatar:Z.avatar,x:a.x,y:a.y}).catch(()=>{})}addEventListener("beforeunload",()=>!X&&navigator.sendBeacon?.("/__loop/api/presence",new Blob([JSON.stringify({id:Z.id,leave:!0})],{type:"application/json"})));function di(e){if(e.length<4)return`M${e[0]} ${e[1]}l.01 0`;let t=`M${e[0]} ${e[1]}`;for(let n=2;n<e.length-2;n+=2)t+=`Q${e[n]} ${e[n+1]} ${(e[n]+e[n+2])/2} ${(e[n+1]+e[n+3])/2}`;return t+`L${e[e.length-2]} ${e[e.length-1]}`}const an=new Set;let vn=null;function fi(e){const t=new Set(f.comments.find(n=>n.id===e)?.inkStrokes||[]);for(const n of Object.values(f.live||{})){const a=f.comments.find(s=>s.id===n.commentId);if(a&&(a.parentId||a.id)===e)for(const s of a.inkStrokes||[])t.add(s)}return[...t].filter(n=>f.strokes.some(a=>a.id===n))}function Lc(){const e=new Set(O?.inkStrokes||[]);for(const t of Object.values(f.live||{}))for(const n of f.comments.find(a=>a.id===t.commentId)?.inkStrokes||[])e.add(n);for(const t of Object.values(f.live||{})){const n=f.comments.find(s=>s.id===t.commentId),a=n&&f.comments.find(s=>s.id===n.parentId);for(const s of a?.inkStrokes||[])e.add(s)}return e}function zo(e){if(e.fx==null||!e.frameId)return{dx:0,dy:0};const t=f.frames.find(a=>a.id===e.frameId);if(!t)return{dx:0,dy:0};const n=qe(t);return{dx:n.x-e.fx,dy:n.y-e.fy}}const wn=e=>{const{dx:t,dy:n}=zo(e);return t||n?e.points.map((a,s)=>a+(s%2?n:t)):e.points};function Ho(e){for(const t of f.strokes){if(e&&t.frameId!==e)continue;const{dx:n,dy:a}=zo(t),s=n||a?`translate(${n} ${a})`:"";At.querySelectorAll(`path[data-id="${t.id}"], path[data-for="${t.id}"]`).forEach(i=>{(i.getAttribute("transform")||"")!==s&&(s?i.setAttribute("transform",s):i.removeAttribute("transform"))})}}function Wt(){At.querySelector("defs")||At.insertAdjacentHTML("afterbegin",`<defs>
|
|
11
11
|
<filter id="aura-blur" x="-60%" y="-60%" width="220%" height="220%"><feGaussianBlur stdDeviation="10"/></filter>
|
|
12
12
|
<linearGradient id="aura-grad" x1="0" y1="0" x2="1" y2="0" spreadMethod="reflect">
|
|
13
13
|
<stop offset="0" stop-color="#7c98ff"/><stop offset=".45" stop-color="#c58bff"/><stop offset=".55" stop-color="#ffffff"/><stop offset="1" stop-color="#7cd4ff"/>
|
|
14
14
|
<animateTransform attributeName="gradientTransform" type="translate" from="-1 0" to="1 0" dur="2.4s" repeatCount="indefinite"/>
|
|
15
|
-
</linearGradient></defs><g class="auras"></g>`);const e=new Set([...
|
|
16
|
-
<button class="t-btn" data-pk="open" title="Open and reply">${
|
|
17
|
-
`)[0].replace(/[*_`#>]/g,"").trim()||t.step||"Working\u2026":""}function Sl(e){const t=f.live[e],n=Sa(e);if(!t||!n)return;const a=f.comments.find(o=>o.id===t.commentId)?.parentId||t.commentId,i=n.querySelector(`.pin[data-key="${a}"] .pl`);if(!i)return;const s=co(e);i.textContent!==s&&(i.textContent=s,(t.partial||"").trim()||(i.classList.remove("tick"),i.offsetWidth,i.classList.add("tick")))}async function Tl(e){const t=e.dataset.act,n=e.dataset.cid;if(!t||!n)return;if(t==="see")return Fn(e.dataset.key||n);delete e.dataset.act;const a=e.querySelector(".pl");a._h=null,a.textContent=t==="send"?"Sending\u2026":t==="allow"?"Allowed":"Starting\u2026";try{await w("POST",`/__loop/api/comments/${n}/${t}`,t==="allow"?{all:!0,i:f.comments.find(i=>i.id===n)?.blocked?.findIndex(i=>!i.allowed)}:void 0)}catch(i){y(i.message);const s=f.comments.find(o=>o.id===n)?.frameId;s&&Et(s)}}function Nn(){for(const e of f.frames)Et(e.id);Et(le)}function Sa(e){return e===le?m("#canvas-pins"):D.get(e)?.pins}function Ht(e){return e===le?m("#canvas-pins"):D.get(e)?.el.querySelector(".areas")}function Et(e){const t=Sa(e);if(!t)return;const n={pins:t},a=no(e),i=a.map((u,p)=>({key:u.id,n:p+1,c:u})).filter(u=>!u.c.resolved||j===u.key);B?.frameId===e&&!B.prompt&&i.push({key:"__draft",n:a.length+1,draft:!0});const s=new Set(i.map(u=>u.key));n.pins.querySelectorAll(".pin").forEach(u=>{s.has(u.dataset.key)||u.remove()});for(const u of i){let p=n.pins.querySelector(`.pin[data-key="${u.key}"]`);p||(p=document.createElement("div"),p.className="pin",p.dataset.key=u.key,p.innerHTML='<div class="pin-dot"><b class="pn"></b><svg class="pw" viewBox="0 0 16 16" aria-hidden="true"><circle cx="8" cy="8" r="5.5"/></svg><span class="pl"></span></div>',p.addEventListener("pointerdown",q=>q.stopPropagation()),u.draft||p.addEventListener("click",q=>{if(q.stopPropagation(),p.dataset.act&&q.target.closest(".pin-act"))return Tl(p);if(p.classList.contains("making")&&q.target.closest(".pl")){const ne=f.comments.find(R=>R.id===u.key);if(ne?.optionSection)return pi.delete(ne.optionSection),Ir(ne.optionSection)}Fn(u.key)}),p.addEventListener("pointerenter",()=>{Ht(e)?.querySelector(`.area[data-key="${u.key}"]`)?.classList.add("hover"),u.draft||Ll(u.key)}),p.addEventListener("pointerleave",()=>{ye!==u.key&&(Ht(e)?.querySelector(`.area[data-key="${u.key}"]`)?.classList.remove("hover"),clearTimeout(Ma))}),n.pins.appendChild(p));const h=p.querySelector(".pn"),g=!!u.c&&(u.c.author?.guest||!!u.c.author?.name&&u.c.author.name!==U.name);let v=u.draft?"draft":Ca(u.key);!u.draft&&v==="done"&&j===u.key&&Ds(u.key);const T=!u.draft&&v==="done"&&Jr(u.key);T?h._ck!==1&&(h._ck=1,h.innerHTML=nl):(h._ck&&(h._ck=0,h.textContent=""),$e(h,String(u.n)));const C=!u.draft&&f.frames.some(q=>q.building&&q.optionOf?.cid===u.key)&&!(v==="queued"&&f.agent.mode==="inbox"&&!f.chatListening);C&&v!=="working"&&(v="working");const k=lo.get(u.key);lo.set(u.key,v),k==="working"&&v!=="working"&&v!=="queued"&&(p._ended=v==="done"?T?null:"Done":v==="error"?"Failed":"Stopped",clearTimeout(p._endT),p._endT=setTimeout(()=>{p._ended=null,f&&Et(e)},2400));const M=p.querySelector(".pl"),E=!u.draft&&Xt(u.key).filter(q=>q.kind!=="note").pop(),N=!u.draft&&$()&&!X&&E&&(v==="queued"&&!E.local&&!E.background&&f.agent.mode==="inbox"&&!f.chatListening?f.chatHistory?{act:"background",say:"Chat isn\u2019t listening",btn:"Carry on here",tip:"The chat this was sent to isn\u2019t listening. Carry on in the background from a copy of that chat, with everything it knows. It also starts by itself in a moment."}:{act:"background",say:"Chat isn\u2019t listening",btn:"Run in new chat",tip:"The chat this was sent to isn\u2019t listening. Run it in a new session instead (without that chat\u2019s history). It also starts by itself in a moment."}:v==="waiting"?{act:"send",say:"Waiting for you",btn:"Send",tip:"Send this comment to the agent"}:(v==="done"||v==="error")&&Wi(E).length?Bl(E):null);if(N){p.dataset.act=N.act,p.dataset.cid=E.id;const q=`<span>${L(N.say)}</span><button class="pin-act" title="${L(N.tip)}">${L(N.btn)}${N.act==="background"?`<kbd>${rt==="metaKey"?"\u2318":"Ctrl"}\u21B5</kbd>`:""}</button>`;M._h!==q&&(M._h=q,M.innerHTML=q)}else p.dataset.act&&(delete p.dataset.act,M._h=null,M.textContent="");if(v==="working"){const q=f.live[e],ne=q&&(f.comments.find(R=>R.id===q.commentId)?.parentId||q.commentId)===u.key;$e(M,C?"Making options \u2192":ne?co(e):"Working\u2026")}else T&&!N?$e(M,"Done"):p._ended&&$e(M,p._ended);p.className=`pin ${v}${u.c?.resolved?" resolved":""}${j===u.key||u.draft?" active":""}${v==="working"?" talking":N?" talking needs":T?" talking done-new":p._ended?" talking ended":""}${p.classList.contains("carded")?" carded":""}${p.classList.contains("ping")?" ping":""}${p.classList.contains("low")?" low":""}${g?" theirs":""}${C?" making":""}`}const o=f.live[e]?.commentId,r=o&&(f.comments.find(u=>u.id===o)?.parentId||o),c=i.filter(u=>u.draft?B?.area:u.c?.anchor?.scope==="area"||u.c?.anchor?.area||u.key===r&&(u.c?.anchor?.scope==="elements"||u.c?.anchor?.scope==="frame"||Ii(u.key).length)),l=new Set(c.map(u=>u.key)),d=Ht(e);d.querySelectorAll(".area:not(.picking)").forEach(u=>{l.has(u.dataset.key)||u.remove()});for(const u of c){let p=d.querySelector(`.area[data-key="${u.key}"]`);p||(p=document.createElement("div"),p.dataset.key=u.key,d.prepend(p));const h=!u.draft&&u.key!==r&&Ca(u.key)==="queued";p.className=`area${u.draft?" draft show":""}${j===u.key?" show":""}${u.key===r?" show working":""}${h?" show queued":""}${u.c?.anchor?.scope==="frame"?" whole":""}${u.key===r&&Ii(u.key).length&&u.c?.anchor?.scope!=="area"&&!u.c?.anchor?.area?" inkbox":""}`}ut(e),c.some(u=>u.key===r)&&tl(),Hn()}function ut(e){const t=Sa(e);!t||!f||(x?.frameId===e&&Pe(),Ht(e)?.querySelectorAll(".area[data-key]").forEach(n=>{const a=n.dataset.key==="__draft"?B?.anchor:f.comments.find(c=>c.id===n.dataset.key)?.anchor;if(!a)return;if(a.scope==="frame"){const c=f.frames.find(l=>l.id===e);if(!c)return;Object.assign(n.style,{left:"0px",top:"0px",width:`${c.w}px`,height:`${c.h}px`});return}if(n.classList.contains("inkbox")){const c=Ii(n.dataset.key),l=f.frames.find(M=>M.id===e),d=l&&De(l),u=f.strokes.filter(M=>c.includes(M.id)).flatMap(M=>fn(M));if(!d||u.length<2){n.style.width="0";return}const p=u.filter((M,E)=>E%2===0).map(M=>M-d.x),h=u.filter((M,E)=>E%2).map(M=>M-d.y),g=12,v=Math.max(0,Math.min(...p)-g),T=Math.max(0,Math.min(...h)-g),C=Math.min(d.w,Math.max(...p)+g),k=Math.min(d.h,Math.max(...h)+g);Object.assign(n.style,{left:`${v}px`,top:`${T}px`,width:`${Math.max(0,C-v)}px`,height:`${Math.max(0,k-T)}px`});return}if(a.scope==="elements"){const c=de(e),l=(a.elements||[]).map(g=>{try{return c?.querySelector(g.selector)?.getBoundingClientRect()}catch{return null}}).filter(g=>g&&(g.width||g.height));if(!l.length){n.style.width="0";return}const d=Math.min(...l.map(g=>g.left)),u=Math.min(...l.map(g=>g.top)),p=Math.max(...l.map(g=>g.right)),h=Math.max(...l.map(g=>g.bottom));Object.assign(n.style,{left:`${d}px`,top:`${u}px`,width:`${p-d}px`,height:`${h-u}px`});return}const{x:i,y:s}=Rn(e,a),o=a.area?a.area.w:a.w,r=a.area?a.area.h:a.h;Object.assign(n.style,{left:`${i}px`,top:`${s}px`,width:`${o}px`,height:`${r}px`})}),t.querySelectorAll(".pin").forEach(n=>{const a=n.dataset.key==="__draft"?B?.anchor:f.comments.find(r=>r.id===n.dataset.key)?.anchor;if(!a){n.hidden=!0;return}const{x:i,y:s}=Rn(e,a);n.style.left=`${i}px`,n.style.top=`${s}px`;const o=f.frames.find(r=>r.id===e);n.hidden=!!o&&(i<-4||s<-4||i>o.w+4||s>o.h+4),n.classList.toggle("low",e!==le&&s*b.z<34*(parseFloat(getComputedStyle(document.documentElement).getPropertyValue("--lz"))||1))}),(B?.frameId===e||j&&f.comments.find(n=>n.id===j)?.frameId===e)&&_e())}function Ta(e,t,n){if(e===le)return{x:b.x+t*b.z,y:b.y+n*b.z};const a=De(f.frames.find(i=>i.id===e));return{x:b.x+(a.x+t)*b.z,y:b.y+(a.y+n)*b.z}}function fo(e,t,n,a){const i=e.offsetWidth||340,s=e.offsetHeight||140,o=28*(parseFloat(getComputedStyle(document.documentElement).getPropertyValue("--lz"))||1);let r=a?t+o+10:t+18,c=a?Math.min(a.top,n)-4:n-18;r+i>innerWidth-12&&(r=t-i-10),r=Math.max(12,Math.min(r,innerWidth-i-12)),c=Math.max(60,Math.min(c,innerHeight-s-76)),e.style.left=`${r}px`,e.style.top=`${c}px`}let zt=28;function uo(e,t,n,a,i){zt=28*(parseFloat(getComputedStyle(document.documentElement).getPropertyValue("--lz"))||1),i&&i.height>4&&(t=i.left,n=i.bottom,zt=i.height),a&&(e.style.maxHeight="");const s=e.offsetWidth||340;let o=e.offsetHeight||140;const r=n-56,c=innerHeight-12-(n-zt),l=innerWidth-12-t,d=t+zt-12;let u=a&&e._side;u&&(u[0]==="b"?o>r&&c>r:o>c&&r>c)&&(u=(u[0]==="b"?"t":"b")+u[1]);const p=a?o:Math.max(o,380);if(u||(u=(p<=r||r>=c?"b":"t")+(s<=l||l>=d?"l":"r")),a){e._side=u;const C=u[0]==="b"?r:c;o>C&&(e.style.maxHeight=`${Math.max(180,Math.floor(C))}px`,o=e.offsetHeight)}const h=u[1]==="l"?t:t+zt-s,g=u[0]==="b"?n-o:n-zt,v=Math.max(12,Math.min(h,innerWidth-s-12)),T=Math.max(56,Math.min(g,innerHeight-o-12));e.style.left=`${Math.round(v)}px`,e.style.top=`${Math.round(T)}px`,e.dataset.o=u,e.style.transformOrigin=`${Math.max(0,Math.min(s,t+zt/2-v))}px ${Math.max(0,Math.min(o,n-zt/2-T))}px`,e.classList.toggle("at-pin",u==="bl"&&v===h&&T===g),e._covers=v===h&&T===g}function Aa(){const e=new Set;j&&!z.hidden&&!z.classList.contains("docked")&&z._covers&&e.add(j),ye&&!ge.hidden&&ge._covers&&e.add(ye),document.querySelectorAll(".pin").forEach(t=>t.classList.toggle("carded",e.has(t.dataset.key)))}function _e(){if(f){if(Bt(),Zo(),B?.prompt&&!H.hidden){const e=De(f.frames.find(t=>t.id===B.frameId));if(e){const t=Ri(e),n=b.z,a=e.w*(1-2*t.lx)*n,i=Math.min(44,t.fs*n),s=D.get(e.id)?.el.querySelector(".frame-body"),o=!!s;if(H.classList.toggle("onpage",o),o)H.dataset.on=t.on,H.parentElement!==s&&(Ni(s),H.style.left=H.style.top=H.style.width=""),(H._pz!==n||H._pw!==e.w)&&(H._pz=n,H._pw=e.w,ot(W));else{Ni(document.body),H._pz=H._pw=null;const r=H.offsetWidth||380,c=H.offsetHeight||200,l=b.y+(e.y+e.h/2)*n;fo(H,b.x+(e.x+e.w)*n,l-c/2+18)}}}else if(B&&!H.hidden){const e=Rn(B.frameId,B.anchor),t=Ta(B.frameId,e.x,e.y);fo(H,t.x,t.y,Mt("__draft"))}if(j&&!z.hidden&&!z.classList.contains("docked")){const e=f.comments.find(t=>t.id===j);if(e?.anchor){const t=Rn(e.frameId,e.anchor),n=Ta(e.frameId,t.x,t.y);uo(z,n.x,n.y,!0,Mt(j)),z._grow&&(z._grow=!1,$l(z,Mt(j)))}}if(Aa(),Cn(),Ze){const e=Ta(Ze.frameId,Ze.lx,Ze.ly),t=m("#ink-chip");t.style.left=`${e.x+10}px`,t.style.top=`${e.y+10}px`}}}function Oi(e){return f.strokes.filter(t=>t.frameId===e&&!t.commentId&&_s.has(t.id))}function st(e,t,n,a,i){Ne&&jn(!0),ee(),Bn(),H.classList.remove("prompt"),Bi();const s=e===le?null:i?Hi(e,i.x+i.w/2,i.y+i.h/2):Hi(e,t,n),o=Oi(e);B={frameId:e,picked:s,lx:t,ly:n,area:i||null,inkStrokes:o.map(l=>l.id)},ql(e===le?"canvas":i?"area":"point");const r=m("#composer-area");r.classList.remove("chip-frame"),r.hidden=!i,i&&(r.textContent=e===le?`Area \xB7 ${B.anchor.near.length||"no"} frame${B.anchor.near.length===1?"":"s"}`:`Area \xB7 ${B.anchor.elements.length} element${B.anchor.elements.length===1?"":"s"}`);const c=m("#composer-ink");c.hidden=!o.length,c.innerHTML=`${Co}<span>${o.length} mark${o.length===1?"":"s"}</span>`,W.placeholder=$()?"Ask for a change":"Add a comment",Kn.length=0,H.hidden=!1,W.value="",ot(W),Zi.paint(),Et(e),_e(),qt(),setTimeout(()=>W.focus({preventScroll:!0}),0),Fi(e)}function po(e,t){return f.frames.map(n=>({f:n,d:Math.hypot(Math.max(n.x-e,0,e-n.x-n.w),Math.max(n.y-t,0,t-n.y-n.h))})).sort((n,a)=>n.d-a.d).slice(0,2).filter(n=>n.d<1200).map(n=>n.f.name)}function Al(e){const t=f.frames.filter(n=>n.x<e.x+e.w&&n.x+n.w>e.x&&n.y<e.y+e.h&&n.y+n.h>e.y).map(n=>n.name);return t.length?t:po(e.x+e.w/2,e.y+e.h/2)}function _l(e,t){const n=de(e);if(!n?.body)return[];const a=Math.max(12,Math.min(t.w,t.h)*.08),i=t.x-a,s=t.y-a,o=t.x+t.w+a,r=t.y+t.h+a,c=[];for(const u of n.body.querySelectorAll("*")){if(c.length>600)break;const p=u.getBoundingClientRect();!p.width||!p.height||["SCRIPT","STYLE","LINK","META"].includes(u.tagName)||p.left>=i&&p.top>=s&&p.right<=o&&p.bottom<=r&&c.push(u)}const l=new Set(c);let d=c.filter(u=>{for(let p=u.parentElement;p;p=p.parentElement)if(l.has(p))return!1;return!0});if(!d.length){const u=Me(e,t.x+t.w/2,t.y+t.h/2);u&&u!==n.documentElement&&(d=[u])}return d.slice(0,14).map(u=>({selector:Dt(u),tag:u.tagName.toLowerCase(),text:(u.innerText||u.getAttribute("aria-label")||u.getAttribute("alt")||"").replace(/\s+/g," ").trim().slice(0,80)}))}function Pl(e,t){const n=de(e);let a=Me(e,t.x+t.w/2,t.y+t.h/2);for(;a&&a!==n?.body;){const i=a.getBoundingClientRect();if(i.left<=t.x+2&&i.top<=t.y+2&&i.right>=t.x+t.w-2&&i.bottom>=t.y+t.h-2)break;a=a.parentElement}return a&&a!==n?.documentElement?{selector:Dt(a),tag:a.tagName.toLowerCase(),text:(a.innerText||"").replace(/\s+/g," ").trim().slice(0,80)}:null}function ql(e){const t=B;if(!t)return;const n=f.frames.find(a=>a.id===t.frameId);t.scope=e,e==="canvas"&&t.area?t.anchor={scope:e,wx:t.area.x,wy:t.area.y,area:{w:t.area.w,h:t.area.h},near:Al(t.area)}:e==="canvas"?t.anchor={scope:e,wx:t.lx,wy:t.ly,near:po(t.lx,t.ly)}:e==="area"?t.anchor={scope:e,x:t.area.x,y:t.area.y,w:t.area.w,h:t.area.h,sx:t.picked?.sx||0,sy:t.picked?.sy||0,elements:_l(t.frameId,t.area),container:Pl(t.frameId,t.area)}:t.anchor={...t.picked||{},scope:"point",x:t.lx,y:t.ly,fx:void 0,fy:void 0},On(t.frameId,t.anchor),Et(t.frameId),_e()}function Ri(e){const t=e.w<=480;let n="light";if(e.fill==="none")n="canvas";else if(/^#[0-9a-f]{6}$/i.test(e.fill||"")){const a=parseInt(e.fill.slice(1),16);.299*(a>>16)+.587*(a>>8&255)+.114*(a&255)<140&&(n="dark")}return{fs:Math.max(e.w*.037,Math.min(30,e.w*.077)),lx:t?.09:.11,ty:t?.15:.27,on:n,what:e.w<=1024?"screen":"page"}}function Ni(e){if(H.parentElement===e)return;const t=document.activeElement===W;e.appendChild(H),t&&W.focus({preventScroll:!0})}function Bi(){H.classList.remove("onpage"),Ni(document.body),H._pz=H._pw=null,document.querySelectorAll(".frame.prompting").forEach(e=>e.classList.remove("prompting"))}const Dl={Mobile:["Login","Onboarding","Home feed","Profile","Settings","Checkout"],Tablet:["Dashboard","Reader","Calendar","Settings","Kanban board"],Desktop:["Landing page","Dashboard","Pricing","Sign up","Settings","Blog post"]};function _a(e){const t=f?.frames.find(a=>a.id===e);if(!t)return;ee(),Bn(),Bi();const n=t.w<=480?"Mobile":t.w<=1024?"Tablet":"Desktop";B={frameId:e,picked:null,lx:24,ly:24,area:null,inkStrokes:[],prompt:!0,scope:"frame",anchor:{scope:"frame",x:24,y:24}},H.classList.add("prompt"),D.get(e)?.el.classList.add("prompting"),m("#prompt-title").textContent=`What should \u201C${t.name}\u201D be?`,m("#prompt-ideas").innerHTML=Dl[n].map(a=>`<button>${L(a)}</button>`).join(""),m("#composer-area").hidden=!0,m("#composer-ink").hidden=!0,W.placeholder=`Describe this ${Ri(t).what}`,Kn.length=0,H.hidden=!1,W.value="",ot(W),Zi.paint(),_e(),setTimeout(()=>W.focus({preventScroll:!0}),0),Fi(e)}m("#prompt-ideas").addEventListener("click",e=>{const t=e.target.closest("button");t&&(W.value=`${t.textContent} `,ot(W),Zi.paint(),W.focus(),W.setSelectionRange(W.value.length,W.value.length))});function te(){H.classList.contains("soft")&&(H.querySelector(".hint").innerHTML="<kbd>\u21B5</kbd> send \xB7 <kbd>\u21E7\u21B5</kbd> new line \xB7 <kbd>esc</kbd>"),H.classList.remove("prompt","soft"),Bi(),go=null,To(),B?.deep&&Ve(),document.querySelectorAll(".frame.whole").forEach(t=>t.classList.remove("whole"));const e=B?.frameId;B=null,H.hidden=!0,e&&Et(e),f&&qt()}function ot(e){e.style.height="auto",e.style.height=`${Math.min(e===W&&H.classList.contains("onpage")?innerHeight*.45/b.z:180,e.scrollHeight)}px`}W.addEventListener("input",()=>ot(W)),or(W),W.addEventListener("keydown",e=>{if(e.stopPropagation(),e.key==="Enter"&&!e.shiftKey&&!e.isComposing){if(e.preventDefault(),B?.deep&&!W.value.trim()&&!Kn.length&&x?.els.length===1&&xn(x.els[0],!0)&&$()){const{frameId:t,els:n}=x;te(),kn(t,n[0]);return}mo()}e.key==="Escape"&&te()});async function mo(){const e=Kn.splice(0),t=W.value.trim()||(e.length?"See the attached reference.":"");if(!t||!B)return;const n=B;te(),Ee("select");const a=f.strokes.filter(o=>n.inkStrokes.includes(o.id)),i={id:ga(),frameId:n.frameId,text:t,anchor:n.anchor,author:{name:U.name,color:U.color},inkStrokes:n.inkStrokes,attachments:e,refs:rr(W,t)};a.length&&n.frameId!==le&&Object.assign(i,Il(n.frameId,a));const s=Pa(i);try{const o=await w("POST","/__loop/api/comments",i);o?.id&&o.id!==i.id&&s(),$()||y("Comment added \u2014 the host will send it to the agent")}catch(o){s(),y(o.message)}}function Pa(e){if(X)return()=>{};const t={id:e.id,frameId:e.frameId,parentId:e.parentId||null,text:e.text,anchor:e.anchor||f.comments.find(n=>n.id===e.parentId)?.anchor||null,author:{...e.author,guest:!$()},inkStrokes:e.inkStrokes||[],status:$()?"queued":"waiting",reply:null,createdAt:Date.now(),local:!0,...e.attachments?.length?{attachments:e.attachments.map(n=>({name:n.name,type:n.type,url:n.data}))}:{}};f.comments.push(t);for(const n of f.strokes)t.inkStrokes.includes(n.id)&&(n.commentId=t.id);return wa(),()=>{f.comments=f.comments.filter(n=>n!==t),wa()}}const ho=new Map;function Fi(e){!f||X||!$()||!e||Date.now()-(ho.get(e)||0)<6e4||(ho.set(e,Date.now()),w("POST",`/__loop/api/frames/${e}/warm`).catch(()=>{}))}function Il(e,t){const n=f.frames.find(l=>l.id===e),a=de(e),i=new Map;for(const l of t){const d=l.points.length/2,u=Math.max(1,Math.floor(d/14));for(let p=0;p<d;p+=u){const h=l.points[p*2]-(l.fx??n.x),g=l.points[p*2+1]-(l.fy??n.y),v=Me(e,h,g);if(!v||v===a?.documentElement||v===a?.body)continue;const T=Dt(v);i.has(T)||i.set(T,{selector:T,tag:v.tagName.toLowerCase(),text:(v.innerText||"").replace(/\s+/g," ").trim().slice(0,60),el:v})}}const s=[...i.values()].slice(0,10),o=Math.min(1,1280/Math.max(n.w,n.h)),r=document.createElement("canvas");r.width=Math.round(n.w*o),r.height=Math.round(n.h*o);const c=r.getContext("2d");c.scale(o,o),c.fillStyle="#fff",c.fillRect(0,0,n.w,n.h),c.strokeStyle="#C8C8CE",c.lineWidth=2,c.strokeRect(1,1,n.w-2,n.h-2),c.font="14px ui-monospace, Menlo, monospace";for(const l of s)try{const d=l.el.getBoundingClientRect();c.strokeStyle="#2F5BFF",c.setLineDash([6,4]),c.lineWidth=1.5,c.strokeRect(d.left,d.top,d.width,d.height),c.setLineDash([]),c.fillStyle="#2F5BFF",c.fillText(l.tag+(l.text?` "${l.text.slice(0,30)}"`:""),d.left+4,Math.max(14,d.top-4))}catch{}c.strokeStyle=Li,c.lineWidth=4,c.lineCap="round",c.lineJoin="round";for(const l of t){c.beginPath();for(let d=0;d<l.points.length;d+=2){const u=l.points[d]-(l.fx??n.x),p=l.points[d+1]-(l.fy??n.y);d?c.lineTo(u,p):c.moveTo(u,p)}c.stroke()}return{ink:s.map(({el:l,...d})=>d),annotationPng:r.toDataURL("image/png")}}function Pd(e,t,n){Ze={frameId:e,lx:t,ly:n},m("#ink-chip").hidden=!1,_e()}function Bn(){Ze=null,m("#ink-chip").hidden=!0}let go=null;function Hl(e,t,n){if(!(!H.hidden&&W.value.trim())){if(e){const a=f.frames.find(l=>l.id===e),i=Oi(e),s=i.flatMap(l=>fn(l).filter((d,u)=>u%2===0)),o=i.flatMap(l=>fn(l).filter((d,u)=>u%2===1)),r=(s.length?(Math.min(...s)+Math.max(...s))/2:t[t.length-2])-a.x,c=(o.length?(Math.min(...o)+Math.max(...o))/2:t[t.length-1])-a.y;st(e,r,c)}else st(le,t[t.length-2],t[t.length-1],"canvas");B&&(B.soft=!0,H.classList.add("soft"),W.placeholder="What should change here?",H.querySelector(".hint").innerHTML="<kbd>\u21B5</kbd> send \xB7 <kbd>esc</kbd> skip",go={x:n.clientX,y:n.clientY,t:Date.now()})}}addEventListener("pointerdown",e=>{!B?.soft||H.hidden||H.contains(e.target)||W.value.trim()||K==="pen"&&e.target.closest("#viewport")||te()},!0),W.addEventListener("input",()=>{B?.soft&&W.value.trim()&&(B.soft=!1,H.classList.remove("soft"))}),m("#ink-chip button").addEventListener("click",()=>{if(!Ze)return;const e=Oi(Ze.frameId),t=f.frames.find(o=>o.id===Ze.frameId),n=e.flatMap(o=>fn(o).filter((r,c)=>c%2===0)),a=e.flatMap(o=>fn(o).filter((r,c)=>c%2===1)),i=n.length?(Math.min(...n)+Math.max(...n))/2-t.x:Ze.lx,s=a.length?(Math.min(...a)+Math.max(...a))/2-t.y:Ze.ly;st(Ze.frameId,i,s)});function Fn(e,t,n){Ne&&jn(!0),clearTimeout(it),it=null,It=!!n,e!==j&&(pt=!1),te(),Bn(),e!==j&&(Da.length=0),Re(),e!==j&&(z.dataset.tid="",z._side=t||null,z.classList.remove("in","grow"),z.offsetWidth,z.classList.add(t?"grow":"in"),z._grow=!t),j=e,z.hidden=!1;{const a=f.comments.find(i=>i.id===e);Ds(e)&&a&&Et(a.frameId)}z.classList.toggle("docked",pt),pt&&(z.style.left=z.style.top=z.style.maxHeight=""),Ia(),Nn(),_e()}function ee(){j&&(To(),(Vt.size||dn)&&(Vt.clear(),dn=null,qt()),Ct(Mt(j),4)&&(un=j),clearTimeout(it),it=null,It=!1,pt=!1,j=null,z.hidden=!0,z.dataset.tid="",Nn(),Aa())}const Ut=e=>{const t=(Date.now()-e)/1e3;return t<60?"just now":t<3600?`${Math.floor(t/60)}m ago`:t<86400?`${Math.floor(t/3600)}h ago`:new Date(e).toLocaleDateString()};function Zt(e){if(!e)return"";const t=/claude-([a-z]+)-(\d+)(?:-(\d+))?/i.exec(e);if(t)return`${t[1][0].toUpperCase()}${t[1].slice(1)} ${t[2]}${t[3]&&t[3].length<=2?"."+t[3]:""}`;const n=/^gpt-([\d.]+)(?:-([a-z]+))?/i.exec(e);return n?`GPT-${n[1]}${n[2]?" "+n[2][0].toUpperCase()+n[2].slice(1):""}`:e}function qd(e){const t=[];if(e.model&&t.push(Zt(e.model)),e.startedAt&&e.finishedAt){const n=Math.round((e.finishedAt-e.startedAt)/1e3);t.push(n<60?`${n}s`:`${Math.floor(n/60)}m ${n%60}s`)}return t.length?`<div class="a-meta">${L(t.join(" \xB7 "))}</div>`:""}const Dd=A("check","s"),zl={claude:'<svg class="lg claude" viewBox="0 0 24 24"><path d="m4.7144 15.9555 4.7174-2.6471.079-.2307-.079-.1275h-.2307l-.7893-.0486-2.6956-.0729-2.3375-.0971-2.2646-.1214-.5707-.1215-.5343-.7042.0546-.3522.4797-.3218.686.0608 1.5179.1032 2.2767.1578 1.6514.0972 2.4468.255h.3886l.0546-.1579-.1336-.0971-.1032-.0972L6.973 9.8356l-2.55-1.6879-1.3356-.9714-.7225-.4918-.3643-.4614-.1578-1.0078.6557-.7225.8803.0607.2246.0607.8925.686 1.9064 1.4754 2.4893 1.8336.3643.3035.1457-.1032.0182-.0728-.164-.2733-1.3539-2.4467-1.445-2.4893-.6435-1.032-.17-.6194c-.0607-.255-.1032-.4674-.1032-.7285L6.287.1335 6.6997 0l.9957.1336.419.3642.6192 1.4147 1.0018 2.2282 1.5543 3.0296.4553.8985.2429.8318.091.255h.1579v-.1457l.1275-1.706.2368-2.0947.2307-2.6957.0789-.7589.3764-.9107.7468-.4918.5828.2793.4797.686-.0668.4433-.2853 1.8517-.5586 2.9021-.3643 1.9429h.2125l.2429-.2429.9835-1.3053 1.6514-2.0643.7286-.8196.85-.9046.5464-.4311h1.0321l.759 1.1293-.34 1.1657-1.0625 1.3478-.8804 1.1414-1.2628 1.7-.7893 1.36.0729.1093.1882-.0183 2.8535-.607 1.5421-.2794 1.8396-.3157.8318.3886.091.3946-.3278.8075-1.967.4857-2.3072.4614-3.4364.8136-.0425.0304.0486.0607 1.5482.1457.6618.0364h1.621l3.0175.2247.7892.522.4736.6376-.079.4857-1.2142.6193-1.6393-.3886-3.825-.9107-1.3113-.3279h-.1822v.1093l1.0929 1.0686 2.0035 1.8092 2.5075 2.3314.1275.5768-.3218.4554-.34-.0486-2.2039-1.6575-.85-.7468-1.9246-1.621h-.1275v.17l.4432.6496 2.3436 3.5214.1214 1.0807-.17.3521-.6071.2125-.6679-.1214-1.3721-1.9246L14.38 17.959l-1.1414-1.9428-.1397.079-.674 7.2552-.3156.3703-.7286.2793-.6071-.4614-.3218-.7468.3218-1.4753.3886-1.9246.3157-1.53.2853-1.9004.17-.6314-.0121-.0425-.1397.0182-1.4328 1.9672-2.1796 2.9446-1.7243 1.8456-.4128.164-.7164-.3704.0667-.6618.4008-.5889 2.386-3.0357 1.4389-1.882.929-1.0868-.0062-.1579h-.0546l-6.3385 4.1164-1.1293.1457-.4857-.4554.0608-.7467.2307-.2429 1.9064-1.3114Z"/></svg>',codex:'<svg class="lg" viewBox="0 0 24 24"><path d="M22.2819 9.8211a5.9847 5.9847 0 0 0-.5157-4.9108 6.0462 6.0462 0 0 0-6.5098-2.9A6.0651 6.0651 0 0 0 4.9807 4.1818a5.9847 5.9847 0 0 0-3.9977 2.9 6.0462 6.0462 0 0 0 .7427 7.0966 5.98 5.98 0 0 0 .511 4.9107 6.051 6.051 0 0 0 6.5146 2.9001A5.9847 5.9847 0 0 0 13.2599 24a6.0557 6.0557 0 0 0 5.7718-4.2058 5.9894 5.9894 0 0 0 3.9977-2.9001 6.0557 6.0557 0 0 0-.7475-7.0729zm-9.022 12.6081a4.4755 4.4755 0 0 1-2.8764-1.0408l.1419-.0804 4.7783-2.7582a.7948.7948 0 0 0 .3927-.6813v-6.7369l2.02 1.1686a.071.071 0 0 1 .038.052v5.5826a4.504 4.504 0 0 1-4.4945 4.4944zm-9.6607-4.1254a4.4708 4.4708 0 0 1-.5346-3.0137l.142.0852 4.783 2.7582a.7712.7712 0 0 0 .7806 0l5.8428-3.3685v2.3324a.0804.0804 0 0 1-.0332.0615L9.74 19.9502a4.4992 4.4992 0 0 1-6.1408-1.6464zM2.3408 7.8956a4.485 4.485 0 0 1 2.3655-1.9728V11.6a.7664.7664 0 0 0 .3879.6765l5.8144 3.3543-2.0201 1.1685a.0757.0757 0 0 1-.071 0l-4.8303-2.7865A4.504 4.504 0 0 1 2.3408 7.872zm16.5963 3.8558L13.1038 8.364 15.1192 7.2a.0757.0757 0 0 1 .071 0l4.8303 2.7913a4.4944 4.4944 0 0 1-.6765 8.1042v-5.6772a.79.79 0 0 0-.407-.667zm2.0107-3.0231l-.142-.0852-4.7735-2.7818a.7759.7759 0 0 0-.7854 0L9.409 9.2297V6.8974a.0662.0662 0 0 1 .0284-.0615l4.8303-2.7866a4.4992 4.4992 0 0 1 6.6802 4.66zM8.3065 12.863l-2.02-1.1638a.0804.0804 0 0 1-.038-.0567V6.0742a4.4992 4.4992 0 0 1 7.3757-3.4537l-.142.0805L8.704 5.459a.7948.7948 0 0 0-.3927.6813zm1.0976-2.3654l2.602-1.4998 2.6069 1.4998v2.9994l-2.5974 1.4997-2.6067-1.4997Z"/></svg>',loop:'<svg class="lg ring" viewBox="0 0 24 24"><circle cx="12" cy="12" r="6.5"/></svg>'};function Ol(e){const t=String(e?.model||"").toLowerCase();return/claude|opus|sonnet|haiku|fable|mythos/.test(t)?"claude":/gpt|codex|^o\d/.test(t)||f?.agentBin==="codex"?"codex":f?.agentBin==="claude"?"claude":"loop"}const Rl={claude:"Claude",codex:"Codex",loop:"Agent"},yo=e=>{const t=Ol(e);return`<span class="m-mark" title="${Rl[t]}">${zl[t]}</span>`};function Id(e){if(!(e.startedAt&&e.finishedAt))return"";const t=Math.round((e.finishedAt-e.startedAt)/1e3);return`<span title="${L(e.model?Zt(e.model):"")}">Worked ${t<60?`${t}s`:`${Math.floor(t/60)}m ${t%60}s`}</span>`}const Wn={undo:A("undo"),before:A("before"),redo:A("redo"),copy:A("copy"),check:A("check"),stop:A("stop"),send:A("up"),retry:A("retry"),steer:A("steer"),bg:A("play"),x:A("x")},Qe=(e,t,n,a,i="")=>`<button class="a-btn${a?" lbl":""}${i?" "+i:""}" ${t} title="${L(n)}" aria-label="${L(n)}">${Wn[e]}${a?`<span>${L(a)}</span>`:""}</button>`;function Nl(e){const t=$(),n=(i,s,o,r)=>`<div class="m-agent ${i}">${yo(e)}<div class="m-body">${s}${o?`<div class="m-acts${r?" show":""}">${o}</div>`:""}</div></div>`,a=`data-id="${e.id}"`;switch(e.status){case"waiting":return n("quiet",'<div class="m-text">Waiting for the host to send this to the agent.</div>',t?Qe("send",`data-act="send" ${a}`,"Send to the agent","Send","primary"):"",!0);case"queued":{if(e.local)return n("quiet",'<div class="m-work"><span class="a-text">Sending\u2026</span></div>',"");const i=e.parentId||e.id,s=t&&Xt(i).some(l=>l.status==="working"),o=f.agent.mode==="inbox"&&!e.background,r=o&&!f.chatListening,c=s?"Queued \xB7 runs after the current change":r?f.chatHistory?"Your chat isn\u2019t listening, so this carries on in the background in a moment, with what that chat knows.":"Your chat isn\u2019t listening, so this starts in a new session in a moment.":o?"Sent to your chat":"Queued";return n("quiet",`<div class="m-work"><span class="a-text">${c}</span></div>`,t?`${s?Qe("steer",`data-act="steer" ${a}`,"Steer: stop the current run and include this message in it","Steer","primary"):""}${r?Qe("bg",`data-act="background" ${a}`,f.chatHistory?"Carry on now in the background, from a copy of your chat":"Run it now in the background, without your chat\u2019s context","Run now"):""}${Qe("x",`data-act="cancel" ${a}`,"Cancel")}`:"",!0)}case"working":return n("",`<ol class="m-steps" data-steps-for="${e.id}"></ol><div class="m-work"><span class="a-text" data-step-for="${e.id}"></span><span class="m-time" data-elapsed-from="${f.live[e.frameId]?.startedAt||e.startedAt||e.createdAt}"></span>${t?Qe("stop",`data-act="cancel" ${a}`,"Stop"):""}</div><div class="m-text md m-stream" data-partial-for="${e.id}" hidden></div>`,"");case"done":return n("",`${jl(e)}<div class="m-text md">${e.undone?"Reverted.":qa(e.reply||"Done.")}</div>${Yl(e)}${bo(e)}`,`${e.snapshot&&!X&&f.frames.find(i=>i.id===e.frameId)?.kind==="folder"?Qe("before",`data-act="before" ${a}`,"See the frame before this change"):""}${t&&e.snapshot&&!e.undone?Qe("undo",`data-act="undo" ${a}`,"Undo this change"):""}${t&&e.undone&&e.redoSnap?Qe("redo",`data-act="redo" ${a}`,"Redo this change"):""}${Qe("copy",`data-copy="${e.id}"`,"Copy the reply")}<time>${Ut(e.finishedAt||e.createdAt)}</time>`);case"error":return n("error",`<div class="m-text">${L(e.reply||"Something went wrong.")}</div>${bo(e)}`,t?Qe("retry",`data-act="send" ${a}`,"Try again","Retry","primary"):"",!0);case"interrupted":return n("quiet",'<div class="m-text">Interrupted \xB7 continued below</div>',"");case"canceled":return n("quiet",'<div class="m-text">Stopped.</div>',t?Qe("retry",`data-act="send" ${a}`,"Send again","Send again","primary"):"",!0);default:return""}}const Wi=e=>(e?.blocked||[]).filter(t=>!t.allowed);function Bl(e){const t=Wi(e);return t.length===1?{act:"allow",say:"Blocked",btn:"Allow",tip:`The agent wasn\u2019t allowed to use ${t[0].label}. Allow it on this canvas and let the agent carry on.`}:{act:"allow",say:`${t.length} blocked`,btn:"Allow all",tip:`The agent wasn\u2019t allowed to use: ${t.map(a=>a.label).join(" \xB7 ")}. Allow them all on this canvas and let the agent carry on. (Press the pin itself to see them one by one.)`}}function bo(e){if(!e.blocked?.length)return"";const t=$()&&!X;return`<div class="m-blocked">${e.blocked.map((n,a)=>`<div class="blk${n.allowed?" ok":""}">
|
|
18
|
-
<span class="blk-k">${n.allowed?"Allowed":"Blocked"}</span><code title="${
|
|
19
|
-
${!n.allowed&&t?`<button class="blk-go" data-act="allow" data-id="${e.id}" data-k="${a}" title="Let the agent use this on this canvas from now on, and carry on">Allow</button>`:""}</div>`).join("")}${t&&
|
|
20
|
-
<div class="bubble${e.attachments?.length?" has-files":""}">${
|
|
21
|
-
<div class="m-meta">${e.author?.guest||e.author?.name&&e.author.name!==
|
|
22
|
-
</div>${t?"":
|
|
23
|
-
<span class="os-img" style="width:${o}px;height:${r}px">${h?`<img src="${
|
|
24
|
-
<span class="os-name">${u?`<i>${u}</i>`:""}${
|
|
25
|
-
${n.optionApplied?`<button class="os-use" data-use="${n.optionApplied}">Use ${n.optionApplied}</button>`:""}`,
|
|
26
|
-
${n&&e.optionApplied?`<span class="opt-acts"><button class="opt-use" data-use="${e.optionApplied}" data-for="${e.id}">Use ${
|
|
27
|
-
`)){const
|
|
28
|
-
<div class="thread-reply"><div class="cbox"><div class="c-files" hidden></div><textarea rows="1" placeholder="Reply"></textarea></div></div>`,
|
|
29
|
-
${
|
|
30
|
-
<span class="t-title">${
|
|
15
|
+
</linearGradient></defs><g class="auras"></g>`);const e=new Set([...Lc()].filter(s=>!(O?.inkStrokes||[]).includes(s))),t=new Set,n=At.querySelector("g.auras");n.querySelectorAll("path").forEach(s=>{t.has(s.dataset.for)||s.remove()});for(const s of f.strokes){if(!t.has(s.id)||n.querySelector(`path[data-for="${s.id}"]`))continue;const i=document.createElementNS("http://www.w3.org/2000/svg","path");i.dataset.for=s.id,i.setAttribute("d",di(s.points)),i.setAttribute("class","aura-stroke"),i.setAttribute("stroke","url(#aura-grad)"),i.setAttribute("filter","url(#aura-blur)"),n.appendChild(i)}const a=new Set(f.strokes.map(s=>s.id));At.querySelectorAll("path[data-id]").forEach(s=>{a.has(s.dataset.id)||s.remove()});for(const s of f.strokes){let i=At.querySelector(`path[data-id="${s.id}"]`);i||(i=document.createElementNS("http://www.w3.org/2000/svg","path"),i.dataset.id=s.id,i.setAttribute("d",di(s.points)),At.appendChild(i)),i.setAttribute("stroke",s.color),i.setAttribute("stroke-width",s.width),i.classList.toggle("used",!!s.commentId),i.classList.toggle("working",e.has(s.id)),i.style.display=s.commentId&&!e.has(s.id)&&!an.has(s.commentId)&&vn!==s.commentId?"none":""}Ho()}function Gn(e,t){for(let n=f.frames.length-1;n>=0;n--){const a=f.frames[n];if(e>=a.x&&e<=a.x+a.w&&t>=a.y&&t<=a.y+a.h)return a}return null}function ue(e){try{return P.get(e)?.iframe.contentDocument||null}catch{return null}}function Qe(e,t,n){const a=P.get(e).iframe.getBoundingClientRect();return{lx:(t-a.left)/v.z,ly:(n-a.top)/v.z}}function Se(e,t,n){const a=ue(e);if(!a)return null;try{return a.elementFromPoint(t,n)}catch{return null}}function jt(e){if(!e||!e.ownerDocument)return"";const t=e.ownerDocument,n=[];for(let a=e;a&&a.nodeType===1&&a!==t.documentElement;a=a.parentElement){if(a.id&&/^[A-Za-z][\w-]*$/.test(a.id)){n.unshift(`#${a.id}`);break}let s=a.tagName.toLowerCase();const i=a.parentElement?[...a.parentElement.children].filter(o=>o.tagName===a.tagName):[];if(i.length>1&&(s+=`:nth-of-type(${i.indexOf(a)+1})`),n.unshift(s),a.tagName==="BODY"||n.length>7)break}return n.join(" > ")}function Oo(e){const t=typeof e.className=="string"&&e.className.trim()?"."+e.className.trim().split(/\s+/)[0]:"";return e.tagName.toLowerCase()+t}function ui(e,t,n){const a=Se(e,t,n),s=ue(e);let i=0,o=0;try{i=s.defaultView.scrollX,o=s.defaultView.scrollY}catch{}const r={x:t,y:n,sx:i,sy:o};if(a&&a!==s.documentElement){const l=a.getBoundingClientRect();Object.assign(r,{selector:jt(a),tag:a.tagName.toLowerCase(),label:Oo(a),text:(a.innerText||a.getAttribute?.("aria-label")||a.getAttribute?.("alt")||"").replace(/\s+/g," ").trim().slice(0,140),html:a.outerHTML.length>1500?a.outerHTML.slice(0,1500)+"\u2026":a.outerHTML,fx:l.width?(t-l.left)/l.width:0,fy:l.height?(n-l.top)/l.height:0})}return r}const le="__canvas";function pi(e,t){const n=ue(e);if(!n?.defaultView)return null;const a=n.defaultView,s=n.scrollingElement||n.documentElement;let i=a.scrollX,o=a.scrollY;const r=t.selector||t.container?.selector||t.elements?.[0]?.selector;try{for(let l=r&&n.querySelector(r)?.parentElement;l&&l!==s&&l!==n.documentElement;l=l.parentElement)i+=l.scrollLeft,o+=l.scrollTop}catch{}return{x:i,y:o}}function Zn(e,t){const n=e!==le&&t&&pi(e,t);return n&&(t.sx=n.x,t.sy=n.y),t}function Jn(e,t){if(e===le)return{x:t.wx,y:t.wy};if(t.scope==="frame"||t.scope==="point"||t.scope==="area"||t.scope==="elements"){if(t.scope==="frame")return{x:t.x,y:t.y};const s=pi(e,t)||{x:t.sx||0,y:t.sy||0};return{x:t.x-(s.x-(t.sx||0)),y:t.y-(s.y-(t.sy||0))}}const n=ue(e);if(n&&t.selector)try{const s=n.querySelector(t.selector);if(s){const i=s.getBoundingClientRect();if(i.width||i.height)return{x:i.left+t.fx*i.width,y:i.top+t.fy*i.height}}}catch{}const a=pi(e,t)||{x:t.sx||0,y:t.sy||0};return{x:t.x-(a.x-(t.sx||0)),y:t.y-(a.y-(t.sy||0))}}function Wa(e,t,n,a="deep"){const{lx:s,ly:i}=Qe(e,t,n),o=ue(e),r=ps(e,Se(e,s,i),a==="drill"?"level":a);if(!r||r===o?.documentElement){G.hidden=!0;return}const l=P.get(e).iframe.getBoundingClientRect(),c=r.getBoundingClientRect(),d=v.z,u=Math.max(l.left,l.left+c.left*d),p=Math.max(l.top,l.top+c.top*d),h=Math.min(l.right,l.left+c.right*d),g=Math.min(l.bottom,l.top+c.bottom*d);Object.assign(G.style,{left:`${u}px`,top:`${p}px`,width:`${Math.max(0,h-u)}px`,height:`${Math.max(0,g-p)}px`}),G.dataset.tag=Ke(r),G.classList.toggle("sel",!!L?.els.includes(r));const w=[...r.children].filter($=>!/^(SCRIPT|STYLE|BR)$/.test($.tagName)).slice(0,30).map($=>$.getBoundingClientRect()).filter($=>$.width>3&&$.height>3),T=`${c.left},${c.top},${c.width},${c.height},${d},${w.length}`;G._k!==T&&(G._k=T,G.innerHTML=w.map($=>`<i style="left:${($.left-c.left)*d-1.5}px;top:${($.top-c.top)*d-1.5}px;width:${$.width*d}px;height:${$.height*d}px"></i>`).join("")),G.hidden=!1}function sn(e){return f.comments.filter(t=>t.id===e||t.parentId===e).sort((t,n)=>t.createdAt-n.createdAt)}function xn(e){const t=sn(e).filter(n=>n.kind!=="note");return t.some(n=>n.status==="working")?"working":t[t.length-1]?.status||"done"}function Ro(e){return f.comments.filter(t=>t.frameId===e&&!t.parentId&&t.kind!=="create").sort((t,n)=>t.createdAt-n.createdAt)}const we=document.createElement("div");we.id="peek",we.className="pop",we.hidden=!0,document.body.appendChild(we);let xe=null,ja=null,Ya=null,bt=null,kn=null;const No="Start listening to the Loop canvas again: run `loop watch` with the Monitor tool and keep it running.",Dt=(e,t)=>!!e&&je.x>=e.left-t&&je.x<=e.right+t&&je.y>=e.top-t&&je.y<=e.bottom+t,qt=e=>document.querySelector(`.pin[data-key="${e}"] .pin-dot`)?.getBoundingClientRect()||null;function Cc(e,t){if(!t||matchMedia("(prefers-reduced-motion: reduce)").matches)return;const n=e.getBoundingClientRect();if(!n.width||!n.height)return;const a=(l,c)=>Math.max(0,Math.min(c,l)),s=a(t.left-n.left,n.width-24),i=a(t.top-n.top,n.height-24),o=a(n.right-t.right,n.width-s-24),r=a(n.bottom-t.bottom,n.height-i-24);e._growing?.cancel(),e._growing=e.animate([{clipPath:`inset(${i}px ${o}px ${r}px ${s}px round 14px)`,opacity:.7},{clipPath:"inset(0px 0px 0px 0px round 18px)",opacity:1}],{duration:190,easing:"cubic-bezier(.2, .8, .2, 1)"})}function Mc(e){clearTimeout(ja),!(xe===e||kn===e)&&(document.querySelector(`.pin[data-key="${e}"]`)?.dataset.act||xe&&Dt(we.getBoundingClientRect(),0)||(ja=setTimeout(()=>{V===e||oe||!f?.comments.some(t=>t.id===e)||!Dt(qt(e),6)||V&&!Yt||O&&!H.hidden||na(e,null,!0)},V?30:80)))}let Yt=!1,ft=null;function Ec(){kn&&!Dt(qt(kn),4)&&(kn=null),Yt&&V&&(R.contains(document.activeElement)||!!R.querySelector(".thread-reply textarea")?.value.trim()||Ja.length?(Yt=!1,clearTimeout(ft),ft=null):Dt(R.getBoundingClientRect(),12)||Dt(qt(V),8)?(clearTimeout(ft),ft=null):ft||(ft=setTimeout(()=>{ft=null,Yt&&te()},180))),xe&&(Dt(we.getBoundingClientRect(),10)||Dt(Ya,8)?(clearTimeout(bt),bt=null):bt||(bt=setTimeout(()=>{bt=null,Re()},150)))}function Re(){if(clearTimeout(ja),clearTimeout(bt),bt=null,!xe)return;Dt(Ya,4)&&(kn=xe);const e=f?.comments.find(t=>t.id===xe);e&&Kt(e.frameId)?.querySelector(`.area[data-key="${xe}"]`)?.classList.remove("hover"),xe=null,we.hidden=!0,Ua()}function Bo(e){const t=Ro(e.frameId).findIndex(n=>n.id===e.id)+1;return t?`<span class="pin-n" title="Comment ${t}">${t}</span>`:""}function Sc(){const e=f.comments.find(o=>o.id===xe);if(!e||V===xe)return Re();const t=sn(e.id),n=t[t.length-1],a=t.length-(n===e?1:2),s=[[e.id,xi(e,n!==e)]];a>0&&s.push(["__more",`<div class="pk-gap">${a} more ${a===1?"message":"messages"}</div>`]),n!==e&&s.push([n.id,xi(n)]),we.firstChild||(we.innerHTML='<div class="thread-body"></div><div class="pk-bar"></div>'),Fo(we.querySelector(".thread-body"),s);const i=`${Bo(e)}<span class="pk-who">${C(e.author?.name||"You")} \xB7 ${on(e.createdAt)}</span>
|
|
16
|
+
<button class="t-btn" data-pk="open" title="Open and reply">${nt.reply}</button>${k()?`<button class="t-btn" data-pk="resolve" title="${e.resolved?"Reopen":"Resolve"}">${e.resolved?nt.reopen:nt.resolve}</button>`:""}`;we._bar!==i&&(we._bar=i,we.querySelector(".pk-bar").innerHTML=i),Wo(we),Tc()}function Tc(){if(!xe)return;const e=f.comments.find(a=>a.id===xe);if(!e?.anchor)return;const t=Jn(e.frameId,e.anchor),n=Va(e.frameId,t.x,t.y);Uo(we,n.x,n.y,!1,qt(xe)),Ya=qt(xe)||Ya,Ua()}document.documentElement.addEventListener("pointerleave",()=>{xe&&!bt&&(bt=setTimeout(()=>{bt=null,Re()},150))}),we.addEventListener("pointerdown",e=>e.stopPropagation()),we.addEventListener("wheel",e=>e.stopPropagation()),we.addEventListener("click",async e=>{const t=xe;if(!t)return;if(e.target.closest('[data-pk="resolve"]')){Re();try{await x("POST",`/__loop/api/comments/${t}/resolve`)}catch(a){y(a.message)}return}if(e.target.closest("a"))return;const n=we.dataset.o;Re(),na(t,n)});function Fo(e,t){const n=e._cache||=new Map,a=new Set(t.map(i=>i[0]));for(const i of[...e.children])a.has(i.dataset.mid)||(n.delete(i.dataset.mid),i.remove());let s=null;for(const[i,o]of t){let r=[...e.children].find(c=>c.dataset.mid===i);r||(r=document.createElement("div"),r.className="m",r.dataset.mid=i),n.get(i)!==o&&(n.set(i,o),r.innerHTML=o);const l=s?s.nextSibling:e.firstChild;l!==r&&e.insertBefore(r,l),s=r}}function Wo(e){e.querySelectorAll("[data-step-for]").forEach(t=>{const n=f.comments.find(s=>s.id===t.dataset.stepFor),a=n&&f.live[n.frameId];$e(t,a?.commentId===n?.id&&a.step||"Working\u2026"),n&&ar(n.id,e),a?.commentId===n?.id&&jo(n.id,a.partial||"",e)}),e.querySelectorAll("[data-elapsed-from]").forEach(t=>$e(t,Na(+t.dataset.elapsedFrom)))}function jo(e,t,n=document){n.querySelectorAll(`[data-partial-for="${e}"]`).forEach(a=>{if(a._src===t)return;a._src=t,a.hidden=!t,a.innerHTML=t?Za(t):"";const s=a.closest(".thread-body");s&&s.scrollHeight-s.scrollTop-s.clientHeight<80&&(s.scrollTop=s.scrollHeight)})}const Yo=new Map;function Ko(e){const t=f.live[e];return t?(t.partial||"").trim().split(`
|
|
17
|
+
`)[0].replace(/[*_`#>]/g,"").trim()||t.step||"Working\u2026":""}function Ac(e){const t=f.live[e],n=Ka(e);if(!t||!n)return;const a=f.comments.find(o=>o.id===t.commentId)?.parentId||t.commentId,s=n.querySelector(`.pin[data-key="${a}"] .pl`);if(!s)return;const i=Ko(e);s.textContent!==i&&(s.textContent=i,(t.partial||"").trim()||(s.classList.remove("tick"),s.offsetWidth,s.classList.add("tick")))}async function _c(e){const t=e.dataset.act,n=e.dataset.cid;if(!t||!n)return;if(t==="see")return na(e.dataset.key||n);delete e.dataset.act;const a=e.querySelector(".pl");a._h=null,a.textContent=t==="send"?"Sending\u2026":t==="allow"?"Allowed":"Starting\u2026";try{await x("POST",`/__loop/api/comments/${n}/${t}`,t==="allow"?{all:!0,i:f.comments.find(s=>s.id===n)?.blocked?.findIndex(s=>!s.allowed)}:void 0)}catch(s){y(s.message);const i=f.comments.find(o=>o.id===n)?.frameId;i&&vt(i)}}function Qn(){for(const e of f.frames)vt(e.id);vt(le)}function Ka(e){return e===le?m("#canvas-pins"):P.get(e)?.pins}function Kt(e){return e===le?m("#canvas-pins"):P.get(e)?.el.querySelector(".areas")}function vt(e){const t=Ka(e);if(!t)return;const n={pins:t},a=Ro(e),s=a.map((u,p)=>({key:u.id,n:p+1,c:u})).filter(u=>!u.c.resolved||V===u.key);O?.frameId===e&&!O.prompt&&s.push({key:"__draft",n:a.length+1,draft:!0});const i=new Set(s.map(u=>u.key));n.pins.querySelectorAll(".pin").forEach(u=>{i.has(u.dataset.key)||u.remove()});for(const u of s){let p=n.pins.querySelector(`.pin[data-key="${u.key}"]`);p||(p=document.createElement("div"),p.className="pin",p.dataset.key=u.key,p.innerHTML='<div class="pin-dot"><b class="pn"></b><svg class="pw" viewBox="0 0 16 16" aria-hidden="true"><circle cx="8" cy="8" r="5.5"/></svg><span class="pl"></span></div>',p.addEventListener("pointerdown",_=>_.stopPropagation()),u.draft||p.addEventListener("click",_=>{if(_.stopPropagation(),p.dataset.act&&_.target.closest(".pin-act"))return _c(p);if(p.classList.contains("making")&&_.target.closest(".pl")){const se=f.comments.find(F=>F.id===u.key);if(se?.optionSection)return qs.delete(se.optionSection),Cl(se.optionSection)}na(u.key)}),p.addEventListener("pointerenter",()=>{Kt(e)?.querySelector(`.area[data-key="${u.key}"]`)?.classList.add("hover"),u.draft||Mc(u.key)}),p.addEventListener("pointerleave",()=>{xe!==u.key&&(Kt(e)?.querySelector(`.area[data-key="${u.key}"]`)?.classList.remove("hover"),clearTimeout(ja))}),n.pins.appendChild(p));const h=p.querySelector(".pn"),g=!!u.c&&(u.c.author?.guest||!!u.c.author?.name&&u.c.author.name!==Z.name);let w=u.draft?"draft":xn(u.key);!u.draft&&w==="done"&&V===u.key&&bo(u.key);const T=!u.draft&&w==="done"&&nc(u.key);T?h._ck!==1&&(h._ck=1,h.innerHTML=sc):(h._ck&&(h._ck=0,h.textContent=""),$e(h,String(u.n)));const $=!u.draft&&f.frames.some(_=>_.building&&_.optionOf?.cid===u.key)&&!(w==="queued"&&f.agent.mode==="inbox"&&!f.chatListening);$&&w!=="working"&&(w="working");const b=Yo.get(u.key);Yo.set(u.key,w),b==="working"&&w!=="working"&&w!=="queued"&&(p._ended=w==="done"?T?null:"Done":w==="error"?"Failed":"Stopped",clearTimeout(p._endT),p._endT=setTimeout(()=>{p._ended=null,f&&vt(e)},2400));const M=p.querySelector(".pl"),E=!u.draft&&sn(u.key).filter(_=>_.kind!=="note").pop(),z=!u.draft&&k()&&!X&&E&&(w==="queued"&&!E.local&&!E.background&&f.agent.mode==="inbox"&&!f.chatListening?f.chatHistory?{act:"background",say:"Chat isn\u2019t listening",btn:"Carry on here",tip:"The chat this was sent to isn\u2019t listening. Carry on in the background from a copy of that chat, with everything it knows. It also starts by itself in a moment."}:{act:"background",say:"Chat isn\u2019t listening",btn:"Run in new chat",tip:"The chat this was sent to isn\u2019t listening. Run it in a new session instead (without that chat\u2019s history). It also starts by itself in a moment."}:w==="waiting"?{act:"send",say:"Waiting for you",btn:"Send",tip:"Send this comment to the agent"}:(w==="done"||w==="error")&&wi(E).length?jc(E):null);if(z){p.dataset.act=z.act,p.dataset.cid=E.id;const _=`<span>${C(z.say)}</span><button class="pin-act" title="${C(z.tip)}">${C(z.btn)}${z.act==="background"?`<kbd>${pt==="metaKey"?"\u2318":"Ctrl"}\u21B5</kbd>`:""}</button>`;M._h!==_&&(M._h=_,M.innerHTML=_)}else p.dataset.act&&(delete p.dataset.act,M._h=null,M.textContent="");if(w==="working"){const _=f.live[e],se=_&&(f.comments.find(F=>F.id===_.commentId)?.parentId||_.commentId)===u.key;$e(M,$?"Making options \u2192":se?Ko(e):"Working\u2026")}else T&&!z?$e(M,"Done"):p._ended&&$e(M,p._ended);p.className=`pin ${w}${u.c?.resolved?" resolved":""}${V===u.key||u.draft?" active":""}${w==="working"?" talking":z?" talking needs":T?" talking done-new":p._ended?" talking ended":""}${p.classList.contains("carded")?" carded":""}${p.classList.contains("ping")?" ping":""}${p.classList.contains("low")?" low":""}${g?" theirs":""}${$?" making":""}`}const o=f.live[e]?.commentId,r=o&&(f.comments.find(u=>u.id===o)?.parentId||o),l=s.filter(u=>u.draft?O?.area:u.c?.anchor?.scope==="area"||u.c?.anchor?.area||u.key===r&&(u.c?.anchor?.scope==="elements"||u.c?.anchor?.scope==="frame"||fi(u.key).length)),c=new Set(l.map(u=>u.key)),d=Kt(e);d.querySelectorAll(".area:not(.picking):not(.mirror-work)").forEach(u=>{c.has(u.dataset.key)||u.remove()});for(const u of l){let p=d.querySelector(`.area[data-key="${u.key}"]`);p||(p=document.createElement("div"),p.dataset.key=u.key,d.prepend(p));const h=!u.draft&&u.key!==r&&xn(u.key)==="queued";p.className=`area${u.draft?" draft show":""}${V===u.key?" show":""}${u.key===r?" show working":""}${h?" show queued":""}${u.c?.anchor?.scope==="frame"?" whole":""}${u.key===r&&fi(u.key).length&&u.c?.anchor?.scope!=="area"&&!u.c?.anchor?.area?" inkbox":""}`}wt(e),l.some(u=>u.key===r)&&ni(),Xn()}function wt(e){const t=Ka(e);!t||!f||(L?.frameId===e&&Pe(),Kt(e)?.querySelectorAll(".area[data-key]").forEach(n=>{const a=n.dataset.key==="__draft"?O?.anchor:f.comments.find(l=>l.id===n.dataset.key)?.anchor;if(!a)return;if(a.scope==="frame"){const l=f.frames.find(c=>c.id===e);if(!l)return;Object.assign(n.style,{left:"0px",top:"0px",width:`${l.w}px`,height:`${l.h}px`});return}if(n.classList.contains("inkbox")){const l=fi(n.dataset.key),c=f.frames.find(M=>M.id===e),d=c&&qe(c),u=f.strokes.filter(M=>l.includes(M.id)).flatMap(M=>wn(M));if(!d||u.length<2){n.style.width="0";return}const p=u.filter((M,E)=>E%2===0).map(M=>M-d.x),h=u.filter((M,E)=>E%2).map(M=>M-d.y),g=12,w=Math.max(0,Math.min(...p)-g),T=Math.max(0,Math.min(...h)-g),$=Math.min(d.w,Math.max(...p)+g),b=Math.min(d.h,Math.max(...h)+g);Object.assign(n.style,{left:`${w}px`,top:`${T}px`,width:`${Math.max(0,$-w)}px`,height:`${Math.max(0,b-T)}px`});return}if(a.scope==="elements"){const l=ue(e),c=(a.elements||[]).map(g=>{try{return l?.querySelector(g.selector)?.getBoundingClientRect()}catch{return null}}).filter(g=>g&&(g.width||g.height));if(!c.length){n.style.width="0";return}const d=Math.min(...c.map(g=>g.left)),u=Math.min(...c.map(g=>g.top)),p=Math.max(...c.map(g=>g.right)),h=Math.max(...c.map(g=>g.bottom));Object.assign(n.style,{left:`${d}px`,top:`${u}px`,width:`${p-d}px`,height:`${h-u}px`});return}const{x:s,y:i}=Jn(e,a),o=a.area?a.area.w:a.w,r=a.area?a.area.h:a.h;Object.assign(n.style,{left:`${s}px`,top:`${i}px`,width:`${o}px`,height:`${r}px`})}),t.querySelectorAll(".pin").forEach(n=>{const a=n.dataset.key==="__draft"?O?.anchor:f.comments.find(r=>r.id===n.dataset.key)?.anchor;if(!a){n.hidden=!0;return}const{x:s,y:i}=Jn(e,a);n.style.left=`${s}px`,n.style.top=`${i}px`;const o=f.frames.find(r=>r.id===e);n.hidden=!!o&&(s<-4||i<-4||s>o.w+4||i>o.h+4),n.classList.toggle("low",e!==le&&i*v.z<34*(parseFloat(getComputedStyle(document.documentElement).getPropertyValue("--lz"))||1))}),(O?.frameId===e||V&&f.comments.find(n=>n.id===V)?.frameId===e)&&Te())}function Va(e,t,n){if(e===le)return{x:v.x+t*v.z,y:v.y+n*v.z};const a=qe(f.frames.find(s=>s.id===e));return{x:v.x+(a.x+t)*v.z,y:v.y+(a.y+n)*v.z}}function Vo(e,t,n,a){const s=e.offsetWidth||340,i=e.offsetHeight||140,o=28*(parseFloat(getComputedStyle(document.documentElement).getPropertyValue("--lz"))||1);let r=a?t+o+10:t+18,l=a?Math.min(a.top,n)-4:n-18;r+s>innerWidth-12&&(r=t-s-10),r=Math.max(12,Math.min(r,innerWidth-s-12)),l=Math.max(60,Math.min(l,innerHeight-i-76)),e.style.left=`${r}px`,e.style.top=`${l}px`}let Vt=28;function Uo(e,t,n,a,s){Vt=28*(parseFloat(getComputedStyle(document.documentElement).getPropertyValue("--lz"))||1),s&&s.height>4&&(t=s.left,n=s.bottom,Vt=s.height),a&&(e.style.maxHeight="");const i=e.offsetWidth||340;let o=e.offsetHeight||140;const r=n-56,l=innerHeight-12-(n-Vt),c=innerWidth-12-t,d=t+Vt-12;let u=a&&e._side;u&&(u[0]==="b"?o>r&&l>r:o>l&&r>l)&&(u=(u[0]==="b"?"t":"b")+u[1]);const p=a?o:Math.max(o,380);if(u||(u=(p<=r||r>=l?"b":"t")+(i<=c||c>=d?"l":"r")),a){e._side=u;const $=u[0]==="b"?r:l;o>$&&(e.style.maxHeight=`${Math.max(180,Math.floor($))}px`,o=e.offsetHeight)}const h=u[1]==="l"?t:t+Vt-i,g=u[0]==="b"?n-o:n-Vt,w=Math.max(12,Math.min(h,innerWidth-i-12)),T=Math.max(56,Math.min(g,innerHeight-o-12));e.style.left=`${Math.round(w)}px`,e.style.top=`${Math.round(T)}px`,e.dataset.o=u,e.style.transformOrigin=`${Math.max(0,Math.min(i,t+Vt/2-w))}px ${Math.max(0,Math.min(o,n-Vt/2-T))}px`,e.classList.toggle("at-pin",u==="bl"&&w===h&&T===g),e._covers=w===h&&T===g}function Ua(){const e=new Set;V&&!R.hidden&&!R.classList.contains("docked")&&R._covers&&e.add(V),xe&&!we.hidden&&we._covers&&e.add(xe),document.querySelectorAll(".pin").forEach(t=>t.classList.toggle("carded",e.has(t.dataset.key)))}function Te(){if(f){if(Zt(),Hr(),O?.prompt&&!H.hidden){const e=qe(f.frames.find(t=>t.id===O.frameId));if(e){const t=hi(e),n=v.z,a=e.w*(1-2*t.lx)*n,s=Math.min(44,t.fs*n),i=P.get(e.id)?.el.querySelector(".frame-body"),o=!!i;if(H.classList.toggle("onpage",o),o)H.dataset.on=t.on,H.parentElement!==i&&(gi(i),H.style.left=H.style.top=H.style.width=""),(H._pz!==n||H._pw!==e.w)&&(H._pz=n,H._pw=e.w,ut(j));else{gi(document.body),H._pz=H._pw=null;const r=H.offsetWidth||380,l=H.offsetHeight||200,c=v.y+(e.y+e.h/2)*n;Vo(H,v.x+(e.x+e.w)*n,c-l/2+18)}}}else if(O&&!H.hidden){const e=Jn(O.frameId,O.anchor),t=Va(O.frameId,e.x,e.y);Vo(H,t.x,t.y,qt("__draft"))}if(V&&!R.hidden&&!R.classList.contains("docked")){const e=f.comments.find(t=>t.id===V);if(e?.anchor){const t=Jn(e.frameId,e.anchor),n=Va(e.frameId,t.x,t.y);Uo(R,n.x,n.y,!0,qt(V)),R._grow&&(R._grow=!1,Cc(R,qt(V)))}}if(Ua(),In(),Je){const e=Va(Je.frameId,Je.lx,Je.ly),t=m("#ink-chip");t.style.left=`${e.x+10}px`,t.style.top=`${e.y+10}px`}}}function mi(e){return f.strokes.filter(t=>t.frameId===e&&!t.commentId&&ho.has(t.id))}function et(e,t,n,a,s){Ne&&sa(!0),te(),ta(),H.classList.remove("prompt"),yi();const i=e===le?null:s?ui(e,s.x+s.w/2,s.y+s.h/2):ui(e,t,n),o=mi(e);O={frameId:e,picked:i,lx:t,ly:n,area:s||null,inkStrokes:o.map(c=>c.id)},Ic(e===le?"canvas":s?"area":"point");const r=m("#composer-area");r.classList.remove("chip-frame"),r.hidden=!s,s&&(r.textContent=e===le?`Area \xB7 ${O.anchor.near.length||"no"} frame${O.anchor.near.length===1?"":"s"}`:`Area \xB7 ${O.anchor.elements.length} element${O.anchor.elements.length===1?"":"s"}`);const l=m("#composer-ink");l.hidden=!o.length,l.innerHTML=`${lr}<span>${o.length} mark${o.length===1?"":"s"}</span>`,j.placeholder=k()?"Ask for a change":"Add a comment",ia.length=0,H.hidden=!1,j.value="",ut(j),Ei.paint(),vt(e),Te(),Wt(),setTimeout(()=>j.focus({preventScroll:!0}),0),vi(e)}function Xo(e,t){return f.frames.map(n=>({f:n,d:Math.hypot(Math.max(n.x-e,0,e-n.x-n.w),Math.max(n.y-t,0,t-n.y-n.h))})).sort((n,a)=>n.d-a.d).slice(0,2).filter(n=>n.d<1200).map(n=>n.f.name)}function Pc(e){const t=f.frames.filter(n=>n.x<e.x+e.w&&n.x+n.w>e.x&&n.y<e.y+e.h&&n.y+n.h>e.y).map(n=>n.name);return t.length?t:Xo(e.x+e.w/2,e.y+e.h/2)}function Dc(e,t){const n=ue(e);if(!n?.body)return[];const a=Math.max(12,Math.min(t.w,t.h)*.08),s=t.x-a,i=t.y-a,o=t.x+t.w+a,r=t.y+t.h+a,l=[];for(const u of n.body.querySelectorAll("*")){if(l.length>600)break;const p=u.getBoundingClientRect();!p.width||!p.height||["SCRIPT","STYLE","LINK","META"].includes(u.tagName)||p.left>=s&&p.top>=i&&p.right<=o&&p.bottom<=r&&l.push(u)}const c=new Set(l);let d=l.filter(u=>{for(let p=u.parentElement;p;p=p.parentElement)if(c.has(p))return!1;return!0});if(!d.length){const u=Se(e,t.x+t.w/2,t.y+t.h/2);u&&u!==n.documentElement&&(d=[u])}return d.slice(0,14).map(u=>({selector:jt(u),tag:u.tagName.toLowerCase(),text:(u.innerText||u.getAttribute("aria-label")||u.getAttribute("alt")||"").replace(/\s+/g," ").trim().slice(0,80)}))}function qc(e,t){const n=ue(e);let a=Se(e,t.x+t.w/2,t.y+t.h/2);for(;a&&a!==n?.body;){const s=a.getBoundingClientRect();if(s.left<=t.x+2&&s.top<=t.y+2&&s.right>=t.x+t.w-2&&s.bottom>=t.y+t.h-2)break;a=a.parentElement}return a&&a!==n?.documentElement?{selector:jt(a),tag:a.tagName.toLowerCase(),text:(a.innerText||"").replace(/\s+/g," ").trim().slice(0,80)}:null}function Ic(e){const t=O;if(!t)return;const n=f.frames.find(a=>a.id===t.frameId);t.scope=e,e==="canvas"&&t.area?t.anchor={scope:e,wx:t.area.x,wy:t.area.y,area:{w:t.area.w,h:t.area.h},near:Pc(t.area)}:e==="canvas"?t.anchor={scope:e,wx:t.lx,wy:t.ly,near:Xo(t.lx,t.ly)}:e==="area"?t.anchor={scope:e,x:t.area.x,y:t.area.y,w:t.area.w,h:t.area.h,sx:t.picked?.sx||0,sy:t.picked?.sy||0,elements:Dc(t.frameId,t.area),container:qc(t.frameId,t.area)}:t.anchor={...t.picked||{},scope:"point",x:t.lx,y:t.ly,fx:void 0,fy:void 0},Zn(t.frameId,t.anchor),vt(t.frameId),Te()}function hi(e){const t=e.w<=480;let n="light";if(e.fill==="none")n="canvas";else if(/^#[0-9a-f]{6}$/i.test(e.fill||"")){const a=parseInt(e.fill.slice(1),16);.299*(a>>16)+.587*(a>>8&255)+.114*(a&255)<140&&(n="dark")}return{fs:Math.max(e.w*.037,Math.min(30,e.w*.077)),lx:t?.09:.11,ty:t?.15:.27,on:n,what:e.w<=1024?"screen":"page"}}function gi(e){if(H.parentElement===e)return;const t=document.activeElement===j;e.appendChild(H),t&&j.focus({preventScroll:!0})}function yi(){H.classList.remove("onpage"),gi(document.body),H._pz=H._pw=null,document.querySelectorAll(".frame.prompting").forEach(e=>e.classList.remove("prompting"))}const Go={Mobile:["Login","Onboarding","Home feed","Profile","Settings","Checkout"],Tablet:["Dashboard","Reader","Calendar","Settings","Kanban board"],Desktop:["Landing page","Dashboard","Pricing","Sign up","Settings","Blog post"]},zc=e=>Go[e.w<=480?"Mobile":e.w<=1024?"Tablet":"Desktop"];function Hc(e,t,n,a){const s=e.hintBox||=e.el.querySelector(".empty-hint");if(!s)return;const i=H.querySelector(".c-model")?.textContent||"",o=`${a}|${n.on}|${t.w}|${i}`;if(s._key===o)return;s._key=o;const r=H.querySelector(".c-foot")?.cloneNode(!0);r?.querySelectorAll("input").forEach(l=>l.remove()),r?.querySelectorAll("button").forEach(l=>{l.tabIndex=-1,l.disabled=l.classList.contains("c-send")}),s.innerHTML=`<div class="pghost prompt onpage" data-on="${n.on}" aria-hidden="true"><textarea rows="1" readonly tabindex="-1" placeholder="${C(a)}"></textarea><div class="prompt-ideas">${zc(t).map(l=>`<button tabindex="-1">${C(l)}</button>`).join("")}</div></div>`,r&&s.firstChild.appendChild(r)}function ea(e){const t=f?.frames.find(a=>a.id===e);if(!t)return;if(O?.prompt&&O.frameId===e&&!H.hidden){j.focus({preventScroll:!0});return}te(),ta(),yi();const n=t.w<=480?"Mobile":t.w<=1024?"Tablet":"Desktop";O={frameId:e,picked:null,lx:24,ly:24,area:null,inkStrokes:[],prompt:!0,scope:"frame",anchor:{scope:"frame",x:24,y:24}},H.classList.add("prompt"),P.get(e)?.el.classList.add("prompting"),m("#prompt-title").textContent=`What should \u201C${t.name}\u201D be?`,m("#prompt-ideas").innerHTML=Go[n].map(a=>`<button>${C(a)}</button>`).join(""),m("#composer-area").hidden=!0,m("#composer-ink").hidden=!0,j.placeholder=`Describe this ${hi(t).what}`,ia.length=0,H.hidden=!1,j.value="",ut(j),Ei.paint(),Te(),setTimeout(()=>j.focus({preventScroll:!0}),0),vi(e)}function Xa(e){j.value=`${e} `,ut(j),Ei.paint(),j.focus(),j.setSelectionRange(j.value.length,j.value.length)}m("#prompt-ideas").addEventListener("click",e=>{const t=e.target.closest("button");t&&Xa(t.textContent)});const $n={x:-1,y:-1};addEventListener("pointerdown",e=>{$n.x=e.clientX,$n.y=e.clientY},!0);function bi(e,t){document.body.classList.add("ghost-hit");try{return document.elementsFromPoint(e,t).find(n=>n.matches?.(".frame.empty .pghost .prompt-ideas button"))?.textContent||null}finally{document.body.classList.remove("ghost-hit")}}function ae(){H.classList.contains("soft")&&(H.querySelector(".hint").innerHTML="<kbd>\u21B5</kbd> send \xB7 <kbd>\u21E7\u21B5</kbd> new line \xB7 <kbd>esc</kbd>"),H.classList.remove("prompt","soft"),yi(),Qo=null,ur(),O?.deep&&Ve(),document.querySelectorAll(".frame.whole, .section.whole").forEach(t=>t.classList.remove("whole"));const e=O?.frameId;O=null,H.hidden=!0,e&&vt(e),f&&Wt()}function ut(e){e.style.height="auto",e.style.height=`${Math.min(e===j&&H.classList.contains("onpage")?innerHeight*.45/v.z:180,e.scrollHeight)}px`}j.addEventListener("input",()=>ut(j)),Vr(j),j.addEventListener("keydown",e=>{if(e.stopPropagation(),e.key==="Enter"&&!e.shiftKey&&!e.isComposing){if(e.preventDefault(),O?.deep&&!j.value.trim()&&!ia.length&&L?.els.length===1&&_n(L.els[0],!0)&&k()){const{frameId:t,els:n}=L;ae(),Pn(t,n[0]);return}Zo()}e.key==="Escape"&&ae()});async function Zo(){const e=ia.splice(0),t=j.value.trim()||(e.length?"See the attached reference.":"");if(!t||!O)return;const n=O;ae(),Ae("select");const a=f.strokes.filter(o=>n.inkStrokes.includes(o.id)),s={id:Ia(),frameId:n.frameId,text:t,anchor:n.anchor,author:{name:Z.name,color:Z.color},inkStrokes:n.inkStrokes,attachments:e,refs:Ur(j,t)};a.length&&n.frameId!==le&&Object.assign(s,Oc(n.frameId,a));const i=Ga(s);try{const o=await x("POST","/__loop/api/comments",s);o?.id&&o.id!==s.id&&i(),k()||y("Comment added \u2014 the host will send it to the agent")}catch(o){i(),y(o.message)}}function Ga(e){if(X)return()=>{};const t={id:e.id,frameId:e.frameId,parentId:e.parentId||null,text:e.text,anchor:e.anchor||f.comments.find(n=>n.id===e.parentId)?.anchor||null,author:{...e.author,guest:!k()},inkStrokes:e.inkStrokes||[],status:k()?"queued":"waiting",reply:null,createdAt:Date.now(),local:!0,...e.attachments?.length?{attachments:e.attachments.map(n=>({name:n.name,type:n.type,url:n.data}))}:{}};f.comments.push(t);for(const n of f.strokes)t.inkStrokes.includes(n.id)&&(n.commentId=t.id);return Ra(),()=>{f.comments=f.comments.filter(n=>n!==t),Ra()}}const Jo=new Map;function vi(e){!f||X||!k()||!e||Date.now()-(Jo.get(e)||0)<6e4||(Jo.set(e,Date.now()),x("POST",`/__loop/api/frames/${e}/warm`).catch(()=>{}))}function Oc(e,t){const n=f.frames.find(c=>c.id===e),a=ue(e),s=new Map;for(const c of t){const d=c.points.length/2,u=Math.max(1,Math.floor(d/14));for(let p=0;p<d;p+=u){const h=c.points[p*2]-(c.fx??n.x),g=c.points[p*2+1]-(c.fy??n.y),w=Se(e,h,g);if(!w||w===a?.documentElement||w===a?.body)continue;const T=jt(w);s.has(T)||s.set(T,{selector:T,tag:w.tagName.toLowerCase(),text:(w.innerText||"").replace(/\s+/g," ").trim().slice(0,60),el:w})}}const i=[...s.values()].slice(0,10),o=Math.min(1,1280/Math.max(n.w,n.h)),r=document.createElement("canvas");r.width=Math.round(n.w*o),r.height=Math.round(n.h*o);const l=r.getContext("2d");l.scale(o,o),l.fillStyle="#fff",l.fillRect(0,0,n.w,n.h),l.strokeStyle="#C8C8CE",l.lineWidth=2,l.strokeRect(1,1,n.w-2,n.h-2),l.font="14px ui-monospace, Menlo, monospace";for(const c of i)try{const d=c.el.getBoundingClientRect();l.strokeStyle="#2F5BFF",l.setLineDash([6,4]),l.lineWidth=1.5,l.strokeRect(d.left,d.top,d.width,d.height),l.setLineDash([]),l.fillStyle="#2F5BFF",l.fillText(c.tag+(c.text?` "${c.text.slice(0,30)}"`:""),d.left+4,Math.max(14,d.top-4))}catch{}l.strokeStyle=Js,l.lineWidth=4,l.lineCap="round",l.lineJoin="round";for(const c of t){l.beginPath();for(let d=0;d<c.points.length;d+=2){const u=c.points[d]-(c.fx??n.x),p=c.points[d+1]-(c.fy??n.y);d?l.lineTo(u,p):l.moveTo(u,p)}l.stroke()}return{ink:i.map(({el:c,...d})=>d),annotationPng:r.toDataURL("image/png")}}function tu(e,t,n){Je={frameId:e,lx:t,ly:n},m("#ink-chip").hidden=!1,Te()}function ta(){Je=null,m("#ink-chip").hidden=!0}let Qo=null;function Rc(e,t,n){if(!(!H.hidden&&j.value.trim())){if(e){const a=f.frames.find(c=>c.id===e),s=mi(e),i=s.flatMap(c=>wn(c).filter((d,u)=>u%2===0)),o=s.flatMap(c=>wn(c).filter((d,u)=>u%2===1)),r=(i.length?(Math.min(...i)+Math.max(...i))/2:t[t.length-2])-a.x,l=(o.length?(Math.min(...o)+Math.max(...o))/2:t[t.length-1])-a.y;et(e,r,l)}else et(le,t[t.length-2],t[t.length-1],"canvas");O&&(O.soft=!0,H.classList.add("soft"),j.placeholder="What should change here?",H.querySelector(".hint").innerHTML="<kbd>\u21B5</kbd> send \xB7 <kbd>esc</kbd> skip",Qo={x:n.clientX,y:n.clientY,t:Date.now()})}}addEventListener("pointerdown",e=>{!O?.soft||H.hidden||H.contains(e.target)||j.value.trim()||U==="pen"&&e.target.closest("#viewport")||ae()},!0),j.addEventListener("input",()=>{O?.soft&&j.value.trim()&&(O.soft=!1,H.classList.remove("soft"))}),m("#ink-chip button").addEventListener("click",()=>{if(!Je)return;const e=mi(Je.frameId),t=f.frames.find(o=>o.id===Je.frameId),n=e.flatMap(o=>wn(o).filter((r,l)=>l%2===0)),a=e.flatMap(o=>wn(o).filter((r,l)=>l%2===1)),s=n.length?(Math.min(...n)+Math.max(...n))/2-t.x:Je.lx,i=a.length?(Math.min(...a)+Math.max(...a))/2-t.y:Je.ly;et(Je.frameId,s,i)});function na(e,t,n){Ne&&sa(!0),clearTimeout(ft),ft=null,Yt=!!n,e!==V&&(xt=!1),ae(),ta(),e!==V&&(Ja.length=0),Re(),e!==V&&(R.dataset.tid="",R._side=t||null,R.classList.remove("in","grow"),R.offsetWidth,R.classList.add(t?"grow":"in"),R._grow=!t),V=e,R.hidden=!1;{const a=f.comments.find(s=>s.id===e);bo(e)&&a&&vt(a.frameId)}R.classList.toggle("docked",xt),xt&&(R.style.left=R.style.top=R.style.maxHeight=""),Qa(),Qn(),Te()}function te(){V&&(ur(),(an.size||vn)&&(an.clear(),vn=null,Wt()),Dt(qt(V),4)&&(kn=V),clearTimeout(ft),ft=null,Yt=!1,xt=!1,V=null,R.hidden=!0,R.dataset.tid="",Qn(),Ua())}const on=e=>{const t=(Date.now()-e)/1e3;return t<60?"just now":t<3600?`${Math.floor(t/60)}m ago`:t<86400?`${Math.floor(t/3600)}h ago`:new Date(e).toLocaleDateString()};function rn(e){if(!e)return"";const t=/claude-([a-z]+)-(\d+)(?:-(\d+))?/i.exec(e);if(t)return`${t[1][0].toUpperCase()}${t[1].slice(1)} ${t[2]}${t[3]&&t[3].length<=2?"."+t[3]:""}`;const n=/^gpt-([\d.]+)(?:-([a-z]+))?/i.exec(e);return n?`GPT-${n[1]}${n[2]?" "+n[2][0].toUpperCase()+n[2].slice(1):""}`:e}function nu(e){const t=[];if(e.model&&t.push(rn(e.model)),e.startedAt&&e.finishedAt){const n=Math.round((e.finishedAt-e.startedAt)/1e3);t.push(n<60?`${n}s`:`${Math.floor(n/60)}m ${n%60}s`)}return t.length?`<div class="a-meta">${C(t.join(" \xB7 "))}</div>`:""}const au=A("check","s"),Nc={claude:'<svg class="lg claude" viewBox="0 0 24 24"><path d="m4.7144 15.9555 4.7174-2.6471.079-.2307-.079-.1275h-.2307l-.7893-.0486-2.6956-.0729-2.3375-.0971-2.2646-.1214-.5707-.1215-.5343-.7042.0546-.3522.4797-.3218.686.0608 1.5179.1032 2.2767.1578 1.6514.0972 2.4468.255h.3886l.0546-.1579-.1336-.0971-.1032-.0972L6.973 9.8356l-2.55-1.6879-1.3356-.9714-.7225-.4918-.3643-.4614-.1578-1.0078.6557-.7225.8803.0607.2246.0607.8925.686 1.9064 1.4754 2.4893 1.8336.3643.3035.1457-.1032.0182-.0728-.164-.2733-1.3539-2.4467-1.445-2.4893-.6435-1.032-.17-.6194c-.0607-.255-.1032-.4674-.1032-.7285L6.287.1335 6.6997 0l.9957.1336.419.3642.6192 1.4147 1.0018 2.2282 1.5543 3.0296.4553.8985.2429.8318.091.255h.1579v-.1457l.1275-1.706.2368-2.0947.2307-2.6957.0789-.7589.3764-.9107.7468-.4918.5828.2793.4797.686-.0668.4433-.2853 1.8517-.5586 2.9021-.3643 1.9429h.2125l.2429-.2429.9835-1.3053 1.6514-2.0643.7286-.8196.85-.9046.5464-.4311h1.0321l.759 1.1293-.34 1.1657-1.0625 1.3478-.8804 1.1414-1.2628 1.7-.7893 1.36.0729.1093.1882-.0183 2.8535-.607 1.5421-.2794 1.8396-.3157.8318.3886.091.3946-.3278.8075-1.967.4857-2.3072.4614-3.4364.8136-.0425.0304.0486.0607 1.5482.1457.6618.0364h1.621l3.0175.2247.7892.522.4736.6376-.079.4857-1.2142.6193-1.6393-.3886-3.825-.9107-1.3113-.3279h-.1822v.1093l1.0929 1.0686 2.0035 1.8092 2.5075 2.3314.1275.5768-.3218.4554-.34-.0486-2.2039-1.6575-.85-.7468-1.9246-1.621h-.1275v.17l.4432.6496 2.3436 3.5214.1214 1.0807-.17.3521-.6071.2125-.6679-.1214-1.3721-1.9246L14.38 17.959l-1.1414-1.9428-.1397.079-.674 7.2552-.3156.3703-.7286.2793-.6071-.4614-.3218-.7468.3218-1.4753.3886-1.9246.3157-1.53.2853-1.9004.17-.6314-.0121-.0425-.1397.0182-1.4328 1.9672-2.1796 2.9446-1.7243 1.8456-.4128.164-.7164-.3704.0667-.6618.4008-.5889 2.386-3.0357 1.4389-1.882.929-1.0868-.0062-.1579h-.0546l-6.3385 4.1164-1.1293.1457-.4857-.4554.0608-.7467.2307-.2429 1.9064-1.3114Z"/></svg>',codex:'<svg class="lg" viewBox="0 0 24 24"><path d="M22.2819 9.8211a5.9847 5.9847 0 0 0-.5157-4.9108 6.0462 6.0462 0 0 0-6.5098-2.9A6.0651 6.0651 0 0 0 4.9807 4.1818a5.9847 5.9847 0 0 0-3.9977 2.9 6.0462 6.0462 0 0 0 .7427 7.0966 5.98 5.98 0 0 0 .511 4.9107 6.051 6.051 0 0 0 6.5146 2.9001A5.9847 5.9847 0 0 0 13.2599 24a6.0557 6.0557 0 0 0 5.7718-4.2058 5.9894 5.9894 0 0 0 3.9977-2.9001 6.0557 6.0557 0 0 0-.7475-7.0729zm-9.022 12.6081a4.4755 4.4755 0 0 1-2.8764-1.0408l.1419-.0804 4.7783-2.7582a.7948.7948 0 0 0 .3927-.6813v-6.7369l2.02 1.1686a.071.071 0 0 1 .038.052v5.5826a4.504 4.504 0 0 1-4.4945 4.4944zm-9.6607-4.1254a4.4708 4.4708 0 0 1-.5346-3.0137l.142.0852 4.783 2.7582a.7712.7712 0 0 0 .7806 0l5.8428-3.3685v2.3324a.0804.0804 0 0 1-.0332.0615L9.74 19.9502a4.4992 4.4992 0 0 1-6.1408-1.6464zM2.3408 7.8956a4.485 4.485 0 0 1 2.3655-1.9728V11.6a.7664.7664 0 0 0 .3879.6765l5.8144 3.3543-2.0201 1.1685a.0757.0757 0 0 1-.071 0l-4.8303-2.7865A4.504 4.504 0 0 1 2.3408 7.872zm16.5963 3.8558L13.1038 8.364 15.1192 7.2a.0757.0757 0 0 1 .071 0l4.8303 2.7913a4.4944 4.4944 0 0 1-.6765 8.1042v-5.6772a.79.79 0 0 0-.407-.667zm2.0107-3.0231l-.142-.0852-4.7735-2.7818a.7759.7759 0 0 0-.7854 0L9.409 9.2297V6.8974a.0662.0662 0 0 1 .0284-.0615l4.8303-2.7866a4.4992 4.4992 0 0 1 6.6802 4.66zM8.3065 12.863l-2.02-1.1638a.0804.0804 0 0 1-.038-.0567V6.0742a4.4992 4.4992 0 0 1 7.3757-3.4537l-.142.0805L8.704 5.459a.7948.7948 0 0 0-.3927.6813zm1.0976-2.3654l2.602-1.4998 2.6069 1.4998v2.9994l-2.5974 1.4997-2.6067-1.4997Z"/></svg>',loop:'<svg class="lg ring" viewBox="0 0 24 24"><circle cx="12" cy="12" r="6.5"/></svg>'};function Bc(e){const t=String(e?.model||"").toLowerCase();return/claude|opus|sonnet|haiku|fable|mythos/.test(t)?"claude":/gpt|codex|^o\d/.test(t)||f?.agentBin==="codex"?"codex":f?.agentBin==="claude"?"claude":"loop"}const Fc={claude:"Claude",codex:"Codex",loop:"Agent"},er=e=>{const t=Bc(e);return`<span class="m-mark" title="${Fc[t]}">${Nc[t]}</span>`};function su(e){if(!(e.startedAt&&e.finishedAt))return"";const t=Math.round((e.finishedAt-e.startedAt)/1e3);return`<span title="${C(e.model?rn(e.model):"")}">Worked ${t<60?`${t}s`:`${Math.floor(t/60)}m ${t%60}s`}</span>`}const aa={undo:A("undo"),before:A("before"),redo:A("redo"),copy:A("copy"),check:A("check"),stop:A("stop"),send:A("up"),retry:A("retry"),steer:A("steer"),bg:A("play"),x:A("x")},tt=(e,t,n,a,s="")=>`<button class="a-btn${a?" lbl":""}${s?" "+s:""}" ${t} title="${C(n)}" aria-label="${C(n)}">${aa[e]}${a?`<span>${C(a)}</span>`:""}</button>`;function Wc(e){const t=k(),n=(s,i,o,r)=>`<div class="m-agent ${s}">${er(e)}<div class="m-body">${i}${o?`<div class="m-acts${r?" show":""}">${o}</div>`:""}</div></div>`,a=`data-id="${e.id}"`;switch(e.status){case"waiting":return n("quiet",'<div class="m-text">Waiting for the host to send this to the agent.</div>',t?tt("send",`data-act="send" ${a}`,"Send to the agent","Send","primary"):"",!0);case"queued":{if(e.local)return n("quiet",'<div class="m-work"><span class="a-text">Sending\u2026</span></div>',"");const s=e.parentId||e.id,i=t&&sn(s).some(c=>c.status==="working"),o=f.agent.mode==="inbox"&&!e.background,r=o&&!f.chatListening,l=i?"Queued \xB7 runs after the current change":r?f.chatHistory?"Your chat isn\u2019t listening, so this carries on in the background in a moment, with what that chat knows.":"Your chat isn\u2019t listening, so this starts in a new session in a moment.":o?"Sent to your chat":"Queued";return n("quiet",`<div class="m-work"><span class="a-text">${l}</span></div>`,t?`${i?tt("steer",`data-act="steer" ${a}`,"Steer: stop the current run and include this message in it","Steer","primary"):""}${r?tt("bg",`data-act="background" ${a}`,f.chatHistory?"Carry on now in the background, from a copy of your chat":"Run it now in the background, without your chat\u2019s context","Run now"):""}${tt("x",`data-act="cancel" ${a}`,"Cancel")}`:"",!0)}case"working":return n("",`<ol class="m-steps" data-steps-for="${e.id}"></ol><div class="m-work"><span class="a-text" data-step-for="${e.id}"></span><span class="m-time" data-elapsed-from="${f.live[e.frameId]?.startedAt||e.startedAt||e.createdAt}"></span>${t?tt("stop",`data-act="cancel" ${a}`,"Stop"):""}</div><div class="m-text md m-stream" data-partial-for="${e.id}" hidden></div>`,"");case"done":return n("",`${Vc(e)}<div class="m-text md">${e.undone?"Reverted.":Za(e.reply||"Done.")}</div>${Xc(e)}${tr(e)}`,`${e.snapshot&&!X&&f.frames.find(s=>s.id===e.frameId)?.kind==="folder"?tt("before",`data-act="before" ${a}`,"See the frame before this change"):""}${t&&e.snapshot&&!e.undone?tt("undo",`data-act="undo" ${a}`,"Undo this change"):""}${t&&e.undone&&e.redoSnap?tt("redo",`data-act="redo" ${a}`,"Redo this change"):""}${tt("copy",`data-copy="${e.id}"`,"Copy the reply")}<time>${on(e.finishedAt||e.createdAt)}</time>`);case"error":return n("error",`<div class="m-text">${C(e.reply||"Something went wrong.")}</div>${tr(e)}`,t?tt("retry",`data-act="send" ${a}`,"Try again","Retry","primary"):"",!0);case"interrupted":return n("quiet",'<div class="m-text">Interrupted \xB7 continued below</div>',"");case"canceled":return n("quiet",'<div class="m-text">Stopped.</div>',t?tt("retry",`data-act="send" ${a}`,"Send again","Send again","primary"):"",!0);default:return""}}const wi=e=>(e?.blocked||[]).filter(t=>!t.allowed);function jc(e){const t=wi(e);return t.length===1?{act:"allow",say:"Blocked",btn:"Allow",tip:`The agent wasn\u2019t allowed to use ${t[0].label}. Allow it on this canvas and let the agent carry on.`}:{act:"allow",say:`${t.length} blocked`,btn:"Allow all",tip:`The agent wasn\u2019t allowed to use: ${t.map(a=>a.label).join(" \xB7 ")}. Allow them all on this canvas and let the agent carry on. (Press the pin itself to see them one by one.)`}}function tr(e){if(!e.blocked?.length)return"";const t=k()&&!X;return`<div class="m-blocked">${e.blocked.map((n,a)=>`<div class="blk${n.allowed?" ok":""}">
|
|
18
|
+
<span class="blk-k">${n.allowed?"Allowed":"Blocked"}</span><code title="${C(n.cmd||n.label)}">${C(n.label)}</code>
|
|
19
|
+
${!n.allowed&&t?`<button class="blk-go" data-act="allow" data-id="${e.id}" data-k="${a}" title="Let the agent use this on this canvas from now on, and carry on">Allow</button>`:""}</div>`).join("")}${t&&wi(e).length>1?`<div class="blk blk-all"><button class="blk-go" data-act="allowall" data-id="${e.id}" title="Let the agent use all of these on this canvas from now on, and carry on">Allow all</button></div>`:""}</div>`}const Yc={read:A("read"),edit:A("edit"),find:A("find"),look:A("look"),run:A("run"),think:A("think"),add:A("add")},Kc=e=>Yc[/^(Reading)/.test(e)?"read":/^(Editing|Writing)/.test(e)?"edit":/^Searching/.test(e)?"find":/^(Looking|Taking)/.test(e)?"look":/^(Adding|Setting|Making)/.test(e)?"add":/^(Running)/.test(e)?"run":"think"],nr=e=>e.say?`<li class="say"><div class="md">${Za(e.s)}</div></li>`:`<li>${Kc(e.s)}<span>${C(e.s)}</span></li>`;function Vc(e){const t=(e.steps||[]).filter(s=>s.s!=="Thinking\u2026"),n=e.startedAt&&e.finishedAt?Math.round((e.finishedAt-e.startedAt)/1e3):0;if(!n&&!t.length)return"";const a=n?`Worked for ${n<60?`${n}s`:`${Math.floor(n/60)}m ${n%60}s`}`:"Worked";return t.length?`<details class="m-did"><summary><span>${a}</span>${A("right","s")}</summary><ol class="m-steps">${t.map(nr).join("")}</ol></details>`:`<div class="m-did flat"><span>${a}</span></div>`}function ar(e,t=document){const n=f.comments.find(r=>r.id===e);if(!n)return;const a=(n.steps||[]).filter(r=>r.s!=="Thinking\u2026"),s=f.live[n.frameId]?.commentId===e?f.live[n.frameId].step:null,o=(a.length&&!a[a.length-1].say&&a[a.length-1].s===s?a.slice(0,-1):a).slice(-8).map(nr).join("");t.querySelectorAll(`[data-steps-for="${e}"]`).forEach(r=>{r._h!==o&&(r._h=o,r.innerHTML=o,r.hidden=!o)})}function xi(e,t){return e.kind==="note"?`<div class="m-agent">${er(e)}<div class="m-body"><div class="m-text md">${Za(e.text)}</div><div class="m-acts">${tt("copy",`data-copy="${e.id}"`,"Copy")}<time>${on(e.createdAt)}</time></div></div></div>`:`<div class="m-user">
|
|
20
|
+
<div class="bubble${e.attachments?.length?" has-files":""}">${Gc(e)}<div class="b-text">${C(e.text)}</div>${Zc(e)}</div>
|
|
21
|
+
<div class="m-meta">${e.author?.guest||e.author?.name&&e.author.name!==Z.name?`${C(e.author?.name||"Guest")} \xB7 `:""}${on(e.createdAt)}</div>
|
|
22
|
+
</div>${t?"":Wc(e)}`}function Uc(){for(const[e,t]of P){const n=[...f.comments].reverse().find(u=>u.frameId===e&&u.options?.some(p=>p.files?.length&&!p.frameId)&&!u.optionChosen&&!u.optionsCleared);let a=t.el.querySelector(":scope > .opt-strip");if(!n||!k()){a?.remove();continue}const s=f.frames.find(u=>u.id===e),i=s?s.w/s.h:1.5,o=Math.round(Math.min(150,Math.max(70,84*i))),r=Math.round(o/i),l=n.options.filter(u=>u.files?.length&&!u.frameId),c=n.id+"|"+(n.optionApplied||"")+"|"+l.map(u=>u.id+(u.thumb||"")).join(",");if(a?.dataset.key===c)continue;a||(a=document.createElement("div"),a.className="opt-strip",t.el.appendChild(a),a.addEventListener("pointerdown",u=>u.stopPropagation()),a.addEventListener("click",async u=>{const p=u.target.closest("[data-opt]"),h=u.target.closest("[data-use]"),g=a.dataset.cid;try{h?(await x("POST",`/__loop/api/comments/${g}/choose`,{option:h.dataset.use}),y(`Using option ${h.dataset.use}`)):p&&await x("POST",`/__loop/api/comments/${g}/preview`,{option:p.dataset.opt||null})}catch(w){y(w.message)}})),a.dataset.key=c,a.dataset.cid=n.id;const d=(u,p,h)=>`<button class="os-tile${(n.optionApplied||"")===u?" on":""}" data-opt="${u}" title="${u?`Preview ${C(p)}`:"Back to the original"}">
|
|
23
|
+
<span class="os-img" style="width:${o}px;height:${r}px">${h?`<img src="${C(h)}" alt="">`:`<b>${u||"\xB7"}</b>`}</span>
|
|
24
|
+
<span class="os-name">${u?`<i>${u}</i>`:""}${C(p)}</span></button>`;a.innerHTML=`<span class="os-label">Options</span>${d("","Original",n.origThumb||"")}${l.map(u=>d(u.id,u.name,u.thumb)).join("")}
|
|
25
|
+
${n.optionApplied?`<button class="os-use" data-use="${n.optionApplied}">Use ${n.optionApplied}</button>`:""}`,l.some(u=>!u.thumb)&&s?.kind==="folder"&&!n._thumbsAsked&&(n._thumbsAsked=!0,x("POST",`/__loop/api/comments/${n.id}/thumbs`).catch(()=>{}))}}function Xc(e){const t=(e.options||[]).filter(a=>a.files?.length);if(!t.length)return"";if(t.some(a=>a.frameId)||e.optionsCleared){const a=t.filter(s=>s.frameId&&f.frames.some(i=>i.id===s.frameId));return a.length?`<div class="m-opts">${a.map(s=>`<button class="opt${e.optionChosen===s.id?" on":""}" data-goto="${s.frameId}" title="Go to this option's frame"><b>${C(s.id)}</b>${C(s.name)}</button>`).join("")}</div>`:e.optionChosen?`<div class="m-opts chosen"><span class="opt on"><b>${C(e.optionChosen)}</b>${C(t.find(s=>s.id===e.optionChosen)?.name||"")}</span><span class="opt-note">Chosen</span></div>`:""}if(e.optionChosen){const a=t.find(s=>s.id===e.optionChosen);return`<div class="m-opts chosen"><span class="opt on"><b>${C(a?.id||"")}</b>${C(a?.name||"")}</span><span class="opt-note">Chosen</span></div>`}const n=k();return`<div class="m-opts">${t.map(a=>`<button class="opt${e.optionApplied===a.id?" on":""}" ${n?`data-opt="${a.id}" data-for="${e.id}"`:"disabled"} title="Preview in the frame"><b>${C(a.id)}</b>${C(a.name)}</button>`).join("")}
|
|
26
|
+
${n&&e.optionApplied?`<span class="opt-acts"><button class="opt-use" data-use="${e.optionApplied}" data-for="${e.id}">Use ${C(e.optionApplied)}</button><button class="opt-orig" data-opt="" data-for="${e.id}">Original</button></span>`:`<span class="opt-note">${n?"Click an option to preview it in the frame":"Options"}</span>`}</div>`}R.addEventListener("click",async e=>{const t=e.target.closest("[data-goto]");if(t){const i=t.dataset.goto;f.frames.some(o=>o.id===i)&&(te(),Q(i),Oe(!0,[i]));return}const n=e.target.closest("[data-opt]"),a=e.target.closest("[data-use]");if(!n&&!a)return;const s=(n||a).dataset.for;try{a?(await x("POST",`/__loop/api/comments/${s}/choose`,{option:a.dataset.use}),y(`Using option ${a.dataset.use}`)):await x("POST",`/__loop/api/comments/${s}/preview`,{option:n.dataset.opt||null})}catch(i){y(i.message)}});function Za(e){const t=s=>C(s).replace(/`([^`]+)`/g,"<code>$1</code>").replace(/\*\*([^*]+)\*\*/g,"<b>$1</b>").replace(/(^|[\s(])\*([^*\s][^*]*)\*/g,"$1<i>$2</i>"),n=[];let a=null;for(const s of String(e).split(`
|
|
27
|
+
`)){const i=/^\s*(?:[-*•]|\d+\.)\s+(.*)$/.exec(s);if(i){a||(a=[],n.push(a)),a.push(t(i[1]));continue}a=null,s.trim()&&n.push(`<p>${t(s)}</p>`)}return n.map(s=>Array.isArray(s)?`<ul>${s.map(i=>`<li>${i}</li>`).join("")}</ul>`:s).join("")}function Gc(e){return e.attachments?.length?`<div class="m-files">${e.attachments.map(t=>t.type.startsWith("image/")?`<a href="${C(t.url)}" target="_blank" rel="noopener"><img src="${C(t.url)}" alt="${C(t.name)}"></a>`:`<a class="f" href="${C(t.url)}" target="_blank" rel="noopener">${Ln.file}<span>${C(t.name)}</span></a>`).join("")}</div>`:""}const Ja=[];function Zc(e){const t=(e.inkStrokes||[]).filter(a=>f.strokes.some(s=>s.id===a)).length;if(!t)return"";const n=an.has(e.id);return`<button class="m-marks${n?" on":""}" data-marks="${e.id}" title="${n?"Hide":"Show"} the marks on the canvas">${lr}<span>${n?"Hide":`${t} mark${t===1?"":"s"}`}</span></button>`}R.addEventListener("pointerover",e=>{const t=e.target.closest("[data-marks]");t&&vn!==t.dataset.marks&&(vn=t.dataset.marks,Wt())}),R.addEventListener("pointerout",e=>{const t=e.target.closest("[data-marks]");t&&!t.contains(e.relatedTarget)&&(vn=null,Wt())}),R.addEventListener("click",e=>{const t=e.target.closest("[data-marks]");if(!t)return;const n=t.dataset.marks;an.has(n)?an.delete(n):an.add(n),Wt(),Qa()});function Qa(){const e=f.comments.find(s=>s.id===V);if(!e)return te();if(R.dataset.tid!==e.id){R.dataset.tid=e.id,R.innerHTML=`<div class="t-tools"></div><div class="thread-body"></div>
|
|
28
|
+
<div class="thread-reply"><div class="cbox"><div class="c-files" hidden></div><textarea rows="1" placeholder="Reply"></textarea></div></div>`,R._tools=null;const s=R.querySelector("textarea");Vr(s);const i=async()=>{const r=f.comments.find(h=>h.id===V);if(!r)return;const l=Ja.splice(0),c=s.value.trim()||(l.length?"See the attached reference.":"");if(!c)return;s.value="",ut(s),o.paint();const d={id:Ia(),frameId:r.frameId,parentId:r.id,text:c,author:{name:Z.name,color:Z.color},attachments:l,refs:Ur(s,c)},u=Ga(d),p=R.querySelector(".thread-body");p&&(p.scrollTop=p.scrollHeight);try{const h=await x("POST","/__loop/api/comments",d);h?.id&&h.id!==d.id&&u()}catch(h){u(),y(h.message)}},o=fr(R.querySelector(".thread-reply .cbox"),Ja,i);ut(s),s.addEventListener("input",()=>ut(s)),s.addEventListener("keydown",r=>{if(r.stopPropagation(),r.key==="Escape")return te();r.key==="Enter"&&!r.shiftKey&&!r.isComposing&&(r.preventDefault(),i())}),s.addEventListener("focus",()=>vi(f.comments.find(r=>r.id===V)?.frameId),{once:!0})}const t=`
|
|
29
|
+
${Bo(e)}
|
|
30
|
+
<span class="t-title">${C(e.frameId===le?"Canvas":f.frames.find(s=>s.id===e.frameId)?.name||"")}</span>
|
|
31
31
|
${e.resolved?'<span class="t-state">Resolved</span>':""}
|
|
32
|
-
<button class="t-btn" data-act="dock" title="${
|
|
33
|
-
<button class="t-btn" data-act="resolve" title="${e.resolved?"Reopen":"Resolve"}">${e.resolved?
|
|
34
|
-
<span class="t-more"><button class="t-btn" data-act="more" title="More">${
|
|
35
|
-
<span class="t-menu" hidden><button data-act="delete">${
|
|
36
|
-
<button class="t-btn" data-act="close" title="Close (esc)">${
|
|
37
|
-
<div class="cp-item${
|
|
38
|
-
<span class="cp-av${r==="working"||r==="queued"?" busy":r==="error"?" err":""}">${
|
|
39
|
-
<span class="cp-text">${
|
|
40
|
-
${
|
|
41
|
-
</div>`}).join(""):`<div class="cp-empty">${
|
|
42
|
-
<div class="mm-title">Effort</div>${n("effort","",t,e.chat.effort?
|
|
43
|
-
${f.agent.mode==="inbox"?'<p class="mm-note">Your chat answers with its own model. This is for the runs Loop starts itself.</p>':""}`}function Eo(){if(!za?.isConnected){ve.hidden=!0;return}const e=za.getBoundingClientRect(),t=ve.offsetWidth,n=ve.offsetHeight,a=e.top-n-8>=8||e.top>innerHeight-e.bottom;ve.style.left=`${Math.max(8,Math.min(innerWidth-t-8,e.right-t))}px`,ve.style.top=`${Math.max(8,Math.min(innerHeight-n-8,a?e.top-n-8:e.bottom+8))}px`}document.addEventListener("click",e=>{const t=e.target.closest(".c-model.pick");if(t){if(!ve.hidden&&za===t){ve.hidden=!0;return}za=t,Mo(),ve.hidden=!1,Eo()}}),ve.addEventListener("pointerdown",e=>e.stopPropagation()),ve.addEventListener("click",async e=>{const t=e.target.closest("[data-mm]");if(t){if(f.models){const n=f.models,a=t.dataset.mm;n.pick[a]=t.dataset.v||null,n[a]=n.pick[a]||n.chat[a],Ui()}try{await w("POST","/__loop/api/settings",{pick:{[t.dataset.mm]:t.dataset.v||null}})}catch(n){y(n.message)}}}),addEventListener("pointerdown",e=>{!ve.hidden&&!e.target.closest("#model-menu, .c-model")&&(ve.hidden=!0)},!0),addEventListener("keydown",e=>{e.key==="Escape"&&!ve.hidden&&(ve.hidden=!0,e.stopPropagation())},!0);function Ui(){const e=Jl(),t=!!f?.models&&$();document.querySelectorAll(".c-model").forEach(n=>{n.textContent!==e&&(n.textContent=e),n.classList.toggle("pick",t),n.title=t?"Model and effort":""}),ve.hidden||(Mo(),Eo())}function Jl(){if(!f)return"";if(!$())return"Host reviews first";const e=f.models;if(e?.model){const a=f.agent.lastModel,i=e.pick.model&&a&&a.startsWith(`claude-${e.pick.model}-`)?a:e.model;return Vi(i)+(e.pick.effort?` \xB7 ${Xi(e.pick.effort)}`:"")}const t=f.agent.lastModel;return t&&(f.agentBin==="codex"?!/^claude/.test(t):/^claude/.test(t))?Zt(t):f.agentLabel||"Agent"}const ec=e=>new Promise((t,n)=>{const a=new FileReader;a.onload=()=>t(a.result),a.onerror=n,a.readAsDataURL(e)});function So(e,t,n){e.insertAdjacentHTML("beforeend",`<div class="c-foot"><button type="button" class="c-btn" data-box="attach" title="Attach images or files \u2014 or drop them here">${pn.plus}</button><input type="file" multiple hidden><span class="c-model"></span>${Lo?`<button type="button" class="c-btn" data-box="mic" title="Dictate">${pn.mic}</button>`:""}<button type="button" class="c-send" data-box="send" title="Send (\u21B5)">${pn.up}</button></div>`);const a=e.querySelector("textarea"),i=e.querySelector("input[type=file]"),s=e.querySelector(".c-files"),o=e.querySelector(".c-send"),r=()=>{o.disabled=!a.value.trim()&&!t.length},c=()=>{s.hidden=!t.length,s.innerHTML=t.map((d,u)=>`<span class="c-file${d.type.startsWith("image/")?" img":""}" title="${L(d.name)}">${d.type.startsWith("image/")?`<img src="${d.data}" alt="">`:`${pn.file}<span>${L(d.name)}</span>`}<button type="button" data-rm="${u}" title="Remove">${pn.x}</button></span>`).join(""),Ui(),r()},l=async d=>{for(const u of d){if(t.length>=$o){y(`Up to ${$o} files per message`);break}if(u.size>Zl){y(`${u.name} is over 8 MB`);continue}t.push({name:u.name||"pasted-image.png",type:u.type||"application/octet-stream",data:await ec(u)})}c(),a.focus()};return i.addEventListener("change",()=>{l([...i.files]),i.value=""}),e.addEventListener("click",d=>{const u=d.target.closest("[data-rm]");if(u){t.splice(+u.dataset.rm,1),c();return}const p=d.target.closest("[data-box]");p&&(p.dataset.box==="attach"?i.click():p.dataset.box==="mic"?tc(a,p,r):p.dataset.box==="send"&&n())}),e.addEventListener("dragover",d=>{[...d.dataTransfer.types].includes("Files")&&(d.preventDefault(),d.stopPropagation(),e.classList.add("drop"))}),e.addEventListener("dragleave",d=>{e.contains(d.relatedTarget)||e.classList.remove("drop")}),e.addEventListener("drop",d=>{d.preventDefault(),d.stopPropagation(),e.classList.remove("drop"),l([...d.dataTransfer.files])}),a.addEventListener("paste",d=>{const u=[...d.clipboardData?.files||[]];u.length&&(d.preventDefault(),l(u))}),a.addEventListener("input",r),c(),{paint:c}}let mn=null;function tc(e,t,n){if(mn){mn.stop();return}const a=new Lo;a.continuous=!0,a.interimResults=!0,a.lang=navigator.language||"en-US";const i=e.value&&!/\s$/.test(e.value)?e.value+" ":e.value;a.onresult=s=>{let o="";for(const r of s.results)o+=r[0].transcript;e.value=i+o,ot(e),n()},a.onend=()=>{mn=null,t.classList.remove("on"),e.focus()},a.onerror=s=>{s.error==="not-allowed"||s.error==="service-not-allowed"?y("Allow microphone access to dictate"):["aborted","no-speech"].includes(s.error)||y(`Dictation stopped (${s.error})`)},mn=a,t.classList.add("on");try{a.start()}catch{mn=null,t.classList.remove("on")}}function To(){try{mn?.stop()}catch{}}const Zi=So(H.querySelector(".cbox"),Kn,()=>mo());z.addEventListener("pointerdown",e=>{e.stopPropagation(),It=!1}),z.addEventListener("click",async e=>{const t=e.target.closest("[data-act]");if(!t)return;const n=t.dataset.act,a=t.dataset.id||j;try{if(n==="close")return ee();if(n==="dock"){pt=!pt,It=!1,z.classList.toggle("docked",pt),pt&&(z.style.left=z.style.top=z.style.maxHeight=""),Ia(),_e();return}if(n==="more"){const i=z.querySelector(".t-menu");i.hidden=!i.hidden;return}if(n==="allow"){t.disabled=!0,t.textContent="Allowing\u2026",await w("POST",`/__loop/api/comments/${a}/allow`,{i:+t.dataset.k});return}if(n==="allowall"){t.disabled=!0,t.textContent="Allowing\u2026",await w("POST",`/__loop/api/comments/${a}/allow`,{all:!0,i:f.comments.find(i=>i.id===a)?.blocked?.findIndex(i=>!i.allowed)});return}if(n==="before"){const i=f.comments.find(s=>s.id===a);i&&(Ls(i.frameId,i.id),St(i.frameId));return}if(n==="delete"){confirm("Delete this comment thread? This can\u2019t be undone.")&&(await w("DELETE",`/__loop/api/comments/${j}`),ee());return}if(n==="resolve"){const i=f.comments.find(s=>s.id===j)?.resolved;await w("POST",`/__loop/api/comments/${j}/resolve`),i||(ee(),y("Resolved. Find it in Comments \u2192 Resolved"));return}if(n==="undo"){let i=await fetch(`/__loop/api/comments/${a}/undo`,{method:"POST",headers:{"content-type":"application/json"},body:"{}"}),s=await i.json().catch(()=>({}));if(i.status===409&&s.error==="newer"){if(!confirm(`This frame has ${s.newer} newer change${s.newer===1?"":"s"} after this one. Undoing this reverts ${s.newer===1?"it":"them"} too. Continue?`))return;i=await fetch(`/__loop/api/comments/${a}/undo`,{method:"POST",headers:{"content-type":"application/json"},body:JSON.stringify({force:!0})}),s=await i.json().catch(()=>({}))}if(!i.ok)throw new Error(s.error||"Could not undo");y(s.reverted>1?`Reverted ${s.reverted} changes`:"Change reverted");return}await w("POST",`/__loop/api/comments/${a}/${n}`),n==="redo"&&y("Change re-applied")}catch(i){y(i.message)}}),H.addEventListener("pointerdown",e=>e.stopPropagation()),m("#empty .empty-set").addEventListener("pointerdown",e=>e.stopPropagation()),m("#empty").addEventListener("click",e=>{const t=e.target.closest(".empty-frame");t&&$()&&bn(t.dataset.name,+t.dataset.w,+t.dataset.h)});for(const e of["click","dblclick","contextmenu"])H.addEventListener(e,t=>{H.classList.contains("onpage")&&t.stopPropagation()});addEventListener("scroll",()=>{for(const e of[document.scrollingElement,document.body,I])e&&(e.scrollTop||e.scrollLeft)&&(e.scrollTop=0,e.scrollLeft=0)},!0);let Be=!1;function Ee(e){if(!((e==="frame"||e==="section")&&!$())){if(Be=e==="use",Be&&(e="select"),!Be&&fe&&!S&&(fe=null,ht()),e!=="deep"&&x&&Ve(),B?.soft&&!W.value.trim()&&te(),K=e,I.dataset.tool=e,e!=="select"&&fe&&(fe=null,ht()),e==="select"||e==="hand"){const t=m("#move-btn");t.dataset.tool!==e&&(t.dataset.tool=e,t.innerHTML=A(e==="hand"?"hand":"select"),t.title=e==="hand"?"Hand (H)":"Select (V)")}if(document.querySelectorAll("#tool-menu [data-pick-tool]").forEach(t=>t.classList.toggle("on",t.dataset.pickTool===e&&!Be)),document.querySelectorAll("#toolbar [data-tool]").forEach(t=>t.classList.toggle("on",t.dataset.tool===(Be?"use":e))),I.dataset.use=Be?"1":"",ws(),Xo(),Be&&x&&(te(),Ve()),V.hidden=!0,e!=="pen"&&Bn(),f)for(const t of f.frames)J(t);Fe()}}document.querySelectorAll("#toolbar [data-tool]").forEach(e=>e.addEventListener("click",()=>Ee(e.dataset.tool)));const mt=m("#tool-menu");m("#move-caret").addEventListener("click",e=>{if(e.stopPropagation(),!mt.hidden){mt.hidden=!0;return}mt.hidden=!1;const t=m("#move-caret").closest(".tb-group").getBoundingClientRect();mt.style.left=`${Math.round(t.left)}px`,mt.style.bottom=`${Math.round(innerHeight-t.top+8)}px`,mt.style.top="auto"}),mt.addEventListener("click",e=>{const t=e.target.closest("[data-pick-tool]");t&&(Ee(t.dataset.pickTool),mt.hidden=!0)}),addEventListener("pointerdown",e=>{!mt.hidden&&!e.target.closest("#tool-menu, #move-caret")&&(mt.hidden=!0)},!0);let Ke=null,fe=null;function Gi(e){if(fe!==e&&(fe=e,f))for(const t of f.frames)J(t)}function Ao(e,t,n){if(!n)return!1;const a=e?.ownerDocument;if(!a)return!1;const i=a.defaultView,s=a.scrollingElement||a.documentElement;for(let o=e.nodeType===1?e:e.parentElement;o;o=o.parentElement){const r=o===s||o===a.body,c=i.getComputedStyle(o),l=t==="x"?c.overflowX:c.overflowY;if(!r&&!/(auto|scroll|overlay)/.test(l))continue;const d=r?s:o,u=t==="x"?d.scrollLeft:d.scrollTop,p=t==="x"?d.scrollWidth-d.clientWidth:d.scrollHeight-d.clientHeight;if(p>1&&(n>0?u<p-1:u>0))return!0;if(r)break}return!1}function ht(){document.activeElement?.tagName==="IFRAME"&&document.activeElement.blur(),window.focus()}function Z(e){if(ke&&(ke=null,wt()),e!==Ke&&(Ke=null),(e||fe)&&(fe=null,ht()),_=e,Y.clear(),f)for(const t of f.frames)J(t);Fe(),oa(),ui()}let se=null,hn={fid:null,t:0,x:0,y:0};I.addEventListener("pointermove",e=>{const t=e.target.closest?.(".frame")?.dataset.id||null;t!==In&&(In=t,cn())}),I.addEventListener("pointerleave",()=>{In&&(In=null,cn())}),I.addEventListener("pointerdown",e=>{if(cn(),!f||e.target.closest(".pin, .stop, .rename, .count, .dims"))return;P&&e.target.closest(".frame")?.dataset.id!==P.fid&&nt();const t=S&&e.button===0&&e.target.closest(".frame-body")&&e.target.closest(".frame")?.dataset.id;if(t&&t!==S.fid&&H.hidden&&!j)return e.preventDefault(),vt(t);if(S&&e.button===0&&e.target.closest(".frame:not(.edge-zone)")?.dataset.id!==S.fid){!H.hidden||j?(te(),ee()):dt();return}const n=e.target.closest(".edge-zone")?null:e.target.closest(".frame"),a=n?.dataset.id;if(S&&e.button===0&&a&&a!==S.fid)return e.preventDefault(),vt(a);if(e.button===1||K==="hand"||Yt)return ac(e);if(e.button!==0)return;if(K==="pen")return oc(e);if(K==="frame"||K==="section")return ic(e);if(K==="erase"){se={type:"erase"},qo(e),I.setPointerCapture(e.pointerId);return}if(K==="deep"){if(a&&e.target.closest(".frame-body")){Qt(a,e);return}Ve(),te(),ee();return}if(K==="comment"&&a&&e.target.closest(".frame-label")){e.preventDefault(),ee(),st(a,0,0),B.scope="frame",B.anchor=On(a,{scope:"frame",x:0,y:0});const r=m("#composer-area");r.hidden=!1,r.innerHTML=`${A("frame")}<b>${L(f.frames.find(c=>c.id===a)?.name||"Frame")}</b><span>Whole frame</span>`,r.classList.add("chip-frame"),W.placeholder="What should change about this screen?",D.get(a)?.el.classList.add("whole"),Et(a),_e();return}if(K==="comment"){const r=a&&e.target.closest(".frame-body");if(!r&&(!H.hidden||j)){te(),ee();return}se={type:"cpick",fid:r?a:le,sx:e.clientX,sy:e.clientY,area:!1,rect:null},I.setPointerCapture(e.pointerId);return}if(e.altKey&&$()&&!Be&&!S&&a&&e.target.closest(".frame-body")&&!e.target.closest(".pin")&&!Tn(f.frames.find(r=>r.id===a)||{})){const{lx:r,ly:c}=Ge(a,e.clientX,e.clientY),l=Me(a,r,c),d=de(a),u=x?.frameId===a?x.els[x.els.length-1]:null,p=u&&u.contains(l)?u:Xa(a,l,"deep");if(p&&p!==d?.documentElement&&p!==d?.body){p!==u&&Qt(a,e),se={type:"edrag",fid:a,el:p,sx:e.clientX,sy:e.clientY,moved:!1},I.classList.add("dragging"),I.setPointerCapture(e.pointerId);return}}if(!Be&&(!S||a===S.fid)&&a&&e.target.closest(".frame-body")&&!e.target.closest(".pin")&&!Tn(f.frames.find(r=>r.id===a)||{})&&!D.get(a)?.el.classList.contains("empty")){const r=performance.now(),c=Jn.fid===a&&r-Jn.t<420&&Math.hypot(e.clientX-Jn.x,e.clientY-Jn.y)<6;Jn={fid:a,t:c?0:r,x:e.clientX,y:e.clientY};const l=x?.frameId===a?x.els[x.els.length-1]:null;if(c&&l&&$()&&xn(l,!0)){kn(a,l);return}if(c)return;if(ee(),l&&$()&&!e.shiftKey&&!S&&x.els.length===1&&l.isConnected&&l.parentElement&&l!==de(a)?.body){const{lx:d,ly:u}=Ge(a,e.clientX,e.clientY),p=Me(a,d,u);if(p&&l.contains(p)){se={type:e[rt]?"efree":"emove",fid:a,el:l,sx:e.clientX,sy:e.clientY,moved:!1,ev:{clientX:e.clientX,clientY:e.clientY,shiftKey:!1}},I.classList.add("dragging"),I.setPointerCapture(e.pointerId);return}}Qt(a,e,e[rt]?"deep":"smart");return}x&&!e.target.closest(".pin")&&Ve(),te();const i=a?null:e.target.closest(".section"),s=i?i.dataset.id:null;if(s&&e.target.closest(".srz")&&$())return $d(s,e);if(s&&!e.target.closest(".sec-label")&&!e.shiftKey){ee(),fe&&(fe=null,ht()),yi(s),$()&&zr(s,e);return}if(s&&e.target.closest(".sec-label")){ee();const r=performance.now(),c=hi.id===s&&r-hi.t<420;return hi={id:s,t:r},yi(s),$()?c&&e.target.closest(".sec-name")?(e.preventDefault(),hi.t=0,Rr(s)):zr(s,e):void 0}if(e.target.closest(".resize")&&$())return sc(a,e);if(a&&e.shiftKey&&$()){od(a),ee();return}if(e.target.closest(".frame-label")){ee();const r=performance.now(),c=hn.fid===a&&r-hn.t<420&&Math.hypot(e.clientX-hn.x,e.clientY-hn.y)<6;if(hn={fid:a,t:r,x:e.clientX,y:e.clientY},c&&$()&&e.target.closest(".name")&&!D.get(a)?.renaming)return e.preventDefault(),Z(a),hn.t=0,_i(a);if(Y.has(a))return $()?_o(a,e):void 0;if(Z(a),!$())return;Po(a,e),se.onDims=!!e.target.closest(".dims");return}if(a&&e.target.closest(".frame-body")&&Tn(f.frames.find(r=>r.id===a)||{})){ee();const r=performance.now(),c=mi.fid===a&&r-mi.t<420;if(mi={fid:a,t:r},c)return mi.t=0,Z(a),Oe(!0,[a]);if(Y.has(a))return $()?_o(a,e):void 0;Z(a),$()&&Po(a,e);return}if(ee(),!a&&!e.shiftKey&&(Z(null),fe)){fe=null,ht();for(const r of f.frames)J(r)}nc(e,a),se.clickSid=s||null});function nc(e,t){const n=re(e.clientX,e.clientY);se={type:"marquee",x0:n.x,y0:n.y,clickFid:t,base:e.shiftKey?new Set([...Y,..._?[_]:[]]):new Set},I.classList.add("dragging"),I.setPointerCapture(e.pointerId)}function _o(e,t){const n=[...Y];se={type:"gmove",ids:n,sx:t.clientX,sy:t.clientY,from:Object.fromEntries(n.map(a=>{const i=f.frames.find(s=>s.id===a);return[a,{x:i.x,y:i.y}]})),moved:!1},I.classList.add("dragging"),I.setPointerCapture(t.pointerId)}function ac(e){se={type:"pan",sx:e.clientX,sy:e.clientY,vx:b.x,vy:b.y},I.classList.add("dragging"),I.setPointerCapture(e.pointerId)}function Po(e,t){const n=f.frames.find(a=>a.id===e);se={type:"move",fid:e,sx:t.clientX,sy:t.clientY,fx:n.x,fy:n.y,moved:!1,dup:t.altKey,kids:t.altKey?[]:yc(e).map(a=>({id:a.id,x:a.x,y:a.y}))},I.classList.add("dragging"),I.setPointerCapture(t.pointerId)}function ic(e){const t=re(e.clientX,e.clientY);se={type:"draw",x0:t.x,y0:t.y,rect:null},I.classList.add("dragging"),I.setPointerCapture(e.pointerId)}function sc(e,t){const n=f.frames.find(i=>i.id===e),a=t.target.closest(".resize")?.dataset.dir||"se";se={type:"resize",fid:e,dir:a,sx:t.clientX,sy:t.clientY,x0:n.x,y0:n.y,w:n.w,h:n.h},I.classList.add("dragging"),I.setPointerCapture(t.pointerId)}function oc(e){Bn(),B?.soft&&!W.value.trim()&&te();const t=re(e.clientX,e.clientY),n=document.createElementNS("http://www.w3.org/2000/svg","path");n.setAttribute("stroke",Li),n.setAttribute("stroke-width",3/b.z),kt.appendChild(n),se={type:"stroke",points:[t.x,t.y],path:n,width:3/b.z},I.classList.add("dragging"),I.setPointerCapture(e.pointerId)}const rc=11;function lc(e,t,n,a,i,s){const o=i-n,r=s-a,c=o*o+r*r,l=c?Math.max(0,Math.min(1,((e-n)*o+(t-a)*r)/c)):0;return Math.hypot(e-(n+l*o),t-(a+l*r))}function qo(e){const t=re(e.clientX,e.clientY);for(const n of[...f.strokes]){if(n.commentId||String(n.id).startsWith("ink-"))continue;const a=rc/b.z+(n.width||3)/2,i=fn(n);let s=!1;for(let o=0;o+1<i.length&&!s;o+=2){const r=o+3<i.length?i[o+2]:i[o],c=o+3<i.length?i[o+3]:i[o+1];s=lc(t.x,t.y,i[o],i[o+1],r,c)<=a}s&&(f.strokes=f.strokes.filter(o=>o.id!==n.id),kt.querySelector(`path[data-id="${n.id}"]`)?.remove(),w("DELETE",`/__loop/api/strokes/${n.id}`).catch(()=>{}),G("Erase mark",()=>He({strokes:[n]}),()=>w("DELETE",`/__loop/api/strokes/${n.id}`)))}}I.addEventListener("pointermove",e=>{if(xl(e.clientX,e.clientY),!se){if(K==="comment"){const n=e.target.closest?.(".frame-body")&&!e.target.closest(".pin")&&e.target.closest(".frame")?.dataset.id,a=n&&f.frames.find(i=>i.id===n);a&&!Tn(a)&&(!S||n===S.fid)&&!D.get(n)?.el.classList.contains("empty")?La(n,e.clientX,e.clientY,"block"):V.hidden=!0}if(K==="deep"){const n=e.target.closest(".frame-body")&&e.target.closest(".frame")?.dataset.id;n&&!e.target.closest(".pin")?La(n,e.clientX,e.clientY):V.hidden=!0}else if(K==="select"&&!Be&&!xe){const n=e.target.closest?.(".frame-body")&&e.target.closest(".frame")?.dataset.id,a=n&&f.frames.find(i=>i.id===n);a&&(!S||n===S.fid)&&(S||!Tn(a))&&!e.target.closest(".pin")&&!D.get(n)?.el.classList.contains("empty")?La(n,e.clientX,e.clientY,e[rt]?"deep":"smart"):V.hidden=!0}return}const t=se;if(t.type==="pan")b.x=t.vx+e.clientX-t.sx,b.y=t.vy+e.clientY-t.sy,ie();else if(t.type==="smove"){const n=(e.clientX-t.sx)/b.z,a=(e.clientY-t.sy)/b.z;if(!t.moved&&Math.hypot(e.clientX-t.sx,e.clientY-t.sy)<3)return;t.moved=!0,ua.set(t.sid,{x:t.x0+n,y:t.y0+a});for(const[i,s]of Object.entries(t.from))ze.set(i,{x:s.x+n,y:s.y+a}),J(f.frames.find(o=>o.id===i));wt(),_e()}else if(t.type==="sresize"){const n=(e.clientX-t.sx)/b.z,a=(e.clientY-t.sy)/b.z,i=120;let s=t.x0,o=t.y0,r=t.w,c=t.h;t.dir.includes("e")&&(r=t.w+n),t.dir.includes("s")&&(c=t.h+a),t.dir.includes("w")&&(r=t.w-n,s=t.x0+n),t.dir.includes("n")&&(c=t.h-a,o=t.y0+a),r<i&&(t.dir.includes("w")&&(s=t.x0+t.w-i),r=i),c<i&&(t.dir.includes("n")&&(o=t.y0+t.h-i),c=i),ua.set(t.sid,{x:s,y:o,w:r,h:c}),wt(),gi({x:s,y:o,w:r,h:c})}else if(t.type==="move"&&t.dup){t.moved=!0;const n=f.frames.find(i=>i.id===t.fid);if(t.to={x:t.fx+(e.clientX-t.sx)/b.z,y:t.fy+(e.clientY-t.sy)/b.z},!e.metaKey&&!e.ctrlKey){const i=ys({...t.to,w:n.w,h:n.h},null);t.to.x+=i.dx,t.to.y+=i.dy,At(i.guides)}else At([]);const a=m("#dup-ghost");Object.assign(a.style,{left:`${t.to.x}px`,top:`${t.to.y}px`,width:`${n.w}px`,height:`${n.h}px`}),a.querySelector("span").textContent=`${n.name} copy`,a.hidden=!1}else if(t.type==="move"){t.moved=!0;const n=f.frames.find(s=>s.id===t.fid),a={x:t.fx+(e.clientX-t.sx)/b.z,y:t.fy+(e.clientY-t.sy)/b.z};if(e.shiftKey&&(Math.abs(a.x-t.fx)>=Math.abs(a.y-t.fy)?a.y=t.fy:a.x=t.fx),!e.metaKey&&!e.ctrlKey){const s=ys({...a,w:n.w,h:n.h},t.fid);(!e.shiftKey||a.y===t.fy)&&(a.x+=s.dx),(!e.shiftKey||a.x===t.fx)&&(a.y+=s.dy),At(s.guides)}else At([]);ze.set(t.fid,a);for(const s of t.kids||[]){ze.set(s.id,{x:s.x+a.x-t.fx,y:s.y+a.y-t.fy});const o=f.frames.find(r=>r.id===s.id);o&&J(o)}const i=(f.sections||[]).find(s=>An(s,{...n,...a}));Kt.querySelectorAll(".section").forEach(s=>s.classList.toggle("target",s.dataset.id===i?.id)),J(n),_e()}else if(t.type==="marquee"){const n=re(e.clientX,e.clientY),a={x:Math.min(t.x0,n.x),y:Math.min(t.y0,n.y),w:Math.abs(n.x-t.x0),h:Math.abs(n.y-t.y0)};if(!t.moved&&a.w*b.z<4&&a.h*b.z<4)return;!t.moved&&t.clickFid&&!e.shiftKey&&Z(null),t.moved=!0;const i=m("#marquee");i.hidden=!1,Object.assign(i.style,{left:`${a.x}px`,top:`${a.y}px`,width:`${a.w}px`,height:`${a.h}px`});const s=f.frames.filter(o=>o.x<a.x+a.w&&o.x+o.w>a.x&&o.y<a.y+a.h&&o.y+o.h>a.y).map(o=>o.id);hs([...new Set([...t.base,...s])])}else if(t.type==="gmove"){t.moved=!0;let n=(e.clientX-t.sx)/b.z,a=(e.clientY-t.sy)/b.z;const i=t.ids.map(s=>{const o=f.frames.find(r=>r.id===s);return{x:t.from[s].x+n,y:t.from[s].y+a,w:o.w,h:o.h}});if(!e.metaKey&&!e.ctrlKey){const s=gs(i),o=ys(s,new Set(t.ids));n+=o.dx,a+=o.dy,At(o.guides)}else At([]);for(const s of t.ids)ze.set(s,{x:t.from[s].x+n,y:t.from[s].y+a}),J(f.frames.find(o=>o.id===s));Cn()}else if(t.type==="cpick"){if(!t.area&&Math.hypot(e.clientX-t.sx,e.clientY-t.sy)>6&&(t.area=!0,V.hidden=!0,te(),ee(),I.classList.add("dragging")),!t.area)return;let n,a;if(t.fid===le)n=re(t.sx,t.sy),a=re(e.clientX,e.clientY);else{const s=f.frames.find(r=>r.id===t.fid),o=r=>({x:Math.max(0,Math.min(s.w,r.lx)),y:Math.max(0,Math.min(s.h,r.ly))});n=o(Ge(t.fid,t.sx,t.sy)),a=o(Ge(t.fid,e.clientX,e.clientY))}t.rect={x:Math.min(n.x,a.x),y:Math.min(n.y,a.y),w:Math.abs(a.x-n.x),h:Math.abs(a.y-n.y)};let i=Ht(t.fid).querySelector(".area.picking");i||(i=document.createElement("div"),i.className="area picking show",Ht(t.fid).prepend(i)),Object.assign(i.style,{left:`${t.rect.x}px`,top:`${t.rect.y}px`,width:`${t.rect.w}px`,height:`${t.rect.h}px`})}else if(t.type==="efree"){if(!t.moved&&Math.hypot(e.clientX-t.sx,e.clientY-t.sy)<5)return;if(!t.moved){t.moved=!0,V.hidden=!0;const s=t.el,o=s.parentElement,r=s.ownerDocument.defaultView,c=s.getBoundingClientRect(),l=o.getBoundingClientRect(),d=r.getComputedStyle(o);t.base=s.getAttribute("style"),t.pbase=o.getAttribute("style"),t.props={},t.pprops={},d.position==="static"&&(o.style.position="relative",t.pprops.position="relative"),t.x0=c.left-l.left-o.clientLeft+o.scrollLeft,t.y0=c.top-l.top-o.clientTop+o.scrollTop,Object.assign(t.props,{position:"absolute",margin:"0",width:r.getComputedStyle(s).width,left:`${Math.round(t.x0)}px`,top:`${Math.round(t.y0)}px`});for(const[u,p]of Object.entries(t.props))s.style.setProperty(u,p)}const n=b.z,a=Math.round(t.x0+(e.clientX-t.sx)/n),i=Math.round(t.y0+(e.clientY-t.sy)/n);t.props.left=`${a}px`,t.props.top=`${i}px`,t.el.style.left=t.props.left,t.el.style.top=t.props.top,Pe(),Bt()}else if(t.type==="emove"){if(!t.moved&&Math.hypot(e.clientX-t.sx,e.clientY-t.sy)<5)return;t.moved||(t.moved=!0,t.op=t.el.style.opacity,t.el.style.opacity=".35",V.hidden=!0,ae.hidden=!0,t.line=document.createElement("div"),t.line.id="el-line",document.body.appendChild(t.line));const n=D.get(t.fid).iframe.getBoundingClientRect(),a=b.z,i=(e.clientX-n.left)/a,s=(e.clientY-n.top)/a;if(!t.box){const R=t.el.getBoundingClientRect();t.box=document.createElement("div"),t.box.id="el-drag",t.bx=n.left+R.left*a,t.by=n.top+R.top*a,Object.assign(t.box.style,{width:`${R.width*a}px`,height:`${R.height*a}px`}),document.body.appendChild(t.box)}if(t.box.style.transform=`translate(${t.bx+e.clientX-t.sx}px, ${t.by+e.clientY-t.sy}px)`,t.intoBox||(t.intoBox=document.createElement("div"),t.intoBox.id="el-into",document.body.appendChild(t.intoBox)),document.querySelectorAll(".frame.drop-into").forEach(R=>R.classList.remove("drop-into")),t.before=void 0,t.into=null,t.line.hidden=!0,t.intoBox.hidden=!0,t.out=e.clientX<n.left||e.clientX>n.right||e.clientY<n.top||e.clientY>n.bottom,t.out){const R=re(e.clientX,e.clientY),ce=zn(R.x,R.y);ce&&ce.id!==t.fid&&D.get(ce.id)?.el.classList.add("drop-into");return}const o=t.el.ownerDocument,r=o.body,c=t.el.parentElement,l=Me(t.fid,i,s),d=R=>[...R.children].some(ce=>ce!==t.el&&fs(ce))||!R.children.length&&!R.textContent.trim()&&/^(block|flex|grid|flow-root|list-item)$/.test(o.defaultView.getComputedStyle(R).display);let u=!l||l===o.documentElement?r:l;if(t.el.contains(u))u=c;else{for(;u!==r&&!d(u);)u=u.parentElement;t.el.contains(u)&&(u=c)}if(u!==r&&u!==c&&!u.contains(t.el)){const R=u.getBoundingClientRect(),ce=7/a;(i-R.left<ce||R.right-i<ce||s-R.top<ce||R.bottom-s<ce)&&(u=u.parentElement)}const p=[...u.children].filter(fs),h=p.filter(R=>R!==t.el),g=h.map(R=>R.getBoundingClientRect()),v=u.getBoundingClientRect(),T=(R,ce,rn,Yr)=>Object.assign(t.line.style,{left:`${n.left+R*a}px`,top:`${n.top+ce*a}px`,width:`${rn}px`,height:`${Yr}px`,marginLeft:"0",marginTop:"0"}),C=()=>{u!==c&&(Object.assign(t.intoBox.style,{left:`${n.left+v.left*a}px`,top:`${n.top+v.top*a}px`,width:`${v.width*a}px`,height:`${v.height*a}px`}),t.intoBox.hidden=!1)};if(!h.length){if(u===c)return;t.into=u,t.before=null,T(v.left+4,v.top+4,Math.max(8,(v.width-8)*a),2),t.line.hidden=!1,C();return}const k=p.slice(0,2).map(R=>R.getBoundingClientRect()),M=k.length>1&&Math.abs(k[1].left-k[0].left)>Math.abs(k[1].top-k[0].top);let E=g.findIndex(R=>M?i<R.left+R.width/2:s<R.top+R.height/2);E<0&&(E=h.length);const N=h[E]||null;if(u===c&&N===(p[p.indexOf(t.el)+1]||null))return;t.into=u,t.before=N;const q=g[E-1],ne=g[E];if(M){const R=q&&ne?(q.right+ne.left)/2:ne?ne.left-4:q.right+4,ce=ne||q;T(R,ce.top,2,ce.height*a),t.line.style.marginLeft="-1px"}else{const R=q&&ne?(q.bottom+ne.top)/2:ne?ne.top-4:q.bottom+4,ce=ne||q;T(Math.max(ce.left,v.left),R,Math.min(ce.width,v.width)*a,2),t.line.style.marginTop="-1px"}C(),t.line.hidden=!1}else if(t.type==="edrag"){if(!t.moved&&Math.hypot(e.clientX-t.sx,e.clientY-t.sy)<4)return;if(!t.moved){t.moved=!0,t.copy=na(t.fid,t.el);const o=De(f.frames.find(r=>r.id===t.fid));t.x0=o.x+t.copy.x,t.y0=o.y+t.copy.y,t.ghost=document.createElement("div"),t.ghost.id="el-ghost",t.ghost.innerHTML=t.copy.html,Object.assign(t.ghost.style,{width:`${t.copy.w}px`,height:`${t.copy.h}px`}),xt.appendChild(t.ghost),V.hidden=!0}const n=(e.clientX-t.sx)/b.z,a=(e.clientY-t.sy)/b.z;t.ghost.style.transform=`translate(${t.x0+n}px, ${t.y0+a}px)`;const i=re(e.clientX,e.clientY),s=zn(i.x,i.y);document.querySelectorAll(".frame.drop-into").forEach(o=>o.classList.remove("drop-into")),s&&D.get(s.id)?.el.classList.add("drop-into")}else if(t.type==="draw"){const n=re(e.clientX,e.clientY),a={x:Math.min(t.x0,n.x),y:Math.min(t.y0,n.y),w:Math.abs(n.x-t.x0),h:Math.abs(n.y-t.y0)};if(e.shiftKey&&(a.w=a.h=Math.max(a.w,a.h)),t.rect=a,K==="section"){t.sec||(t.sec=document.createElement("div"),t.sec.className="section drawing",t.sec.innerHTML='<div class="sec-label"><span class="sec-name">Section</span></div>',Kt.appendChild(t.sec)),Object.assign(t.sec.style,{left:`${a.x}px`,top:`${a.y}px`,width:`${a.w}px`,height:`${a.h}px`}),gi(a);return}const i=m("#draw-box");Object.assign(i.style,{left:`${a.x}px`,top:`${a.y}px`,width:`${a.w}px`,height:`${a.h}px`}),i.querySelector("span").textContent=`${Math.round(a.w)} \xD7 ${Math.round(a.h)}`,i.hidden=!1}else if(t.type==="resize"){const n=(e.clientX-t.sx)/b.z,a=(e.clientY-t.sy)/b.z,i=120;let s=t.x0,o=t.y0,r=t.w,c=t.h;if(t.dir.includes("e")&&(r=t.w+n),t.dir.includes("s")&&(c=t.h+a),t.dir.includes("w")&&(r=t.w-n,s=t.x0+n),t.dir.includes("n")&&(c=t.h-a,o=t.y0+a),e.shiftKey&&t.dir.length===2){const d=Math.max(r/t.w,c/t.h),u=t.w*d,p=t.h*d;t.dir.includes("w")&&(s=t.x0+t.w-u),t.dir.includes("n")&&(o=t.y0+t.h-p),r=u,c=p}r<i&&(t.dir.includes("w")&&(s=t.x0+t.w-i),r=i),c<i&&(t.dir.includes("n")&&(o=t.y0+t.h-i),c=i);const l={x:s,y:o,w:r,h:c};if(!e.metaKey&&!e.ctrlKey&&!e.shiftKey){const d=fd(l,t.fid,t.dir);Object.assign(l,d.rect),At(d.guides)}else At([]);ze.set(t.fid,l),J(f.frames.find(d=>d.id===t.fid)),m("#fp-sw")&&(m("#fp-sw").value=Math.round(l.w),m("#fp-sh").value=Math.round(l.h))}else if(t.type==="stroke"){const n=re(e.clientX,e.clientY),a=t.points.length;if(Math.hypot(n.x-t.points[a-2],n.y-t.points[a-1])*b.z<1.5)return;t.points.push(n.x,n.y),t.path.setAttribute("d",Di(t.points))}else t.type==="erase"&&qo(e)});const Do=async e=>{const t=se;if(t){if(se=null,I.classList.remove("dragging"),At([]),Kt.querySelectorAll(".section.target").forEach(n=>n.classList.remove("target")),t.type==="smove"||t.type==="sresize"){gi(null);const n=ua.get(t.sid),a=f.sections.find(r=>r.id===t.sid);if(ua.delete(t.sid),!n||!a)return;const i=t.type==="smove"?{x:t.x0,y:t.y0}:{x:t.x0,y:t.y0,w:t.w,h:t.h},s={...n},o=t.sid;if(Object.assign(a,n),w("PATCH",`/__loop/api/sections/${o}`,n).catch(r=>y(r.message)),t.type==="smove"){const r=t.from,c={};for(const l of Object.keys(r)){const d=ze.get(l);ze.delete(l);const u=f.frames.find(p=>p.id===l);d&&u&&(Object.assign(u,d),c[l]={x:d.x,y:d.y})}Se(c),G("Move section",()=>Promise.all([Pt(o,i),Se(r)]),()=>Promise.all([Pt(o,s),Se(c)]))}else G("Resize section",()=>Pt(o,i),()=>Pt(o,s));wt();return}if(t.type==="marquee"){if(m("#marquee").hidden=!0,!t.moved&&!t.clickFid&&t.clickSid){yi(t.clickSid);return}if(!t.moved&&t.clickFid){const n=t.clickFid,a=f.frames.find(o=>o.id===n);if(D.get(n)?.el.classList.contains("empty")){Z(n),_a(n);return}Z(n),Gi(n);const i=re(e.clientX,e.clientY),s=a&&Me(n,i.x-a.x,i.y-a.y);try{D.get(n)?.iframe.focus()}catch{}if(s&&s!==de(n)?.documentElement)try{s.focus?.({preventScroll:!0,focusVisible:!1}),s.click?.()}catch{}}return}if(t.type==="gmove"){if(!t.moved)return;be=null,oi();const n=t.from,a={};for(const i of t.ids){const s=ze.get(i);ze.delete(i);const o=f.frames.find(r=>r.id===i);s&&o&&(Object.assign(o,s),a[i]={x:s.x,y:s.y})}Se(a),G(`Move ${t.ids.length} frames`,()=>Se(n),()=>Se(a));return}if(t.type==="cpick"){if(document.querySelectorAll(".area.picking").forEach(s=>s.remove()),t.area&&t.rect&&t.rect.w*b.z>8&&t.rect.h*b.z>8)return st(t.fid,t.rect.x,t.rect.y,null,t.rect);if(t.area)return;if(t.fid===le){const s=re(t.sx,t.sy);return st(le,s.x,s.y,"canvas")}const{lx:n,ly:a}=Ge(t.fid,t.sx,t.sy);if(D.get(t.fid)?.el.classList.contains("empty"))return _a(t.fid);const i=Xa(t.fid,Me(t.fid,n,a),"block");return i?(te(),ee(),V.hidden=!0,x={frameId:t.fid,els:[i],scope:i.parentElement},ea()):st(t.fid,n,a)}if(t.type==="efree")return t.moved?Yc(t):Qt(t.fid,t.ev,"deep");if(t.type==="emove")return t.line?.remove(),t.box?.remove(),t.intoBox?.remove(),document.querySelectorAll(".frame.drop-into").forEach(n=>n.classList.remove("drop-into")),t.moved&&(t.el.style.opacity=t.op||""),t.moved&&bt(),t.moved&&!t.el.getAttribute("style")&&t.el.removeAttribute("style"),t.moved?t.out?Uc(t,e):t.into?Vc(t.fid,t.el,t.into,t.before):void 0:Qt(t.fid,t.ev,"smart");if(t.type==="edrag"){if(t.ghost?.remove(),document.querySelectorAll(".frame.drop-into").forEach(o=>o.classList.remove("drop-into")),!t.moved)return;const n=re(e.clientX,e.clientY),a=zn(n.x,n.y);if(a){const o=De(a),r=Me(a.id,n.x-o.x,n.y-o.y);return ti(t.copy,a.id,r)}const i=(e.clientX-t.sx)/b.z,s=(e.clientY-t.sy)/b.z;return Qa(t.copy,t.x0+i,t.y0+s)}if(t.type==="draw"){m("#draw-box").hidden=!0,t.sec?.remove(),gi(null);const n=t.rect;if(K==="section"){Ee("select"),n&&n.w*b.z>24&&n.h*b.z>24&&Ld({x:n.x,y:n.y,w:n.w,h:n.h});return}n&&n.w*b.z>12&&n.h*b.z>12?bn("Frame",n.w,n.h,n.x,n.y):K==="frame"&&bn(ue.name,ue.w,ue.h,t.x0,t.y0);return}if(t.type==="move"&&t.dup){m("#dup-ghost").hidden=!0,t.moved&&t.to&&qn(t.fid,t.to);return}if(t.type==="move"&&!t.moved&&t.onDims){Ke=Ke===t.fid?null:t.fid,Fe();return}if(t.type==="move"&&t.moved||t.type==="resize"){const n=ze.get(t.fid),a=f.frames.find(s=>s.id===t.fid),i=t.type==="move"?{x:t.fx,y:t.fy}:{x:t.x0,y:t.y0,w:t.w,h:t.h};if(n&&a&&Object.assign(a,n),ze.delete(t.fid),n){const s=t.fid,o=t.type==="move"?t.kids||[]:[];let r;if(t.type==="move"&&a){const u=new Set([s,...o.map(h=>h.id)]),p=Go({...a,...n},u)?.id;(p||void 0)!==a.parent&&(r=p||null)}w("PATCH",`/__loop/api/frames/${s}`,r===void 0?n:{...n,parent:r}).catch(u=>y(u.message)),r!==void 0&&a&&(a.parent=r||void 0);const c={...n},l={},d={};for(const u of o){const p=ze.get(u.id);ze.delete(u.id),p&&(l[u.id]={x:u.x,y:u.y},d[u.id]={x:Math.round(p.x),y:Math.round(p.y)})}o.length&&Se(d),G(t.type==="move"?"Move frame":"Resize frame",()=>Promise.all([Rt(s,i),o.length&&Se(l)]),()=>Promise.all([Rt(s,c),o.length&&Se(d)]))}t.type==="resize"&&setTimeout(()=>ut(t.fid),50)}else if(t.type==="stroke"){const n=t.points;n.length<4&&n.push(n[0]+.5,n[1]+.5);const a=new Map;for(let s=0;s<n.length;s+=2){const o=zn(n[s],n[s+1]);o&&a.set(o.id,(a.get(o.id)||0)+1)}const i=[...a.entries()].sort((s,o)=>o[1]-s[1])[0]?.[0]||null;try{const s=await w("POST","/__loop/api/strokes",{points:n,color:Li,width:t.width,frameId:i});_s.add(s.id),G("Draw mark",()=>w("DELETE",`/__loop/api/strokes/${s.id}`),()=>He({strokes:[s]})),t.path.remove(),f.strokes.find(o=>o.id===s.id)||f.strokes.push(s),qt(),Hl(i,n,e)}catch(s){t.path.remove(),y(s.message)}}}};I.addEventListener("pointerup",Do),I.addEventListener("pointercancel",Do),I.addEventListener("pointerleave",()=>{V.hidden=!0}),addEventListener("wheel",e=>{if(S&&e.target.closest?.("#viewport")){e.preventDefault();try{const a=e.deltaMode===1?16:1,{lx:i,ly:s}=Ge(S.fid,e.clientX,e.clientY),o=Me(S.fid,i,s),r=de(S.fid)?.defaultView;if(o&&r){let c=o;const l=r.document.scrollingElement||r.document.documentElement;for(;c&&c!==l&&c!==r.document.body;c=c.parentElement){const d=r.getComputedStyle(c).overflowY;if(/(auto|scroll|overlay)/.test(d)&&c.scrollHeight>c.clientHeight+1)break}(c&&c!==r.document.body?c:l).scrollTop+=e.deltaY*a,V.hidden=!0,requestAnimationFrame(()=>{Pe(),_e()})}}catch{}return}if(e.ctrlKey||e.metaKey)return Os(e,e.clientX,e.clientY);if(!e.target.closest?.("#viewport"))return;e.preventDefault();const t=e.deltaMode===1?16:1,n=e.target.closest?.(".frame-body")&&e.target.closest(".frame")?.dataset.id;if(n&&(x?.frameId===n||_===n)&&Math.abs(e.deltaY)>=Math.abs(e.deltaX))try{const{lx:a,ly:i}=Ge(n,e.clientX,e.clientY),s=Me(n,a,i),o=de(n)?.defaultView;if(s&&o&&Ao(s,"y",e.deltaY)){let r=s;const c=o.document.scrollingElement||o.document.documentElement;for(;r&&r!==c&&r!==o.document.body;r=r.parentElement){const l=o.getComputedStyle(r).overflowY;if(/(auto|scroll|overlay)/.test(l)&&r.scrollHeight>r.clientHeight+1&&(e.deltaY>0?r.scrollTop<r.scrollHeight-r.clientHeight-1:r.scrollTop>0))break}(r&&r!==o.document.body?r:c).scrollTop+=e.deltaY*t,V.hidden=!0,requestAnimationFrame(()=>{Pe(),_e()});return}}catch{}b.x-=e.deltaX*t,b.y-=e.deltaY*t,Si()},{passive:!1,capture:!0});let Oa=1;addEventListener("gesturestart",e=>{e.preventDefault(),Oa=b.z}),addEventListener("gesturechange",e=>{e.preventDefault(),!S&&Lt(e.clientX,e.clientY,Oa*e.scale/b.z)});const Ot=()=>{const e=document.activeElement;return e&&(e.tagName==="INPUT"||e.tagName==="TEXTAREA"||e.isContentEditable)};addEventListener("keydown",e=>{if(Ot())return;if(e.code==="Space"&&!Yt){Yt=!0,I.classList.add("panning"),f&&f.frames.forEach(J),e.preventDefault();return}if(e.metaKey||e.ctrlKey){if(e.key.toLowerCase()==="z"){e.preventDefault(),e.shiftKey?Qn():Va();return}if(e.key.toLowerCase()==="c"&&x&&!xe&&$()){e.preventDefault();const n=x.els[x.els.length-1];pe=na(x.frameId,n),Xe=null;try{navigator.clipboard?.write?.([new ClipboardItem({"text/html":new Blob([pe.html],{type:"text/html"}),"text/plain":new Blob([pe.html],{type:"text/plain"})})]).catch(()=>{})}catch{}y(`Copied \u201C${pe.name}\u201D \u2014 \u2318V to paste`,1600);return}if(e.key.toLowerCase()==="v"&&pe&&!Xe&&$()){if(e.preventDefault(),x){ti(pe,x.frameId,x.els[x.els.length-1]);return}const n=f.frames.find(r=>r.id===pe.fid),a=pe.w,i=pe.h,s=r=>f.frames.some(c=>r.x<c.x+c.w+40&&r.x+a+40>c.x&&r.y<c.y+c.h+40&&r.y+i+40>c.y);let o=n?{x:n.x+n.w+80,y:n.y}:re(innerWidth/2-a*b.z/2,innerHeight/2-i*b.z/2);s(o)&&(o=ts(a,i)),Qa(pe,o.x,o.y);return}if(e.key.toLowerCase()==="s"&&e.shiftKey&&$()){e.preventDefault();const n=ke||_&&f.sections.find(a=>An(a,f.frames.find(i=>i.id===_)||{}))?.id;n?bi(n):y("Select a section to remove it (its frames stay)");return}if(e.key.toLowerCase()==="f"&&e.shiftKey&&$()){e.preventDefault(),_?Jo(_):y("Select a frame to unframe it (what is inside stays)");return}if(e.key.toLowerCase()==="c"&&e.shiftKey&&_&&!x){e.preventDefault(),ar(_);return}if(e.key.toLowerCase()==="l"&&e.shiftKey&&(x||_)){e.preventDefault(),os(x?x.frameId:_,x?x.els[x.els.length-1]:null);return}if(e.key.toLowerCase()==="c"&&_&&$()){e.preventDefault(),Xe=_,pe=null,y(`Copied \u201C${f.frames.find(n=>n.id===_)?.name}\u201D \u2014 \u2318V to paste`,1600);return}if(e.key.toLowerCase()==="v"&&Xe&&$()){e.preventDefault(),f.frames.find(n=>n.id===Xe)?qn(Xe):y("The copied frame no longer exists");return}if(e.key.toLowerCase()==="d"&&x?.els.length===1&&$()){e.preventDefault(),pr();return}if(e.key.toLowerCase()==="d"&&Y.size&&$()){e.preventDefault(),[...Y].forEach(n=>qn(n));return}if(e.key.toLowerCase()==="d"&&_&&$()){e.preventDefault(),qn(_);return}if(e.key.toLowerCase()==="a"&&$()){e.preventDefault(),hs(f.frames.map(n=>n.id));return}if(e.key.toLowerCase()==="y"&&e.ctrlKey){e.preventDefault(),Qn();return}e.key==="0"&&(e.preventDefault(),b.z=1,ie()),(e.key==="="||e.key==="+")&&(e.preventDefault(),Lt(innerWidth/2,innerHeight/2,1.25)),e.key==="-"&&(e.preventDefault(),Lt(innerWidth/2,innerHeight/2,.8));return}const t=e.key.toLowerCase();if(t==="s"&&!e.shiftKey&&!e.altKey){if(e.preventDefault(),S)return dt();const n=_||x?.frameId||(Y.size===1?[...Y][0]:null)||_t;n&&f.frames.some(a=>a.id===n)?vt(n):y("Select a frame, then press S to open it on stage");return}if(t==="v")Ee("select");else if(t==="h")Ee("hand");else if(t==="p")Ee("pen");else if(t==="e")Ee("erase");else if(t==="s"&&e.shiftKey&&$())Ee(K==="section"?"select":"section");else if((e.key==="Backspace"||e.key==="Delete")&&x&&$())e.preventDefault(),ms();else if((e.key==="Backspace"||e.key==="Delete")&&ke&&$())bi(ke);else if(t==="c"&&e.shiftKey)jn();else if(t==="c"){if(Ne&&jn(!0),x?.els.length){e.preventDefault(),ea();return}Ee("comment")}else if(t==="x")Ee("use");else if(t==="d"&&e.shiftKey)Ts();else if(t==="n"&&$())Ji();else if(t==="f"&&e.shiftKey&&$())_?ra(_):y("Select a frame to freeze it");else if(t==="k"&&$()&&_)di(_);else if(t==="f"&&$())Ee(K==="frame"?"select":"frame");else if(e.key==="!"||e.shiftKey&&e.code==="Digit1")Oe();else if(e.key==="@"||e.shiftKey&&e.code==="Digit2")Io(!1);else if(x&&K!=="frame"&&/^Arrow(Left|Right|Up|Down)$/.test(e.key)&&$()&&!S)e.preventDefault(),Zc(e.key);else if(K==="frame"&&/^Arrow(Left|Right|Up|Down)$/.test(e.key)&&$()&&!S)e.preventDefault(),gc(e.key);else if(K==="frame"&&e.key==="Enter"&&!m("#preset-menu").hidden)e.preventDefault(),m("#preset-menu").hidden=!0;else if(/^Arrow(Left|Right|Up|Down)$/.test(e.key)&&$()&&!S&&!P&&(_||Y.size||ke)){const n=e.shiftKey?10:1;kd(e.key==="ArrowLeft"?-n:e.key==="ArrowRight"?n:0,e.key==="ArrowUp"?-n:e.key==="ArrowDown"?n:0)&&e.preventDefault()}else if(e.key==="="||e.key==="+")Lt(innerWidth/2,innerHeight/2,1.25);else if(e.key==="-")Lt(innerWidth/2,innerHeight/2,.8);else if(e.key==="Escape"&&x){const n=x.els.length===1&&x.els[0],a=n?.parentElement,i=n?.ownerDocument;a&&a!==i.body&&a!==i.documentElement&&H.hidden?(x={frameId:x.frameId,els:[a],scope:a.parentElement},Za(x.frameId)):(Ve(),te())}else if(e.key==="Escape")H.hidden?j?ee():!m("#agent-menu").hidden||!m("#share-menu").hidden?gt():S?dt():(Z(null),Ee("select")):te();else if((e.key==="Backspace"||e.key==="Delete")&&Y.size&&$())wr([...Y]);else if(e.altKey&&$()&&Y.size>=2&&br[e.code])e.preventDefault(),vr(br[e.code]);else if((e.key==="Backspace"||e.key==="Delete")&&_&&$()){const n=f.frames.find(a=>a.id===_);n&&bc(n.id).then(()=>{_=null,Fe()})}}),addEventListener("keyup",e=>{e.code==="Space"&&(Yt=!1,I.classList.remove("panning"),f&&f.frames.forEach(J))}),addEventListener("blur",()=>{Yt&&(Yt=!1,I.classList.remove("panning"))}),m("#zoom-in").onclick=()=>Lt(innerWidth/2,innerHeight/2,1.25),m("#zoom-out").onclick=()=>Lt(innerWidth/2,innerHeight/2,.8),m("#zoom-level").onclick=()=>Io(!0);function Io(e){if(x?.els.length){const n=f.frames.find(a=>a.id===x.frameId);if(n){const a=x.els.map(c=>c.getBoundingClientRect()),i=Math.min(...a.map(c=>c.left)),s=Math.min(...a.map(c=>c.top)),o=Math.max(...a.map(c=>c.right)),r=Math.max(...a.map(c=>c.bottom));return Rs({x:n.x+i,y:n.y+s,w:o-i,h:r-s},2)}}const t=Y.size?[...Y]:_?[_]:ke?an(f.sections.find(n=>n.id===ke)).map(n=>n.id):[];if(t.length)return Oe(!0,t);if(e)return Oe();y("Select something to zoom to it")}function gt(){m("#agent-menu").hidden=!0,m("#share-menu").hidden=!0}function Ho(e,t){const n=t.getBoundingClientRect();e.hidden=!1,e.style.top=`${n.bottom+8}px`,e.style.left=`${Math.max(12,Math.min(n.right-e.offsetWidth,innerWidth-e.offsetWidth-12))}px`}const Hd="loop watch";function cc(e){const t=m("#reconnect-pop");if(!t||t.hidden)return;const n=t.querySelector(".rc-status");e==="on"&&!t.classList.contains("done")&&(t.classList.add("done"),n.innerHTML='<i class="rc-ok"></i><span>Connected. Comments go to your chat again.</span>',setTimeout(()=>{t.hidden=!0,t.classList.remove("done")},1600))}function Qi(e){let t=m("#reconnect-pop");t||(t=document.createElement("div"),t.id="reconnect-pop",t.hidden=!0,document.body.appendChild(t),t.addEventListener("pointerdown",s=>s.stopPropagation()),t.addEventListener("click",async s=>{const o=s.target.closest("[data-rc]");if(o){if(o.dataset.rc==="copy")try{await navigator.clipboard.writeText(ao),o.textContent="Copied",t.querySelector(".rc-status").hidden=!1,setTimeout(()=>{o.textContent="Copy"},1600)}catch{y("Select the line and copy it")}if(o.dataset.rc==="close"&&(t.hidden=!0),o.dataset.rc==="loop"){t.hidden=!0;try{await w("POST","/__loop/api/settings",{mode:"headless"}),y(`${f.agentLabel||"Claude Code"} will run your comments directly`)}catch(r){y(r.message)}}}}),addEventListener("pointerdown",s=>{!t.hidden&&!t.contains(s.target)&&!s.target.closest("#reconnect-btn")&&(t.hidden=!0)}));const n=f.agentBin==="codex"?"Codex":"Claude Code";t.classList.remove("done"),t.innerHTML=`<div class="rc-head"><b>Reconnect your chat</b><button class="rc-x" data-rc="close" aria-label="Close"><svg viewBox="0 0 16 16"><path d="M4 4l8 8M12 4l-8 8"/></svg></button></div>
|
|
32
|
+
<button class="t-btn" data-act="dock" title="${xt?"Collapse":"Expand"}">${xt?nt.collapse:nt.expand}</button>
|
|
33
|
+
<button class="t-btn" data-act="resolve" title="${e.resolved?"Reopen":"Resolve"}">${e.resolved?nt.reopen:nt.resolve}</button>
|
|
34
|
+
<span class="t-more"><button class="t-btn" data-act="more" title="More">${nt.more}</button>
|
|
35
|
+
<span class="t-menu" hidden><button data-act="delete">${nt.trash}<span>Delete thread</span></button></span></span>
|
|
36
|
+
<button class="t-btn" data-act="close" title="Close (esc)">${nt.close}</button>`;R._tools!==t&&(R._tools=t,R.querySelector(".t-tools").innerHTML=t);const n=R.querySelector(".thread-body"),a=n.scrollHeight-n.scrollTop-n.clientHeight<40;Fo(n,sn(e.id).map(s=>[s.id,xi(s)])),Wo(R),a&&(n.scrollTop=n.scrollHeight),Te()}R.addEventListener("click",e=>{const t=e.target.closest("[data-copy]");if(!t)return;const n=f.comments.find(a=>a.id===t.dataset.copy);navigator.clipboard?.writeText(n?.kind==="note"?n.text:n?.reply||"").then(()=>{t.innerHTML=aa.check,t.classList.add("ok"),setTimeout(()=>{t.innerHTML=aa.copy,t.classList.remove("ok")},1200)}).catch(()=>{})});let xt=!1;const nt={expand:A("expand"),collapse:A("collapse"),resolve:A("resolve"),reopen:A("reopen"),more:A("more"),close:A("x"),reply:A("reply"),trash:A("trash")};function sr(){m("#comments-panel").hidden=!0,at(),Ye&&(Ye=null,Fe()),m("#shortcuts")?.setAttribute("hidden","")}let Ne=!!K.get("loop.hideComments",!1);function sa(e){Ne=e?!1:!Ne,K.set("loop.hideComments",Ne),document.body.classList.toggle("no-comments",Ne),Ne&&(Re(),te(),ae()),m("#comments-btn").classList.toggle("off",Ne),m("#comments-btn").dataset.tip=Ne?"Comments are hidden (\u21E7C to show)":"All comments",y(Ne?"Comments hidden \xB7 \u21E7C to show":"Comments shown",1600)}document.body.classList.toggle("no-comments",Ne),m("#comments-btn").classList.toggle("off",Ne);let es="open";function ir(){return f.comments.filter(e=>!e.parentId&&e.kind!=="create").sort((e,t)=>t.createdAt-e.createdAt)}function Jc(){const e=f?ir().filter(t=>!t.resolved).length:0;m("#comments-count").textContent=e||"",m("#comments-btn").classList.toggle("has",e>0),m("#comments-panel").hidden||ki()}function ki(){const e=ir(),t=e.filter(o=>!o.resolved),n=e.filter(o=>o.resolved),a=m("#comments-panel .cp-tabs");a.querySelector('[data-tab="open"] span').textContent=t.length||"",a.querySelector('[data-tab="resolved"] span').textContent=n.length||"",a.querySelectorAll("button").forEach(o=>o.classList.toggle("on",o.dataset.tab===es));const s=es==="open"?t:n,i=o=>o.frameId===le?"Canvas":f.frames.find(r=>r.id===o.frameId)?.name||"Deleted frame";m("#comments-panel .cp-list").innerHTML=s.length?s.map(o=>{const r=xn(o.id);return`
|
|
37
|
+
<div class="cp-item${V===o.id?" on":""}" data-id="${o.id}" title="${C(`${o.author?.name||"You"} \xB7 ${i(o)} \xB7 ${on(o.createdAt)}`)}">
|
|
38
|
+
<span class="cp-av${r==="working"||r==="queued"?" busy":r==="error"?" err":""}">${mo(o.author?.name||Z.name,o.author?.color||Z.color)}</span>
|
|
39
|
+
<span class="cp-text">${C(o.text)}</span>
|
|
40
|
+
${k()?`<button class="cp-res" data-res="${o.id}" title="${o.resolved?"Reopen":"Resolve"}">${o.resolved?nt.reopen:nt.resolve}</button>`:""}
|
|
41
|
+
</div>`}).join(""):`<div class="cp-empty">${es==="open"?"No open comments. Press C and click anything to leave one.":"Nothing resolved yet."}</div>`}function $i(e,t){Ne&&sa(!0),te(),Re(),S&>();const n=e.frameId!==le&&f.frames.find(s=>s.id===e.frameId),a=e.anchor;if(n&&a){P.get(n.id)?.parked&&(Q(n.id),Xn());try{const i=a.selector||a.container?.selector||a.elements?.[0]?.selector,o=i&&ue(n.id)?.querySelector(i),r=o?.getBoundingClientRect();r&&(r.top<0||r.bottom>n.h||r.left<0||r.right>n.w)&&o.scrollIntoView({block:"center",inline:"center",behavior:"instant"})}catch{}}requestAnimationFrame(()=>{const s=m("#comments-panel").hidden?0:m("#comments-panel").offsetWidth;if(n){Q(n.id);const i=24+s,o=76,r=innerWidth-i-24,l=innerHeight-o-96,c=Math.min(1,r/n.w,l/n.h);rt({z:c,x:i+(r-n.w*c)/2-n.x*c,y:o+(l-n.h*c)/2-n.y*c},380)}else{const i=(a?.wx||0)+(a?.area?.w||0)/2,o=(a?.wy||0)+(a?.area?.h||0)/2,r=Math.max(v.z,.8);rt({z:r,x:(innerWidth-s)/2-i*r,y:innerHeight/2-o*r},380)}setTimeout(()=>{if(e.resolved||t)return na(e.id);wt(e.frameId);const i=Ka(e.frameId)?.querySelector(`.pin[data-key="${e.id}"]`);i&&(i.classList.remove("ping"),i.offsetWidth,i.classList.add("ping"),setTimeout(()=>i.classList.remove("ping"),2200))},420)})}m("#comments-btn").addEventListener("click",()=>{const e=m("#comments-panel");e.hidden=!e.hidden,e.hidden||(at?.(),ki())}),m("#comments-panel").addEventListener("pointerdown",e=>e.stopPropagation()),m("#comments-panel").addEventListener("wheel",e=>e.stopPropagation()),m("#comments-panel").addEventListener("click",async e=>{if(e.target.closest(".cp-x")){m("#comments-panel").hidden=!0;return}const t=e.target.closest("[data-tab]");if(t){es=t.dataset.tab,ki();return}const n=e.target.closest("[data-res]");if(n){try{await x("POST",`/__loop/api/comments/${n.dataset.res}/resolve`)}catch(i){y(i.message)}return}const a=e.target.closest(".cp-item");if(!a)return;const s=f.comments.find(i=>i.id===a.dataset.id);s&&$i(s)}),m("#comments-panel").addEventListener("dblclick",e=>{const t=e.target.closest(".cp-item");if(!t||e.target.closest("[data-res]"))return;const n=f.comments.find(a=>a.id===t.dataset.id);n&&$i(n,!0)});const Ln={plus:A("plus"),mic:A("mic"),up:A("up"),file:A("file"),x:A("x","s")},or=6,Qc=8e6,rr=window.SpeechRecognition||window.webkitSpeechRecognition,ia=[],lr=A("pen","s"),ed={fable:"Fable",opus:"Opus",sonnet:"Sonnet",haiku:"Haiku"},td={minimal:"Minimal",low:"Low",medium:"Medium",high:"High",xhigh:"Extra high",max:"Max",ultra:"Ultra"},Li=e=>ed[e]||rn(e),Ci=e=>td[e]||e,Le=document.createElement("div");Le.id="model-menu",Le.className="menu model-menu",Le.hidden=!0,document.body.appendChild(Le);let ts=null;function cr(){const e=f?.models;if(!e)return;const t=e.runner==="codex"?"Codex default":e.chat.model||e.chat.effort?"Same as your chat":"Default",n=(a,s,i,o)=>`<button class="tm-item${(e.pick[a]||"")===s?" on":""}" data-mm="${a}" data-v="${C(s)}"><span class="tm-check"></span><span>${C(i)}</span>${o?`<kbd>${C(o)}</kbd>`:""}</button>`;Le.innerHTML=`<div class="mm-title">Model</div>${n("model","",t,e.chat.model?Li(e.chat.model):"")}${e.models.map(a=>n("model",a,Li(a))).join("")}
|
|
42
|
+
<div class="mm-title">Effort</div>${n("effort","",t,e.chat.effort?Ci(e.chat.effort):"")}${e.efforts.map(a=>n("effort",a,Ci(a))).join("")}
|
|
43
|
+
${f.agent.mode==="inbox"?'<p class="mm-note">Your chat answers with its own model. This is for the runs Loop starts itself.</p>':""}`}function dr(){if(!ts?.isConnected){Le.hidden=!0;return}const e=ts.getBoundingClientRect(),t=Le.offsetWidth,n=Le.offsetHeight,a=e.top-n-8>=8||e.top>innerHeight-e.bottom;Le.style.left=`${Math.max(8,Math.min(innerWidth-t-8,e.right-t))}px`,Le.style.top=`${Math.max(8,Math.min(innerHeight-n-8,a?e.top-n-8:e.bottom+8))}px`}document.addEventListener("click",e=>{const t=e.target.closest(".c-model.pick");if(t){if(!Le.hidden&&ts===t){Le.hidden=!0;return}ts=t,cr(),Le.hidden=!1,dr()}}),Le.addEventListener("pointerdown",e=>e.stopPropagation()),Le.addEventListener("click",async e=>{const t=e.target.closest("[data-mm]");if(t){if(f.models){const n=f.models,a=t.dataset.mm;n.pick[a]=t.dataset.v||null,n[a]=n.pick[a]||n.chat[a],Mi()}try{await x("POST","/__loop/api/settings",{pick:{[t.dataset.mm]:t.dataset.v||null}})}catch(n){y(n.message)}}}),addEventListener("pointerdown",e=>{!Le.hidden&&!e.target.closest("#model-menu, .c-model")&&(Le.hidden=!0)},!0),addEventListener("keydown",e=>{e.key==="Escape"&&!Le.hidden&&(Le.hidden=!0,e.stopPropagation())},!0);function Mi(){const e=nd(),t=!!f?.models&&k();document.querySelectorAll(".c-model").forEach(n=>{n.textContent!==e&&(n.textContent=e),n.classList.toggle("pick",t),n.title=t?"Model and effort":""}),Le.hidden||(cr(),dr())}function nd(){if(!f)return"";if(!k())return"Host reviews first";const e=f.models;if(e?.model){const a=f.agent.lastModel,s=e.pick.model&&a&&a.startsWith(`claude-${e.pick.model}-`)?a:e.model;return Li(s)+(e.pick.effort?` \xB7 ${Ci(e.pick.effort)}`:"")}const t=f.agent.lastModel;return t&&(f.agentBin==="codex"?!/^claude/.test(t):/^claude/.test(t))?rn(t):f.agentLabel||"Agent"}const ad=e=>new Promise((t,n)=>{const a=new FileReader;a.onload=()=>t(a.result),a.onerror=n,a.readAsDataURL(e)});function fr(e,t,n){e.insertAdjacentHTML("beforeend",`<div class="c-foot"><button type="button" class="c-btn" data-box="attach" title="Attach images or files \u2014 or drop them here">${Ln.plus}</button><input type="file" multiple hidden><span class="c-model"></span>${rr?`<button type="button" class="c-btn" data-box="mic" title="Dictate">${Ln.mic}</button>`:""}<button type="button" class="c-send" data-box="send" title="Send (\u21B5)">${Ln.up}</button></div>`);const a=e.querySelector("textarea"),s=e.querySelector("input[type=file]"),i=e.querySelector(".c-files"),o=e.querySelector(".c-send"),r=()=>{o.disabled=!a.value.trim()&&!t.length},l=()=>{i.hidden=!t.length,i.innerHTML=t.map((d,u)=>`<span class="c-file${d.type.startsWith("image/")?" img":""}" title="${C(d.name)}">${d.type.startsWith("image/")?`<img src="${d.data}" alt="">`:`${Ln.file}<span>${C(d.name)}</span>`}<button type="button" data-rm="${u}" title="Remove">${Ln.x}</button></span>`).join(""),Mi(),r()},c=async d=>{for(const u of d){if(t.length>=or){y(`Up to ${or} files per message`);break}if(u.size>Qc){y(`${u.name} is over 8 MB`);continue}t.push({name:u.name||"pasted-image.png",type:u.type||"application/octet-stream",data:await ad(u)})}l(),a.focus()};return s.addEventListener("change",()=>{c([...s.files]),s.value=""}),e.addEventListener("click",d=>{const u=d.target.closest("[data-rm]");if(u){t.splice(+u.dataset.rm,1),l();return}const p=d.target.closest("[data-box]");p&&(p.dataset.box==="attach"?s.click():p.dataset.box==="mic"?sd(a,p,r):p.dataset.box==="send"&&n())}),e.addEventListener("dragover",d=>{[...d.dataTransfer.types].includes("Files")&&(d.preventDefault(),d.stopPropagation(),e.classList.add("drop"))}),e.addEventListener("dragleave",d=>{e.contains(d.relatedTarget)||e.classList.remove("drop")}),e.addEventListener("drop",d=>{d.preventDefault(),d.stopPropagation(),e.classList.remove("drop"),c([...d.dataTransfer.files])}),a.addEventListener("paste",d=>{const u=[...d.clipboardData?.files||[]];u.length&&(d.preventDefault(),c(u))}),a.addEventListener("input",r),l(),{paint:l}}let Cn=null;function sd(e,t,n){if(Cn){Cn.stop();return}const a=new rr;a.continuous=!0,a.interimResults=!0,a.lang=navigator.language||"en-US";const s=e.value&&!/\s$/.test(e.value)?e.value+" ":e.value;a.onresult=i=>{let o="";for(const r of i.results)o+=r[0].transcript;e.value=s+o,ut(e),n()},a.onend=()=>{Cn=null,t.classList.remove("on"),e.focus()},a.onerror=i=>{i.error==="not-allowed"||i.error==="service-not-allowed"?y("Allow microphone access to dictate"):["aborted","no-speech"].includes(i.error)||y(`Dictation stopped (${i.error})`)},Cn=a,t.classList.add("on");try{a.start()}catch{Cn=null,t.classList.remove("on")}}function ur(){try{Cn?.stop()}catch{}}const Ei=fr(H.querySelector(".cbox"),ia,()=>Zo());R.addEventListener("pointerdown",e=>{e.stopPropagation(),Yt=!1}),R.addEventListener("click",async e=>{const t=e.target.closest("[data-act]");if(!t)return;const n=t.dataset.act,a=t.dataset.id||V;try{if(n==="close")return te();if(n==="dock"){xt=!xt,Yt=!1,R.classList.toggle("docked",xt),xt&&(R.style.left=R.style.top=R.style.maxHeight=""),Qa(),Te();return}if(n==="more"){const s=R.querySelector(".t-menu");s.hidden=!s.hidden;return}if(n==="allow"){t.disabled=!0,t.textContent="Allowing\u2026",await x("POST",`/__loop/api/comments/${a}/allow`,{i:+t.dataset.k});return}if(n==="allowall"){t.disabled=!0,t.textContent="Allowing\u2026",await x("POST",`/__loop/api/comments/${a}/allow`,{all:!0,i:f.comments.find(s=>s.id===a)?.blocked?.findIndex(s=>!s.allowed)});return}if(n==="before"){const s=f.comments.find(i=>i.id===a);s&&(ro(s.frameId,s.id),zt(s.frameId));return}if(n==="delete"){confirm("Delete this comment thread? This can\u2019t be undone.")&&(await x("DELETE",`/__loop/api/comments/${V}`),te());return}if(n==="resolve"){const s=f.comments.find(i=>i.id===V)?.resolved;await x("POST",`/__loop/api/comments/${V}/resolve`),s||(te(),y("Resolved. Find it in Comments \u2192 Resolved"));return}if(n==="undo"){let s=await fetch(`/__loop/api/comments/${a}/undo`,{method:"POST",headers:{"content-type":"application/json"},body:"{}"}),i=await s.json().catch(()=>({}));if(s.status===409&&i.error==="newer"){if(!confirm(`This frame has ${i.newer} newer change${i.newer===1?"":"s"} after this one. Undoing this reverts ${i.newer===1?"it":"them"} too. Continue?`))return;s=await fetch(`/__loop/api/comments/${a}/undo`,{method:"POST",headers:{"content-type":"application/json"},body:JSON.stringify({force:!0})}),i=await s.json().catch(()=>({}))}if(!s.ok)throw new Error(i.error||"Could not undo");y(i.reverted>1?`Reverted ${i.reverted} changes`:"Change reverted");return}await x("POST",`/__loop/api/comments/${a}/${n}`),n==="redo"&&y("Change re-applied")}catch(s){y(s.message)}}),H.addEventListener("pointerdown",e=>e.stopPropagation()),m("#empty .empty-set").addEventListener("pointerdown",e=>e.stopPropagation()),m("#empty").addEventListener("click",e=>{const t=e.target.closest(".empty-frame");t&&k()&&Tn(t.dataset.name,+t.dataset.w,+t.dataset.h)});for(const e of["click","dblclick","contextmenu"])H.addEventListener(e,t=>{H.classList.contains("onpage")&&t.stopPropagation()});addEventListener("scroll",()=>{for(const e of[document.scrollingElement,document.body,q])e&&(e.scrollTop||e.scrollLeft)&&(e.scrollTop=0,e.scrollLeft=0)},!0);let Be=!1;function Ae(e){if(!((e==="frame"||e==="section")&&!k())){if(Be=e==="use",Be&&(e="select"),!Be&&me&&!S&&(me=null,$t()),e!=="deep"&&L&&Ve(),O?.soft&&!j.value.trim()&&ae(),U=e,q.dataset.tool=e,e!=="select"&&me&&(me=null,$t()),e==="select"||e==="hand"){const t=m("#move-btn");t.dataset.tool!==e&&(t.dataset.tool=e,t.innerHTML=A(e==="hand"?"hand":"select"),t.title=e==="hand"?"Hand (H)":"Select (V)")}if(document.querySelectorAll("#tool-menu [data-pick-tool]").forEach(t=>t.classList.toggle("on",t.dataset.pickTool===e&&!Be)),document.querySelectorAll("#toolbar [data-tool]").forEach(t=>t.classList.toggle("on",t.dataset.tool===(Be?"use":e))),q.dataset.use=Be?"1":"",eo(),Ir(),Be&&L&&(ae(),Ve()),G.hidden=!0,e!=="pen"&&ta(),f)for(const t of f.frames)ee(t);Fe()}}document.querySelectorAll("#toolbar [data-tool]").forEach(e=>e.addEventListener("click",()=>Ae(e.dataset.tool)));const kt=m("#tool-menu");m("#move-caret").addEventListener("click",e=>{if(e.stopPropagation(),!kt.hidden){kt.hidden=!0;return}kt.hidden=!1;const t=m("#move-caret").closest(".tb-group").getBoundingClientRect();kt.style.left=`${Math.round(t.left)}px`,kt.style.bottom=`${Math.round(innerHeight-t.top+8)}px`,kt.style.top="auto"}),kt.addEventListener("click",e=>{const t=e.target.closest("[data-pick-tool]");t&&(Ae(t.dataset.pickTool),kt.hidden=!0)}),addEventListener("pointerdown",e=>{!kt.hidden&&!e.target.closest("#tool-menu, #move-caret")&&(kt.hidden=!0)},!0);let Ye=null,me=null;function Si(e){if(me!==e&&(me=e,f))for(const t of f.frames)ee(t)}function pr(e,t,n){if(!n)return!1;const a=e?.ownerDocument;if(!a)return!1;const s=a.defaultView,i=a.scrollingElement||a.documentElement;for(let o=e.nodeType===1?e:e.parentElement;o;o=o.parentElement){const r=o===i||o===a.body,l=s.getComputedStyle(o),c=t==="x"?l.overflowX:l.overflowY;if(!r&&!/(auto|scroll|overlay)/.test(c))continue;const d=r?i:o,u=t==="x"?d.scrollLeft:d.scrollTop,p=t==="x"?d.scrollWidth-d.clientWidth:d.scrollHeight-d.clientHeight;if(p>1&&(n>0?u<p-1:u>0))return!0;if(r)break}return!1}function $t(){document.activeElement?.tagName==="IFRAME"&&document.activeElement.blur(),window.focus()}function Q(e){if(e&&e!==D&&!S&&k?.()&&P.get(e)?.el.classList.contains("empty")&&!(O?.prompt&&O.frameId===e)){const t=bi($n.x,$n.y);setTimeout(()=>{D===e&&!W.size&&!O&&P.get(e)?.el.classList.contains("empty")&&(ea(e),t&&setTimeout(()=>Xa(t),0))},0)}if(ye&&(ye=null,yt()),e!==Ye&&(Ye=null),(e||me)&&(me=null,$t()),D=e,W.clear(),f)for(const t of f.frames)ee(t);Fe(),va(),Ps()}let oe=null,Mn={fid:null,t:0,x:0,y:0};q.addEventListener("pointermove",e=>{const t=e.target.closest?.(".frame")?.dataset.id||null;t!==Un&&(Un=t,bn())}),q.addEventListener("pointerleave",()=>{Un&&(Un=null,bn())}),q.addEventListener("pointerdown",e=>{if(bn(),!f||e.target.closest(".pin, .stop, .rename, .count, .dims"))return;I&&e.target.closest(".frame")?.dataset.id!==I.fid&&ct();const t=S&&e.button===0&&e.target.closest(".frame-body")&&e.target.closest(".frame")?.dataset.id;if(t&&t!==S.fid&&H.hidden&&!V)return e.preventDefault(),ht(t);if(S&&e.button===0&&e.target.closest(".frame:not(.edge-zone)")?.dataset.id!==S.fid){!H.hidden||V?(ae(),te()):gt();return}const n=e.target.closest(".edge-zone")?null:e.target.closest(".frame"),a=n?.dataset.id;if(S&&e.button===0&&a&&a!==S.fid)return e.preventDefault(),ht(a);if(e.button===1||U==="hand"||nn)return od(e);if(e.button!==0)return;if(U==="pen")return cd(e);if(U==="frame"||U==="section")return rd(e);if(U==="erase"){oe={type:"erase"},gr(e),q.setPointerCapture(e.pointerId);return}if(U==="deep"){if(a&&e.target.closest(".frame-body")){ln(a,e);return}Ve(),ae(),te();return}if(U==="comment"&&!a&&e.target.closest(".section .sec-label")&&!e.target.closest(".sec-more")){e.preventDefault(),Al(e.target.closest(".section").dataset.id);return}if(U==="comment"&&a&&e.target.closest(".frame-label")){e.preventDefault(),io(a);return}if(U==="comment"){const r=a&&e.target.closest(".frame-body");if(!r&&(!H.hidden||V)){ae(),te();return}oe={type:"cpick",fid:r?a:le,sx:e.clientX,sy:e.clientY,area:!1,rect:null},q.setPointerCapture(e.pointerId);return}if(e.altKey&&k()&&!Be&&!S&&a&&e.target.closest(".frame-body")&&!e.target.closest(".pin")&&!Nn(f.frames.find(r=>r.id===a)||{})){const{lx:r,ly:l}=Qe(a,e.clientX,e.clientY),c=Se(a,r,l),d=ue(a),u=L?.frameId===a?L.els[L.els.length-1]:null,p=u&&u.contains(c)?u:ps(a,c,"deep");if(p&&p!==d?.documentElement&&p!==d?.body){p!==u&&ln(a,e),oe={type:"edrag",fid:a,el:p,sx:e.clientX,sy:e.clientY,moved:!1},q.classList.add("dragging"),q.setPointerCapture(e.pointerId);return}}if(!Be&&(!S||a===S.fid)&&a&&e.target.closest(".frame-body")&&!e.target.closest(".pin")&&!Nn(f.frames.find(r=>r.id===a)||{})&&!P.get(a)?.el.classList.contains("empty")){const r=performance.now(),l=ua.fid===a&&r-ua.t<420&&Math.hypot(e.clientX-ua.x,e.clientY-ua.y)<6;ua={fid:a,t:l?0:r,x:e.clientX,y:e.clientY};const c=L?.frameId===a?L.els[L.els.length-1]:null;if(l&&c&&k()&&_n(c,!0)){Pn(a,c);return}if(l)return;if(te(),c&&k()&&!e.shiftKey&&!S&&L.els.length===1&&c.isConnected&&c.parentElement&&c!==ue(a)?.body){const{lx:d,ly:u}=Qe(a,e.clientX,e.clientY),p=Se(a,d,u);if(p&&c.contains(p)){oe={type:e[pt]?"efree":"emove",fid:a,el:c,sx:e.clientX,sy:e.clientY,moved:!1,ev:{clientX:e.clientX,clientY:e.clientY,shiftKey:!1}},q.classList.add("dragging"),q.setPointerCapture(e.pointerId);return}}ln(a,e,e[pt]?"deep":"smart");return}L&&!e.target.closest(".pin")&&Ve(),ae();const s=a?null:e.target.closest(".section"),i=s?s.dataset.id:null;if(i&&e.target.closest(".srz")&&k())return Df(i,e);if(i&&!e.target.closest(".sec-label")&&!e.shiftKey){te(),me&&(me=null,$t()),Sa(i),k()&&Pl(i,e);return}if(i&&e.target.closest(".sec-label")){te();const r=performance.now(),l=zs.id===i&&r-zs.t<420;return zs={id:i,t:r},Sa(i),k()?l&&e.target.closest(".sec-name")?(e.preventDefault(),zs.t=0,zl(i)):Pl(i,e):void 0}if(e.target.closest(".resize")&&k())return ld(a,e);if(a&&e.shiftKey&&k()){df(a),te();return}if(e.target.closest(".frame-label")){te();const r=performance.now(),l=Mn.fid===a&&r-Mn.t<420&&Math.hypot(e.clientX-Mn.x,e.clientY-Mn.y)<6;if(Mn={fid:a,t:r,x:e.clientX,y:e.clientY},l&&k()&&e.target.closest(".name")&&!P.get(a)?.renaming)return e.preventDefault(),Q(a),Mn.t=0,ri(a);if(W.has(a))return k()?mr(a,e):void 0;if(Q(a),!k())return;hr(a,e),oe.onDims=!!e.target.closest(".dims");return}if(a&&e.target.closest(".frame-body")&&Nn(f.frames.find(r=>r.id===a)||{})){te();const r=performance.now(),l=Is.fid===a&&r-Is.t<420;if(Is={fid:a,t:r},l)return Is.t=0,Q(a),Oe(!0,[a]);if(W.has(a))return k()?mr(a,e):void 0;Q(a),k()&&hr(a,e);return}if(te(),!a&&!e.shiftKey&&(Q(null),me)){me=null,$t();for(const r of f.frames)ee(r)}id(e,a),oe.clickSid=i||null});function id(e,t){const n=fe(e.clientX,e.clientY);oe={type:"marquee",x0:n.x,y0:n.y,clickFid:t,base:e.shiftKey?new Set([...W,...D?[D]:[]]):new Set},q.classList.add("dragging"),q.setPointerCapture(e.pointerId)}function mr(e,t){const n=[...W];oe={type:"gmove",ids:n,sx:t.clientX,sy:t.clientY,from:Object.fromEntries(n.map(a=>{const s=f.frames.find(i=>i.id===a);return[a,{x:s.x,y:s.y}]})),moved:!1},q.classList.add("dragging"),q.setPointerCapture(t.pointerId)}function od(e){oe={type:"pan",sx:e.clientX,sy:e.clientY,vx:v.x,vy:v.y},q.classList.add("dragging"),q.setPointerCapture(e.pointerId)}function hr(e,t){const n=f.frames.find(a=>a.id===e);oe={type:"move",fid:e,sx:t.clientX,sy:t.clientY,fx:n.x,fy:n.y,moved:!1,dup:t.altKey,kids:t.altKey?[]:wd(e).map(a=>({id:a.id,x:a.x,y:a.y}))},q.classList.add("dragging"),q.setPointerCapture(t.pointerId)}function rd(e){const t=fe(e.clientX,e.clientY);oe={type:"draw",x0:t.x,y0:t.y,rect:null},q.classList.add("dragging"),q.setPointerCapture(e.pointerId)}function ld(e,t){const n=f.frames.find(s=>s.id===e),a=t.target.closest(".resize")?.dataset.dir||"se";oe={type:"resize",fid:e,dir:a,sx:t.clientX,sy:t.clientY,x0:n.x,y0:n.y,w:n.w,h:n.h},q.classList.add("dragging"),q.setPointerCapture(t.pointerId)}function cd(e){ta(),O?.soft&&!j.value.trim()&&ae();const t=fe(e.clientX,e.clientY),n=document.createElementNS("http://www.w3.org/2000/svg","path");n.setAttribute("stroke",Js),n.setAttribute("stroke-width",3/v.z),At.appendChild(n),oe={type:"stroke",points:[t.x,t.y],path:n,width:3/v.z},q.classList.add("dragging"),q.setPointerCapture(e.pointerId)}const dd=11;function fd(e,t,n,a,s,i){const o=s-n,r=i-a,l=o*o+r*r,c=l?Math.max(0,Math.min(1,((e-n)*o+(t-a)*r)/l)):0;return Math.hypot(e-(n+c*o),t-(a+c*r))}function gr(e){const t=fe(e.clientX,e.clientY);for(const n of[...f.strokes]){if(n.commentId||String(n.id).startsWith("ink-"))continue;const a=dd/v.z+(n.width||3)/2,s=wn(n);let i=!1;for(let o=0;o+1<s.length&&!i;o+=2){const r=o+3<s.length?s[o+2]:s[o],l=o+3<s.length?s[o+3]:s[o+1];i=fd(t.x,t.y,s[o],s[o+1],r,l)<=a}i&&(f.strokes=f.strokes.filter(o=>o.id!==n.id),At.querySelector(`path[data-id="${n.id}"]`)?.remove(),x("DELETE",`/__loop/api/strokes/${n.id}`).catch(()=>{}),J("Erase mark",()=>ze({strokes:[n]}),()=>x("DELETE",`/__loop/api/strokes/${n.id}`)))}}q.addEventListener("pointermove",e=>{if($c(e.clientX,e.clientY),!oe){if(U==="comment"){const n=e.target.closest?.(".frame-body")&&!e.target.closest(".pin")&&e.target.closest(".frame")?.dataset.id,a=n&&f.frames.find(s=>s.id===n);a&&!Nn(a)&&(!S||n===S.fid)&&!P.get(n)?.el.classList.contains("empty")?Wa(n,e.clientX,e.clientY,"block"):G.hidden=!0}if(U==="deep"){const n=e.target.closest(".frame-body")&&e.target.closest(".frame")?.dataset.id;n&&!e.target.closest(".pin")?Wa(n,e.clientX,e.clientY):G.hidden=!0}else if(U==="select"&&!Be&&!Ce){const n=e.target.closest?.(".frame-body")&&e.target.closest(".frame")?.dataset.id,a=n&&f.frames.find(s=>s.id===n);a&&(!S||n===S.fid)&&(S||!Nn(a))&&!e.target.closest(".pin")&&!P.get(n)?.el.classList.contains("empty")?Wa(n,e.clientX,e.clientY,e[pt]?"deep":"smart"):G.hidden=!0}return}const t=oe;if(t.type==="pan")v.x=t.vx+e.clientX-t.sx,v.y=t.vy+e.clientY-t.sy,re();else if(t.type==="smove"){const n=(e.clientX-t.sx)/v.z,a=(e.clientY-t.sy)/v.z;if(!t.moved&&Math.hypot(e.clientX-t.sx,e.clientY-t.sy)<3)return;t.moved=!0,Ea.set(t.sid,{x:t.x0+n,y:t.y0+a});for(const[s,i]of Object.entries(t.from))He.set(s,{x:i.x+n,y:i.y+a}),ee(f.frames.find(o=>o.id===s));yt(),Te()}else if(t.type==="sresize"){const n=(e.clientX-t.sx)/v.z,a=(e.clientY-t.sy)/v.z,s=120;let i=t.x0,o=t.y0,r=t.w,l=t.h;t.dir.includes("e")&&(r=t.w+n),t.dir.includes("s")&&(l=t.h+a),t.dir.includes("w")&&(r=t.w-n,i=t.x0+n),t.dir.includes("n")&&(l=t.h-a,o=t.y0+a),r<s&&(t.dir.includes("w")&&(i=t.x0+t.w-s),r=s),l<s&&(t.dir.includes("n")&&(o=t.y0+t.h-s),l=s),Ea.set(t.sid,{x:i,y:o,w:r,h:l}),yt(),Hs({x:i,y:o,w:r,h:l})}else if(t.type==="move"&&t.dup){t.moved=!0;const n=f.frames.find(s=>s.id===t.fid);if(t.to={x:t.fx+(e.clientX-t.sx)/v.z,y:t.fy+(e.clientY-t.sy)/v.z},!e.metaKey&&!e.ctrlKey){const s=Zi({...t.to,w:n.w,h:n.h},null);t.to.x+=s.dx,t.to.y+=s.dy,Ot(s.guides)}else Ot([]);const a=m("#dup-ghost");Object.assign(a.style,{left:`${t.to.x}px`,top:`${t.to.y}px`,width:`${n.w}px`,height:`${n.h}px`}),a.querySelector("span").textContent=`${n.name} copy`,a.hidden=!1}else if(t.type==="move"){t.moved=!0;const n=f.frames.find(i=>i.id===t.fid),a={x:t.fx+(e.clientX-t.sx)/v.z,y:t.fy+(e.clientY-t.sy)/v.z};if(e.shiftKey&&(Math.abs(a.x-t.fx)>=Math.abs(a.y-t.fy)?a.y=t.fy:a.x=t.fx),!e.metaKey&&!e.ctrlKey){const i=Zi({...a,w:n.w,h:n.h},t.fid);(!e.shiftKey||a.y===t.fy)&&(a.x+=i.dx),(!e.shiftKey||a.x===t.fx)&&(a.y+=i.dy),Ot(i.guides)}else Ot([]);He.set(t.fid,a);for(const i of t.kids||[]){He.set(i.id,{x:i.x+a.x-t.fx,y:i.y+a.y-t.fy});const o=f.frames.find(r=>r.id===i.id);o&&ee(o)}const s=(f.sections||[]).find(i=>Bn(i,{...n,...a}));Nt.querySelectorAll(".section").forEach(i=>i.classList.toggle("target",i.dataset.id===s?.id)),ee(n),Te()}else if(t.type==="marquee"){const n=fe(e.clientX,e.clientY),a={x:Math.min(t.x0,n.x),y:Math.min(t.y0,n.y),w:Math.abs(n.x-t.x0),h:Math.abs(n.y-t.y0)};if(!t.moved&&a.w*v.z<4&&a.h*v.z<4)return;!t.moved&&t.clickFid&&!e.shiftKey&&Q(null),t.moved=!0;const s=m("#marquee");s.hidden=!1,Object.assign(s.style,{left:`${a.x}px`,top:`${a.y}px`,width:`${a.w}px`,height:`${a.h}px`});const i=f.frames.filter(o=>o.x<a.x+a.w&&o.x+o.w>a.x&&o.y<a.y+a.h&&o.y+o.h>a.y).map(o=>o.id);Xi([...new Set([...t.base,...i])])}else if(t.type==="gmove"){t.moved=!0;let n=(e.clientX-t.sx)/v.z,a=(e.clientY-t.sy)/v.z;const s=t.ids.map(i=>{const o=f.frames.find(r=>r.id===i);return{x:t.from[i].x+n,y:t.from[i].y+a,w:o.w,h:o.h}});if(!e.metaKey&&!e.ctrlKey){const i=Gi(s),o=Zi(i,new Set(t.ids));n+=o.dx,a+=o.dy,Ot(o.guides)}else Ot([]);for(const i of t.ids)He.set(i,{x:t.from[i].x+n,y:t.from[i].y+a}),ee(f.frames.find(o=>o.id===i));In()}else if(t.type==="cpick"){if(!t.area&&Math.hypot(e.clientX-t.sx,e.clientY-t.sy)>6&&(t.area=!0,G.hidden=!0,ae(),te(),q.classList.add("dragging")),!t.area)return;let n,a;if(t.fid===le)n=fe(t.sx,t.sy),a=fe(e.clientX,e.clientY);else{const i=f.frames.find(r=>r.id===t.fid),o=r=>({x:Math.max(0,Math.min(i.w,r.lx)),y:Math.max(0,Math.min(i.h,r.ly))});n=o(Qe(t.fid,t.sx,t.sy)),a=o(Qe(t.fid,e.clientX,e.clientY))}t.rect={x:Math.min(n.x,a.x),y:Math.min(n.y,a.y),w:Math.abs(a.x-n.x),h:Math.abs(a.y-n.y)};let s=Kt(t.fid).querySelector(".area.picking");s||(s=document.createElement("div"),s.className="area picking show",Kt(t.fid).prepend(s)),Object.assign(s.style,{left:`${t.rect.x}px`,top:`${t.rect.y}px`,width:`${t.rect.w}px`,height:`${t.rect.h}px`})}else if(t.type==="efree"){if(!t.moved&&Math.hypot(e.clientX-t.sx,e.clientY-t.sy)<5)return;if(!t.moved){t.moved=!0,G.hidden=!0;const i=t.el,o=i.parentElement,r=i.ownerDocument.defaultView,l=i.getBoundingClientRect(),c=o.getBoundingClientRect(),d=r.getComputedStyle(o);t.base=i.getAttribute("style"),t.pbase=o.getAttribute("style"),t.props={},t.pprops={},d.position==="static"&&(o.style.position="relative",t.pprops.position="relative"),t.x0=l.left-c.left-o.clientLeft+o.scrollLeft,t.y0=l.top-c.top-o.clientTop+o.scrollTop,Object.assign(t.props,{position:"absolute",margin:"0",width:r.getComputedStyle(i).width,left:`${Math.round(t.x0)}px`,top:`${Math.round(t.y0)}px`});for(const[u,p]of Object.entries(t.props))i.style.setProperty(u,p)}const n=v.z,a=Math.round(t.x0+(e.clientX-t.sx)/n),s=Math.round(t.y0+(e.clientY-t.sy)/n);t.props.left=`${a}px`,t.props.top=`${s}px`,t.el.style.left=t.props.left,t.el.style.top=t.props.top,Pe(),Zt()}else if(t.type==="emove"){if(!t.moved&&Math.hypot(e.clientX-t.sx,e.clientY-t.sy)<5)return;t.moved||(t.moved=!0,t.op=t.el.style.opacity,t.el.style.opacity=".35",G.hidden=!0,ie.hidden=!0,t.line=document.createElement("div"),t.line.id="el-line",document.body.appendChild(t.line));const n=P.get(t.fid).iframe.getBoundingClientRect(),a=v.z,s=(e.clientX-n.left)/a,i=(e.clientY-n.top)/a;if(!t.box){const F=t.el.getBoundingClientRect();t.box=document.createElement("div"),t.box.id="el-drag",t.bx=n.left+F.left*a,t.by=n.top+F.top*a,Object.assign(t.box.style,{width:`${F.width*a}px`,height:`${F.height*a}px`}),document.body.appendChild(t.box)}if(t.box.style.transform=`translate(${t.bx+e.clientX-t.sx}px, ${t.by+e.clientY-t.sy}px)`,t.intoBox||(t.intoBox=document.createElement("div"),t.intoBox.id="el-into",document.body.appendChild(t.intoBox)),document.querySelectorAll(".frame.drop-into").forEach(F=>F.classList.remove("drop-into")),t.before=void 0,t.into=null,t.line.hidden=!0,t.intoBox.hidden=!0,t.out=e.clientX<n.left||e.clientX>n.right||e.clientY<n.top||e.clientY>n.bottom,t.out){const F=fe(e.clientX,e.clientY),pe=Gn(F.x,F.y);pe&&pe.id!==t.fid&&P.get(pe.id)?.el.classList.add("drop-into");return}const o=t.el.ownerDocument,r=o.body,l=t.el.parentElement,c=Se(t.fid,s,i),d=F=>[...F.children].some(pe=>pe!==t.el&&Yi(pe))||!F.children.length&&!F.textContent.trim()&&/^(block|flex|grid|flow-root|list-item)$/.test(o.defaultView.getComputedStyle(F).display);let u=!c||c===o.documentElement?r:c;if(t.el.contains(u))u=l;else{for(;u!==r&&!d(u);)u=u.parentElement;t.el.contains(u)&&(u=l)}if(u!==r&&u!==l&&!u.contains(t.el)){const F=u.getBoundingClientRect(),pe=7/a;(s-F.left<pe||F.right-s<pe||i-F.top<pe||F.bottom-i<pe)&&(u=u.parentElement)}const p=[...u.children].filter(Yi),h=p.filter(F=>F!==t.el),g=h.map(F=>F.getBoundingClientRect()),w=u.getBoundingClientRect(),T=(F,pe,gn,Xl)=>Object.assign(t.line.style,{left:`${n.left+F*a}px`,top:`${n.top+pe*a}px`,width:`${gn}px`,height:`${Xl}px`,marginLeft:"0",marginTop:"0"}),$=()=>{u!==l&&(Object.assign(t.intoBox.style,{left:`${n.left+w.left*a}px`,top:`${n.top+w.top*a}px`,width:`${w.width*a}px`,height:`${w.height*a}px`}),t.intoBox.hidden=!1)};if(!h.length){if(u===l)return;t.into=u,t.before=null,T(w.left+4,w.top+4,Math.max(8,(w.width-8)*a),2),t.line.hidden=!1,$();return}const b=p.slice(0,2).map(F=>F.getBoundingClientRect()),M=b.length>1&&Math.abs(b[1].left-b[0].left)>Math.abs(b[1].top-b[0].top);let E=g.findIndex(F=>M?s<F.left+F.width/2:i<F.top+F.height/2);E<0&&(E=h.length);const z=h[E]||null;if(u===l&&z===(p[p.indexOf(t.el)+1]||null))return;t.into=u,t.before=z;const _=g[E-1],se=g[E];if(M){const F=_&&se?(_.right+se.left)/2:se?se.left-4:_.right+4,pe=se||_;T(F,pe.top,2,pe.height*a),t.line.style.marginLeft="-1px"}else{const F=_&&se?(_.bottom+se.top)/2:se?se.top-4:_.bottom+4,pe=se||_;T(Math.max(pe.left,w.left),F,Math.min(pe.width,w.width)*a,2),t.line.style.marginTop="-1px"}$(),t.line.hidden=!1}else if(t.type==="edrag"){if(!t.moved&&Math.hypot(e.clientX-t.sx,e.clientY-t.sy)<4)return;if(!t.moved){t.moved=!0,t.copy=ha(t.fid,t.el);const o=qe(f.frames.find(r=>r.id===t.fid));t.x0=o.x+t.copy.x,t.y0=o.y+t.copy.y,t.ghost=document.createElement("div"),t.ghost.id="el-ghost",t.ghost.innerHTML=t.copy.html,Object.assign(t.ghost.style,{width:`${t.copy.w}px`,height:`${t.copy.h}px`}),Tt.appendChild(t.ghost),G.hidden=!0}const n=(e.clientX-t.sx)/v.z,a=(e.clientY-t.sy)/v.z;t.ghost.style.transform=`translate(${t.x0+n}px, ${t.y0+a}px)`;const s=fe(e.clientX,e.clientY),i=Gn(s.x,s.y);document.querySelectorAll(".frame.drop-into").forEach(o=>o.classList.remove("drop-into")),i&&P.get(i.id)?.el.classList.add("drop-into")}else if(t.type==="draw"){const n=fe(e.clientX,e.clientY),a={x:Math.min(t.x0,n.x),y:Math.min(t.y0,n.y),w:Math.abs(n.x-t.x0),h:Math.abs(n.y-t.y0)};if(e.shiftKey&&(a.w=a.h=Math.max(a.w,a.h)),t.rect=a,U==="section"){t.sec||(t.sec=document.createElement("div"),t.sec.className="section drawing",t.sec.innerHTML='<div class="sec-label"><span class="sec-name">Section</span></div>',Nt.appendChild(t.sec)),Object.assign(t.sec.style,{left:`${a.x}px`,top:`${a.y}px`,width:`${a.w}px`,height:`${a.h}px`}),Hs(a);return}const s=m("#draw-box");Object.assign(s.style,{left:`${a.x}px`,top:`${a.y}px`,width:`${a.w}px`,height:`${a.h}px`}),s.querySelector("span").textContent=`${Math.round(a.w)} \xD7 ${Math.round(a.h)}`,s.hidden=!1}else if(t.type==="resize"){const n=(e.clientX-t.sx)/v.z,a=(e.clientY-t.sy)/v.z,s=120;let i=t.x0,o=t.y0,r=t.w,l=t.h;if(t.dir.includes("e")&&(r=t.w+n),t.dir.includes("s")&&(l=t.h+a),t.dir.includes("w")&&(r=t.w-n,i=t.x0+n),t.dir.includes("n")&&(l=t.h-a,o=t.y0+a),e.shiftKey&&t.dir.length===2){const d=Math.max(r/t.w,l/t.h),u=t.w*d,p=t.h*d;t.dir.includes("w")&&(i=t.x0+t.w-u),t.dir.includes("n")&&(o=t.y0+t.h-p),r=u,l=p}r<s&&(t.dir.includes("w")&&(i=t.x0+t.w-s),r=s),l<s&&(t.dir.includes("n")&&(o=t.y0+t.h-s),l=s);const c={x:i,y:o,w:r,h:l};if(!e.metaKey&&!e.ctrlKey&&!e.shiftKey){const d=hf(c,t.fid,t.dir);Object.assign(c,d.rect),Ot(d.guides)}else Ot([]);He.set(t.fid,c),ee(f.frames.find(d=>d.id===t.fid)),m("#fp-sw")&&(m("#fp-sw").value=Math.round(c.w),m("#fp-sh").value=Math.round(c.h))}else if(t.type==="stroke"){const n=fe(e.clientX,e.clientY),a=t.points.length;if(Math.hypot(n.x-t.points[a-2],n.y-t.points[a-1])*v.z<1.5)return;t.points.push(n.x,n.y),t.path.setAttribute("d",di(t.points))}else t.type==="erase"&&gr(e)});const yr=async e=>{const t=oe;if(t){if(oe=null,q.classList.remove("dragging"),Ot([]),Nt.querySelectorAll(".section.target").forEach(n=>n.classList.remove("target")),t.type==="smove"||t.type==="sresize"){Hs(null);const n=Ea.get(t.sid),a=f.sections.find(r=>r.id===t.sid);if(Ea.delete(t.sid),!n||!a)return;const s=t.type==="smove"?{x:t.x0,y:t.y0}:{x:t.x0,y:t.y0,w:t.w,h:t.h},i={...n},o=t.sid;if(Object.assign(a,n),x("PATCH",`/__loop/api/sections/${o}`,n).catch(r=>y(r.message)),t.type==="smove"){const r=t.from,l={};for(const c of Object.keys(r)){const d=He.get(c);He.delete(c);const u=f.frames.find(p=>p.id===c);d&&u&&(Object.assign(u,d),l[c]={x:d.x,y:d.y})}_e(l),J("Move section",()=>Promise.all([Ft(o,s),_e(r)]),()=>Promise.all([Ft(o,i),_e(l)]))}else J("Resize section",()=>Ft(o,s),()=>Ft(o,i));yt();return}if(t.type==="marquee"){if(m("#marquee").hidden=!0,!t.moved&&!t.clickFid&&t.clickSid){Sa(t.clickSid);return}if(!t.moved&&t.clickFid){const n=t.clickFid,a=f.frames.find(o=>o.id===n);if(P.get(n)?.el.classList.contains("empty")){const o=bi(e.clientX,e.clientY);Q(n),ea(n),o&&setTimeout(()=>Xa(o),0);return}Q(n),Si(n);const s=fe(e.clientX,e.clientY),i=a&&Se(n,s.x-a.x,s.y-a.y);try{P.get(n)?.iframe.focus()}catch{}if(i&&i!==ue(n)?.documentElement)try{i.focus?.({preventScroll:!0,focusVisible:!1}),i.click?.()}catch{}}return}if(t.type==="gmove"){if(!t.moved)return;ke=null,Cs();const n=t.from,a={};for(const s of t.ids){const i=He.get(s);He.delete(s);const o=f.frames.find(r=>r.id===s);i&&o&&(Object.assign(o,i),a[s]={x:i.x,y:i.y})}_e(a),J(`Move ${t.ids.length} frames`,()=>_e(n),()=>_e(a));return}if(t.type==="cpick"){if(document.querySelectorAll(".area.picking").forEach(i=>i.remove()),t.area&&t.rect&&t.rect.w*v.z>8&&t.rect.h*v.z>8)return et(t.fid,t.rect.x,t.rect.y,null,t.rect);if(t.area)return;if(t.fid===le){const i=fe(t.sx,t.sy);return et(le,i.x,i.y,"canvas")}const{lx:n,ly:a}=Qe(t.fid,t.sx,t.sy);if(P.get(t.fid)?.el.classList.contains("empty")){const i=bi($n.x,$n.y);ea(t.fid),i&&setTimeout(()=>Xa(i),0);return}const s=ps(t.fid,Se(t.fid,n,a),"block");return s?(ae(),te(),G.hidden=!0,L={frameId:t.fid,els:[s],scope:s.parentElement},pa()):et(t.fid,n,a)}if(t.type==="efree")return t.moved?Xd(t):ln(t.fid,t.ev,"deep");if(t.type==="emove")return t.line?.remove(),t.box?.remove(),t.intoBox?.remove(),document.querySelectorAll(".frame.drop-into").forEach(n=>n.classList.remove("drop-into")),t.moved&&(t.el.style.opacity=t.op||""),t.moved&&Mt(),t.moved&&!t.el.getAttribute("style")&&t.el.removeAttribute("style"),t.moved?t.out?Jd(t,e):t.into?Gd(t.fid,t.el,t.into,t.before):void 0:ln(t.fid,t.ev,"smart");if(t.type==="edrag"){if(t.ghost?.remove(),document.querySelectorAll(".frame.drop-into").forEach(o=>o.classList.remove("drop-into")),!t.moved)return;const n=fe(e.clientX,e.clientY),a=Gn(n.x,n.y);if(a){const o=qe(a),r=Se(a.id,n.x-o.x,n.y-o.y);return ws(t.copy,a.id,r)}const s=(e.clientX-t.sx)/v.z,i=(e.clientY-t.sy)/v.z;return ys(t.copy,t.x0+s,t.y0+i)}if(t.type==="draw"){m("#draw-box").hidden=!0,t.sec?.remove(),Hs(null);const n=t.rect;if(U==="section"){Ae("select"),n&&n.w*v.z>24&&n.h*v.z>24&&qf({x:n.x,y:n.y,w:n.w,h:n.h});return}n&&n.w*v.z>12&&n.h*v.z>12?Tn("Frame",n.w,n.h,n.x,n.y):U==="frame"&&Tn(he.name,he.w,he.h,t.x0,t.y0);return}if(t.type==="move"&&t.dup){m("#dup-ghost").hidden=!0,t.moved&&t.to&&jn(t.fid,t.to);return}if(t.type==="move"&&!t.moved&&t.onDims){Ye=Ye===t.fid?null:t.fid,Fe();return}if(t.type==="move"&&t.moved||t.type==="resize"){const n=He.get(t.fid),a=f.frames.find(i=>i.id===t.fid),s=t.type==="move"?{x:t.fx,y:t.fy}:{x:t.x0,y:t.y0,w:t.w,h:t.h};if(n&&a&&Object.assign(a,n),He.delete(t.fid),n){const i=t.fid,o=t.type==="move"?t.kids||[]:[];let r;if(t.type==="move"&&a){const u=new Set([i,...o.map(h=>h.id)]),p=Or({...a,...n},u)?.id;(p||void 0)!==a.parent&&(r=p||null)}x("PATCH",`/__loop/api/frames/${i}`,r===void 0?n:{...n,parent:r}).catch(u=>y(u.message)),r!==void 0&&a&&(a.parent=r||void 0);const l={...n},c={},d={};for(const u of o){const p=He.get(u.id);He.delete(u.id),p&&(c[u.id]={x:u.x,y:u.y},d[u.id]={x:Math.round(p.x),y:Math.round(p.y)})}o.length&&_e(d),J(t.type==="move"?"Move frame":"Resize frame",()=>Promise.all([Ut(i,s),o.length&&_e(c)]),()=>Promise.all([Ut(i,l),o.length&&_e(d)]))}t.type==="resize"&&setTimeout(()=>wt(t.fid),50)}else if(t.type==="stroke"){const n=t.points;n.length<4&&n.push(n[0]+.5,n[1]+.5);const a=new Map;for(let i=0;i<n.length;i+=2){const o=Gn(n[i],n[i+1]);o&&a.set(o.id,(a.get(o.id)||0)+1)}const s=[...a.entries()].sort((i,o)=>o[1]-i[1])[0]?.[0]||null;try{const i=await x("POST","/__loop/api/strokes",{points:n,color:Js,width:t.width,frameId:s});ho.add(i.id),J("Draw mark",()=>x("DELETE",`/__loop/api/strokes/${i.id}`),()=>ze({strokes:[i]})),t.path.remove(),f.strokes.find(o=>o.id===i.id)||f.strokes.push(i),Wt(),Rc(s,n,e)}catch(i){t.path.remove(),y(i.message)}}}};q.addEventListener("pointerup",yr),q.addEventListener("pointercancel",yr),q.addEventListener("pointerleave",()=>{G.hidden=!0}),addEventListener("wheel",e=>{if(S&&e.target.closest?.("#viewport")){e.preventDefault();try{const a=e.deltaMode===1?16:1,{lx:s,ly:i}=Qe(S.fid,e.clientX,e.clientY),o=Se(S.fid,s,i),r=ue(S.fid)?.defaultView;if(o&&r){let l=o;const c=r.document.scrollingElement||r.document.documentElement;for(;l&&l!==c&&l!==r.document.body;l=l.parentElement){const d=r.getComputedStyle(l).overflowY;if(/(auto|scroll|overlay)/.test(d)&&l.scrollHeight>l.clientHeight+1)break}(l&&l!==r.document.body?l:c).scrollTop+=e.deltaY*a,G.hidden=!0,requestAnimationFrame(()=>{Pe(),Te()})}}catch{}return}if(e.ctrlKey||e.metaKey)return xo(e,e.clientX,e.clientY);if(!e.target.closest?.("#viewport"))return;e.preventDefault();const t=e.deltaMode===1?16:1,n=e.target.closest?.(".frame-body")&&e.target.closest(".frame")?.dataset.id;if(n&&(L?.frameId===n||D===n)&&Math.abs(e.deltaY)>=Math.abs(e.deltaX))try{const{lx:a,ly:s}=Qe(n,e.clientX,e.clientY),i=Se(n,a,s),o=ue(n)?.defaultView;if(i&&o&&pr(i,"y",e.deltaY)){let r=i;const l=o.document.scrollingElement||o.document.documentElement;for(;r&&r!==l&&r!==o.document.body;r=r.parentElement){const c=o.getComputedStyle(r).overflowY;if(/(auto|scroll|overlay)/.test(c)&&r.scrollHeight>r.clientHeight+1&&(e.deltaY>0?r.scrollTop<r.scrollHeight-r.clientHeight-1:r.scrollTop>0))break}(r&&r!==o.document.body?r:l).scrollTop+=e.deltaY*t,G.hidden=!0,requestAnimationFrame(()=>{Pe(),Te()});return}}catch{}v.x-=e.deltaX*t,v.y-=e.deltaY*t,si()},{passive:!1,capture:!0});let ns=1;addEventListener("gesturestart",e=>{e.preventDefault(),ns=v.z}),addEventListener("gesturechange",e=>{e.preventDefault(),!S&&Pt(e.clientX,e.clientY,ns*e.scale/v.z)});const It=()=>{const e=document.activeElement;return e&&(e.tagName==="INPUT"||e.tagName==="TEXTAREA"||e.isContentEditable)};addEventListener("keydown",e=>{if(It())return;if(e.code==="Space"&&!nn){nn=!0,q.classList.add("panning"),f&&f.frames.forEach(ee),e.preventDefault();return}if(e.metaKey||e.ctrlKey){if(e.key.toLowerCase()==="z"){e.preventDefault(),e.shiftKey?fa():us();return}if(e.key.toLowerCase()==="c"&&L&&!Ce&&k()){e.preventDefault();const n=L.els[L.els.length-1];ge=ha(L.frameId,n),Ge=null;try{navigator.clipboard?.write?.([new ClipboardItem({"text/html":new Blob([ge.html],{type:"text/html"}),"text/plain":new Blob([ge.html],{type:"text/plain"})})]).catch(()=>{})}catch{}y(`Copied \u201C${ge.name}\u201D \u2014 \u2318V to paste`,1600);return}if(e.key.toLowerCase()==="v"&&ge&&!Ge&&k()){if(e.preventDefault(),L){ws(ge,L.frameId,L.els[L.els.length-1]);return}const n=f.frames.find(r=>r.id===ge.fid),a=ge.w,s=ge.h,i=r=>f.frames.some(l=>r.x<l.x+l.w+40&&r.x+a+40>l.x&&r.y<l.y+l.h+40&&r.y+s+40>l.y);let o=n?{x:n.x+n.w+80,y:n.y}:fe(innerWidth/2-a*v.z/2,innerHeight/2-s*v.z/2);i(o)&&(o=Ii(a,s)),ys(ge,o.x,o.y);return}if(e.key.toLowerCase()==="s"&&e.shiftKey&&k()){e.preventDefault();const n=ye||D&&f.sections.find(a=>Bn(a,f.frames.find(s=>s.id===D)||{}))?.id;n?Fs(n):y("Select a section to remove it (its frames stay)");return}if(e.key.toLowerCase()==="f"&&e.shiftKey&&k()){e.preventDefault(),D?Nr(D):y("Select a frame to unframe it (what is inside stays)");return}if(e.key.toLowerCase()==="c"&&e.shiftKey&&D&&!L){e.preventDefault(),jr(D);return}if(e.key.toLowerCase()==="b"&&e.shiftKey&&ye&&!W.size&&!D){e.preventDefault(),ql(ye);return}if(e.key.toLowerCase()==="b"&&e.shiftKey&&(W.size||D)){e.preventDefault();const n=W.size?[...W]:[D];n.some(a=>Pa(f.frames.find(s=>s.id===a)))&&Vs(n);return}if(e.key.toLowerCase()==="l"&&e.shiftKey&&(L||D)){e.preventDefault(),Ni(L?L.frameId:D,L?L.els[L.els.length-1]:null);return}if(e.key.toLowerCase()==="c"&&D&&k()){e.preventDefault(),Ge=D,ge=null,y(`Copied \u201C${f.frames.find(n=>n.id===D)?.name}\u201D \u2014 \u2318V to paste`,1600);return}if(e.key.toLowerCase()==="v"&&Ge&&k()){e.preventDefault(),f.frames.find(n=>n.id===Ge)?jn(Ge):y("The copied frame no longer exists");return}if(e.key.toLowerCase()==="d"&&L?.els.length===1&&k()){e.preventDefault(),el();return}if(e.key.toLowerCase()==="d"&&W.size&&k()){e.preventDefault(),[...W].forEach(n=>jn(n));return}if(e.key.toLowerCase()==="d"&&D&&k()){e.preventDefault(),jn(D);return}if(e.key.toLowerCase()==="a"&&k()){e.preventDefault(),Xi(f.frames.map(n=>n.id));return}if(e.key.toLowerCase()==="y"&&e.ctrlKey){e.preventDefault(),fa();return}e.key==="0"&&(e.preventDefault(),v.z=1,re()),(e.key==="="||e.key==="+")&&(e.preventDefault(),Pt(innerWidth/2,innerHeight/2,1.25)),e.key==="-"&&(e.preventDefault(),Pt(innerWidth/2,innerHeight/2,.8));return}const t=e.key.toLowerCase();if(t==="s"&&!e.shiftKey&&!e.altKey){if(e.preventDefault(),S)return gt();const n=D||L?.frameId||(W.size===1?[...W][0]:null)||lt;n&&f.frames.some(a=>a.id===n)?ht(n):y("Select a frame, then press S to open it on stage");return}if(t==="v")Ae("select");else if(t==="h")Ae("hand");else if(t==="p")Ae("pen");else if(t==="e")Ae("erase");else if(t==="s"&&e.shiftKey&&k())Ae(U==="section"?"select":"section");else if((e.key==="Backspace"||e.key==="Delete")&&L&&k())e.preventDefault(),Ui();else if((e.key==="Backspace"||e.key==="Delete")&&ye&&k())Fs(ye);else if(t==="c"&&e.shiftKey)sa();else if(t==="c"){if(Ne&&sa(!0),L?.els.length){e.preventDefault(),pa();return}Ae("comment")}else if(t==="x")Ae("use");else if(t==="d"&&e.shiftKey)po();else if(t==="n"&&k())Di();else if(t==="f"&&e.shiftKey&&k())D?wa(D):y("Select a frame to freeze it");else if(t==="k"&&k()&&D)Ts(D);else if(t==="f"&&k())Ae(U==="frame"?"select":"frame");else if(e.key==="!"||e.shiftKey&&e.code==="Digit1")Oe();else if(e.key==="@"||e.shiftKey&&e.code==="Digit2")br(!1);else if(L&&U!=="frame"&&/^Arrow(Left|Right|Up|Down)$/.test(e.key)&&k()&&!S)e.preventDefault(),Qd(e.key);else if(U==="frame"&&/^Arrow(Left|Right|Up|Down)$/.test(e.key)&&k()&&!S)e.preventDefault(),vd(e.key);else if(U==="frame"&&e.key==="Enter"&&!m("#preset-menu").hidden)e.preventDefault(),m("#preset-menu").hidden=!0;else if(/^Arrow(Left|Right|Up|Down)$/.test(e.key)&&k()&&!S&&!I&&(D||W.size||ye)){const n=e.shiftKey?10:1;Sf(e.key==="ArrowLeft"?-n:e.key==="ArrowRight"?n:0,e.key==="ArrowUp"?-n:e.key==="ArrowDown"?n:0)&&e.preventDefault()}else if(e.key==="="||e.key==="+")Pt(innerWidth/2,innerHeight/2,1.25);else if(e.key==="-")Pt(innerWidth/2,innerHeight/2,.8);else if(e.key==="Escape"&&L){const n=L.els.length===1&&L.els[0],a=n?.parentElement,s=n?.ownerDocument;a&&a!==s.body&&a!==s.documentElement&&H.hidden?(L={frameId:L.frameId,els:[a],scope:a.parentElement},hs(L.frameId)):(Ve(),ae())}else if(e.key==="Escape")H.hidden?V?te():!m("#agent-menu").hidden||!m("#share-menu").hidden?at():S?gt():(Q(null),Ae("select")):ae();else if((e.key==="Backspace"||e.key==="Delete")&&W.size&&k())rl([...W]);else if(e.altKey&&k()&&W.size>=2&&il[e.code])e.preventDefault(),ol(il[e.code]);else if((e.key==="Backspace"||e.key==="Delete")&&D&&k()){const n=f.frames.find(a=>a.id===D);n&&xd(n.id).then(()=>{D=null,Fe()})}}),addEventListener("keyup",e=>{e.code==="Space"&&(nn=!1,q.classList.remove("panning"),f&&f.frames.forEach(ee))}),addEventListener("blur",()=>{nn&&(nn=!1,q.classList.remove("panning"))}),m("#zoom-in").onclick=()=>Pt(innerWidth/2,innerHeight/2,1.25),m("#zoom-out").onclick=()=>Pt(innerWidth/2,innerHeight/2,.8),m("#zoom-level").onclick=()=>br(!0);function br(e){if(L?.els.length){const n=f.frames.find(a=>a.id===L.frameId);if(n){const a=L.els.map(l=>l.getBoundingClientRect()),s=Math.min(...a.map(l=>l.left)),i=Math.min(...a.map(l=>l.top)),o=Math.max(...a.map(l=>l.right)),r=Math.max(...a.map(l=>l.bottom));return ko({x:n.x+s,y:n.y+i,w:o-s,h:r-i},2)}}const t=W.size?[...W]:D?[D]:ye?Bt(f.sections.find(n=>n.id===ye)).map(n=>n.id):[];if(t.length)return Oe(!0,t);if(e)return Oe();y("Select something to zoom to it")}function at(){clearTimeout(Lt),m("#agent-menu").hidden=!0,m("#agent-menu").classList.remove("peek"),m("#share-menu").hidden=!0}function ud(e,t){const n=t.getBoundingClientRect();e.hidden=!1,e.style.top=`${n.bottom+8}px`,e.style.left=`${Math.max(12,Math.min(n.right-e.offsetWidth,innerWidth-e.offsetWidth-12))}px`}const iu="loop watch";function pd(e){const t=m("#reconnect-pop");if(!t||t.hidden)return;const n=t.querySelector(".rc-status");e==="on"&&!t.classList.contains("done")&&(t.classList.add("done"),n.innerHTML='<i class="rc-ok"></i><span>Connected. Comments go to your chat again.</span>',setTimeout(()=>{t.hidden=!0,t.classList.remove("done")},1600))}function vr(e){let t=m("#reconnect-pop");t||(t=document.createElement("div"),t.id="reconnect-pop",t.hidden=!0,document.body.appendChild(t),t.addEventListener("pointerdown",i=>i.stopPropagation()),t.addEventListener("click",async i=>{const o=i.target.closest("[data-rc]");if(o){if(o.dataset.rc==="copy")try{await navigator.clipboard.writeText(No),o.textContent="Copied",t.querySelector(".rc-status").hidden=!1,setTimeout(()=>{o.textContent="Copy"},1600)}catch{y("Select the line and copy it")}if(o.dataset.rc==="close"&&(t.hidden=!0),o.dataset.rc==="loop"){t.hidden=!0;try{await x("POST","/__loop/api/settings",{mode:"headless"}),y(`${f.agentLabel||"Claude Code"} will run your comments directly`)}catch(r){y(r.message)}}}}),addEventListener("pointerdown",i=>{!t.hidden&&!t.contains(i.target)&&!i.target.closest("#reconnect-btn")&&(t.hidden=!0)}));const n=f.agentBin==="codex"?"Codex":"Claude Code";t.classList.remove("done"),t.innerHTML=`<div class="rc-head"><b>Reconnect your chat</b><button class="rc-x" data-rc="close" aria-label="Close"><svg viewBox="0 0 16 16"><path d="M4 4l8 8M12 4l-8 8"/></svg></button></div>
|
|
44
44
|
<ol class="rc-steps">
|
|
45
45
|
<li><span class="rc-n">1</span><span>Go to the ${n} chat that opened this canvas</span></li>
|
|
46
|
-
<li><span class="rc-n">2</span><span>Paste this and send it<span class="rc-code"><code>${
|
|
46
|
+
<li><span class="rc-n">2</span><span>Paste this and send it<span class="rc-code"><code>${C(No)}</code><button data-rc="copy">Copy</button></span></span></li>
|
|
47
47
|
<li><span class="rc-n">3</span><span class="rc-status"><i class="rc-spin"></i><span>Waiting for your chat\u2026</span></span></li>
|
|
48
48
|
</ol>
|
|
49
|
-
<div class="rc-foot">Meanwhile, comments run in the background. <button data-rc="loop">Let ${n} run them directly instead</button></div>`,t.hidden=!1;const a=e.getBoundingClientRect(),
|
|
50
|
-
<b class="ac-name">${
|
|
51
|
-
<div class="ac-rows">${
|
|
52
|
-
${e.
|
|
53
|
-
<div class="
|
|
54
|
-
|
|
55
|
-
<
|
|
56
|
-
`+t.documentElement.outerHTML;return w("POST","/__loop/api/cloud/snapshot",{frameId:e,html:n})}async function mc(e){await w("POST","/__loop/api/cloud/publish");const t=f.frames.filter(a=>a.kind==="route");let n=0;for(const a of t){e.textContent=`Uploading screens\u2026 ${++n}/${t.length}`;try{await Wo(a.id)}catch(i){console.warn("snapshot",a.name,i)}}}function hc(e){const t=f?.frames.find(n=>n.id===e);X||!t||t.kind!=="route"||!Ie?.canvasId||!Ie?.user||setTimeout(()=>Wo(e).catch(()=>{}),2500)}m("#invite-go").addEventListener("click",jo),m("#invite-emails").addEventListener("keydown",e=>{e.stopPropagation(),e.key==="Enter"&&jo()});async function jo(){const e=m("#invite-emails").value.split(/[\s,;]+/).map(a=>a.trim()).filter(Boolean),t=m("#invite-note"),n=m("#invite-go");if(!e.length){t.textContent="Add one or more email addresses.";return}n.disabled=!0;try{await mc(t),t.textContent="Sending invites\u2026";const a=await w("POST","/__loop/api/cloud/invite",{emails:e});m("#invite-emails").value="",t.textContent=a.warning?a.warning:a.failed?.length?`Invited, but email failed for ${a.failed.map(i=>i.email).join(", ")} \u2014 share the link with them.`:`Invite${a.emailed.length===1?"":"s"} sent to ${a.emailed.join(", ")}.`,await Wa()}catch(a){t.textContent=a.message}n.disabled=!1}const ja=[["Mobile",393,852],["Tablet",834,1194],["Desktop",1440,1024]],Ka=[["Phone",[["iPhone 16",393,852],["iPhone 16 Pro Max",440,956],["iPhone SE",375,667],["Android (compact)",412,917],["Android (large)",448,998]]],["Tablet",[["iPad mini",744,1133],['iPad Pro 11"',834,1194],['iPad Pro 13"',1032,1376],["Android tablet",800,1280]]],["Desktop",[["Desktop",1440,1024],["MacBook Air",1280,832],['MacBook Pro 14"',1512,982],["Desktop HD",1920,1080],["Wide",1728,1117]]]],Ko={Mobile:A("phone"),Tablet:A("tablet"),Desktop:A("desktop")};let ue=Ae.get("loop.framePreset",null)||{name:"Desktop",w:1440,h:1024};const Yo={Phone:A("phone"),Tablet:A("tablet"),Desktop:A("desktop")},et=document.createElement("div");et.id="frame-ghost",et.hidden=!0,et.innerHTML="<span></span>",xt.appendChild(et);let yn=null;function Vn(){const e=K==="frame"&&!!yn&&!se&&!!f&&$();if(et.hidden!==!e&&(et.hidden=!e),!e)return;const t=re(yn.x,yn.y),n=et.style,a=`<b>${L(ue.name)}</b>${ue.w} \xD7 ${ue.h}`;n.left=`${t.x}px`,n.top=`${t.y}px`,n.width=`${ue.w}px`,n.height=`${ue.h}px`,et._l!==a&&(et._l=a,et.firstChild.innerHTML=a)}addEventListener("pointermove",e=>{if(K!=="frame"){et.hidden||(et.hidden=!0);return}yn=I.contains(e.target)?{x:e.clientX,y:e.clientY}:null,Vn()},!0),addEventListener("pointerup",()=>{K==="frame"&&requestAnimationFrame(Vn)},!0),addEventListener("wheel",()=>{K==="frame"&&yn&&requestAnimationFrame(Vn)},{capture:!0,passive:!0});function Ya(){const e=m("#preset-menu"),t=m("#toolbar"),n=!e.hidden&&e.dataset.mode==="new";if(t.classList.toggle("menu-open",n),m("#frame-tray .tr-more")?.classList.toggle("open",n),!n)return;const a=t.getBoundingClientRect();e.style.left=`${a.left}px`,e.style.width=`${a.width}px`,e.style.bottom=`${innerHeight-a.top-1}px`,e.style.top="",e.classList.toggle("narrow",a.width<470)}new MutationObserver(Ya).observe(m("#preset-menu"),{attributes:!0,attributeFilter:["hidden","data-mode"]}),new ResizeObserver(Ya).observe(m("#toolbar")),addEventListener("resize",Ya);const Vo=()=>document.querySelectorAll('#preset-menu[data-mode="new"] .pm-row').forEach(e=>e.classList.toggle("on",+e.dataset.w===ue.w&&+e.dataset.h===ue.h));function gc(e){const t=m("#preset-menu"),n=!t.hidden&&t.dataset.mode==="new",a=e==="ArrowRight"||e==="ArrowDown"?1:-1,i=e==="ArrowLeft"||e==="ArrowRight";if(!n){if(e==="ArrowUp")es(),t.hidden=!1;else if(i){const l=[...ja].reverse(),d=l.findIndex(([,g,v])=>ue.w===g&&ue.h===v),[u,p,h]=l[d<0?a>0?0:l.length-1:(d+a+l.length)%l.length];Xn(u,p,h)}return}const s=[...t.querySelectorAll(".pm-group")].map(l=>[...l.querySelectorAll(".pm-row")]);let o=s.findIndex(l=>l.some(d=>d.classList.contains("on"))),r=o<0?-1:s[o].findIndex(l=>l.classList.contains("on"));if(o<0)o=0,r=0;else if(i)o=Math.max(0,Math.min(s.length-1,o+a)),r=Math.min(r,s[o].length-1);else if(r+=a,r<0&&(r=0),r>=s[o].length){t.hidden=!0;return}const c=s[o][r];Xn(c.dataset.name,+c.dataset.w,+c.dataset.h),Vo(),c.scrollIntoView({block:"nearest"})}function Xn(e,t,n){ue={name:e,w:Math.round(t),h:Math.round(n)},Ae.set("loop.framePreset",ue),Xo()}function Xo(){const e=m("#toolbar"),t=m("#frame-tray"),n=K==="frame"&&!!f&&$();if(e.classList.toggle("tray-open",n),!n){m("#preset-menu").hidden=!0,yn=null,Vn();return}const a=(r,c)=>ue.w===r&&ue.h===c,i=[...ja].reverse(),s=i.some(([,r,c])=>a(r,c)),o=i.map(([r,c,l])=>`<button class="tr-dev${a(c,l)?" on":""}" data-w="${c}" data-h="${l}" data-name="${r}" title="${r} \xB7 ${c} \xD7 ${l}">${Ko[r]}</button>`).join("")+`<button class="tr-more${s?"":" on"}" title="All sizes">${s?"<span>More</span>":`<span>${L(ue.name)}</span>`}<small>${ue.w} \xD7 ${ue.h}</small>${A("down")}</button>`;t._h!==o&&(t._h=o,t.innerHTML=o),Vn(),Ya()}function es(e){const t=m("#preset-menu"),n=e||ue,a=(i,s)=>Math.round(n.w)===i&&Math.round(n.h)===s;if(t.dataset.mode=e?"resize":"new",t.classList.toggle("for-frame",!!e),t.classList.toggle("docked",!e),e&&(t.style.width=t.style.bottom="",t.classList.remove("narrow")),e){const i=[e.kind==="frozen"?e.from?'<button class="pm-act" data-act="live">Open live</button>':"":`<button class="pm-act" data-act="freeze">${ci}<span>Freeze a copy</span><kbd>\u21E7F</kbd></button>`,en(e)?`<button class="pm-act${e.keyboard?" on":""}" data-act="keyboard"><span>Keyboard</span><kbd>K</kbd></button>`:""].join("");t.innerHTML=`<div class="pm-custom pm-top"><span>Size</span><label>W<input id="pm-w" inputmode="numeric" value="${Math.round(e.w)}"></label><label>H<input id="pm-h" inputmode="numeric" value="${Math.round(e.h)}"></label><button id="pm-use">Apply</button></div>`+Ka.map(([s,o])=>`<div class="pm-group"><div class="pm-title">${Yo[s]||""}<span>${s}</span></div>${o.map(([r,c,l])=>`<button class="pm-row${a(c,l)?" on":""}" data-w="${c}" data-h="${l}" data-name="${L(r)}"><span>${L(r)}</span><small>${c} \xD7 ${l}</small></button>`).join("")}</div>`).join("")+(i?`<div class="pm-acts">${i}</div>`:"");return}t.innerHTML=[...Ka].reverse().map(([i,s])=>`<div class="pm-group"><div class="pm-title">${Yo[i]||""}<span>${i}</span></div>${s.map(([o,r,c])=>`<button class="pm-row${a(r,c)?" on":""}" data-w="${r}" data-h="${c}" data-name="${L(o)}"><span>${L(o)}</span><small>${r} \xD7 ${c}</small></button>`).join("")}</div>`).join("")+`<div class="pm-custom"><span>Custom</span><label>W<input id="pm-w" inputmode="numeric" value="${ue.w}"></label><label>H<input id="pm-h" inputmode="numeric" value="${ue.h}"></label><button id="pm-use">Use</button></div><button class="pm-describe" id="pm-describe">${A("frame")}<span>Describe a frame for the agent</span><kbd>N</kbd></button>`}m("#frame-tray").addEventListener("pointerdown",e=>e.stopPropagation()),m("#frame-tray").addEventListener("click",e=>{const t=e.target.closest(".tr-dev");if(t){Xn(t.dataset.name,+t.dataset.w,+t.dataset.h),Vo();return}if(e.target.closest(".tr-more")){const n=m("#preset-menu");if(!n.hidden){n.hidden=!0;return}es(),n.hidden=!1}}),m("#preset-menu").addEventListener("pointerdown",e=>e.stopPropagation()),m("#preset-menu").addEventListener("click",e=>{const t=m("#preset-menu");if(t.dataset.mode==="resize"){const a=e.target.closest("[data-act]")?.dataset.act;if(a&&_){a==="freeze"?ra(_):a==="live"?Cr(_):a==="keyboard"&&di(_),Uo(!0);return}const i=e.target.closest(".pm-row");if(i){Zn(+i.dataset.w,+i.dataset.h);return}if(e.target.closest("#pm-use")){const s=+m("#pm-w").value,o=+m("#pm-h").value;s>=40&&o>=40&&Zn(s,o)}return}const n=e.target.closest(".pm-row");if(n){Xn(n.dataset.name,+n.dataset.w,+n.dataset.h),t.hidden=!0;return}if(e.target.closest("#pm-use")){const a=+m("#pm-w").value,i=+m("#pm-h").value;a>=40&&i>=40&&(Xn("Frame",a,i),t.hidden=!0);return}e.target.closest("#pm-describe")&&(m("#preset-menu").hidden=!0,Ee("select"),Ji())}),m("#preset-menu").addEventListener("keydown",e=>{e.key==="Enter"&&(e.target.id==="pm-w"||e.target.id==="pm-h")&&m("#pm-use").click(),e.key==="Escape"&&(m("#preset-menu").hidden=!0,e.stopPropagation())}),addEventListener("pointerdown",e=>{const t=m("#preset-menu");t.hidden||e.target.closest("#preset-menu, #frame-tray, .frame > .dims")||(t.hidden=!0,t.dataset.mode==="resize"&&Ke&&(Ke=null))},!0);function Uo(e){const t=m("#preset-menu"),n=f&&$()&&!X&&K==="select"&&_&&Ke===_&&f.frames.find(i=>i.id===_);if(!n){t.dataset.mode==="resize"&&(t.hidden=!0);return}const a=`${n.id}|${Math.round(n.w)}|${Math.round(n.h)}|${n.kind}|${!!n.keyboard}`;(e||t.dataset.mode!=="resize"||t._key!==a&&!t.contains(document.activeElement))&&(es(n),t._for=n.id,t._key=a),t.hidden=!1,Zo()}function Zo(){const e=m("#preset-menu");if(e.hidden||e.dataset.mode!=="resize")return;const t=D.get(e._for)?.el.querySelector(":scope > .dims");if(!t)return;const n=t.getBoundingClientRect(),a=t.parentElement.querySelector(".frame-body").getBoundingClientRect(),i=e.offsetWidth,s=e.offsetHeight;let o=a.right+14,r=Math.max(60,Math.min(a.bottom-s,innerHeight-s-76));o+i>innerWidth-12&&(o=a.left-14-i),o<12&&(o=Math.max(12,Math.min(n.left+n.width/2-i/2,innerWidth-i-12)),r=n.bottom+8,r+s>innerHeight-70&&(r=Math.max(12,n.top-s-8))),e.style.left=`${Math.round(o)}px`,e.style.top=`${Math.round(r)}px`}function Un(e){const t=new Set(f.frames.map(n=>n.name));if(!t.has(e))return e;for(let n=2;;n++)if(!t.has(`${e} ${n}`))return`${e} ${n}`}function ts(e,t,n){const a=n||re(innerWidth/2,innerHeight/2),i=(r,c)=>f.frames.some(l=>r<l.x+l.w+80&&r+e+80>l.x&&c<l.y+l.h+80&&c+t+80>l.y),s=Math.round(a.x-e/2),o=Math.round(a.y-t/2);for(let r=0;r<30;r++)for(const[c,l]of[[1,0],[0,1],[-1,0],[0,-1]]){const d=s+c*r*(e*.5+80),u=o+l*r*(t*.5+80);if(!i(d,u))return{x:d,y:u}}return{x:s,y:o}}function St(e){if(S)return;const t=f.frames.find(i=>i.id===e);if(!t)return;const n={x:b.x+t.x*b.z,y:b.y+t.y*b.z},a={x:n.x+t.w*b.z,y:n.y+t.h*b.z};(n.x<0||n.y<60||a.x>innerWidth||a.y>innerHeight-80)&&Oe(!0,[e])}function yc(e){const t=[],n=a=>{for(const i of f.frames)i.parent===a&&!t.includes(i)&&(t.push(i),n(i.id))};return n(e),t}function Go(e,t=new Set){return f.frames.filter(n=>!t.has(n.id)&&e.x>=n.x&&e.y>=n.y&&e.x+e.w<=n.x+n.w&&e.y+e.h<=n.y+n.h).sort((n,a)=>n.w*n.h-a.w*a.h)[0]||null}async function bn(e,t,n,a,i){const s=a!=null?{x:Math.round(a),y:Math.round(i)}:ts(t,n),o=a!=null?Go({...s,w:t,h:n})?.id:null;try{const r=await w("POST","/__loop/api/frames",{new:!0,blank:!0,name:Un(e),w:Math.round(t),h:Math.round(n),...s,...o?{parent:o}:{}});Ue=r.id,ya=r.id;let c=null;G("Add frame",async()=>{c=yt(r.id)||c,await w("DELETE",`/__loop/api/frames/${r.id}`)},()=>He(c||{frames:[r]})),Ee("select"),f.frames.find(l=>l.id===r.id)&&(Ue=ya=null,Z(r.id),St(r.id),setTimeout(()=>_a(r.id),340))}catch(r){y(r.message)}}function Fe(){const e=m("#frame-panel");e.hidden=!0,Uo()}async function Zn(e,t){const n=f.frames.find(o=>o.id===_);if(!n||!(e>0&&t>0))return;const a={w:n.w,h:n.h},i={w:Math.round(e),h:Math.round(t)},s=n.id;(a.w!==i.w||a.h!==i.h)&&G("Resize frame",()=>Rt(s,a),()=>Rt(s,i)),Object.assign(n,i),J(n);try{await w("PATCH",`/__loop/api/frames/${n.id}`,{w:n.w,h:n.h})}catch(o){y(o.message)}Fe(),setTimeout(()=>ut(n.id),60)}m("#frame-panel").addEventListener("pointerdown",e=>e.stopPropagation()),m("#frame-panel").addEventListener("click",e=>{const t=e.target.closest('[data-pick="frame-fill"]');if(t)return ii(t);if(e.target.closest(".fp-fill-none")){const n=f.frames.find(i=>i.id===_);if(!n)return;const a=n.fill==="none"?null:"none";Wt={id:n.id,before:n.fill||null},n.fill=a||void 0,J(n),w("PATCH",`/__loop/api/frames/${n.id}`,{fill:a}).catch(i=>y(i.message)),yr(),Fe()}}),m("#frame-panel").addEventListener("wheel",e=>e.stopPropagation()),m("#frame-panel").addEventListener("click",e=>{const t=e.target.closest("[data-act]")?.dataset.act;if(t&&_){t==="freeze"?ra(_):t==="live"?Cr(_):t==="keyboard"&&di(_);return}if(e.target.closest("#fp-close")){K==="frame"?Ee("select"):(Ke=null,Fe());return}if(e.target.closest("#fp-describe")){Ee("select"),Ji();return}if(e.target.closest("#fp-make")){const a=+m("#fp-w").value,i=+m("#fp-h").value;a>0&&i>0&&bn("Frame",a,i);return}const n=e.target.closest("[data-w]");n&&(K==="frame"?bn(n.dataset.name,+n.dataset.w,+n.dataset.h):Zn(+n.dataset.w,+n.dataset.h))}),m("#frame-panel").addEventListener("keydown",e=>{if(e.stopPropagation(),e.key==="Escape"){e.target.blur();return}if(e.key==="Enter"){if(e.target.id==="fp-sw"||e.target.id==="fp-sh"){const t=+m("#fp-sw").value,n=+m("#fp-sh").value;e.target.blur(),Zn(t,n)}(e.target.id==="fp-w"||e.target.id==="fp-h")&&m("#fp-make").click()}}),m("#frame-panel").addEventListener("focusout",e=>{if((e.target.id==="fp-sw"||e.target.id==="fp-sh")&&!m("#frame-panel").contains(e.relatedTarget)){const t=f.frames.find(i=>i.id===_),n=+m("#fp-sw")?.value,a=+m("#fp-sh")?.value;t&&(n!==Math.round(t.w)||a!==Math.round(t.h))&&Zn(n,a)}});const Gn=[],ns=[];let as=!1;function G(e,t,n){as||X||!$()||(Gn.push({label:e,undo:t,redo:n}),Gn.length>200&&Gn.shift(),ns.length=0)}async function Qo(e,t,n){const a=e.pop();if(!a){y(n==="undo"?"Nothing to undo":"Nothing to redo",1200);return}as=!0;try{await a[n](),t.push(a),y(`${n==="undo"?"Undo":"Redo"}: ${a.label}`,1400)}catch(i){y(`Couldn't ${n}: ${i.message}`)}finally{as=!1}}const Va=()=>Qo(Gn,ns,"undo"),Qn=()=>Qo(ns,Gn,"redo");function Rt(e,t){const n=f.frames.find(a=>a.id===e);return n&&(Object.assign(n,t),J(n),Fe(),setTimeout(()=>ut(e),50)),w("PATCH",`/__loop/api/frames/${e}`,t)}const He=e=>w("POST","/__loop/api/restore",e);function yt(e){const t=f.frames.find(n=>n.id===e);return t?{frames:[{...t}],comments:f.comments.filter(n=>n.frameId===e).map(n=>({...n}))}:null}async function Jo(e){const t=f.frames.find(l=>l.id===e);if(!t)return;const n=f.frames.filter(l=>l.parent===e),a=yt(e);if(n.length){for(const l of n)await w("PATCH",`/__loop/api/frames/${l.id}`,{parent:null});return await w("DELETE",`/__loop/api/frames/${e}`),Z(null),G("Unframe",async()=>{await He(a);for(const l of n)await w("PATCH",`/__loop/api/frames/${l.id}`,{parent:e})},async()=>{for(const l of n)await w("PATCH",`/__loop/api/frames/${l.id}`,{parent:null});await w("DELETE",`/__loop/api/frames/${e}`)}),y(`Unframed \u201C${t.name}\u201D: its ${n.length} frame${n.length===1?"":"s"} stay where they are \xB7 \u2318Z to undo`,2800)}if(t.kind!=="folder"||t.image)return y(t.image?"An image has no parts to keep.":"A live app page can\u2019t be taken apart. Unframe works on static pages, or frames that hold other frames.",3e3);const i=aa(e);if(!i?.body)return y("Open the frame first so its page has loaded");const s=l=>[...l.children].filter(d=>!/^(SCRIPT|STYLE|TEMPLATE|LINK|META|NOSCRIPT)$/.test(d.tagName)&&d.getBoundingClientRect().width>2&&d.getBoundingClientRect().height>2);let o=i.body,r=s(o);for(let l=0;l<4&&r.length===1&&s(r[0]).length;l++)o=r[0],r=s(o);if(!r.length)return y("Nothing in this frame to keep");if(r.length>40)return y(`That would make ${r.length} frames. Unframe works best on a page with a few parts.`,3e3);const c=[];try{for(const l of r){const d=na(e,l),u=await w("POST","/__loop/api/frames",{new:!0,name:Un(d.name||"Part"),w:d.w,h:d.h,x:Math.round(t.x+d.x),y:Math.round(t.y+d.y),html:nr(d),fill:"none"});c.push(u.id)}await w("DELETE",`/__loop/api/frames/${e}`),Z(null)}catch(l){for(const d of c)w("DELETE",`/__loop/api/frames/${d}`).catch(()=>{});return y(l.message)}G("Unframe",async()=>{for(const l of c)await w("DELETE",`/__loop/api/frames/${l}`);await He(a)},()=>y("Unframe again to split it once more")),y(`Unframed \u201C${t.name}\u201D into ${c.length} part${c.length===1?"":"s"} \xB7 \u2318Z to undo`,2800)}async function bc(e){const t=yt(e);t&&(await w("DELETE",`/__loop/api/frames/${e}`),G("Delete frame",()=>He(t),()=>w("DELETE",`/__loop/api/frames/${e}`)),y(`Deleted \u201C${t.frames[0].name}\u201D \u2014 \u2318Z to undo`,2600))}let x=null,Jn={fid:null,t:0,x:0,y:0};function er(e){let t=e;for(let n=0;n<6;n++){const a=[...t.children].filter(o=>!/^(SCRIPT|STYLE|LINK|META|NOSCRIPT|TEMPLATE)$/.test(o.tagName));if(a.length!==1||!a[0].children.length)break;const i=t.getBoundingClientRect();if(a[0].getBoundingClientRect().width<i.width*.9)break;t=a[0]}return t}function Xa(e,t,n){const a=de(e),i=a?.body;if(!t||!i||t===a.documentElement)return null;if(n==="block")return i.contains(t)?wc(t,i):null;if(n==="deep"||!i.contains(t))return t===i?null:t;if(n==="smart"){const l=x?.frameId===e?x.els[x.els.length-1]:null;if(l?.isConnected&&l!==i&&l.contains(t)){if(t===l)return l;let d=t;for(;d.parentElement&&d.parentElement!==l;)d=d.parentElement;return d}return vc(t,i)}if(n==="outer"){const l=x?.frameId===e?x.els[x.els.length-1]:null,d=l?.isConnected&&l.contains(t)?l:t,u=d.parentElement;return!u||u===i?d:u}const s=x?.frameId===e,o=s?x.els[x.els.length-1]:null;let r=(n==="drill"||n==="step")&&o?.isConnected&&o.contains(t)?o:s&&x.scope?.isConnected?x.scope:er(i);for(;r!==i&&!r.contains(t);)r=r.parentElement;if(t===r)return r===i?null:r;let c=t;for(;c.parentElement&&c.parentElement!==r;)c=c.parentElement;return c}function vc(e,t){if(!t.contains(e)||e===t)return null;const n=t.ownerDocument.defaultView,a=e.closest?.('button, a[href], input, select, textarea, label, img, picture, video, canvas, iframe, svg, [role="button"], [role="link"], [role="tab"], [role="checkbox"], [role="switch"]');if(a&&t.contains(a))return a.closest("svg")&&a.tagName.toLowerCase()!=="svg"?a.closest("svg"):a;let i=e;for(;i.parentElement&&i.parentElement!==t&&/^inline$/.test(n.getComputedStyle(i).display);)i=i.parentElement;const s=(o,r)=>{const c=o.getBoundingClientRect(),l=r.getBoundingClientRect();return Math.abs(c.left-l.left)<1&&Math.abs(c.top-l.top)<1&&Math.abs(c.width-l.width)<1&&Math.abs(c.height-l.height)<1};for(;i.parentElement&&i.parentElement!==t&&i.parentElement.children.length===1&&s(i,i.parentElement);)i=i.parentElement;return i===t?null:i}function wc(e,t){let n=e.closest?.("svg")||e;for(;n&&n!==t;n=n.parentElement){if(n.tagName.toLowerCase()==="svg")continue;const a=[...n.children].filter(s=>!/^(SCRIPT|STYLE|BR|TEMPLATE)$/.test(s.tagName)).length,i=n.getBoundingClientRect();if(a&&n.ownerDocument.defaultView.getComputedStyle(n).display!=="inline"&&i.width>24&&i.height>16)return n}return null}function Ye(e){const t=[...e.childNodes].filter(o=>o.nodeType===3).map(o=>o.data).join(" ").replace(/\s+/g," ").trim();if(t&&!e.children.length)return t.length>28?t.slice(0,27)+"\u2026":t;const n=e.tagName.toLowerCase(),a={img:"Image",svg:"Icon",picture:"Image",video:"Video",canvas:"Canvas",button:"Button",a:"Link",input:"Field",textarea:"Field",select:"Menu",ul:"List",ol:"List",li:"Item",nav:"Navigation",header:"Header",footer:"Footer",form:"Form",table:"Table",label:"Label",section:"Section",main:"Main",aside:"Aside",article:"Article"},i=(e.getAttribute("aria-label")||"").trim();if(a[n]&&(n==="button"||n==="a")&&(t||i))return`${a[n]} \xB7 ${(t||i).slice(0,22)}`;if(a[n])return a[n];if(/^h[1-6]$/.test(n))return"Heading";const s=typeof e.className=="string"&&e.className.trim().split(/\s+/).find(o=>/^[a-zA-Z][a-zA-Z0-9_-]{2,}$/.test(o)&&!/[:\[]/.test(o)&&!/\d/.test(o))||(/^[a-zA-Z][\w-]*$/.test(e.id)?e.id:"");if(s){const o=s.replace(/[-_]+/g," ").replace(/([a-z])([A-Z])/g,"$1 $2").trim();return o[0].toUpperCase()+o.slice(1).toLowerCase()}return t?"Text":"Frame"}let Nt={fid:null,x:0,y:0,n:0,t:0},qe=null,Ua=0;function xc(e,t,n){if(t?.ctx)return;if(n!=="step"&&n!=="smart"){n==="deep"&&K==="select"&&Ae.set("loop.knowsDeep",1),Nt.n=0;return}const a=performance.now(),i=Nt.fid===e&&a-Nt.t<2500&&Math.hypot(t.clientX-Nt.x,t.clientY-Nt.y)<14;Nt={fid:e,x:t.clientX,y:t.clientY,n:i?Nt.n+1:1,t:a},Nt.n>=3&&!qe&&!Ae.get("loop.knowsDeep",0)&&Ae.get("loop.deepTipSeen",0)<2&&tr(t.clientX,t.clientY)}function tr(e,t,n){qe&&is();const a=rt==="metaKey"?"\u2318":"Ctrl";qe=document.createElement("div"),qe.id="deep-tip",qe.innerHTML=`<div class="dt-demo" aria-hidden="true"><div class="dt-card"><i class="dt-l t"></i><i class="dt-l a"></i><i class="dt-l b"></i><i class="dt-btn"></i></div>
|
|
49
|
+
<div class="rc-foot">Meanwhile, comments run in the background. <button data-rc="loop">Let ${n} run them directly instead</button></div>`,t.hidden=!1;const a=e.getBoundingClientRect(),s=t.offsetWidth;t.style.left=`${Math.max(12,Math.min(innerWidth-s-12,a.right-s))}px`,t.style.top=`${a.bottom+8}px`}m("#reconnect-btn").addEventListener("click",e=>{e.stopPropagation(),_i();const t=m("#reconnect-pop");if(t&&!t.hidden){t.hidden=!0;return}at?.(),vr(m("#agent-pill"))}),m("#reconnect-btn").addEventListener("keydown",e=>{(e.key==="Enter"||e.key===" ")&&(e.preventDefault(),e.stopPropagation(),e.currentTarget.click())});let Lt=0;const st=()=>m("#agent-menu");function Ti(){const e=m("#agent-pill")._info;if(!e||st().hidden)return;const t=m("#am-card"),n=e.state==="away"?["away","Disconnected"]:e.state==="offline"?["offline",`${C(f.hostName||"Host")} is offline`]:e.n?["busy",`Working${e.n>1?` on ${e.n}`:""}`]:["on",f.agent.mode==="inbox"?"Connected":"Ready"],a=e.ctx?.pct??0,s=2*Math.PI*27,i=[e.ctx&&["Context",e.ctx.compacted?"<small>Compacted, updates after the next reply</small>":`<span class="ac-bar"><i style="width:${a}%"></i></span><b>${a}%</b><small>${e.ctx.used} of ${e.ctx.window}</small>`],e.model&&["Model",f.agent.mode==="inbox"||!k()?C(e.model):`<button class="c-model pick ac-pick">${C(e.model)}<svg viewBox="0 0 12 12" aria-hidden="true"><path d="M3.5 4.75L6 7.25l2.5-2.5"/></svg></button>`],e.n&&["Working now",`${e.n} comment${e.n>1?"s":""}`],e.queued&&["Waiting",`${e.queued} comment${e.queued>1?"s":""}`],e.waiting&&k()&&["To review",`${e.waiting} from guests`],f.agent.chat?.permission&&f.agent.mode==="inbox"&&["Permissions",f.agent.chat.permission==="bypassPermissions"?"Allowed without asking":f.agent.chat.permission==="auto"?"Auto":C(f.agent.chat.permission)],["Comments go to",f.agent.mode==="inbox"?e.state==="away"?"Background, for now":"Your chat":`${C(e.who)}, run by Loop`,"ac-dest"]].filter(Boolean);t.className=`ac-${n[0]}${e.ctx?" ac-ctx":""}${a>=95?" ac-full":a>=80?" ac-high":""}`;const o=`<div class="ac-top"><span class="ac-mark"><svg class="ac-ring" viewBox="0 0 60 60" aria-hidden="true"><circle class="t" cx="30" cy="30" r="27"/>${e.ctx?`<circle class="f" cx="30" cy="30" r="27" stroke-dasharray="${s*a/100} ${s}"/>`:""}</svg><span class="ac-logo">${ci[e.runner]}</span></span>
|
|
50
|
+
<b class="ac-name">${C(e.who)}</b><span class="ac-state"><i></i>${n[1]}</span></div>
|
|
51
|
+
<div class="ac-rows">${i.map(([r,l,c])=>`<div class="ac-row${c?` ${c}`:""}"><span>${r}</span><span class="ac-v">${l}</span></div>`).join("")}</div>
|
|
52
|
+
${e.ctx&&!e.ctx.compacted&&a>=80&&k()?`<div class="ac-note"><span>${a>=95?"Almost out of room.":"Getting full."} Compact your chat to keep going.</span><button data-ac="compact">Copy /compact</button></div>`:""}
|
|
53
|
+
${e.state==="away"&&k()?'<button class="ac-btn" data-ac="reconnect">Reconnect</button>':k()?'<div class="ac-hint">Click for settings</div>':""}`;t._html!==o&&(t._html=o,t.innerHTML=o)}function wr(){const e=()=>y("Copied. Paste /compact in your chat.",2600);navigator.clipboard?.writeText("/compact").then(e,()=>y("Type /compact in your chat")),xr(Ai()),ss()}const Ai=()=>{const e=m("#agent-pill")._info?.ctx;return!e||e.compacted?0:e.pct>=95?2:e.pct>=80?1:0},as=()=>`loop.ctxhint.${f.agent?.chat?.session||f.name}`;function xr(e){e&&K.set(as(),Math.max(e,K.get(as(),0)))}function ss(){let e=m("#ctx-hint");const t=Ai(),n=m("#agent-pill");if(t||K.set(as(),0),!(t&&k()&&f.agent.mode==="inbox"&&K.get(as(),0)<t&&st().hidden&&!document.querySelector("#reconnect-pop:not([hidden])"))){e&&(e.hidden=!0);return}e||(e=document.createElement("div"),e.id="ctx-hint",e.setAttribute("role","status"),document.body.appendChild(e),e.addEventListener("click",l=>{const c=l.target.closest("[data-ch]");c&&(c.dataset.ch==="copy"?wr():(xr(Ai()),ss()))}));const s=n._info.ctx.pct,i=`<b>Context ${s}% full</b><span>${t===2?"Your chat is almost out of room. Compact it now so it keeps this canvas in mind.":"Compact your chat soon so it keeps going with this canvas in mind."}</span><div class="ch-acts"><button data-ch="later">Not now</button><button data-ch="copy" class="primary">Copy /compact</button></div>`;e._html!==i&&(e._html=i,e.innerHTML=i),e.classList.toggle("full",t===2),e.hidden=!1;const o=n.getBoundingClientRect(),r=e.offsetWidth;e.style.left=`${Math.max(12,Math.min(innerWidth-r-12,o.left+o.width/2-r/2))}px`,e.style.top=`${o.bottom+10}px`}function kr(){const e=st(),t=m("#agent-pill").getBoundingClientRect(),n=e.offsetWidth;e.style.left=`${Math.max(12,Math.min(innerWidth-n-12,t.left+t.width/2-n/2))}px`,e.style.top=`${t.bottom+8}px`}function $r(){const e=st();!e.hidden||m("#reconnect-pop")&&!m("#reconnect-pop").hidden||!m("#share-menu").hidden||(e.classList.add("peek"),e.hidden=!1,Ti(),kr())}function _i(){clearTimeout(Lt);const e=st();e.classList.contains("peek")&&(e.hidden=!0,e.classList.remove("peek"))}function Pi(){const e=st();clearTimeout(Lt),e.hidden&&(at(),e.classList.add("peek"),e.hidden=!1,Ti(),kr(),e.offsetHeight),e.classList.remove("peek")}m("#agent-pill").addEventListener("pointerenter",()=>{clearTimeout(Lt),Lt=setTimeout($r,220)}),m("#agent-pill").addEventListener("pointerleave",()=>{clearTimeout(Lt),Lt=setTimeout(_i,180)}),st().addEventListener("pointerenter",()=>clearTimeout(Lt)),st().addEventListener("pointerleave",()=>{st().classList.contains("peek")&&(Lt=setTimeout(_i,180))}),m("#am-card").addEventListener("click",e=>{if(e.target.closest('[data-ac="reconnect"]')){at(),vr(m("#agent-pill"));return}if(e.target.closest('[data-ac="compact"]')){wr();return}if(e.target.closest(".ac-pick")){st().classList.contains("peek")&&Pi();return}st().classList.contains("peek")&&k()&&Pi()}),m("#agent-pill").addEventListener("click",e=>{e.stopPropagation();const t=st();if(!k()){clearTimeout(Lt),$r();return}!t.hidden&&!t.classList.contains("peek")?at():Pi()}),document.querySelectorAll("#agent-menu .am-opt").forEach(e=>e.addEventListener("click",async()=>{try{await x("POST","/__loop/api/settings",{mode:e.dataset.mode,runner:e.dataset.runner}),y(e.dataset.mode==="inbox"?"Comments will queue for your agent session":`Loop will run ${e.dataset.runner==="codex"?"Codex":"Claude Code"} on each comment`)}catch(t){y(t.message)}at()}));let En=!1;m("#agent-allowed").addEventListener("click",e=>{const t=e.target.closest(".al-head");t&&(e.stopPropagation(),En=!En,t.setAttribute("aria-expanded",En),t.nextElementSibling.hidden=!En)}),m("#agent-allowed").addEventListener("click",async e=>{const t=e.target.closest("[data-disallow]");if(t)try{await x("POST","/__loop/api/settings",{disallow:t.dataset.disallow})}catch(n){y(n.message)}});function md(){const e=!!f.emailSharing;m("#share-menu > .menu-title").textContent=e?"Invite people":"Share this canvas",m("#invite-signin").hidden=!e||!!Ie?.user,m("#invite-form").hidden=!e||!Ie?.user;const t=m("#share-menu .lan-share");t.open=!e,t.querySelector("summary").hidden=!e,t.classList.toggle("only",!e)}function is(){const e=f.share||{};m("#share-lan").value=e.lan||"No network connection",m("#share-public-row").hidden=!e.public,m("#share-public").value=e.public||"",m("#share-public-btn").hidden=!!e.public,m("#share-public-btn").textContent=e.tunnelAvailable?"Create public link":"Create public link (needs cloudflared)"}m("#share-btn").addEventListener("click",async e=>{if(e.stopPropagation(),!k()){try{await navigator.clipboard.writeText(location.href),y("Link copied")}catch{y(location.href,5e3)}return}const t=m("#share-menu"),n=!t.hidden;at(),n||(is(),md(),m("#share-public-note").textContent="",ud(t,e.currentTarget),ls())}),m("#share-public-btn").addEventListener("click",async()=>{const e=m("#share-public-note"),t=m("#share-public-btn");t.disabled=!0,e.textContent="Opening a tunnel\u2026";try{f.share=await x("POST","/__loop/api/share/public"),e.textContent="Live while this Mac is awake and Loop is running.",is()}catch(n){e.textContent=n.message}t.disabled=!1}),m("#share-rotate").addEventListener("click",async()=>{confirm("Reset share links? Anyone using the old links loses access.")&&(f.share=await x("POST","/__loop/api/share/rotate"),is(),y("Links reset"))}),document.querySelectorAll("[data-copy]").forEach(e=>e.addEventListener("click",async()=>{const t=m("#"+e.dataset.copy).value;try{await navigator.clipboard.writeText(t),y("Link copied")}catch{m("#"+e.dataset.copy).select()}})),document.querySelectorAll(".menu").forEach(e=>e.addEventListener("pointerdown",t=>t.stopPropagation())),addEventListener("pointerdown",e=>{e.target.closest(".menu, #agent-pill, #share-btn")||at()});let Lr="1440x1024";function Di(){at(),m("#new-frame").hidden=!1;const e=m("#new-frame-input");e.value="",setTimeout(()=>e.focus(),0)}function os(){m("#new-frame").hidden=!0}m("#new-frame [data-close]").addEventListener("click",os),m("#new-frame").addEventListener("pointerdown",e=>{e.target.id==="new-frame"&&os()}),document.querySelectorAll("#size-pick button").forEach(e=>e.addEventListener("click",()=>{Lr=e.dataset.size,document.querySelectorAll("#size-pick button").forEach(t=>t.classList.toggle("on",t===e))})),m("#new-frame-input").addEventListener("keydown",e=>{e.stopPropagation(),e.key==="Escape"&&os(),e.key==="Enter"&&!e.shiftKey&&!e.isComposing&&(e.preventDefault(),Cr())}),m("#new-frame-go").addEventListener("click",Cr);async function Cr(){const e=m("#new-frame-input").value.trim();if(!e)return;const[t,n]=Lr.split("x").map(Number),a=/^(https?:\/\/|\/|~\/|\.\.?\/)/.test(e)&&!/\s/.test(e);try{const s=await x("POST","/__loop/api/frames",a?{src:e,w:t,h:n}:{prompt:e,w:t,h:n});os(),setTimeout(()=>{Q(null),Oe(!0,[s.id])},80)}catch(s){y(s.message,4e3)}}function Mr(){m("#name-input").value=Z.name||"",m("#name-go").textContent=Z.name?"Save":"Join",m("#name-modal").hidden=!1,setTimeout(()=>m("#name-input").select(),30)}m("#presence").addEventListener("click",e=>{e.target.closest(".avatar.me")&&Mr()}),m("#name-modal").addEventListener("keydown",e=>{e.key==="Escape"&&Z.name&&(m("#name-modal").hidden=!0)}),m("#name-go").addEventListener("click",Er),m("#name-input").addEventListener("keydown",e=>{e.stopPropagation(),e.key==="Enter"&&Er()});function Er(){const e=m("#name-input").value.trim();e&&(Z.name=e,K.set("loop.me",Z),m("#name-modal").hidden=!0,Fa(),k()&&!X&&x("POST","/__loop/api/settings",{hostName:e}).catch(t=>y(t.message)))}let Ie=null,rs=null;async function Sr(e){if(rs)return rs;const{createClient:t}=await import("https://cdn.jsdelivr.net/npm/@supabase/supabase-js@2.49.4/+esm");return rs=t(e.url,e.key,{auth:{flowType:"pkce",detectSessionInUrl:!0,persistSession:!0,storageKey:"loop-host-auth"}}),rs}async function ls(){if(!(X||!k())&&f.emailSharing){try{Ie=await x("GET","/__loop/api/cloud")}catch(e){m("#invite-note").textContent=e.message;return}hd()}}function Tr(e,t){return t?`<img src="${C(t)}" alt="" referrerpolicy="no-referrer">`:C(Do(e))}function hd(){const e=!!Ie?.user;m("#invite-signin").hidden=e,m("#invite-form").hidden=!e,e&&(m("#me-avatar").innerHTML=Tr(Ie.user.name,Ie.user.avatar),m("#me-email").textContent=Ie.user.email,m("#cloud-link").value=Ie.link||"",Ie.error&&!m("#invite-note").textContent&&(m("#invite-note").textContent=Ie.error),m("#members").innerHTML=(Ie.members||[]).map(t=>`
|
|
54
|
+
<div class="member"><span class="m-av">${Tr(t.name||t.email,t.avatar_url)}</span>
|
|
55
|
+
<span class="m-text"><div class="m-name">${C(t.name||t.email)}</div><div class="m-sub">${t.name?C(t.email)+" \xB7 ":""}${t.joined_at?"Joined":"Invited"}${t.role==="viewer"?" \xB7 can view":""}</div></span>
|
|
56
|
+
<button class="m-x" title="Remove" data-email="${C(t.email)}">\xD7</button></div>`).join(""))}m("#members").addEventListener("click",async e=>{const t=e.target.closest("[data-email]");if(t&&confirm(`Remove ${t.dataset.email} from this canvas?`))try{await x("DELETE",`/__loop/api/cloud/members/${encodeURIComponent(t.dataset.email)}`),ls()}catch(n){y(n.message)}}),m("#cloud-google").addEventListener("click",async()=>{try{const e=Ie||await x("GET","/__loop/api/cloud");if(!(await fetch(`${e.config.url}/auth/v1/settings`,{headers:{apikey:e.config.key}}).then(s=>s.json()).catch(()=>({external:{google:!0}}))).external?.google){m("#invite-note").textContent="",y("Google sign-in isn\u2019t switched on yet. Enable the Google provider in Supabase (Authentication \u2192 Sign In / Providers).",7e3);return}const n=await Sr(e.config),{error:a}=await n.auth.signInWithOAuth({provider:"google",options:{redirectTo:`${location.origin}/__loop/?loop_auth=1`}});if(a)throw a}catch(e){y(e.message||"Google sign-in is not available",5e3)}}),m("#cloud-signout").addEventListener("click",async()=>{await x("POST","/__loop/api/cloud/signout"),Ie=null,ls()});async function gd(){if(!(X||!new URLSearchParams(location.search).has("loop_auth"))){try{const e=await x("GET","/__loop/api/cloud"),t=await Sr(e.config);let{data:n}=await t.auth.getSession();for(let s=0;!n.session&&s<20;s++)await new Promise(i=>setTimeout(i,150)),{data:n}=await t.auth.getSession();if(!n.session)throw new Error("Google sign-in did not complete");t.auth.stopAutoRefresh();const{user:a}=await x("POST","/__loop/api/cloud/session",{access_token:n.session.access_token,refresh_token:n.session.refresh_token,expires_at:n.session.expires_at});try{localStorage.removeItem("loop-host-auth")}catch{}y(`Signed in as ${a.email}`),setTimeout(()=>m("#share-btn").click(),300)}catch(e){y(e.message,5e3)}history.replaceState(null,"","/__loop/")}}async function Ar(e){const t=ue(e);if(!t?.documentElement)throw new Error("screen not loaded yet");const n=`<!doctype html>
|
|
57
|
+
`+t.documentElement.outerHTML;return x("POST","/__loop/api/cloud/snapshot",{frameId:e,html:n})}async function yd(e){await x("POST","/__loop/api/cloud/publish");const t=f.frames.filter(a=>a.kind==="route");let n=0;for(const a of t){e.textContent=`Uploading screens\u2026 ${++n}/${t.length}`;try{await Ar(a.id)}catch(s){console.warn("snapshot",a.name,s)}}}function bd(e){const t=f?.frames.find(n=>n.id===e);X||!t||t.kind!=="route"||!Ie?.canvasId||!Ie?.user||setTimeout(()=>Ar(e).catch(()=>{}),2500)}m("#invite-go").addEventListener("click",_r),m("#invite-emails").addEventListener("keydown",e=>{e.stopPropagation(),e.key==="Enter"&&_r()});async function _r(){const e=m("#invite-emails").value.split(/[\s,;]+/).map(a=>a.trim()).filter(Boolean),t=m("#invite-note"),n=m("#invite-go");if(!e.length){t.textContent="Add one or more email addresses.";return}n.disabled=!0;try{await yd(t),t.textContent="Sending invites\u2026";const a=await x("POST","/__loop/api/cloud/invite",{emails:e});m("#invite-emails").value="",t.textContent=a.warning?a.warning:a.failed?.length?`Invited, but email failed for ${a.failed.map(s=>s.email).join(", ")} \u2014 share the link with them.`:`Invite${a.emailed.length===1?"":"s"} sent to ${a.emailed.join(", ")}.`,await ls()}catch(a){t.textContent=a.message}n.disabled=!1}const cs=[["Mobile",393,852],["Tablet",834,1194],["Desktop",1440,1024]],ds=[["Phone",[["iPhone 16",393,852],["iPhone 16 Pro Max",440,956],["iPhone Duo",466,678],["iPhone SE",375,667],["Android (compact)",412,917],["Android (large)",448,998]]],["Tablet",[["iPhone Duo, open",951,669],["iPad mini",744,1133],['iPad Pro 11"',834,1194],['iPad Pro 13"',1032,1376],["Android tablet",800,1280]]],["Desktop",[["Desktop",1440,1024],["MacBook Air",1280,832],['MacBook Pro 14"',1512,982],["Desktop HD",1920,1080],["Wide",1728,1117]]]],Pr={Mobile:A("phone"),Tablet:A("tablet"),Desktop:A("desktop")};let he=K.get("loop.framePreset",null)||{name:"Desktop",w:1440,h:1024};const Dr={Phone:A("phone"),Tablet:A("tablet"),Desktop:A("desktop")},it=document.createElement("div");it.id="frame-ghost",it.hidden=!0,it.innerHTML="<span></span>",Tt.appendChild(it);let Sn=null;function oa(){const e=U==="frame"&&!!Sn&&!oe&&!!f&&k();if(it.hidden!==!e&&(it.hidden=!e),!e)return;const t=fe(Sn.x,Sn.y),n=it.style,a=`<b>${C(he.name)}</b>${he.w} \xD7 ${he.h}`;n.left=`${t.x}px`,n.top=`${t.y}px`,n.width=`${he.w}px`,n.height=`${he.h}px`,it._l!==a&&(it._l=a,it.firstChild.innerHTML=a)}addEventListener("pointermove",e=>{if(U!=="frame"){it.hidden||(it.hidden=!0);return}Sn=q.contains(e.target)?{x:e.clientX,y:e.clientY}:null,oa()},!0),addEventListener("pointerup",()=>{U==="frame"&&requestAnimationFrame(oa)},!0),addEventListener("wheel",()=>{U==="frame"&&Sn&&requestAnimationFrame(oa)},{capture:!0,passive:!0});function fs(){const e=m("#preset-menu"),t=m("#toolbar"),n=!e.hidden&&e.dataset.mode==="new";if(t.classList.toggle("menu-open",n),m("#frame-tray .tr-more")?.classList.toggle("open",n),!n)return;const a=t.getBoundingClientRect();e.style.left=`${a.left}px`,e.style.width=`${a.width}px`,e.style.bottom=`${innerHeight-a.top-1}px`,e.style.top="",e.classList.toggle("narrow",a.width<470)}new MutationObserver(fs).observe(m("#preset-menu"),{attributes:!0,attributeFilter:["hidden","data-mode"]}),new ResizeObserver(fs).observe(m("#toolbar")),addEventListener("resize",fs);const qr=()=>document.querySelectorAll('#preset-menu[data-mode="new"] .pm-row').forEach(e=>e.classList.toggle("on",+e.dataset.w===he.w&&+e.dataset.h===he.h));function vd(e){const t=m("#preset-menu"),n=!t.hidden&&t.dataset.mode==="new",a=e==="ArrowRight"||e==="ArrowDown"?1:-1,s=e==="ArrowLeft"||e==="ArrowRight";if(!n){if(e==="ArrowUp")qi(),t.hidden=!1;else if(s){const c=[...cs].reverse(),d=c.findIndex(([,g,w])=>he.w===g&&he.h===w),[u,p,h]=c[d<0?a>0?0:c.length-1:(d+a+c.length)%c.length];ra(u,p,h)}return}const i=[...t.querySelectorAll(".pm-group")].map(c=>[...c.querySelectorAll(".pm-row")]);let o=i.findIndex(c=>c.some(d=>d.classList.contains("on"))),r=o<0?-1:i[o].findIndex(c=>c.classList.contains("on"));if(o<0)o=0,r=0;else if(s)o=Math.max(0,Math.min(i.length-1,o+a)),r=Math.min(r,i[o].length-1);else if(r+=a,r<0&&(r=0),r>=i[o].length){t.hidden=!0;return}const l=i[o][r];ra(l.dataset.name,+l.dataset.w,+l.dataset.h),qr(),l.scrollIntoView({block:"nearest"})}function ra(e,t,n){he={name:e,w:Math.round(t),h:Math.round(n)},K.set("loop.framePreset",he),Ir()}function Ir(){const e=m("#toolbar"),t=m("#frame-tray"),n=U==="frame"&&!!f&&k();if(e.classList.toggle("tray-open",n),!n){m("#preset-menu").hidden=!0,Sn=null,oa();return}const a=(r,l)=>he.w===r&&he.h===l,s=[...cs].reverse(),i=s.some(([,r,l])=>a(r,l)),o=s.map(([r,l,c])=>`<button class="tr-dev${a(l,c)?" on":""}" data-w="${l}" data-h="${c}" data-name="${r}" title="${r} \xB7 ${l} \xD7 ${c}">${Pr[r]}</button>`).join("")+`<button class="tr-more${i?"":" on"}" title="All sizes">${i?"<span>More</span>":`<span>${C(he.name)}</span>`}<small>${he.w} \xD7 ${he.h}</small>${A("down")}</button>`;t._h!==o&&(t._h=o,t.innerHTML=o),oa(),fs()}function qi(e){const t=m("#preset-menu"),n=e||he,a=(s,i)=>Math.round(n.w)===s&&Math.round(n.h)===i;if(t.dataset.mode=e?"resize":"new",t.classList.toggle("for-frame",!!e),t.classList.toggle("docked",!e),e&&(t.style.width=t.style.bottom="",t.classList.remove("narrow")),e){const s=[e.kind==="frozen"?e.from?'<button class="pm-act" data-act="live">Open live</button>':"":`<button class="pm-act" data-act="freeze">${Ss}<span>Freeze a copy</span><kbd>\u21E7F</kbd></button>`,Et(e)?`<button class="pm-act${e.keyboard?" on":""}" data-act="keyboard"><span>Keyboard</span><kbd>K</kbd></button>`:""].join("");t.innerHTML=`<div class="pm-custom pm-top"><span>Size</span><label>W<input id="pm-w" inputmode="numeric" value="${Math.round(e.w)}"></label><label>H<input id="pm-h" inputmode="numeric" value="${Math.round(e.h)}"></label><button id="pm-use">Apply</button></div>`+ds.map(([i,o])=>`<div class="pm-group"><div class="pm-title">${Dr[i]||""}<span>${i}</span></div>${o.map(([r,l,c])=>`<button class="pm-row${a(l,c)?" on":""}" data-w="${l}" data-h="${c}" data-name="${C(r)}"><span>${C(r)}</span><small>${l} \xD7 ${c}</small></button>`).join("")}</div>`).join("")+(s?`<div class="pm-acts">${s}</div>`:"");return}t.innerHTML=[...ds].reverse().map(([s,i])=>`<div class="pm-group"><div class="pm-title">${Dr[s]||""}<span>${s}</span></div>${i.map(([o,r,l])=>`<button class="pm-row${a(r,l)?" on":""}" data-w="${r}" data-h="${l}" data-name="${C(o)}"><span>${C(o)}</span><small>${r} \xD7 ${l}</small></button>`).join("")}</div>`).join("")+`<div class="pm-custom"><span>Custom</span><label>W<input id="pm-w" inputmode="numeric" value="${he.w}"></label><label>H<input id="pm-h" inputmode="numeric" value="${he.h}"></label><button id="pm-use">Use</button></div><button class="pm-describe" id="pm-describe">${A("frame")}<span>Describe a frame for the agent</span><kbd>N</kbd></button>`}m("#frame-tray").addEventListener("pointerdown",e=>e.stopPropagation()),m("#frame-tray").addEventListener("click",e=>{const t=e.target.closest(".tr-dev");if(t){ra(t.dataset.name,+t.dataset.w,+t.dataset.h),qr();return}if(e.target.closest(".tr-more")){const n=m("#preset-menu");if(!n.hidden){n.hidden=!0;return}qi(),n.hidden=!1}}),m("#preset-menu").addEventListener("pointerdown",e=>e.stopPropagation()),m("#preset-menu").addEventListener("click",e=>{const t=m("#preset-menu");if(t.dataset.mode==="resize"){const a=e.target.closest("[data-act]")?.dataset.act;if(a&&D){a==="freeze"?wa(D):a==="live"?fl(D):a==="keyboard"&&Ts(D),zr(!0);return}const s=e.target.closest(".pm-row");if(s){ca(+s.dataset.w,+s.dataset.h);return}if(e.target.closest("#pm-use")){const i=+m("#pm-w").value,o=+m("#pm-h").value;i>=40&&o>=40&&ca(i,o)}return}const n=e.target.closest(".pm-row");if(n){ra(n.dataset.name,+n.dataset.w,+n.dataset.h),t.hidden=!0;return}if(e.target.closest("#pm-use")){const a=+m("#pm-w").value,s=+m("#pm-h").value;a>=40&&s>=40&&(ra("Frame",a,s),t.hidden=!0);return}e.target.closest("#pm-describe")&&(m("#preset-menu").hidden=!0,Ae("select"),Di())}),m("#preset-menu").addEventListener("keydown",e=>{e.key==="Enter"&&(e.target.id==="pm-w"||e.target.id==="pm-h")&&m("#pm-use").click(),e.key==="Escape"&&(m("#preset-menu").hidden=!0,e.stopPropagation())}),addEventListener("pointerdown",e=>{const t=m("#preset-menu");t.hidden||e.target.closest("#preset-menu, #frame-tray, .frame > .dims")||(t.hidden=!0,t.dataset.mode==="resize"&&Ye&&(Ye=null))},!0);function zr(e){const t=m("#preset-menu"),n=f&&k()&&!X&&U==="select"&&D&&Ye===D&&f.frames.find(s=>s.id===D);if(!n){t.dataset.mode==="resize"&&(t.hidden=!0);return}const a=`${n.id}|${Math.round(n.w)}|${Math.round(n.h)}|${n.kind}|${!!n.keyboard}`;(e||t.dataset.mode!=="resize"||t._key!==a&&!t.contains(document.activeElement))&&(qi(n),t._for=n.id,t._key=a),t.hidden=!1,Hr()}function Hr(){const e=m("#preset-menu");if(e.hidden||e.dataset.mode!=="resize")return;const t=P.get(e._for)?.el.querySelector(":scope > .dims");if(!t)return;const n=t.getBoundingClientRect(),a=t.parentElement.querySelector(".frame-body").getBoundingClientRect(),s=e.offsetWidth,i=e.offsetHeight;let o=a.right+14,r=Math.max(60,Math.min(a.bottom-i,innerHeight-i-76));o+s>innerWidth-12&&(o=a.left-14-s),o<12&&(o=Math.max(12,Math.min(n.left+n.width/2-s/2,innerWidth-s-12)),r=n.bottom+8,r+i>innerHeight-70&&(r=Math.max(12,n.top-i-8))),e.style.left=`${Math.round(o)}px`,e.style.top=`${Math.round(r)}px`}function la(e){const t=new Set(f.frames.map(n=>n.name));if(!t.has(e))return e;for(let n=2;;n++)if(!t.has(`${e} ${n}`))return`${e} ${n}`}function Ii(e,t,n){const a=n||fe(innerWidth/2,innerHeight/2),s=(r,l)=>f.frames.some(c=>r<c.x+c.w+80&&r+e+80>c.x&&l<c.y+c.h+80&&l+t+80>c.y),i=Math.round(a.x-e/2),o=Math.round(a.y-t/2);for(let r=0;r<30;r++)for(const[l,c]of[[1,0],[0,1],[-1,0],[0,-1]]){const d=i+l*r*(e*.5+80),u=o+c*r*(t*.5+80);if(!s(d,u))return{x:d,y:u}}return{x:i,y:o}}function zt(e){if(S)return;const t=f.frames.find(s=>s.id===e);if(!t)return;const n={x:v.x+t.x*v.z,y:v.y+t.y*v.z},a={x:n.x+t.w*v.z,y:n.y+t.h*v.z};(n.x<0||n.y<60||a.x>innerWidth||a.y>innerHeight-80)&&Oe(!0,[e])}function wd(e){const t=[],n=a=>{for(const s of f.frames)s.parent===a&&!t.includes(s)&&(t.push(s),n(s.id))};return n(e),t}function Or(e,t=new Set){return f.frames.filter(n=>!t.has(n.id)&&e.x>=n.x&&e.y>=n.y&&e.x+e.w<=n.x+n.w&&e.y+e.h<=n.y+n.h).sort((n,a)=>n.w*n.h-a.w*a.h)[0]||null}async function Tn(e,t,n,a,s){const i=a!=null?{x:Math.round(a),y:Math.round(s)}:Ii(t,n),o=a!=null?Or({...i,w:t,h:n})?.id:null;try{const r=await x("POST","/__loop/api/frames",{new:!0,blank:!0,name:la(e),w:Math.round(t),h:Math.round(n),...i,...o?{parent:o}:{}});Ze=r.id,za=r.id;let l=null;J("Add frame",async()=>{l=Ct(r.id)||l,await x("DELETE",`/__loop/api/frames/${r.id}`)},()=>ze(l||{frames:[r]})),Ae("select"),f.frames.find(c=>c.id===r.id)&&(Ze=za=null,Q(r.id),zt(r.id),setTimeout(()=>ea(r.id),340))}catch(r){y(r.message)}}function Fe(){const e=m("#frame-panel");e.hidden=!0,zr()}async function ca(e,t){const n=f.frames.find(l=>l.id===D);if(!n||!(e>0&&t>0))return;const a={w:n.w,h:n.h},s={w:Math.round(e),h:Math.round(t)},i=n.id;(a.w!==s.w||a.h!==s.h)&&J("Resize frame",()=>Ut(i,a),()=>Ut(i,s));const o=Os(a),r=Os(s);Object.assign(n,s),ee(n),o!==r&&["route","url","folder"].includes(n.kind)&&!n.image&&!n.sizeOf&&k()&&(K.set(`loop.respFrame.${f.name}.${i}`,{from:{...a,cls:o},at:Date.now()}),ee(n));try{await x("PATCH",`/__loop/api/frames/${n.id}`,{w:n.w,h:n.h})}catch(l){y(l.message)}Fe(),setTimeout(()=>wt(n.id),60)}m("#frame-panel").addEventListener("pointerdown",e=>e.stopPropagation()),m("#frame-panel").addEventListener("click",e=>{const t=e.target.closest('[data-pick="frame-fill"]');if(t)return $s(t);if(e.target.closest(".fp-fill-none")){const n=f.frames.find(s=>s.id===D);if(!n)return;const a=n.fill==="none"?null:"none";Qt={id:n.id,before:n.fill||null},n.fill=a||void 0,ee(n),x("PATCH",`/__loop/api/frames/${n.id}`,{fill:a}).catch(s=>y(s.message)),sl(),Fe()}}),m("#frame-panel").addEventListener("wheel",e=>e.stopPropagation()),m("#frame-panel").addEventListener("click",e=>{const t=e.target.closest("[data-act]")?.dataset.act;if(t&&D){t==="freeze"?wa(D):t==="live"?fl(D):t==="keyboard"&&Ts(D);return}if(e.target.closest("#fp-close")){U==="frame"?Ae("select"):(Ye=null,Fe());return}if(e.target.closest("#fp-describe")){Ae("select"),Di();return}if(e.target.closest("#fp-make")){const a=+m("#fp-w").value,s=+m("#fp-h").value;a>0&&s>0&&Tn("Frame",a,s);return}const n=e.target.closest("[data-w]");n&&(U==="frame"?Tn(n.dataset.name,+n.dataset.w,+n.dataset.h):ca(+n.dataset.w,+n.dataset.h))}),m("#frame-panel").addEventListener("keydown",e=>{if(e.stopPropagation(),e.key==="Escape"){e.target.blur();return}if(e.key==="Enter"){if(e.target.id==="fp-sw"||e.target.id==="fp-sh"){const t=+m("#fp-sw").value,n=+m("#fp-sh").value;e.target.blur(),ca(t,n)}(e.target.id==="fp-w"||e.target.id==="fp-h")&&m("#fp-make").click()}}),m("#frame-panel").addEventListener("focusout",e=>{if((e.target.id==="fp-sw"||e.target.id==="fp-sh")&&!m("#frame-panel").contains(e.relatedTarget)){const t=f.frames.find(s=>s.id===D),n=+m("#fp-sw")?.value,a=+m("#fp-sh")?.value;t&&(n!==Math.round(t.w)||a!==Math.round(t.h))&&ca(n,a)}});const da=[],zi=[];let Hi=!1;function J(e,t,n){Hi||X||!k()||(da.push({label:e,undo:t,redo:n}),da.length>200&&da.shift(),zi.length=0)}async function Rr(e,t,n){const a=e.pop();if(!a){y(n==="undo"?"Nothing to undo":"Nothing to redo",1200);return}Hi=!0;try{await a[n](),t.push(a),y(`${n==="undo"?"Undo":"Redo"}: ${a.label}`,1400)}catch(s){y(`Couldn't ${n}: ${s.message}`)}finally{Hi=!1}}const us=()=>Rr(da,zi,"undo"),fa=()=>Rr(zi,da,"redo");function Ut(e,t){const n=f.frames.find(a=>a.id===e);return n&&(Object.assign(n,t),ee(n),Fe(),setTimeout(()=>wt(e),50)),x("PATCH",`/__loop/api/frames/${e}`,t)}const ze=e=>x("POST","/__loop/api/restore",e);function Ct(e){const t=f.frames.find(n=>n.id===e);return t?{frames:[{...t}],comments:f.comments.filter(n=>n.frameId===e).map(n=>({...n}))}:null}async function Nr(e){const t=f.frames.find(c=>c.id===e);if(!t)return;const n=f.frames.filter(c=>c.parent===e),a=Ct(e);if(n.length){for(const c of n)await x("PATCH",`/__loop/api/frames/${c.id}`,{parent:null});return await x("DELETE",`/__loop/api/frames/${e}`),Q(null),J("Unframe",async()=>{await ze(a);for(const c of n)await x("PATCH",`/__loop/api/frames/${c.id}`,{parent:e})},async()=>{for(const c of n)await x("PATCH",`/__loop/api/frames/${c.id}`,{parent:null});await x("DELETE",`/__loop/api/frames/${e}`)}),y(`Unframed \u201C${t.name}\u201D: its ${n.length} frame${n.length===1?"":"s"} stay where they are \xB7 \u2318Z to undo`,2800)}if(t.kind!=="folder"||t.image)return y(t.image?"An image has no parts to keep.":"A live app page can\u2019t be taken apart. Unframe works on static pages, or frames that hold other frames.",3e3);const s=ga(e);if(!s?.body)return y("Open the frame first so its page has loaded");const i=c=>[...c.children].filter(d=>!/^(SCRIPT|STYLE|TEMPLATE|LINK|META|NOSCRIPT)$/.test(d.tagName)&&d.getBoundingClientRect().width>2&&d.getBoundingClientRect().height>2);let o=s.body,r=i(o);for(let c=0;c<4&&r.length===1&&i(r[0]).length;c++)o=r[0],r=i(o);if(!r.length)return y("Nothing in this frame to keep");if(r.length>40)return y(`That would make ${r.length} frames. Unframe works best on a page with a few parts.`,3e3);const l=[];try{for(const c of r){const d=ha(e,c),u=await x("POST","/__loop/api/frames",{new:!0,name:la(d.name||"Part"),w:d.w,h:d.h,x:Math.round(t.x+d.x),y:Math.round(t.y+d.y),html:Wr(d),fill:"none"});l.push(u.id)}await x("DELETE",`/__loop/api/frames/${e}`),Q(null)}catch(c){for(const d of l)x("DELETE",`/__loop/api/frames/${d}`).catch(()=>{});return y(c.message)}J("Unframe",async()=>{for(const c of l)await x("DELETE",`/__loop/api/frames/${c}`);await ze(a)},()=>y("Unframe again to split it once more")),y(`Unframed \u201C${t.name}\u201D into ${l.length} part${l.length===1?"":"s"} \xB7 \u2318Z to undo`,2800)}async function xd(e){const t=Ct(e);t&&(await x("DELETE",`/__loop/api/frames/${e}`),J("Delete frame",()=>ze(t),()=>x("DELETE",`/__loop/api/frames/${e}`)),y(`Deleted \u201C${t.frames[0].name}\u201D \u2014 \u2318Z to undo`,2600))}let L=null,ua={fid:null,t:0,x:0,y:0};function Br(e){let t=e;for(let n=0;n<6;n++){const a=[...t.children].filter(o=>!/^(SCRIPT|STYLE|LINK|META|NOSCRIPT|TEMPLATE)$/.test(o.tagName));if(a.length!==1||!a[0].children.length)break;const s=t.getBoundingClientRect();if(a[0].getBoundingClientRect().width<s.width*.9)break;t=a[0]}return t}function ps(e,t,n){const a=ue(e),s=a?.body;if(!t||!s||t===a.documentElement)return null;if(n==="block")return s.contains(t)?$d(t,s):null;if(n==="deep"||!s.contains(t))return t===s?null:t;if(n==="smart"){const c=L?.frameId===e?L.els[L.els.length-1]:null;if(c?.isConnected&&c!==s&&c.contains(t)){if(t===c)return c;let d=t;for(;d.parentElement&&d.parentElement!==c;)d=d.parentElement;return d}return kd(t,s)}if(n==="outer"){const c=L?.frameId===e?L.els[L.els.length-1]:null,d=c?.isConnected&&c.contains(t)?c:t,u=d.parentElement;return!u||u===s?d:u}const i=L?.frameId===e,o=i?L.els[L.els.length-1]:null;let r=(n==="drill"||n==="step")&&o?.isConnected&&o.contains(t)?o:i&&L.scope?.isConnected?L.scope:Br(s);for(;r!==s&&!r.contains(t);)r=r.parentElement;if(t===r)return r===s?null:r;let l=t;for(;l.parentElement&&l.parentElement!==r;)l=l.parentElement;return l}function kd(e,t){if(!t.contains(e)||e===t)return null;const n=t.ownerDocument.defaultView,a=e.closest?.('button, a[href], input, select, textarea, label, img, picture, video, canvas, iframe, svg, [role="button"], [role="link"], [role="tab"], [role="checkbox"], [role="switch"]');if(a&&t.contains(a))return a.closest("svg")&&a.tagName.toLowerCase()!=="svg"?a.closest("svg"):a;let s=e;for(;s.parentElement&&s.parentElement!==t&&/^inline$/.test(n.getComputedStyle(s).display);)s=s.parentElement;const i=(o,r)=>{const l=o.getBoundingClientRect(),c=r.getBoundingClientRect();return Math.abs(l.left-c.left)<1&&Math.abs(l.top-c.top)<1&&Math.abs(l.width-c.width)<1&&Math.abs(l.height-c.height)<1};for(;s.parentElement&&s.parentElement!==t&&s.parentElement.children.length===1&&i(s,s.parentElement);)s=s.parentElement;return s===t?null:s}function $d(e,t){let n=e.closest?.("svg")||e;for(;n&&n!==t;n=n.parentElement){if(n.tagName.toLowerCase()==="svg")continue;const a=[...n.children].filter(i=>!/^(SCRIPT|STYLE|BR|TEMPLATE)$/.test(i.tagName)).length,s=n.getBoundingClientRect();if(a&&n.ownerDocument.defaultView.getComputedStyle(n).display!=="inline"&&s.width>24&&s.height>16)return n}return null}function Ke(e){const t=[...e.childNodes].filter(o=>o.nodeType===3).map(o=>o.data).join(" ").replace(/\s+/g," ").trim();if(t&&!e.children.length)return t.length>28?t.slice(0,27)+"\u2026":t;const n=e.tagName.toLowerCase(),a={img:"Image",svg:"Icon",picture:"Image",video:"Video",canvas:"Canvas",button:"Button",a:"Link",input:"Field",textarea:"Field",select:"Menu",ul:"List",ol:"List",li:"Item",nav:"Navigation",header:"Header",footer:"Footer",form:"Form",table:"Table",label:"Label",section:"Section",main:"Main",aside:"Aside",article:"Article"},s=(e.getAttribute("aria-label")||"").trim();if(a[n]&&(n==="button"||n==="a")&&(t||s))return`${a[n]} \xB7 ${(t||s).slice(0,22)}`;if(a[n])return a[n];if(/^h[1-6]$/.test(n))return"Heading";const i=typeof e.className=="string"&&e.className.trim().split(/\s+/).find(o=>/^[a-zA-Z][a-zA-Z0-9_-]{2,}$/.test(o)&&!/[:\[]/.test(o)&&!/\d/.test(o))||(/^[a-zA-Z][\w-]*$/.test(e.id)?e.id:"");if(i){const o=i.replace(/[-_]+/g," ").replace(/([a-z])([A-Z])/g,"$1 $2").trim();return o[0].toUpperCase()+o.slice(1).toLowerCase()}return t?"Text":"Frame"}let Xt={fid:null,x:0,y:0,n:0,t:0},De=null,ms=0;function Ld(e,t,n){if(t?.ctx)return;if(n!=="step"&&n!=="smart"){n==="deep"&&U==="select"&&K.set("loop.knowsDeep",1),Xt.n=0;return}const a=performance.now(),s=Xt.fid===e&&a-Xt.t<2500&&Math.hypot(t.clientX-Xt.x,t.clientY-Xt.y)<14;Xt={fid:e,x:t.clientX,y:t.clientY,n:s?Xt.n+1:1,t:a},Xt.n>=3&&!De&&!K.get("loop.knowsDeep",0)&&K.get("loop.deepTipSeen",0)<2&&Fr(t.clientX,t.clientY)}function Fr(e,t,n){De&&Oi();const a=pt==="metaKey"?"\u2318":"Ctrl";De=document.createElement("div"),De.id="deep-tip",De.innerHTML=`<div class="dt-demo" aria-hidden="true"><div class="dt-card"><i class="dt-l t"></i><i class="dt-l a"></i><i class="dt-l b"></i><i class="dt-btn"></i></div>
|
|
57
58
|
<i class="dt-o o1"></i><i class="dt-o o2"></i><i class="dt-o o3"></i><kbd class="dt-key">${a}</kbd>
|
|
58
59
|
<svg class="dt-cur" viewBox="0 0 24 24"><path d="M5 3l14 7.5-6.2 1.6L10.5 19z"/></svg></div>
|
|
59
60
|
<button class="dt-x" title="Close" aria-label="Close"><svg viewBox="0 0 16 16"><path d="M4 4l8 8M12 4l-8 8"/></svg></button>
|
|
60
|
-
<div class="dt-say"><b>Go straight to it</b><span>Hold <kbd>${a}</kbd> and move over the page. Whatever is under the pointer gets picked, however deep it sits.</span></div>`,document.body.appendChild(qe);const i=272,s=qe.offsetHeight||190;qe.style.left=Math.max(12,Math.min(innerWidth-i-12,e+18))+"px",qe.style.top=Math.max(60,Math.min(innerHeight-s-90,t+22))+"px",n||Ae.set("loop.deepTipSeen",Ae.get("loop.deepTipSeen",0)+1);const o=qe;o.querySelector(".dt-x").addEventListener("click",is),o.addEventListener("pointerdown",c=>c.stopPropagation());const r=()=>{if(qe===o){if(o.matches(":hover")){Ua=setTimeout(r,800);return}o.classList.add("docked"),o.style.left=innerWidth-o.offsetWidth-16+"px",o.style.top="60px"}};clearTimeout(Ua),Ua=setTimeout(r,4500)}function is(){clearTimeout(Ua);const e=qe;e&&(qe=null,e.classList.add("out"),setTimeout(()=>e.remove(),180))}addEventListener("resize",()=>{qe?.classList.contains("docked")&&(qe.style.left=innerWidth-qe.offsetWidth-16+"px")});function Qt(e,t,n="deep"){xc(e,t,n);const{lx:a,ly:i}=Ge(e,t.clientX,t.clientY),s=Me(e,a,i),o=de(e),r=x?.frameId===e?x.els[x.els.length-1]:null;if(n==="drill"&&r&&r.contains(s)&&(s===r||!r.children.length)&&xn(r,!0)){kn(e,r);return}const c=Xa(e,s,n);if(!c||c===o?.documentElement)return;if(n==="drill"&&c===r&&xn(r,!0)){kn(e,r);return}if(t.shiftKey&&x?.frameId===e){const d=x.els.indexOf(c);if(d>=0?x.els.splice(d,1):x.els.push(c),!x.els.length){Ve(),te();return}}else H.hidden||te(),x={frameId:e,els:[c],scope:c.parentElement};V.hidden=!0,fe===e&&(fe=null,ht());const l=f.frames.find(d=>d.id===e);l&&J(l),Za(e)}function Za(e){{const t=f.frames.find(n=>n.id===e);t&&J(t)}ee(),Re(),Pe(),bt()}function ea(){if(!x)return;const{frameId:e,els:t}=x,n=t[t.length-1].getBoundingClientRect(),a=D.get(e).iframe.getBoundingClientRect(),i=x;x=null,st(e,n.left+Math.min(n.width/2,60),n.top+Math.min(n.height/2,20)),x=i,B.deep=!0,B.anchor=On(e,{...B.anchor,scope:"elements",elements:t.map(ta)}),W.placeholder=t.length>1?"What should change about these?":"What should change about this?";const s=m("#composer-area");s.hidden=!1,s.classList.remove("chip-frame"),s.textContent=t.length===1?Ye(t[0]):`${t.length} layers`,ae.hidden=!0,Pe(),_e()}function zd(){if(!x||x.els.length!==1)return!1;const e=x.frameId,t=x.els[0],n=de(e)?.body,a=t.parentElement;if(!n||!a||a===n||a===er(n)||!n.contains(a))return!1;const i=a.getBoundingClientRect(),s=D.get(e).iframe.getBoundingClientRect();return x={frameId:e,els:[a],scope:a.parentElement},Za(e),!0}function ta(e){const t=e.outerHTML;return{selector:Dt(e),tag:e.tagName.toLowerCase(),label:to(e),text:(e.innerText||e.getAttribute("aria-label")||e.getAttribute("alt")||"").replace(/\s+/g," ").trim().slice(0,120),html:t.length>900?t.slice(0,900)+"\u2026":t}}function Pe(){if(document.querySelectorAll(".deep-box").forEach(t=>t.remove()),!x)return;const e=Ht(x.frameId);if(e)for(const t of x.els){const n=t.getBoundingClientRect(),a=document.createElement("div");a.className="deep-box",Object.assign(a.style,{left:`${n.left}px`,top:`${n.top}px`,width:`${n.width}px`,height:`${n.height}px`}),a.dataset.tag=Ye(t),e.appendChild(a);const i=x.els.length===1&&t.parentElement,s=t.ownerDocument.body;if(i&&i!==s&&i!==t.ownerDocument.documentElement){const o=i.getBoundingClientRect(),r=document.createElement("div");r.className="deep-box par",Object.assign(r.style,{left:`${o.left}px`,top:`${o.top}px`,width:`${o.width}px`,height:`${o.height}px`}),e.appendChild(r)}}}function Ve(){if(Ft(),x=null,document.querySelectorAll(".deep-box").forEach(e=>e.remove()),O&&(clearTimeout(O.t),Object.keys(O.pending).length&&f.frames.find(e=>e.id===O.fid)?.kind==="folder"&&hr()),ae.hidden=!0,O=null,V.hidden=!0,f)for(const e of f.frames)J(e)}const rt=/Mac|iPhone|iPad/.test(navigator.platform)?"metaKey":"ctrlKey",kc=new Set(["area","base","br","col","embed","hr","img","input","link","meta","source","track","wbr"]),$c=new Set(["script","style","textarea","title"]),Lc=new Set(["address","article","aside","blockquote","div","dl","fieldset","footer","form","h1","h2","h3","h4","h5","h6","header","hr","main","nav","ol","p","pre","section","table","ul"]),Cc={li:["li"],dt:["dt","dd"],dd:["dt","dd"],option:["option"],tr:["tr"],td:["td","th"],th:["td","th"]};function Mc(e){const t={tag:"#root",kids:[],parent:null},n=e.length;let a=t,i=0,s=0,o=0;const r=l=>{l>s&&a.kids.push({text:!0,a:s,b:l})},c=(l,d,u)=>{l.innerB=d,l.b=u,(l.tag==="svg"||l.tag==="math")&&(o=Math.max(0,o-1))};for(;i<n;){const l=e.indexOf("<",i);if(l<0)break;if(e.startsWith("<!--",l)){r(l);const E=e.indexOf("-->",l+4),N=E<0?n:E+3;a.kids.push({comment:!0,a:l,b:N}),i=s=N;continue}const d=e[l+1];if(d==="!"||d==="?"){r(l);const E=e.indexOf(">",l);i=s=E<0?n:E+1;continue}const u=/^<(\/?)([a-zA-Z][^\s/>]*)/.exec(e.slice(l,l+96));if(!u){i=l+1;continue}let p=l+u[0].length,h=null;for(;p<n;p++){const E=e[p];if(h)E===h&&(h=null);else if(E==='"'||E==="'")h=E;else if(E===">")break}if(p>=n)break;r(l);const g=u[2].toLowerCase(),v=p+1;if(u[1]){let E=a;for(;E!==t&&E.tag!==g;)E=E.parent;if(E!==t){for(let N=a;N!==E;N=N.parent)c(N,l,l);c(E,l,v),a=E.parent}i=s=v;continue}if(!o){Lc.has(g)&&a.tag==="p"&&(c(a,l,l),a=a.parent);const E=Cc[g];E&&E.includes(a.tag)&&(c(a,l,l),a=a.parent)}const T={tag:g,a:l,openEnd:v,kids:[],parent:a,attrs:[],innerA:v,innerB:n,b:n},C=/([^\s"'<>\/=]+)(?:\s*=\s*(?:"([^"]*)"|'([^']*)'|([^\s"'=<>`]+)))?/g,k=e.slice(l+u[0].length,p);for(let E;E=C.exec(k);){const N=l+u[0].length+E.index,q=E[2]??E[3]??E[4],ne=E[2]!=null?'"':E[3]!=null?"'":"",R=q==null?-1:N+E[0].length-q.length-(ne?1:0);T.attrs.push({name:E[1].toLowerCase(),a:N,b:N+E[0].length,va:R,vb:R<0?-1:R+q.length,q:ne,value:q})}a.kids.push(T);const M=e[p-1]==="/";if(kc.has(g)||M&&o){T.innerB=v,T.b=v,i=s=v;continue}if($c.has(g)&&!o){const E=new RegExp(`</${g}\\s*>`,"i"),N=e.slice(v),q=E.exec(N),ne=q?v+q.index:n,R=q?ne+q[0].length:n;ne>v&&T.kids.push({text:!0,a:v,b:ne}),T.innerB=ne,T.b=R,i=s=R;continue}(g==="svg"||g==="math")&&o++,a=T,i=s=v}return r(n),t}const Ec=e=>e.kids.filter(t=>t.tag),Ga=e=>[...e.childNodes].map(t=>t.nodeType===3?"t":t.nodeType===1?t.tagName.toLowerCase():"c").join(","),Sc=e=>e.kids.map(t=>t.text?"t":t.tag?t.tag:"c").join(","),Tc=e=>e.replace(/&/g,"&").replace(/</g,"<").replace(/>/g,">");async function We(e,t){const n=f.frames.find(a=>a.id===e);if(!n||n.kind!=="folder"||X||!$())return null;try{const a=t.ownerDocument,i=[];for(let p=t;p&&p!==a.body;p=p.parentElement){if(!p.parentElement)return null;i.unshift(p)}const{text:s}=await w("GET",`/__loop/api/frames/${e}/source`),o=new DOMParser().parseFromString(s,"text/html"),r=p=>{if(p.tag==="body")return p;for(const h of p.kids)if(h.tag){const g=r(h);if(g)return g}return null};let c=o.body,l=r(Mc(s)),d=a.body;if(!c||!l)return null;const u=p=>`${p.tagName}#${p.id||""}.${typeof p.className=="string"?p.className.trim().split(/\s+/).filter(h=>!/^(on|active|is-|selected|open)/.test(h)).sort().join("."):""}`;for(const p of i){const h=Ec(l);if(h.length!==c.children.length)return null;const g=[...d.children],v=[...c.children];let T=0,C=-1;for(const k of g){let M=T;for(;M<v.length&&u(v[M])!==u(k)&&v[M].tagName!==k.tagName;)M++;if(M<v.length&&(u(v[M])===u(k)||v[M].tagName===k.tagName&&!g.slice(g.indexOf(k)+1).some(E=>u(E)===u(v[M]))))k===p&&(C=M),T=M+1;else if(k===p)return null}if(C<0||(c=v[C],l=h[C],d=p,!c||!l||c.tagName.toLowerCase()!==l.tag))return null}return c.tagName!==t.tagName?null:{src:s,P:c,N:l}}catch{return null}}/[?&]debug\b/.test(location.search)&&(window.__loop={locate:(...e)=>We(...e),stage:e=>vt(e),fit:e=>Oe(!0,[e])});let tt=null;const ss=new Map;function Ac(e){const t=e instanceof(e.ownerDocument.defaultView.SVGElement||SVGElement),n=(t?"svg:":"")+e.tagName.toLowerCase();if(ss.has(n))return ss.get(n);if(!tt){const o=document.createElement("iframe");o.style.cssText="position:fixed;left:-9999px;width:10px;height:10px;visibility:hidden",document.body.appendChild(o),tt=o.contentDocument,tt.open(),tt.write("<!doctype html><html><body></body></html>"),tt.close()}const a=t?tt.createElementNS("http://www.w3.org/2000/svg",e.tagName):tt.createElement(e.tagName);(t?tt.body.querySelector("svg")||tt.body.appendChild(tt.createElementNS("http://www.w3.org/2000/svg","svg")):tt.body).appendChild(a);const i=tt.defaultView.getComputedStyle(a),s={};for(const o of i)s[o]=i.getPropertyValue(o);return a.remove(),ss.set(n,s),s}function _c(e){let t="",n="";for(const a of e.querySelectorAll('link[rel~="stylesheet"]'))/fonts\.(googleapis|gstatic)\.com|typekit|fonts\.bunny/.test(a.href)&&(t+=`<link rel="stylesheet" href="${a.href}">`);for(const a of e.styleSheets){let i;try{i=a.cssRules}catch{continue}const s=a.href||e.baseURI;for(const o of i)o.constructor.name==="CSSFontFaceRule"?n+=o.cssText.replace(/url\((['"]?)([^'")]+)\1\)/g,(r,c,l)=>/^(data:|https?:)/.test(l)?r:`url("${new URL(l,s).href}")`):o.constructor.name==="CSSImportRule"&&/fonts/.test(o.href)&&(t+=`<link rel="stylesheet" href="${new URL(o.href,s).href}">`)}return t+(n?`<style>${n}</style>`:"")}function na(e,t){const n=t.ownerDocument,a=n.defaultView,i=t.cloneNode(!0),s=[t,...t.querySelectorAll("*")],o=[i,...i.querySelectorAll("*")];s.forEach((c,l)=>{const d=o[l];if(!d||d.nodeType!==1)return;if(/^(SCRIPT|NOSCRIPT|TEMPLATE)$/.test(c.tagName)){d.remove();return}const u=a.getComputedStyle(c),p=Ac(c);let h="";for(const g of u){const v=u.getPropertyValue(g);v!==p[g]&&!/^(transition|animation)/.test(g)&&(h+=`${g}:${v};`)}d.setAttribute("style",h),d.removeAttribute("contenteditable");for(const g of["src","href","poster"])d.hasAttribute(g)&&c[g]&&typeof c[g]=="string"&&d.setAttribute(g,c[g]);d.hasAttribute("srcset")&&d.removeAttribute("srcset")}),i.style.setProperty("margin","0"),i.style.setProperty("position","relative"),i.style.setProperty("inset","auto"),i.style.setProperty("transform","none");const r=t.getBoundingClientRect();return{html:i.outerHTML,fonts:_c(n),w:Math.max(8,Math.ceil(r.width)),h:Math.max(8,Math.ceil(r.height)),name:Ye(t),fid:e,x:r.left,y:r.top}}const nr=e=>`<!doctype html>
|
|
61
|
-
<html><head><meta charset="utf-8"><meta name="viewport" content="width=device-width,initial-scale=1"><title>${
|
|
61
|
+
<div class="dt-say"><b>Go straight to it</b><span>Hold <kbd>${a}</kbd> and move over the page. Whatever is under the pointer gets picked, however deep it sits.</span></div>`,document.body.appendChild(De);const s=272,i=De.offsetHeight||190;De.style.left=Math.max(12,Math.min(innerWidth-s-12,e+18))+"px",De.style.top=Math.max(60,Math.min(innerHeight-i-90,t+22))+"px",n||K.set("loop.deepTipSeen",K.get("loop.deepTipSeen",0)+1);const o=De;o.querySelector(".dt-x").addEventListener("click",Oi),o.addEventListener("pointerdown",l=>l.stopPropagation());const r=()=>{if(De===o){if(o.matches(":hover")){ms=setTimeout(r,800);return}o.classList.add("docked"),o.style.left=innerWidth-o.offsetWidth-16+"px",o.style.top="60px"}};clearTimeout(ms),ms=setTimeout(r,4500)}function Oi(){clearTimeout(ms);const e=De;e&&(De=null,e.classList.add("out"),setTimeout(()=>e.remove(),180))}addEventListener("resize",()=>{De?.classList.contains("docked")&&(De.style.left=innerWidth-De.offsetWidth-16+"px")});function ln(e,t,n="deep"){Ld(e,t,n);const{lx:a,ly:s}=Qe(e,t.clientX,t.clientY),i=Se(e,a,s),o=ue(e),r=L?.frameId===e?L.els[L.els.length-1]:null;if(n==="drill"&&r&&r.contains(i)&&(i===r||!r.children.length)&&_n(r,!0)){Pn(e,r);return}const l=ps(e,i,n);if(!l||l===o?.documentElement)return;if(n==="drill"&&l===r&&_n(r,!0)){Pn(e,r);return}if(t.shiftKey&&L?.frameId===e){const d=L.els.indexOf(l);if(d>=0?L.els.splice(d,1):L.els.push(l),!L.els.length){Ve(),ae();return}}else H.hidden||ae(),L={frameId:e,els:[l],scope:l.parentElement};G.hidden=!0,me===e&&(me=null,$t());const c=f.frames.find(d=>d.id===e);c&&ee(c),hs(e)}function hs(e){{const t=f.frames.find(n=>n.id===e);t&&ee(t)}te(),Re(),Pe(),Mt()}function pa(){if(!L)return;const{frameId:e,els:t}=L,n=t[t.length-1].getBoundingClientRect(),a=P.get(e).iframe.getBoundingClientRect(),s=L;L=null,et(e,n.left+Math.min(n.width/2,60),n.top+Math.min(n.height/2,20)),L=s,O.deep=!0,O.anchor=Zn(e,{...O.anchor,scope:"elements",elements:t.map(ma)}),j.placeholder=t.length>1?"What should change about these?":"What should change about this?";const i=m("#composer-area");i.hidden=!1,i.classList.remove("chip-frame"),i.textContent=t.length===1?Ke(t[0]):`${t.length} layers`,ie.hidden=!0,Pe(),Te()}function ou(){if(!L||L.els.length!==1)return!1;const e=L.frameId,t=L.els[0],n=ue(e)?.body,a=t.parentElement;if(!n||!a||a===n||a===Br(n)||!n.contains(a))return!1;const s=a.getBoundingClientRect(),i=P.get(e).iframe.getBoundingClientRect();return L={frameId:e,els:[a],scope:a.parentElement},hs(e),!0}function ma(e){const t=e.outerHTML;return{selector:jt(e),tag:e.tagName.toLowerCase(),label:Oo(e),text:(e.innerText||e.getAttribute("aria-label")||e.getAttribute("alt")||"").replace(/\s+/g," ").trim().slice(0,120),html:t.length>900?t.slice(0,900)+"\u2026":t}}function Pe(){if(document.querySelectorAll(".deep-box").forEach(t=>t.remove()),!L)return;const e=Kt(L.frameId);if(e)for(const t of L.els){const n=t.getBoundingClientRect(),a=document.createElement("div");a.className="deep-box",Object.assign(a.style,{left:`${n.left}px`,top:`${n.top}px`,width:`${n.width}px`,height:`${n.height}px`}),a.dataset.tag=Ke(t),e.appendChild(a);const s=L.els.length===1&&t.parentElement,i=t.ownerDocument.body;if(s&&s!==i&&s!==t.ownerDocument.documentElement){const o=s.getBoundingClientRect(),r=document.createElement("div");r.className="deep-box par",Object.assign(r.style,{left:`${o.left}px`,top:`${o.top}px`,width:`${o.width}px`,height:`${o.height}px`}),e.appendChild(r)}}}function Ve(){if(Jt(),L=null,document.querySelectorAll(".deep-box").forEach(e=>e.remove()),N&&(clearTimeout(N.t),Object.keys(N.pending).length&&f.frames.find(e=>e.id===N.fid)?.kind==="folder"&&nl()),ie.hidden=!0,N=null,G.hidden=!0,f)for(const e of f.frames)ee(e)}const pt=/Mac|iPhone|iPad/.test(navigator.platform)?"metaKey":"ctrlKey",Cd=new Set(["area","base","br","col","embed","hr","img","input","link","meta","source","track","wbr"]),Md=new Set(["script","style","textarea","title"]),Ed=new Set(["address","article","aside","blockquote","div","dl","fieldset","footer","form","h1","h2","h3","h4","h5","h6","header","hr","main","nav","ol","p","pre","section","table","ul"]),Sd={li:["li"],dt:["dt","dd"],dd:["dt","dd"],option:["option"],tr:["tr"],td:["td","th"],th:["td","th"]};function Td(e){const t={tag:"#root",kids:[],parent:null},n=e.length;let a=t,s=0,i=0,o=0;const r=c=>{c>i&&a.kids.push({text:!0,a:i,b:c})},l=(c,d,u)=>{c.innerB=d,c.b=u,(c.tag==="svg"||c.tag==="math")&&(o=Math.max(0,o-1))};for(;s<n;){const c=e.indexOf("<",s);if(c<0)break;if(e.startsWith("<!--",c)){r(c);const E=e.indexOf("-->",c+4),z=E<0?n:E+3;a.kids.push({comment:!0,a:c,b:z}),s=i=z;continue}const d=e[c+1];if(d==="!"||d==="?"){r(c);const E=e.indexOf(">",c);s=i=E<0?n:E+1;continue}const u=/^<(\/?)([a-zA-Z][^\s/>]*)/.exec(e.slice(c,c+96));if(!u){s=c+1;continue}let p=c+u[0].length,h=null;for(;p<n;p++){const E=e[p];if(h)E===h&&(h=null);else if(E==='"'||E==="'")h=E;else if(E===">")break}if(p>=n)break;r(c);const g=u[2].toLowerCase(),w=p+1;if(u[1]){let E=a;for(;E!==t&&E.tag!==g;)E=E.parent;if(E!==t){for(let z=a;z!==E;z=z.parent)l(z,c,c);l(E,c,w),a=E.parent}s=i=w;continue}if(!o){Ed.has(g)&&a.tag==="p"&&(l(a,c,c),a=a.parent);const E=Sd[g];E&&E.includes(a.tag)&&(l(a,c,c),a=a.parent)}const T={tag:g,a:c,openEnd:w,kids:[],parent:a,attrs:[],innerA:w,innerB:n,b:n},$=/([^\s"'<>\/=]+)(?:\s*=\s*(?:"([^"]*)"|'([^']*)'|([^\s"'=<>`]+)))?/g,b=e.slice(c+u[0].length,p);for(let E;E=$.exec(b);){const z=c+u[0].length+E.index,_=E[2]??E[3]??E[4],se=E[2]!=null?'"':E[3]!=null?"'":"",F=_==null?-1:z+E[0].length-_.length-(se?1:0);T.attrs.push({name:E[1].toLowerCase(),a:z,b:z+E[0].length,va:F,vb:F<0?-1:F+_.length,q:se,value:_})}a.kids.push(T);const M=e[p-1]==="/";if(Cd.has(g)||M&&o){T.innerB=w,T.b=w,s=i=w;continue}if(Md.has(g)&&!o){const E=new RegExp(`</${g}\\s*>`,"i"),z=e.slice(w),_=E.exec(z),se=_?w+_.index:n,F=_?se+_[0].length:n;se>w&&T.kids.push({text:!0,a:w,b:se}),T.innerB=se,T.b=F,s=i=F;continue}(g==="svg"||g==="math")&&o++,a=T,s=i=w}return r(n),t}const Ad=e=>e.kids.filter(t=>t.tag),gs=e=>[...e.childNodes].map(t=>t.nodeType===3?"t":t.nodeType===1?t.tagName.toLowerCase():"c").join(","),_d=e=>e.kids.map(t=>t.text?"t":t.tag?t.tag:"c").join(","),Pd=e=>e.replace(/&/g,"&").replace(/</g,"<").replace(/>/g,">");async function We(e,t){const n=f.frames.find(a=>a.id===e);if(!n||n.kind!=="folder"||X||!k())return null;try{const a=t.ownerDocument,s=[];for(let p=t;p&&p!==a.body;p=p.parentElement){if(!p.parentElement)return null;s.unshift(p)}const{text:i}=await x("GET",`/__loop/api/frames/${e}/source`),o=new DOMParser().parseFromString(i,"text/html"),r=p=>{if(p.tag==="body")return p;for(const h of p.kids)if(h.tag){const g=r(h);if(g)return g}return null};let l=o.body,c=r(Td(i)),d=a.body;if(!l||!c)return null;const u=p=>`${p.tagName}#${p.id||""}.${typeof p.className=="string"?p.className.trim().split(/\s+/).filter(h=>!/^(on|active|is-|selected|open)/.test(h)).sort().join("."):""}`;for(const p of s){const h=Ad(c);if(h.length!==l.children.length)return null;const g=[...d.children],w=[...l.children];let T=0,$=-1;for(const b of g){let M=T;for(;M<w.length&&u(w[M])!==u(b)&&w[M].tagName!==b.tagName;)M++;if(M<w.length&&(u(w[M])===u(b)||w[M].tagName===b.tagName&&!g.slice(g.indexOf(b)+1).some(E=>u(E)===u(w[M]))))b===p&&($=M),T=M+1;else if(b===p)return null}if($<0||(l=w[$],c=h[$],d=p,!l||!c||l.tagName.toLowerCase()!==c.tag))return null}return l.tagName!==t.tagName?null:{src:i,P:l,N:c}}catch{return null}}/[?&]debug\b/.test(location.search)&&(window.__loop={locate:(...e)=>We(...e),stage:e=>ht(e),fit:e=>Oe(!0,[e])});let ot=null;const Ri=new Map;function Dd(e){const t=e instanceof(e.ownerDocument.defaultView.SVGElement||SVGElement),n=(t?"svg:":"")+e.tagName.toLowerCase();if(Ri.has(n))return Ri.get(n);if(!ot){const o=document.createElement("iframe");o.style.cssText="position:fixed;left:-9999px;width:10px;height:10px;visibility:hidden",document.body.appendChild(o),ot=o.contentDocument,ot.open(),ot.write("<!doctype html><html><body></body></html>"),ot.close()}const a=t?ot.createElementNS("http://www.w3.org/2000/svg",e.tagName):ot.createElement(e.tagName);(t?ot.body.querySelector("svg")||ot.body.appendChild(ot.createElementNS("http://www.w3.org/2000/svg","svg")):ot.body).appendChild(a);const s=ot.defaultView.getComputedStyle(a),i={};for(const o of s)i[o]=s.getPropertyValue(o);return a.remove(),Ri.set(n,i),i}function qd(e){let t="",n="";for(const a of e.querySelectorAll('link[rel~="stylesheet"]'))/fonts\.(googleapis|gstatic)\.com|typekit|fonts\.bunny/.test(a.href)&&(t+=`<link rel="stylesheet" href="${a.href}">`);for(const a of e.styleSheets){let s;try{s=a.cssRules}catch{continue}const i=a.href||e.baseURI;for(const o of s)o.constructor.name==="CSSFontFaceRule"?n+=o.cssText.replace(/url\((['"]?)([^'")]+)\1\)/g,(r,l,c)=>/^(data:|https?:)/.test(c)?r:`url("${new URL(c,i).href}")`):o.constructor.name==="CSSImportRule"&&/fonts/.test(o.href)&&(t+=`<link rel="stylesheet" href="${new URL(o.href,i).href}">`)}return t+(n?`<style>${n}</style>`:"")}function ha(e,t){const n=t.ownerDocument,a=n.defaultView,s=t.cloneNode(!0),i=[t,...t.querySelectorAll("*")],o=[s,...s.querySelectorAll("*")];i.forEach((l,c)=>{const d=o[c];if(!d||d.nodeType!==1)return;if(/^(SCRIPT|NOSCRIPT|TEMPLATE)$/.test(l.tagName)){d.remove();return}const u=a.getComputedStyle(l),p=Dd(l);let h="";for(const g of u){const w=u.getPropertyValue(g);w!==p[g]&&!/^(transition|animation)/.test(g)&&(h+=`${g}:${w};`)}d.setAttribute("style",h),d.removeAttribute("contenteditable");for(const g of["src","href","poster"])d.hasAttribute(g)&&l[g]&&typeof l[g]=="string"&&d.setAttribute(g,l[g]);d.hasAttribute("srcset")&&d.removeAttribute("srcset")}),s.style.setProperty("margin","0"),s.style.setProperty("position","relative"),s.style.setProperty("inset","auto"),s.style.setProperty("transform","none");const r=t.getBoundingClientRect();return{html:s.outerHTML,fonts:qd(n),w:Math.max(8,Math.ceil(r.width)),h:Math.max(8,Math.ceil(r.height)),name:Ke(t),fid:e,x:r.left,y:r.top}}const Wr=e=>`<!doctype html>
|
|
62
|
+
<html><head><meta charset="utf-8"><meta name="viewport" content="width=device-width,initial-scale=1"><title>${C(e.name)}</title>${e.fonts}<style>html,body{margin:0;background:transparent}</style></head>
|
|
62
63
|
<body>
|
|
63
64
|
${e.html}
|
|
64
65
|
</body></html>
|
|
65
|
-
`;async function Qa(e,t,n){return Kc(e,t,n)}function ar(e){const t=f.frames.find(a=>a.id===e);if(!t)return;y("Copying a picture of the frame\u2026",4e3);const n=w("POST",`/__loop/api/frames/${e}/shot`).then(a=>fetch(`/__loop/shots/${a.path.split("/").pop()}`)).then(a=>{if(!a.ok)throw new Error("No picture");return a.blob()}).then(a=>a.type==="image/png"?a:new Blob([a],{type:"image/png"}));try{navigator.clipboard.write([new ClipboardItem({"image/png":n})]).then(()=>y(`Copied \u201C${t.name}\u201D as an image`,1800),a=>y(`Couldn\u2019t copy the picture (${a.message||a.name})`))}catch(a){y(`Couldn\u2019t copy the picture (${a.message})`)}}function Pc(e){const t=e.ownerDocument,n=[];for(let a=e;a&&a.nodeType===1&&a!==t.documentElement;a=a.parentElement){if(a.id&&/^[A-Za-z][\w-]*$/.test(a.id)&&t.querySelectorAll(`#${a.id}`).length===1){n.unshift(`#${a.id}`);break}if(a.tagName==="BODY"){n.unshift("body");break}const i=a.parentElement?[...a.parentElement.children].filter(s=>s.tagName===a.tagName):[];n.unshift(a.tagName.toLowerCase()+(i.length>1?`:nth-of-type(${i.indexOf(a)+1})`:""))}return n.join(" > ")}function qc(e,t){const n=f.frames.find(s=>s.id===e);if(!n)return null;const a=(f.publicLink||`${location.origin}/__loop/`).split("#")[0],i=t?Ye(t):n.name;return{url:`${a}#f=${encodeURIComponent(e)}${t?`&e=${encodeURIComponent(Pc(t))}`:""}&n=${encodeURIComponent(i)}`,label:i,frame:n.name}}function os(e,t){const n=qc(e,t);if(!n)return;const a=()=>y(`Copied a link to \u201C${n.label}\u201D${t?` in ${n.frame}`:""}. Paste it in a comment to point at it.`,2400);try{navigator.clipboard.write([new ClipboardItem({"text/plain":new Blob([n.url],{type:"text/plain"})})]).then(a,()=>navigator.clipboard.writeText(n.url).then(a,()=>y("Couldn\u2019t copy the link")))}catch{navigator.clipboard?.writeText(n.url).then(a,()=>y("Couldn\u2019t copy the link"))}}function ir(e){try{const t=new URL(String(e).trim());if(!/\/__loop\/?$/.test(t.pathname))return null;const n=new URLSearchParams(t.hash.slice(1));return n.get("f")?{f:n.get("f"),e:n.get("e"),n:n.get("n")}:null}catch{return null}}const aa=e=>{try{return D.get(e)?.iframe.contentDocument}catch{return null}};async function sr(){const e=ir(location.href);if(!e||!f)return;history.replaceState(null,"",location.pathname+location.search);const t=f.frames.find(n=>n.id===e.f);if(!t)return y("That frame is no longer on this canvas");if(S&&dt(),Z(t.id),Oe(!0,[t.id]),!!e.e){for(let n=0;n<40;n++){const a=aa(t.id)?.querySelector(e.e);if(a){Z(null),x={frameId:t.id,els:[a],scope:a.parentElement},Pe(),bt?.();return}await new Promise(i=>setTimeout(i,250))}y(`\u201C${e.n||"That element"}\u201D isn\u2019t on the page any more. Here is its frame.`,2600)}}addEventListener("hashchange",()=>sr());const Ja=new WeakMap;function or(e){e.addEventListener("paste",t=>{const n=ir(t.clipboardData?.getData("text/plain")||"");if(!n)return;const a=f.frames.find(l=>l.id===n.f);if(!a)return;t.preventDefault(),t.stopPropagation();const i=n.e?aa(a.id)?.querySelector(n.e):null,s=i?ta(i):null,o=(n.n||(i?Ye(i):a.name)).replace(/\s+/g," ").trim(),r={frameId:a.id,label:o,selector:n.e||void 0,tag:s?.tag,text:s?.text,html:s?.html||i?.outerHTML?.slice(0,3e3)};Ja.set(e,[...Ja.get(e)||[],r]);const c=`@${o}${n.e?` (${a.name})`:""}`;e.setRangeText(c+" ",e.selectionStart,e.selectionEnd,"end"),e.dispatchEvent(new Event("input"))})}function rr(e,t){const n=(Ja.get(e)||[]).filter(a=>t.includes(`@${a.label}`));return Ja.delete(e),n}const oe=document.createElement("div");oe.id="ctx",oe.hidden=!0,oe.setAttribute("role","menu"),document.body.appendChild(oe);let ia=[];const we={cmd:rt==="metaKey"?"\u2318":"Ctrl ",shift:"\u21E7"};function ei(e,t,n,a){ia=a.filter(Boolean);const i=ia.filter((r,c,l)=>!(r.sep&&(c===0||c===l.length-1||l[c-1].sep)));ia=i,oe.innerHTML=`${n?`<div class="cx-head">${n}</div>`:""}${i.map((r,c)=>r.sep?'<div class="cx-sep"></div>':`<button class="cx-item${r.danger?" danger":""}" data-i="${c}" role="menuitem"${r.disabled?" disabled":""}><span>${L(r.label)}</span>${r.keys?`<kbd>${L(r.keys)}</kbd>`:""}</button>`).join("")}`,oe.hidden=!1,oe.classList.remove("in"),oe.offsetWidth,oe.classList.add("in");const s=oe.offsetWidth,o=oe.offsetHeight;oe.style.left=`${Math.max(8,e+s+8>innerWidth?e-s:e)}px`,oe.style.top=`${Math.max(8,t+o+8>innerHeight?t-o:t)}px`,oe.style.transformOrigin=`${e+s+8>innerWidth?"right":"left"} ${t+o+8>innerHeight?"bottom":"top"}`,oe.querySelector(".cx-item:not([disabled])")?.focus({preventScroll:!0})}function vn(){oe.hidden||(oe.hidden=!0,ia=[])}oe.addEventListener("pointerdown",e=>e.stopPropagation()),oe.addEventListener("contextmenu",e=>e.preventDefault()),oe.addEventListener("click",e=>{const t=e.target.closest(".cx-item");if(!t||t.disabled)return;const n=ia[+t.dataset.i];vn(),n?.act()}),oe.addEventListener("pointermove",e=>{const t=e.target.closest(".cx-item:not([disabled])");t&&document.activeElement!==t&&t.focus({preventScroll:!0})}),oe.addEventListener("keydown",e=>{const t=[...oe.querySelectorAll(".cx-item:not([disabled])")],n=t.indexOf(document.activeElement);e.key==="ArrowDown"||e.key==="ArrowUp"?(e.preventDefault(),t[(n+(e.key==="ArrowDown"?1:-1)+t.length)%t.length]?.focus()):e.key==="Escape"?(e.preventDefault(),vn()):e.key==="Enter"&&(e.preventDefault(),document.activeElement?.click()),e.stopPropagation()}),addEventListener("pointerdown",e=>{oe.contains(e.target)||vn()},!0),addEventListener("blur",vn),addEventListener("resize",vn),I.addEventListener("wheel",vn,{passive:!0}),I.addEventListener("contextmenu",e=>{e.preventDefault(),lr(e.clientX,e.clientY,e.target)});function lr(e,t,n){if(!f)return;te?.(),is?.();const a=n?.closest?.(".frame"),i=a&&f.frames.find(r=>r.id===a.dataset.id);if(i&&n.closest(".frame-body")&&!a.classList.contains("empty")&&!n.closest(".pin")){const{lx:r,ly:c}=Ge(i.id,e,t),l=Me(i.id,r,c);let d=x?.frameId===i.id?x.els.find(u=>u===l||u.contains(l)):null;if(!d&&l&&l!==aa(i.id)?.documentElement&&l!==aa(i.id)?.body&&(Qt(i.id,{clientX:e,clientY:t,ctx:!0},"smart"),d=x?.frameId===i.id?x.els[x.els.length-1]:null),d)return Dc(i,d,e,t)}if(i)return Z(i.id),Ic(i,e,t);const s=n?.closest?.(".section"),o=s&&f.sections.find(r=>r.id===s.dataset.id);if(o)return zc(o,e,t);Oc(e,t)}function Dc(e,t,n,a){const i=$(),s=e.kind==="folder"&&!X,o=t.parentElement,r=t.ownerDocument,c=p=>{x={frameId:e.id,els:[p],scope:p.parentElement},Pe(),bt?.()},{lx:l,ly:d}=Ge(e.id,n,a);let u=Me(e.id,l,d);for(;u&&u.parentElement&&u.parentElement!==t;)u=u.parentElement;(u?.parentElement!==t||u===t)&&(u=null),ei(n,a,`<b>${L(Ye(t))}</b><span>${L(e.name)}</span>`,[{label:"Comment",keys:"C",act:()=>{c(t),ea()}},{label:"Copy link",keys:`${we.shift}${we.cmd}L`,act:()=>os(e.id,t)},{sep:1},i&&{label:"Copy",keys:`${we.cmd}C`,act:()=>{pe=na(e.id,t),Xe=null;try{navigator.clipboard?.write?.([new ClipboardItem({"text/html":new Blob([pe.html],{type:"text/html"}),"text/plain":new Blob([pe.html],{type:"text/plain"})})]).catch(()=>{})}catch{}y(`Copied \u201C${pe.name}\u201D \u2014 \u2318V to paste`,1600)}},i&&s&&pe&&{label:"Paste after it",keys:`${we.cmd}V`,act:()=>ti(pe,e.id,t)},i&&s&&{label:"Duplicate",keys:`${we.cmd}D`,act:()=>{c(t),pr()}},{sep:1},u&&{label:"Select inside",act:()=>c(u)},o&&o!==r.body&&o!==r.documentElement&&{label:"Select the box around it",act:()=>c(o)},{label:"Select its frame",act:()=>{Ve(),Z(e.id)}},i&&{sep:1},i&&(s?{label:"Delete",keys:"\u232B",danger:!0,act:()=>{c(t),ms()}}:{label:"Ask to remove it\u2026",act:()=>{c(t),ea(),W.value="Remove this.",ot(W),W.focus(),W.select()}})])}function Ic(e,t,n){const a=$(),i=["route","url","folder"].includes(e.kind)&&!e.image&&!e.sizeOf,s=D.get(e.id),o=s&&!s.count.hidden;ei(t,n,`<b>${L(e.name)}</b><span>${e.w} \xD7 ${e.h}</span>`,[a&&e.optionOf&&{label:"Use this option",act:()=>Hc(e)},a&&e.optionOf&&{sep:1},{label:"Open on stage",keys:"S",act:()=>vt(e.id)},{label:"Comment on the frame",act:()=>{const r=s.el.querySelector(".frame-body").getBoundingClientRect();st(e.id,24,24)}},{sep:1},{label:"Copy link",keys:`${we.shift}${we.cmd}L`,act:()=>os(e.id,null)},{label:"Copy as image",keys:`${we.shift}${we.cmd}C`,act:()=>ar(e.id)},a&&{label:"Copy",keys:`${we.cmd}C`,act:()=>{Xe=e.id,pe=null,y(`Copied \u201C${e.name}\u201D \u2014 \u2318V to paste`,1600)}},a&&{label:"Duplicate",keys:`${we.cmd}D`,act:()=>qn(e.id)},a&&(e.kind==="route"||e.kind==="url")&&{label:"Duplicate as an editable copy",act:()=>ud(e.id)},a&&e.draftOf&&{label:"Make it real in the app\u2026",act:()=>{Z(e.id),st(e.id,24,24),W.value="Build this into the app.",ot(W),W.focus(),W.select()}},a&&{sep:1},a&&{label:"Rename",act:()=>_i(e.id)},a&&i&&{label:"See it at other sizes",act:()=>Pr(e)},o&&{label:"Versions",act:()=>Ls(e.id)},a&&e.kind!=="frozen"&&{label:"Freeze a copy",keys:`${we.shift}F`,act:()=>ra(e.id)},a&&{sep:1},a&&(f.frames.some(r=>r.parent===e.id)||e.kind==="folder"&&!e.image)&&{label:"Unframe (keep what\u2019s inside)",keys:`${we.shift}${we.cmd}F`,act:()=>Jo(e.id)},a&&{label:"Delete",keys:"\u232B",danger:!0,act:()=>wr([e.id])}])}async function Hc(e){const t=e.optionOf;if(t)try{await w("POST",`/__loop/api/comments/${t.cid}/choose`,{option:t.oid}),y(t.live?"Now the real screen. The other options are gone.":"The original now has this option. Its old version is kept in its versions.",2600)}catch(n){y(n.message)}}function zc(e,t,n){const a=$(),i=an(e).length;a&&(ke=e.id,wt?.()),ei(t,n,`<b>${L(e.name)}</b><span>${i} frame${i===1?"":"s"}</span>`,[{label:"Fit to the section",act:()=>Oe(!0,an(e).map(s=>s.id).concat([]))},a&&{label:"Rename",act:()=>Rr(e.id)},a&&{sep:1},a&&{label:i?"Unsection (keep the frames)":"Delete section",keys:`${we.shift}${we.cmd}S`,act:()=>bi(e.id)},a&&i&&{label:`Delete section and its ${i} frame${i===1?"":"s"}`,danger:!0,act:()=>Or(e.id)}])}function Oc(e,t){const n=$(),a=re(e,t);ei(e,t,"",[n&&(Xe||pe)&&{label:"Paste here",keys:`${we.cmd}V`,act:()=>{Xe&&f.frames.find(i=>i.id===Xe)?qn(Xe,{x:Math.round(a.x),y:Math.round(a.y)}):pe&&Qa(pe,a.x,a.y)}},n&&{label:"New frame here",act:()=>bn("Frame",1440,1024,a.x,a.y)},{label:"Comment here",act:()=>st(le,a.x,a.y,"canvas")},{sep:1},{label:"Fit everything",keys:`${we.shift}1`,act:()=>Oe(!0)},n&&!X&&{label:"Canvas history",act:()=>Kr(!0)},{label:"Keyboard shortcuts",keys:"?",act:()=>Ms(!0)}])}const cr=/^image\/(png|jpeg|gif|webp|svg\+xml)$/;function rs(e,t){return new Promise((n,a)=>{const i=new FileReader;i.onload=()=>n(i.result),i.onerror=a,i[t](e)})}function dr(e){return new Promise(t=>{const n=new Image;n.onload=()=>t([n.naturalWidth||800,n.naturalHeight||600]),n.onerror=()=>t([800,600]),n.src=e})}function Rc(e,t,n=0){const i=e>0&&t>0&&e<innerWidth&&t<innerHeight?re(e,t):re(innerWidth/2,innerHeight/2);return{x:Math.round(i.x+n*40),y:Math.round(i.y+n*40)}}async function ls(e,t,n,a=!1){if(!$())return y("Only the host can add frames");let i=0,s=0;for(const o of e){const r=Rc(t,n,s),c=(l,d)=>a&&f.frames.some(p=>r.x<p.x+p.w+40&&r.x+l+40>p.x&&r.y<p.y+p.h+40&&r.y+d+40>p.y)?ts(l,d,{x:r.x+l/2,y:r.y+d/2}):r;try{let l=null;if(o.file&&cr.test(o.file.type)){if(o.file.size>12e6){y("That image is too big (over 12 MB)");continue}const u=await rs(o.file,"readAsDataURL");let[p,h]=await dr(u);(/^Screen ?Shot|^Screenshot|^image\.png$/i.test(o.file.name||"")||p>1800)&&p>600&&(p=Math.round(p/2),h=Math.round(h/2));const v=Math.min(1,2400/Math.max(p,h));p=Math.round(p*v),h=Math.round(h*v),l=await w("POST","/__loop/api/frames",{image:u,name:o.file.name&&!/^image\.png$/i.test(o.file.name)?o.file.name:"Image",w:p,h,...c(p,h)})}else if(o.file&&/\.html?$/i.test(o.file.name)){const u=await rs(o.file,"readAsText");l=await w("POST","/__loop/api/frames",{new:!0,name:Un(o.file.name.replace(/\.html?$/i,"")),html:u,w:1280,h:800,...c(1280,800)})}else if(o.imageUrl){let[u,p]=await dr(o.imageUrl);const h=Math.min(1,2400/Math.max(u,p));u=Math.round(u*h),p=Math.round(p*h),l=await w("POST","/__loop/api/frames",{imageUrl:o.imageUrl,name:decodeURIComponent(o.imageUrl.split(/[?#]/)[0].split("/").pop()||"Image"),w:u,h:p,...c(u,p)})}else if(o.url&&!Nc(o.url)&&!o.live){const u=await Fc(o.url,t,n);if(!u)continue;if(u==="rebuild"){const p=c(1440,1024);l=await w("POST","/__loop/api/frames",{prompt:Bc(o.url),source:o.url,name:Un(`${cs(o.url)} (rebuilt)`),w:1440,h:1024,...p})}else l=await w("POST","/__loop/api/frames",{src:o.url,name:o.url.replace(/^https?:\/\//,"").replace(/\/$/,"").slice(0,60),w:1280,h:800,...c(1280,800)})}else if(o.url)l=await w("POST","/__loop/api/frames",{src:o.url,name:o.url.replace(/^https?:\/\//,"").replace(/\/$/,"").slice(0,60),w:1280,h:800,...c(1280,800)});else if(o.file){y(`${o.file.name} can't be put on the canvas (images and HTML files can)`);continue}if(!l)continue;let d=null;G("Add frame",async()=>{d=yt(l.id)||d,await w("DELETE",`/__loop/api/frames/${l.id}`)},()=>He(d||{frames:[l]})),Ue=l.id,i++,s++}catch(l){y(l.message)}}return i}const Nc=e=>{try{return/^(localhost|127\.0\.0\.1|\[::1\])$/.test(new URL(e).hostname)}catch{return!1}},cs=e=>{try{const t=new URL(e);return(t.hostname.replace(/^www\./,"")+(t.pathname.length>1?" \xB7 "+t.pathname.replace(/\/$/,"").split("/").slice(-1)[0].replace(/[-_]+/g," ").replace(/\?.*$/,""):"")).slice(0,40)}catch{return"Page"}},Bc=e=>`Rebuild the design at ${e} as this frame's page, as close to the original as you can.
|
|
66
|
+
`;async function ys(e,t,n){return Ud(e,t,n)}function jr(e){const t=f.frames.find(a=>a.id===e);if(!t)return;y("Copying a picture of the frame\u2026",4e3);const n=x("POST",`/__loop/api/frames/${e}/shot`).then(a=>fetch(`/__loop/shots/${a.path.split("/").pop()}`)).then(a=>{if(!a.ok)throw new Error("No picture");return a.blob()}).then(a=>a.type==="image/png"?a:new Blob([a],{type:"image/png"}));try{navigator.clipboard.write([new ClipboardItem({"image/png":n})]).then(()=>y(`Copied \u201C${t.name}\u201D as an image`,1800),a=>y(`Couldn\u2019t copy the picture (${a.message||a.name})`))}catch(a){y(`Couldn\u2019t copy the picture (${a.message})`)}}function Id(e){const t=e.ownerDocument,n=[];for(let a=e;a&&a.nodeType===1&&a!==t.documentElement;a=a.parentElement){if(a.id&&/^[A-Za-z][\w-]*$/.test(a.id)&&t.querySelectorAll(`#${a.id}`).length===1){n.unshift(`#${a.id}`);break}if(a.tagName==="BODY"){n.unshift("body");break}const s=a.parentElement?[...a.parentElement.children].filter(i=>i.tagName===a.tagName):[];n.unshift(a.tagName.toLowerCase()+(s.length>1?`:nth-of-type(${s.indexOf(a)+1})`:""))}return n.join(" > ")}function zd(e,t){const n=f.frames.find(i=>i.id===e);if(!n)return null;const a=(f.publicLink||`${location.origin}/__loop/`).split("#")[0],s=t?Ke(t):n.name;return{url:`${a}#f=${encodeURIComponent(e)}${t?`&e=${encodeURIComponent(Id(t))}`:""}&n=${encodeURIComponent(s)}`,label:s,frame:n.name}}function Ni(e,t){const n=zd(e,t);if(!n)return;const a=()=>y(`Copied a link to \u201C${n.label}\u201D${t?` in ${n.frame}`:""}. Paste it in a comment to point at it.`,2400);try{navigator.clipboard.write([new ClipboardItem({"text/plain":new Blob([n.url],{type:"text/plain"})})]).then(a,()=>navigator.clipboard.writeText(n.url).then(a,()=>y("Couldn\u2019t copy the link")))}catch{navigator.clipboard?.writeText(n.url).then(a,()=>y("Couldn\u2019t copy the link"))}}function Yr(e){try{const t=new URL(String(e).trim());if(!/\/__loop\/?$/.test(t.pathname))return null;const n=new URLSearchParams(t.hash.slice(1));return n.get("f")?{f:n.get("f"),e:n.get("e"),n:n.get("n")}:null}catch{return null}}const ga=e=>{try{return P.get(e)?.iframe.contentDocument}catch{return null}};async function Kr(){const e=Yr(location.href);if(!e||!f)return;history.replaceState(null,"",location.pathname+location.search);const t=f.frames.find(n=>n.id===e.f);if(!t)return y("That frame is no longer on this canvas");if(S&>(),Q(t.id),Oe(!0,[t.id]),!!e.e){for(let n=0;n<40;n++){const a=ga(t.id)?.querySelector(e.e);if(a){Q(null),L={frameId:t.id,els:[a],scope:a.parentElement},Pe(),Mt?.();return}await new Promise(s=>setTimeout(s,250))}y(`\u201C${e.n||"That element"}\u201D isn\u2019t on the page any more. Here is its frame.`,2600)}}addEventListener("hashchange",()=>Kr());const bs=new WeakMap;function Vr(e){e.addEventListener("paste",t=>{const n=Yr(t.clipboardData?.getData("text/plain")||"");if(!n)return;const a=f.frames.find(c=>c.id===n.f);if(!a)return;t.preventDefault(),t.stopPropagation();const s=n.e?ga(a.id)?.querySelector(n.e):null,i=s?ma(s):null,o=(n.n||(s?Ke(s):a.name)).replace(/\s+/g," ").trim(),r={frameId:a.id,label:o,selector:n.e||void 0,tag:i?.tag,text:i?.text,html:i?.html||s?.outerHTML?.slice(0,3e3)};bs.set(e,[...bs.get(e)||[],r]);const l=`@${o}${n.e?` (${a.name})`:""}`;e.setRangeText(l+" ",e.selectionStart,e.selectionEnd,"end"),e.dispatchEvent(new Event("input"))})}function Ur(e,t){const n=(bs.get(e)||[]).filter(a=>t.includes(`@${a.label}`));return bs.delete(e),n}const ce=document.createElement("div");ce.id="ctx",ce.hidden=!0,ce.setAttribute("role","menu"),document.body.appendChild(ce);let ya=[];const de={cmd:pt==="metaKey"?"\u2318":"Ctrl ",shift:"\u21E7"};function vs(e,t,n,a){ya=a.filter(Boolean);const s=ya.filter((r,l,c)=>!(r.sep&&(l===0||l===c.length-1||c[l-1].sep)));ya=s,ce.innerHTML=`${n?`<div class="cx-head">${n}</div>`:""}${s.map((r,l)=>r.sep?'<div class="cx-sep"></div>':`<button class="cx-item${r.danger?" danger":""}" data-i="${l}" role="menuitem"${r.disabled?" disabled":""}><span>${C(r.label)}</span>${r.keys?`<kbd>${C(r.keys)}</kbd>`:""}</button>`).join("")}`,ce.hidden=!1,ce.classList.remove("in"),ce.offsetWidth,ce.classList.add("in");const i=ce.offsetWidth,o=ce.offsetHeight;ce.style.left=`${Math.max(8,e+i+8>innerWidth?e-i:e)}px`,ce.style.top=`${Math.max(8,t+o+8>innerHeight?t-o:t)}px`,ce.style.transformOrigin=`${e+i+8>innerWidth?"right":"left"} ${t+o+8>innerHeight?"bottom":"top"}`,ce.querySelector(".cx-item:not([disabled])")?.focus({preventScroll:!0})}function Gt(){ce.hidden||(ce.hidden=!0,ya=[])}ce.addEventListener("pointerdown",e=>e.stopPropagation()),ce.addEventListener("contextmenu",e=>e.preventDefault()),ce.addEventListener("click",e=>{const t=e.target.closest(".cx-item");if(!t||t.disabled)return;const n=ya[+t.dataset.i];Gt(),n?.act()}),ce.addEventListener("pointermove",e=>{const t=e.target.closest(".cx-item:not([disabled])");t&&document.activeElement!==t&&t.focus({preventScroll:!0})}),ce.addEventListener("keydown",e=>{const t=[...ce.querySelectorAll(".cx-item:not([disabled])")],n=t.indexOf(document.activeElement);e.key==="ArrowDown"||e.key==="ArrowUp"?(e.preventDefault(),t[(n+(e.key==="ArrowDown"?1:-1)+t.length)%t.length]?.focus()):e.key==="Escape"?(e.preventDefault(),Gt()):e.key==="Enter"&&(e.preventDefault(),document.activeElement?.click()),e.stopPropagation()}),addEventListener("pointerdown",e=>{ce.contains(e.target)||Gt()},!0),addEventListener("blur",Gt),addEventListener("resize",Gt),q.addEventListener("wheel",Gt,{passive:!0}),q.addEventListener("contextmenu",e=>{e.preventDefault(),Xr(e.clientX,e.clientY,e.target)});function Xr(e,t,n){if(!f)return;ae?.(),Oi?.();const a=n?.closest?.(".frame"),s=a&&f.frames.find(r=>r.id===a.dataset.id);if(s&&n.closest(".frame-body")&&!a.classList.contains("empty")&&!n.closest(".pin")){const{lx:r,ly:l}=Qe(s.id,e,t),c=Se(s.id,r,l);let d=L?.frameId===s.id?L.els.find(u=>u===c||u.contains(c)):null;if(!d&&c&&c!==ga(s.id)?.documentElement&&c!==ga(s.id)?.body&&(ln(s.id,{clientX:e,clientY:t,ctx:!0},"smart"),d=L?.frameId===s.id?L.els[L.els.length-1]:null),d)return Hd(s,d,e,t)}if(s)return Q(s.id),Od(s,e,t);const i=n?.closest?.(".section"),o=i&&f.sections.find(r=>r.id===i.dataset.id);if(o)return Nd(o,e,t);Bd(e,t)}function Hd(e,t,n,a){const s=k(),i=e.kind==="folder"&&!X,o=t.parentElement,r=t.ownerDocument,l=p=>{L={frameId:e.id,els:[p],scope:p.parentElement},Pe(),Mt?.()},{lx:c,ly:d}=Qe(e.id,n,a);let u=Se(e.id,c,d);for(;u&&u.parentElement&&u.parentElement!==t;)u=u.parentElement;(u?.parentElement!==t||u===t)&&(u=null),vs(n,a,`<b>${C(Ke(t))}</b><span>${C(e.name)}</span>`,[{label:"Comment",keys:"C",act:()=>{l(t),pa()}},{label:"Copy link",keys:`${de.shift}${de.cmd}L`,act:()=>Ni(e.id,t)},{sep:1},s&&{label:"Copy",keys:`${de.cmd}C`,act:()=>{ge=ha(e.id,t),Ge=null;try{navigator.clipboard?.write?.([new ClipboardItem({"text/html":new Blob([ge.html],{type:"text/html"}),"text/plain":new Blob([ge.html],{type:"text/plain"})})]).catch(()=>{})}catch{}y(`Copied \u201C${ge.name}\u201D \u2014 \u2318V to paste`,1600)}},s&&i&&ge&&{label:"Paste after it",keys:`${de.cmd}V`,act:()=>ws(ge,e.id,t)},s&&i&&{label:"Duplicate",keys:`${de.cmd}D`,act:()=>{l(t),el()}},{sep:1},u&&{label:"Select inside",act:()=>l(u)},o&&o!==r.body&&o!==r.documentElement&&{label:"Select the box around it",act:()=>l(o)},{label:"Select its frame",act:()=>{Ve(),Q(e.id)}},s&&{sep:1},s&&(i?{label:"Delete",keys:"\u232B",danger:!0,act:()=>{l(t),Ui()}}:{label:"Ask to remove it\u2026",act:()=>{l(t),pa(),j.value="Remove this.",ut(j),j.focus(),j.select()}})])}function Od(e,t,n){const a=k(),s=["route","url","folder"].includes(e.kind)&&!e.image&&!e.sizeOf,i=P.get(e.id),o=i&&!i.count.hidden;vs(t,n,`<b>${C(e.name)}</b><span>${e.w} \xD7 ${e.h}</span>`,[a&&e.optionOf&&{label:"Use this option",act:()=>Rd(e)},a&&e.optionOf&&{sep:1},a&&Pa(e)&&{label:"Build into project\u2026",keys:`${de.shift}${de.cmd}B`,act:()=>Vs(W.size>1&&W.has(e.id)?[...W]:[e.id])},{label:"Open on stage",keys:"S",act:()=>ht(e.id)},{label:"Comment on the frame",act:()=>{const r=i.el.querySelector(".frame-body").getBoundingClientRect();et(e.id,24,24)}},{sep:1},{label:"Copy link",keys:`${de.shift}${de.cmd}L`,act:()=>Ni(e.id,null)},{label:"Copy as image",keys:`${de.shift}${de.cmd}C`,act:()=>jr(e.id)},a&&{label:"Copy",keys:`${de.cmd}C`,act:()=>{Ge=e.id,ge=null,y(`Copied \u201C${e.name}\u201D \u2014 \u2318V to paste`,1600)}},a&&{label:"Duplicate",keys:`${de.cmd}D`,act:()=>jn(e.id)},a&&(e.kind==="route"||e.kind==="url")&&{label:"Duplicate as an editable copy",act:()=>gf(e.id)},a&&e.draftOf&&{label:"Make it real in the app\u2026",act:()=>{Q(e.id),et(e.id,24,24),j.value="Build this into the app.",ut(j),j.focus(),j.select()}},a&&{sep:1},a&&{label:"Rename",act:()=>ri(e.id)},a&&s&&{label:"See it at other sizes",act:()=>xl(e)},o&&{label:"Versions",act:()=>ro(e.id)},a&&e.kind!=="frozen"&&{label:"Freeze a copy",keys:`${de.shift}F`,act:()=>wa(e.id)},a&&{sep:1},a&&(f.frames.some(r=>r.parent===e.id)||e.kind==="folder"&&!e.image)&&{label:"Unframe (keep what\u2019s inside)",keys:`${de.shift}${de.cmd}F`,act:()=>Nr(e.id)},a&&{label:"Delete",keys:"\u232B",danger:!0,act:()=>rl([e.id])}])}async function Rd(e){const t=e.optionOf;if(t)try{await x("POST",`/__loop/api/comments/${t.cid}/choose`,{option:t.oid}),y(t.live?"Now the real screen. The other options are gone.":"The original now has this option. Its old version is kept in its versions.",2600)}catch(n){y(n.message)}}function Nd(e,t,n){const a=k(),s=Bt(e).length;a&&(ye=e.id,yt?.()),vs(t,n,`<b>${C(e.name)}</b><span>${s} frame${s===1?"":"s"}</span>`,[{label:"Fit to the section",act:()=>Oe(!0,Bt(e).map(i=>i.id).concat([]))},a&&{label:"Rename",act:()=>zl(e.id)},a&&{sep:1},a&&{label:s?"Unsection (keep the frames)":"Delete section",keys:`${de.shift}${de.cmd}S`,act:()=>Fs(e.id)},a&&s&&{label:`Delete section and its ${s} frame${s===1?"":"s"}`,danger:!0,act:()=>Il(e.id)}])}function Bd(e,t){const n=k(),a=fe(e,t);vs(e,t,"",[n&&(Ge||ge)&&{label:"Paste here",keys:`${de.cmd}V`,act:()=>{Ge&&f.frames.find(s=>s.id===Ge)?jn(Ge,{x:Math.round(a.x),y:Math.round(a.y)}):ge&&ys(ge,a.x,a.y)}},n&&{label:"New frame here",act:()=>Tn("Frame",1440,1024,a.x,a.y)},{label:"Comment here",act:()=>et(le,a.x,a.y,"canvas")},{sep:1},{label:"Fit everything",keys:`${de.shift}1`,act:()=>Oe(!0)},n&&!X&&{label:"Canvas history",act:()=>Fl(!0)},{label:"Keyboard shortcuts",keys:"?",act:()=>Ys(!0)}])}const Gr=/^image\/(png|jpeg|gif|webp|svg\+xml)$/;function Bi(e,t){return new Promise((n,a)=>{const s=new FileReader;s.onload=()=>n(s.result),s.onerror=a,s[t](e)})}function Zr(e){return new Promise(t=>{const n=new Image;n.onload=()=>t([n.naturalWidth||800,n.naturalHeight||600]),n.onerror=()=>t([800,600]),n.src=e})}function Fd(e,t,n=0){const s=e>0&&t>0&&e<innerWidth&&t<innerHeight?fe(e,t):fe(innerWidth/2,innerHeight/2);return{x:Math.round(s.x+n*40),y:Math.round(s.y+n*40)}}async function Fi(e,t,n,a=!1){if(!k())return y("Only the host can add frames");let s=0,i=0;for(const o of e){const r=Fd(t,n,i),l=(c,d)=>a&&f.frames.some(p=>r.x<p.x+p.w+40&&r.x+c+40>p.x&&r.y<p.y+p.h+40&&r.y+d+40>p.y)?Ii(c,d,{x:r.x+c/2,y:r.y+d/2}):r;try{let c=null;if(o.file&&Gr.test(o.file.type)){if(o.file.size>12e6){y("That image is too big (over 12 MB)");continue}const u=await Bi(o.file,"readAsDataURL");let[p,h]=await Zr(u);(/^Screen ?Shot|^Screenshot|^image\.png$/i.test(o.file.name||"")||p>1800)&&p>600&&(p=Math.round(p/2),h=Math.round(h/2));const w=Math.min(1,2400/Math.max(p,h));p=Math.round(p*w),h=Math.round(h*w),c=await x("POST","/__loop/api/frames",{image:u,name:o.file.name&&!/^image\.png$/i.test(o.file.name)?o.file.name:"Image",w:p,h,...l(p,h)})}else if(o.file&&/\.html?$/i.test(o.file.name)){const u=await Bi(o.file,"readAsText");c=await x("POST","/__loop/api/frames",{new:!0,name:la(o.file.name.replace(/\.html?$/i,"")),html:u,w:1280,h:800,...l(1280,800)})}else if(o.imageUrl){let[u,p]=await Zr(o.imageUrl);const h=Math.min(1,2400/Math.max(u,p));u=Math.round(u*h),p=Math.round(p*h),c=await x("POST","/__loop/api/frames",{imageUrl:o.imageUrl,name:decodeURIComponent(o.imageUrl.split(/[?#]/)[0].split("/").pop()||"Image"),w:u,h:p,...l(u,p)})}else if(o.url&&!Wd(o.url)&&!o.live){const u=await Yd(o.url,t,n);if(!u)continue;if(u==="rebuild"){const p=l(1440,1024);c=await x("POST","/__loop/api/frames",{prompt:jd(o.url),source:o.url,name:la(`${Wi(o.url)} (rebuilt)`),w:1440,h:1024,shapeless:!0,...p})}else c=await x("POST","/__loop/api/frames",{src:o.url,name:o.url.replace(/^https?:\/\//,"").replace(/\/$/,"").slice(0,60),w:1280,h:800,...l(1280,800)})}else if(o.url)c=await x("POST","/__loop/api/frames",{src:o.url,name:o.url.replace(/^https?:\/\//,"").replace(/\/$/,"").slice(0,60),w:1280,h:800,...l(1280,800)});else if(o.file){y(`${o.file.name} can't be put on the canvas (images and HTML files can)`);continue}if(!c)continue;let d=null;J("Add frame",async()=>{d=Ct(c.id)||d,await x("DELETE",`/__loop/api/frames/${c.id}`)},()=>ze(d||{frames:[c]})),Ze=c.id,s++,i++}catch(c){y(c.message)}}return s}const Wd=e=>{try{return/^(localhost|127\.0\.0\.1|\[::1\])$/.test(new URL(e).hostname)}catch{return!1}},Wi=e=>{try{const t=new URL(e);return(t.hostname.replace(/^www\./,"")+(t.pathname.length>1?" \xB7 "+t.pathname.replace(/\/$/,"").split("/").slice(-1)[0].replace(/[-_]+/g," ").replace(/\?.*$/,""):"")).slice(0,40)}catch{return"Page"}},jd=e=>`Rebuild the design at ${e} as this frame's page, as close to the original as you can.
|
|
66
67
|
If it is a link to a file in a design tool and you have a tool or connector that can read that file, read the file's structure (layout and spacing, text and its styles, colours, effects, components and their variants, variables, images and icons) rather than working from a picture of it; otherwise work from what you can see at the address.
|
|
67
|
-
|
|
68
|
-
|
|
68
|
+
First of all, before you write anything, find the original's size and set this frame to it with the size command in your instructions (it has no shape on the canvas until you do; if the original has no fixed size, use the device size it was designed for).
|
|
69
|
+
Use the real text. Use the original's colours, type and spacing exactly.
|
|
70
|
+
When it is built, compare your page with the original (a render of it, or the page itself) and fix every difference you can see; repeat until they match.`;function Yd(e,t,n){return new Promise(a=>{document.querySelector("#url-ask")?.remove();const s=document.createElement("div");s.id="url-ask",s.innerHTML=`<div class="ua-host">${C(Wi(e))}</div>
|
|
69
71
|
<button data-how="live" class="ua-opt"><b>Show it live</b><span>The site itself, as it is now</span><kbd>\u21B5</kbd></button>
|
|
70
|
-
<button data-how="rebuild" class="ua-opt"><b>Rebuild it as a page</b><span>The agent recreates it here, so you can comment on it and change it</span><kbd>R</kbd></button>`,document.body.appendChild(
|
|
71
|
-
`).map(
|
|
72
|
-
${e.html}`}],`Paste \u201C${e.name}\u201D`),y(`Pasted \u201C${e.name}\u201D into ${a.name}`,1600),!0}catch(
|
|
73
|
-
`,g-1)+1
|
|
74
|
-
`,
|
|
72
|
+
<button data-how="rebuild" class="ua-opt"><b>Rebuild it as a page</b><span>The agent recreates it here, so you can comment on it and change it</span><kbd>R</kbd></button>`,document.body.appendChild(s);const i=t>0&&t<innerWidth?t:innerWidth/2,o=n>0&&n<innerHeight?n:innerHeight/2;s.style.left=`${Math.max(12,Math.min(innerWidth-312,i-20))}px`,s.style.top=`${Math.max(60,Math.min(innerHeight-200,o+12))}px`;const r=d=>{removeEventListener("keydown",l,!0),removeEventListener("pointerdown",c,!0),s.remove(),a(d)},l=d=>{d.key==="Escape"?(d.preventDefault(),d.stopPropagation(),r(null)):d.key==="Enter"?(d.preventDefault(),d.stopPropagation(),r(s.querySelector('[data-how="live"]').disabled?"rebuild":"live")):d.key.toLowerCase()==="r"&&(d.preventDefault(),d.stopPropagation(),r("rebuild"))},c=d=>{s.contains(d.target)||r(null)};addEventListener("keydown",l,!0),setTimeout(()=>addEventListener("pointerdown",c,!0),0),s.addEventListener("click",d=>{const u=d.target.closest("[data-how]");u&&!u.disabled&&r(u.dataset.how)}),x("POST","/__loop/api/probe-url",{url:e}).then(d=>{if(d.embeddable||!s.isConnected)return;const u=s.querySelector('[data-how="live"]');u.disabled=!0,u.querySelector("span").textContent=d.blocked?"This site doesn\u2019t allow being shown inside other pages":"This address didn\u2019t open (it may need you to sign in)",s.querySelector('[data-how="rebuild"]').classList.add("first")}).catch(()=>{})})}const Kd=e=>/^https?:\/\/[^\s]+$/i.test(e)&&e.length<2e3,Jr=e=>/\.(png|jpe?g|gif|webp|svg)(\?|#|$)/i.test(e);addEventListener("blur",()=>{Ge=null,ge=null}),document.addEventListener("paste",e=>{if(It()||!f||!k())return;const t=[...e.clipboardData?.files||[]],n=(e.clipboardData?.getData("text/plain")||"").trim();if(t.length){e.preventDefault(),Fi(t.map(a=>({file:a})),je.x,je.y,!0);return}Kd(n)&&(e.preventDefault(),Fi([Jr(n)?{imageUrl:n}:{url:n}],je.x,je.y,!0))});let An=null;function Qr(e,t){const n=[...P.values()].find(o=>{const r=o.el.querySelector(".frame-body")?.getBoundingClientRect();return r&&e>=r.left&&e<=r.right&&t>=r.top&&t<=r.bottom}),a=n&&f.frames.find(o=>o.id===n.id);if(!a||a.kind!=="folder"||a.image||!k())return null;const{lx:s,ly:i}=Qe(a.id,e,t);for(let o=Se(a.id,s,i),r=0;o&&r<4;o=o.parentElement,r++){if(o.tagName==="IMG")return{fid:a.id,el:o,kind:"img"};try{if(/url\(/.test(o.ownerDocument.defaultView.getComputedStyle(o).backgroundImage))return{fid:a.id,el:o,kind:"bg"}}catch{}if(/^(BODY|HTML)$/.test(o.tagName))break}return null}function ji(e){if(!e){G.hidden=!0,q.classList.remove("swapping");return}const t=P.get(e.fid).iframe.getBoundingClientRect(),n=e.el.getBoundingClientRect(),a=v.z;Object.assign(G.style,{left:`${t.left+n.left*a}px`,top:`${t.top+n.top*a}px`,width:`${n.width*a}px`,height:`${n.height*a}px`}),G.dataset.tag="Replace image",G.innerHTML="",G._k=null,G.classList.remove("sel"),G.hidden=!1,q.classList.add("swapping")}async function Vd(e,t){if(!Gr.test(t.type))return y("Drop an image file (PNG, JPEG, GIF, WebP or SVG)");try{const n=await We(e.fid,e.el);if(!n)return y("This picture is drawn by the page\u2019s script, so it can\u2019t be swapped by hand. Ask the agent instead.");const{path:a}=await x("POST",`/__loop/api/frames/${e.fid}/asset`,{image:await Bi(t,"readAsDataURL"),name:t.name}),{src:s,N:i}=n;let o;if(e.kind==="img"){const r=i.attrs.find(d=>d.name==="src");o=r&&r.va>=0?{a:r.va,b:r.vb,before:s.slice(r.va,r.vb),text:a}:r?{a:r.a,b:r.b,before:s.slice(r.a,r.b),text:`src="${a}"`}:(()=>{const d=s[i.openEnd-2]==="/"?i.openEnd-2:i.openEnd-1;return{a:d,b:d,before:"",text:` src="${a}"`}})();const l=i.attrs.find(d=>d.name==="srcset"),c=[o];l&&c.push({a:l.a-(s[l.a-1]===" "?1:0),b:l.b,before:s.slice(l.a-(s[l.a-1]===" "?1:0),l.b),text:""}),await mt(e.fid,c,"Replace image")}else await mt(e.fid,[Ki(s,i,{"background-image":`url('${a}')`})],"Replace image");y("Image replaced",1400)}catch(n){y(n.message)}}q.addEventListener("dragover",e=>{const t=[...e.dataTransfer?.types||[]];!t.includes("Files")&&!t.includes("text/uri-list")||(e.preventDefault(),e.dataTransfer.dropEffect="copy",An=t.includes("Files")?Qr(e.clientX,e.clientY):null,ji(An),q.classList.toggle("dropping",!An))}),q.addEventListener("dragleave",e=>{(!e.relatedTarget||!q.contains(e.relatedTarget))&&(q.classList.remove("dropping"),An=null,ji(null))}),q.addEventListener("drop",e=>{q.classList.remove("dropping");const t=An||([...e.dataTransfer?.files||[]].length===1?Qr(e.clientX,e.clientY):null);if(An=null,ji(null),t&&e.dataTransfer.files.length===1){e.preventDefault(),Vd(t,e.dataTransfer.files[0]);return}const n=[...e.dataTransfer?.files||[]],a=(e.dataTransfer?.getData("text/uri-list")||"").split(`
|
|
73
|
+
`).map(s=>s.trim()).find(s=>s&&!s.startsWith("#"));!n.length&&!a||(e.preventDefault(),Fi(n.length?n.map(s=>({file:s})):[Jr(a)||(e.dataTransfer.types||[]).includes("Files")?{imageUrl:a}:{url:a}],e.clientX,e.clientY))});async function Ud(e,t,n){try{const a=await x("POST","/__loop/api/frames",{new:!0,name:la(e.name||"Element"),w:e.w,h:e.h,x:Math.round(t),y:Math.round(n),html:Wr(e),fill:"none"});let s=null;return J("Copy element",async()=>{s=Ct(a.id)||s,await x("DELETE",`/__loop/api/frames/${a.id}`)},()=>ze(s||{frames:[a]})),Ze=a.id,y(`Copied \u201C${e.name}\u201D to its own frame`,1600),!0}catch(a){y(a.message)}}async function ws(e,t,n){const a=f.frames.find(l=>l.id===t);if(!a||a.kind!=="folder")return y("Elements can be pasted into static frames. For an app screen, ask the agent.");const s=ue(t),i=n&&n!==s?.documentElement?n:s?.body,o=i&&await We(t,i);if(!o)return y("Couldn\u2019t find that spot in the page\u2019s file. Try selecting another element first.");const r=i===s.body?o.N.innerB??o.N.b:o.N.b;try{return await mt(t,[{a:r,b:r,before:"",text:`
|
|
74
|
+
${e.html}`}],`Paste \u201C${e.name}\u201D`),y(`Pasted \u201C${e.name}\u201D into ${a.name}`,1600),!0}catch(l){y(l.message)}}let ge=null;async function mt(e,t,n){await x("POST",`/__loop/api/frames/${e}/edit`,{edits:t,what:n});let a=0;const s=[...t].sort((i,o)=>i.a-o.a).map(i=>{const o={a:i.a+a,b:i.a+a+i.text.length,before:i.text,text:i.before};return a+=i.text.length-(i.b-i.a),o});J(n,()=>x("POST",`/__loop/api/frames/${e}/edit`,{edits:s,what:`Undo: ${n}`}),()=>x("POST",`/__loop/api/frames/${e}/edit`,{edits:t,what:n}))}const Yi=e=>!/^(SCRIPT|STYLE|TEMPLATE|BR|LINK|META)$/.test(e.tagName)&&e.getBoundingClientRect().width>0;function ba(e){const t=P.get(e);t&&(t.quietN=(t.quietN||0)+1,t.quietT=Date.now()+2500)}function Ki(e,t,n){const a=t.attrs.find(r=>r.name==="style"),s=new Map;for(const r of(a?.value||"").split(";")){const l=r.indexOf(":");l>0&&s.set(r.slice(0,l).trim().toLowerCase(),r.slice(l+1).trim())}for(const[r,l]of Object.entries(n))s.set(r,l);const i=[...s].map(([r,l])=>`${r}: ${l}`).join("; ").replace(/"/g,"'");if(a&&a.va>=0&&a.q)return{a:a.va,b:a.vb,before:e.slice(a.va,a.vb),text:a.q==='"'?i:i.replace(/'/g,'"')};if(a)return{a:a.a,b:a.b,before:e.slice(a.a,a.b),text:`style="${i}"`};const o=e[t.openEnd-2]==="/"?t.openEnd-2:t.openEnd-1;return{a:o,b:o,before:"",text:` style="${i}"`}}async function Xd(e){const{fid:t,el:n}=e,a=n.parentElement,s=()=>{e.base==null?n.removeAttribute("style"):n.setAttribute("style",e.base),e.pbase==null?a.removeAttribute("style"):a.setAttribute("style",e.pbase),Pe(),Zt()};try{const i=await We(t,n),o=i&&Object.keys(e.pprops).length?await We(t,a):null;if(!i||Object.keys(e.pprops).length&&!o){s(),y("This one can\u2019t be placed by hand (its page is a live app, or its own script draws it). Ask for it in a comment.",3200);return}const r=[Ki(i.src,i.N,e.props)];o&&r.push(Ki(i.src,o.N,e.pprops)),ba(t),await mt(t,r,`Place ${Ke(n)}`),Pe(),Mt()}catch(i){s(),y(i.message)}}async function Gd(e,t,n,a){if(Ht)return;const s=[...n.children].filter(Yi).filter(o=>o!==t),i=a||s[s.length-1]||null;Ht=!0;try{const o=await We(e,t),r=o&&await We(e,i||n);if(!o||!r){y("This one can\u2019t be moved by hand (its page is a live app, or its own script draws it). Ask for the move in a comment.",3200);return}const l=o.src,c=l.slice(o.N.a,o.N.b),d=(g,w)=>{const T=l.lastIndexOf(`
|
|
75
|
+
`,g-1)+1,$=l.indexOf(`
|
|
76
|
+
`,w),b=$<0?l.length:$,M=/^[ \t]*$/.test(l.slice(T,g))&&/^[ \t]*$/.test(l.slice(w,b));return M?{a:T,b:$<0?l.length:$+1,indent:l.slice(T,g),own:M}:{a:g,b:w,indent:"",own:M}},u=d(o.N.a,o.N.b);let p,h;if(i){const g=d(r.N.a,r.N.b);p=a?g.a:g.b,h=g.own?p>0&&l[p-1]!==`
|
|
75
77
|
`?`
|
|
76
|
-
${g.indent}${
|
|
77
|
-
`:
|
|
78
|
-
`,r.N.a-1)+1,
|
|
79
|
-
${
|
|
80
|
-
${
|
|
78
|
+
${g.indent}${c}`:`${g.indent}${c}
|
|
79
|
+
`:c}else{p=r.N.innerB??r.N.openEnd;const g=l.lastIndexOf(`
|
|
80
|
+
`,r.N.a-1)+1,w=(/^[ \t]*/.exec(l.slice(g,r.N.a))||[""])[0];h=`
|
|
81
|
+
${w} ${c}
|
|
82
|
+
${w}`}if(p>u.a&&p<u.b)return;a?n.insertBefore(t,a):i?i.after(t):n.appendChild(t),N?.el===t&&(N.sel=jt(t)),L.scope=t.parentElement,Pe(),Mt(),ba(e),await mt(e,[{a:u.a,b:u.b,before:l.slice(u.a,u.b),text:""},{a:p,b:p,before:"",text:h}],`Move ${Ke(t)}`)}catch(o){y(o.message)}finally{Ht=!1}}async function el(){if(Ht||!L||L.els.length!==1)return;const e=L.frameId,t=L.els[0];if(!(!t.isConnected||!t.parentElement)){Ht=!0;try{const n=await We(e,t);if(!n){y("This one can\u2019t be copied by hand (its page is a live app, or its own script draws it). Ask for it in a comment.",3200);return}const a=n.src,s=a.slice(n.N.a,n.N.b),i=s.indexOf(">"),o=a.lastIndexOf(`
|
|
81
83
|
`,n.N.a-1)+1,r=a.indexOf(`
|
|
82
|
-
`,n.N.b),
|
|
83
|
-
${a.slice(o,n.N.a)}${
|
|
84
|
-
`,o-1)+1,
|
|
85
|
-
`,r);return/^[ \t]*$/.test(
|
|
86
|
-
${a("color","Text",
|
|
87
|
-
<span class="q-sep"></span>${
|
|
88
|
-
<span class="q-sep"></span><button class="q-btn" data-q="comment" title="Comment on this (for the agent)">${A("comment")}</button><button class="q-btn" data-q="delete" title="Delete (\u232B)">${A("trash")}</button><span class="q-note"></span>`,
|
|
84
|
+
`,n.N.b),l=r<0?a.length:r,c=s.slice(0,i).replace(/\sid\s*=\s*("[^"]*"|'[^']*'|[^\s>]+)/i,"")+s.slice(i),d=/^[ \t]*$/.test(a.slice(o,n.N.a))&&/^[ \t]*$/.test(a.slice(n.N.b,l)),u=d?l:n.N.b,p=d?`
|
|
85
|
+
${a.slice(o,n.N.a)}${c}`:c,h=t.cloneNode(!0);h.removeAttribute("id"),t.after(h),L={frameId:e,els:[h],scope:h.parentElement},Pe(),Mt(),ba(e),await mt(e,[{a:u,b:u,before:"",text:p}],`Duplicate ${Ke(t)}`)}catch(n){y(n.message)}finally{Ht=!1}}}async function Zd(e,t,n){const a=t.isConnected?await We(e,t):null;if(!a)return!1;const{src:s,N:i}=a;let o=i.a,r=i.b;const l=s.lastIndexOf(`
|
|
86
|
+
`,o-1)+1,c=s.indexOf(`
|
|
87
|
+
`,r);return/^[ \t]*$/.test(s.slice(l,o))&&/^[ \t]*$/.test(s.slice(r,c<0?s.length:c))&&(o=l,r=c<0?s.length:c+1),Ve(),t.remove(),ba(e),await mt(e,[{a:o,b:r,before:s.slice(o,r),text:""}],n),!0}async function Jd(e,t){const{fid:n,el:a}=e,s=Ke(a),i=ha(n,a),o=fe(t.clientX,t.clientY),r=Gn(o.x,o.y);if(r?.id===n)return;let l;if(r){const c=qe(r);l=await ws(i,r.id,Se(r.id,o.x-c.x,o.y-c.y))}else{const c=fe(e.bx+t.clientX-e.sx,e.by+t.clientY-e.sy);l=await ys(i,c.x,c.y)}if(l===!0)try{await Zd(n,a,`Move \u201C${s}\u201D out`)?y(r?`Moved \u201C${s}\u201D into ${r.name}`:`Moved \u201C${s}\u201D to its own frame`,1800):y(`Copied \u201C${s}\u201D (the original stays: its page can\u2019t be changed by hand)`,3e3)}catch(c){y(c.message)}}let Ht=!1;async function Qd(e){if(Ht||!L||L.els.length!==1)return;const t=L.frameId,n=L.els[0],a=n.parentElement;if(!a||!n.isConnected)return;const s=h=>!/^(SCRIPT|STYLE|TEMPLATE|BR|LINK|META)$/.test(h.tagName)&&h.getBoundingClientRect().width>0;let i=n.previousElementSibling;for(;i&&!s(i);)i=i.previousElementSibling;let o=n.nextElementSibling;for(;o&&!s(o);)o=o.nextElementSibling;const r=h=>{const g=h.getBoundingClientRect();return[g.left+g.width/2,g.top+g.height/2]},l=r(n),c=e==="ArrowLeft"||e==="ArrowRight",d=e==="ArrowRight"||e==="ArrowDown"?1:-1,u=h=>{if(!h)return!1;const g=r(h),w=g[0]-l[0],T=g[1]-l[1];return c?Math.abs(w)>Math.abs(T)&&Math.sign(w)===d:Math.abs(T)>=Math.abs(w)&&Math.sign(T)===d},p=u(i)?i:u(o)?o:null;if(p){Ht=!0;try{const h=await We(t,n),g=h&&await We(t,p);if(!h||!g){y("This one can\u2019t be moved by hand (its page is a live app, or its own script draws it). Ask for the move in a comment.",3200);return}const w=h.src.slice(h.N.a,h.N.b),T=h.src.slice(g.N.a,g.N.b);p===i?a.insertBefore(n,p):a.insertBefore(p,n),N?.el===n&&(N.sel=jt(n)),Pe(),Mt(),ba(t),await mt(t,[{a:h.N.a,b:h.N.b,before:w,text:T},{a:g.N.a,b:g.N.b,before:T,text:w}],`Move ${Ke(n)}`)}catch(h){y(h.message)}finally{Ht=!1}}}async function tl(e,t,n,a){const s=t.getBoundingClientRect(),i=Zn(e,{...ui(e,s.left+Math.min(s.width/2,40),s.top+Math.min(s.height/2,20)),scope:"elements",elements:[n]}),o={id:Ia(),frameId:e,text:a,anchor:i,author:{name:Z.name,color:Z.color}},r=Ga(o);try{const l=await x("POST","/__loop/api/comments",o);l?.id&&l.id!==o.id&&r()}catch(l){r(),y(l.message)}}let Ce=null;function _n(e,t){let n=e?.nodeType===3?e.parentElement:e;return!n||n.nodeType!==1||n.namespaceURI!=="http://www.w3.org/1999/xhtml"||/^(INPUT|TEXTAREA|SELECT|SCRIPT|STYLE|HTML|BODY)$/.test(n.tagName)||n.isContentEditable||![...n.childNodes].some(a=>a.nodeType===3&&a.data.trim())||!t&&n.closest('a, button, label, summary, select, [role="button"], [role="tab"], [role="link"]')?null:n}function Pn(e,t){if(!k()||Ce||X)return!1;ae(),te(),Re(),G.hidden=!0,ie.hidden=!0,Ce={fid:e,el:t,html:t.innerHTML,texts:[...t.childNodes].map(i=>i.nodeType===3?i.data:null),shape:gs(t),desc:ma(t),attr:t.getAttribute("contenteditable"),outline:[t.style.outline,t.style.outlineOffset,t.style.cursor]},t.setAttribute("contenteditable","plaintext-only"),t.contentEditable!=="plaintext-only"&&t.setAttribute("contenteditable","true"),Object.assign(t.style,{outline:"1.5px solid #2F5BFF",outlineOffset:"3px",cursor:"text"});const n=Ce,a=f.frames.find(i=>i.id===e);a&&ee(a);const s=()=>{if(Ce===n){try{P.get(e)?.iframe.focus()}catch{}t.focus({preventScroll:!0});try{const i=t.ownerDocument.getSelection(),o=t.ownerDocument.createRange();o.selectNodeContents(t),i.removeAllRanges(),i.addRange(o)}catch{}}};return n.t0=performance.now(),s(),setTimeout(s,40),t.addEventListener("blur",n.onBlur=()=>{performance.now()-n.t0<300?setTimeout(s,0):xs(!0)}),!0}async function xs(e){const t=Ce;if(!t)return;Ce=null;const{fid:n,el:a}=t;a.removeEventListener("blur",t.onBlur),t.attr==null?a.removeAttribute("contenteditable"):a.setAttribute("contenteditable",t.attr),[a.style.outline,a.style.outlineOffset,a.style.cursor]=t.outline,a.getAttribute("style")||a.removeAttribute("style");try{a.ownerDocument.getSelection().removeAllRanges(),a.blur()}catch{}{const p=f.frames.find(h=>h.id===n);p&&ee(p),$t()}const s=[...a.childNodes].map(p=>p.nodeType===3?p.data:null),i=p=>(p||"").replace(/\s+/g," ").trim(),o=i(t.texts.filter(p=>p!=null).join(" ")),r=i(a.textContent);if(L?.frameId===n&&N&&(ie.hidden=!1,Zt()),!e||!r||gs(a)===t.shape&&s.every((p,h)=>i(p)===i(t.texts[h]))){a.innerHTML=t.html;return}const l=await We(n,a);let c=null;if(l){const{src:p,P:h,N:g}=l,w=($,b)=>/^\s*/.exec($)[0]+Pd(b.trim())+/\s*$/.exec($)[0],T=[...h.childNodes].map($=>$.nodeType===3?$.data:null);gs(h)===t.shape&&_d(g)===t.shape&&T.every(($,b)=>i($)===i(t.texts[b]))&&(gs(a)===t.shape?c=s.map(($,b)=>$!=null&&i($)!==i(t.texts[b])?{a:g.kids[b].a,b:g.kids[b].b,before:p.slice(g.kids[b].a,g.kids[b].b),text:w(p.slice(g.kids[b].a,g.kids[b].b),$)}:null).filter(Boolean):!a.children.length&&!h.children.length&&(c=[{a:g.innerA,b:g.innerB,before:p.slice(g.innerA,g.innerB),text:w(p.slice(g.innerA,g.innerB),a.textContent)}]))}if(c?.length)try{await mt(n,c,"Edited text"),y("Saved",1100);return}catch(p){y(p.message),a.innerHTML=t.html;return}(L?.frameId!==n||L.els[0]!==a)&&(L={frameId:n,els:[a],scope:a.parentElement},hs(n)),N?.el===a&&(N.text={from:N.text?.from||o,to:r},N.held=!0,Dn());const d=N,u=t.html;J("Edited text",()=>{a.innerHTML=u,d&&(d.text=null),Pe(),N===d&&Dn()},()=>{})}function ef(e,t,n){const a=r=>r[pt]&&U==="select"&&r.button===0,s=r=>{r.preventDefault(),r.stopImmediatePropagation()};for(const r of["pointerdown","mousedown","pointerup","mouseup","dblclick"])e.addEventListener(r,l=>{(a(l)&&!Ce||performance.now()<0)&&s(l)},!0);e.addEventListener("click",r=>{if(performance.now()<0)return s(r);if(Ce?.fid===t)return Ce.el.contains(r.target)?s(r):void 0;if(!a(r))return;s(r);const[l,c]=n(r);G.hidden=!0,ln(t,{clientX:l,clientY:c,shiftKey:r.shiftKey})},!0);let o=!1;e.addEventListener("mousemove",r=>{if(r[pt]&&U==="select"&&!Ce){const[l,c]=n(r);Wa(t,l,c),o=!0}else o&&(o=!1,G.hidden=!0)},!0),e.addEventListener("keyup",r=>{o&&(r.key==="Meta"||r.key==="Control")&&(o=!1,G.hidden=!0)},!0),e.addEventListener("mouseleave",()=>{o&&(o=!1,G.hidden=!0)}),e.addEventListener("dblclick",r=>{if(U!=="select"||!k()||Ce||!r[pt])return;const l=_n(r.target,!0);l&&(s(r),Pn(t,l))},!0),e.addEventListener("keydown",r=>{Ce?.fid===t&&(r.stopImmediatePropagation(),r.key==="Enter"&&!r.shiftKey&&!r.isComposing?(r.preventDefault(),xs(!0)):r.key==="Escape"&&(r.preventDefault(),xs(!1)))},!0);for(const r of["keyup","keypress"])e.addEventListener(r,l=>{Ce?.fid===t&&(l.stopImmediatePropagation(),l.key===" "&&r==="keyup"&&l.preventDefault())},!0)}const tf='<svg class="qi" viewBox="0 0 16 16"><path d="M2 4.5V3h7v1.5M5.5 3v10M4 13h3"/><path d="M10 8.5V8h4.5v.5M12.25 8v5M11.25 13h2"/></svg>',nf='<svg class="qi" viewBox="0 0 16 16"><path d="M3 13V8a5 5 0 0 1 5-5h5"/><path d="M3 13h.01M13 3h.01" stroke-width="2.2"/></svg>',ie=document.createElement("div");ie.id="quick",ie.hidden=!0;{const e=()=>document.body.classList.toggle("card-open",!R.hidden||!H.hidden);for(const t of[R,H])new MutationObserver(e).observe(t,{attributes:!0,attributeFilter:["hidden"]})}document.body.appendChild(ie);let N=null;const ks=e=>{const t=/rgba?\(\s*([\d.]+)[,\s]+([\d.]+)[,\s]+([\d.]+)(?:[,\s/]+([\d.]+))?/.exec(e||"");return!t||t[4]!=null&&+t[4]==0?"":"#"+[t[1],t[2],t[3]].map(n=>Math.round(+n).toString(16).padStart(2,"0")).join("")};function Mt(){const e=L?.els.length===1?L.els[0]:null;if(!L||X){ie.hidden=!0,N=null;return}if(!e){ie.innerHTML=`<span class="q-count">${L.els.length} selected</span><span class="q-sep"></span><button class="q-btn" data-q="comment" title="Comment on these">${A("comment")}</button>`,ie.hidden=!1,N=null,Zt();return}const t=L.frameId,n=e.ownerDocument.defaultView.getComputedStyle(e);if(N?.el!==e&&(N={fid:t,el:e,sel:jt(e),pending:{},text:null,held:!1,t:null,desc:ma(e)}),!k()){ie.innerHTML=`<button class="q-btn" data-q="comment" title="Comment on this">${A("comment")}</button>`,ie.hidden=!1,Zt();return}const a=(i,o,r)=>`<button class="q-sw${r?"":" none"}" data-pick="${i}" data-val="${r}" title="${o} colour"><i style="${r?`background:${r}`:""}"></i><span>${o}</span></button>`,s=(i,o,r,l)=>`<div class="q-num" title="${r}"><span class="q-scrub" data-scrub="${i}" title="Drag to change ${r.toLowerCase()}">${o}</span><input type="text" inputmode="numeric" data-q="${i}" value="${Math.round(parseFloat(l)||0)}"></div>`;ie.innerHTML=`${_n(e,!0)?`<button class="q-btn" data-q="text" title="Edit the text (or double-click it)">${A("edit")}</button><span class="q-sep"></span>`:""}
|
|
88
|
+
${a("color","Text",ks(n.color))}${a("background-color","Fill",ks(n.backgroundColor))}${a("border-color","Border",parseFloat(n.borderTopWidth)?ks(n.borderTopColor):"")}
|
|
89
|
+
<span class="q-sep"></span>${s("font-size",tf,"Text size",n.fontSize)}${s("border-radius",nf,"Corner radius",n.borderTopLeftRadius)}
|
|
90
|
+
<span class="q-sep"></span><button class="q-btn" data-q="comment" title="Comment on this (for the agent)">${A("comment")}</button><button class="q-btn" data-q="delete" title="Delete (\u232B)">${A("trash")}</button><span class="q-note"></span>`,ie.hidden=!1,Dn(),Zt()}function Zt(){if(ie.hidden||!L)return;const e=L.frameId,t=L.els[L.els.length-1],n=P.get(e);if(!n||!t?.isConnected)return;const a=n.iframe.getBoundingClientRect(),s=t.getBoundingClientRect(),i=v.z,o=a.left+s.left*i,r=a.top+s.top*i,l=a.top+s.bottom*i,c=ie.offsetWidth,d=ie.offsetHeight;let u=r-d-8;u<60&&(u=l+8),u+d>innerHeight-76&&(u=Math.max(60,r+8)),ie.style.left=`${Math.round(Math.max(12,Math.min(o,innerWidth-c-12)))}px`,ie.style.top=`${Math.round(u)}px`}function Dn(e){const t=ie.querySelector(".q-note");if(!t||!N)return;const n=f.frames.find(s=>s.id===N.fid)?.kind==="folder",a=Object.keys(N.pending).length+(N.text?1:0);t.innerHTML=e?`<span>${C(e)}</span>`:(N.held||!n)&&a?`<span>Only on screen</span><button class="q-send" data-q="send" title="Loop can't change this in the code by itself. Ask the agent to make it real">Send to agent</button>`:"",Zt()}function qn(e,t){if(!N)return;const{el:n}=N,a=(i,o)=>{n.style.setProperty(i,o),N.pending[i]=o};if(!N.base){const i=N,o=n.getAttribute("style");N.base=!0,setTimeout(()=>{i.base=!1},1500),(i.held||f.frames.find(r=>r.id===i.fid)?.kind!=="folder")&&J("Edited style",()=>{o==null?i.el.removeAttribute("style"):i.el.setAttribute("style",o),i.pending={},Pe(),N===i&&Mt()},()=>{})}e==="border-color"&&!parseFloat(n.ownerDocument.defaultView.getComputedStyle(n).borderTopWidth)&&(a("border-width","1px"),a("border-style","solid")),a(e,t),Pe();const s=f.frames.find(i=>i.id===N.fid)?.kind==="folder";clearTimeout(N.t),s?N.t=setTimeout(nl,380):Dn()}async function nl(){const e=N;if(!e||!Object.keys(e.pending).length)return;const t=e.pending;e.pending={};const n=e.el.isConnected?await We(e.fid,e.el):null;if(!n){e.pending={...t,...e.pending},e.held=!0,N===e&&Dn();return}const{src:a,N:s}=n,i=s.attrs.find(c=>c.name==="style"),o=new Map;for(const c of(i?.value||"").split(";")){const d=c.indexOf(":");d>0&&o.set(c.slice(0,d).trim().toLowerCase(),c.slice(d+1).trim())}for(const[c,d]of Object.entries(t))o.set(c,d);"background-color"in t&&o.get("background")==="none"&&o.delete("background");const r=[...o].map(([c,d])=>`${c}: ${d}`).join("; ").replace(/"/g,"'");let l;if(i&&i.va>=0&&i.q)l={a:i.va,b:i.vb,before:a.slice(i.va,i.vb),text:i.q==='"'?r:r.replace(/'/g,'"')};else if(i)l={a:i.a,b:i.b,before:a.slice(i.a,i.b),text:`style="${r}"`};else{const c=a[s.openEnd-2]==="/"?s.openEnd-2:s.openEnd-1;l={a:c,b:c,before:"",text:` style="${r}"`}}try{await mt(e.fid,[l],"Edited style"),N===e&&Dn("Saved")}catch(c){y(c.message)}}async function af(e){const t=Object.entries(e.pending).map(([a,s])=>`${a}: ${s}`).join("; "),n=[e.text&&`Change this text from "${e.text.from.slice(0,300)}" to "${e.text.to.slice(0,600)}".`,t&&`Set these on this element: ${t}.`].filter(Boolean);n.length&&(e.pending={},e.text=null,e.held=!1,Ve(),await tl(e.fid,e.el,e.desc,`${n.join(" ")} Make it in the source and change nothing else.`))}ie.addEventListener("pointerdown",e=>e.stopPropagation()),ie.addEventListener("input",e=>{const t=e.target.closest("[data-q]");if(!(!t||!N)&&t.type==="color"){const n=t.closest(".q-sw");n.classList.remove("none"),n.querySelector("i").style.background=t.value,qn(t.dataset.q,t.value)}}),ie.addEventListener("change",e=>{const t=e.target.closest("input[data-q]");t&&t.value.trim()!==""&&!isNaN(+t.value)&&qn(t.dataset.q,`${Math.max(0,Math.min(400,Math.round(+t.value)))}px`)}),ie.addEventListener("keydown",e=>{if(e.stopPropagation(),(e.metaKey||e.ctrlKey)&&e.key.toLowerCase()==="z"){e.preventDefault(),e.target.blur?.(),e.shiftKey?fa():us();return}if(e.key==="Escape")return e.target.blur?.(),Ve();if(e.key==="Enter")return e.target.blur?.();const t=e.target.closest("input[data-q]");t&&(e.key==="ArrowUp"||e.key==="ArrowDown")&&(e.preventDefault(),t.value=Math.max(0,Math.min(400,(parseInt(t.value)||0)+(e.key==="ArrowUp"?1:-1)*(e.shiftKey?10:1))),qn(t.dataset.q,`${t.value}px`))}),ie.addEventListener("pointerdown",e=>{const t=e.target.closest("[data-scrub]");if(!t||!N)return;e.preventDefault();const n=t.parentElement.querySelector("input"),a=parseInt(n.value)||0,s=e.clientX;t.setPointerCapture(e.pointerId),document.body.classList.add("scrubbing");const i=r=>{const l=Math.max(0,Math.min(400,Math.round(a+(r.clientX-s)/2*(r.shiftKey?10:1))));String(l)!==n.value&&(n.value=l,qn(t.dataset.scrub,`${l}px`))},o=()=>{t.removeEventListener("pointermove",i),document.body.classList.remove("scrubbing")};t.addEventListener("pointermove",i),t.addEventListener("pointerup",o,{once:!0}),t.addEventListener("pointercancel",o,{once:!0})}),ie.addEventListener("click",e=>{const t=e.target.closest("[data-pick]");if(t&&N)return $s(t);const n=e.target.closest("button[data-q]");if(!n)return;if(n.dataset.q==="comment")return pa();if(n.dataset.q==="delete")return Ui();const a=e.target.closest("[data-pick]");if(a&&N)return $s(a);if(N)if(n.dataset.q==="text"){const{fid:s,el:i}=N;Pn(s,i)}else n.dataset.q==="send"&&af(N)});const Ee=document.createElement("div");Ee.id="cpick",Ee.hidden=!0,document.body.appendChild(Ee);let ne=null;const sf=(e,t,n)=>{const a=s=>{const i=(s+e/60)%6;return n-n*t*Math.max(0,Math.min(i,4-i,1))};return[a(5),a(3),a(1)].map(s=>Math.round(s*255))},of=e=>"#"+e.map(t=>t.toString(16).padStart(2,"0")).join("");function Vi(e){const t=/^#?([0-9a-f]{6})$/i.exec(e||"");if(!t)return{h:0,s:0,v:1};const n=parseInt(t[1],16),a=(n>>16&255)/255,s=(n>>8&255)/255,i=(n&255)/255,o=Math.max(a,s,i),r=o-Math.min(a,s,i);return{h:r?o===a?((s-i)/r+6)%6*60:o===s?((i-a)/r+2)*60:((a-s)/r+4)*60:0,s:o?r/o:0,v:o}}function rf(e){const t=new Map;for(const n of[...e.body.querySelectorAll("*")].slice(0,1500)){const a=e.defaultView.getComputedStyle(n);for(const s of[a.color,a.backgroundColor,a.borderTopWidth!=="0px"?a.borderTopColor:""]){const i=ks(s);i&&t.set(i,(t.get(i)||0)+1)}}return[...t].sort((n,a)=>a[1]-n[1]).slice(0,14).map(n=>n[0])}function $s(e){if(ne?.btn===e)return Jt();Jt();const t=e.dataset.val||"#ffffff";ne={prop:e.dataset.pick,btn:e,...Vi(t)};const n=(()=>{try{return rf(N.el.ownerDocument)}catch{return[]}})();Ee.innerHTML=`<div class="cp-sv"><i></i></div><div class="cp-hue"><i></i></div>
|
|
89
91
|
<div class="cp-row"><span class="cp-now"></span><input class="cp-hex" spellcheck="false" maxlength="7">${e.dataset.pick==="frame-fill"?'<button class="cp-none" title="No fill: the frame shows the canvas behind it">No fill</button>':e.dataset.pick==="background-color"?'<button class="cp-none" title="No fill: whatever is behind it shows through">No fill</button>':e.dataset.pick==="border-color"?'<button class="cp-none" title="Remove the border">No border</button>':""}</div>
|
|
90
|
-
${n.length?`<div class="cp-label">On this page</div><div class="cp-used">${n.map(r=>`<button data-c="${r}" style="background:${r}" title="${r}"></button>`).join("")}</div>`:""}`,
|
|
91
|
-
`,u-1)+1,g=
|
|
92
|
-
`,p);/^[ \t]*$/.test(
|
|
93
|
-
`);return}if(
|
|
94
|
-
`);for(const
|
|
95
|
-
`;
|
|
96
|
-
`)};for(const
|
|
97
|
-
`+
|
|
98
|
-
<div class="kb-row">${r(
|
|
99
|
-
<div class="kb-row"><span class="k fn">\u21E7</span>${r(
|
|
100
|
-
<div class="kb-row"><span class="k fn">123</span><span class="k fn">\u263A</span><span class="k sp">space</span><span class="k fn ret">return</span></div>`}o.classList.toggle("num",
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
<button class="sb-exit" data-sb="exit" title="Exit stage (Esc)">${A("x")}<span>Exit</span></button>`;for(const c of[250,900,2e3])setTimeout(_r,c)}function Ar(e){try{const t=D.get(e.id)?.iframe.contentDocument,n=t?.documentElement;if(!n||!t.body)return 0;const a=Math.max(n.scrollWidth,t.body.scrollWidth)-n.clientWidth;return a>4?Math.round(a):0}catch{return 0}}function _r(){const e=m("#stage-bar .sb-fit"),t=S&&f.frames.find(a=>a.id===S.fid);if(!e||!t)return;const n=f.live[t.id]||t.kind==="frozen"?0:Ar(t);e.hidden=!n,e.dataset.over=n,e.title=`The page is ${n}px wider than this ${t.w}\xD7${t.h} frame. Ask the agent to make it fit this size.`}async function gd(){const e=S&&f.frames.find(i=>i.id===S.fid),t=e&&Ar(e);if(!t)return _r();const n={id:ga(),frameId:e.id,author:{name:U.name,color:U.color},anchor:On(e.id,{scope:"frame",x:0,y:0}),text:`This screen doesn\u2019t fit at ${e.w}\xD7${e.h}: the page runs ${t}px wider than the frame. Make it responsive at this size, and keep it looking the same at the sizes it already works at.`},a=Pa(n);try{const i=await w("POST","/__loop/api/comments",n);i?.id&&i.id!==n.id&&a(),m("#stage-bar .sb-fit").hidden=!0,y("Asked the agent to make it fit")}catch(i){a(),y(i.message)}}const yd='<svg viewBox="0 0 24 24" aria-hidden="true"><path d="M20.5 12a8.5 8.5 0 1 1-2.6-6.1"/><path d="M20.5 3.5v5h-5"/></svg>',bd='<svg viewBox="0 0 24 24" aria-hidden="true"><rect x="2.5" y="5" width="12" height="9" rx="1.5"/><rect x="12" y="8" width="6" height="10" rx="1.2"/><rect x="17" y="11" width="4.5" height="8" rx="1"/></svg>';async function Pr(e){try{const t=await w("POST",`/__loop/api/frames/${e.id}/sizes`);dt(),setTimeout(()=>Oe(!0,[e.id,...t.frames]),450),t.existing||y("The same screen at the other sizes, live. Comment on whichever one breaks.",3e3)}catch(t){y(t.message)}}async function qr(){const e=S&&f.frames.find(i=>i.id===S.fid);if(!e||!ca(e)||!$())return;const t={w:e.w,h:e.h,x:e.x,y:e.y},n={w:e.h,h:e.w,x:Math.round(e.x+(e.w-e.h)/2),y:Math.round(e.y+(e.h-e.w)/2)},a=i=>(Object.assign(e,i),J(e),S?.fid===e.id&&(da(),ct(En(e),320)),w("PATCH",`/__loop/api/frames/${e.id}`,i).catch(s=>y(s.message)));G("Rotate frame",()=>a(t),()=>a(n)),a(n)}function vd(e){const t=S&&f.frames.find(l=>l.id===S.fid);if(!t)return;const n=l=>({x:l.x+l.w/2,y:l.y+l.h/2}),a=n(t),i=e==="left"||e==="right",s=e==="right"||e==="down"?1:-1,o=f.frames.filter(l=>l.id!==t.id).map(l=>{const d=n(l);return{f:l,along:(i?d.x-a.x:d.y-a.y)*s,side:Math.abs(i?d.y-a.y:d.x-a.x)}}),c=o.filter(l=>l.along>1).sort((l,d)=>l.along+2*l.side-(d.along+2*d.side))[0]||o.sort((l,d)=>l.along+2*l.side-(d.along+2*d.side))[0];c&&vt(c.f.id)}function Od(e){if(!S)return;const t=xs(),n=t.findIndex(a=>a.id===S.fid);t.length>1&&vt(t[(n+e+t.length)%t.length].id)}function wd(e){const t=e.target.closest("[data-sb]");if(!t||!S)return;const n=f.frames.find(o=>o.id===S.fid);if(!n)return;const a=t.dataset.sb,i=xs(),s=i.findIndex(o=>o.id===n.id);if(a==="exit")return dt();if(a==="prev"||a==="next"){const o=i[(s+(a==="next"?1:-1)+i.length)%i.length];return vt(o.id)}if(a==="device"){la.has(n.id)?la.delete(n.id):la.add(n.id);try{localStorage.setItem("loop.stageNoDevice",JSON.stringify([...la]))}catch{}return da(),ct(En(n),300)}if(a==="keyboard")return di(n.id);if(a==="rotate")return qr();if(a==="fit")return gd();if(a==="sizes")return Pr(n);if(a==="freeze")return ra(n.id);if(a==="zoom")return S.zoom=S.zoom==="fit"?"100":"fit",da(),ct(En(n),320)}addEventListener("keydown",e=>{if(!S||Ot()||e.metaKey||e.ctrlKey)return;const t={ArrowRight:"right",ArrowLeft:"left",ArrowUp:"up",ArrowDown:"down"}[e.key];if(t&&(e.preventDefault(),vd(t)),e.key.toLowerCase()==="r"&&!e.shiftKey&&!e.altKey){const n=f.frames.find(a=>a.id===S.fid);n&&ca(n)&&$()&&(e.preventDefault(),e.stopImmediatePropagation(),qr())}}),addEventListener("resize",()=>{if(S){const e=f.frames.find(t=>t.id===S.fid);e&&(b=En(e),ie())}});const Te=document.createElement("div");Te.id="edge",Te.hidden=!0,document.body.appendChild(Te),Te.innerHTML=`<button class="eg-btn" data-eg="stage">${A("stage")}<span></span></button>`;let _t=null,tn=null,fi=!1,ks=0;const je={x:-1,y:-1},Sn=52;function jt(e){const t=De(e),n=b.z;return{l:b.x+t.x*n,t:b.y+t.y*n,w:t.w*n,h:t.h*n}}function xd(){if(!f)return null;if(S)return S.fid;if(se||document.body.classList.contains("versions-on"))return null;for(let e=f.frames.length-1;e>=0;e--){const t=jt(f.frames[e]),n=Math.max(t.t,Sn);if(je.x>=t.l-6&&je.x<=t.l+t.w+6&&je.y>=Math.max(t.t-44,0)&&je.y<=Math.min(n+110,t.t+t.h))return f.frames[e].id}return!Y.size&&_||fe||null}function ui(){const e=xd();e?(clearTimeout(tn),tn=null,_t=e):_t&&!tn&&!fi&&(tn=setTimeout(()=>{tn=null,fi||(_t=null,fa())},380)),fa()}function fa(){const e=_t&&f?.frames.find(d=>d.id===_t),t=!1,n=e&&jt(e);if(!e||S||n.w<72||n.t+n.h<Sn+30||n.t>innerHeight-40||n.l>innerWidth-40||n.l+n.w<40){Te.hidden=!0;return}Te.hidden=!1,Te.classList.toggle("exit",t),Te.classList.toggle("compact",!t&&n.w<200);const a=Te.querySelector('[data-eg="stage"]');$e(a.lastChild,t?"Exit stage":"Stage"),a.dataset.tip="Stage: focus on this frame (S)";const i=Te.offsetWidth,s=Te.offsetHeight;let o=n.t-12*(parseFloat(getComputedStyle(document.documentElement).getPropertyValue("--lz"))||1)-s/2;const r=o<Sn;r&&(o=Math.max(n.t+8,Sn+4));const c=r?-8:parseFloat(getComputedStyle(a).paddingRight)||0;let l=Math.min(n.l+n.w-i+c,innerWidth-i-12);l=Math.max(l,n.l),Te.classList.toggle("inside",r),Te.style.left=`${Math.round(l)}px`,Te.style.top=`${Math.round(o)}px`;for(const[d,u]of D){const p=u.el.querySelector(":scope > .opt-strip, :scope > .ver-strip");if(!p)continue;const h=f.frames.find(k=>k.id===d);if(!h)continue;const g=jt(h),v=p.offsetHeight,T=g.t-34-v,C=T<Sn+4?Math.min(Sn+4-T,Math.max(0,g.h-20)):0;p.style.translate=C?`0 ${C/b.z}px`:""}}addEventListener("pointermove",e=>{je.x=e.clientX,je.y=e.clientY,Cl(),ks||(ks=requestAnimationFrame(()=>{ks=0,ui()}))},{capture:!0,passive:!0}),Te.addEventListener("pointerenter",()=>{fi=!0,clearTimeout(tn),tn=null}),Te.addEventListener("pointerleave",()=>{fi=!1,ui()}),Te.addEventListener("pointerdown",e=>e.stopPropagation()),Te.addEventListener("click",async e=>{!e.target.closest('[data-eg="stage"]')||!_t||(S?.fid===_t?dt():vt(_t))});const pi=new Set;function Dr(e,t=0){if(!pi.has(e)){if((se||S||F||xe)&&t<40)return setTimeout(()=>Dr(e,t+1),250);setTimeout(()=>{!pi.has(e)&&f.sections.some(n=>n.id===e)&&(pi.add(e),Ir(e))},t?0:500)}}function Ir(e){const t=f.sections.find(u=>u.id===e),n=t&&f.comments.find(u=>u.id===t.optionsFor),a=n&&f.frames.find(u=>u.id===n.frameId);if(!t||!a||S||F)return;const i=Math.min(a.x,t.x),s=Math.min(a.y,t.y)-40,o=Math.max(a.x+a.w,t.x+t.w),r=Math.max(a.y+a.h,t.y+t.h),c={x:b.x+i*b.z,y:b.y+s*b.z},l={x:b.x+o*b.z,y:b.y+r*b.z};if(c.x>=0&&c.y>=50&&l.x<=innerWidth&&l.y<=innerHeight-70&&(o-i)*b.z>innerWidth*.45)return;const d=Math.min(1,(innerWidth-160)/(o-i),(innerHeight-240)/(r-s));ct({z:d,x:(innerWidth-(o-i)*d)/2-i*d,y:120+(innerHeight-240-(r-s)*d)/2-s*d},520)}function Tn(e){const t=b.z;return t<.33||e.w*t<300&&e.h*t<300}let mi={fid:null,t:0},nn=null;function kd(e,t){const n=ke&&f.sections.find(i=>i.id===ke),a=n?an(n).map(i=>i.id):Y.size?[...Y]:_?[_]:[];if(!a.length&&!n)return!1;nn||={from:Object.fromEntries(a.map(i=>{const s=f.frames.find(o=>o.id===i);return[i,{x:s.x,y:s.y}]})),sec:n&&{id:n.id,x:n.x,y:n.y}};for(const i of Object.keys(nn.from)){const s=f.frames.find(o=>o.id===i);s&&(s.x+=e,s.y+=t,J(s))}return n&&nn.sec&&(n.x+=e,n.y+=t,wt()),_e(),fa(),oa(),clearTimeout(nn.t),nn.t=setTimeout(()=>{const i=nn;nn=null;const s=Object.fromEntries(Object.keys(i.from).map(d=>{const u=f.frames.find(p=>p.id===d);return[d,{x:u.x,y:u.y}]})),o=i.from,r=i.sec&&f.sections.find(d=>d.id===i.sec.id),c=r&&{x:r.x,y:r.y},l=i.sec&&{x:i.sec.x,y:i.sec.y};Se(s),r&&w("PATCH",`/__loop/api/sections/${r.id}`,c).catch(()=>{}),G("Nudge",()=>Promise.all([Se(o),r&&Pt(r.id,l)]),()=>Promise.all([Se(s),r&&Pt(r.id,c)]))},400),!0}const Kt=m("#sections"),ua=new Map;let ke=null,hi={id:null,t:0};const $s=e=>({...e,...ua.get(e.id)||{}}),An=(e,t)=>{const n=Math.min(t.x+t.w,e.x+e.w)-Math.max(t.x,e.x),a=Math.min(t.y+t.h,e.y+e.h)-Math.max(t.y,e.y);return n>0&&a>0&&n*a>t.w*t.h*.5};function gi(e){for(const t of f.frames)D.get(t.id)?.el.classList.toggle("joining",!!e&&!t.parent&&An(e,De(t)))}const an=e=>f.frames.filter(t=>An(e,t));function Hr(){if(!f)return;const e=b.z,t=(f.sections||[]).map($s);for(const n of f.frames){const a=D.get(n.id);if(!a)continue;const i=n.w*e,s=De(n),o=t.some(r=>An(r,s)&&(s.y-r.y)*e<24);a.el.classList.toggle("narrow",i<200),a.el.classList.toggle("noname",i<34||o)}for(const n of t){const a=Kt.querySelector(`.section[data-id="${n.id}"]`);a&&(a.classList.toggle("noname",n.w*e<48),a.classList.remove("lift"))}}function wt(){const e=f.sections||[],t=new Set(e.map(n=>n.id));Kt.querySelectorAll(".section").forEach(n=>{t.has(n.dataset.id)||n.remove()}),ke&&!t.has(ke)&&(ke=null);for(const n of e){const a=$s(n);let i=Kt.querySelector(`.section[data-id="${a.id}"]`);if(!i){i=document.createElement("div"),i.className="section",i.dataset.id=a.id,i.innerHTML=`<div class="sec-label"><span class="sec-name"></span><button class="sec-more" title="Section options"><svg viewBox="0 0 16 16" aria-hidden="true"><circle cx="3.5" cy="8" r="1.3"/><circle cx="8" cy="8" r="1.3"/><circle cx="12.5" cy="8" r="1.3"/></svg></button></div>${["n","s","e","w","ne","nw","se","sw"].map(l=>`<div class="srz rz-${l}" data-dir="${l}"></div>`).join("")}`,Kt.appendChild(i);const r=i.querySelector(".sec-more"),c=a.id;r.addEventListener("pointerdown",l=>l.stopPropagation()),r.addEventListener("click",l=>{l.stopPropagation(),Cd(c,r)})}Object.assign(i.style,{left:`${a.x}px`,top:`${a.y}px`,width:`${a.w}px`,height:`${a.h}px`}),i.style.setProperty("--sw",`${a.w}px`);const s=i.querySelector(".sec-name");s.classList.contains("editing-name")||$e(s,a.name),i.classList.toggle("selected",ke===a.id);const o=a.optionsFor&&f.comments.find(r=>r.id===a.optionsFor);i.classList.toggle("making",!!o&&(Ca(o.id)==="working"||f.frames.some(r=>r.building&&r.optionOf?.cid===o.id)))}Hr()}function yi(e){(_||Y.size||fe)&&Z(null),ke=e,wt()}function zr(e,t){const n=f.sections.find(a=>a.id===e);se={type:"smove",sid:e,sx:t.clientX,sy:t.clientY,x0:n.x,y0:n.y,moved:!1,from:Object.fromEntries(an(n).map(a=>[a.id,{x:a.x,y:a.y}]))},I.classList.add("dragging"),I.setPointerCapture(t.pointerId)}function $d(e,t){const n=f.sections.find(a=>a.id===e);se={type:"sresize",sid:e,dir:t.target.dataset.dir||"se",sx:t.clientX,sy:t.clientY,x0:n.x,y0:n.y,w:n.w,h:n.h},I.classList.add("dragging"),I.setPointerCapture(t.pointerId)}function Pt(e,t){const n=f.sections.find(a=>a.id===e);return n&&(Object.assign(n,t),wt()),w("PATCH",`/__loop/api/sections/${e}`,t)}async function Ld(e){try{const t=await w("POST","/__loop/api/sections",e);f.sections.find(n=>n.id===t.id)||f.sections.push(t),G("Add section",()=>w("DELETE",`/__loop/api/sections/${t.id}`),()=>He({sections:[t]})),yi(t.id)}catch(t){y(t.message)}}const me=document.createElement("div");me.id="sec-menu",me.className="menu",me.hidden=!0,document.body.appendChild(me);function Cd(e,t){if(!me.hidden&&me._for===e){me.hidden=!0;return}const n=f.sections.find(c=>c.id===e);if(!n||!$())return;const a=an(n).length,i=`${a} frame${a===1?"":"s"}`;me._for=e,me.innerHTML=a?`<button class="menu-item" data-sm="keep"><span><b>Unsection</b><small>Its ${i} stay${a===1?"s":""} on the canvas \xB7 ${we.shift}${we.cmd}S</small></span></button>
|
|
107
|
-
|
|
108
|
-
|
|
92
|
+
${n.length?`<div class="cp-label">On this page</div><div class="cp-used">${n.map(r=>`<button data-c="${r}" style="background:${r}" title="${r}"></button>`).join("")}</div>`:""}`,Ee.hidden=!1,Ls(!0);const a=e.getBoundingClientRect(),s=Ee.offsetWidth,i=Ee.offsetHeight;let o=a.bottom+8;o+i>innerHeight-12&&(o=a.top-i-8),Ee.style.left=`${Math.round(Math.max(12,Math.min(a.left-8,innerWidth-s-12)))}px`,Ee.style.top=`${Math.round(Math.max(12,o))}px`,e.classList.add("on")}function Jt(){ne&&(ne.prop==="frame-fill"&&sl(),ne.btn?.classList.remove("on"),ne=null,Ee.hidden=!0)}let Qt=null;function al(e){const t=f.frames.find(n=>n.id===D);t&&((!Qt||Qt.id!==t.id)&&(Qt={id:t.id,before:t.fill||null}),t.fill=e,ee(t),clearTimeout(Qt.t),Qt.t=setTimeout(()=>x("PATCH",`/__loop/api/frames/${t.id}`,{fill:e}).catch(n=>y(n.message)),250))}function sl(){const e=Qt;if(Qt=null,!e)return;const t=f.frames.find(s=>s.id===e.id),n=t?.fill||null;if(n===e.before)return;const a=s=>{const i=f.frames.find(o=>o.id===e.id);return i&&(i.fill=s||void 0,ee(i),Fe()),x("PATCH",`/__loop/api/frames/${e.id}`,{fill:s})};J("Frame fill",()=>a(e.before),()=>a(n))}function Ls(e){if(!ne)return;const t=of(sf(ne.h,ne.s,ne.v));Ee.querySelector(".cp-sv").style.background=`linear-gradient(to top, #000, transparent), linear-gradient(to right, #fff, hsl(${ne.h}, 100%, 50%))`,Object.assign(Ee.querySelector(".cp-sv i").style,{left:`${ne.s*100}%`,top:`${(1-ne.v)*100}%`,background:t}),Object.assign(Ee.querySelector(".cp-hue i").style,{left:`${ne.h/360*100}%`,background:`hsl(${ne.h}, 100%, 50%)`}),Ee.querySelector(".cp-now").style.background=t;const n=Ee.querySelector(".cp-hex");if(document.activeElement!==n&&(n.value=t.toUpperCase()),e)return;const a=ne.btn;if(a.classList.remove("none"),a.querySelector("i").style.background=t,a.dataset.val=t,ne.prop==="frame-fill"){const s=a.querySelector("span");return s&&(s.textContent=t.toUpperCase()),al(t)}qn(ne.prop,t)}Ee.addEventListener("pointerdown",e=>{e.stopPropagation();const t=e.target.closest(".cp-sv, .cp-hue");if(!t||!ne)return;e.preventDefault(),t.setPointerCapture(e.pointerId);const n=s=>{const i=t.getBoundingClientRect(),o=Math.max(0,Math.min(1,(s.clientX-i.left)/i.width)),r=Math.max(0,Math.min(1,(s.clientY-i.top)/i.height));t.classList.contains("cp-hue")?ne.h=o*360:(ne.s=o,ne.v=1-r),Ls()};n(e);const a=()=>t.removeEventListener("pointermove",n);t.addEventListener("pointermove",n),t.addEventListener("pointerup",a,{once:!0})}),Ee.addEventListener("click",e=>{if(e.target.closest(".cp-none")&&ne?.prop==="frame-fill"){al("none"),Jt(),Fe();return}if(e.target.closest(".cp-none")&&ne){const n=ne.btn,a=ne.prop==="border-color";qn(a?"border-style":"background","none"),n.classList.add("none"),n.dataset.val="",n.querySelector("i").style.background="",Jt();return}const t=e.target.closest("[data-c]");t&&ne&&(Object.assign(ne,Vi(t.dataset.c)),Ls())}),Ee.addEventListener("keydown",e=>{e.stopPropagation(),e.key==="Escape"&&Jt(),(e.metaKey||e.ctrlKey)&&e.key.toLowerCase()==="z"&&(e.preventDefault(),e.target.blur?.(),e.shiftKey?fa():us())}),Ee.addEventListener("input",e=>{if(!e.target.classList.contains("cp-hex")||!ne)return;const t=e.target.value.trim(),n=/^#?([0-9a-f]{6})$/i.exec(t);n&&(Object.assign(ne,Vi("#"+n[1])),Ls())}),addEventListener("pointerdown",e=>{ne&&!e.target.closest("#cpick, [data-pick]")&&Jt()},!0);async function Ui(){if(!L||!k())return;const{frameId:e,els:t}=L,n=[],a=[];for(const r of t){const l=r.isConnected?await We(e,r):null;if(l){const{src:c,N:d}=l;let u=d.a,p=d.b;const h=c.lastIndexOf(`
|
|
93
|
+
`,u-1)+1,g=c.indexOf(`
|
|
94
|
+
`,p);/^[ \t]*$/.test(c.slice(h,u))&&/^[ \t]*$/.test(c.slice(p,g<0?c.length:g))&&(u=h,p=g<0?c.length:g+1),n.push({a:u,b:p,before:c.slice(u,p),text:""})}else a.push(r)}n.sort((r,l)=>r.a-l.a||l.b-r.b);const s=n.filter((r,l)=>!n.slice(0,l).some(c=>c.a<=r.a&&c.b>=r.b)),i=t.map(ma),o=t.length===1?Ke(t[0]):`${t.length} layers`;if(Ve(),a.length){const r=a.map(l=>[l,l.parentNode,l.nextSibling]);a.forEach(l=>l.remove()),J(`Delete ${o}`,()=>r.forEach(([l,c,d])=>c?.insertBefore(l,d)),()=>{}),lf(e,a[0],i)}if(s.length)try{await mt(e,s,`Delete ${o}`)}catch(r){y(r.message)}}function lf(e,t,n){const a=document.createElement("div");a.id="del-ask",a.innerHTML="<span>Hidden for now. The page\u2019s code draws it.</span><button>Remove it for real</button>",document.querySelector("#del-ask")?.remove(),document.body.appendChild(a),a.querySelector("button").onclick=async()=>{a.remove(),await tl(e,t,n[0],`Remove ${n.length===1?"this element":`these ${n.length} elements`} from the page, in the source. Change nothing else.`)},setTimeout(()=>a.remove(),8e3)}function cf(e){if(L?.frameId!==e||!N||N.fid!==e)return;const t=ue(e);if(!t||t.location.href==="about:blank"||!t.body?.children.length)return;const n=t.querySelector(N.sel);if(!n)return ae();const a=N.pending;L.els=[n],N.el=n;for(const[s,i]of Object.entries(a))n.style.setProperty(s,i);Pe(),Mt()}function Xi(e){if(e=e.filter(t=>f.frames.find(n=>n.id===t)),e.length===1)return Q(e[0]);D=null,W.clear(),e.forEach(t=>W.add(t));for(const t of f.frames)ee(t);Fe(),va()}function df(e){const t=new Set(W.size?W:D?[D]:[]);t.has(e)?t.delete(e):t.add(e),Xi([...t])}const Gi=e=>{const t=Math.min(...e.map(a=>a.x)),n=Math.min(...e.map(a=>a.y));return{x:t,y:n,w:Math.max(...e.map(a=>a.x+a.w))-t,h:Math.max(...e.map(a=>a.y+a.h))-n}};async function _e(e){for(const[t,n]of Object.entries(e)){const a=f.frames.find(s=>s.id===t);a&&(Object.assign(a,n),ee(a))}In(),Qn(),await Promise.all(Object.entries(e).map(([t,n])=>x("PATCH",`/__loop/api/frames/${t}`,n)))}const il={KeyA:"left",KeyD:"right",KeyW:"top",KeyS:"bottom",KeyH:"hcenter",KeyV:"vcenter"};function ol(e){const t=[...W].map(o=>f.frames.find(r=>r.id===o)).filter(Boolean);if(t.length<2)return;const n=Gi(t),a={},s={};for(const o of t)a[o.id]={x:o.x,y:o.y};if(e==="hdist"||e==="vdist")return ff(e,t,n,a);ke=null,Cs();for(const o of t){const r={...a[o.id]};e==="left"?r.x=n.x:e==="right"?r.x=n.x+n.w-o.w:e==="hcenter"?r.x=Math.round(n.x+n.w/2-o.w/2):e==="top"?r.y=n.y:e==="bottom"?r.y=n.y+n.h-o.h:e==="vcenter"&&(r.y=Math.round(n.y+n.h/2-o.h/2)),s[o.id]=r}_e(s);const i={left:"Align left",right:"Align right",hcenter:"Align centres",top:"Align top",bottom:"Align bottom",vcenter:"Align middles",hdist:"Distribute horizontally",vdist:"Distribute vertically"}[e];J(i,()=>_e(a),()=>_e(s))}async function rl(e){const t=e.map(Ct).filter(Boolean);await Promise.all(e.map(a=>x("DELETE",`/__loop/api/frames/${a}`)));const n={frames:t.flatMap(a=>a.frames),comments:t.flatMap(a=>a.comments)};J(`Delete ${e.length} frames`,()=>ze(n),()=>Promise.all(e.map(a=>x("DELETE",`/__loop/api/frames/${a}`)))),W.clear(),va(),y(`Deleted ${e.length} frames \u2014 \u2318Z to undo`,2600)}let ke=null;function ff(e,t,n,a){const s=e==="hdist"?"x":"y",i=e==="hdist"?"w":"h",o=[...t].sort((c,d)=>c[s]-d[s]);let r=((s==="x"?n.w:n.h)-o.reduce((c,d)=>c+d[i],0))/Math.max(1,o.length-1);r<40&&(r=80),ke={k:s,size:i,ids:o.map(c=>c.id),start:o[0][s],before:a,after:null,gap:Math.round(r)};const l=ke;cn(l.gap,!0),J(e==="hdist"?"Distribute horizontally":"Distribute vertically",()=>_e(l.before),()=>_e(l.after)),Cs()}function uf(e){const t=ke,n={};let a=t.start;for(const s of t.ids){const i=f.frames.find(o=>o.id===s);i&&(n[s]={...t.before[s],[t.k]:Math.round(a)},a+=i[t.size]+e)}return n}function cn(e,t){if(!ke)return;e=Math.max(0,Math.round(e)),ke.gap=e;const n=uf(e);if(t)ke.after=n,_e(n);else{for(const[o,r]of Object.entries(n)){const l=f.frames.find(c=>c.id===o);l&&(Object.assign(l,r),ee(l))}In(),Qn()}const a=m("#align-bar"),s=a.querySelector(".ab-range"),i=a.querySelector(".ab-val");s&&(s.max=Math.max(800,e*2),s.value=e),i&&document.activeElement!==i&&(i.value=e)}function Cs(){const e=m("#align-bar").querySelector(".ab-spacing");if(!e||(e.hidden=!ke,!ke))return;e.querySelector(".ab-scrub").innerHTML=ke.k==="x"?'<svg viewBox="0 0 24 24"><path d="M3 12h18M7 8l-4 4 4 4M17 8l4 4-4 4"/></svg>':'<svg viewBox="0 0 24 24"><path d="M12 3v18M8 7l4-4 4 4M8 17l4 4 4-4"/></svg>';const t=e.querySelector(".ab-range"),n=e.querySelector(".ab-val");t.max=Math.max(800,ke.gap*2),t.value=ke.gap,document.activeElement!==n&&(n.value=ke.gap),In()}const pf={left:'<path d="M4 3v18"/><rect x="7" y="6" width="11" height="4" rx="1"/><rect x="7" y="14" width="7" height="4" rx="1"/>',hcenter:'<path d="M12 3v18"/><rect x="5" y="6" width="14" height="4" rx="1"/><rect x="8" y="14" width="8" height="4" rx="1"/>',right:'<path d="M20 3v18"/><rect x="6" y="6" width="11" height="4" rx="1"/><rect x="10" y="14" width="7" height="4" rx="1"/>',top:'<path d="M3 4h18"/><rect x="6" y="7" width="4" height="11" rx="1"/><rect x="14" y="7" width="4" height="7" rx="1"/>',vcenter:'<path d="M3 12h18"/><rect x="6" y="5" width="4" height="14" rx="1"/><rect x="14" y="8" width="4" height="8" rx="1"/>',bottom:'<path d="M3 20h18"/><rect x="6" y="6" width="4" height="11" rx="1"/><rect x="14" y="10" width="4" height="7" rx="1"/>',hdist:'<path d="M4 4v16M20 4v16"/><rect x="9" y="7" width="6" height="10" rx="1"/>',vdist:'<path d="M4 4h16M4 20h16"/><rect x="7" y="9" width="10" height="6" rx="1"/>'},mf={left:"Align left (\u2325A)",hcenter:"Align horizontal centres (\u2325H)",right:"Align right (\u2325D)",top:"Align top (\u2325W)",vcenter:"Align vertical centres (\u2325V)",bottom:"Align bottom (\u2325S)",hdist:"Distribute horizontally",vdist:"Distribute vertically"};function va(){const e=m("#align-bar");if(!f||W.size<2||!k()||X){e.hidden=!0;return}if(!e.dataset.ready){e.innerHTML='<span class="ab-count"></span><span class="ab-sep"></span>'+["left","hcenter","right","|","top","vcenter","bottom","|","hdist","vdist"].map(s=>s==="|"?'<span class="ab-sep"></span>':`<button data-align="${s}" title="${mf[s]}"><svg viewBox="0 0 24 24">${pf[s]}</svg></button>`).join("")+'<span class="ab-spacing" hidden><span class="ab-sep"></span><span class="ab-scrub" title="Drag left or right to change the spacing"></span><input class="ab-range" type="range" min="0" max="800" step="1" title="Drag to spread them out or pull them closer"><label class="ab-num" title="Space between frames"><input class="ab-val" inputmode="numeric"><small>px</small></label></span>';const t=e.querySelector(".ab-range"),n=e.querySelector(".ab-val"),a=e.querySelector(".ab-scrub");t.addEventListener("input",()=>cn(+t.value,!1)),t.addEventListener("change",()=>cn(+t.value,!0)),n.addEventListener("keydown",s=>{s.stopPropagation(),s.key==="Enter"&&(cn(+n.value||0,!0),n.blur()),s.key==="Escape"&&n.blur()}),n.addEventListener("change",()=>cn(+n.value||0,!0)),a.addEventListener("pointerdown",s=>{if(!ke)return;s.preventDefault(),a.setPointerCapture(s.pointerId);const i=s.clientX,o=ke.gap,r=c=>cn(o+(c.clientX-i)*2,!1),l=()=>{a.removeEventListener("pointermove",r),a.removeEventListener("pointerup",l),cn(ke.gap,!0)};a.addEventListener("pointermove",r),a.addEventListener("pointerup",l)}),e.addEventListener("pointerdown",s=>s.stopPropagation()),e.addEventListener("click",s=>{const i=s.target.closest("[data-align]");i&&ol(i.dataset.align)}),e.dataset.ready="1"}e.querySelector(".ab-count").textContent=`${W.size} frames`,e.querySelectorAll('[data-align$="dist"]').forEach(t=>t.disabled=W.size<2),ke&&(ke.ids.length!==W.size||ke.ids.some(t=>!W.has(t)))&&(ke=null),Cs(),e.hidden=!1,In()}function In(){const e=m("#align-bar");if(e.hidden||W.size<2||!f)return;const t=[...W].map(o=>f.frames.find(r=>r.id===o)).filter(Boolean).map(qe);if(!t.length)return;const n=Gi(t),a=v.x+(n.x+n.w/2)*v.z,s=v.y+n.y*v.z-34,i=e.offsetWidth||360;e.style.left=`${Math.max(12,Math.min(a-i/2,innerWidth-i-12))}px`,e.style.top=`${Math.max(60,s-46)}px`}const ll=6,Ms=e=>[e.x,e.x+e.w/2,e.x+e.w],Es=e=>[e.y,e.y+e.h/2,e.y+e.h];function cl(e){const t=e instanceof Set?e:new Set([e]);return f.frames.filter(n=>!t.has(n.id)).map(n=>qe(n))}function zn(e,t,n){let a=null;for(const s of e)for(const i of t){const o=i-s;Math.abs(o)<=n&&(!a||Math.abs(o)<Math.abs(a.d))&&(a={d:o,at:i})}return a}function dl(e,t,n,a){const s=[],i=[e,...t],o=.5/v.z;if(n){const r=i.filter(l=>Ms(l).some(c=>Math.abs(c-n.at)<o));s.push({x1:n.at,y1:Math.min(...r.map(l=>l.y)),x2:n.at,y2:Math.max(...r.map(l=>l.y+l.h))})}if(a){const r=i.filter(l=>Es(l).some(c=>Math.abs(c-a.at)<o));s.push({x1:Math.min(...r.map(l=>l.x)),y1:a.at,x2:Math.max(...r.map(l=>l.x+l.w)),y2:a.at})}return s}function Zi(e,t){const n=cl(t),a=ll/v.z,s=zn(Ms(e),n.flatMap(Ms),a),i=zn(Es(e),n.flatMap(Es),a),o={...e,x:e.x+(s?.d||0),y:e.y+(i?.d||0)};return{dx:s?.d||0,dy:i?.d||0,guides:dl(o,n,s,i)}}function hf(e,t,n="se"){const a=cl(t),s=ll/v.z,i=a.flatMap(Ms),o=a.flatMap(Es),r={...e};let l=null,c=null;return n.includes("e")?(l=zn([e.x+e.w],i,s),l&&(r.w=e.w+l.d)):n.includes("w")&&(l=zn([e.x],i,s),l&&(r.x=e.x+l.d,r.w=e.w-l.d)),n.includes("s")?(c=zn([e.y+e.h],o,s),c&&(r.h=e.h+c.d)):n.includes("n")&&(c=zn([e.y],o,s),c&&(r.y=e.y+c.d,r.h=e.h-c.d)),{rect:r,guides:dl(r,a,l,c)}}function Ot(e){const t=m("#guides");t.innerHTML=e.map(n=>`<line x1="${n.x1}" y1="${n.y1}" x2="${n.x2}" y2="${n.y2}"/>`).join("")}const Ss=A("freeze");function Ji(e){const t=P.get(e),n=ue(e);if(!t||t.parked||!n?.documentElement||n.location.href==="about:blank")throw new Error("Bring the frame into view first, so it is loaded");const a=t.iframe.contentWindow,s=b=>{try{const M=new URL(b,n.baseURI);return M.origin===location.origin?M.pathname+M.search+M.hash:M.href}catch{return b}},i=(b,M)=>b.replace(/url\(\s*(['"]?)([^'")]+)\1\s*\)/g,(E,z,_)=>/^(data:|blob:|#)/.test(_)?E:`url("${s(new URL(_,M).href)}")`);let o="";const r=(b,M=0)=>{let E;try{E=b.cssRules}catch{b.href&&(o+=`@import url("${s(b.href)}");
|
|
95
|
+
`);return}if(b.disabled||!E)return;const z=b.media?.mediaText;z&&M===0&&b.ownerNode?.tagName==="LINK"&&(o+=`@media ${z} {
|
|
96
|
+
`);for(const _ of E)_.type===CSSRule.IMPORT_RULE&&_.styleSheet&&M<4?r(_.styleSheet,M+1):o+=i(_.cssText,b.href||n.baseURI)+`
|
|
97
|
+
`;z&&M===0&&b.ownerNode?.tagName==="LINK"&&(o+=`}
|
|
98
|
+
`)};for(const b of[...n.styleSheets,...n.adoptedStyleSheets||[]])r(b);const l=n.documentElement.cloneNode(!0),c=n.querySelectorAll("input, textarea, select"),d=l.querySelectorAll("input, textarea, select");c.forEach((b,M)=>{const E=d[M];E&&(b.tagName==="TEXTAREA"?E.textContent=b.value:b.tagName==="SELECT"?[...b.options].forEach((z,_)=>E.options[_]?.toggleAttribute("selected",z.selected)):/^(checkbox|radio)$/.test(b.type)?E.toggleAttribute("checked",b.checked):/^(password|file)$/.test(b.type)||E.setAttribute("value",b.value))});const u=n.querySelectorAll("canvas"),p=l.querySelectorAll("canvas");u.forEach((b,M)=>{const E=n.createElement("img");for(const _ of p[M].attributes)E.setAttribute(_.name,_.value);try{E.src=b.toDataURL("image/png")}catch{}const z=b.getBoundingClientRect();b.getAttribute("style")||E.setAttribute("style",`width:${z.width}px;height:${z.height}px`),p[M].replaceWith(E)});const h=n.documentElement.querySelectorAll("*"),g=l.querySelectorAll("*");h.length===g.length&&h.forEach((b,M)=>{(b.scrollTop||b.scrollLeft)&&g[M].setAttribute("data-loop-scroll",`${b.scrollLeft},${b.scrollTop}`)}),l.querySelectorAll('script, noscript, base, link[rel="stylesheet"], link[rel="preload"], link[rel="modulepreload"], link[rel="prefetch"], style').forEach(b=>b.remove()),l.querySelectorAll("*").forEach(b=>{for(const M of[...b.attributes])(/^on/i.test(M.name)||/^(href|src|action)$/i.test(M.name)&&/^\s*javascript:/i.test(M.value))&&b.removeAttribute(M.name)});let w=l.querySelector("head");w||(w=n.createElement("head"),l.prepend(w));const T=a.location.pathname+a.location.search,$=`scrollTo(${Math.round(a.scrollX)},${Math.round(a.scrollY)});document.querySelectorAll('[data-loop-scroll]').forEach(e=>{const[x,y]=e.dataset.loopScroll.split(',');e.scrollLeft=+x;e.scrollTop=+y});addEventListener('click',e=>{if(e.target.closest('a[href]'))e.preventDefault()},true);addEventListener('submit',e=>e.preventDefault(),true)`;return w.insertAdjacentHTML("afterbegin",`<meta charset="utf-8"><base href="${C(T)}"><meta name="loop-frozen" content="${Date.now()}"><style>${o.replace(/<\/style/gi,"<\\/style")}</style>`),l.querySelector("body")?.insertAdjacentHTML("beforeend",`<script>addEventListener('load',()=>{${$}})<\/script>`),`<!doctype html>
|
|
99
|
+
`+l.outerHTML}async function gf(e){const t=f.frames.find(a=>a.id===e);if(!t)return;let n;try{n=Ji(e)}catch(a){return y(a.message)}try{const a=qe(t),s=await x("POST",`/__loop/api/frames/${e}/freeze`,{html:n,from:Vn(P.get(e)),editable:!0,x:a.x+a.w+80,y:a.y});let i=null;J("Editable copy",async()=>{i=Ct(s.id)||i,await x("DELETE",`/__loop/api/frames/${s.id}`)},()=>ze(i||{frames:[s]})),f.frames.find(o=>o.id===s.id)?(Q(s.id),zt(s.id)):Ze=s.id,y("Editable copy beside it. Changes stay in the copy; ask the agent to make it real when it is right.",3400)}catch(a){y(a.message)}}async function wa(e){const t=f.frames.find(a=>a.id===e);if(!t)return;if(t.kind==="frozen")return y("This frame is already frozen");let n;try{n=Ji(e)}catch(a){return y(a.message)}try{const a=await x("POST",`/__loop/api/frames/${e}/freeze`,{html:n,from:Vn(P.get(e))});let s=null;if(J("Freeze frame",async()=>{s=Ct(a.id)||s,await x("DELETE",`/__loop/api/frames/${a.id}`)},()=>ze(s||{frames:[a]})),S)return y("Frozen copy added next to this frame");f.frames.find(i=>i.id===a.id)?(Q(a.id),zt(a.id)):Ze=a.id,y("Frozen: this copy keeps the screen as it is now")}catch(a){y(a.message)}}async function fl(e){const t=f.frames.find(n=>n.id===e);if(t?.from)try{const n=await x("POST","/__loop/api/frames",{route:t.from,name:t.name.replace(/ · frozen( \d+)?$/,""),w:t.w,h:t.h,near:t.id,dup:!0});f.frames.find(a=>a.id===n.id)?(Q(n.id),zt(n.id)):Ze=n.id}catch(n){y(n.message)}}const Et=e=>{const t=Math.min(e.w,e.h),n=Math.max(e.w,e.h);return t>=320&&t<=500&&n>=560&&n<=1e3&&n/t>=1.5||Math.abs(t-466)<=2&&Math.abs(n-678)<=2},Qi=["qwertyuiop","asdfghjkl","zxcvbnm"];function ul(e,t){const n=e.autoKb,a=Et(t)&&(!!t.keyboard||!!n);if(e.el.classList.toggle("kb-on",a),!a)return;const s=t.w>t.h,i=n==="num"?"num":"abc";let o=e.el.querySelector(".kb");if(o||(o=document.createElement("div"),o.className="kb",e.el.querySelector(".frame-body").appendChild(o)),o.dataset.kind!==i){o.dataset.kind=i;const r=l=>[...l].map(c=>`<span class="k">${c}</span>`).join("");o.innerHTML=i==="num"?[["1",""],["2","ABC"],["3","DEF"],["4","GHI"],["5","JKL"],["6","MNO"],["7","PQRS"],["8","TUV"],["9","WXYZ"],[".",null],["0",""],["\u232B",null]].reduce((l,c,d)=>((l[Math.floor(d/3)]||=[]).push(c),l),[]).map(l=>`<div class="kb-row">${l.map(([c,d])=>`<span class="k${d==null?" fn plain":""}"><b>${c}</b>${d?`<i>${d}</i>`:""}</span>`).join("")}</div>`).join(""):`<div class="kb-bar"><span>I</span><span>The</span><span>I\u2019m</span></div>
|
|
100
|
+
<div class="kb-row">${r(Qi[0])}</div><div class="kb-row r2">${r(Qi[1])}</div>
|
|
101
|
+
<div class="kb-row"><span class="k fn">\u21E7</span>${r(Qi[2])}<span class="k fn">\u232B</span></div>
|
|
102
|
+
<div class="kb-row"><span class="k fn">123</span><span class="k fn">\u263A</span><span class="k sp">space</span><span class="k fn ret">return</span></div>`}o.classList.toggle("num",i==="num"),o.classList.toggle("land",s)}function yf(e){if(!e||e.disabled||e.readOnly)return null;const t=e.tagName,n=(e.getAttribute?.("type")||"text").toLowerCase(),a=(e.getAttribute?.("inputmode")||"").toLowerCase();return a==="none"?null:t==="TEXTAREA"||e.isContentEditable?"abc":t!=="INPUT"||/^(checkbox|radio|range|button|submit|reset|file|color|date|time|datetime-local|month|week|image|hidden)$/.test(n)?null:/^(numeric|decimal|tel)$/.test(a)||/^(number|tel)$/.test(n)?"num":"abc"}function bf(e,t,n){const a=()=>{const s=f?.frames.find(o=>o.id===n);if(!s||!Et(s))return;const i=Ce?.fid===n?null:yf(e.document.activeElement);t.autoKb!==i&&(t.autoKb=i,ul(t,s),i&&setTimeout(()=>{try{e.document.activeElement?.scrollIntoView({block:"center",behavior:"smooth"})}catch{}},60),S?.fid===n&&setTimeout(()=>wt(n),80))};e.addEventListener("focusin",a),e.addEventListener("focusout",()=>setTimeout(a,0))}async function Ts(e){const t=f.frames.find(a=>a.id===e);if(!t)return;if(!Et(t))return y("The keyboard is for phone-sized frames");const n=!t.keyboard;try{await x("PATCH",`/__loop/api/frames/${e}`,{keyboard:n}),J(n?"Show keyboard":"Hide keyboard",()=>x("PATCH",`/__loop/api/frames/${e}`,{keyboard:!n}),()=>x("PATCH",`/__loop/api/frames/${e}`,{keyboard:n}))}catch(a){y(a.message)}}let S=null;const xa=(()=>{try{return new Set(JSON.parse(localStorage.getItem("loop.stageNoDevice")||"[]"))}catch{return new Set}})(),vf=[[669,951],[744,1133],[768,1024],[810,1080],[820,1180],[834,1112],[834,1194],[800,1280],[1024,1366],[1032,1376]],As=e=>{const t=Math.min(e.w,e.h),n=Math.max(e.w,e.h);return!Et(e)&&!(e.w===1280&&e.h===800)&&vf.some(([a,s])=>Math.abs(a-t)<=2&&Math.abs(s-n)<=2)},ka=e=>Et(e)||As(e),pl=e=>ka(e)&&!xa.has(e.id);let ml=0;function rt(e,t=420){const n={...v},a=performance.now(),s=++ml,i=o=>{if(s!==ml)return;const r=Math.min(1,(o-a)/t),l=r<.5?4*r*r*r:1-Math.pow(-2*r+2,3)/2;v={x:n.x+(e.x-n.x)*l,y:n.y+(e.y-n.y)*l,z:n.z+(e.z-n.z)*l},re(),r<1&&requestAnimationFrame(i)};requestAnimationFrame(i)}function dn(e){const t=typeof Rt=="function"&&Rt(e)==="split"?{...e,w:e.w*2+6}:e,n=pl(e),a=n?As(e)?34:22:0,s=P.get(e.id)?.el.querySelector(":scope > .opt-strip"),i=84+(s?s.offsetHeight+44:0)+(I?.fid===e.id?I.el.offsetHeight+18:0),o=96,l=Math.max(.04,Math.min((innerWidth-40*2)/(t.w+a*2),(innerHeight-i-o)/(t.h+a*2),2)),c=S.zoom==="100"?1:l;return{z:c,x:innerWidth/2-(t.x+t.w/2)*c,y:i+(innerHeight-i-o)/2-(t.y+t.h/2)*c}}function ht(e){const t=f.frames.find(n=>n.id===e);t&&(S||(S={prev:{...v},zoom:"fit"}),document.querySelectorAll(".frame.staged").forEach(n=>n.classList.remove("staged","device","tablet")),S.fid=e,Q(null),te(),ae(),sr(),ct(),Re(),Ve(),Jt(),G.hidden=!0,Ce&&xs(!1),Aa?.(),document.body.classList.add("staging"),Xe(),rt(dn(t)),Be&&Si(e))}function gt(){if(!S)return;I&&(I.staged=!1,ct(!0));const e=S.prev;if(document.querySelectorAll(".frame.staged").forEach(t=>t.classList.remove("staged","device","landscape","tablet")),document.querySelectorAll(".fold-deco, .frame-body > .sbar").forEach(t=>t.remove()),Us(),document.body.classList.remove("staging"),m("#stage-bar")?.remove(),S=null,eo(),me){me=null,$t();for(const t of f.frames)ee(t)}rt(e,380)}function hl(e){return!!e&&ka(e)&&(S?S.fid===e.id:Be)}function eo(){for(const[e,t]of P)try{t.iframe.contentDocument?.documentElement.classList.toggle("loop-touch",hl(f.frames.find(n=>n.id===e)))}catch{}}function to(){return[...f.frames].sort((e,t)=>Math.abs(e.y-t.y)<200?e.x-t.x:e.y-t.y)}const Ue=[{id:"landscape",name:"Landscape",w:951,h:669,rail:!0,about:"Fully open on its side: the big inner display, with the bars down the side."},{id:"portrait",name:"Portrait",w:669,h:951,about:"Fully open and upright: room for more, with normal top and bottom bars."},{id:"closed",name:"Closed",w:466,h:678,rail:!0,cam:!0,about:"The compact outer display, with the controls moved to the side."},{id:"seated",name:"Seated",w:669,h:951,seat:!0,about:"Set down half open: the content on the upright half, the controls on the half lying flat."},{id:"standing",name:"Standing",w:678,h:466,rail:!0,cam:!0,about:"Stood up like a tent: the outer display on its side, for glanceable things."}],gl={landscape:'<svg viewBox="0 0 24 24"><rect x="2.5" y="5" width="19" height="14" rx="2.4"/><path d="M12 5v14" stroke-dasharray="1.6 1.8"/></svg>',portrait:'<svg viewBox="0 0 24 24"><rect x="5" y="2.5" width="14" height="19" rx="2.4"/><path d="M5 12h14" stroke-dasharray="1.6 1.8"/></svg>',closed:'<svg viewBox="0 0 24 24"><rect x="6.5" y="3.5" width="11" height="17" rx="2.4"/><circle cx="9" cy="6" r=".9"/></svg>',seated:'<svg viewBox="0 0 24 24"><path d="M6 4h12v9H6z"/><path d="M6 13l-2.5 6.5h17L18 13"/></svg>',standing:'<svg viewBox="0 0 24 24"><path d="M12 5L4 19M12 5l8 14M3 19h18"/></svg>'},wf='<svg viewBox="0 0 24 24" aria-hidden="true"><rect x="6" y="2.5" width="12" height="19" rx="2.5"/><path d="M8.5 6h2M13.5 6h2"/></svg>',$a=()=>K.get("loop.stageSbar",!1),Hn=(e,t)=>Math.abs(e-t)<=2,On=e=>!!e&&Ue.some(t=>Hn(e.w,t.w)&&Hn(e.h,t.h)),Rn=e=>{const t=Rt(e);if(!t||!Kn())return t;const n=K.get(`loop.duoPose.${f.name}.${e.id}`,null);return Ue.some(a=>a.id===n)?n:t};function Rt(e){if(!On(e))return null;const t=Ue.filter(a=>Hn(e.w,a.w)&&Hn(e.h,a.h)),n=K.get(`loop.duoPose.${f.name}.${e.id}`,null);return(t.find(a=>a.id===n)||t[0]).id}const yl=`It is shown on the iPhone Duo, Apple's foldable iPhone. Follow Apple's guidance for it:
|
|
103
|
+
1. Two displays: the outer display when closed (466\xD7678, compact: wider and shorter than other iPhones) and the inner display when open (951\xD7669 in landscape, 669\xD7951 in portrait). It is also set down half open (seated: the inner display in portrait, folded across the middle, content on the upright half and controls on the half lying flat) and stood up like a tent (standing: the outer display on its side, 678\xD7466, for glanceable things like a clock or photos). Use a compact-width layout for the outer display and a regular-width layout for the inner one, and let the same layout expand: don't reinvent it per size.
|
|
104
|
+
2. Bars go on the side: on the outer display, and on the inner display in landscape, the status bar, Dynamic Island, toolbar and tab bar sit in one column down the right-hand side (about 56px wide), not at the top and bottom. The outer display's camera is in its top-right corner, at the top of that column, and is always there: put nothing tappable or important in that corner (move avatars, profile buttons and close buttons away from it). Keep content clear of that strip and make your navigation a vertical rail there: back or close at the top, then the main actions, then the tabs. The inner display upright keeps normal top and bottom bars.
|
|
105
|
+
3. Show one more level on the inner display when it helps (for example a list beside the selected item), but keep the same content, functions and state in every pose.
|
|
106
|
+
4. Partly open like a book, a folding region runs down the middle of the inner display: keep text and controls off it and let the layout divide into two equal halves there (an even number of columns divides cleanly). Fully open, the middle is usable.
|
|
107
|
+
5. Split View: beside another app it gets about 475\xD7669, with its controls along its own outer edge.
|
|
108
|
+
6. When it folds or changes pose, favour small adjustments over rearranging, and prefer icons over text buttons in side bars.`;async function La(e){const t=S&&f.frames.find(a=>a.id===S.fid),n=Ue.find(a=>a.id===e);if(!(!t||!n||!k())){if(K.set(`loop.duoPose.${f.name}.${t.id}`,e),Kn()){B?.api?.setPose(e),Da(),Xe();return}if(Hn(t.w,n.w)&&Hn(t.h,n.h))Xe();else{const a={w:t.w,h:t.h,x:t.x,y:t.y},s={w:n.w,h:n.h,x:Math.round(t.x+(t.w-n.w)/2),y:Math.round(t.y+(t.h-n.h)/2)},i=o=>(Object.assign(t,o),ee(t),S?.fid===t.id&&(Xe(),rt(dn(t),420)),x("PATCH",`/__loop/api/frames/${t.id}`,o).catch(r=>y(r.message)));J("Duo pose",()=>i(a),()=>i(s)),await i(s)}}}function xf(e,t){t?.el.querySelectorAll(":scope > .fold-deco").forEach(i=>i.remove()),t?.el.classList.toggle("duo",!!Rt(e));const n=Ue.find(i=>i.id===Rt(e));if(!n||!t)return;const a=document.createElement("div");a.className=`fold-deco fd-${n.id}`;const s=$a()?`<span class="fd-time">9:41</span><span class="fd-ics">${Sl}</span>`:"";a.innerHTML=`${n.rail?`<div class="fd-rail">${n.cam?'<i class="fd-cam"></i>':""}${s}</div>`:""}${n.seat?'<div class="fd-fold"></div><div class="fd-flat"></div>':""}`,t.el.appendChild(a)}function bl(e){if(ht(e),S){S.explore=!0;const t=f.frames.find(n=>n.id===e);Rt(t)!=="landscape"?La("landscape"):Xe()}}function Xe(){const e=f.frames.find(d=>d.id===S.fid);if(!e)return gt();const t=P.get(e.id),n=As(e),a=ka(e),s=pl(e);t?.el.classList.add("staged"),t?.el.classList.toggle("device",s),t?.el.classList.toggle("tablet",s&&n),t?.el.classList.toggle("landscape",e.w>e.h),eo();let i=m("#stage-bar");i||(i=document.createElement("div"),i.id="stage-bar",document.body.appendChild(i),i.addEventListener("pointerdown",d=>d.stopPropagation()),i.addEventListener("click",Mf));const o=to(),r=o.findIndex(d=>d.id===e.id),l=Rn(e),c=l&&Ue.find(d=>d.id===l);xf(e,t),oo(t,e),Zf(e,l),i.innerHTML=`
|
|
109
|
+
${l?`<div class="sb-seg"><button class="${Kn()?"on":""}" data-sb="duo-3d" title="The device in 3D">3D</button><button class="${Kn()?"":"on"}" data-sb="duo-live" title="The live screen, to click through">Live</button></div>`:""}
|
|
110
|
+
${l&&k()&&!Kn()?`<div class="sb-fold">${Ue.map(d=>`<button class="sb-btn${d.id===l?" on":""}" data-fold="${d.id}" title="${d.name} \xB7 ${d.w} \xD7 ${d.h}">${gl[d.id]}</button>`).join("")}</div>${S.explore?`<span class="sb-ask">${{landscape:"Does it work in landscape?",portrait:"Does it work in portrait?",closed:"Does it work closed?",seated:"Does it work seated?",standing:"Does it work standing?"}[c.id]}</span><button class="sb-thumb" data-sb="fold-up" title="Yes: next state">${Ns}</button><button class="sb-thumb" data-sb="fold-down" title="No: say what's off">${Bs}</button>`:`<span class="sb-fname">${c.name}</span>`}<span class="sb-sep"></span>`:l&&S.explore?`<span class="sb-ask">${{landscape:"Does it work in landscape?",portrait:"Does it work in portrait?",closed:"Does it work closed?",seated:"Does it work seated?",standing:"Does it work standing?"}[c.id]}</span><button class="sb-thumb" data-sb="fold-up" title="Yes: next pose">${Ns}</button><button class="sb-thumb" data-sb="fold-down" title="No: say what's off">${Bs}</button><span class="sb-sep"></span>`:""}
|
|
111
|
+
${Et(e)&&e.h>e.w||l?`<button class="sb-btn${$a()?" on":""}" data-sb="sbar" title="${$a()?"Hide":"Show"} the status bar">${wf}</button>`:""}
|
|
112
|
+
${a&&!l?`<button class="sb-btn${s?" on":""}" data-sb="device" title="Show it inside ${n?"an iPad":"an iPhone"}"><span class="sb-dev${e.w>e.h?" side":""}">${A(n?"tablet":"phone")}</span></button>
|
|
113
|
+
${k()?`<button class="sb-btn" data-sb="rotate" title="Turn it ${e.w>e.h?"upright":"on its side"} (R)">${$f}</button>`:""}`:""}
|
|
114
|
+
${e.kind!=="frozen"&&k()?`<button class="sb-btn" data-sb="freeze" title="Freeze a copy of it as it is now (\u21E7F)">${Ss}</button>`:""}
|
|
115
|
+
${k()&&["route","url","folder"].includes(e.kind)&&!e.image&&!e.sizeOf?`<button class="sb-btn" data-sb="sizes" title="See it at phone, tablet and desktop size, side by side">${Lf}</button>`:""}
|
|
116
|
+
${k()?'<button class="sb-fit" data-sb="fit" hidden><i></i><span>Doesn\u2019t fit</span><b>Make it fit</b></button>':""}
|
|
117
|
+
<button class="sb-btn" data-sb="export" title="Export: an image or the page's code">${jf}</button>
|
|
118
|
+
<button class="sb-exit" data-sb="exit" title="Exit stage (Esc)">${A("x")}<span>Exit</span></button>`;for(const d of[250,900,2e3])setTimeout(wl,d)}function vl(e){try{const t=P.get(e.id)?.iframe.contentDocument,n=t?.documentElement;if(!n||!t.body)return 0;const a=Math.max(n.scrollWidth,t.body.scrollWidth)-n.clientWidth;return a>4?Math.round(a):0}catch{return 0}}function wl(){const e=m("#stage-bar .sb-fit"),t=S&&f.frames.find(a=>a.id===S.fid);if(!e||!t)return;const n=f.live[t.id]||t.kind==="frozen"?0:vl(t);e.hidden=!n,e.dataset.over=n,e.title=`The page is ${n}px wider than this ${t.w}\xD7${t.h} frame. Ask the agent to make it fit this size.`}async function kf(){const e=S&&f.frames.find(s=>s.id===S.fid),t=e&&vl(e);if(!t)return wl();const n={id:Ia(),frameId:e.id,author:{name:Z.name,color:Z.color},anchor:Zn(e.id,{scope:"frame",x:0,y:0}),text:`This screen doesn\u2019t fit at ${e.w}\xD7${e.h}: the page runs ${t}px wider than the frame. Make it responsive at this size, and keep it looking the same at the sizes it already works at.`},a=Ga(n);try{const s=await x("POST","/__loop/api/comments",n);s?.id&&s.id!==n.id&&a(),m("#stage-bar .sb-fit").hidden=!0,y("Asked the agent to make it fit")}catch(s){a(),y(s.message)}}const $f='<svg viewBox="0 0 24 24" aria-hidden="true"><path d="M20.5 12a8.5 8.5 0 1 1-2.6-6.1"/><path d="M20.5 3.5v5h-5"/></svg>',Lf='<svg viewBox="0 0 24 24" aria-hidden="true"><path d="M12 15H4.5A1.5 1.5 0 0 1 3 13.5v-8A1.5 1.5 0 0 1 4.5 4h12A1.5 1.5 0 0 1 18 5.5V8"/><path d="M7.5 19.5h4.5"/><path d="M9.75 15v4.5"/><rect x="14.5" y="9.5" width="7" height="11" rx="1.8"/><path d="M17.25 18h1.5"/></svg>';async function xl(e){try{const t=await x("POST",`/__loop/api/frames/${e.id}/sizes`);gt(),setTimeout(()=>Oe(!0,[e.id,...t.frames]),450),t.existing||y("The same screen at the other sizes, live. Comment on whichever one breaks.",3e3)}catch(t){y(t.message)}}async function kl(){const e=S&&f.frames.find(i=>i.id===S.fid);if(!e||!ka(e)||!k())return;const t={w:e.w,h:e.h,x:e.x,y:e.y},n={w:e.h,h:e.w,x:Math.round(e.x+(e.w-e.h)/2),y:Math.round(e.y+(e.h-e.w)/2)},a=i=>(Object.assign(e,i),ee(e),S?.fid===e.id&&(Xe(),rt(dn(e),420)),x("PATCH",`/__loop/api/frames/${e.id}`,i).catch(o=>y(o.message))),s=i=>{const o=P.get(e.id)?.el,r=i.w>i.h?-90:90;if(!o||ti.matches)return a(i);o.classList.add("turning"),o.style.setProperty("--turn",`${r}deg`),setTimeout(()=>{o.classList.add("turned-in"),o.classList.remove("turning"),o.style.removeProperty("--turn"),a(i),requestAnimationFrame(()=>requestAnimationFrame(()=>o.classList.remove("turned-in")))},360)};J("Rotate frame",()=>s(t),()=>s(n)),s(n)}function Cf(e){const t=S&&f.frames.find(c=>c.id===S.fid);if(!t)return;const n=c=>({x:c.x+c.w/2,y:c.y+c.h/2}),a=n(t),s=e==="left"||e==="right",i=e==="right"||e==="down"?1:-1,o=f.frames.filter(c=>c.id!==t.id).map(c=>{const d=n(c);return{f:c,along:(s?d.x-a.x:d.y-a.y)*i,side:Math.abs(s?d.y-a.y:d.x-a.x)}}),l=o.filter(c=>c.along>1).sort((c,d)=>c.along+2*c.side-(d.along+2*d.side))[0]||o.sort((c,d)=>c.along+2*c.side-(d.along+2*d.side))[0];l&&ht(l.f.id)}function ru(e){if(!S)return;const t=to(),n=t.findIndex(a=>a.id===S.fid);t.length>1&&ht(t[(n+e+t.length)%t.length].id)}function Mf(e){const t=e.target.closest("[data-fold]");if(t&&S)return La(t.dataset.fold);const n=e.target.closest("[data-sb]");if(!n||!S)return;const a=f.frames.find(r=>r.id===S.fid);if(!a)return;const s=n.dataset.sb,i=to(),o=i.findIndex(r=>r.id===a.id);if(s==="exit")return gt();if(s==="export")return Vf(a,n);if(s==="duo-3d"||s==="duo-live"){Gf(s==="duo-3d");return}if(s==="sbar"){K.set("loop.stageSbar",!$a()),Xe(),oo(P.get(a.id),a);return}if(s==="fold-up"||s==="fold-down"){const r=Rn(a),l=Ue.findIndex(c=>c.id===r);if(s==="fold-down"){const c=Ue[l];io(a.id,`What's off ${c.name.toLowerCase()}?`),j.value=`${c.name} (${c.w}\xD7${c.h}): `;return}if(l===Ue.length-1){S.explore=!1,Xe(),y("Checked in every Duo state",2200);return}return La(Ue[l+1].id)}if(s==="prev"||s==="next"){const r=i[(o+(s==="next"?1:-1)+i.length)%i.length];return ht(r.id)}if(s==="device"){xa.has(a.id)?xa.delete(a.id):xa.add(a.id);try{localStorage.setItem("loop.stageNoDevice",JSON.stringify([...xa]))}catch{}return Xe(),rt(dn(a),300)}if(s==="keyboard")return Ts(a.id);if(s==="rotate")return kl();if(s==="fit")return kf();if(s==="sizes")return xl(a);if(s==="freeze")return wa(a.id);if(s==="zoom")return S.zoom=S.zoom==="fit"?"100":"fit",Xe(),rt(dn(a),320)}addEventListener("keydown",e=>{if(!S||It()||e.metaKey||e.ctrlKey)return;const t={ArrowRight:"right",ArrowLeft:"left",ArrowUp:"up",ArrowDown:"down"}[e.key];if(t&&(e.preventDefault(),Cf(t)),e.key.toLowerCase()==="r"&&!e.shiftKey&&!e.altKey){const n=f.frames.find(a=>a.id===S.fid);n&&ka(n)&&k()&&(e.preventDefault(),e.stopImmediatePropagation(),kl())}}),addEventListener("resize",()=>{if(S){const e=f.frames.find(t=>t.id===S.fid);e&&(v=dn(e),re())}});const Me=document.createElement("div");Me.id="edge",Me.hidden=!0,document.body.appendChild(Me);const $l='<svg viewBox="0 0 24 24" aria-hidden="true"><path d="M12 4v10"/><path d="M8 10.5l4 4 4-4"/><path d="M5 19h14"/></svg>';Me.innerHTML=`<button class="eg-btn eg-build" data-eg="build" data-tip="Build into the project (\u21E7\u2318B)">${$l}<span>Build</span></button><button class="eg-btn" data-eg="stage">${A("stage")}<span></span></button>`;let lt=null,fn=null,_s=!1,no=0;const je={x:-1,y:-1},Ca=52;function en(e){const t=qe(e),n=v.z;return{l:v.x+t.x*n,t:v.y+t.y*n,w:t.w*n,h:t.h*n}}function Ef(){if(!f)return null;if(S)return S.fid;if(oe||document.body.classList.contains("versions-on"))return null;for(let e=f.frames.length-1;e>=0;e--){const t=en(f.frames[e]),n=Math.max(t.t,Ca);if(je.x>=t.l-6&&je.x<=t.l+t.w+6&&je.y>=Math.max(t.t-44,0)&&je.y<=Math.min(n+110,t.t+t.h))return f.frames[e].id}return!W.size&&D||me||null}function Ps(){const e=Ef();e?(clearTimeout(fn),fn=null,lt=e):lt&&!fn&&!_s&&(fn=setTimeout(()=>{fn=null,_s||(lt=null,Ma())},380)),Ma()}let Ds=null;function ao(e,t){Ds&&Ds!==e&&P.get(Ds)?.el.style.removeProperty("--edge-room"),Ds=e,e&&P.get(e)?.el.style.setProperty("--edge-room",`${Math.max(0,Math.round(t))}px`)}function Ma(){const e=lt&&f?.frames.find(c=>c.id===lt),t=!1,n=e&&en(e);if(!e||e.shapeless||S||n.w<72||n.t+n.h<Ca+30||n.t>innerHeight-40||n.l>innerWidth-40||n.l+n.w<40){Me.hidden=!0,ao(null);return}Me.hidden=!1,Me.classList.toggle("exit",t);const a=!!f.live?.[e.id]||P.get(e.id)?.el.classList.contains("working");Me.classList.toggle("compact",!t&&(n.w<440||a&&n.w<720)),Me.querySelector('[data-eg="build"]').hidden=!(k()&&Pa(e))||n.w<260;const s=Me.querySelector('[data-eg="stage"]');$e(s.lastChild,t?"Exit stage":"Stage"),s.dataset.tip="Stage: focus on this frame (S)";const i=Me.offsetWidth,o=Me.offsetHeight,r=n.t-12*(parseFloat(getComputedStyle(document.documentElement).getPropertyValue("--lz"))||1)-o/2,l=n.l+n.w-i+(parseFloat(getComputedStyle(s).paddingRight)||0);if(r<Ca-o/2||r>innerHeight||l>innerWidth||l+i<0){Me.hidden=!0,ao(null);return}ao(e.id,i-(parseFloat(getComputedStyle(s).paddingRight)||0)+10),Me.classList.remove("inside"),Me.style.left=`${Math.round(l)}px`,Me.style.top=`${Math.round(r)}px`;for(const[c,d]of P){const u=d.el.querySelector(":scope > .opt-strip, :scope > .ver-strip");if(!u)continue;const p=f.frames.find($=>$.id===c);if(!p)continue;const h=en(p),g=u.offsetHeight,w=h.t-34-g,T=w<Ca+4?Math.min(Ca+4-w,Math.max(0,h.h-20)):0;u.style.translate=T?`0 ${T/v.z}px`:""}}addEventListener("pointermove",e=>{je.x=e.clientX,je.y=e.clientY,Ec(),no||(no=requestAnimationFrame(()=>{no=0,Ps()}))},{capture:!0,passive:!0}),Me.addEventListener("pointerenter",()=>{_s=!0,clearTimeout(fn),fn=null}),Me.addEventListener("pointerleave",()=>{_s=!1,Ps()}),Me.addEventListener("pointerdown",e=>e.stopPropagation()),Me.addEventListener("click",async e=>{if(e.target.closest('[data-eg="build"]')&<){Vs(W.size>1&&W.has(lt)?[...W]:[lt],e.target.closest("[data-eg]"));return}!e.target.closest('[data-eg="stage"]')||!lt||(S?.fid===lt?gt():ht(lt))});const qs=new Set;function Ll(e,t=0){if(!qs.has(e)){if((oe||S||Y||Ce)&&t<40)return setTimeout(()=>Ll(e,t+1),250);setTimeout(()=>{!qs.has(e)&&f.sections.some(n=>n.id===e)&&(qs.add(e),Cl(e))},t?0:500)}}function Cl(e){const t=f.sections.find(u=>u.id===e),n=t&&f.comments.find(u=>u.id===t.optionsFor),a=n&&f.frames.find(u=>u.id===n.frameId);if(!t||!a||S||Y)return;const s=Math.min(a.x,t.x),i=Math.min(a.y,t.y)-40,o=Math.max(a.x+a.w,t.x+t.w),r=Math.max(a.y+a.h,t.y+t.h),l={x:v.x+s*v.z,y:v.y+i*v.z},c={x:v.x+o*v.z,y:v.y+r*v.z};if(l.x>=0&&l.y>=50&&c.x<=innerWidth&&c.y<=innerHeight-70&&(o-s)*v.z>innerWidth*.45)return;const d=Math.min(1,(innerWidth-160)/(o-s),(innerHeight-240)/(r-i));rt({z:d,x:(innerWidth-(o-s)*d)/2-s*d,y:120+(innerHeight-240-(r-i)*d)/2-i*d},520)}function Nn(e){const t=v.z;return t<.33||e.w*t<300&&e.h*t<300}let Is={fid:null,t:0},un=null;function Sf(e,t){const n=ye&&f.sections.find(s=>s.id===ye),a=n?Bt(n).map(s=>s.id):W.size?[...W]:D?[D]:[];if(!a.length&&!n)return!1;un||={from:Object.fromEntries(a.map(s=>{const i=f.frames.find(o=>o.id===s);return[s,{x:i.x,y:i.y}]})),sec:n&&{id:n.id,x:n.x,y:n.y}};for(const s of Object.keys(un.from)){const i=f.frames.find(o=>o.id===s);i&&(i.x+=e,i.y+=t,ee(i))}return n&&un.sec&&(n.x+=e,n.y+=t,yt()),Te(),Ma(),va(),clearTimeout(un.t),un.t=setTimeout(()=>{const s=un;un=null;const i=Object.fromEntries(Object.keys(s.from).map(d=>{const u=f.frames.find(p=>p.id===d);return[d,{x:u.x,y:u.y}]})),o=s.from,r=s.sec&&f.sections.find(d=>d.id===s.sec.id),l=r&&{x:r.x,y:r.y},c=s.sec&&{x:s.sec.x,y:s.sec.y};_e(i),r&&x("PATCH",`/__loop/api/sections/${r.id}`,l).catch(()=>{}),J("Nudge",()=>Promise.all([_e(o),r&&Ft(r.id,c)]),()=>Promise.all([_e(i),r&&Ft(r.id,l)]))},400),!0}const Nt=m("#sections"),Ea=new Map;let ye=null,zs={id:null,t:0};const so=e=>({...e,...Ea.get(e.id)||{}}),Bn=(e,t)=>{const n=Math.min(t.x+t.w,e.x+e.w)-Math.max(t.x,e.x),a=Math.min(t.y+t.h,e.y+e.h)-Math.max(t.y,e.y);return n>0&&a>0&&n*a>t.w*t.h*.5};function Hs(e){for(const t of f.frames)P.get(t.id)?.el.classList.toggle("joining",!!e&&!t.parent&&Bn(e,qe(t)))}const Bt=e=>f.frames.filter(t=>Bn(e,t));function Ml(){if(!f)return;const e=v.z,t=(f.sections||[]).map(so);for(const n of f.frames){const a=P.get(n.id);if(!a)continue;const s=n.w*e,i=qe(n),o=t.some(r=>Bn(r,i)&&(i.y-r.y)*e<24);a.el.classList.toggle("narrow",s<200),a.el.classList.toggle("noname",s<34||o)}for(const n of t){const a=Nt.querySelector(`.section[data-id="${n.id}"]`);a&&(a.classList.toggle("noname",n.w*e<48),a.classList.remove("lift"))}}function io(e,t){te(),et(e,0,0),O.scope="frame",O.anchor=Zn(e,{scope:"frame",x:0,y:0});const n=m("#composer-area");n.hidden=!1,n.innerHTML=`${A("frame")}<b>${C(f.frames.find(a=>a.id===e)?.name||"Frame")}</b><span>Whole frame</span>`,n.classList.add("chip-frame"),j.placeholder=t||"What should change about this screen?",P.get(e)?.el.classList.add("whole"),vt(e),Te()}const Os=e=>Et(e)?"phone":As(e)?"tablet":e.w>=1e3?"desktop":"other",El={phone:"phone",tablet:"tablet",desktop:"desktop",other:"custom"};function Tf(e,t){return[...f.comments].reverse().find(n=>n.frameId===e.id&&!n.parentId&&n.text.startsWith(Rs)&&n.createdAt>=t.at)}function Af(e,t){const n=`loop.respFrame.${f.name}.${t.id}`,a=k()&&K.get(n,null);let s=e.el.querySelector(":scope > .resp-note");const i=a&&Tf(t,a),o=i&&xn(i.id),r=o==="working"||o==="queued"||!!f.live[t.id],l=!a||a.off?null:r&&i?"busy":o==="done"?a.rated?null:"ask":i||Os(t)===a.from.cls?null:"offer";if(!l){s?.remove();return}s||(s=document.createElement("div"),s.className="sec-resp resp-note",s.innerHTML=`<span class="sr-q">Not looking right?</span><span class="sr-busy">Making it responsive\u2026</span><button class="sr-go">Make it responsive</button><span class="sr-ready">Ready for every Duo state</span><button class="sr-explore">Explore the states</button><span class="sr-ask">Did that fix it?</span><button class="sr-thumb" data-v="up" title="Yes, it works now">${Ns}</button><button class="sr-thumb" data-v="down" title="Not yet: say what's still off">${Bs}</button><button class="sr-x" title="Dismiss">${A("x")}</button>`,e.el.appendChild(s),s.addEventListener("pointerdown",c=>c.stopPropagation()),s.addEventListener("click",async c=>{c.stopPropagation();const d=f.frames.find(p=>p.id===t.id),u=K.get(n,null);if(!(!d||!u)){if(c.target.closest(".sr-go"))try{await x("POST","/__loop/api/comments",{frameId:d.id,anchor:{scope:"frame",x:24,y:24},text:`${Rs} It was designed as a ${El[u.from.cls]} screen at ${u.from.w}\xD7${u.from.h}, and this frame is now a ${El[Os(d)]} screen at ${d.w}\xD7${d.h}. Re-lay it out so it works well at this size: same content and copy, nothing overflowing, clipped or cramped, type, spacing and tap targets suited to the device, navigation and grids adapted to the width. Keep it working at the other sizes too.${On(d)?` ${yl}`:""} Take a screenshot to check before you finish.`}),y("Making it responsive at this size",2200)}catch(p){y(p.message)}else if(c.target.closest(".sr-explore"))K.set(n,{...u,rated:"explored"}),bl(d.id);else if(c.target.closest(".sr-x"))K.set(n,{...u,off:!0});else if(c.target.closest('[data-v="up"]'))K.set(n,{...u,rated:"up",off:!0}),y("Glad it works",1400);else if(c.target.closest('[data-v="down"]'))K.set(n,{...u,rated:"down"}),io(d.id,"What still looks off at this size?");else return;ee(d)}})),s.dataset.mode=l==="ask"&&On(t)?"explore":l}const Sl='<svg class="sb-sig" viewBox="0 0 18 12" aria-hidden="true"><rect x="0" y="8" width="3" height="4" rx=".8"/><rect x="5" y="5.5" width="3" height="6.5" rx=".8"/><rect x="10" y="3" width="3" height="9" rx=".8"/><rect x="15" y="0" width="3" height="12" rx=".8"/></svg><svg class="sb-wifi" viewBox="0 0 16 12" aria-hidden="true"><path d="M8 2.3c2.4 0 4.6.9 6.3 2.5l1.2-1.3A10.8 10.8 0 0 0 8 .5C5.1.5 2.5 1.6.5 3.5l1.2 1.3A9.1 9.1 0 0 1 8 2.3zm0 3.6c1.4 0 2.7.5 3.7 1.4l1.2-1.3A7.2 7.2 0 0 0 8 4.1c-1.8 0-3.5.7-4.9 1.9l1.2 1.3c1-.9 2.3-1.4 3.7-1.4zM8 9.4l1.9 2-1.9 2-1.9-2 1.9-2z" transform="translate(0 -1.4)"/></svg><span class="sb-bat"><i></i></span>';function oo(e,t){const n=typeof Rt=="function"&&Ue.find(l=>l.id===Rt(t)),a=!!S&&S.fid===t.id&&$a()&&(n&&!n.rail||!n&&Et(t)&&t.h>t.w)&&!t.image,s=e?.el.querySelector(".frame-body");let i=s?.querySelector(":scope > .sbar");if(!a){i?.remove();return}!i&&s&&(i=document.createElement("div"),i.className="sbar",i.innerHTML=`<b>9:41</b><span class="sb-r">${Sl}</span>`,s.appendChild(i));const o=Date.now();if(o-(e.sbarAt||0)<1200)return;e.sbarAt=o;let r=!1;try{let c=e.iframe.contentDocument?.elementFromPoint(t.w/2,27);for(;c;){const d=getComputedStyle(c).backgroundColor,u=/rgba?\(([\d.]+),\s*([\d.]+),\s*([\d.]+)(?:,\s*([\d.]+))?/.exec(d);if(u&&(u[4]===void 0||+u[4]>.5)){r=.299*u[1]+.587*u[2]+.114*u[3]<140;break}c=c.parentElement}}catch{}i.classList.toggle("on-dark",r)}const pn=e=>f.frames.filter(t=>t.sizeOf===e.sizesOf).sort((t,n)=>t.x-n.x);function Tl(e,t){const n=!!(t.sizeOf&&!f.live[t.id]&&f.frames.some(i=>i.sizeOf===t.sizeOf&&i.id!==t.id&&f.live[i.id])),a=e.el.querySelector(".areas");let s=a?.querySelector(":scope > .mirror-work");n&&!s&&a?(s=document.createElement("div"),s.className="area working whole show mirror-work",a.appendChild(s),ni()):!n&&s&&s.remove()}const Rs="Make this screen responsive.",Ns='<svg viewBox="0 0 24 24" aria-hidden="true"><path d="M7.5 10.5v9H5a1.5 1.5 0 0 1-1.5-1.5v-6A1.5 1.5 0 0 1 5 10.5h2.5z"/><path d="M7.5 10.5l3.6-6.6a1.7 1.7 0 0 1 3.1 1.2l-.7 4.4h4.8a2 2 0 0 1 2 2.3l-1 6.2a2 2 0 0 1-2 1.5H7.5"/></svg>',Bs='<svg viewBox="0 0 24 24" aria-hidden="true" style="transform:scaleY(-1)"><path d="M7.5 10.5v9H5a1.5 1.5 0 0 1-1.5-1.5v-6A1.5 1.5 0 0 1 5 10.5h2.5z"/><path d="M7.5 10.5l3.6-6.6a1.7 1.7 0 0 1 3.1 1.2l-.7 4.4h4.8a2 2 0 0 1 2 2.3l-1 6.2a2 2 0 0 1-2 1.5H7.5"/></svg>';function Al(e,t){const n=(f.sections||[]).find(r=>r.id===e);if(!n)return;const a=Bt(n);te(),Sa(null);const s=n.x+18,i=n.y+52;et(le,s,i,"canvas"),O.scope="canvas",O.anchor={scope:"canvas",wx:s,wy:i,near:a.map(r=>r.name),section:{id:n.id,name:n.name}};const o=m("#composer-area");o.hidden=!1,o.classList.add("chip-frame"),o.innerHTML=`${A("frame")}<b>${C(n.name)}</b><span>Whole section \xB7 ${a.length} frame${a.length===1?"":"s"}</span>`,j.placeholder=t||"What should change across these screens?",Nt.querySelector(`.section[data-id="${n.id}"]`)?.classList.add("whole"),vt(le),Te()}function _f(e){const t=f.frames.find(a=>a.id===e.sizesOf),n=pn(e);return`${Rs} It doesn't hold up at every size yet: it's shown at ${n.map(a=>`${a.w}\xD7${a.h} (frame ${a.id})`).join(", ")} in the "${e.name}" section${t?`, and at ${t.w}\xD7${t.h} in "${t.name}" (frame ${t.id})`:""}. Fix the layout so it works at every size from phone to desktop: nothing overflowing, clipped or cramped, type and spacing scaled sensibly, navigation and grids adapted to the width. They all show the same files, so change them once.${n.some(On)?` ${yl}`:""} Take a screenshot of each size to check before you finish.`}const _l=e=>{const t=new Set(pn(e).map(n=>n.id));return[...f.comments].reverse().find(n=>t.has(n.frameId)&&!n.parentId&&n.text.startsWith(Rs))};async function Pf(e){const t=(f.sections||[]).find(a=>a.id===e),n=t&&pn(t)[0];if(!(!n||!k()))try{await x("POST","/__loop/api/comments",{frameId:n.id,text:_f(t),anchor:{scope:"frame",x:24,y:24}}),y("Making it responsive at every size",2200)}catch(a){y(a.message)}}function yt(){const e=f.sections||[],t=new Set(e.map(n=>n.id));Nt.querySelectorAll(".section").forEach(n=>{t.has(n.dataset.id)||n.remove()}),ye&&!t.has(ye)&&(ye=null);for(const n of e){const a=so(n);let s=Nt.querySelector(`.section[data-id="${a.id}"]`);if(!s){s=document.createElement("div"),s.className="section",s.dataset.id=a.id,s.innerHTML=`<div class="sec-label"><span class="sec-name"></span><button class="sec-more" title="Section options"><svg viewBox="0 0 16 16" aria-hidden="true"><circle cx="3.5" cy="8" r="1.3"/><circle cx="8" cy="8" r="1.3"/><circle cx="12.5" cy="8" r="1.3"/></svg></button></div>${["n","s","e","w","ne","nw","se","sw"].map(d=>`<div class="srz rz-${d}" data-dir="${d}"></div>`).join("")}`,Nt.appendChild(s);const l=s.querySelector(".sec-more"),c=a.id;l.addEventListener("pointerdown",d=>d.stopPropagation()),l.addEventListener("click",d=>{d.stopPropagation(),If(c,l)})}Object.assign(s.style,{left:`${a.x}px`,top:`${a.y}px`,width:`${a.w}px`,height:`${a.h}px`}),s.style.setProperty("--sw",`${a.w}px`);const i=s.querySelector(".sec-name");i.classList.contains("editing-name")||$e(i,a.name),s.classList.toggle("selected",ye===a.id);const o=a.optionsFor&&f.comments.find(l=>l.id===a.optionsFor);s.classList.toggle("making",!!o&&(xn(o.id)==="working"||f.frames.some(l=>l.building&&l.optionOf?.cid===o.id)));let r=s.querySelector(":scope > .sec-resp");if(a.sizesOf&&k()&&f.frames.some(l=>l.sizeOf===a.sizesOf)){const l=_l(a),c=l&&xn(l.id),d=c==="working"||c==="queued"||pn(a).some(g=>f.live[g.id]),u=K.get(`loop.respOff.${f.name}.${a.id}`,!1),p=l&&K.get(`loop.respRated.${f.name}.${l.id}`,!1),h=u?null:d?"busy":c==="done"?p?null:"ask":"offer";h?(r||(r=document.createElement("div"),r.className="sec-resp",r.innerHTML=`<span class="sr-q">Not looking right?</span><span class="sr-busy">Making it responsive\u2026</span><button class="sr-go">Make it responsive</button><span class="sr-ask">Did that fix it?</span><button class="sr-thumb" data-v="up" title="Yes, it works now">${Ns}</button><button class="sr-thumb" data-v="down" title="Not yet: say what's still off">${Bs}</button><button class="sr-fold" title="Try the iPhone Duo held each way, on stage">Duo states</button><button class="sr-x" title="Dismiss">${A("x")}</button>`,s.appendChild(r),r.addEventListener("pointerdown",g=>g.stopPropagation()),r.addEventListener("click",g=>{g.stopPropagation();const w=(f.sections||[]).find($=>$.id===a.id),T=w&&_l(w);if(g.target.closest(".sr-fold")){const $=w&&pn(w).find(On);$&&bl($.id);return}if(g.target.closest(".sr-go"))Pf(a.id);else if(g.target.closest(".sr-x"))K.set(`loop.respOff.${f.name}.${a.id}`,!0);else if(g.target.closest('[data-v="up"]'))T&&K.set(`loop.respRated.${f.name}.${T.id}`,"up"),K.set(`loop.respOff.${f.name}.${a.id}`,!0),y("Glad it works",1400);else if(g.target.closest('[data-v="down"]'))T&&K.set(`loop.respRated.${f.name}.${T.id}`,"down"),Al(a.id,"What still looks off? Say which size and what's wrong");else return;yt()})),r.dataset.mode=h,r.classList.toggle("has-fold",pn(a).some(On))):s.querySelector(":scope > .sec-resp")?.remove()}else s.querySelector(":scope > .sec-resp")?.remove()}for(const n of f.frames)if(n.sizeOf){const a=P.get(n.id);a&&Tl(a,n)}Ml()}function Sa(e){(D||W.size||me)&&Q(null),ye=e,yt()}function Pl(e,t){const n=f.sections.find(a=>a.id===e);oe={type:"smove",sid:e,sx:t.clientX,sy:t.clientY,x0:n.x,y0:n.y,moved:!1,from:Object.fromEntries(Bt(n).map(a=>[a.id,{x:a.x,y:a.y}]))},q.classList.add("dragging"),q.setPointerCapture(t.pointerId)}function Df(e,t){const n=f.sections.find(a=>a.id===e);oe={type:"sresize",sid:e,dir:t.target.dataset.dir||"se",sx:t.clientX,sy:t.clientY,x0:n.x,y0:n.y,w:n.w,h:n.h},q.classList.add("dragging"),q.setPointerCapture(t.pointerId)}function Ft(e,t){const n=f.sections.find(a=>a.id===e);return n&&(Object.assign(n,t),yt()),x("PATCH",`/__loop/api/sections/${e}`,t)}async function qf(e){try{const t=await x("POST","/__loop/api/sections",e);f.sections.find(n=>n.id===t.id)||f.sections.push(t),J("Add section",()=>x("DELETE",`/__loop/api/sections/${t.id}`),()=>ze({sections:[t]})),Sa(t.id)}catch(t){y(t.message)}}const be=document.createElement("div");be.id="sec-menu",be.className="menu",be.hidden=!0,document.body.appendChild(be);const Dl=e=>e.sizesOf?[e.sizesOf]:Bt(e).map(t=>t.id).filter(t=>Pa(f.frames.find(n=>n.id===t)));function ql(e){const t=f.sections.find(a=>a.id===e);if(!t)return;const n=Dl(t);n.length&&Vs(n,null,t.sizesOf?`It has to work at every size in "${t.name}": ${pn(t).map(a=>`${a.w}\xD7${a.h}`).join(", ")}.`:"")}function If(e,t){if(!be.hidden&&be._for===e){be.hidden=!0;return}const n=f.sections.find(l=>l.id===e);if(!n||!k())return;const a=Bt(n).length,s=`${a} frame${a===1?"":"s"}`;be._for=e,be.innerHTML=(a&&Dl(n).length?`<button class="menu-item" data-sm="build"><span><b>Build into project\u2026</b><small>${n.sizesOf?"The screen, working at every size here":`All ${s}, built together`} \xB7 ${de.shift}${de.cmd}B</small></span></button>`:"")+(a?`<button class="menu-item" data-sm="keep"><span><b>Unsection</b><small>Its ${s} stay${a===1?"s":""} on the canvas \xB7 ${de.shift}${de.cmd}S</small></span></button>
|
|
119
|
+
<button class="menu-item danger" data-sm="all"><span><b>Delete section and its ${s}</b><small>Everything inside it goes too</small></span></button>`:'<button class="menu-item" data-sm="keep"><span><b>Delete section</b><small>It has no frames in it</small></span></button>'),be.hidden=!1;const i=t.getBoundingClientRect(),o=be.offsetWidth,r=be.offsetHeight;be.style.left=`${Math.round(Math.max(12,Math.min(i.left,innerWidth-o-12)))}px`,be.style.top=`${Math.round(i.bottom+6+r>innerHeight-12?Math.max(12,i.top-r-6):i.bottom+6)}px`}be.addEventListener("pointerdown",e=>e.stopPropagation()),be.addEventListener("click",e=>{const t=e.target.closest("[data-sm]");if(!t)return;const n=be._for;if(be.hidden=!0,t.dataset.sm==="build")return ql(n);(t.dataset.sm==="all"?Il(n):Fs(n)).catch(a=>y(a.message))}),addEventListener("pointerdown",e=>{!be.hidden&&!e.target.closest("#sec-menu, .sec-more")&&(be.hidden=!0)},!0),addEventListener("keydown",e=>{e.key==="Escape"&&!be.hidden&&(be.hidden=!0,e.stopPropagation())},!0);async function Il(e){const t=f.sections.find(o=>o.id===e);if(!t)return;const n={...t},a=Bt(t).map(o=>o.id),s=a.map(Ct).filter(Boolean),i=()=>Promise.all([...a.map(o=>x("DELETE",`/__loop/api/frames/${o}`).catch(()=>{})),x("DELETE",`/__loop/api/sections/${e}`).catch(()=>{})]);ye=null,await i(),J("Delete section and its frames",()=>ze({frames:s.flatMap(o=>o.frames),comments:s.flatMap(o=>o.comments),sections:[n]}),i),y(`Deleted \u201C${n.name}\u201D and ${a.length} frame${a.length===1?"":"s"} \xB7 \u2318Z to undo`,2800)}async function Fs(e){const t=f.sections.find(a=>a.id===e);if(!t)return;const n={...t};ye=null,await x("DELETE",`/__loop/api/sections/${e}`),J("Delete section",()=>ze({sections:[n]}),()=>x("DELETE",`/__loop/api/sections/${e}`)),y(`Removed \u201C${n.name}\u201D (its frames stay) \xB7 \u2318Z to undo`,2600)}function zl(e){const t=Nt.querySelector(`.section[data-id="${e}"] .sec-name`),n=f.sections.find(a=>a.id===e);!t||!n||_o(t,n.name,a=>{if(a){const s=n.name;Ft(e,{name:a}),J("Rename section",()=>Ft(e,{name:s}),()=>Ft(e,{name:a}))}ye===e&&(ye=null,yt())})}let I=null;const Fn=e=>{const t=Ws(e);return t.length?[...t,{id:"",now:!0,label:t[t.length-1].last,at:Date.now(),thumb:null}]:[]};function ro(e,t){if(I?.fid===e&&t==null)return ct();ct();const n=P.get(e),a=f.frames.find(r=>r.id===e);if(!n||!a||!Fn(e).length)return;Y&&mn(),zf(e),ae(),Re();const s=S?.fid===e;ht(e);const i=document.createElement("div");i.className="ver-strip top",i.innerHTML='<div class="vt-row"></div><div class="vt-acts"></div>',document.body.appendChild(i),I={fid:e,pin:t??null,hover:null,now:null,el:i,key:"",akey:"",back:null,staged:!s};const o=i.querySelector(".vt-row");i.addEventListener("pointerdown",r=>r.stopPropagation()),o.addEventListener("wheel",r=>{(Math.abs(r.deltaX)>Math.abs(r.deltaY)||r.shiftKey)&&r.stopPropagation()},{passive:!0}),i.addEventListener("click",r=>{const l=r.target.closest("[data-vs]"),c=r.target.closest("[data-v]");if(l)return Hf(l.dataset.vs);c&&(I.pin=c.dataset.v===""||I.pin===c.dataset.v?null:c.dataset.v,I.hover=null,Wn(),Ta())}),Wn(),Ta(),o.scrollLeft=o.scrollWidth,rt(dn(a)),x("POST",`/__loop/api/frames/${e}/versions`).then(r=>{I?.el===i&&(I.now=r.now,Wn())}).catch(()=>{})}function lu(){const e=f.frames.find(o=>o.id===I.fid);if(!e)return;const t=en(e),n=64+I.el.offsetHeight+44,a=t.l<12||t.l+Math.min(t.w,I.el.offsetWidth)>innerWidth-12;if(t.t>=n&&t.t<innerHeight-160&&!a)return;const s=v.z,i={z:s,x:a?Math.max(24,(innerWidth-e.w*s)/2)-e.x*s:v.x,y:n-e.y*s};I.back={from:{...v},to:i},rt(i,320)}function zf(e){const t=V&&f.comments.find(n=>n.id===V);t&&t.frameId!==e&&te()}function Wn(){if(!I)return;const{fid:e,el:t}=I,n=f.frames.find(d=>d.id===e),a=Fn(e);if(!n||!a.length)return ct();I.pin&&!a.some(d=>d.id===I.pin)&&(I.pin=null);const s=n.w/n.h,i=52,o=Math.round(Math.min(104,Math.max(32,i*s))),r=a.map((d,u)=>{const p=d.now?I.now:d.thumb;return`<button class="vt${(d.now?!I.pin:I.pin===d.id)?" on":""}" data-v="${d.id}"><span class="vt-img" style="width:${o}px;height:${i}px">${p?`<img src="${C(p)}" alt="" draggable="false">`:""}</span><span class="vt-n">${u+1}</span></button>`}).join(""),l=t.querySelector(".vt-row");if(I.key!==r){const d=l.scrollLeft;I.key=r,l.innerHTML=r,l.scrollLeft=d}const c=I.pin&&k()?`<button class="vt-go" data-vs="back" title="Go back to this version (the one you are on is kept)">${A("undo")}<span>Go back</span></button><button class="vt-btn" data-vs="dup" title="Make this version its own frame">${aa.copy}</button>`:"";if(I.akey!==c){I.akey=c;const d=t.querySelector(".vt-acts");d.innerHTML=c,d.hidden=!c}Hl(),Ma()}const cu=A("layers");function Hl(){if(!I)return;const e=Fn(I.fid),t=I.hover!=null?I.hover:I.pin,n=t?e.findIndex(o=>o.id===t):e.length-1,a=e[n];if(!a)return;const s=`<b>${a.now?"Now":`v${n+1}`}</b><span>${C(a.label||"")}</span>${a.now?"":`<time>${on(a.at)}</time>`}`,i=I.el.querySelector(".vt-cap");i&&i._h!==s&&(i._h=s,i.innerHTML=s,i.title=a.label||"")}function Ta(){if(!I)return;Hl();const{fid:e}=I,t=P.get(e),n=f.frames.find(p=>p.id===e);if(!t||!n)return;const a=I.hover!=null?I.hover:I.pin,s=t.el.querySelector(".frame-body");let i=s.querySelector(":scope > .ver-prev");const o=a?Fn(e).find(p=>p.id===a):null;if(t.el.classList.toggle("previewing",!!o),!o){i&&(i.classList.remove("on"),setTimeout(()=>{i.classList.contains("on")||i.remove()},180));return}i||(i=document.createElement("div"),i.className="ver-prev",i.innerHTML='<img alt="" draggable="false"><iframe title=""></iframe>',s.appendChild(i),i.offsetWidth),i.classList.add("on");const r=i.querySelector("img"),l=i.querySelector("iframe"),c=`/__loop/hist/${o.id}/${encodeURIComponent(n.entry||"index.html")}`;o.thumb?(r.getAttribute("src")!==o.thumb&&(r.src=o.thumb),r.hidden=!1):r.hidden=!0;const d=I.pin===o.id,u=d||!o.thumb;i.classList.toggle("live",d),u?l.dataset.src!==c&&(l.dataset.src=c,l.classList.remove("ready"),i.classList.add("loading"),l.onload=()=>{l.classList.add("ready"),i.classList.remove("loading")},l.src=c):(i.classList.remove("loading"),l.dataset.src&&(l.dataset.src="",l.classList.remove("ready"),l.src="about:blank")),i.classList.toggle("bare",!o.thumb)}function ct(e){if(!I)return;const{fid:t,el:n,back:a,staged:s}=I;I=null,n.remove(),s&&S?.fid===t&&!e&&setTimeout(()=>{I||gt()},0);const i=P.get(t);i?.el.classList.remove("previewing"),i?.el.querySelector(".frame-body > .ver-prev")?.remove(),a&&!e&&Math.abs(v.x-a.to.x)<2&&Math.abs(v.y-a.to.y)<2&&Math.abs(v.z-a.to.z)<.004&&rt(a.from,300)}async function Hf(e){if(!I)return;const{fid:t,pin:n}=I,a=Fn(t),s=a.findIndex(o=>o.id===n),i=f.frames.find(o=>o.id===t);if(e==="close")return ct();if(e==="stack")return ct(!0),Of(t,n);if(!(s<0))try{if(e==="back")await x("POST",`/__loop/api/frames/${t}/versions/restore`,{id:n}),ct(),y("Back to that version. The one you were on is kept.",3200);else if(e==="dup"){const o=await x("POST",`/__loop/api/frames/${t}/versions/duplicate`,{id:n,name:`${i?.name||"Frame"} \xB7 v${s+1}`});ct(!0),f.frames.find(r=>r.id===o.id)?(Q(o.id),zt(o.id)):Ze=o.id,y("That version is now its own frame")}}catch(o){y(o.message)}}addEventListener("keydown",e=>{if(!I||Y||It()||e.metaKey||e.ctrlKey)return;if(e.key==="Escape"){e.stopPropagation(),e.preventDefault(),I.pin?(I.pin=null,Wn(),Ta()):ct();return}if(e.key!=="ArrowLeft"&&e.key!=="ArrowRight")return;e.stopPropagation(),e.preventDefault();const t=Fn(I.fid),n=I.pin?t.findIndex(o=>o.id===I.pin):t.length-1,a=t[Math.max(0,Math.min(t.length-1,n+(e.key==="ArrowRight"?1:-1)))];I.pin=a.now?null:a.id,I.hover=null,Wn(),Ta();const s=I.el.querySelector(".vt-row"),i=s.querySelector(".vt.on");i&&(s.scrollLeft=Math.max(0,Math.min(i.offsetLeft-(s.clientWidth-i.offsetWidth)/2,s.scrollWidth)))},!0);let Y=null;function Ws(e){const t=f.frames.find(a=>a.id===e),n=[...f.comments.filter(a=>a.frameId===e&&a.snapshot&&!a.snapBlank&&!a.local&&a.status!=="working"&&a.status!=="queued").map(a=>({id:a.id,at:a.startedAt||a.createdAt,thumb:a.snapThumb,what:a.kind==="create"?"Created":a.text})),...(t?.restores||[]).map(a=>({id:a.id,at:a.at,thumb:a.thumb,what:a.what||"Went back to an earlier version"}))].sort((a,s)=>a.at-s.at);return n.map((a,s)=>({id:a.id,thumb:a.thumb,at:s?n[s-1].at:a.at,label:s?n[s-1].what:"Original",last:n[n.length-1].what}))}function Of(e,t){const n=f.frames.find(b=>b.id===e),a=n&&Ws(e).slice(-11);if(!n||!a.length||Y)return;S&>(),te(),ae(),Re(),Q(null),sr(),ct(!0);const s=en(n),i=132,o=96,r=Math.min((innerWidth-200)/n.w,(innerHeight-i-o)/n.h,1.2),l=n.w*r,c=n.h*r,d=(innerWidth-l)/2,u=i+(innerHeight-i-o-c)/2,p=[...a,{id:"",now:!0,label:a[a.length-1].last,at:Date.now(),thumb:null}].reverse(),h=t?Math.max(0,p.findIndex(b=>b.id===t)):0,g=document.createElement("div");g.id="versions",g.innerHTML=`<div class="vs-rig" style="left:${d}px;top:${u}px;width:${l}px;height:${c}px">
|
|
120
|
+
${p.map((b,M)=>`<div class="vs-layer${M===h?" front":""}" data-i="${M}">${b.thumb?`<img src="${C(b.thumb)}" alt="" draggable="false">`:""}</div>`).join("")}
|
|
109
121
|
<div class="vs-live"><iframe title="" style="width:${n.w}px;height:${n.h}px;transform:scale(${r})"></iframe></div></div>
|
|
110
|
-
<div class="vs-bar"></div>`,document.body.appendChild(g),document.body.classList.add("versions-on"),
|
|
122
|
+
<div class="vs-bar"></div>`,document.body.appendChild(g),document.body.classList.add("versions-on"),Y={fid:e,layers:p,el:g,at:h,liveT:null};const w=g.querySelector(".vs-rig");w.style.transform=`translate(${s.l-d}px, ${s.t-u}px) scale(${s.w/l})`,requestAnimationFrame(()=>requestAnimationFrame(()=>{Y?.el===g&&(w.style.transform="",g.classList.add("open"),lo())})),x("POST",`/__loop/api/frames/${e}/versions`).then(b=>{!Y||Y.el!==g||(b.now&&Nl(0,b.now),Rl())}).catch(b=>{Y?.el===g&&(Y.failed=b.message,g.classList.add("failed"),Ol())}),g.addEventListener("pointerdown",b=>b.stopPropagation());let T=0,$=0;g.addEventListener("wheel",b=>{b.preventDefault(),b.stopPropagation(),T+=Math.abs(b.deltaY)>=Math.abs(b.deltaX)?b.deltaY:b.deltaX;const M=performance.now();Math.abs(T)>40&&M-$>170&&(js(T>0?1:-1),T=0,$=M)},{passive:!1}),g.addEventListener("click",b=>{const M=b.target.closest("[data-vc]");if(M)return Rf(M.dataset.vc);if(b.target.closest(".vs-bar, .vs-live"))return;const E=b.target.closest(".vs-layer");if(E){+E.dataset.i!==Y.at&&(Y.at=+E.dataset.i,lo());return}mn()})}function js(e){if(!Y)return;const t=Math.max(0,Math.min(Y.layers.length-1,Y.at+e));t!==Y.at&&(Y.at=t,lo())}function lo(){if(!Y)return;const{el:e,layers:t,at:n,fid:a}=Y,s=f.frames.find(c=>c.id===a);e.querySelectorAll(".vs-layer").forEach(c=>{const d=+c.dataset.i-n,u=d<0||d>3;c.classList.toggle("front",d===0),c.classList.toggle("gone",u),c.style.transform=d<0?"translate3d(0, 48px, 260px)":`translate3d(0, ${-d*22}px, ${-d*150}px)`,c.style.opacity=u?"0":"1",c.style.filter=d>0&&!u?`brightness(${(1-d*.09).toFixed(2)})`:"",c.style.zIndex=String(100-Math.abs(d))}),Ol();const i=e.querySelector(".vs-live"),o=i.querySelector("iframe"),r=t[n];if(i.classList.remove("ready"),clearTimeout(Y.liveT),!s||!r)return;const l=r.now?`/__loop/f/${s.id}/${encodeURIComponent(s.entry||"index.html")}?_v=${Date.now()}`:`/__loop/hist/${r.id}/${encodeURIComponent(s.entry||"index.html")}`;Y.liveT=setTimeout(()=>{Y?.el!==e||Y.at!==n||(o.onload=()=>{Y?.el===e&&Y.at===n&&i.classList.add("ready")},o.src=l)},460)}function Ol(){if(!Y)return;const{el:e,layers:t,at:n}=Y,a=t.length,s=t[n],i=s.now?"Now":`v${a-n}`;e.querySelector(".vs-bar").innerHTML=`
|
|
111
123
|
<button class="sb-btn" data-vc="older" title="Older version (\u2190)" ${n>=a-1?"disabled":""}>${A("left")}</button>
|
|
112
|
-
<div class="vs-pos"><b>${
|
|
124
|
+
<div class="vs-pos"><b>${i}</b><span>${a-n} of ${a}</span></div>
|
|
113
125
|
<button class="sb-btn" data-vc="newer" title="Newer version (\u2192)" ${n<=0?"disabled":""}>${A("right")}</button>
|
|
114
126
|
<span class="sb-sep"></span>
|
|
115
|
-
<div class="vs-what" title="${
|
|
116
|
-
${
|
|
127
|
+
<div class="vs-what" title="${C(s.label||"")}"><span>${Y.failed?`The pictures could not be made (${C(Y.failed)})`:C(s.label||"")}</span>${s.now?"":`<time>${on(s.at)}</time>`}</div>
|
|
128
|
+
${k()&&!s.now?`<span class="sb-sep"></span>
|
|
117
129
|
<button class="sb-tog" data-vc="restore" title="Go back to this version (the one you are on is kept)">${A("undo")}<span>Go back to it</span></button>
|
|
118
130
|
<button class="sb-btn" data-vc="duplicate" title="Make this version its own frame on the canvas">${A("copy")}</button>`:""}
|
|
119
131
|
<span class="sb-sep"></span>
|
|
120
|
-
<button class="sb-btn" data-vc="exit" title="Close (esc)">${A("x")}</button>`}async function
|
|
121
|
-
<div class="sc-grid">${
|
|
122
|
-
<div class="sc-tips"><div class="sc-group">Tips</div><button class="sc-tip" data-tip="deep"><span><b>Go straight to it</b>Hold \u2318 to pick whatever is under the pointer, however deep</span><em>Show</em></button></div></div>`,document.body.appendChild(t),t.querySelector('[data-tip="deep"]').addEventListener("click",()=>{t.hidden=!0,
|
|
132
|
+
<button class="sb-btn" data-vc="exit" title="Close (esc)">${A("x")}</button>`}async function Rf(e){if(!Y)return;const t=Y.at,n=Y.layers[t],a=Y.layers.length,s=Y.fid,i=f.frames.find(o=>o.id===s);if(e==="exit")return mn();if(e==="older")return js(1);if(e==="newer")return js(-1);if(!(!n||n.now))try{if(e==="duplicate"){const o=await x("POST",`/__loop/api/frames/${s}/versions/duplicate`,{id:n.id,name:`${i?.name||"Frame"} \xB7 v${a-t}`});mn(!0),f.frames.find(r=>r.id===o.id)?(Q(o.id),zt(o.id)):Ze=o.id,y(`v${a-t} is now its own frame`)}else e==="restore"&&(await x("POST",`/__loop/api/frames/${s}/versions/restore`,{id:n.id}),mn(),y(`Back to v${a-t}. The version you were on is kept.`,3200))}catch(o){y(o.message)}}function Rl(){if(!Y)return;const e=Ws(Y.fid);Y.layers.forEach((t,n)=>{const a=!t.now&&e.find(s=>s.id===t.id)?.thumb;a&&Nl(n,a)})}function Nl(e,t){const n=Y?.el.querySelector(`.vs-layer[data-i="${e}"]`);if(!n)return;let a=n.querySelector("img");a||(a=document.createElement("img"),a.alt="",a.draggable=!1,n.appendChild(a)),a.getAttribute("src")!==t&&(a.src=t)}function mn(e){if(!Y)return;const{el:t,fid:n}=Y;clearTimeout(Y.liveT),Y=null;const a=f.frames.find(i=>i.id===n),s=t.querySelector(".vs-rig");if(t.classList.remove("open"),t.classList.add("closing"),a&&s&&!e){const i=en(a),o=parseFloat(s.style.left),r=parseFloat(s.style.top),l=parseFloat(s.style.width);s.style.transform=`translate(${i.l-o}px, ${i.t-r}px) scale(${i.w/l})`}document.body.classList.remove("versions-on"),setTimeout(()=>t.remove(),380)}addEventListener("keydown",e=>{Y&&(e.key==="Escape"?(e.stopPropagation(),e.preventDefault(),mn()):/^Arrow(Left|Right|Up|Down)$/.test(e.key)&&!It()&&(e.stopPropagation(),e.preventDefault(),js(e.key==="ArrowLeft"||e.key==="ArrowUp"?1:-1)))},!0),addEventListener("resize",()=>mn());let Ge=null;async function jn(e,t){try{const n=P.get(e),a=n&&!n.parked?Vn(n):n?.resume,s=await x("POST",`/__loop/api/frames/${e}/duplicate`,{...t?{x:Math.round(t.x),y:Math.round(t.y)}:{},...a?{route:a}:{}});let i=null;J("Duplicate frame",async()=>{i=Ct(s.id)||i,await x("DELETE",`/__loop/api/frames/${s.id}`)},()=>ze(i||{frames:[s]})),f.frames.find(o=>o.id===s.id)?(Q(s.id),zt(s.id)):Ze=s.id}catch(n){y(n.message)}}addEventListener("keydown",e=>{e.key==="Alt"&&q.classList.add("alt")}),addEventListener("keydown",e=>{const t=document.activeElement,n=It()&&(t.value??t.textContent??"").trim();if(e.key!=="Enter"||!e[pt]||n||!k())return;const a=[...document.querySelectorAll('.pin.needs[data-act="background"], .wait-pill')];if(!a.length)return;const s=(o=>{const r=o.getBoundingClientRect();return r.right>0&&r.bottom>0&&r.left<innerWidth&&r.top<innerHeight?Math.hypot(r.left+r.width/2-innerWidth/2,r.top+r.height/2-innerHeight/2):1/0}),i=a.find(o=>o.dataset.key===V)||a.filter(o=>s(o)<1/0).sort((o,r)=>s(o)-s(r))[0];i&&(e.preventDefault(),(i.querySelector(".pin-act")||i.querySelector("button"))?.click())}),addEventListener("keyup",e=>{e.key==="Alt"&&q.classList.remove("alt")}),addEventListener("blur",()=>q.classList.remove("alt"));const Nf=[["Tools",[["V","Select: frames, and the elements inside them"],["Click","Select the thing under the pointer: a button, a card, an image, a text"],["Click again / Esc","One level in / one level out"],["Hold \u2318","Reach the exact element under the pointer, however deep"],["\u2190 \u2192 \u2191 \u2193 on an element","Move it past its neighbour, following its layout"],["Drag a selected element","Drop it in any gap, in any container; out of the frame makes it a frame of its own"],["\u2318-drag a selected element","Place it freely: it leaves the layout and stays where you put it"],["\u2318D on an element","Duplicate it, right after itself"],["X","Interact: click, type and scroll in the pages"],["Scroll in a frame you\u2019re using","Up/down scrolls its page; sideways moves the canvas"],["H / hold Space","Pan"],["F","Frame (presets, or drag to draw)"],["S","Open the selected frame on stage (S again to leave)"],["\u21E7\u2318S","Unsection: remove the section, keep its frames"],["\u21E7\u2318F","Unframe: remove the frame, keep what is inside"],["\u21E7S","Section: drag a region that holds frames"],["C","Comment (click = pin, drag = area)"],["C, then hold \u2318","Comment on a block: hover to outline it, click to comment"],["\u21E7C","Hide / show comments"],["D","Deep select: pick exact elements (\u21E7 for more)"],["P","Draw"],["E","Erase marks"],["N","Describe a frame for the agent"]]],["Edit",[["\u2318Z","Undo"],["\u21E7\u2318Z / Ctrl Y","Redo"],["\u2325 drag title","Duplicate frame"],["\u2318C / \u2318V","Copy / paste frame"],["\u2318D","Duplicate in place"],["\u21E7\u2318C","Copy a frame as an image"],["\u21E7\u2318L","Copy a link to the frame or element"],["Right-click","Everything you can do with what is under the pointer"],["Drop / \u2318V","Put an image, a web address or an HTML file on the canvas"],["\u21E7F","Freeze a copy (keeps this moment)"],["K","Phone keyboard on / off"],["\u21E7 click / drag box","Select several frames"],["\u2318A","Select all frames"],["\u2325A \u2325H \u2325D","Align left / centre / right"],["\u2325W \u2325V \u2325S","Align top / middle / bottom"],["Delete","Delete selected frame"],["Double-click title","Rename frame"],["Click the size by a title","Size & device presets"],["Esc","Close / deselect"]]],["View",[["Pinch / \u2318 scroll","Zoom"],["Scroll","Pan"],["\u21E71","Fit everything"],["\u21E72","Zoom to the selection"],["Arrows / \u21E7 arrows","Nudge the selection 1px / 10px"],["\u21E7 drag","Move straight across or up/down"],["\u23180","Zoom to 100%"],["+ / \u2212","Zoom in / out"]]],["Comments",[["\u21B5","Send to the agent"],["\u21E7\u21B5","New line"],["?","This list"]]]];function Ys(e){let t=m("#shortcuts");t||(t=document.createElement("div"),t.id="shortcuts",t.className="modal",t.hidden=!0,t.innerHTML=`<div class="modal-card sc-card"><div class="modal-head"><span>Keyboard shortcuts</span><button class="icon-btn" data-close>\xD7</button></div>
|
|
133
|
+
<div class="sc-grid">${Nf.map(([n,a])=>`<div><div class="sc-group">${n}</div>${a.map(([s,i])=>`<div class="sc-row"><span>${C(i)}</span><span class="sc-keys">${s.split(" / ").map(o=>`<kbd>${C(o)}</kbd>`).join(" ")}</span></div>`).join("")}</div>`).join("")}</div>
|
|
134
|
+
<div class="sc-tips"><div class="sc-group">Tips</div><button class="sc-tip" data-tip="deep"><span><b>Go straight to it</b>Hold \u2318 to pick whatever is under the pointer, however deep</span><em>Show</em></button></div></div>`,document.body.appendChild(t),t.querySelector('[data-tip="deep"]').addEventListener("click",()=>{t.hidden=!0,Fr(innerWidth/2-136,innerHeight/2-120,!0)}),t.addEventListener("pointerdown",n=>{(n.target===t||n.target.closest("[data-close]"))&&(t.hidden=!0)})),t.hidden=e===void 0?!t.hidden:!e}addEventListener("keydown",e=>{It()||(e.key==="?"?(e.preventDefault(),Ys()):e.key==="Escape"&&m("#shortcuts")&&!m("#shortcuts").hidden&&Ys(!1))});function Bl(e){const t=f.frames.find(a=>a.id===D),n=e.value.trim();if(t&&n&&n!==t.name){const a=t.name,s=t.id;t.name=n,ee(t),x("PATCH",`/__loop/api/frames/${s}`,{name:n}).catch(i=>y(i.message)),J("Rename frame",()=>Ut(s,{name:a}),()=>Ut(s,{name:n}))}}m("#frame-panel").addEventListener("change",e=>{e.target.id==="fp-name"&&Bl(e.target)}),m("#frame-panel").addEventListener("keydown",e=>{e.target.id==="fp-name"&&e.key==="Enter"&&(Bl(e.target),e.target.blur())},!0),m("#history-btn").addEventListener("click",e=>{e.stopPropagation(),Fl()});async function Fl(e){let t=m("#hist-pop");if(t&&e!==!0){t.remove();return}t||(t=document.createElement("aside"),t.id="hist-pop",t.className="sheet",document.body.appendChild(t),t.addEventListener("pointerdown",i=>i.stopPropagation()),t.addEventListener("wheel",i=>i.stopPropagation())),t.innerHTML=`<div class="cp-head"><b>Canvas history</b><button class="cp-x" title="Close" data-hp-close>${A("x")}</button></div><p class="hp-intro">The canvas as it was, kept before frames or comments go and every ten minutes while you work.</p><div class="hp-list"><div class="hp-empty">Loading\u2026</div></div>`,t.querySelector("[data-hp-close]").addEventListener("click",()=>t.remove());let n=[];try{n=(await x("GET","/__loop/api/canvas-history")).items}catch(i){y(i.message)}const a=i=>{const o=new Date(i);return(new Date().toDateString()===o.toDateString()?"":o.toLocaleDateString([],{month:"short",day:"numeric"})+", ")+o.toLocaleTimeString([],{hour:"numeric",minute:"2-digit"})},s=i=>i==="before restoring"?"Before a restore":i==="before a change"?"Before frames or comments went":"";t.querySelector(".hp-list").innerHTML=n.length?n.map(i=>`<div class="hp-row"><span><b>${a(i.at)}</b><small>${s(i.label)?`${s(i.label)} \xB7 `:""}${i.frames} frame${i.frames===1?"":"s"}, ${i.comments} comment${i.comments===1?"":"s"}${i.names.length?` \xB7 ${C(i.names.join(", "))}`:""}</small></span><button data-restore="${i.id}">Restore</button></div>`).join(""):'<div class="hp-empty">Nothing kept yet.</div>',t.querySelectorAll("[data-restore]").forEach(i=>i.addEventListener("click",async()=>{try{const o=await x("POST",`/__loop/api/canvas-history/${i.dataset.restore}/restore`);t.remove(),y(`Restored (${o.frames} frames). What was there before is in the history too.`,3200)}catch(o){y(o.message)}}))}m("#canvas-name").addEventListener("click",()=>{const e=m("#canvas-name");if(!k()||X||e.querySelector("input"))return;const t=document.createElement("input");t.className="canvas-rename",t.value=f.name,t.spellcheck=!1,e.replaceChildren(t),t.focus(),t.select();const n=a=>{const s=t.value.trim();if(e.textContent=a&&s?s:f.name,a&&s&&s!==f.name){const i=f.name;f.name=s,x("POST","/__loop/api/settings",{name:s}).catch(o=>y(o.message)),J("Rename canvas",()=>x("POST","/__loop/api/settings",{name:i}),()=>x("POST","/__loop/api/settings",{name:s}))}};t.addEventListener("keydown",a=>{a.stopPropagation(),a.key==="Enter"&&t.blur(),a.key==="Escape"&&(t.value=f.name,t.blur())}),t.addEventListener("blur",()=>n(!0))}),addEventListener("resize",()=>Te()),gd(),Ae("select"),re(),ec();const dt=document.createElement("div");dt.id="tip",dt.hidden=!0,document.body.appendChild(dt);let hn=null,co=null,fo=0;function Aa(){clearTimeout(co),co=null,hn&&!dt.hidden&&(fo=Date.now()),hn=null,dt.hidden=!0}function Bf(e,t){if(!e.isConnected)return Aa();const n=/^(.*\S)\s+\(([^()]{1,14})\)$/.exec(t);dt.innerHTML=n?`${C(n[1])}<kbd>${C(n[2])}</kbd>`:C(t),dt.hidden=!1;const a=e.getBoundingClientRect(),s=dt.offsetWidth,i=dt.offsetHeight,o=a.bottom+8+i<innerHeight-6&&a.top<innerHeight*.6;dt.style.left=`${Math.round(Math.max(8,Math.min(a.left+a.width/2-s/2,innerWidth-s-8)))}px`,dt.style.top=`${Math.round(o?a.bottom+8:a.top-i-8)}px`,dt.classList.toggle("up",!o)}document.addEventListener("pointerover",e=>{const t=e.target.closest?.("[title]:not(iframe), [data-tip]");if(t===hn||(Aa(),!t||e.pointerType==="touch"))return;t.title&&(t.dataset.tip=t.title,!t.getAttribute("aria-label")&&!t.textContent.trim()&&t.setAttribute("aria-label",t.title),t.removeAttribute("title"));const n=t.dataset.tip;n&&(hn=t,co=setTimeout(()=>Bf(t,n),Date.now()-fo<700?0:260))},!0),document.addEventListener("pointerout",e=>{hn&&!hn.contains(e.relatedTarget)&&Aa()},!0);for(const e of["pointerdown","wheel","keydown"])addEventListener(e,()=>{hn&&(Aa(),fo=0)},{capture:!0,passive:!0});const Yn={"agent-menu":e=>{e.hidden=!0,e.classList.remove("peek")},"share-menu":e=>{e.hidden=!0},"comments-panel":e=>{e.hidden=!0},ctx:()=>Gt(),"hist-pop":e=>e.remove(),shortcuts:()=>Ys(!1),"sec-menu":e=>{e.hidden=!0},"model-menu":e=>{e.hidden=!0},"reconnect-pop":e=>{e.hidden=!0},"tool-menu":e=>{e.hidden=!0},"build-card":e=>e.remove(),"export-menu":e=>e.remove()},_a=e=>{const t=document.getElementById(e);return!!t&&t.isConnected&&!t.hidden&&!(e==="agent-menu"&&t.classList.contains("peek"))};let Ks=null,Wl=new Set(Object.keys(Yn).filter(_a));addEventListener("pointerdown",e=>{Ks=e.target},!0),addEventListener("keydown",()=>{Ks=null},!0),new MutationObserver(e=>{if(!e.some(a=>a.type==="attributes"&&a.target.id in Yn||[...a.addedNodes,...a.removedNodes].some(s=>s.id in Yn)))return;const t=new Set(Object.keys(Yn).filter(_a)),n=[...t].filter(a=>!Wl.has(a));if(n.length){const a=new Set(n);for(const s of t)if(!a.has(s)){const i=document.getElementById(s);if(Ks&&i.contains(Ks))continue;Yn[s](i)}}Wl=new Set(Object.keys(Yn).filter(_a)),ss(),Ff()}).observe(document.body,{subtree:!0,childList:!0,attributes:!0,attributeFilter:["hidden","class"]});function Ff(){const e=_a("comments-panel"),t=_a("hist-pop");m("#comments-btn").classList.toggle("on",e),m("#history-btn").classList.toggle("on",t),document.body.classList.toggle("sheet-open",e||t)}addEventListener("keydown",e=>{e.key!=="Escape"||It()||!document.body.classList.contains("sheet-open")||!H.hidden||V||!m("#agent-menu").hidden||!m("#share-menu").hidden||(e.stopImmediatePropagation(),m("#comments-panel").hidden=!0,m("#hist-pop")?.remove())},!0);const Pa=e=>!!e&&!X&&!e.image&&!e.sizeOf&&["folder","route","url","frozen"].includes(e.kind),Wf=e=>f.comments.some(t=>t.kind==="build"&&t.status==="done"&&!t.undone&&(t.build?.frames||[t.frameId]).includes(e));async function Vs(e,t,n=""){if(e=e.filter($=>Pa(f.frames.find(b=>b.id===$))),!e.length||!k())return;const a=f.frames.find($=>$.id===e[0]);let s={mode:"add",route:null};try{s=await x("GET",`/__loop/api/frames/${a.id}/build-target`)}catch{}at(),Gt?.();let i=m("#build-card");i||(i=document.createElement("div"),i.id="build-card",i.className="menu",document.body.appendChild(i),i.addEventListener("pointerdown",$=>$.stopPropagation()));let o=s.mode;const r=K.get("loop.buildCommit",!1),l=e.length>1,c=()=>o==="wrap"?"Its changes are already in the code. The agent reviews them and tidies them up to the project\u2019s standard.":o==="replace"?`Replaces the app\u2019s <code>${C(s.route||"screen")}</code> screen with this design, keeping what the screen does.`:l?`Adds ${e.length} screens to the project, built together. The agent picks where they belong.`:"Adds it to the project as a new screen. The agent picks where it belongs and tells you.";i.innerHTML=`<div class="bc-head"><span class="bc-ic">${$l}</span><b>Build into project</b><button class="cp-x" data-bc="x" title="Close">${A("x")}</button></div>
|
|
135
|
+
<div class="bc-name">${l?`${e.length} frames \xB7 ${C(a.name)} and ${e.length-1} more`:C(a.name)}</div>
|
|
136
|
+
${s.mode==="replace"?`<div class="bc-seg"><button data-mode="replace">Replace ${C(s.route||"the screen")}</button><button data-mode="add">Add as new</button></div>`:""}
|
|
137
|
+
<p class="bc-what"></p>
|
|
138
|
+
<textarea class="bc-note" rows="2" placeholder="Anything to keep in mind? (optional)"></textarea>
|
|
139
|
+
<label class="bc-commit"><input type="checkbox" ${r?"checked":""}><span>Commit when it\u2019s done</span><small>never pushes</small></label>
|
|
140
|
+
<div class="bc-acts"><button data-bc="x">Cancel</button><button class="primary" data-bc="go">Build <kbd>\u2318\u21B5</kbd></button></div>`;const d=()=>{i.querySelector(".bc-what").innerHTML=c(),i.querySelectorAll("[data-mode]").forEach($=>$.classList.toggle("on",$.dataset.mode===o))};d(),i.onclick=async $=>{const b=$.target.closest("[data-mode]");if(b){o=b.dataset.mode,d();return}const M=$.target.closest("[data-bc]")?.dataset.bc;if(M){if(M==="x"){i.remove();return}M==="go"&&u()}};const u=async()=>{const $=i.querySelector(".bc-note").value.trim(),b=i.querySelector(".bc-commit input").checked;K.set("loop.buildCommit",b);try{await x("POST","/__loop/api/comments",{frameId:a.id,kind:"build",text:$||(l?"Build these into the project":"Build this into the project"),anchor:{scope:"frame",x:24,y:24},build:{mode:o,commit:b,frames:e}}),i.remove(),y(l?`Building ${e.length} screens into the project`:`Building \u201C${a.name}\u201D into the project`,2400)}catch(M){y(M.message)}};i.onkeydown=$=>{$.stopPropagation(),$.key==="Enter"&&($.metaKey||$.ctrlKey)?($.preventDefault(),u()):$.key==="Escape"&&i.remove()},i.hidden=!1;const p=(t||P.get(a.id)?.el.querySelector(".frame-body"))?.getBoundingClientRect(),h=i.offsetWidth,g=i.offsetHeight,w=t?p.right-h:p.left+p.width/2-h/2,T=t?p.bottom+8:p.top+40;i.style.left=`${Math.max(12,Math.min(innerWidth-h-12,w))}px`,i.style.top=`${Math.max(60,Math.min(innerHeight-g-12,T))}px`,n&&(i.querySelector(".bc-note").value=n),setTimeout(()=>i.querySelector(".bc-note").focus({preventScroll:!0}),0)}addEventListener("keydown",e=>{e.key==="Escape"&&m("#build-card")&&m("#build-card").remove()});const jf='<svg viewBox="0 0 24 24" aria-hidden="true"><path d="M12 3.5v11"/><path d="M7.5 10l4.5 4.5 4.5-4.5"/><path d="M4.5 15.5v2.5a2 2 0 0 0 2 2h11a2 2 0 0 0 2-2v-2.5"/></svg>',jl=e=>String(e||"screen").toLowerCase().replace(/[^\w]+/g,"-").replace(/^-+|-+$/g,"").slice(0,60)||"screen";function Yl(e,t){const n=document.createElement("a");n.href=URL.createObjectURL(e),n.download=t,document.body.appendChild(n),n.click(),n.remove(),setTimeout(()=>URL.revokeObjectURL(n.href),4e3)}async function Yf(e){const t=await x("POST",`/__loop/api/frames/${e}/shot`),n=await fetch(`/__loop/shots/${t.path.split("/").pop()}`);if(!n.ok)throw new Error("No picture");return n.blob()}async function Kf(e){let t=Ji(e);const n=new Set;for(const o of t.matchAll(/(?:src|href|poster)=["']([^"']+)["']|url\(\s*["']?([^"')]+)["']?\s*\)/g)){const r=o[1]||o[2];r&&!/^(data:|blob:|#|mailto:|tel:|javascript:)/.test(r)&&!/\.(html?|css)(\?|$)/i.test(r.split("#")[0])&&n.add(r)}const a=ue(e)?.baseURI||location.href,s=async o=>{try{const r=await fetch(new URL(o,a));if(!r.ok)return null;const l=await r.blob();return l.size>6e6?null:await new Promise(c=>{const d=new FileReader;d.onload=()=>c(d.result),d.onerror=()=>c(null),d.readAsDataURL(l)})}catch{return null}},i=new Map(await Promise.all([...n].slice(0,120).map(async o=>[o,await s(o)])));for(const[o,r]of i)r&&(t=t.split(o).join(r));return t=t.replace(/<base href="[^"]*">/,"").replace(/<meta name="loop-frozen"[^>]*>/,""),t.startsWith("<!")?t:`<!doctype html>
|
|
141
|
+
${t}`}function Vf(e,t){let n=m("#export-menu");if(n){n.remove();return}n=document.createElement("div"),n.id="export-menu",n.className="menu",n.innerHTML=`<div class="ex-title">Export \u201C${C(e.name)}\u201D</div>
|
|
142
|
+
<button class="menu-item" data-ex="png"><span><b>Image</b><small>PNG of the screen, ${e.w} \xD7 ${e.h}</small></span></button>
|
|
143
|
+
<button class="menu-item" data-ex="html"><span><b>HTML file</b><small>The page as it is now, in one file that opens anywhere</small></span></button>
|
|
144
|
+
<button class="menu-item" data-ex="copy"><span><b>Copy HTML</b><small>The same page, on the clipboard</small></span></button>`,document.body.appendChild(n),n.addEventListener("pointerdown",s=>s.stopPropagation());const a=t.getBoundingClientRect();n.style.top=`${a.bottom+8}px`,n.style.left=`${Math.max(12,Math.min(innerWidth-n.offsetWidth-12,a.left+a.width/2-n.offsetWidth/2))}px`,n.addEventListener("click",async s=>{const i=s.target.closest("[data-ex]")?.dataset.ex;if(i){n.remove();try{if(i==="png")y("Making the picture\u2026",4e3),Yl(await Yf(e.id),`${jl(e.name)}.png`),y("Image saved",1600);else{y("Packing the page\u2026",4e3);const o=await Kf(e.id);i==="html"?(Yl(new Blob([o],{type:"text/html"}),`${jl(e.name)}.html`),y("HTML file saved",1600)):(await navigator.clipboard.writeText(o),y("HTML copied",1600))}}catch(o){y(o.message||"Could not export")}}})}addEventListener("pointerdown",e=>{const t=m("#export-menu");t&&!t.contains(e.target)&&!e.target.closest('[data-sb="export"]')&&t.remove()});const St=document.createElement("div");St.id="cursor-tag",St.innerHTML="<span></span>",document.body.appendChild(St);let tn=!1;function Uf(e){const t=U==="comment"&&!oe&&e.target.closest?.(".frame-label, .section .sec-label"),n=t?t.classList.contains("sec-label")?"Comment on this section":"Comment on this frame":null;if(!n){tn&&(tn=!1,St.classList.remove("open","on"),q.classList.remove("ctag"));return}St.style.transform=`translate(${e.clientX}px, ${e.clientY-23}px)`,$e(St.firstChild,n),tn||(tn=!0,q.classList.add("ctag"),St.classList.add("on"),requestAnimationFrame(()=>St.classList.add("open")))}q.addEventListener("pointermove",Uf),q.addEventListener("pointerleave",()=>{tn&&(tn=!1,St.classList.remove("open","on"),q.classList.remove("ctag"))}),q.addEventListener("pointerdown",()=>{tn&&(tn=!1,St.classList.remove("open","on"),q.classList.remove("ctag"))},!0);let B=null;const Kn=()=>K.get("loop.duo3d",!0),Xf=[["inner",951,669],["innerTall",669,951],["outer",466,678],["outerWide",678,466]];function Gf(e){K.set("loop.duo3d",e);const t=S&&f.frames.find(n=>n.id===S.fid);if(t){if(!e){const n=K.get(`loop.duoPose.${f.name}.${t.id}`,null)||Rt(t);Us(),Xe(),n&&La(n);return}Xe()}}function Us(){if(B){try{B.api?.dispose()}catch{}B.el.remove(),B.rail.remove(),B.slider.remove(),document.body.classList.remove("duo3d-on"),B=null}}async function Zf(e,t){if(!t||!Kn()){Us();return}if(B&&B.fid!==e.id&&Us(),!B){const a=document.createElement("div");a.id="duo3d",a.innerHTML='<div class="d3-wait"><span>Getting your screens ready\u2026</span></div>';const s=document.createElement("div");s.id="duo-rail";const i=document.createElement("div");i.id="duo-slider",i.innerHTML='<input type="range" min="0" max="100" value="100" aria-label="How far open: shut to flat">',document.body.append(a,s,i),document.body.classList.add("duo3d-on");for(const r of[a,s,i])r.addEventListener("pointerdown",l=>l.stopPropagation()),r.addEventListener("wheel",l=>l.stopPropagation(),{passive:!0});B={fid:e.id,el:a,rail:s,slider:i,api:null,shots:{},have:new Set,rev:-1};const o=B;s.addEventListener("click",r=>{const l=r.target.closest("[data-pose]");l&&La(l.dataset.pose)}),i.addEventListener("input",r=>o.api?.setOpenness(+r.target.value/100)),Da();try{const r=await import("./duo3d.js");if(B!==o)return;o.api=r.createDuo(a,{onPose:()=>{Da(),uo()},onSettle:()=>Da(),onPicture:l=>{o.have.add(l),uo()},onRest:()=>Ul(),onBusy:()=>Vl()}),o.api.setPose(Rn(e),!0),uo(),o.api.useApple("/__loop/api/duo-model").catch(l=>console.warn("Loop: using its own iPhone Duo model",l))}catch(r){a.querySelector(".d3-wait span").textContent="3D isn\u2019t available in this browser",console.error(r);return}}const n=P.get(e.id);B.api&&B.rev!==(n?.rev||0)&&(B.rev=n?.rev||0,Jf(e,B),B.live&&(B.live.src=B.live.src)),Da()}async function Jf(e,t){const n=Kl[Rn(e)];for(const[a,s,i]of[...Xf].sort((o,r)=>(r[0]===n)-(o[0]===n)))try{const o=await x("POST",`/__loop/api/frames/${e.id}/shot`,{w:s,h:i});if(B!==t)return;t.api.setPictures({[a]:`/__loop/shots/${o.path.split("/").pop()}`})}catch(o){a==="inner"&&y(o.message||"No pictures of the screen")}}const Kl={landscape:"inner",portrait:"innerTall",seated:"innerTall",closed:"outer",standing:"outerWide"};function uo(){if(!B)return;const e=B.api?.pose||Rn(f.frames.find(a=>a.id===B.fid)),t=!!B.api&&B.have.has(Kl[e]);B.el.classList.toggle("waiting",!t);let n=B.el.querySelector(".d3-wait");!t&&!n&&(n=document.createElement("div"),n.className="d3-wait",n.innerHTML="<span>Getting your screens ready\u2026</span>",B.el.appendChild(n)),t&&n&&n.remove()}const Qf={landscape:["inner",951,669],portrait:["innerTall",669,951],closed:["outer",466,678],standing:["outerWide",678,466]};function Vl(){B?.liveWrap&&(B.liveWrap.style.visibility="hidden")}function Ul(){if(!B?.api)return;const e=Qf[B.api.pose],t=e&&B.api.resting&&B.have.size&&B.api.screenQuad(e[0]);if(!t){Vl();return}const n=P.get(B.fid),a=n?.iframe?.src;if(!a)return;let s=B.live,i=B.liveWrap;if(!s){i=B.liveWrap=document.createElement("div"),i.className="duo-live",i.style.visibility="hidden",s=B.live=document.createElement("iframe"),s.title="The screen, live",s.src=a;const l=document.createElement("i");l.className="duo-cam",i.append(s,l),B.el.appendChild(i),s.addEventListener("load",()=>{s.dataset.ready="1",Ul()})}(s.width!=e[1]||s.height!=e[2])&&(s.width=e[1],s.height=e[2],i.style.width=`${e[1]}px`,i.style.height=`${e[2]}px`),i.style.borderRadius=e[0].startsWith("inner")?"26px":"40px";const o=i.querySelector(".duo-cam"),r={outer:[.9,.075],outerWide:[.925,.9]}[e[0]];o.hidden=!r,r&&(o.style.left=`${r[0]*e[1]}px`,o.style.top=`${r[1]*e[2]}px`),i.style.transform=eu(e[1],e[2],t),i.style.visibility=s.dataset.ready?"visible":"hidden"}function eu(e,t,[n,a,s,i]){const o=[[0,0],[e,0],[e,t],[0,t]],r=[n,a,s,i],l=[],c=[];for(let b=0;b<4;b++){const[M,E]=o[b],[z,_]=r[b];l.push([M,E,1,0,0,0,-M*z,-E*z]),c.push(z),l.push([0,0,0,M,E,1,-M*_,-E*_]),c.push(_)}for(let b=0;b<8;b++){let M=b;for(let E=b+1;E<8;E++)Math.abs(l[E][b])>Math.abs(l[M][b])&&(M=E);[l[b],l[M]]=[l[M],l[b]],[c[b],c[M]]=[c[M],c[b]];for(let E=0;E<8;E++)if(E!==b){const z=l[E][b]/l[b][b];for(let _=b;_<8;_++)l[E][_]-=z*l[b][_];c[E]-=z*c[b]}}const[d,u,p,h,g,w,T,$]=c.map((b,M)=>b/l[M][M]);return`matrix3d(${d},${h},0,${T},${u},${g},0,${$},0,0,1,0,${p},${w},0,1)`}function Da(){if(!B)return;const e=f.frames.find(s=>s.id===B.fid),t=B.api?.pose||Rn(e),n=Math.round((B.api?.openness??1)*100);document.activeElement!==B.slider.firstChild&&(B.slider.firstChild.value=n);const a=Ue.map(s=>`<button class="dr-pose${s.id===t?" on":""}" data-pose="${s.id}"><span class="dr-ic">${gl[s.id]}</span><span class="dr-txt"><b>${s.name}</b></span></button>`).join("");B.rail._html!==a&&(B.rail._html=a,B.rail.innerHTML=a)}
|