@epic-web/workshop-app 6.64.0 → 6.64.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (56) hide show
  1. package/build/client/assets/{_exerciseNumber-CcPKmB4n.js → _exerciseNumber-D3f2-zl6.js} +2 -2
  2. package/build/client/assets/{_exerciseNumber-CcPKmB4n.js.map → _exerciseNumber-D3f2-zl6.js.map} +1 -1
  3. package/build/client/assets/{_exerciseNumber_.finished-knzx8riV.js → _exerciseNumber_.finished-DBaOwcf2.js} +2 -2
  4. package/build/client/assets/{_exerciseNumber_.finished-knzx8riV.js.map → _exerciseNumber_.finished-DBaOwcf2.js.map} +1 -1
  5. package/build/client/assets/{_extra-DB6-IJuV.js → _extra-B4vZXPjV.js} +2 -2
  6. package/build/client/assets/{_extra-DB6-IJuV.js.map → _extra-B4vZXPjV.js.map} +1 -1
  7. package/build/client/assets/{_layout-Be0gsSoP.js → _layout-C6NSVF79.js} +2 -2
  8. package/build/client/assets/{_layout-Be0gsSoP.js.map → _layout-C6NSVF79.js.map} +1 -1
  9. package/build/client/assets/{_layout-D05w5xUz.js → _layout-oPmquiOE.js} +2 -2
  10. package/build/client/assets/{_layout-D05w5xUz.js.map → _layout-oPmquiOE.js.map} +1 -1
  11. package/build/client/assets/app-BcJkSksP.js +2 -0
  12. package/build/client/assets/{app-rrQthl25.js.map → app-BcJkSksP.js.map} +1 -1
  13. package/build/client/assets/{diff-De24Mp-s.js → diff-Ba99U4EI.js} +2 -2
  14. package/build/client/assets/{diff-De24Mp-s.js.map → diff-Ba99U4EI.js.map} +1 -1
  15. package/build/client/assets/{diff-Bd9VlQ-I.js → diff-DmmI9IU6.js} +2 -2
  16. package/build/client/assets/{diff-Bd9VlQ-I.js.map → diff-DmmI9IU6.js.map} +1 -1
  17. package/build/client/assets/{epic-video-DdpYdAlg.js → epic-video-5HutgMR0.js} +2 -2
  18. package/build/client/assets/{epic-video-DdpYdAlg.js.map → epic-video-5HutgMR0.js.map} +1 -1
  19. package/build/client/assets/{epic-video-Bndfj6GR.js → epic-video-BX2A437e.js} +2 -2
  20. package/build/client/assets/{epic-video-Bndfj6GR.js.map → epic-video-BX2A437e.js.map} +1 -1
  21. package/build/client/assets/{finished-HnwwiFtu.js → finished-BLRyuOTb.js} +2 -2
  22. package/build/client/assets/{finished-HnwwiFtu.js.map → finished-BLRyuOTb.js.map} +1 -1
  23. package/build/client/assets/index-DVd41HZN.js +68 -0
  24. package/build/client/assets/index-DVd41HZN.js.map +1 -0
  25. package/build/client/assets/{index-CvFJy3s8.js → index-Dt_ngnka.js} +2 -2
  26. package/build/client/assets/{index-CvFJy3s8.js.map → index-Dt_ngnka.js.map} +1 -1
  27. package/build/client/assets/{index-BL399UJV.js → index-InnNe6aG.js} +2 -2
  28. package/build/client/assets/{index-BL399UJV.js.map → index-InnNe6aG.js.map} +1 -1
  29. package/build/client/assets/{index-B1TztMYA.js → index-T3LlCTSm.js} +2 -2
  30. package/build/client/assets/{index-B1TztMYA.js.map → index-T3LlCTSm.js.map} +1 -1
  31. package/build/client/assets/{loading-IJRzD1mm.js → loading-BiVU3Oa8.js} +2 -2
  32. package/build/client/assets/{loading-IJRzD1mm.js.map → loading-BiVU3Oa8.js.map} +1 -1
  33. package/build/client/assets/{login-VlyrGJvd.js → login-Ej63Q5LC.js} +2 -2
  34. package/build/client/assets/{login-VlyrGJvd.js.map → login-Ej63Q5LC.js.map} +1 -1
  35. package/build/client/assets/manifest-9482f5db.js +1 -0
  36. package/build/client/assets/{mdx-CbaVHkqG.js → mdx-BlaeOyqK.js} +2 -2
  37. package/build/client/assets/{mdx-CbaVHkqG.js.map → mdx-BlaeOyqK.js.map} +1 -1
  38. package/build/client/assets/{playground-xNPUi1cK.js → playground-DIm_r4fy.js} +2 -2
  39. package/build/client/assets/{playground-xNPUi1cK.js.map → playground-DIm_r4fy.js.map} +1 -1
  40. package/build/client/assets/{preview-DUByetdK.js → preview-D11Pscbe.js} +2 -2
  41. package/build/client/assets/{preview-DUByetdK.js.map → preview-D11Pscbe.js.map} +1 -1
  42. package/build/client/assets/{product-DlgtjMXY.js → product-CNG57fZy.js} +2 -2
  43. package/build/client/assets/{product-DlgtjMXY.js.map → product-CNG57fZy.js.map} +1 -1
  44. package/build/client/assets/{root-B-fnUAyN.js → root-hU3hrO-C.js} +2 -2
  45. package/build/client/assets/{root-B-fnUAyN.js.map → root-hU3hrO-C.js.map} +1 -1
  46. package/build/client/assets/{test-wFDk9A6D.js → test-CpoHBC_8.js} +2 -2
  47. package/build/client/assets/{test-wFDk9A6D.js.map → test-CpoHBC_8.js.map} +1 -1
  48. package/build/client/assets/{tests-BldZ_klJ.js → tests-CITG_DX3.js} +2 -2
  49. package/build/client/assets/{tests-BldZ_klJ.js.map → tests-CITG_DX3.js.map} +1 -1
  50. package/build/server/index.js +22 -23
  51. package/build/server/index.js.map +1 -1
  52. package/package.json +3 -3
  53. package/build/client/assets/app-rrQthl25.js +0 -2
  54. package/build/client/assets/index-Cg-9mI3Y.js +0 -68
  55. package/build/client/assets/index-Cg-9mI3Y.js.map +0 -1
  56. package/build/client/assets/manifest-3610e2d1.js +0 -1
@@ -1,2 +1,2 @@
1
- import{j as e}from"./jsx-runtime-C5WNSv3b.js";import{r as l}from"./index-CqIc3cxq.js";import{A as ue,L as M}from"./chunk-EPOLDU6W-C4NOdiis.js";import{u as de,I as N,c as fe}from"./misc-CRhJChs6.js";import{L as me}from"./loading-IJRzD1mm.js";import{D as xe,u as pe}from"./discord-C9e3SYlE.js";import{u as he}from"./online-D6QnZT5V.js";import{c as G,d as O,P as T,f as g,e as ve,u as K,o as ge,g as be,S as je}from"./tooltip-f3C9W-4C.js";import{g as we,u as $}from"./index-D9Wd20Hl.js";import{t as Ne}from"./index-DzdDahau.js";import{S as Te}from"./set-playground-DaRl3X5k.js";import{P as Ie}from"./playground-window-BnU6LeUy.js";import{P as Ce}from"./preview-DUByetdK.js";var _="rovingFocusGroup.onEntryFocus",ye={bubbles:!1,cancelable:!0},I="RovingFocusGroup",[A,V,Fe]=we(I),[Re,B]=G(I,[Fe]),[Pe,Se]=Re(I),z=l.forwardRef((t,s)=>e.jsx(A.Provider,{scope:t.__scopeRovingFocusGroup,children:e.jsx(A.Slot,{scope:t.__scopeRovingFocusGroup,children:e.jsx(Ee,{...t,ref:s})})}));z.displayName=I;var Ee=l.forwardRef((t,s)=>{const{__scopeRovingFocusGroup:n,orientation:r,loop:a=!1,dir:u,currentTabStopId:i,defaultCurrentTabStopId:m,onCurrentTabStopIdChange:v,onEntryFocus:x,preventScrollOnEntryFocus:o=!1,...c}=t,p=l.useRef(null),C=ve(s,p),y=$(u),[F,d]=K({prop:i,defaultProp:m??null,onChange:v,caller:I}),[b,P]=l.useState(!1),h=ge(x),j=V(n),S=l.useRef(!1),[oe,k]=l.useState(0);return l.useEffect(()=>{const f=p.current;if(f)return f.addEventListener(_,h),()=>f.removeEventListener(_,h)},[h]),e.jsx(Pe,{scope:n,orientation:r,dir:y,loop:a,currentTabStopId:F,onItemFocus:l.useCallback(f=>d(f),[d]),onItemShiftTab:l.useCallback(()=>P(!0),[]),onFocusableItemAdd:l.useCallback(()=>k(f=>f+1),[]),onFocusableItemRemove:l.useCallback(()=>k(f=>f-1),[]),children:e.jsx(T.div,{tabIndex:b||oe===0?-1:0,"data-orientation":r,...c,ref:C,style:{outline:"none",...t.style},onMouseDown:g(t.onMouseDown,()=>{S.current=!0}),onFocus:g(t.onFocus,f=>{const ae=!S.current;if(f.target===f.currentTarget&&ae&&!b){const L=new CustomEvent(_,ye);if(f.currentTarget.dispatchEvent(L),!L.defaultPrevented){const E=j().filter(w=>w.focusable),ie=E.find(w=>w.active),le=E.find(w=>w.id===F),ce=[ie,le,...E].filter(Boolean).map(w=>w.ref.current);Y(ce,o)}}S.current=!1}),onBlur:g(t.onBlur,()=>P(!1))})})}),H="RovingFocusGroupItem",W=l.forwardRef((t,s)=>{const{__scopeRovingFocusGroup:n,focusable:r=!0,active:a=!1,tabStopId:u,children:i,...m}=t,v=O(),x=u||v,o=Se(H,n),c=o.currentTabStopId===x,p=V(n),{onFocusableItemAdd:C,onFocusableItemRemove:y,currentTabStopId:F}=o;return l.useEffect(()=>{if(r)return C(),()=>y()},[r,C,y]),e.jsx(A.ItemSlot,{scope:n,id:x,focusable:r,active:a,children:e.jsx(T.span,{tabIndex:c?0:-1,"data-orientation":o.orientation,...m,ref:s,onMouseDown:g(t.onMouseDown,d=>{r?o.onItemFocus(x):d.preventDefault()}),onFocus:g(t.onFocus,()=>o.onItemFocus(x)),onKeyDown:g(t.onKeyDown,d=>{if(d.key==="Tab"&&d.shiftKey){o.onItemShiftTab();return}if(d.target!==d.currentTarget)return;const b=De(d,o.orientation,o.dir);if(b!==void 0){if(d.metaKey||d.ctrlKey||d.altKey||d.shiftKey)return;d.preventDefault();let h=p().filter(j=>j.focusable).map(j=>j.ref.current);if(b==="last")h.reverse();else if(b==="prev"||b==="next"){b==="prev"&&h.reverse();const j=h.indexOf(d.currentTarget);h=o.loop?ke(h,j+1):h.slice(j+1)}setTimeout(()=>Y(h))}}),children:typeof i=="function"?i({isCurrentTabStop:c,hasTabStop:F!=null}):i})})});W.displayName=H;var _e={ArrowLeft:"prev",ArrowUp:"prev",ArrowRight:"next",ArrowDown:"next",PageUp:"first",Home:"first",PageDown:"last",End:"last"};function Ae(t,s){return s!=="rtl"?t:t==="ArrowLeft"?"ArrowRight":t==="ArrowRight"?"ArrowLeft":t}function De(t,s,n){const r=Ae(t.key,n);if(!(s==="vertical"&&["ArrowLeft","ArrowRight"].includes(r))&&!(s==="horizontal"&&["ArrowUp","ArrowDown"].includes(r)))return _e[r]}function Y(t,s=!1){const n=document.activeElement;for(const r of t)if(r===n||(r.focus({preventScroll:s}),document.activeElement!==n))return}function ke(t,s){return t.map((n,r)=>t[(s+r)%t.length])}var Le=z,Ue=W,R="Tabs",[Me]=G(R,[B]),q=B(),[Ge,D]=Me(R),J=l.forwardRef((t,s)=>{const{__scopeTabs:n,value:r,onValueChange:a,defaultValue:u,orientation:i="horizontal",dir:m,activationMode:v="automatic",...x}=t,o=$(m),[c,p]=K({prop:r,onChange:a,defaultProp:u??"",caller:R});return e.jsx(Ge,{scope:n,baseId:O(),value:c,onValueChange:p,orientation:i,dir:o,activationMode:v,children:e.jsx(T.div,{dir:o,"data-orientation":i,...x,ref:s})})});J.displayName=R;var Q="TabsList",X=l.forwardRef((t,s)=>{const{__scopeTabs:n,loop:r=!0,...a}=t,u=D(Q,n),i=q(n);return e.jsx(Le,{asChild:!0,...i,orientation:u.orientation,dir:u.dir,loop:r,children:e.jsx(T.div,{role:"tablist","aria-orientation":u.orientation,...a,ref:s})})});X.displayName=Q;var Z="TabsTrigger",ee=l.forwardRef((t,s)=>{const{__scopeTabs:n,value:r,disabled:a=!1,...u}=t,i=D(Z,n),m=q(n),v=ne(i.baseId,r),x=re(i.baseId,r),o=r===i.value;return e.jsx(Ue,{asChild:!0,...m,focusable:!a,active:o,children:e.jsx(T.button,{type:"button",role:"tab","aria-selected":o,"aria-controls":x,"data-state":o?"active":"inactive","data-disabled":a?"":void 0,disabled:a,id:v,...u,ref:s,onMouseDown:g(t.onMouseDown,c=>{!a&&c.button===0&&c.ctrlKey===!1?i.onValueChange(r):c.preventDefault()}),onKeyDown:g(t.onKeyDown,c=>{[" ","Enter"].includes(c.key)&&i.onValueChange(r)}),onFocus:g(t.onFocus,()=>{const c=i.activationMode!=="manual";!o&&!a&&c&&i.onValueChange(r)})})})});ee.displayName=Z;var te="TabsContent",se=l.forwardRef((t,s)=>{const{__scopeTabs:n,value:r,forceMount:a,children:u,...i}=t,m=D(te,n),v=ne(m.baseId,r),x=re(m.baseId,r),o=r===m.value,c=l.useRef(o);return l.useEffect(()=>{const p=requestAnimationFrame(()=>c.current=!1);return()=>cancelAnimationFrame(p)},[]),e.jsx(be,{present:a||o,children:({present:p})=>e.jsx(T.div,{"data-state":o?"active":"inactive","data-orientation":m.orientation,role:"tabpanel","aria-labelledby":v,hidden:!p,id:x,tabIndex:0,...i,ref:s,style:{...t.style,animationDuration:c.current?"0s":void 0},children:p&&u})})});se.displayName=te;function ne(t,s){return`${t}-trigger-${s}`}function re(t,s){return`${t}-content-${s}`}var ot=J,Oe=X,Ke=ee,at=se;function it({discordPostsPromise:t}){return e.jsxs("div",{className:"flex h-full w-full flex-col gap-4 pt-4",children:[e.jsx("div",{className:"text-center",children:e.jsx(xe,{})}),e.jsx("div",{className:"bg-accent scrollbar-thin scrollbar-thumb-scrollbar flex-1 overflow-y-scroll pb-4",children:e.jsx($e,{discordPostsPromise:t})})]})}function $e({discordPostsPromise:t}){const s=pe(),n=de();return he()?e.jsxs("div",{className:"flex h-full flex-col items-center justify-between",children:[e.jsx(l.Suspense,{fallback:e.jsx("div",{className:"flex h-full w-full flex-col items-center justify-center",children:e.jsx(me,{children:"Loading Discord Posts"})}),children:e.jsx(ue,{resolve:t,errorElement:e.jsx("div",{className:"text-foreground-destructive",children:"There was a problem loading the discord posts"}),children:a=>e.jsx("ul",{className:"flex w-full flex-col gap-4 p-3 xl:p-12",children:a.map(u=>e.jsx("li",{className:"bg-background rounded-xl border transition-all duration-200 focus-within:-translate-y-1 focus-within:shadow-lg hover:-translate-y-1 hover:shadow-lg",children:e.jsx(Ve,{thread:u})},u.id))})})}),e.jsx("div",{children:e.jsxs(M,{to:n&&!s.includes("oauth")?s.replace(/^https/,"discord"):s,target:s.includes("oauth")?void 0:"_blank",rel:"noreferrer noopener",onClick:n?a=>{a.preventDefault(),window.open(a.currentTarget.href,"_blank","noreferrer noopener")}:void 0,className:"flex items-center gap-2 p-2 text-xl hover:underline",children:["Create Post ",e.jsx(N,{name:"ExternalLink"})]})})]}):e.jsx("div",{className:"flex h-full flex-col items-center justify-between",children:e.jsx("div",{className:"text-foreground-destructive flex h-full w-full flex-col items-center justify-center",children:e.jsx(N,{name:"WifiNoConnection",size:"xl",children:"Unable to load discord messages when offline"})})})}function Ve({thread:t}){const s=t.reactions.filter(n=>n.count);return e.jsx("div",{children:e.jsxs("div",{className:"flex flex-col gap-2 p-4",children:[e.jsxs("div",{className:"flex min-w-0 gap-4",children:[e.jsxs("div",{className:"flex min-w-0 flex-col gap-1",children:[t.tags.length?e.jsx("div",{className:"flex gap-2",children:t.tags.map(n=>e.jsxs("div",{className:"bg-accent flex items-center justify-center gap-1 rounded-full px-2 py-1 text-sm",children:[e.jsx("span",{className:"h-3 w-3 leading-3",children:e.jsx(U,{name:n.emojiName,url:n.emojiUrl})}),e.jsx("span",{children:n.name})]},`${n.name}-${n.emojiName??n.emojiUrl??"tag"}`))}):null,e.jsx("strong",{className:"text-xl font-bold",children:t.name}),e.jsxs("div",{className:"flex min-w-0 flex-col gap-1",children:[e.jsxs("div",{className:"flex items-center gap-1",children:[t.authorAvatarUrl?e.jsx("img",{src:t.authorAvatarUrl,alt:"",className:"h-6 w-6 rounded-full"}):null,e.jsxs("span",{children:[e.jsx("span",{className:"font-bold",style:t.authorHexAccentColor?{color:t.authorHexAccentColor}:{},children:t.authorDisplayName}),":"," "]})]}),e.jsx("span",{className:"text-muted-foreground line-clamp-4 min-w-0",children:t.messagePreview})]})]}),t.previewImageUrl?e.jsx("img",{src:t.previewImageUrl,alt:"",className:"h-28 w-28 rounded-lg object-cover"}):null]}),e.jsxs("div",{className:"flex justify-between",children:[e.jsxs("div",{className:"flex items-center gap-3",children:[e.jsx("span",{children:s.length?e.jsx("ul",{className:"flex items-center gap-2",children:s.map((n,r)=>e.jsxs("li",{className:"border-info/60 bg-info/10 text-info flex items-center gap-1 rounded-md border px-[5px] py-[0.5px] text-sm",children:[e.jsx("span",{className:"h-3 w-3 leading-3",children:e.jsx(U,{name:n.emojiName,url:n.emojiUrl})}),e.jsx("span",{children:n.count})]},`${n.emojiName??n.emojiUrl??"reaction"}-${r}`))}):null}),e.jsxs("span",{className:"flex items-center gap-1",children:[e.jsxs("span",{className:"inline-flex items-center gap-1",children:[e.jsx(N,{name:"Chat"})," ",t.messageCount]}),` · ${t.lastUpdatedDisplay}`]})]}),e.jsxs("span",{className:"flex items-center gap-4",children:[e.jsx("a",{href:t.link.replace(/^https/,"discord"),children:e.jsx(N,{name:"Discord"})}),e.jsx("a",{href:t.link,target:"_blank",rel:"noreferrer noopener",children:e.jsx(N,{name:"ExternalLink"})})]})]})]})})}function U({name:t,url:s}){return s?e.jsx("img",{src:s,alt:t,className:"h-full w-full"}):t||null}function Be({status:t}){const s={running:{pinger:"bg-yellow-500/60",circle:"bg-yellow-500"},passed:{circle:"bg-success"},failed:{circle:"bg-destructive"},stopped:{circle:"bg-muted-foreground"}}[t];return e.jsxs("span",{className:"relative flex h-3 w-3",children:[s.pinger?e.jsx("span",{className:`absolute inline-flex h-full w-full animate-ping rounded-full ${s.pinger} opacity-75`}):null,e.jsx("span",{className:`relative inline-flex h-3 w-3 rounded-full ${s.circle}`})]})}function lt(t,s,n){const r=new URLSearchParams(t);return s===n?r.delete("preview"):r.set("preview",s),r}function ct({tabs:t}){return e.jsx(Oe,{className:"scrollbar-thin scrollbar-thumb-scrollbar h-14 min-h-14 overflow-x-auto border-b whitespace-nowrap",children:t.map(s=>e.jsx(Ke,{value:s.id,hidden:s.hidden,asChild:!0,children:e.jsx(M,{id:`${s.id}-tab`,className:fe("clip-path-button radix-state-active:z-10 radix-state-active:bg-foreground radix-state-active:text-background radix-state-active:hover:bg-foreground/80 radix-state-active:hover:text-background/80 radix-state-inactive:hover:bg-foreground/20 radix-state-inactive:hover:text-foreground/80 focus:bg-foreground/80 focus:text-background/80 relative h-full px-6 py-4 font-mono text-sm uppercase outline-none",s.hidden?"hidden":"inline-block"),preventScrollReset:!0,prefetch:"intent",onClick:s.onClick,to:s.to,children:e.jsxs("span",{className:"flex items-center gap-2",children:[s.status?e.jsx(Be,{status:s.status}):null,e.jsx("span",{children:s.label})]})})},s.id))})}function ut({appInfo:t,inBrowserBrowserRef:s,problemAppName:n,allApps:r,isUpToDate:a}){return e.jsx(Ie,{playgroundAppName:t?.appName,problemAppName:n,allApps:r,isUpToDate:a,children:t?.dev?.type==="none"?e.jsxs("div",{className:"flex h-full flex-col items-center justify-center gap-4",children:[e.jsx("div",{className:"text-secondary-foreground text-2xl",children:"Non-UI exercise"}),e.jsxs("div",{className:"text-secondary-foreground max-w-md text-center text-balance",children:["This exercise has no application or other UI associated with it."," ",e.jsx("br",{}),"Navigate to"," ",e.jsx(je,{content:t.fullPath,children:e.jsxs("span",{className:"inline-flex cursor-pointer items-center gap-1.5 underline",onClick:()=>{navigator.clipboard.writeText(t.fullPath),Ne.success("Copied playground path to clipboard")},children:["the playground directory",e.jsx(N,{name:"Copy",size:"sm"})]})})," ","in your editor and follow the exercise instructions to complete it."]})]}):t?e.jsx(Ce,{id:t.appName,appInfo:t,inBrowserBrowserRef:s}):e.jsxs("div",{className:"flex flex-col justify-center gap-2",children:[e.jsx("p",{children:"Please set the playground first"}),n?e.jsx(Te,{appName:n}):null]})})}export{at as C,it as D,ct as P,ot as R,ut as a,lt as g};
2
- //# sourceMappingURL=playground-xNPUi1cK.js.map
1
+ import{j as e}from"./jsx-runtime-C5WNSv3b.js";import{r as l}from"./index-CqIc3cxq.js";import{A as ue,L as M}from"./chunk-EPOLDU6W-C4NOdiis.js";import{u as de,I as N,c as fe}from"./misc-CRhJChs6.js";import{L as me}from"./loading-BiVU3Oa8.js";import{D as xe,u as pe}from"./discord-C9e3SYlE.js";import{u as he}from"./online-D6QnZT5V.js";import{c as G,d as O,P as T,f as g,e as ve,u as K,o as ge,g as be,S as je}from"./tooltip-f3C9W-4C.js";import{g as we,u as $}from"./index-D9Wd20Hl.js";import{t as Ne}from"./index-DzdDahau.js";import{S as Te}from"./set-playground-DaRl3X5k.js";import{P as Ie}from"./playground-window-BnU6LeUy.js";import{P as Ce}from"./preview-D11Pscbe.js";var _="rovingFocusGroup.onEntryFocus",ye={bubbles:!1,cancelable:!0},I="RovingFocusGroup",[A,V,Fe]=we(I),[Re,B]=G(I,[Fe]),[Pe,Se]=Re(I),z=l.forwardRef((t,s)=>e.jsx(A.Provider,{scope:t.__scopeRovingFocusGroup,children:e.jsx(A.Slot,{scope:t.__scopeRovingFocusGroup,children:e.jsx(Ee,{...t,ref:s})})}));z.displayName=I;var Ee=l.forwardRef((t,s)=>{const{__scopeRovingFocusGroup:n,orientation:r,loop:a=!1,dir:u,currentTabStopId:i,defaultCurrentTabStopId:m,onCurrentTabStopIdChange:v,onEntryFocus:x,preventScrollOnEntryFocus:o=!1,...c}=t,p=l.useRef(null),C=ve(s,p),y=$(u),[F,d]=K({prop:i,defaultProp:m??null,onChange:v,caller:I}),[b,P]=l.useState(!1),h=ge(x),j=V(n),S=l.useRef(!1),[oe,k]=l.useState(0);return l.useEffect(()=>{const f=p.current;if(f)return f.addEventListener(_,h),()=>f.removeEventListener(_,h)},[h]),e.jsx(Pe,{scope:n,orientation:r,dir:y,loop:a,currentTabStopId:F,onItemFocus:l.useCallback(f=>d(f),[d]),onItemShiftTab:l.useCallback(()=>P(!0),[]),onFocusableItemAdd:l.useCallback(()=>k(f=>f+1),[]),onFocusableItemRemove:l.useCallback(()=>k(f=>f-1),[]),children:e.jsx(T.div,{tabIndex:b||oe===0?-1:0,"data-orientation":r,...c,ref:C,style:{outline:"none",...t.style},onMouseDown:g(t.onMouseDown,()=>{S.current=!0}),onFocus:g(t.onFocus,f=>{const ae=!S.current;if(f.target===f.currentTarget&&ae&&!b){const L=new CustomEvent(_,ye);if(f.currentTarget.dispatchEvent(L),!L.defaultPrevented){const E=j().filter(w=>w.focusable),ie=E.find(w=>w.active),le=E.find(w=>w.id===F),ce=[ie,le,...E].filter(Boolean).map(w=>w.ref.current);Y(ce,o)}}S.current=!1}),onBlur:g(t.onBlur,()=>P(!1))})})}),H="RovingFocusGroupItem",W=l.forwardRef((t,s)=>{const{__scopeRovingFocusGroup:n,focusable:r=!0,active:a=!1,tabStopId:u,children:i,...m}=t,v=O(),x=u||v,o=Se(H,n),c=o.currentTabStopId===x,p=V(n),{onFocusableItemAdd:C,onFocusableItemRemove:y,currentTabStopId:F}=o;return l.useEffect(()=>{if(r)return C(),()=>y()},[r,C,y]),e.jsx(A.ItemSlot,{scope:n,id:x,focusable:r,active:a,children:e.jsx(T.span,{tabIndex:c?0:-1,"data-orientation":o.orientation,...m,ref:s,onMouseDown:g(t.onMouseDown,d=>{r?o.onItemFocus(x):d.preventDefault()}),onFocus:g(t.onFocus,()=>o.onItemFocus(x)),onKeyDown:g(t.onKeyDown,d=>{if(d.key==="Tab"&&d.shiftKey){o.onItemShiftTab();return}if(d.target!==d.currentTarget)return;const b=De(d,o.orientation,o.dir);if(b!==void 0){if(d.metaKey||d.ctrlKey||d.altKey||d.shiftKey)return;d.preventDefault();let h=p().filter(j=>j.focusable).map(j=>j.ref.current);if(b==="last")h.reverse();else if(b==="prev"||b==="next"){b==="prev"&&h.reverse();const j=h.indexOf(d.currentTarget);h=o.loop?ke(h,j+1):h.slice(j+1)}setTimeout(()=>Y(h))}}),children:typeof i=="function"?i({isCurrentTabStop:c,hasTabStop:F!=null}):i})})});W.displayName=H;var _e={ArrowLeft:"prev",ArrowUp:"prev",ArrowRight:"next",ArrowDown:"next",PageUp:"first",Home:"first",PageDown:"last",End:"last"};function Ae(t,s){return s!=="rtl"?t:t==="ArrowLeft"?"ArrowRight":t==="ArrowRight"?"ArrowLeft":t}function De(t,s,n){const r=Ae(t.key,n);if(!(s==="vertical"&&["ArrowLeft","ArrowRight"].includes(r))&&!(s==="horizontal"&&["ArrowUp","ArrowDown"].includes(r)))return _e[r]}function Y(t,s=!1){const n=document.activeElement;for(const r of t)if(r===n||(r.focus({preventScroll:s}),document.activeElement!==n))return}function ke(t,s){return t.map((n,r)=>t[(s+r)%t.length])}var Le=z,Ue=W,R="Tabs",[Me]=G(R,[B]),q=B(),[Ge,D]=Me(R),J=l.forwardRef((t,s)=>{const{__scopeTabs:n,value:r,onValueChange:a,defaultValue:u,orientation:i="horizontal",dir:m,activationMode:v="automatic",...x}=t,o=$(m),[c,p]=K({prop:r,onChange:a,defaultProp:u??"",caller:R});return e.jsx(Ge,{scope:n,baseId:O(),value:c,onValueChange:p,orientation:i,dir:o,activationMode:v,children:e.jsx(T.div,{dir:o,"data-orientation":i,...x,ref:s})})});J.displayName=R;var Q="TabsList",X=l.forwardRef((t,s)=>{const{__scopeTabs:n,loop:r=!0,...a}=t,u=D(Q,n),i=q(n);return e.jsx(Le,{asChild:!0,...i,orientation:u.orientation,dir:u.dir,loop:r,children:e.jsx(T.div,{role:"tablist","aria-orientation":u.orientation,...a,ref:s})})});X.displayName=Q;var Z="TabsTrigger",ee=l.forwardRef((t,s)=>{const{__scopeTabs:n,value:r,disabled:a=!1,...u}=t,i=D(Z,n),m=q(n),v=ne(i.baseId,r),x=re(i.baseId,r),o=r===i.value;return e.jsx(Ue,{asChild:!0,...m,focusable:!a,active:o,children:e.jsx(T.button,{type:"button",role:"tab","aria-selected":o,"aria-controls":x,"data-state":o?"active":"inactive","data-disabled":a?"":void 0,disabled:a,id:v,...u,ref:s,onMouseDown:g(t.onMouseDown,c=>{!a&&c.button===0&&c.ctrlKey===!1?i.onValueChange(r):c.preventDefault()}),onKeyDown:g(t.onKeyDown,c=>{[" ","Enter"].includes(c.key)&&i.onValueChange(r)}),onFocus:g(t.onFocus,()=>{const c=i.activationMode!=="manual";!o&&!a&&c&&i.onValueChange(r)})})})});ee.displayName=Z;var te="TabsContent",se=l.forwardRef((t,s)=>{const{__scopeTabs:n,value:r,forceMount:a,children:u,...i}=t,m=D(te,n),v=ne(m.baseId,r),x=re(m.baseId,r),o=r===m.value,c=l.useRef(o);return l.useEffect(()=>{const p=requestAnimationFrame(()=>c.current=!1);return()=>cancelAnimationFrame(p)},[]),e.jsx(be,{present:a||o,children:({present:p})=>e.jsx(T.div,{"data-state":o?"active":"inactive","data-orientation":m.orientation,role:"tabpanel","aria-labelledby":v,hidden:!p,id:x,tabIndex:0,...i,ref:s,style:{...t.style,animationDuration:c.current?"0s":void 0},children:p&&u})})});se.displayName=te;function ne(t,s){return`${t}-trigger-${s}`}function re(t,s){return`${t}-content-${s}`}var ot=J,Oe=X,Ke=ee,at=se;function it({discordPostsPromise:t}){return e.jsxs("div",{className:"flex h-full w-full flex-col gap-4 pt-4",children:[e.jsx("div",{className:"text-center",children:e.jsx(xe,{})}),e.jsx("div",{className:"bg-accent scrollbar-thin scrollbar-thumb-scrollbar flex-1 overflow-y-scroll pb-4",children:e.jsx($e,{discordPostsPromise:t})})]})}function $e({discordPostsPromise:t}){const s=pe(),n=de();return he()?e.jsxs("div",{className:"flex h-full flex-col items-center justify-between",children:[e.jsx(l.Suspense,{fallback:e.jsx("div",{className:"flex h-full w-full flex-col items-center justify-center",children:e.jsx(me,{children:"Loading Discord Posts"})}),children:e.jsx(ue,{resolve:t,errorElement:e.jsx("div",{className:"text-foreground-destructive",children:"There was a problem loading the discord posts"}),children:a=>e.jsx("ul",{className:"flex w-full flex-col gap-4 p-3 xl:p-12",children:a.map(u=>e.jsx("li",{className:"bg-background rounded-xl border transition-all duration-200 focus-within:-translate-y-1 focus-within:shadow-lg hover:-translate-y-1 hover:shadow-lg",children:e.jsx(Ve,{thread:u})},u.id))})})}),e.jsx("div",{children:e.jsxs(M,{to:n&&!s.includes("oauth")?s.replace(/^https/,"discord"):s,target:s.includes("oauth")?void 0:"_blank",rel:"noreferrer noopener",onClick:n?a=>{a.preventDefault(),window.open(a.currentTarget.href,"_blank","noreferrer noopener")}:void 0,className:"flex items-center gap-2 p-2 text-xl hover:underline",children:["Create Post ",e.jsx(N,{name:"ExternalLink"})]})})]}):e.jsx("div",{className:"flex h-full flex-col items-center justify-between",children:e.jsx("div",{className:"text-foreground-destructive flex h-full w-full flex-col items-center justify-center",children:e.jsx(N,{name:"WifiNoConnection",size:"xl",children:"Unable to load discord messages when offline"})})})}function Ve({thread:t}){const s=t.reactions.filter(n=>n.count);return e.jsx("div",{children:e.jsxs("div",{className:"flex flex-col gap-2 p-4",children:[e.jsxs("div",{className:"flex min-w-0 gap-4",children:[e.jsxs("div",{className:"flex min-w-0 flex-col gap-1",children:[t.tags.length?e.jsx("div",{className:"flex gap-2",children:t.tags.map(n=>e.jsxs("div",{className:"bg-accent flex items-center justify-center gap-1 rounded-full px-2 py-1 text-sm",children:[e.jsx("span",{className:"h-3 w-3 leading-3",children:e.jsx(U,{name:n.emojiName,url:n.emojiUrl})}),e.jsx("span",{children:n.name})]},`${n.name}-${n.emojiName??n.emojiUrl??"tag"}`))}):null,e.jsx("strong",{className:"text-xl font-bold",children:t.name}),e.jsxs("div",{className:"flex min-w-0 flex-col gap-1",children:[e.jsxs("div",{className:"flex items-center gap-1",children:[t.authorAvatarUrl?e.jsx("img",{src:t.authorAvatarUrl,alt:"",className:"h-6 w-6 rounded-full"}):null,e.jsxs("span",{children:[e.jsx("span",{className:"font-bold",style:t.authorHexAccentColor?{color:t.authorHexAccentColor}:{},children:t.authorDisplayName}),":"," "]})]}),e.jsx("span",{className:"text-muted-foreground line-clamp-4 min-w-0",children:t.messagePreview})]})]}),t.previewImageUrl?e.jsx("img",{src:t.previewImageUrl,alt:"",className:"h-28 w-28 rounded-lg object-cover"}):null]}),e.jsxs("div",{className:"flex justify-between",children:[e.jsxs("div",{className:"flex items-center gap-3",children:[e.jsx("span",{children:s.length?e.jsx("ul",{className:"flex items-center gap-2",children:s.map((n,r)=>e.jsxs("li",{className:"border-info/60 bg-info/10 text-info flex items-center gap-1 rounded-md border px-[5px] py-[0.5px] text-sm",children:[e.jsx("span",{className:"h-3 w-3 leading-3",children:e.jsx(U,{name:n.emojiName,url:n.emojiUrl})}),e.jsx("span",{children:n.count})]},`${n.emojiName??n.emojiUrl??"reaction"}-${r}`))}):null}),e.jsxs("span",{className:"flex items-center gap-1",children:[e.jsxs("span",{className:"inline-flex items-center gap-1",children:[e.jsx(N,{name:"Chat"})," ",t.messageCount]}),` · ${t.lastUpdatedDisplay}`]})]}),e.jsxs("span",{className:"flex items-center gap-4",children:[e.jsx("a",{href:t.link.replace(/^https/,"discord"),children:e.jsx(N,{name:"Discord"})}),e.jsx("a",{href:t.link,target:"_blank",rel:"noreferrer noopener",children:e.jsx(N,{name:"ExternalLink"})})]})]})]})})}function U({name:t,url:s}){return s?e.jsx("img",{src:s,alt:t,className:"h-full w-full"}):t||null}function Be({status:t}){const s={running:{pinger:"bg-yellow-500/60",circle:"bg-yellow-500"},passed:{circle:"bg-success"},failed:{circle:"bg-destructive"},stopped:{circle:"bg-muted-foreground"}}[t];return e.jsxs("span",{className:"relative flex h-3 w-3",children:[s.pinger?e.jsx("span",{className:`absolute inline-flex h-full w-full animate-ping rounded-full ${s.pinger} opacity-75`}):null,e.jsx("span",{className:`relative inline-flex h-3 w-3 rounded-full ${s.circle}`})]})}function lt(t,s,n){const r=new URLSearchParams(t);return s===n?r.delete("preview"):r.set("preview",s),r}function ct({tabs:t}){return e.jsx(Oe,{className:"scrollbar-thin scrollbar-thumb-scrollbar h-14 min-h-14 overflow-x-auto border-b whitespace-nowrap",children:t.map(s=>e.jsx(Ke,{value:s.id,hidden:s.hidden,asChild:!0,children:e.jsx(M,{id:`${s.id}-tab`,className:fe("clip-path-button radix-state-active:z-10 radix-state-active:bg-foreground radix-state-active:text-background radix-state-active:hover:bg-foreground/80 radix-state-active:hover:text-background/80 radix-state-inactive:hover:bg-foreground/20 radix-state-inactive:hover:text-foreground/80 focus:bg-foreground/80 focus:text-background/80 relative h-full px-6 py-4 font-mono text-sm uppercase outline-none",s.hidden?"hidden":"inline-block"),preventScrollReset:!0,prefetch:"intent",onClick:s.onClick,to:s.to,children:e.jsxs("span",{className:"flex items-center gap-2",children:[s.status?e.jsx(Be,{status:s.status}):null,e.jsx("span",{children:s.label})]})})},s.id))})}function ut({appInfo:t,inBrowserBrowserRef:s,problemAppName:n,allApps:r,isUpToDate:a}){return e.jsx(Ie,{playgroundAppName:t?.appName,problemAppName:n,allApps:r,isUpToDate:a,children:t?.dev?.type==="none"?e.jsxs("div",{className:"flex h-full flex-col items-center justify-center gap-4",children:[e.jsx("div",{className:"text-secondary-foreground text-2xl",children:"Non-UI exercise"}),e.jsxs("div",{className:"text-secondary-foreground max-w-md text-center text-balance",children:["This exercise has no application or other UI associated with it."," ",e.jsx("br",{}),"Navigate to"," ",e.jsx(je,{content:t.fullPath,children:e.jsxs("span",{className:"inline-flex cursor-pointer items-center gap-1.5 underline",onClick:()=>{navigator.clipboard.writeText(t.fullPath),Ne.success("Copied playground path to clipboard")},children:["the playground directory",e.jsx(N,{name:"Copy",size:"sm"})]})})," ","in your editor and follow the exercise instructions to complete it."]})]}):t?e.jsx(Ce,{id:t.appName,appInfo:t,inBrowserBrowserRef:s}):e.jsxs("div",{className:"flex flex-col justify-center gap-2",children:[e.jsx("p",{children:"Please set the playground first"}),n?e.jsx(Te,{appName:n}):null]})})}export{at as C,it as D,ct as P,ot as R,ut as a,lt as g};
2
+ //# sourceMappingURL=playground-DIm_r4fy.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"playground-xNPUi1cK.js","sources":["../../../../../node_modules/@radix-ui/react-roving-focus/dist/index.mjs","../../../../../node_modules/@radix-ui/react-tabs/dist/index.mjs","../../../app/components/discord-chat.tsx","../../../app/components/status-indicator.tsx","../../../app/components/preview-tabs.tsx","../../../app/routes/_app+/exercise+/$exerciseNumber_.$stepNumber.$type+/__shared/playground.tsx"],"sourcesContent":["\"use client\";\n\n// src/roving-focus-group.tsx\nimport * as React from \"react\";\nimport { composeEventHandlers } from \"@radix-ui/primitive\";\nimport { createCollection } from \"@radix-ui/react-collection\";\nimport { useComposedRefs } from \"@radix-ui/react-compose-refs\";\nimport { createContextScope } from \"@radix-ui/react-context\";\nimport { useId } from \"@radix-ui/react-id\";\nimport { Primitive } from \"@radix-ui/react-primitive\";\nimport { useCallbackRef } from \"@radix-ui/react-use-callback-ref\";\nimport { useControllableState } from \"@radix-ui/react-use-controllable-state\";\nimport { useDirection } from \"@radix-ui/react-direction\";\nimport { jsx } from \"react/jsx-runtime\";\nvar ENTRY_FOCUS = \"rovingFocusGroup.onEntryFocus\";\nvar EVENT_OPTIONS = { bubbles: false, cancelable: true };\nvar GROUP_NAME = \"RovingFocusGroup\";\nvar [Collection, useCollection, createCollectionScope] = createCollection(GROUP_NAME);\nvar [createRovingFocusGroupContext, createRovingFocusGroupScope] = createContextScope(\n GROUP_NAME,\n [createCollectionScope]\n);\nvar [RovingFocusProvider, useRovingFocusContext] = createRovingFocusGroupContext(GROUP_NAME);\nvar RovingFocusGroup = React.forwardRef(\n (props, forwardedRef) => {\n return /* @__PURE__ */ jsx(Collection.Provider, { scope: props.__scopeRovingFocusGroup, children: /* @__PURE__ */ jsx(Collection.Slot, { scope: props.__scopeRovingFocusGroup, children: /* @__PURE__ */ jsx(RovingFocusGroupImpl, { ...props, ref: forwardedRef }) }) });\n }\n);\nRovingFocusGroup.displayName = GROUP_NAME;\nvar RovingFocusGroupImpl = React.forwardRef((props, forwardedRef) => {\n const {\n __scopeRovingFocusGroup,\n orientation,\n loop = false,\n dir,\n currentTabStopId: currentTabStopIdProp,\n defaultCurrentTabStopId,\n onCurrentTabStopIdChange,\n onEntryFocus,\n preventScrollOnEntryFocus = false,\n ...groupProps\n } = props;\n const ref = React.useRef(null);\n const composedRefs = useComposedRefs(forwardedRef, ref);\n const direction = useDirection(dir);\n const [currentTabStopId, setCurrentTabStopId] = useControllableState({\n prop: currentTabStopIdProp,\n defaultProp: defaultCurrentTabStopId ?? null,\n onChange: onCurrentTabStopIdChange,\n caller: GROUP_NAME\n });\n const [isTabbingBackOut, setIsTabbingBackOut] = React.useState(false);\n const handleEntryFocus = useCallbackRef(onEntryFocus);\n const getItems = useCollection(__scopeRovingFocusGroup);\n const isClickFocusRef = React.useRef(false);\n const [focusableItemsCount, setFocusableItemsCount] = React.useState(0);\n React.useEffect(() => {\n const node = ref.current;\n if (node) {\n node.addEventListener(ENTRY_FOCUS, handleEntryFocus);\n return () => node.removeEventListener(ENTRY_FOCUS, handleEntryFocus);\n }\n }, [handleEntryFocus]);\n return /* @__PURE__ */ jsx(\n RovingFocusProvider,\n {\n scope: __scopeRovingFocusGroup,\n orientation,\n dir: direction,\n loop,\n currentTabStopId,\n onItemFocus: React.useCallback(\n (tabStopId) => setCurrentTabStopId(tabStopId),\n [setCurrentTabStopId]\n ),\n onItemShiftTab: React.useCallback(() => setIsTabbingBackOut(true), []),\n onFocusableItemAdd: React.useCallback(\n () => setFocusableItemsCount((prevCount) => prevCount + 1),\n []\n ),\n onFocusableItemRemove: React.useCallback(\n () => setFocusableItemsCount((prevCount) => prevCount - 1),\n []\n ),\n children: /* @__PURE__ */ jsx(\n Primitive.div,\n {\n tabIndex: isTabbingBackOut || focusableItemsCount === 0 ? -1 : 0,\n \"data-orientation\": orientation,\n ...groupProps,\n ref: composedRefs,\n style: { outline: \"none\", ...props.style },\n onMouseDown: composeEventHandlers(props.onMouseDown, () => {\n isClickFocusRef.current = true;\n }),\n onFocus: composeEventHandlers(props.onFocus, (event) => {\n const isKeyboardFocus = !isClickFocusRef.current;\n if (event.target === event.currentTarget && isKeyboardFocus && !isTabbingBackOut) {\n const entryFocusEvent = new CustomEvent(ENTRY_FOCUS, EVENT_OPTIONS);\n event.currentTarget.dispatchEvent(entryFocusEvent);\n if (!entryFocusEvent.defaultPrevented) {\n const items = getItems().filter((item) => item.focusable);\n const activeItem = items.find((item) => item.active);\n const currentItem = items.find((item) => item.id === currentTabStopId);\n const candidateItems = [activeItem, currentItem, ...items].filter(\n Boolean\n );\n const candidateNodes = candidateItems.map((item) => item.ref.current);\n focusFirst(candidateNodes, preventScrollOnEntryFocus);\n }\n }\n isClickFocusRef.current = false;\n }),\n onBlur: composeEventHandlers(props.onBlur, () => setIsTabbingBackOut(false))\n }\n )\n }\n );\n});\nvar ITEM_NAME = \"RovingFocusGroupItem\";\nvar RovingFocusGroupItem = React.forwardRef(\n (props, forwardedRef) => {\n const {\n __scopeRovingFocusGroup,\n focusable = true,\n active = false,\n tabStopId,\n children,\n ...itemProps\n } = props;\n const autoId = useId();\n const id = tabStopId || autoId;\n const context = useRovingFocusContext(ITEM_NAME, __scopeRovingFocusGroup);\n const isCurrentTabStop = context.currentTabStopId === id;\n const getItems = useCollection(__scopeRovingFocusGroup);\n const { onFocusableItemAdd, onFocusableItemRemove, currentTabStopId } = context;\n React.useEffect(() => {\n if (focusable) {\n onFocusableItemAdd();\n return () => onFocusableItemRemove();\n }\n }, [focusable, onFocusableItemAdd, onFocusableItemRemove]);\n return /* @__PURE__ */ jsx(\n Collection.ItemSlot,\n {\n scope: __scopeRovingFocusGroup,\n id,\n focusable,\n active,\n children: /* @__PURE__ */ jsx(\n Primitive.span,\n {\n tabIndex: isCurrentTabStop ? 0 : -1,\n \"data-orientation\": context.orientation,\n ...itemProps,\n ref: forwardedRef,\n onMouseDown: composeEventHandlers(props.onMouseDown, (event) => {\n if (!focusable) event.preventDefault();\n else context.onItemFocus(id);\n }),\n onFocus: composeEventHandlers(props.onFocus, () => context.onItemFocus(id)),\n onKeyDown: composeEventHandlers(props.onKeyDown, (event) => {\n if (event.key === \"Tab\" && event.shiftKey) {\n context.onItemShiftTab();\n return;\n }\n if (event.target !== event.currentTarget) return;\n const focusIntent = getFocusIntent(event, context.orientation, context.dir);\n if (focusIntent !== void 0) {\n if (event.metaKey || event.ctrlKey || event.altKey || event.shiftKey) return;\n event.preventDefault();\n const items = getItems().filter((item) => item.focusable);\n let candidateNodes = items.map((item) => item.ref.current);\n if (focusIntent === \"last\") candidateNodes.reverse();\n else if (focusIntent === \"prev\" || focusIntent === \"next\") {\n if (focusIntent === \"prev\") candidateNodes.reverse();\n const currentIndex = candidateNodes.indexOf(event.currentTarget);\n candidateNodes = context.loop ? wrapArray(candidateNodes, currentIndex + 1) : candidateNodes.slice(currentIndex + 1);\n }\n setTimeout(() => focusFirst(candidateNodes));\n }\n }),\n children: typeof children === \"function\" ? children({ isCurrentTabStop, hasTabStop: currentTabStopId != null }) : children\n }\n )\n }\n );\n }\n);\nRovingFocusGroupItem.displayName = ITEM_NAME;\nvar MAP_KEY_TO_FOCUS_INTENT = {\n ArrowLeft: \"prev\",\n ArrowUp: \"prev\",\n ArrowRight: \"next\",\n ArrowDown: \"next\",\n PageUp: \"first\",\n Home: \"first\",\n PageDown: \"last\",\n End: \"last\"\n};\nfunction getDirectionAwareKey(key, dir) {\n if (dir !== \"rtl\") return key;\n return key === \"ArrowLeft\" ? \"ArrowRight\" : key === \"ArrowRight\" ? \"ArrowLeft\" : key;\n}\nfunction getFocusIntent(event, orientation, dir) {\n const key = getDirectionAwareKey(event.key, dir);\n if (orientation === \"vertical\" && [\"ArrowLeft\", \"ArrowRight\"].includes(key)) return void 0;\n if (orientation === \"horizontal\" && [\"ArrowUp\", \"ArrowDown\"].includes(key)) return void 0;\n return MAP_KEY_TO_FOCUS_INTENT[key];\n}\nfunction focusFirst(candidates, preventScroll = false) {\n const PREVIOUSLY_FOCUSED_ELEMENT = document.activeElement;\n for (const candidate of candidates) {\n if (candidate === PREVIOUSLY_FOCUSED_ELEMENT) return;\n candidate.focus({ preventScroll });\n if (document.activeElement !== PREVIOUSLY_FOCUSED_ELEMENT) return;\n }\n}\nfunction wrapArray(array, startIndex) {\n return array.map((_, index) => array[(startIndex + index) % array.length]);\n}\nvar Root = RovingFocusGroup;\nvar Item = RovingFocusGroupItem;\nexport {\n Item,\n Root,\n RovingFocusGroup,\n RovingFocusGroupItem,\n createRovingFocusGroupScope\n};\n//# sourceMappingURL=index.mjs.map\n","\"use client\";\n\n// src/tabs.tsx\nimport * as React from \"react\";\nimport { composeEventHandlers } from \"@radix-ui/primitive\";\nimport { createContextScope } from \"@radix-ui/react-context\";\nimport { createRovingFocusGroupScope } from \"@radix-ui/react-roving-focus\";\nimport { Presence } from \"@radix-ui/react-presence\";\nimport { Primitive } from \"@radix-ui/react-primitive\";\nimport * as RovingFocusGroup from \"@radix-ui/react-roving-focus\";\nimport { useDirection } from \"@radix-ui/react-direction\";\nimport { useControllableState } from \"@radix-ui/react-use-controllable-state\";\nimport { useId } from \"@radix-ui/react-id\";\nimport { jsx } from \"react/jsx-runtime\";\nvar TABS_NAME = \"Tabs\";\nvar [createTabsContext, createTabsScope] = createContextScope(TABS_NAME, [\n createRovingFocusGroupScope\n]);\nvar useRovingFocusGroupScope = createRovingFocusGroupScope();\nvar [TabsProvider, useTabsContext] = createTabsContext(TABS_NAME);\nvar Tabs = React.forwardRef(\n (props, forwardedRef) => {\n const {\n __scopeTabs,\n value: valueProp,\n onValueChange,\n defaultValue,\n orientation = \"horizontal\",\n dir,\n activationMode = \"automatic\",\n ...tabsProps\n } = props;\n const direction = useDirection(dir);\n const [value, setValue] = useControllableState({\n prop: valueProp,\n onChange: onValueChange,\n defaultProp: defaultValue ?? \"\",\n caller: TABS_NAME\n });\n return /* @__PURE__ */ jsx(\n TabsProvider,\n {\n scope: __scopeTabs,\n baseId: useId(),\n value,\n onValueChange: setValue,\n orientation,\n dir: direction,\n activationMode,\n children: /* @__PURE__ */ jsx(\n Primitive.div,\n {\n dir: direction,\n \"data-orientation\": orientation,\n ...tabsProps,\n ref: forwardedRef\n }\n )\n }\n );\n }\n);\nTabs.displayName = TABS_NAME;\nvar TAB_LIST_NAME = \"TabsList\";\nvar TabsList = React.forwardRef(\n (props, forwardedRef) => {\n const { __scopeTabs, loop = true, ...listProps } = props;\n const context = useTabsContext(TAB_LIST_NAME, __scopeTabs);\n const rovingFocusGroupScope = useRovingFocusGroupScope(__scopeTabs);\n return /* @__PURE__ */ jsx(\n RovingFocusGroup.Root,\n {\n asChild: true,\n ...rovingFocusGroupScope,\n orientation: context.orientation,\n dir: context.dir,\n loop,\n children: /* @__PURE__ */ jsx(\n Primitive.div,\n {\n role: \"tablist\",\n \"aria-orientation\": context.orientation,\n ...listProps,\n ref: forwardedRef\n }\n )\n }\n );\n }\n);\nTabsList.displayName = TAB_LIST_NAME;\nvar TRIGGER_NAME = \"TabsTrigger\";\nvar TabsTrigger = React.forwardRef(\n (props, forwardedRef) => {\n const { __scopeTabs, value, disabled = false, ...triggerProps } = props;\n const context = useTabsContext(TRIGGER_NAME, __scopeTabs);\n const rovingFocusGroupScope = useRovingFocusGroupScope(__scopeTabs);\n const triggerId = makeTriggerId(context.baseId, value);\n const contentId = makeContentId(context.baseId, value);\n const isSelected = value === context.value;\n return /* @__PURE__ */ jsx(\n RovingFocusGroup.Item,\n {\n asChild: true,\n ...rovingFocusGroupScope,\n focusable: !disabled,\n active: isSelected,\n children: /* @__PURE__ */ jsx(\n Primitive.button,\n {\n type: \"button\",\n role: \"tab\",\n \"aria-selected\": isSelected,\n \"aria-controls\": contentId,\n \"data-state\": isSelected ? \"active\" : \"inactive\",\n \"data-disabled\": disabled ? \"\" : void 0,\n disabled,\n id: triggerId,\n ...triggerProps,\n ref: forwardedRef,\n onMouseDown: composeEventHandlers(props.onMouseDown, (event) => {\n if (!disabled && event.button === 0 && event.ctrlKey === false) {\n context.onValueChange(value);\n } else {\n event.preventDefault();\n }\n }),\n onKeyDown: composeEventHandlers(props.onKeyDown, (event) => {\n if ([\" \", \"Enter\"].includes(event.key)) context.onValueChange(value);\n }),\n onFocus: composeEventHandlers(props.onFocus, () => {\n const isAutomaticActivation = context.activationMode !== \"manual\";\n if (!isSelected && !disabled && isAutomaticActivation) {\n context.onValueChange(value);\n }\n })\n }\n )\n }\n );\n }\n);\nTabsTrigger.displayName = TRIGGER_NAME;\nvar CONTENT_NAME = \"TabsContent\";\nvar TabsContent = React.forwardRef(\n (props, forwardedRef) => {\n const { __scopeTabs, value, forceMount, children, ...contentProps } = props;\n const context = useTabsContext(CONTENT_NAME, __scopeTabs);\n const triggerId = makeTriggerId(context.baseId, value);\n const contentId = makeContentId(context.baseId, value);\n const isSelected = value === context.value;\n const isMountAnimationPreventedRef = React.useRef(isSelected);\n React.useEffect(() => {\n const rAF = requestAnimationFrame(() => isMountAnimationPreventedRef.current = false);\n return () => cancelAnimationFrame(rAF);\n }, []);\n return /* @__PURE__ */ jsx(Presence, { present: forceMount || isSelected, children: ({ present }) => /* @__PURE__ */ jsx(\n Primitive.div,\n {\n \"data-state\": isSelected ? \"active\" : \"inactive\",\n \"data-orientation\": context.orientation,\n role: \"tabpanel\",\n \"aria-labelledby\": triggerId,\n hidden: !present,\n id: contentId,\n tabIndex: 0,\n ...contentProps,\n ref: forwardedRef,\n style: {\n ...props.style,\n animationDuration: isMountAnimationPreventedRef.current ? \"0s\" : void 0\n },\n children: present && children\n }\n ) });\n }\n);\nTabsContent.displayName = CONTENT_NAME;\nfunction makeTriggerId(baseId, value) {\n return `${baseId}-trigger-${value}`;\n}\nfunction makeContentId(baseId, value) {\n return `${baseId}-content-${value}`;\n}\nvar Root2 = Tabs;\nvar List = TabsList;\nvar Trigger = TabsTrigger;\nvar Content = TabsContent;\nexport {\n Content,\n List,\n Root2 as Root,\n Tabs,\n TabsContent,\n TabsList,\n TabsTrigger,\n Trigger,\n createTabsScope\n};\n//# sourceMappingURL=index.mjs.map\n","import * as React from 'react'\nimport { Await, Link } from 'react-router'\nimport { Icon } from '#app/components/icons.tsx'\nimport { Loading } from '#app/components/loading.tsx'\nimport { DiscordCTA, useDiscordCTALink } from '#app/routes/_app+/discord.tsx'\nimport { useAltDown } from '#app/utils/misc.tsx'\nimport { useIsOnline } from '#app/utils/online.ts'\n\ntype EmojiData = {\n\temojiName?: string\n\temojiUrl?: string\n}\n\ntype DiscordTag = { name: string } & EmojiData\ntype DiscordReaction = { count: number } & EmojiData\n\nexport type DiscordThread = {\n\tid: string\n\ttags: DiscordTag[]\n\tname: string\n\tlink: string\n\tauthorDisplayName: string\n\tauthorHexAccentColor?: string | null\n\tauthorAvatarUrl: string | null\n\tmessagePreview: string\n\tmessageCount: number\n\tlastUpdated: string\n\tlastUpdatedDisplay: string\n\tpreviewImageUrl: string | null\n\treactions: DiscordReaction[]\n}\n\nexport function DiscordChat({\n\tdiscordPostsPromise,\n}: {\n\tdiscordPostsPromise: Promise<DiscordThread[]>\n}) {\n\treturn (\n\t\t<div className=\"flex h-full w-full flex-col gap-4 pt-4\">\n\t\t\t<div className=\"text-center\">\n\t\t\t\t<DiscordCTA />\n\t\t\t</div>\n\t\t\t<div className=\"bg-accent scrollbar-thin scrollbar-thumb-scrollbar flex-1 overflow-y-scroll pb-4\">\n\t\t\t\t<DiscordPosts discordPostsPromise={discordPostsPromise} />\n\t\t\t</div>\n\t\t</div>\n\t)\n}\n\nfunction DiscordPosts({\n\tdiscordPostsPromise,\n}: {\n\tdiscordPostsPromise: Promise<DiscordThread[]>\n}) {\n\tconst ctaLink = useDiscordCTALink()\n\tconst altDown = useAltDown()\n\tconst isOnline = useIsOnline()\n\tif (!isOnline) {\n\t\treturn (\n\t\t\t<div className=\"flex h-full flex-col items-center justify-between\">\n\t\t\t\t<div className=\"text-foreground-destructive flex h-full w-full flex-col items-center justify-center\">\n\t\t\t\t\t<Icon name=\"WifiNoConnection\" size=\"xl\">\n\t\t\t\t\t\tUnable to load discord messages when offline\n\t\t\t\t\t</Icon>\n\t\t\t\t</div>\n\t\t\t</div>\n\t\t)\n\t}\n\treturn (\n\t\t<div className=\"flex h-full flex-col items-center justify-between\">\n\t\t\t<React.Suspense\n\t\t\t\tfallback={\n\t\t\t\t\t<div className=\"flex h-full w-full flex-col items-center justify-center\">\n\t\t\t\t\t\t<Loading>Loading Discord Posts</Loading>\n\t\t\t\t\t</div>\n\t\t\t\t}\n\t\t\t>\n\t\t\t\t<Await\n\t\t\t\t\tresolve={discordPostsPromise}\n\t\t\t\t\terrorElement={\n\t\t\t\t\t\t<div className=\"text-foreground-destructive\">\n\t\t\t\t\t\t\tThere was a problem loading the discord posts\n\t\t\t\t\t\t</div>\n\t\t\t\t\t}\n\t\t\t\t>\n\t\t\t\t\t{(posts) => (\n\t\t\t\t\t\t<ul className=\"flex w-full flex-col gap-4 p-3 xl:p-12\">\n\t\t\t\t\t\t\t{posts.map((post) => (\n\t\t\t\t\t\t\t\t<li\n\t\t\t\t\t\t\t\t\tkey={post.id}\n\t\t\t\t\t\t\t\t\tclassName=\"bg-background rounded-xl border transition-all duration-200 focus-within:-translate-y-1 focus-within:shadow-lg hover:-translate-y-1 hover:shadow-lg\"\n\t\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t\t<DiscordPost thread={post} />\n\t\t\t\t\t\t\t\t</li>\n\t\t\t\t\t\t\t))}\n\t\t\t\t\t\t</ul>\n\t\t\t\t\t)}\n\t\t\t\t</Await>\n\t\t\t</React.Suspense>\n\t\t\t<div>\n\t\t\t\t<Link\n\t\t\t\t\tto={\n\t\t\t\t\t\taltDown && !ctaLink.includes('oauth')\n\t\t\t\t\t\t\t? ctaLink.replace(/^https/, 'discord')\n\t\t\t\t\t\t\t: ctaLink\n\t\t\t\t\t}\n\t\t\t\t\ttarget={ctaLink.includes('oauth') ? undefined : '_blank'}\n\t\t\t\t\trel=\"noreferrer noopener\"\n\t\t\t\t\tonClick={\n\t\t\t\t\t\taltDown\n\t\t\t\t\t\t\t? (event) => {\n\t\t\t\t\t\t\t\t\tevent.preventDefault()\n\t\t\t\t\t\t\t\t\twindow.open(\n\t\t\t\t\t\t\t\t\t\tevent.currentTarget.href,\n\t\t\t\t\t\t\t\t\t\t'_blank',\n\t\t\t\t\t\t\t\t\t\t'noreferrer noopener',\n\t\t\t\t\t\t\t\t\t)\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t: undefined\n\t\t\t\t\t}\n\t\t\t\t\tclassName=\"flex items-center gap-2 p-2 text-xl hover:underline\"\n\t\t\t\t>\n\t\t\t\t\tCreate Post <Icon name=\"ExternalLink\" />\n\t\t\t\t</Link>\n\t\t\t</div>\n\t\t</div>\n\t)\n}\n\nfunction DiscordPost({ thread }: { thread: DiscordThread }) {\n\tconst reactionsWithCounts = thread.reactions.filter(\n\t\t(reaction) => reaction.count,\n\t)\n\n\treturn (\n\t\t<div>\n\t\t\t<div className=\"flex flex-col gap-2 p-4\">\n\t\t\t\t<div className=\"flex min-w-0 gap-4\">\n\t\t\t\t\t<div className=\"flex min-w-0 flex-col gap-1\">\n\t\t\t\t\t\t{thread.tags.length ? (\n\t\t\t\t\t\t\t<div className=\"flex gap-2\">\n\t\t\t\t\t\t\t\t{thread.tags.map((tag) => (\n\t\t\t\t\t\t\t\t\t<div\n\t\t\t\t\t\t\t\t\t\tkey={`${tag.name}-${tag.emojiName ?? tag.emojiUrl ?? 'tag'}`}\n\t\t\t\t\t\t\t\t\t\tclassName=\"bg-accent flex items-center justify-center gap-1 rounded-full px-2 py-1 text-sm\"\n\t\t\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t\t\t<span className=\"h-3 w-3 leading-3\">\n\t\t\t\t\t\t\t\t\t\t\t<Emoji name={tag.emojiName} url={tag.emojiUrl} />\n\t\t\t\t\t\t\t\t\t\t</span>\n\t\t\t\t\t\t\t\t\t\t<span>{tag.name}</span>\n\t\t\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t\t\t))}\n\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t) : null}\n\t\t\t\t\t\t<strong className=\"text-xl font-bold\">{thread.name}</strong>\n\t\t\t\t\t\t<div className=\"flex min-w-0 flex-col gap-1\">\n\t\t\t\t\t\t\t<div className=\"flex items-center gap-1\">\n\t\t\t\t\t\t\t\t{thread.authorAvatarUrl ? (\n\t\t\t\t\t\t\t\t\t<img\n\t\t\t\t\t\t\t\t\t\tsrc={thread.authorAvatarUrl}\n\t\t\t\t\t\t\t\t\t\talt=\"\"\n\t\t\t\t\t\t\t\t\t\tclassName=\"h-6 w-6 rounded-full\"\n\t\t\t\t\t\t\t\t\t/>\n\t\t\t\t\t\t\t\t) : null}\n\t\t\t\t\t\t\t\t<span>\n\t\t\t\t\t\t\t\t\t<span\n\t\t\t\t\t\t\t\t\t\tclassName=\"font-bold\"\n\t\t\t\t\t\t\t\t\t\tstyle={\n\t\t\t\t\t\t\t\t\t\t\tthread.authorHexAccentColor\n\t\t\t\t\t\t\t\t\t\t\t\t? { color: thread.authorHexAccentColor }\n\t\t\t\t\t\t\t\t\t\t\t\t: {}\n\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t\t\t{thread.authorDisplayName}\n\t\t\t\t\t\t\t\t\t</span>\n\t\t\t\t\t\t\t\t\t:{' '}\n\t\t\t\t\t\t\t\t</span>\n\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t\t<span className=\"text-muted-foreground line-clamp-4 min-w-0\">\n\t\t\t\t\t\t\t\t{thread.messagePreview}\n\t\t\t\t\t\t\t</span>\n\t\t\t\t\t\t</div>\n\t\t\t\t\t</div>\n\t\t\t\t\t{thread.previewImageUrl ? (\n\t\t\t\t\t\t<img\n\t\t\t\t\t\t\tsrc={thread.previewImageUrl}\n\t\t\t\t\t\t\talt=\"\"\n\t\t\t\t\t\t\tclassName=\"h-28 w-28 rounded-lg object-cover\"\n\t\t\t\t\t\t/>\n\t\t\t\t\t) : null}\n\t\t\t\t</div>\n\n\t\t\t\t<div className=\"flex justify-between\">\n\t\t\t\t\t<div className=\"flex items-center gap-3\">\n\t\t\t\t\t\t<span>\n\t\t\t\t\t\t\t{reactionsWithCounts.length ? (\n\t\t\t\t\t\t\t\t<ul className=\"flex items-center gap-2\">\n\t\t\t\t\t\t\t\t\t{reactionsWithCounts.map((reaction, index) => (\n\t\t\t\t\t\t\t\t\t\t<li\n\t\t\t\t\t\t\t\t\t\t\tkey={`${reaction.emojiName ?? reaction.emojiUrl ?? 'reaction'}-${index}`}\n\t\t\t\t\t\t\t\t\t\t\tclassName=\"border-info/60 bg-info/10 text-info flex items-center gap-1 rounded-md border px-[5px] py-[0.5px] text-sm\"\n\t\t\t\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t\t\t\t<span className=\"h-3 w-3 leading-3\">\n\t\t\t\t\t\t\t\t\t\t\t\t<Emoji\n\t\t\t\t\t\t\t\t\t\t\t\t\tname={reaction.emojiName}\n\t\t\t\t\t\t\t\t\t\t\t\t\turl={reaction.emojiUrl}\n\t\t\t\t\t\t\t\t\t\t\t\t/>\n\t\t\t\t\t\t\t\t\t\t\t</span>\n\t\t\t\t\t\t\t\t\t\t\t<span>{reaction.count}</span>\n\t\t\t\t\t\t\t\t\t\t</li>\n\t\t\t\t\t\t\t\t\t))}\n\t\t\t\t\t\t\t\t</ul>\n\t\t\t\t\t\t\t) : null}\n\t\t\t\t\t\t</span>\n\t\t\t\t\t\t<span className=\"flex items-center gap-1\">\n\t\t\t\t\t\t\t<span className=\"inline-flex items-center gap-1\">\n\t\t\t\t\t\t\t\t<Icon name=\"Chat\" /> {thread.messageCount}\n\t\t\t\t\t\t\t</span>\n\t\t\t\t\t\t\t{` · ${thread.lastUpdatedDisplay}`}\n\t\t\t\t\t\t</span>\n\t\t\t\t\t</div>\n\t\t\t\t\t<span className=\"flex items-center gap-4\">\n\t\t\t\t\t\t<a href={thread.link.replace(/^https/, 'discord')}>\n\t\t\t\t\t\t\t<Icon name=\"Discord\" />\n\t\t\t\t\t\t</a>\n\t\t\t\t\t\t<a href={thread.link} target=\"_blank\" rel=\"noreferrer noopener\">\n\t\t\t\t\t\t\t<Icon name=\"ExternalLink\" />\n\t\t\t\t\t\t</a>\n\t\t\t\t\t</span>\n\t\t\t\t</div>\n\t\t\t</div>\n\t\t</div>\n\t)\n}\n\nfunction Emoji({ name, url }: { name?: string; url?: string }) {\n\treturn url ? (\n\t\t<img src={url} alt={name} className=\"h-full w-full\" />\n\t) : name ? (\n\t\tname\n\t) : null\n}\n","export function StatusIndicator({\n\tstatus,\n}: {\n\tstatus: 'running' | 'passed' | 'failed' | 'stopped'\n}) {\n\tconst colors = {\n\t\trunning: {\n\t\t\tpinger: 'bg-yellow-500/60',\n\t\t\tcircle: 'bg-yellow-500',\n\t\t},\n\t\tpassed: {\n\t\t\tcircle: 'bg-success',\n\t\t},\n\t\tfailed: {\n\t\t\tcircle: 'bg-destructive',\n\t\t},\n\t\tstopped: {\n\t\t\tcircle: 'bg-muted-foreground',\n\t\t},\n\t}[status]\n\treturn (\n\t\t<span className=\"relative flex h-3 w-3\">\n\t\t\t{colors.pinger ? (\n\t\t\t\t<span\n\t\t\t\t\tclassName={`absolute inline-flex h-full w-full animate-ping rounded-full ${colors.pinger} opacity-75`}\n\t\t\t\t/>\n\t\t\t) : null}\n\t\t\t<span\n\t\t\t\tclassName={`relative inline-flex h-3 w-3 rounded-full ${colors.circle}`}\n\t\t\t/>\n\t\t</span>\n\t)\n}\n","import * as Tabs from '@radix-ui/react-tabs'\nimport * as React from 'react'\nimport { Link } from 'react-router'\nimport { StatusIndicator } from '#app/components/status-indicator.tsx'\nimport { cn } from '#app/utils/misc.tsx'\n\nexport type PreviewTab = {\n\tid: string\n\tlabel: string\n\tto: string\n\thidden?: boolean\n\tstatus?: 'running' | 'passed' | 'failed' | null\n\tonClick?: React.MouseEventHandler<HTMLAnchorElement>\n}\n\nexport function getPreviewSearchParams(\n\tsearchParams: URLSearchParams,\n\tpreviewValue: string,\n\tdefaultValue: string,\n) {\n\tconst next = new URLSearchParams(searchParams)\n\t// Keep URLs clean by omitting the preview param for the default tab.\n\tif (previewValue === defaultValue) {\n\t\tnext.delete('preview')\n\t} else {\n\t\tnext.set('preview', previewValue)\n\t}\n\treturn next\n}\n\nexport function PreviewTabsList({ tabs }: { tabs: PreviewTab[] }) {\n\treturn (\n\t\t<Tabs.List className=\"scrollbar-thin scrollbar-thumb-scrollbar h-14 min-h-14 overflow-x-auto border-b whitespace-nowrap\">\n\t\t\t{tabs.map((tab) => (\n\t\t\t\t<Tabs.Trigger key={tab.id} value={tab.id} hidden={tab.hidden} asChild>\n\t\t\t\t\t<Link\n\t\t\t\t\t\tid={`${tab.id}-tab`}\n\t\t\t\t\t\tclassName={cn(\n\t\t\t\t\t\t\t'clip-path-button radix-state-active:z-10 radix-state-active:bg-foreground radix-state-active:text-background radix-state-active:hover:bg-foreground/80 radix-state-active:hover:text-background/80 radix-state-inactive:hover:bg-foreground/20 radix-state-inactive:hover:text-foreground/80 focus:bg-foreground/80 focus:text-background/80 relative h-full px-6 py-4 font-mono text-sm uppercase outline-none',\n\t\t\t\t\t\t\ttab.hidden ? 'hidden' : 'inline-block',\n\t\t\t\t\t\t)}\n\t\t\t\t\t\tpreventScrollReset\n\t\t\t\t\t\tprefetch=\"intent\"\n\t\t\t\t\t\tonClick={tab.onClick}\n\t\t\t\t\t\tto={tab.to}\n\t\t\t\t\t>\n\t\t\t\t\t\t<span className=\"flex items-center gap-2\">\n\t\t\t\t\t\t\t{tab.status ? <StatusIndicator status={tab.status} /> : null}\n\t\t\t\t\t\t\t<span>{tab.label}</span>\n\t\t\t\t\t\t</span>\n\t\t\t\t\t</Link>\n\t\t\t\t</Tabs.Trigger>\n\t\t\t))}\n\t\t</Tabs.List>\n\t)\n}\n","import { toast as showToast } from 'sonner'\nimport { Icon } from '#app/components/icons.tsx'\nimport { type InBrowserBrowserRef } from '#app/components/in-browser-browser'\nimport { SimpleTooltip } from '#app/components/ui/tooltip'\nimport { SetAppToPlayground } from '#app/routes/set-playground'\nimport { PlaygroundWindow } from './playground-window'\nimport { Preview } from './preview'\n\nexport function Playground({\n\tappInfo: playgroundAppInfo,\n\tinBrowserBrowserRef,\n\tproblemAppName,\n\tallApps,\n\tisUpToDate,\n}: {\n\tappInfo: Parameters<typeof Preview>['0']['appInfo'] | null\n\tinBrowserBrowserRef: React.RefObject<InBrowserBrowserRef | null>\n\tproblemAppName?: string\n\tallApps: Array<{ name: string; displayName: string }>\n\tisUpToDate: boolean\n}) {\n\treturn (\n\t\t<PlaygroundWindow\n\t\t\tplaygroundAppName={playgroundAppInfo?.appName}\n\t\t\tproblemAppName={problemAppName}\n\t\t\tallApps={allApps}\n\t\t\tisUpToDate={isUpToDate}\n\t\t>\n\t\t\t{playgroundAppInfo?.dev?.type === 'none' ? (\n\t\t\t\t<div className=\"flex h-full flex-col items-center justify-center gap-4\">\n\t\t\t\t\t<div className=\"text-secondary-foreground text-2xl\">\n\t\t\t\t\t\tNon-UI exercise\n\t\t\t\t\t</div>\n\t\t\t\t\t<div className=\"text-secondary-foreground max-w-md text-center text-balance\">\n\t\t\t\t\t\tThis exercise has no application or other UI associated with it.{' '}\n\t\t\t\t\t\t<br />\n\t\t\t\t\t\tNavigate to{' '}\n\t\t\t\t\t\t<SimpleTooltip content={playgroundAppInfo.fullPath}>\n\t\t\t\t\t\t\t<span\n\t\t\t\t\t\t\t\tclassName=\"inline-flex cursor-pointer items-center gap-1.5 underline\"\n\t\t\t\t\t\t\t\tonClick={() => {\n\t\t\t\t\t\t\t\t\tvoid navigator.clipboard.writeText(playgroundAppInfo.fullPath)\n\t\t\t\t\t\t\t\t\tshowToast.success('Copied playground path to clipboard')\n\t\t\t\t\t\t\t\t}}\n\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\tthe playground directory\n\t\t\t\t\t\t\t\t<Icon name=\"Copy\" size=\"sm\" />\n\t\t\t\t\t\t\t</span>\n\t\t\t\t\t\t</SimpleTooltip>{' '}\n\t\t\t\t\t\tin your editor and follow the exercise instructions to complete it.\n\t\t\t\t\t</div>\n\t\t\t\t</div>\n\t\t\t) : playgroundAppInfo ? (\n\t\t\t\t<Preview\n\t\t\t\t\tid={playgroundAppInfo.appName}\n\t\t\t\t\tappInfo={playgroundAppInfo}\n\t\t\t\t\tinBrowserBrowserRef={inBrowserBrowserRef}\n\t\t\t\t/>\n\t\t\t) : (\n\t\t\t\t<div className=\"flex flex-col justify-center gap-2\">\n\t\t\t\t\t<p>Please set the playground first</p>\n\t\t\t\t\t{problemAppName ? (\n\t\t\t\t\t\t<SetAppToPlayground appName={problemAppName} />\n\t\t\t\t\t) : null}\n\t\t\t\t</div>\n\t\t\t)}\n\t\t</PlaygroundWindow>\n\t)\n}\n"],"names":["ENTRY_FOCUS","EVENT_OPTIONS","GROUP_NAME","Collection","useCollection","createCollectionScope","createCollection","createRovingFocusGroupContext","createRovingFocusGroupScope","createContextScope","RovingFocusProvider","useRovingFocusContext","RovingFocusGroup","React.forwardRef","props","forwardedRef","jsx","RovingFocusGroupImpl","__scopeRovingFocusGroup","orientation","loop","dir","currentTabStopIdProp","defaultCurrentTabStopId","onCurrentTabStopIdChange","onEntryFocus","preventScrollOnEntryFocus","groupProps","ref","React.useRef","composedRefs","useComposedRefs","direction","useDirection","currentTabStopId","setCurrentTabStopId","useControllableState","isTabbingBackOut","setIsTabbingBackOut","React.useState","handleEntryFocus","useCallbackRef","getItems","isClickFocusRef","focusableItemsCount","setFocusableItemsCount","React.useEffect","node","React.useCallback","tabStopId","prevCount","Primitive","composeEventHandlers","event","isKeyboardFocus","entryFocusEvent","items","item","activeItem","currentItem","candidateNodes","focusFirst","ITEM_NAME","RovingFocusGroupItem","focusable","active","children","itemProps","autoId","useId","id","context","isCurrentTabStop","onFocusableItemAdd","onFocusableItemRemove","focusIntent","getFocusIntent","currentIndex","wrapArray","MAP_KEY_TO_FOCUS_INTENT","getDirectionAwareKey","key","candidates","preventScroll","PREVIOUSLY_FOCUSED_ELEMENT","candidate","array","startIndex","_","index","Root","Item","TABS_NAME","createTabsContext","useRovingFocusGroupScope","TabsProvider","useTabsContext","Tabs","__scopeTabs","valueProp","onValueChange","defaultValue","activationMode","tabsProps","value","setValue","TAB_LIST_NAME","TabsList","listProps","rovingFocusGroupScope","RovingFocusGroup.Root","TRIGGER_NAME","TabsTrigger","disabled","triggerProps","triggerId","makeTriggerId","contentId","makeContentId","isSelected","RovingFocusGroup.Item","isAutomaticActivation","CONTENT_NAME","TabsContent","forceMount","contentProps","isMountAnimationPreventedRef","rAF","Presence","present","baseId","Root2","List","Trigger","Content","DiscordChat","discordPostsPromise","jsxs","DiscordCTA","DiscordPosts","ctaLink","useDiscordCTALink","altDown","useAltDown","useIsOnline","React.Suspense","Loading","Await","posts","post","DiscordPost","Link","Icon","thread","reactionsWithCounts","reaction","tag","Emoji","name","url","StatusIndicator","status","colors","getPreviewSearchParams","searchParams","previewValue","next","PreviewTabsList","tabs","Tabs.List","tab","Tabs.Trigger","cn","Playground","playgroundAppInfo","inBrowserBrowserRef","problemAppName","allApps","isUpToDate","PlaygroundWindow","SimpleTooltip","showToast","Preview","SetAppToPlayground"],"mappings":"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","x_google_ignoreList":[0,1]}
1
+ {"version":3,"file":"playground-DIm_r4fy.js","sources":["../../../../../node_modules/@radix-ui/react-roving-focus/dist/index.mjs","../../../../../node_modules/@radix-ui/react-tabs/dist/index.mjs","../../../app/components/discord-chat.tsx","../../../app/components/status-indicator.tsx","../../../app/components/preview-tabs.tsx","../../../app/routes/_app+/exercise+/$exerciseNumber_.$stepNumber.$type+/__shared/playground.tsx"],"sourcesContent":["\"use client\";\n\n// src/roving-focus-group.tsx\nimport * as React from \"react\";\nimport { composeEventHandlers } from \"@radix-ui/primitive\";\nimport { createCollection } from \"@radix-ui/react-collection\";\nimport { useComposedRefs } from \"@radix-ui/react-compose-refs\";\nimport { createContextScope } from \"@radix-ui/react-context\";\nimport { useId } from \"@radix-ui/react-id\";\nimport { Primitive } from \"@radix-ui/react-primitive\";\nimport { useCallbackRef } from \"@radix-ui/react-use-callback-ref\";\nimport { useControllableState } from \"@radix-ui/react-use-controllable-state\";\nimport { useDirection } from \"@radix-ui/react-direction\";\nimport { jsx } from \"react/jsx-runtime\";\nvar ENTRY_FOCUS = \"rovingFocusGroup.onEntryFocus\";\nvar EVENT_OPTIONS = { bubbles: false, cancelable: true };\nvar GROUP_NAME = \"RovingFocusGroup\";\nvar [Collection, useCollection, createCollectionScope] = createCollection(GROUP_NAME);\nvar [createRovingFocusGroupContext, createRovingFocusGroupScope] = createContextScope(\n GROUP_NAME,\n [createCollectionScope]\n);\nvar [RovingFocusProvider, useRovingFocusContext] = createRovingFocusGroupContext(GROUP_NAME);\nvar RovingFocusGroup = React.forwardRef(\n (props, forwardedRef) => {\n return /* @__PURE__ */ jsx(Collection.Provider, { scope: props.__scopeRovingFocusGroup, children: /* @__PURE__ */ jsx(Collection.Slot, { scope: props.__scopeRovingFocusGroup, children: /* @__PURE__ */ jsx(RovingFocusGroupImpl, { ...props, ref: forwardedRef }) }) });\n }\n);\nRovingFocusGroup.displayName = GROUP_NAME;\nvar RovingFocusGroupImpl = React.forwardRef((props, forwardedRef) => {\n const {\n __scopeRovingFocusGroup,\n orientation,\n loop = false,\n dir,\n currentTabStopId: currentTabStopIdProp,\n defaultCurrentTabStopId,\n onCurrentTabStopIdChange,\n onEntryFocus,\n preventScrollOnEntryFocus = false,\n ...groupProps\n } = props;\n const ref = React.useRef(null);\n const composedRefs = useComposedRefs(forwardedRef, ref);\n const direction = useDirection(dir);\n const [currentTabStopId, setCurrentTabStopId] = useControllableState({\n prop: currentTabStopIdProp,\n defaultProp: defaultCurrentTabStopId ?? null,\n onChange: onCurrentTabStopIdChange,\n caller: GROUP_NAME\n });\n const [isTabbingBackOut, setIsTabbingBackOut] = React.useState(false);\n const handleEntryFocus = useCallbackRef(onEntryFocus);\n const getItems = useCollection(__scopeRovingFocusGroup);\n const isClickFocusRef = React.useRef(false);\n const [focusableItemsCount, setFocusableItemsCount] = React.useState(0);\n React.useEffect(() => {\n const node = ref.current;\n if (node) {\n node.addEventListener(ENTRY_FOCUS, handleEntryFocus);\n return () => node.removeEventListener(ENTRY_FOCUS, handleEntryFocus);\n }\n }, [handleEntryFocus]);\n return /* @__PURE__ */ jsx(\n RovingFocusProvider,\n {\n scope: __scopeRovingFocusGroup,\n orientation,\n dir: direction,\n loop,\n currentTabStopId,\n onItemFocus: React.useCallback(\n (tabStopId) => setCurrentTabStopId(tabStopId),\n [setCurrentTabStopId]\n ),\n onItemShiftTab: React.useCallback(() => setIsTabbingBackOut(true), []),\n onFocusableItemAdd: React.useCallback(\n () => setFocusableItemsCount((prevCount) => prevCount + 1),\n []\n ),\n onFocusableItemRemove: React.useCallback(\n () => setFocusableItemsCount((prevCount) => prevCount - 1),\n []\n ),\n children: /* @__PURE__ */ jsx(\n Primitive.div,\n {\n tabIndex: isTabbingBackOut || focusableItemsCount === 0 ? -1 : 0,\n \"data-orientation\": orientation,\n ...groupProps,\n ref: composedRefs,\n style: { outline: \"none\", ...props.style },\n onMouseDown: composeEventHandlers(props.onMouseDown, () => {\n isClickFocusRef.current = true;\n }),\n onFocus: composeEventHandlers(props.onFocus, (event) => {\n const isKeyboardFocus = !isClickFocusRef.current;\n if (event.target === event.currentTarget && isKeyboardFocus && !isTabbingBackOut) {\n const entryFocusEvent = new CustomEvent(ENTRY_FOCUS, EVENT_OPTIONS);\n event.currentTarget.dispatchEvent(entryFocusEvent);\n if (!entryFocusEvent.defaultPrevented) {\n const items = getItems().filter((item) => item.focusable);\n const activeItem = items.find((item) => item.active);\n const currentItem = items.find((item) => item.id === currentTabStopId);\n const candidateItems = [activeItem, currentItem, ...items].filter(\n Boolean\n );\n const candidateNodes = candidateItems.map((item) => item.ref.current);\n focusFirst(candidateNodes, preventScrollOnEntryFocus);\n }\n }\n isClickFocusRef.current = false;\n }),\n onBlur: composeEventHandlers(props.onBlur, () => setIsTabbingBackOut(false))\n }\n )\n }\n );\n});\nvar ITEM_NAME = \"RovingFocusGroupItem\";\nvar RovingFocusGroupItem = React.forwardRef(\n (props, forwardedRef) => {\n const {\n __scopeRovingFocusGroup,\n focusable = true,\n active = false,\n tabStopId,\n children,\n ...itemProps\n } = props;\n const autoId = useId();\n const id = tabStopId || autoId;\n const context = useRovingFocusContext(ITEM_NAME, __scopeRovingFocusGroup);\n const isCurrentTabStop = context.currentTabStopId === id;\n const getItems = useCollection(__scopeRovingFocusGroup);\n const { onFocusableItemAdd, onFocusableItemRemove, currentTabStopId } = context;\n React.useEffect(() => {\n if (focusable) {\n onFocusableItemAdd();\n return () => onFocusableItemRemove();\n }\n }, [focusable, onFocusableItemAdd, onFocusableItemRemove]);\n return /* @__PURE__ */ jsx(\n Collection.ItemSlot,\n {\n scope: __scopeRovingFocusGroup,\n id,\n focusable,\n active,\n children: /* @__PURE__ */ jsx(\n Primitive.span,\n {\n tabIndex: isCurrentTabStop ? 0 : -1,\n \"data-orientation\": context.orientation,\n ...itemProps,\n ref: forwardedRef,\n onMouseDown: composeEventHandlers(props.onMouseDown, (event) => {\n if (!focusable) event.preventDefault();\n else context.onItemFocus(id);\n }),\n onFocus: composeEventHandlers(props.onFocus, () => context.onItemFocus(id)),\n onKeyDown: composeEventHandlers(props.onKeyDown, (event) => {\n if (event.key === \"Tab\" && event.shiftKey) {\n context.onItemShiftTab();\n return;\n }\n if (event.target !== event.currentTarget) return;\n const focusIntent = getFocusIntent(event, context.orientation, context.dir);\n if (focusIntent !== void 0) {\n if (event.metaKey || event.ctrlKey || event.altKey || event.shiftKey) return;\n event.preventDefault();\n const items = getItems().filter((item) => item.focusable);\n let candidateNodes = items.map((item) => item.ref.current);\n if (focusIntent === \"last\") candidateNodes.reverse();\n else if (focusIntent === \"prev\" || focusIntent === \"next\") {\n if (focusIntent === \"prev\") candidateNodes.reverse();\n const currentIndex = candidateNodes.indexOf(event.currentTarget);\n candidateNodes = context.loop ? wrapArray(candidateNodes, currentIndex + 1) : candidateNodes.slice(currentIndex + 1);\n }\n setTimeout(() => focusFirst(candidateNodes));\n }\n }),\n children: typeof children === \"function\" ? children({ isCurrentTabStop, hasTabStop: currentTabStopId != null }) : children\n }\n )\n }\n );\n }\n);\nRovingFocusGroupItem.displayName = ITEM_NAME;\nvar MAP_KEY_TO_FOCUS_INTENT = {\n ArrowLeft: \"prev\",\n ArrowUp: \"prev\",\n ArrowRight: \"next\",\n ArrowDown: \"next\",\n PageUp: \"first\",\n Home: \"first\",\n PageDown: \"last\",\n End: \"last\"\n};\nfunction getDirectionAwareKey(key, dir) {\n if (dir !== \"rtl\") return key;\n return key === \"ArrowLeft\" ? \"ArrowRight\" : key === \"ArrowRight\" ? \"ArrowLeft\" : key;\n}\nfunction getFocusIntent(event, orientation, dir) {\n const key = getDirectionAwareKey(event.key, dir);\n if (orientation === \"vertical\" && [\"ArrowLeft\", \"ArrowRight\"].includes(key)) return void 0;\n if (orientation === \"horizontal\" && [\"ArrowUp\", \"ArrowDown\"].includes(key)) return void 0;\n return MAP_KEY_TO_FOCUS_INTENT[key];\n}\nfunction focusFirst(candidates, preventScroll = false) {\n const PREVIOUSLY_FOCUSED_ELEMENT = document.activeElement;\n for (const candidate of candidates) {\n if (candidate === PREVIOUSLY_FOCUSED_ELEMENT) return;\n candidate.focus({ preventScroll });\n if (document.activeElement !== PREVIOUSLY_FOCUSED_ELEMENT) return;\n }\n}\nfunction wrapArray(array, startIndex) {\n return array.map((_, index) => array[(startIndex + index) % array.length]);\n}\nvar Root = RovingFocusGroup;\nvar Item = RovingFocusGroupItem;\nexport {\n Item,\n Root,\n RovingFocusGroup,\n RovingFocusGroupItem,\n createRovingFocusGroupScope\n};\n//# sourceMappingURL=index.mjs.map\n","\"use client\";\n\n// src/tabs.tsx\nimport * as React from \"react\";\nimport { composeEventHandlers } from \"@radix-ui/primitive\";\nimport { createContextScope } from \"@radix-ui/react-context\";\nimport { createRovingFocusGroupScope } from \"@radix-ui/react-roving-focus\";\nimport { Presence } from \"@radix-ui/react-presence\";\nimport { Primitive } from \"@radix-ui/react-primitive\";\nimport * as RovingFocusGroup from \"@radix-ui/react-roving-focus\";\nimport { useDirection } from \"@radix-ui/react-direction\";\nimport { useControllableState } from \"@radix-ui/react-use-controllable-state\";\nimport { useId } from \"@radix-ui/react-id\";\nimport { jsx } from \"react/jsx-runtime\";\nvar TABS_NAME = \"Tabs\";\nvar [createTabsContext, createTabsScope] = createContextScope(TABS_NAME, [\n createRovingFocusGroupScope\n]);\nvar useRovingFocusGroupScope = createRovingFocusGroupScope();\nvar [TabsProvider, useTabsContext] = createTabsContext(TABS_NAME);\nvar Tabs = React.forwardRef(\n (props, forwardedRef) => {\n const {\n __scopeTabs,\n value: valueProp,\n onValueChange,\n defaultValue,\n orientation = \"horizontal\",\n dir,\n activationMode = \"automatic\",\n ...tabsProps\n } = props;\n const direction = useDirection(dir);\n const [value, setValue] = useControllableState({\n prop: valueProp,\n onChange: onValueChange,\n defaultProp: defaultValue ?? \"\",\n caller: TABS_NAME\n });\n return /* @__PURE__ */ jsx(\n TabsProvider,\n {\n scope: __scopeTabs,\n baseId: useId(),\n value,\n onValueChange: setValue,\n orientation,\n dir: direction,\n activationMode,\n children: /* @__PURE__ */ jsx(\n Primitive.div,\n {\n dir: direction,\n \"data-orientation\": orientation,\n ...tabsProps,\n ref: forwardedRef\n }\n )\n }\n );\n }\n);\nTabs.displayName = TABS_NAME;\nvar TAB_LIST_NAME = \"TabsList\";\nvar TabsList = React.forwardRef(\n (props, forwardedRef) => {\n const { __scopeTabs, loop = true, ...listProps } = props;\n const context = useTabsContext(TAB_LIST_NAME, __scopeTabs);\n const rovingFocusGroupScope = useRovingFocusGroupScope(__scopeTabs);\n return /* @__PURE__ */ jsx(\n RovingFocusGroup.Root,\n {\n asChild: true,\n ...rovingFocusGroupScope,\n orientation: context.orientation,\n dir: context.dir,\n loop,\n children: /* @__PURE__ */ jsx(\n Primitive.div,\n {\n role: \"tablist\",\n \"aria-orientation\": context.orientation,\n ...listProps,\n ref: forwardedRef\n }\n )\n }\n );\n }\n);\nTabsList.displayName = TAB_LIST_NAME;\nvar TRIGGER_NAME = \"TabsTrigger\";\nvar TabsTrigger = React.forwardRef(\n (props, forwardedRef) => {\n const { __scopeTabs, value, disabled = false, ...triggerProps } = props;\n const context = useTabsContext(TRIGGER_NAME, __scopeTabs);\n const rovingFocusGroupScope = useRovingFocusGroupScope(__scopeTabs);\n const triggerId = makeTriggerId(context.baseId, value);\n const contentId = makeContentId(context.baseId, value);\n const isSelected = value === context.value;\n return /* @__PURE__ */ jsx(\n RovingFocusGroup.Item,\n {\n asChild: true,\n ...rovingFocusGroupScope,\n focusable: !disabled,\n active: isSelected,\n children: /* @__PURE__ */ jsx(\n Primitive.button,\n {\n type: \"button\",\n role: \"tab\",\n \"aria-selected\": isSelected,\n \"aria-controls\": contentId,\n \"data-state\": isSelected ? \"active\" : \"inactive\",\n \"data-disabled\": disabled ? \"\" : void 0,\n disabled,\n id: triggerId,\n ...triggerProps,\n ref: forwardedRef,\n onMouseDown: composeEventHandlers(props.onMouseDown, (event) => {\n if (!disabled && event.button === 0 && event.ctrlKey === false) {\n context.onValueChange(value);\n } else {\n event.preventDefault();\n }\n }),\n onKeyDown: composeEventHandlers(props.onKeyDown, (event) => {\n if ([\" \", \"Enter\"].includes(event.key)) context.onValueChange(value);\n }),\n onFocus: composeEventHandlers(props.onFocus, () => {\n const isAutomaticActivation = context.activationMode !== \"manual\";\n if (!isSelected && !disabled && isAutomaticActivation) {\n context.onValueChange(value);\n }\n })\n }\n )\n }\n );\n }\n);\nTabsTrigger.displayName = TRIGGER_NAME;\nvar CONTENT_NAME = \"TabsContent\";\nvar TabsContent = React.forwardRef(\n (props, forwardedRef) => {\n const { __scopeTabs, value, forceMount, children, ...contentProps } = props;\n const context = useTabsContext(CONTENT_NAME, __scopeTabs);\n const triggerId = makeTriggerId(context.baseId, value);\n const contentId = makeContentId(context.baseId, value);\n const isSelected = value === context.value;\n const isMountAnimationPreventedRef = React.useRef(isSelected);\n React.useEffect(() => {\n const rAF = requestAnimationFrame(() => isMountAnimationPreventedRef.current = false);\n return () => cancelAnimationFrame(rAF);\n }, []);\n return /* @__PURE__ */ jsx(Presence, { present: forceMount || isSelected, children: ({ present }) => /* @__PURE__ */ jsx(\n Primitive.div,\n {\n \"data-state\": isSelected ? \"active\" : \"inactive\",\n \"data-orientation\": context.orientation,\n role: \"tabpanel\",\n \"aria-labelledby\": triggerId,\n hidden: !present,\n id: contentId,\n tabIndex: 0,\n ...contentProps,\n ref: forwardedRef,\n style: {\n ...props.style,\n animationDuration: isMountAnimationPreventedRef.current ? \"0s\" : void 0\n },\n children: present && children\n }\n ) });\n }\n);\nTabsContent.displayName = CONTENT_NAME;\nfunction makeTriggerId(baseId, value) {\n return `${baseId}-trigger-${value}`;\n}\nfunction makeContentId(baseId, value) {\n return `${baseId}-content-${value}`;\n}\nvar Root2 = Tabs;\nvar List = TabsList;\nvar Trigger = TabsTrigger;\nvar Content = TabsContent;\nexport {\n Content,\n List,\n Root2 as Root,\n Tabs,\n TabsContent,\n TabsList,\n TabsTrigger,\n Trigger,\n createTabsScope\n};\n//# sourceMappingURL=index.mjs.map\n","import * as React from 'react'\nimport { Await, Link } from 'react-router'\nimport { Icon } from '#app/components/icons.tsx'\nimport { Loading } from '#app/components/loading.tsx'\nimport { DiscordCTA, useDiscordCTALink } from '#app/routes/_app+/discord.tsx'\nimport { useAltDown } from '#app/utils/misc.tsx'\nimport { useIsOnline } from '#app/utils/online.ts'\n\ntype EmojiData = {\n\temojiName?: string\n\temojiUrl?: string\n}\n\ntype DiscordTag = { name: string } & EmojiData\ntype DiscordReaction = { count: number } & EmojiData\n\nexport type DiscordThread = {\n\tid: string\n\ttags: DiscordTag[]\n\tname: string\n\tlink: string\n\tauthorDisplayName: string\n\tauthorHexAccentColor?: string | null\n\tauthorAvatarUrl: string | null\n\tmessagePreview: string\n\tmessageCount: number\n\tlastUpdated: string\n\tlastUpdatedDisplay: string\n\tpreviewImageUrl: string | null\n\treactions: DiscordReaction[]\n}\n\nexport function DiscordChat({\n\tdiscordPostsPromise,\n}: {\n\tdiscordPostsPromise: Promise<DiscordThread[]>\n}) {\n\treturn (\n\t\t<div className=\"flex h-full w-full flex-col gap-4 pt-4\">\n\t\t\t<div className=\"text-center\">\n\t\t\t\t<DiscordCTA />\n\t\t\t</div>\n\t\t\t<div className=\"bg-accent scrollbar-thin scrollbar-thumb-scrollbar flex-1 overflow-y-scroll pb-4\">\n\t\t\t\t<DiscordPosts discordPostsPromise={discordPostsPromise} />\n\t\t\t</div>\n\t\t</div>\n\t)\n}\n\nfunction DiscordPosts({\n\tdiscordPostsPromise,\n}: {\n\tdiscordPostsPromise: Promise<DiscordThread[]>\n}) {\n\tconst ctaLink = useDiscordCTALink()\n\tconst altDown = useAltDown()\n\tconst isOnline = useIsOnline()\n\tif (!isOnline) {\n\t\treturn (\n\t\t\t<div className=\"flex h-full flex-col items-center justify-between\">\n\t\t\t\t<div className=\"text-foreground-destructive flex h-full w-full flex-col items-center justify-center\">\n\t\t\t\t\t<Icon name=\"WifiNoConnection\" size=\"xl\">\n\t\t\t\t\t\tUnable to load discord messages when offline\n\t\t\t\t\t</Icon>\n\t\t\t\t</div>\n\t\t\t</div>\n\t\t)\n\t}\n\treturn (\n\t\t<div className=\"flex h-full flex-col items-center justify-between\">\n\t\t\t<React.Suspense\n\t\t\t\tfallback={\n\t\t\t\t\t<div className=\"flex h-full w-full flex-col items-center justify-center\">\n\t\t\t\t\t\t<Loading>Loading Discord Posts</Loading>\n\t\t\t\t\t</div>\n\t\t\t\t}\n\t\t\t>\n\t\t\t\t<Await\n\t\t\t\t\tresolve={discordPostsPromise}\n\t\t\t\t\terrorElement={\n\t\t\t\t\t\t<div className=\"text-foreground-destructive\">\n\t\t\t\t\t\t\tThere was a problem loading the discord posts\n\t\t\t\t\t\t</div>\n\t\t\t\t\t}\n\t\t\t\t>\n\t\t\t\t\t{(posts) => (\n\t\t\t\t\t\t<ul className=\"flex w-full flex-col gap-4 p-3 xl:p-12\">\n\t\t\t\t\t\t\t{posts.map((post) => (\n\t\t\t\t\t\t\t\t<li\n\t\t\t\t\t\t\t\t\tkey={post.id}\n\t\t\t\t\t\t\t\t\tclassName=\"bg-background rounded-xl border transition-all duration-200 focus-within:-translate-y-1 focus-within:shadow-lg hover:-translate-y-1 hover:shadow-lg\"\n\t\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t\t<DiscordPost thread={post} />\n\t\t\t\t\t\t\t\t</li>\n\t\t\t\t\t\t\t))}\n\t\t\t\t\t\t</ul>\n\t\t\t\t\t)}\n\t\t\t\t</Await>\n\t\t\t</React.Suspense>\n\t\t\t<div>\n\t\t\t\t<Link\n\t\t\t\t\tto={\n\t\t\t\t\t\taltDown && !ctaLink.includes('oauth')\n\t\t\t\t\t\t\t? ctaLink.replace(/^https/, 'discord')\n\t\t\t\t\t\t\t: ctaLink\n\t\t\t\t\t}\n\t\t\t\t\ttarget={ctaLink.includes('oauth') ? undefined : '_blank'}\n\t\t\t\t\trel=\"noreferrer noopener\"\n\t\t\t\t\tonClick={\n\t\t\t\t\t\taltDown\n\t\t\t\t\t\t\t? (event) => {\n\t\t\t\t\t\t\t\t\tevent.preventDefault()\n\t\t\t\t\t\t\t\t\twindow.open(\n\t\t\t\t\t\t\t\t\t\tevent.currentTarget.href,\n\t\t\t\t\t\t\t\t\t\t'_blank',\n\t\t\t\t\t\t\t\t\t\t'noreferrer noopener',\n\t\t\t\t\t\t\t\t\t)\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t: undefined\n\t\t\t\t\t}\n\t\t\t\t\tclassName=\"flex items-center gap-2 p-2 text-xl hover:underline\"\n\t\t\t\t>\n\t\t\t\t\tCreate Post <Icon name=\"ExternalLink\" />\n\t\t\t\t</Link>\n\t\t\t</div>\n\t\t</div>\n\t)\n}\n\nfunction DiscordPost({ thread }: { thread: DiscordThread }) {\n\tconst reactionsWithCounts = thread.reactions.filter(\n\t\t(reaction) => reaction.count,\n\t)\n\n\treturn (\n\t\t<div>\n\t\t\t<div className=\"flex flex-col gap-2 p-4\">\n\t\t\t\t<div className=\"flex min-w-0 gap-4\">\n\t\t\t\t\t<div className=\"flex min-w-0 flex-col gap-1\">\n\t\t\t\t\t\t{thread.tags.length ? (\n\t\t\t\t\t\t\t<div className=\"flex gap-2\">\n\t\t\t\t\t\t\t\t{thread.tags.map((tag) => (\n\t\t\t\t\t\t\t\t\t<div\n\t\t\t\t\t\t\t\t\t\tkey={`${tag.name}-${tag.emojiName ?? tag.emojiUrl ?? 'tag'}`}\n\t\t\t\t\t\t\t\t\t\tclassName=\"bg-accent flex items-center justify-center gap-1 rounded-full px-2 py-1 text-sm\"\n\t\t\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t\t\t<span className=\"h-3 w-3 leading-3\">\n\t\t\t\t\t\t\t\t\t\t\t<Emoji name={tag.emojiName} url={tag.emojiUrl} />\n\t\t\t\t\t\t\t\t\t\t</span>\n\t\t\t\t\t\t\t\t\t\t<span>{tag.name}</span>\n\t\t\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t\t\t))}\n\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t) : null}\n\t\t\t\t\t\t<strong className=\"text-xl font-bold\">{thread.name}</strong>\n\t\t\t\t\t\t<div className=\"flex min-w-0 flex-col gap-1\">\n\t\t\t\t\t\t\t<div className=\"flex items-center gap-1\">\n\t\t\t\t\t\t\t\t{thread.authorAvatarUrl ? (\n\t\t\t\t\t\t\t\t\t<img\n\t\t\t\t\t\t\t\t\t\tsrc={thread.authorAvatarUrl}\n\t\t\t\t\t\t\t\t\t\talt=\"\"\n\t\t\t\t\t\t\t\t\t\tclassName=\"h-6 w-6 rounded-full\"\n\t\t\t\t\t\t\t\t\t/>\n\t\t\t\t\t\t\t\t) : null}\n\t\t\t\t\t\t\t\t<span>\n\t\t\t\t\t\t\t\t\t<span\n\t\t\t\t\t\t\t\t\t\tclassName=\"font-bold\"\n\t\t\t\t\t\t\t\t\t\tstyle={\n\t\t\t\t\t\t\t\t\t\t\tthread.authorHexAccentColor\n\t\t\t\t\t\t\t\t\t\t\t\t? { color: thread.authorHexAccentColor }\n\t\t\t\t\t\t\t\t\t\t\t\t: {}\n\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t\t\t{thread.authorDisplayName}\n\t\t\t\t\t\t\t\t\t</span>\n\t\t\t\t\t\t\t\t\t:{' '}\n\t\t\t\t\t\t\t\t</span>\n\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t\t<span className=\"text-muted-foreground line-clamp-4 min-w-0\">\n\t\t\t\t\t\t\t\t{thread.messagePreview}\n\t\t\t\t\t\t\t</span>\n\t\t\t\t\t\t</div>\n\t\t\t\t\t</div>\n\t\t\t\t\t{thread.previewImageUrl ? (\n\t\t\t\t\t\t<img\n\t\t\t\t\t\t\tsrc={thread.previewImageUrl}\n\t\t\t\t\t\t\talt=\"\"\n\t\t\t\t\t\t\tclassName=\"h-28 w-28 rounded-lg object-cover\"\n\t\t\t\t\t\t/>\n\t\t\t\t\t) : null}\n\t\t\t\t</div>\n\n\t\t\t\t<div className=\"flex justify-between\">\n\t\t\t\t\t<div className=\"flex items-center gap-3\">\n\t\t\t\t\t\t<span>\n\t\t\t\t\t\t\t{reactionsWithCounts.length ? (\n\t\t\t\t\t\t\t\t<ul className=\"flex items-center gap-2\">\n\t\t\t\t\t\t\t\t\t{reactionsWithCounts.map((reaction, index) => (\n\t\t\t\t\t\t\t\t\t\t<li\n\t\t\t\t\t\t\t\t\t\t\tkey={`${reaction.emojiName ?? reaction.emojiUrl ?? 'reaction'}-${index}`}\n\t\t\t\t\t\t\t\t\t\t\tclassName=\"border-info/60 bg-info/10 text-info flex items-center gap-1 rounded-md border px-[5px] py-[0.5px] text-sm\"\n\t\t\t\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t\t\t\t<span className=\"h-3 w-3 leading-3\">\n\t\t\t\t\t\t\t\t\t\t\t\t<Emoji\n\t\t\t\t\t\t\t\t\t\t\t\t\tname={reaction.emojiName}\n\t\t\t\t\t\t\t\t\t\t\t\t\turl={reaction.emojiUrl}\n\t\t\t\t\t\t\t\t\t\t\t\t/>\n\t\t\t\t\t\t\t\t\t\t\t</span>\n\t\t\t\t\t\t\t\t\t\t\t<span>{reaction.count}</span>\n\t\t\t\t\t\t\t\t\t\t</li>\n\t\t\t\t\t\t\t\t\t))}\n\t\t\t\t\t\t\t\t</ul>\n\t\t\t\t\t\t\t) : null}\n\t\t\t\t\t\t</span>\n\t\t\t\t\t\t<span className=\"flex items-center gap-1\">\n\t\t\t\t\t\t\t<span className=\"inline-flex items-center gap-1\">\n\t\t\t\t\t\t\t\t<Icon name=\"Chat\" /> {thread.messageCount}\n\t\t\t\t\t\t\t</span>\n\t\t\t\t\t\t\t{` · ${thread.lastUpdatedDisplay}`}\n\t\t\t\t\t\t</span>\n\t\t\t\t\t</div>\n\t\t\t\t\t<span className=\"flex items-center gap-4\">\n\t\t\t\t\t\t<a href={thread.link.replace(/^https/, 'discord')}>\n\t\t\t\t\t\t\t<Icon name=\"Discord\" />\n\t\t\t\t\t\t</a>\n\t\t\t\t\t\t<a href={thread.link} target=\"_blank\" rel=\"noreferrer noopener\">\n\t\t\t\t\t\t\t<Icon name=\"ExternalLink\" />\n\t\t\t\t\t\t</a>\n\t\t\t\t\t</span>\n\t\t\t\t</div>\n\t\t\t</div>\n\t\t</div>\n\t)\n}\n\nfunction Emoji({ name, url }: { name?: string; url?: string }) {\n\treturn url ? (\n\t\t<img src={url} alt={name} className=\"h-full w-full\" />\n\t) : name ? (\n\t\tname\n\t) : null\n}\n","export function StatusIndicator({\n\tstatus,\n}: {\n\tstatus: 'running' | 'passed' | 'failed' | 'stopped'\n}) {\n\tconst colors = {\n\t\trunning: {\n\t\t\tpinger: 'bg-yellow-500/60',\n\t\t\tcircle: 'bg-yellow-500',\n\t\t},\n\t\tpassed: {\n\t\t\tcircle: 'bg-success',\n\t\t},\n\t\tfailed: {\n\t\t\tcircle: 'bg-destructive',\n\t\t},\n\t\tstopped: {\n\t\t\tcircle: 'bg-muted-foreground',\n\t\t},\n\t}[status]\n\treturn (\n\t\t<span className=\"relative flex h-3 w-3\">\n\t\t\t{colors.pinger ? (\n\t\t\t\t<span\n\t\t\t\t\tclassName={`absolute inline-flex h-full w-full animate-ping rounded-full ${colors.pinger} opacity-75`}\n\t\t\t\t/>\n\t\t\t) : null}\n\t\t\t<span\n\t\t\t\tclassName={`relative inline-flex h-3 w-3 rounded-full ${colors.circle}`}\n\t\t\t/>\n\t\t</span>\n\t)\n}\n","import * as Tabs from '@radix-ui/react-tabs'\nimport * as React from 'react'\nimport { Link } from 'react-router'\nimport { StatusIndicator } from '#app/components/status-indicator.tsx'\nimport { cn } from '#app/utils/misc.tsx'\n\nexport type PreviewTab = {\n\tid: string\n\tlabel: string\n\tto: string\n\thidden?: boolean\n\tstatus?: 'running' | 'passed' | 'failed' | null\n\tonClick?: React.MouseEventHandler<HTMLAnchorElement>\n}\n\nexport function getPreviewSearchParams(\n\tsearchParams: URLSearchParams,\n\tpreviewValue: string,\n\tdefaultValue: string,\n) {\n\tconst next = new URLSearchParams(searchParams)\n\t// Keep URLs clean by omitting the preview param for the default tab.\n\tif (previewValue === defaultValue) {\n\t\tnext.delete('preview')\n\t} else {\n\t\tnext.set('preview', previewValue)\n\t}\n\treturn next\n}\n\nexport function PreviewTabsList({ tabs }: { tabs: PreviewTab[] }) {\n\treturn (\n\t\t<Tabs.List className=\"scrollbar-thin scrollbar-thumb-scrollbar h-14 min-h-14 overflow-x-auto border-b whitespace-nowrap\">\n\t\t\t{tabs.map((tab) => (\n\t\t\t\t<Tabs.Trigger key={tab.id} value={tab.id} hidden={tab.hidden} asChild>\n\t\t\t\t\t<Link\n\t\t\t\t\t\tid={`${tab.id}-tab`}\n\t\t\t\t\t\tclassName={cn(\n\t\t\t\t\t\t\t'clip-path-button radix-state-active:z-10 radix-state-active:bg-foreground radix-state-active:text-background radix-state-active:hover:bg-foreground/80 radix-state-active:hover:text-background/80 radix-state-inactive:hover:bg-foreground/20 radix-state-inactive:hover:text-foreground/80 focus:bg-foreground/80 focus:text-background/80 relative h-full px-6 py-4 font-mono text-sm uppercase outline-none',\n\t\t\t\t\t\t\ttab.hidden ? 'hidden' : 'inline-block',\n\t\t\t\t\t\t)}\n\t\t\t\t\t\tpreventScrollReset\n\t\t\t\t\t\tprefetch=\"intent\"\n\t\t\t\t\t\tonClick={tab.onClick}\n\t\t\t\t\t\tto={tab.to}\n\t\t\t\t\t>\n\t\t\t\t\t\t<span className=\"flex items-center gap-2\">\n\t\t\t\t\t\t\t{tab.status ? <StatusIndicator status={tab.status} /> : null}\n\t\t\t\t\t\t\t<span>{tab.label}</span>\n\t\t\t\t\t\t</span>\n\t\t\t\t\t</Link>\n\t\t\t\t</Tabs.Trigger>\n\t\t\t))}\n\t\t</Tabs.List>\n\t)\n}\n","import { toast as showToast } from 'sonner'\nimport { Icon } from '#app/components/icons.tsx'\nimport { type InBrowserBrowserRef } from '#app/components/in-browser-browser'\nimport { SimpleTooltip } from '#app/components/ui/tooltip'\nimport { SetAppToPlayground } from '#app/routes/set-playground'\nimport { PlaygroundWindow } from './playground-window'\nimport { Preview } from './preview'\n\nexport function Playground({\n\tappInfo: playgroundAppInfo,\n\tinBrowserBrowserRef,\n\tproblemAppName,\n\tallApps,\n\tisUpToDate,\n}: {\n\tappInfo: Parameters<typeof Preview>['0']['appInfo'] | null\n\tinBrowserBrowserRef: React.RefObject<InBrowserBrowserRef | null>\n\tproblemAppName?: string\n\tallApps: Array<{ name: string; displayName: string }>\n\tisUpToDate: boolean\n}) {\n\treturn (\n\t\t<PlaygroundWindow\n\t\t\tplaygroundAppName={playgroundAppInfo?.appName}\n\t\t\tproblemAppName={problemAppName}\n\t\t\tallApps={allApps}\n\t\t\tisUpToDate={isUpToDate}\n\t\t>\n\t\t\t{playgroundAppInfo?.dev?.type === 'none' ? (\n\t\t\t\t<div className=\"flex h-full flex-col items-center justify-center gap-4\">\n\t\t\t\t\t<div className=\"text-secondary-foreground text-2xl\">\n\t\t\t\t\t\tNon-UI exercise\n\t\t\t\t\t</div>\n\t\t\t\t\t<div className=\"text-secondary-foreground max-w-md text-center text-balance\">\n\t\t\t\t\t\tThis exercise has no application or other UI associated with it.{' '}\n\t\t\t\t\t\t<br />\n\t\t\t\t\t\tNavigate to{' '}\n\t\t\t\t\t\t<SimpleTooltip content={playgroundAppInfo.fullPath}>\n\t\t\t\t\t\t\t<span\n\t\t\t\t\t\t\t\tclassName=\"inline-flex cursor-pointer items-center gap-1.5 underline\"\n\t\t\t\t\t\t\t\tonClick={() => {\n\t\t\t\t\t\t\t\t\tvoid navigator.clipboard.writeText(playgroundAppInfo.fullPath)\n\t\t\t\t\t\t\t\t\tshowToast.success('Copied playground path to clipboard')\n\t\t\t\t\t\t\t\t}}\n\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\tthe playground directory\n\t\t\t\t\t\t\t\t<Icon name=\"Copy\" size=\"sm\" />\n\t\t\t\t\t\t\t</span>\n\t\t\t\t\t\t</SimpleTooltip>{' '}\n\t\t\t\t\t\tin your editor and follow the exercise instructions to complete it.\n\t\t\t\t\t</div>\n\t\t\t\t</div>\n\t\t\t) : playgroundAppInfo ? (\n\t\t\t\t<Preview\n\t\t\t\t\tid={playgroundAppInfo.appName}\n\t\t\t\t\tappInfo={playgroundAppInfo}\n\t\t\t\t\tinBrowserBrowserRef={inBrowserBrowserRef}\n\t\t\t\t/>\n\t\t\t) : (\n\t\t\t\t<div className=\"flex flex-col justify-center gap-2\">\n\t\t\t\t\t<p>Please set the playground first</p>\n\t\t\t\t\t{problemAppName ? (\n\t\t\t\t\t\t<SetAppToPlayground appName={problemAppName} />\n\t\t\t\t\t) : null}\n\t\t\t\t</div>\n\t\t\t)}\n\t\t</PlaygroundWindow>\n\t)\n}\n"],"names":["ENTRY_FOCUS","EVENT_OPTIONS","GROUP_NAME","Collection","useCollection","createCollectionScope","createCollection","createRovingFocusGroupContext","createRovingFocusGroupScope","createContextScope","RovingFocusProvider","useRovingFocusContext","RovingFocusGroup","React.forwardRef","props","forwardedRef","jsx","RovingFocusGroupImpl","__scopeRovingFocusGroup","orientation","loop","dir","currentTabStopIdProp","defaultCurrentTabStopId","onCurrentTabStopIdChange","onEntryFocus","preventScrollOnEntryFocus","groupProps","ref","React.useRef","composedRefs","useComposedRefs","direction","useDirection","currentTabStopId","setCurrentTabStopId","useControllableState","isTabbingBackOut","setIsTabbingBackOut","React.useState","handleEntryFocus","useCallbackRef","getItems","isClickFocusRef","focusableItemsCount","setFocusableItemsCount","React.useEffect","node","React.useCallback","tabStopId","prevCount","Primitive","composeEventHandlers","event","isKeyboardFocus","entryFocusEvent","items","item","activeItem","currentItem","candidateNodes","focusFirst","ITEM_NAME","RovingFocusGroupItem","focusable","active","children","itemProps","autoId","useId","id","context","isCurrentTabStop","onFocusableItemAdd","onFocusableItemRemove","focusIntent","getFocusIntent","currentIndex","wrapArray","MAP_KEY_TO_FOCUS_INTENT","getDirectionAwareKey","key","candidates","preventScroll","PREVIOUSLY_FOCUSED_ELEMENT","candidate","array","startIndex","_","index","Root","Item","TABS_NAME","createTabsContext","useRovingFocusGroupScope","TabsProvider","useTabsContext","Tabs","__scopeTabs","valueProp","onValueChange","defaultValue","activationMode","tabsProps","value","setValue","TAB_LIST_NAME","TabsList","listProps","rovingFocusGroupScope","RovingFocusGroup.Root","TRIGGER_NAME","TabsTrigger","disabled","triggerProps","triggerId","makeTriggerId","contentId","makeContentId","isSelected","RovingFocusGroup.Item","isAutomaticActivation","CONTENT_NAME","TabsContent","forceMount","contentProps","isMountAnimationPreventedRef","rAF","Presence","present","baseId","Root2","List","Trigger","Content","DiscordChat","discordPostsPromise","jsxs","DiscordCTA","DiscordPosts","ctaLink","useDiscordCTALink","altDown","useAltDown","useIsOnline","React.Suspense","Loading","Await","posts","post","DiscordPost","Link","Icon","thread","reactionsWithCounts","reaction","tag","Emoji","name","url","StatusIndicator","status","colors","getPreviewSearchParams","searchParams","previewValue","next","PreviewTabsList","tabs","Tabs.List","tab","Tabs.Trigger","cn","Playground","playgroundAppInfo","inBrowserBrowserRef","problemAppName","allApps","isUpToDate","PlaygroundWindow","SimpleTooltip","showToast","Preview","SetAppToPlayground"],"mappings":"+pBAcA,IAAIA,EAAc,gCACdC,GAAgB,CAAE,QAAS,GAAO,WAAY,EAAI,EAClDC,EAAa,mBACb,CAACC,EAAYC,EAAeC,EAAqB,EAAIC,GAAiBJ,CAAU,EAChF,CAACK,GAA+BC,CAA2B,EAAIC,EACjEP,EACA,CAACG,EAAqB,CACxB,EACI,CAACK,GAAqBC,EAAqB,EAAIJ,GAA8BL,CAAU,EACvFU,EAAmBC,EAAAA,WACrB,CAACC,EAAOC,IACiBC,MAAIb,EAAW,SAAU,CAAE,MAAOW,EAAM,wBAAyB,SAA0BE,MAAIb,EAAW,KAAM,CAAE,MAAOW,EAAM,wBAAyB,SAA0BE,EAAAA,IAAIC,GAAsB,CAAE,GAAGH,EAAO,IAAKC,EAAc,CAAC,CAAE,CAAC,CAAE,CAE5Q,EACAH,EAAiB,YAAcV,EAC/B,IAAIe,GAAuBJ,EAAAA,WAAiB,CAACC,EAAOC,IAAiB,CACnE,KAAM,CACJ,wBAAAG,EACA,YAAAC,EACA,KAAAC,EAAO,GACP,IAAAC,EACA,iBAAkBC,EAClB,wBAAAC,EACA,yBAAAC,EACA,aAAAC,EACA,0BAAAC,EAA4B,GAC5B,GAAGC,CACP,EAAMb,EACEc,EAAMC,EAAAA,OAAa,IAAI,EACvBC,EAAeC,GAAgBhB,EAAca,CAAG,EAChDI,EAAYC,EAAaZ,CAAG,EAC5B,CAACa,EAAkBC,CAAmB,EAAIC,EAAqB,CACnE,KAAMd,EACN,YAAaC,GAA2B,KACxC,SAAUC,EACV,OAAQtB,CACZ,CAAG,EACK,CAACmC,EAAkBC,CAAmB,EAAIC,EAAAA,SAAe,EAAK,EAC9DC,EAAmBC,GAAehB,CAAY,EAC9CiB,EAAWtC,EAAcc,CAAuB,EAChDyB,EAAkBd,EAAAA,OAAa,EAAK,EACpC,CAACe,GAAqBC,CAAsB,EAAIN,EAAAA,SAAe,CAAC,EACtEO,OAAAA,EAAAA,UAAgB,IAAM,CACpB,MAAMC,EAAOnB,EAAI,QACjB,GAAImB,EACF,OAAAA,EAAK,iBAAiB/C,EAAawC,CAAgB,EAC5C,IAAMO,EAAK,oBAAoB/C,EAAawC,CAAgB,CAEvE,EAAG,CAACA,CAAgB,CAAC,EACExB,EAAAA,IACrBN,GACA,CACE,MAAOQ,EACP,YAAAC,EACA,IAAKa,EACL,KAAAZ,EACA,iBAAAc,EACA,YAAac,EAAAA,YACVC,GAAcd,EAAoBc,CAAS,EAC5C,CAACd,CAAmB,CAC5B,EACM,eAAgBa,EAAAA,YAAkB,IAAMV,EAAoB,EAAI,EAAG,CAAA,CAAE,EACrE,mBAAoBU,EAAAA,YAClB,IAAMH,EAAwBK,GAAcA,EAAY,CAAC,EACzD,CAAA,CACR,EACM,sBAAuBF,EAAAA,YACrB,IAAMH,EAAwBK,GAAcA,EAAY,CAAC,EACzD,CAAA,CACR,EACM,SAA0BlC,EAAAA,IACxBmC,EAAU,IACV,CACE,SAAUd,GAAoBO,KAAwB,EAAI,GAAK,EAC/D,mBAAoBzB,EACpB,GAAGQ,EACH,IAAKG,EACL,MAAO,CAAE,QAAS,OAAQ,GAAGhB,EAAM,KAAK,EACxC,YAAasC,EAAqBtC,EAAM,YAAa,IAAM,CACzD6B,EAAgB,QAAU,EAC5B,CAAC,EACD,QAASS,EAAqBtC,EAAM,QAAUuC,GAAU,CACtD,MAAMC,GAAkB,CAACX,EAAgB,QACzC,GAAIU,EAAM,SAAWA,EAAM,eAAiBC,IAAmB,CAACjB,EAAkB,CAChF,MAAMkB,EAAkB,IAAI,YAAYvD,EAAaC,EAAa,EAElE,GADAoD,EAAM,cAAc,cAAcE,CAAe,EAC7C,CAACA,EAAgB,iBAAkB,CACrC,MAAMC,EAAQd,IAAW,OAAQe,GAASA,EAAK,SAAS,EAClDC,GAAaF,EAAM,KAAMC,GAASA,EAAK,MAAM,EAC7CE,GAAcH,EAAM,KAAMC,GAASA,EAAK,KAAOvB,CAAgB,EAI/D0B,GAHiB,CAACF,GAAYC,GAAa,GAAGH,CAAK,EAAE,OACzD,OAClB,EACsD,IAAKC,GAASA,EAAK,IAAI,OAAO,EACpEI,EAAWD,GAAgBlC,CAAyB,CACtD,CACF,CACAiB,EAAgB,QAAU,EAC5B,CAAC,EACD,OAAQS,EAAqBtC,EAAM,OAAQ,IAAMwB,EAAoB,EAAK,CAAC,CACrF,CACA,CACA,CACA,CACA,CAAC,EACGwB,EAAY,uBACZC,EAAuBlD,EAAAA,WACzB,CAACC,EAAOC,IAAiB,CACvB,KAAM,CACJ,wBAAAG,EACA,UAAA8C,EAAY,GACZ,OAAAC,EAAS,GACT,UAAAhB,EACA,SAAAiB,EACA,GAAGC,CACT,EAAQrD,EACEsD,EAASC,EAAK,EACdC,EAAKrB,GAAamB,EAClBG,EAAU5D,GAAsBmD,EAAW5C,CAAuB,EAClEsD,EAAmBD,EAAQ,mBAAqBD,EAChD5B,EAAWtC,EAAcc,CAAuB,EAChD,CAAE,mBAAAuD,EAAoB,sBAAAC,EAAuB,iBAAAxC,CAAgB,EAAKqC,EACxEzB,OAAAA,EAAAA,UAAgB,IAAM,CACpB,GAAIkB,EACF,OAAAS,EAAkB,EACX,IAAMC,EAAqB,CAEtC,EAAG,CAACV,EAAWS,EAAoBC,CAAqB,CAAC,EAClC1D,EAAAA,IACrBb,EAAW,SACX,CACE,MAAOe,EACP,GAAAoD,EACA,UAAAN,EACA,OAAAC,EACA,SAA0BjD,EAAAA,IACxBmC,EAAU,KACV,CACE,SAAUqB,EAAmB,EAAI,GACjC,mBAAoBD,EAAQ,YAC5B,GAAGJ,EACH,IAAKpD,EACL,YAAaqC,EAAqBtC,EAAM,YAAcuC,GAAU,CACzDW,EACAO,EAAQ,YAAYD,CAAE,EADXjB,EAAM,eAAc,CAEtC,CAAC,EACD,QAASD,EAAqBtC,EAAM,QAAS,IAAMyD,EAAQ,YAAYD,CAAE,CAAC,EAC1E,UAAWlB,EAAqBtC,EAAM,UAAYuC,GAAU,CAC1D,GAAIA,EAAM,MAAQ,OAASA,EAAM,SAAU,CACzCkB,EAAQ,eAAc,EACtB,MACF,CACA,GAAIlB,EAAM,SAAWA,EAAM,cAAe,OAC1C,MAAMsB,EAAcC,GAAevB,EAAOkB,EAAQ,YAAaA,EAAQ,GAAG,EAC1E,GAAII,IAAgB,OAAQ,CAC1B,GAAItB,EAAM,SAAWA,EAAM,SAAWA,EAAM,QAAUA,EAAM,SAAU,OACtEA,EAAM,eAAc,EAEpB,IAAIO,EADUlB,IAAW,OAAQe,GAASA,EAAK,SAAS,EAC7B,IAAKA,GAASA,EAAK,IAAI,OAAO,EACzD,GAAIkB,IAAgB,OAAQf,EAAe,QAAO,UACzCe,IAAgB,QAAUA,IAAgB,OAAQ,CACrDA,IAAgB,QAAQf,EAAe,QAAO,EAClD,MAAMiB,EAAejB,EAAe,QAAQP,EAAM,aAAa,EAC/DO,EAAiBW,EAAQ,KAAOO,GAAUlB,EAAgBiB,EAAe,CAAC,EAAIjB,EAAe,MAAMiB,EAAe,CAAC,CACrH,CACA,WAAW,IAAMhB,EAAWD,CAAc,CAAC,CAC7C,CACF,CAAC,EACD,SAAU,OAAOM,GAAa,WAAaA,EAAS,CAAE,iBAAAM,EAAkB,WAAYtC,GAAoB,IAAI,CAAE,EAAIgC,CAC9H,CACA,CACA,CACA,CACE,CACF,EACAH,EAAqB,YAAcD,EACnC,IAAIiB,GAA0B,CAC5B,UAAW,OACX,QAAS,OACT,WAAY,OACZ,UAAW,OACX,OAAQ,QACR,KAAM,QACN,SAAU,OACV,IAAK,MACP,EACA,SAASC,GAAqBC,EAAK5D,EAAK,CACtC,OAAIA,IAAQ,MAAc4D,EACnBA,IAAQ,YAAc,aAAeA,IAAQ,aAAe,YAAcA,CACnF,CACA,SAASL,GAAevB,EAAOlC,EAAaE,EAAK,CAC/C,MAAM4D,EAAMD,GAAqB3B,EAAM,IAAKhC,CAAG,EAC/C,GAAI,EAAAF,IAAgB,YAAc,CAAC,YAAa,YAAY,EAAE,SAAS8D,CAAG,IACtE,EAAA9D,IAAgB,cAAgB,CAAC,UAAW,WAAW,EAAE,SAAS8D,CAAG,GACzE,OAAOF,GAAwBE,CAAG,CACpC,CACA,SAASpB,EAAWqB,EAAYC,EAAgB,GAAO,CACrD,MAAMC,EAA6B,SAAS,cAC5C,UAAWC,KAAaH,EAGtB,GAFIG,IAAcD,IAClBC,EAAU,MAAM,CAAE,cAAAF,EAAe,EAC7B,SAAS,gBAAkBC,GAA4B,MAE/D,CACA,SAASN,GAAUQ,EAAOC,EAAY,CACpC,OAAOD,EAAM,IAAI,CAACE,EAAGC,IAAUH,GAAOC,EAAaE,GAASH,EAAM,MAAM,CAAC,CAC3E,CACA,IAAII,GAAO9E,EACP+E,GAAO5B,EChNP6B,EAAY,OACZ,CAACC,EAAkC,EAAIpF,EAAmBmF,EAAW,CACvEpF,CACF,CAAC,EACGsF,EAA2BtF,EAA2B,EACtD,CAACuF,GAAcC,CAAc,EAAIH,GAAkBD,CAAS,EAC5DK,EAAOpF,EAAAA,WACT,CAACC,EAAOC,IAAiB,CACvB,KAAM,CACJ,YAAAmF,EACA,MAAOC,EACP,cAAAC,EACA,aAAAC,EACA,YAAAlF,EAAc,aACd,IAAAE,EACA,eAAAiF,EAAiB,YACjB,GAAGC,CACT,EAAQzF,EACEkB,EAAYC,EAAaZ,CAAG,EAC5B,CAACmF,EAAOC,CAAQ,EAAIrE,EAAqB,CAC7C,KAAM+D,EACN,SAAUC,EACV,YAAaC,GAAgB,GAC7B,OAAQT,CACd,CAAK,EACD,OAAuB5E,EAAAA,IACrB+E,GACA,CACE,MAAOG,EACP,OAAQ7B,EAAK,EACb,MAAAmC,EACA,cAAeC,EACf,YAAAtF,EACA,IAAKa,EACL,eAAAsE,EACA,SAA0BtF,EAAAA,IACxBmC,EAAU,IACV,CACE,IAAKnB,EACL,mBAAoBb,EACpB,GAAGoF,EACH,IAAKxF,CACjB,CACA,CACA,CACA,CACE,CACF,EACAkF,EAAK,YAAcL,EACnB,IAAIc,EAAgB,WAChBC,EAAW9F,EAAAA,WACb,CAACC,EAAOC,IAAiB,CACvB,KAAM,CAAE,YAAAmF,EAAa,KAAA9E,EAAO,GAAM,GAAGwF,CAAS,EAAK9F,EAC7CyD,EAAUyB,EAAeU,EAAeR,CAAW,EACnDW,EAAwBf,EAAyBI,CAAW,EAClE,OAAuBlF,EAAAA,IACrB8F,GACA,CACE,QAAS,GACT,GAAGD,EACH,YAAatC,EAAQ,YACrB,IAAKA,EAAQ,IACb,KAAAnD,EACA,SAA0BJ,EAAAA,IACxBmC,EAAU,IACV,CACE,KAAM,UACN,mBAAoBoB,EAAQ,YAC5B,GAAGqC,EACH,IAAK7F,CACjB,CACA,CACA,CACA,CACE,CACF,EACA4F,EAAS,YAAcD,EACvB,IAAIK,EAAe,cACfC,GAAcnG,EAAAA,WAChB,CAACC,EAAOC,IAAiB,CACvB,KAAM,CAAE,YAAAmF,EAAa,MAAAM,EAAO,SAAAS,EAAW,GAAO,GAAGC,CAAY,EAAKpG,EAC5DyD,EAAUyB,EAAee,EAAcb,CAAW,EAClDW,EAAwBf,EAAyBI,CAAW,EAC5DiB,EAAYC,GAAc7C,EAAQ,OAAQiC,CAAK,EAC/Ca,EAAYC,GAAc/C,EAAQ,OAAQiC,CAAK,EAC/Ce,EAAaf,IAAUjC,EAAQ,MACrC,OAAuBvD,EAAAA,IACrBwG,GACA,CACE,QAAS,GACT,GAAGX,EACH,UAAW,CAACI,EACZ,OAAQM,EACR,SAA0BvG,EAAAA,IACxBmC,EAAU,OACV,CACE,KAAM,SACN,KAAM,MACN,gBAAiBoE,EACjB,gBAAiBF,EACjB,aAAcE,EAAa,SAAW,WACtC,gBAAiBN,EAAW,GAAK,OACjC,SAAAA,EACA,GAAIE,EACJ,GAAGD,EACH,IAAKnG,EACL,YAAaqC,EAAqBtC,EAAM,YAAcuC,GAAU,CAC1D,CAAC4D,GAAY5D,EAAM,SAAW,GAAKA,EAAM,UAAY,GACvDkB,EAAQ,cAAciC,CAAK,EAE3BnD,EAAM,eAAc,CAExB,CAAC,EACD,UAAWD,EAAqBtC,EAAM,UAAYuC,GAAU,CACtD,CAAC,IAAK,OAAO,EAAE,SAASA,EAAM,GAAG,GAAGkB,EAAQ,cAAciC,CAAK,CACrE,CAAC,EACD,QAASpD,EAAqBtC,EAAM,QAAS,IAAM,CACjD,MAAM2G,EAAwBlD,EAAQ,iBAAmB,SACrD,CAACgD,GAAc,CAACN,GAAYQ,GAC9BlD,EAAQ,cAAciC,CAAK,CAE/B,CAAC,CACb,CACA,CACA,CACA,CACE,CACF,EACAQ,GAAY,YAAcD,EAC1B,IAAIW,GAAe,cACfC,GAAc9G,EAAAA,WAChB,CAACC,EAAOC,IAAiB,CACvB,KAAM,CAAE,YAAAmF,EAAa,MAAAM,EAAO,WAAAoB,EAAY,SAAA1D,EAAU,GAAG2D,CAAY,EAAK/G,EAChEyD,EAAUyB,EAAe0B,GAAcxB,CAAW,EAClDiB,EAAYC,GAAc7C,EAAQ,OAAQiC,CAAK,EAC/Ca,EAAYC,GAAc/C,EAAQ,OAAQiC,CAAK,EAC/Ce,EAAaf,IAAUjC,EAAQ,MAC/BuD,EAA+BjG,EAAAA,OAAa0F,CAAU,EAC5DzE,OAAAA,EAAAA,UAAgB,IAAM,CACpB,MAAMiF,EAAM,sBAAsB,IAAMD,EAA6B,QAAU,EAAK,EACpF,MAAO,IAAM,qBAAqBC,CAAG,CACvC,EAAG,CAAA,CAAE,EACkB/G,EAAAA,IAAIgH,GAAU,CAAE,QAASJ,GAAcL,EAAY,SAAU,CAAC,CAAE,QAAAU,CAAO,IAAuBjH,EAAAA,IACnHmC,EAAU,IACV,CACE,aAAcoE,EAAa,SAAW,WACtC,mBAAoBhD,EAAQ,YAC5B,KAAM,WACN,kBAAmB4C,EACnB,OAAQ,CAACc,EACT,GAAIZ,EACJ,SAAU,EACV,GAAGQ,EACH,IAAK9G,EACL,MAAO,CACL,GAAGD,EAAM,MACT,kBAAmBgH,EAA6B,QAAU,KAAO,MAC3E,EACQ,SAAUG,GAAW/D,CAC7B,CACA,EAAO,CACL,CACF,EACAyD,GAAY,YAAcD,GAC1B,SAASN,GAAcc,EAAQ1B,EAAO,CACpC,MAAO,GAAG0B,CAAM,YAAY1B,CAAK,EACnC,CACA,SAASc,GAAcY,EAAQ1B,EAAO,CACpC,MAAO,GAAG0B,CAAM,YAAY1B,CAAK,EACnC,CACG,IAAC2B,GAAQlC,EACRmC,GAAOzB,EACP0B,GAAUrB,GACVsB,GAAUX,GC3JP,SAASY,GAAY,CAC3B,oBAAAC,CACD,EAEG,CACF,OACCC,EAAAA,KAAC,MAAA,CAAI,UAAU,yCACd,SAAA,CAAAzH,MAAC,MAAA,CAAI,UAAU,cACd,SAAAA,MAAC0H,KAAW,EACb,QACC,MAAA,CAAI,UAAU,mFACd,SAAA1H,EAAAA,IAAC2H,GAAA,CAAa,oBAAAH,EAA0C,CAAA,CACzD,CAAA,EACD,CAEF,CAEA,SAASG,GAAa,CACrB,oBAAAH,CACD,EAEG,CACF,MAAMI,EAAUC,GAAA,EACVC,EAAUC,GAAA,EAEhB,OADiBC,GAAA,EAahBP,EAAAA,KAAC,MAAA,CAAI,UAAU,oDACd,SAAA,CAAAzH,EAAAA,IAACiI,EAAAA,SAAA,CACA,eACE,MAAA,CAAI,UAAU,0DACd,SAAAjI,EAAAA,IAACkI,GAAA,CAAQ,iCAAqB,CAAA,CAC/B,EAGD,SAAAlI,EAAAA,IAACmI,GAAA,CACA,QAASX,EACT,aACCxH,EAAAA,IAAC,MAAA,CAAI,UAAU,8BAA8B,SAAA,gDAE7C,EAGA,SAACoI,GACDpI,EAAAA,IAAC,KAAA,CAAG,UAAU,yCACZ,SAAAoI,EAAM,IAAKC,GACXrI,EAAAA,IAAC,KAAA,CAEA,UAAU,sJAEV,SAAAA,EAAAA,IAACsI,GAAA,CAAY,OAAQD,CAAA,CAAM,CAAA,EAHtBA,EAAK,EAAA,CAKX,CAAA,CACF,CAAA,CAAA,CAEF,CAAA,QAEA,MAAA,CACA,SAAAZ,EAAAA,KAACc,EAAA,CACA,GACCT,GAAW,CAACF,EAAQ,SAAS,OAAO,EACjCA,EAAQ,QAAQ,SAAU,SAAS,EACnCA,EAEJ,OAAQA,EAAQ,SAAS,OAAO,EAAI,OAAY,SAChD,IAAI,sBACJ,QACCE,EACIzF,GAAU,CACXA,EAAM,eAAA,EACN,OAAO,KACNA,EAAM,cAAc,KACpB,SACA,qBAAA,CAEF,EACC,OAEJ,UAAU,sDACV,SAAA,CAAA,eACYrC,EAAAA,IAACwI,EAAA,CAAK,KAAK,cAAA,CAAe,CAAA,CAAA,CAAA,CACvC,CACD,CAAA,EACD,QAlEE,MAAA,CAAI,UAAU,oDACd,SAAAxI,EAAAA,IAAC,OAAI,UAAU,sFACd,SAAAA,EAAAA,IAACwI,EAAA,CAAK,KAAK,mBAAmB,KAAK,KAAK,SAAA,8CAAA,CAExC,EACD,EACD,CA8DH,CAEA,SAASF,GAAY,CAAE,OAAAG,GAAqC,CAC3D,MAAMC,EAAsBD,EAAO,UAAU,OAC3CE,GAAaA,EAAS,KAAA,EAGxB,OACC3I,EAAAA,IAAC,MAAA,CACA,SAAAyH,EAAAA,KAAC,MAAA,CAAI,UAAU,0BACd,SAAA,CAAAA,EAAAA,KAAC,MAAA,CAAI,UAAU,qBACd,SAAA,CAAAA,EAAAA,KAAC,MAAA,CAAI,UAAU,8BACb,SAAA,CAAAgB,EAAO,KAAK,OACZzI,EAAAA,IAAC,MAAA,CAAI,UAAU,aACb,SAAAyI,EAAO,KAAK,IAAKG,GACjBnB,EAAAA,KAAC,MAAA,CAEA,UAAU,kFAEV,SAAA,CAAAzH,EAAAA,IAAC,OAAA,CAAK,UAAU,oBACf,SAAAA,EAAAA,IAAC6I,EAAA,CAAM,KAAMD,EAAI,UAAW,IAAKA,EAAI,QAAA,CAAU,EAChD,EACA5I,EAAAA,IAAC,OAAA,CAAM,SAAA4I,EAAI,IAAA,CAAK,CAAA,CAAA,EANX,GAAGA,EAAI,IAAI,IAAIA,EAAI,WAAaA,EAAI,UAAY,KAAK,EAAA,CAQ3D,EACF,EACG,KACJ5I,EAAAA,IAAC,SAAA,CAAO,UAAU,oBAAqB,WAAO,KAAK,EACnDyH,EAAAA,KAAC,MAAA,CAAI,UAAU,8BACd,SAAA,CAAAA,EAAAA,KAAC,MAAA,CAAI,UAAU,0BACb,SAAA,CAAAgB,EAAO,gBACPzI,EAAAA,IAAC,MAAA,CACA,IAAKyI,EAAO,gBACZ,IAAI,GACJ,UAAU,sBAAA,CAAA,EAER,YACH,OAAA,CACA,SAAA,CAAAzI,EAAAA,IAAC,OAAA,CACA,UAAU,YACV,MACCyI,EAAO,qBACJ,CAAE,MAAOA,EAAO,oBAAA,EAChB,CAAA,EAGH,SAAAA,EAAO,iBAAA,CAAA,EACF,IACL,GAAA,CAAA,CACH,CAAA,EACD,EACAzI,EAAAA,IAAC,OAAA,CAAK,UAAU,6CACd,WAAO,cAAA,CACT,CAAA,CAAA,CACD,CAAA,EACD,EACCyI,EAAO,gBACPzI,EAAAA,IAAC,MAAA,CACA,IAAKyI,EAAO,gBACZ,IAAI,GACJ,UAAU,mCAAA,CAAA,EAER,IAAA,EACL,EAEAhB,EAAAA,KAAC,MAAA,CAAI,UAAU,uBACd,SAAA,CAAAA,EAAAA,KAAC,MAAA,CAAI,UAAU,0BACd,SAAA,CAAAzH,EAAAA,IAAC,OAAA,CACC,SAAA0I,EAAoB,OACpB1I,EAAAA,IAAC,KAAA,CAAG,UAAU,0BACZ,SAAA0I,EAAoB,IAAI,CAACC,EAAUlE,IACnCgD,EAAAA,KAAC,KAAA,CAEA,UAAU,4GAEV,SAAA,CAAAzH,EAAAA,IAAC,OAAA,CAAK,UAAU,oBACf,SAAAA,EAAAA,IAAC6I,EAAA,CACA,KAAMF,EAAS,UACf,IAAKA,EAAS,QAAA,CAAA,EAEhB,EACA3I,EAAAA,IAAC,OAAA,CAAM,SAAA2I,EAAS,KAAA,CAAM,CAAA,CAAA,EATjB,GAAGA,EAAS,WAAaA,EAAS,UAAY,UAAU,IAAIlE,CAAK,EAAA,CAWvE,CAAA,CACF,EACG,KACL,EACAgD,EAAAA,KAAC,OAAA,CAAK,UAAU,0BACf,SAAA,CAAAA,EAAAA,KAAC,OAAA,CAAK,UAAU,iCACf,SAAA,CAAAzH,EAAAA,IAACwI,EAAA,CAAK,KAAK,MAAA,CAAO,EAAE,IAAEC,EAAO,YAAA,EAC9B,EACC,MAAMA,EAAO,kBAAkB,EAAA,CAAA,CACjC,CAAA,EACD,EACAhB,EAAAA,KAAC,OAAA,CAAK,UAAU,0BACf,SAAA,CAAAzH,EAAAA,IAAC,IAAA,CAAE,KAAMyI,EAAO,KAAK,QAAQ,SAAU,SAAS,EAC/C,SAAAzI,EAAAA,IAACwI,EAAA,CAAK,KAAK,SAAA,CAAU,EACtB,EACAxI,EAAAA,IAAC,IAAA,CAAE,KAAMyI,EAAO,KAAM,OAAO,SAAS,IAAI,sBACzC,SAAAzI,MAACwI,EAAA,CAAK,KAAK,eAAe,CAAA,CAC3B,CAAA,CAAA,CACD,CAAA,CAAA,CACD,CAAA,CAAA,CACD,CAAA,CACD,CAEF,CAEA,SAASK,EAAM,CAAE,KAAAC,EAAM,IAAAC,GAAwC,CAC9D,OAAOA,EACN/I,EAAAA,IAAC,MAAA,CAAI,IAAK+I,EAAK,IAAKD,EAAM,UAAU,eAAA,CAAgB,EACjDA,GAEA,IACL,CCjPO,SAASE,GAAgB,CAC/B,OAAAC,CACD,EAEG,CACF,MAAMC,EAAS,CACd,QAAS,CACR,OAAQ,mBACR,OAAQ,eAAA,EAET,OAAQ,CACP,OAAQ,YAAA,EAET,OAAQ,CACP,OAAQ,gBAAA,EAET,QAAS,CACR,OAAQ,qBAAA,CACT,EACCD,CAAM,EACR,OACCxB,EAAAA,KAAC,OAAA,CAAK,UAAU,wBACd,SAAA,CAAAyB,EAAO,OACPlJ,EAAAA,IAAC,OAAA,CACA,UAAW,gEAAgEkJ,EAAO,MAAM,aAAA,CAAA,EAEtF,KACJlJ,EAAAA,IAAC,OAAA,CACA,UAAW,6CAA6CkJ,EAAO,MAAM,EAAA,CAAA,CACtE,EACD,CAEF,CCjBO,SAASC,GACfC,EACAC,EACAhE,EACC,CACD,MAAMiE,EAAO,IAAI,gBAAgBF,CAAY,EAE7C,OAAIC,IAAiBhE,EACpBiE,EAAK,OAAO,SAAS,EAErBA,EAAK,IAAI,UAAWD,CAAY,EAE1BC,CACR,CAEO,SAASC,GAAgB,CAAE,KAAAC,GAAgC,CACjE,OACCxJ,EAAAA,IAACyJ,GAAA,CAAU,UAAU,oGACnB,SAAAD,EAAK,IAAKE,SACTC,GAAA,CAA0B,MAAOD,EAAI,GAAI,OAAQA,EAAI,OAAQ,QAAO,GACpE,SAAA1J,EAAAA,IAACuI,EAAA,CACA,GAAI,GAAGmB,EAAI,EAAE,OACb,UAAWE,GACV,kZACAF,EAAI,OAAS,SAAW,cAAA,EAEzB,mBAAkB,GAClB,SAAS,SACT,QAASA,EAAI,QACb,GAAIA,EAAI,GAER,SAAAjC,EAAAA,KAAC,OAAA,CAAK,UAAU,0BACd,SAAA,CAAAiC,EAAI,OAAS1J,EAAAA,IAACgJ,GAAA,CAAgB,OAAQU,EAAI,OAAQ,EAAK,KACxD1J,EAAAA,IAAC,OAAA,CAAM,SAAA0J,EAAI,KAAA,CAAM,CAAA,CAAA,CAClB,CAAA,CAAA,CACD,EAhBkBA,EAAI,EAiBvB,CACA,EACF,CAEF,CC/CO,SAASG,GAAW,CAC1B,QAASC,EACT,oBAAAC,EACA,eAAAC,EACA,QAAAC,EACA,WAAAC,CACD,EAMG,CACF,OACClK,EAAAA,IAACmK,GAAA,CACA,kBAAmBL,GAAmB,QACtC,eAAAE,EACA,QAAAC,EACA,WAAAC,EAEC,YAAmB,KAAK,OAAS,OACjCzC,OAAC,MAAA,CAAI,UAAU,yDACd,SAAA,CAAAzH,EAAAA,IAAC,MAAA,CAAI,UAAU,qCAAqC,SAAA,kBAEpD,EACAyH,EAAAA,KAAC,MAAA,CAAI,UAAU,8DAA8D,SAAA,CAAA,mEACX,UAChE,KAAA,EAAG,EAAE,cACM,IACZzH,EAAAA,IAACoK,GAAA,CAAc,QAASN,EAAkB,SACzC,SAAArC,EAAAA,KAAC,OAAA,CACA,UAAU,4DACV,QAAS,IAAM,CACT,UAAU,UAAU,UAAUqC,EAAkB,QAAQ,EAC7DO,GAAU,QAAQ,qCAAqC,CACxD,EACA,SAAA,CAAA,2BAEArK,EAAAA,IAACwI,EAAA,CAAK,KAAK,OAAO,KAAK,IAAA,CAAK,CAAA,CAAA,CAAA,EAE9B,EAAiB,IAAI,qEAAA,CAAA,CAEtB,CAAA,CAAA,CACD,EACGsB,EACH9J,EAAAA,IAACsK,GAAA,CACA,GAAIR,EAAkB,QACtB,QAASA,EACT,oBAAAC,CAAA,CAAA,EAGDtC,EAAAA,KAAC,MAAA,CAAI,UAAU,qCACd,SAAA,CAAAzH,EAAAA,IAAC,KAAE,SAAA,iCAAA,CAA+B,EACjCgK,EACAhK,EAAAA,IAACuK,GAAA,CAAmB,QAASP,EAAgB,EAC1C,IAAA,CAAA,CACL,CAAA,CAAA,CAIJ","x_google_ignoreList":[0,1]}
@@ -1,2 +1,2 @@
1
- import{j as e}from"./jsx-runtime-C5WNSv3b.js";import{r as u}from"./index-CqIc3cxq.js";import{f as x,d as A}from"./chunk-EPOLDU6W-C4NOdiis.js";import{u as F,l as k,I as h,a as C,c as R}from"./misc-CRhJChs6.js";import{B as P,L as O}from"./button-CVorsvM4.js";import{L as I}from"./loading-IJRzD1mm.js";import{s as j}from"./progress-bar-Cxy0ZpqZ.js";import{u as g}from"./pe-UQCAhDPv.js";import{u as b}from"./index-Cg-9mI3Y.js";import{a as L}from"./root-loader-BObzljW3.js";import{k as z,T as v,a as S,b as N}from"./tooltip-f3C9W-4C.js";function q({name:r}){const t=x(),n=g(),o=t.formData?.get("intent"),l=o==="stop"?"Stopping App":o==="restart"?"Restarting App":null,a=F();return e.jsxs(t.Form,{method:"POST",action:"/start",children:[n,j,e.jsx("input",{type:"hidden",name:"name",value:r}),e.jsx("button",{type:"submit",name:"intent",value:a?"restart":"stop",className:"h-full border-r px-3 py-4 font-mono text-xs leading-none uppercase",children:l||(a?"Restart App":"Stop App")})]})}function B({port:r}){const t=x(),n=g();return e.jsxs(t.Form,{method:"POST",action:"/start",children:[n,j,e.jsx("input",{type:"hidden",name:"port",value:r}),e.jsx(P,{varient:"mono",type:"submit",name:"intent",value:"stop-port",children:t.state==="idle"?"Stop Port":"Stopping Port"})]})}function D({name:r}){const t=x(),n=g();return t.data?.status==="app-not-started"?t.data.error==="port-unavailable"?e.jsxs("div",{children:["The port is unavailable. Would you like to stop whatever is running on that port and try again?",e.jsx(B,{port:t.data.port})]}):e.jsx("div",{children:"An unknown error has happened."}):e.jsxs(t.Form,{method:"POST",action:"/start",children:[n,j,e.jsx("input",{type:"hidden",name:"name",value:r}),t.state==="idle"?e.jsx(P,{type:"submit",name:"intent",value:"start",varient:"mono",children:"Start App"}):e.jsx("div",{children:e.jsx(I,{children:"Starting App"})})]})}function _({name:r,port:t,portIsAvailable:n,isRunning:o,baseUrl:l,id:a,initialRoute:p,ref:s}){const d=L(),[m,c]=u.useState(!1);return o||m?e.jsx(K,{baseUrl:l,id:a,name:r,ref:s,initialRoute:p}):n===!1?e.jsxs("div",{className:"flex flex-col items-center justify-center",children:[e.jsxs("p",{className:"max-w-xs pb-5 text-center",role:"status",children:["The port for this app is unavailable. It could be that you're running it ",e.jsx("a",{href:k({domain:d.domain,port:t}),className:"underline",target:"_blank",rel:"noreferrer",children:"elsewhere"}),". ",e.jsx(O,{onClick:()=>c(!0),children:"Show here anyway"})]}),e.jsx(B,{port:t})]}):e.jsx("div",{className:"flex h-full flex-col items-center justify-center",children:e.jsx(D,{name:r})})}function K({baseUrl:r,id:t,name:n,initialRoute:o,ref:l}){const a=b(),[p,s]=u.useState(0),d=t+p,m=u.useRef(null),c=new URL(o,r),[i,w]=u.useState(c),y=u.useRef(t);y.current!==t&&(y.current=t,w(c));function U(f){if(f){const E=new URL(f,r);w(E),s(T=>T+1)}}return u.useImperativeHandle(l,()=>({handleExtrnalNavigation:U})),e.jsx(z,{children:e.jsxs("div",{className:"flex h-full grow flex-col",children:[e.jsxs("div",{className:"flex items-center justify-between border-b pl-1.5",children:[e.jsx("div",{className:"mr-2 flex items-center justify-center gap-2 px-1",children:e.jsxs(v,{children:[e.jsx(S,{asChild:!0,children:e.jsx("button",{type:"button",className:"flex aspect-square h-full w-full items-center justify-center p-1 transition disabled:opacity-40",onClick:()=>{s(f=>f+1)},children:e.jsx(h,{name:"Refresh","aria-hidden":"true"})})}),e.jsx(N,{children:"Refresh"})]})}),e.jsx("div",{className:"bg-background text-foreground flex flex-1 items-center border-x p-3 leading-none",children:e.jsx("a",{href:i.toString(),target:"_blank",rel:"noreferrer",children:i.toString()})}),e.jsx(q,{name:n}),e.jsxs(v,{children:[e.jsx(S,{asChild:!0,children:e.jsx("a",{href:i.toString(),target:"_blank",rel:"noreferrer",className:C("flex aspect-square items-center justify-center px-3.5"),children:e.jsx(h,{name:"ExternalLink"})})}),e.jsx(N,{children:"Open in new tab"})]})]}),e.jsx("div",{className:"bg-background flex h-full w-full grow",children:e.jsx("iframe",{title:n,ref:m,src:i.toString(),className:"bg-background h-full w-full grow",style:{colorScheme:a},allow:"clipboard-write"},d)})]})})}function te({id:r,appInfo:t,inBrowserBrowserRef:n}){const o=L(),[l]=A(),a=b();if(!t)return e.jsx("p",{children:"No app here. Sorry."});const{isRunning:p,dev:s,name:d,portIsAvailable:m,title:c}=t;if(!s)return e.jsx("div",{className:"flex h-full items-center justify-center text-lg",children:e.jsx("p",{children:"No preview available for this app."})});if(ENV.EPICSHOP_DEPLOYED&&t.stackBlitzUrl){const i=new URL(t.stackBlitzUrl);return i.searchParams.set("embed","1"),i.searchParams.set("theme",a),e.jsx(H,{title:c,url:i.toString(),loadingContent:e.jsx(I,{children:e.jsxs("span",{children:["Loading"," ",e.jsxs("a",{className:"underline",href:t.stackBlitzUrl,children:['"',c,'"']})]})})})}if(s.type==="script"){const i=k({domain:o.domain,port:s.portNumber});return e.jsx(_,{ref:n,isRunning:p,id:r??d,name:d,portIsAvailable:m,port:s.portNumber,baseUrl:i,initialRoute:l.get("pathname")??s.initialRoute})}else return s.type==="browser"||s.type==="export"?e.jsxs("div",{className:"scrollbar-thin scrollbar-thumb-scrollbar relative h-full grow overflow-y-auto",children:[e.jsxs("a",{href:s.pathname,target:"_blank",rel:"noreferrer",className:R("bg-muted text-foreground hover:bg-muted/80 absolute right-5 bottom-5 flex items-center justify-center rounded-full p-2.5 transition"),children:[e.jsx(h,{name:"ExternalLink","aria-hidden":"true"}),e.jsx("span",{className:"sr-only",children:"Open in New Window"})]}),e.jsx("iframe",{title:c,src:s.pathname,className:"bg-background h-full w-full grow",style:{colorScheme:a},allow:"clipboard-write"})]}):e.jsx("div",{className:"flex h-full items-center justify-center text-lg",children:e.jsxs("p",{children:["Preview for dev type of ",e.jsx("code",{children:s.type})," not supported."]})})}function H({url:r,title:t,loadingContent:n}){const o=b(),[l,a]=u.useState(!1);return e.jsxs("div",{className:"h-full w-full grow",children:[l?null:e.jsx("div",{className:"absolute inset-0 z-10 flex items-center justify-center",children:n}),e.jsx("iframe",{onLoad:()=>a(!0),onError:()=>a(!0),src:r,className:R("h-full w-full grow transition-opacity duration-300",l?"opacity-100":"opacity-0"),title:t,sandbox:"allow-forms allow-scripts allow-same-origin allow-popups allow-popups-to-escape-sandbox",allow:"clipboard-write",style:{colorScheme:o}})]})}export{te as P};
2
- //# sourceMappingURL=preview-DUByetdK.js.map
1
+ import{j as e}from"./jsx-runtime-C5WNSv3b.js";import{r as u}from"./index-CqIc3cxq.js";import{f as x,d as A}from"./chunk-EPOLDU6W-C4NOdiis.js";import{u as F,l as k,I as h,a as C,c as R}from"./misc-CRhJChs6.js";import{B as P,L as O}from"./button-CVorsvM4.js";import{L as I}from"./loading-BiVU3Oa8.js";import{s as j}from"./progress-bar-Cxy0ZpqZ.js";import{u as g}from"./pe-UQCAhDPv.js";import{u as b}from"./index-DVd41HZN.js";import{a as L}from"./root-loader-BObzljW3.js";import{k as z,T as v,a as S,b as N}from"./tooltip-f3C9W-4C.js";function q({name:r}){const t=x(),n=g(),o=t.formData?.get("intent"),l=o==="stop"?"Stopping App":o==="restart"?"Restarting App":null,a=F();return e.jsxs(t.Form,{method:"POST",action:"/start",children:[n,j,e.jsx("input",{type:"hidden",name:"name",value:r}),e.jsx("button",{type:"submit",name:"intent",value:a?"restart":"stop",className:"h-full border-r px-3 py-4 font-mono text-xs leading-none uppercase",children:l||(a?"Restart App":"Stop App")})]})}function B({port:r}){const t=x(),n=g();return e.jsxs(t.Form,{method:"POST",action:"/start",children:[n,j,e.jsx("input",{type:"hidden",name:"port",value:r}),e.jsx(P,{varient:"mono",type:"submit",name:"intent",value:"stop-port",children:t.state==="idle"?"Stop Port":"Stopping Port"})]})}function D({name:r}){const t=x(),n=g();return t.data?.status==="app-not-started"?t.data.error==="port-unavailable"?e.jsxs("div",{children:["The port is unavailable. Would you like to stop whatever is running on that port and try again?",e.jsx(B,{port:t.data.port})]}):e.jsx("div",{children:"An unknown error has happened."}):e.jsxs(t.Form,{method:"POST",action:"/start",children:[n,j,e.jsx("input",{type:"hidden",name:"name",value:r}),t.state==="idle"?e.jsx(P,{type:"submit",name:"intent",value:"start",varient:"mono",children:"Start App"}):e.jsx("div",{children:e.jsx(I,{children:"Starting App"})})]})}function _({name:r,port:t,portIsAvailable:n,isRunning:o,baseUrl:l,id:a,initialRoute:p,ref:s}){const d=L(),[m,c]=u.useState(!1);return o||m?e.jsx(K,{baseUrl:l,id:a,name:r,ref:s,initialRoute:p}):n===!1?e.jsxs("div",{className:"flex flex-col items-center justify-center",children:[e.jsxs("p",{className:"max-w-xs pb-5 text-center",role:"status",children:["The port for this app is unavailable. It could be that you're running it ",e.jsx("a",{href:k({domain:d.domain,port:t}),className:"underline",target:"_blank",rel:"noreferrer",children:"elsewhere"}),". ",e.jsx(O,{onClick:()=>c(!0),children:"Show here anyway"})]}),e.jsx(B,{port:t})]}):e.jsx("div",{className:"flex h-full flex-col items-center justify-center",children:e.jsx(D,{name:r})})}function K({baseUrl:r,id:t,name:n,initialRoute:o,ref:l}){const a=b(),[p,s]=u.useState(0),d=t+p,m=u.useRef(null),c=new URL(o,r),[i,w]=u.useState(c),y=u.useRef(t);y.current!==t&&(y.current=t,w(c));function U(f){if(f){const E=new URL(f,r);w(E),s(T=>T+1)}}return u.useImperativeHandle(l,()=>({handleExtrnalNavigation:U})),e.jsx(z,{children:e.jsxs("div",{className:"flex h-full grow flex-col",children:[e.jsxs("div",{className:"flex items-center justify-between border-b pl-1.5",children:[e.jsx("div",{className:"mr-2 flex items-center justify-center gap-2 px-1",children:e.jsxs(v,{children:[e.jsx(S,{asChild:!0,children:e.jsx("button",{type:"button",className:"flex aspect-square h-full w-full items-center justify-center p-1 transition disabled:opacity-40",onClick:()=>{s(f=>f+1)},children:e.jsx(h,{name:"Refresh","aria-hidden":"true"})})}),e.jsx(N,{children:"Refresh"})]})}),e.jsx("div",{className:"bg-background text-foreground flex flex-1 items-center border-x p-3 leading-none",children:e.jsx("a",{href:i.toString(),target:"_blank",rel:"noreferrer",children:i.toString()})}),e.jsx(q,{name:n}),e.jsxs(v,{children:[e.jsx(S,{asChild:!0,children:e.jsx("a",{href:i.toString(),target:"_blank",rel:"noreferrer",className:C("flex aspect-square items-center justify-center px-3.5"),children:e.jsx(h,{name:"ExternalLink"})})}),e.jsx(N,{children:"Open in new tab"})]})]}),e.jsx("div",{className:"bg-background flex h-full w-full grow",children:e.jsx("iframe",{title:n,ref:m,src:i.toString(),className:"bg-background h-full w-full grow",style:{colorScheme:a},allow:"clipboard-write"},d)})]})})}function te({id:r,appInfo:t,inBrowserBrowserRef:n}){const o=L(),[l]=A(),a=b();if(!t)return e.jsx("p",{children:"No app here. Sorry."});const{isRunning:p,dev:s,name:d,portIsAvailable:m,title:c}=t;if(!s)return e.jsx("div",{className:"flex h-full items-center justify-center text-lg",children:e.jsx("p",{children:"No preview available for this app."})});if(ENV.EPICSHOP_DEPLOYED&&t.stackBlitzUrl){const i=new URL(t.stackBlitzUrl);return i.searchParams.set("embed","1"),i.searchParams.set("theme",a),e.jsx(H,{title:c,url:i.toString(),loadingContent:e.jsx(I,{children:e.jsxs("span",{children:["Loading"," ",e.jsxs("a",{className:"underline",href:t.stackBlitzUrl,children:['"',c,'"']})]})})})}if(s.type==="script"){const i=k({domain:o.domain,port:s.portNumber});return e.jsx(_,{ref:n,isRunning:p,id:r??d,name:d,portIsAvailable:m,port:s.portNumber,baseUrl:i,initialRoute:l.get("pathname")??s.initialRoute})}else return s.type==="browser"||s.type==="export"?e.jsxs("div",{className:"scrollbar-thin scrollbar-thumb-scrollbar relative h-full grow overflow-y-auto",children:[e.jsxs("a",{href:s.pathname,target:"_blank",rel:"noreferrer",className:R("bg-muted text-foreground hover:bg-muted/80 absolute right-5 bottom-5 flex items-center justify-center rounded-full p-2.5 transition"),children:[e.jsx(h,{name:"ExternalLink","aria-hidden":"true"}),e.jsx("span",{className:"sr-only",children:"Open in New Window"})]}),e.jsx("iframe",{title:c,src:s.pathname,className:"bg-background h-full w-full grow",style:{colorScheme:a},allow:"clipboard-write"})]}):e.jsx("div",{className:"flex h-full items-center justify-center text-lg",children:e.jsxs("p",{children:["Preview for dev type of ",e.jsx("code",{children:s.type})," not supported."]})})}function H({url:r,title:t,loadingContent:n}){const o=b(),[l,a]=u.useState(!1);return e.jsxs("div",{className:"h-full w-full grow",children:[l?null:e.jsx("div",{className:"absolute inset-0 z-10 flex items-center justify-center",children:n}),e.jsx("iframe",{onLoad:()=>a(!0),onError:()=>a(!0),src:r,className:R("h-full w-full grow transition-opacity duration-300",l?"opacity-100":"opacity-0"),title:t,sandbox:"allow-forms allow-scripts allow-same-origin allow-popups allow-popups-to-escape-sandbox",allow:"clipboard-write",style:{colorScheme:o}})]})}export{te as P};
2
+ //# sourceMappingURL=preview-D11Pscbe.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"preview-DUByetdK.js","sources":["../../../app/routes/start.tsx","../../../app/components/in-browser-browser.tsx","../../../app/routes/_app+/exercise+/$exerciseNumber_.$stepNumber.$type+/__shared/preview.tsx"],"sourcesContent":["import { invariant, invariantResponse } from '@epic-web/invariant'\nimport { getAppByName } from '@epic-web/workshop-utils/apps.server'\nimport {\n\tcloseProcess,\n\trunAppDev,\n\tstopPort,\n\twaitOnApp,\n} from '@epic-web/workshop-utils/process-manager.server'\nimport { data, type ActionFunctionArgs, useFetcher } from 'react-router'\nimport { Button } from '#app/components/button.tsx'\nimport { Loading } from '#app/components/loading.tsx'\nimport { showProgressBarField } from '#app/components/progress-bar.tsx'\nimport { ensureUndeployed, useAltDown } from '#app/utils/misc.tsx'\nimport { dataWithPE, usePERedirectInput } from '#app/utils/pe.tsx'\nimport { createToastHeaders } from '#app/utils/toast.server'\n\nexport async function action({ request }: ActionFunctionArgs) {\n\tensureUndeployed()\n\tconst formData = await request.formData()\n\tconst intent = formData.get('intent')\n\tinvariantResponse(typeof intent === 'string', 'intent is required')\n\n\tif (intent === 'start' || intent === 'stop' || intent === 'restart') {\n\t\tconst name = formData.get('name')\n\t\tinvariantResponse(typeof name === 'string', 'name is required')\n\t\tconst app = await getAppByName(name)\n\t\tif (!app) {\n\t\t\tthrow new Response('Not found', { status: 404 })\n\t\t}\n\t\tif (app.dev.type !== 'script') {\n\t\t\tthrow new Response(`App \"${name}\" does not have a server`, {\n\t\t\t\tstatus: 400,\n\t\t\t})\n\t\t}\n\n\t\tasync function startApp() {\n\t\t\tinvariant(app, 'app must be defined')\n\t\t\tconst result = await runAppDev(app)\n\t\t\tif (result.running) {\n\t\t\t\tconst appRunningResult = await waitOnApp(app)\n\t\t\t\tif (appRunningResult?.status === 'success') {\n\t\t\t\t\t// wait another 200ms just in case the build output for assets isn't finished\n\t\t\t\t\tawait new Promise((resolve) => setTimeout(resolve, 200))\n\t\t\t\t\treturn dataWithPE(request, formData, {\n\t\t\t\t\t\tstatus: 'app-started',\n\t\t\t\t\t} as const)\n\t\t\t\t} else if (app.dev.type === 'script') {\n\t\t\t\t\tconst errorMessage = appRunningResult\n\t\t\t\t\t\t? appRunningResult.error\n\t\t\t\t\t\t: 'Unknown error'\n\t\t\t\t\treturn data(\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tstatus: 'app-not-started',\n\t\t\t\t\t\t\terror: errorMessage,\n\t\t\t\t\t\t\tport: app.dev.portNumber,\n\t\t\t\t\t\t} as const,\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tstatus: 500,\n\t\t\t\t\t\t\tstatusText: 'App did not start',\n\t\t\t\t\t\t\theaders: await createToastHeaders({\n\t\t\t\t\t\t\t\tdescription: errorMessage,\n\t\t\t\t\t\t\t\ttitle: 'App did not start',\n\t\t\t\t\t\t\t\ttype: 'error',\n\t\t\t\t\t\t\t}),\n\t\t\t\t\t\t},\n\t\t\t\t\t)\n\t\t\t\t}\n\t\t\t} else if (result.portNumber) {\n\t\t\t\treturn dataWithPE(request, formData, {\n\t\t\t\t\tstatus: 'app-not-started',\n\t\t\t\t\terror: result.status,\n\t\t\t\t\tport: result.portNumber,\n\t\t\t\t} as const)\n\t\t\t} else {\n\t\t\t\tthrow new Response(\n\t\t\t\t\t'Tried starting a server for an app that does not have one',\n\t\t\t\t\t{ status: 400 },\n\t\t\t\t)\n\t\t\t}\n\t\t}\n\n\t\tasync function stopApp() {\n\t\t\tinvariant(app, 'app must be defined')\n\t\t\tawait closeProcess(app.name)\n\t\t\treturn dataWithPE(request, formData, { status: 'app-stopped' } as const)\n\t\t}\n\n\t\tswitch (intent) {\n\t\t\tcase 'start': {\n\t\t\t\treturn startApp()\n\t\t\t}\n\t\t\tcase 'stop': {\n\t\t\t\treturn stopApp()\n\t\t\t}\n\t\t\tcase 'restart': {\n\t\t\t\tawait stopApp()\n\t\t\t\treturn startApp()\n\t\t\t}\n\t\t}\n\t}\n\n\tif (intent === 'stop-port') {\n\t\tconst port = formData.get('port')\n\t\tinvariantResponse(typeof port === 'string', 'port is required')\n\t\tawait stopPort(port)\n\t\treturn dataWithPE(request, formData, { status: 'port-stopped' } as const)\n\t}\n\tthrow new Error(`Unknown intent: ${intent}`)\n}\n\nexport function AppStopper({ name }: { name: string }) {\n\tconst fetcher = useFetcher<typeof action>()\n\tconst peRedirectInput = usePERedirectInput()\n\tconst inFlightIntent = fetcher.formData?.get('intent')\n\tconst inFlightState =\n\t\tinFlightIntent === 'stop'\n\t\t\t? 'Stopping App'\n\t\t\t: inFlightIntent === 'restart'\n\t\t\t\t? 'Restarting App'\n\t\t\t\t: null\n\tconst altDown = useAltDown()\n\treturn (\n\t\t<fetcher.Form method=\"POST\" action=\"/start\">\n\t\t\t{peRedirectInput}\n\t\t\t{showProgressBarField}\n\t\t\t<input type=\"hidden\" name=\"name\" value={name} />\n\t\t\t<button\n\t\t\t\ttype=\"submit\"\n\t\t\t\tname=\"intent\"\n\t\t\t\tvalue={altDown ? 'restart' : 'stop'}\n\t\t\t\tclassName=\"h-full border-r px-3 py-4 font-mono text-xs leading-none uppercase\"\n\t\t\t>\n\t\t\t\t{inFlightState ? inFlightState : altDown ? 'Restart App' : 'Stop App'}\n\t\t\t</button>\n\t\t</fetcher.Form>\n\t)\n}\n\nexport function PortStopper({ port }: { port: number | string }) {\n\tconst fetcher = useFetcher<typeof action>()\n\tconst peRedirectInput = usePERedirectInput()\n\treturn (\n\t\t<fetcher.Form method=\"POST\" action=\"/start\">\n\t\t\t{peRedirectInput}\n\t\t\t{showProgressBarField}\n\t\t\t<input type=\"hidden\" name=\"port\" value={port} />\n\t\t\t<Button varient=\"mono\" type=\"submit\" name=\"intent\" value=\"stop-port\">\n\t\t\t\t{fetcher.state === 'idle' ? 'Stop Port' : 'Stopping Port'}\n\t\t\t</Button>\n\t\t</fetcher.Form>\n\t)\n}\n\nexport function AppStarter({ name }: { name: string }) {\n\tconst fetcher = useFetcher<typeof action>()\n\tconst peRedirectInput = usePERedirectInput()\n\tif (fetcher.data?.status === 'app-not-started') {\n\t\tif (fetcher.data.error === 'port-unavailable') {\n\t\t\treturn (\n\t\t\t\t<div>\n\t\t\t\t\tThe port is unavailable. Would you like to stop whatever is running on\n\t\t\t\t\tthat port and try again?\n\t\t\t\t\t<PortStopper port={fetcher.data.port} />\n\t\t\t\t</div>\n\t\t\t)\n\t\t} else {\n\t\t\treturn <div>An unknown error has happened.</div>\n\t\t}\n\t}\n\treturn (\n\t\t<fetcher.Form method=\"POST\" action=\"/start\">\n\t\t\t{peRedirectInput}\n\t\t\t{showProgressBarField}\n\t\t\t<input type=\"hidden\" name=\"name\" value={name} />\n\t\t\t{fetcher.state === 'idle' ? (\n\t\t\t\t<Button type=\"submit\" name=\"intent\" value=\"start\" varient=\"mono\">\n\t\t\t\t\tStart App\n\t\t\t\t</Button>\n\t\t\t) : (\n\t\t\t\t<div>\n\t\t\t\t\t<Loading>Starting App</Loading>\n\t\t\t\t</div>\n\t\t\t)}\n\t\t</fetcher.Form>\n\t)\n}\n","import { clsx } from 'clsx'\nimport * as React from 'react'\nimport { useImperativeHandle, useRef, useState } from 'react'\nimport { Icon } from '#app/components/icons.tsx'\nimport { AppStarter, AppStopper, PortStopper } from '#app/routes/start.tsx'\nimport { useTheme } from '#app/routes/theme/index.tsx'\nimport { getBaseUrl } from '#app/utils/misc.tsx'\nimport { useRequestInfo } from '#app/utils/root-loader.ts'\nimport { LinkButton } from './button.tsx'\nimport {\n\tTooltip,\n\tTooltipContent,\n\tTooltipProvider,\n\tTooltipTrigger,\n} from './ui/tooltip.tsx'\n\nexport type InBrowserBrowserRef = {\n\thandleExtrnalNavigation: (pathname?: string) => void\n}\n\ntype Props = {\n\tid: string\n\tname: string\n\tport: number\n\tportIsAvailable: boolean | null\n\tisRunning: boolean\n\tbaseUrl: string\n\tinitialRoute: string\n\tref?: React.Ref<InBrowserBrowserRef>\n}\n\nexport function InBrowserBrowser({\n\tname,\n\tport,\n\tportIsAvailable,\n\tisRunning,\n\tbaseUrl,\n\tid,\n\tinitialRoute,\n\tref,\n}: Props) {\n\tconst requestInfo = useRequestInfo()\n\tconst [showUnmanaged, setShowUnmanaged] = useState(false)\n\tif (isRunning || showUnmanaged) {\n\t\treturn (\n\t\t\t<InBrowserBrowserForRealz\n\t\t\t\tbaseUrl={baseUrl}\n\t\t\t\tid={id}\n\t\t\t\tname={name}\n\t\t\t\tref={ref}\n\t\t\t\tinitialRoute={initialRoute}\n\t\t\t/>\n\t\t)\n\t} else if (portIsAvailable === false) {\n\t\treturn (\n\t\t\t<div className=\"flex flex-col items-center justify-center\">\n\t\t\t\t<p className=\"max-w-xs pb-5 text-center\" role=\"status\">\n\t\t\t\t\t{`The port for this app is unavailable. It could be that you're running it `}\n\t\t\t\t\t<a\n\t\t\t\t\t\thref={getBaseUrl({ domain: requestInfo.domain, port })}\n\t\t\t\t\t\tclassName=\"underline\"\n\t\t\t\t\t\ttarget=\"_blank\"\n\t\t\t\t\t\trel=\"noreferrer\"\n\t\t\t\t\t>\n\t\t\t\t\t\telsewhere\n\t\t\t\t\t</a>\n\t\t\t\t\t{'. '}\n\t\t\t\t\t<LinkButton onClick={() => setShowUnmanaged(true)}>\n\t\t\t\t\t\tShow here anyway\n\t\t\t\t\t</LinkButton>\n\t\t\t\t</p>\n\t\t\t\t<PortStopper port={port} />\n\t\t\t</div>\n\t\t)\n\t} else {\n\t\treturn (\n\t\t\t<div className=\"flex h-full flex-col items-center justify-center\">\n\t\t\t\t<AppStarter name={name} />\n\t\t\t</div>\n\t\t)\n\t}\n}\ntype RealBrowserProps = {\n\tbaseUrl: string\n\tid: string\n\tname: string\n\tinitialRoute: string\n\tref?: React.Ref<InBrowserBrowserRef>\n}\n\nfunction InBrowserBrowserForRealz({\n\tbaseUrl,\n\tid,\n\tname,\n\tinitialRoute,\n\tref,\n}: RealBrowserProps) {\n\tconst theme = useTheme()\n\tconst [iframeKeyNumber, setIframeKeyNumber] = useState(0)\n\tconst iframeKey = id + iframeKeyNumber\n\tconst iframeRef = useRef<HTMLIFrameElement>(null)\n\n\tconst appUrl = new URL(initialRoute, baseUrl)\n\tconst [iframeSrcUrl, setIframeSrcUrl] = useState(appUrl)\n\n\tconst currentId = useRef(id)\n\tif (currentId.current !== id) {\n\t\tcurrentId.current = id\n\t\tsetIframeSrcUrl(appUrl)\n\t}\n\n\tfunction handleExtrnalNavigation(pathname?: string) {\n\t\tif (pathname) {\n\t\t\tconst newUrl = new URL(pathname, baseUrl)\n\t\t\tsetIframeSrcUrl(newUrl)\n\t\t\tsetIframeKeyNumber((prev) => prev + 1)\n\t\t}\n\t}\n\n\tuseImperativeHandle(ref, () => ({ handleExtrnalNavigation }))\n\n\treturn (\n\t\t<TooltipProvider>\n\t\t\t<div className=\"flex h-full grow flex-col\">\n\t\t\t\t<div className=\"flex items-center justify-between border-b pl-1.5\">\n\t\t\t\t\t<div className=\"mr-2 flex items-center justify-center gap-2 px-1\">\n\t\t\t\t\t\t<Tooltip>\n\t\t\t\t\t\t\t<TooltipTrigger asChild>\n\t\t\t\t\t\t\t\t<button\n\t\t\t\t\t\t\t\t\ttype=\"button\"\n\t\t\t\t\t\t\t\t\tclassName=\"flex aspect-square h-full w-full items-center justify-center p-1 transition disabled:opacity-40\"\n\t\t\t\t\t\t\t\t\tonClick={() => {\n\t\t\t\t\t\t\t\t\t\tsetIframeKeyNumber((prev) => prev + 1)\n\t\t\t\t\t\t\t\t\t}}\n\t\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t\t<Icon name=\"Refresh\" aria-hidden=\"true\" />\n\t\t\t\t\t\t\t\t</button>\n\t\t\t\t\t\t\t</TooltipTrigger>\n\t\t\t\t\t\t\t<TooltipContent>Refresh</TooltipContent>\n\t\t\t\t\t\t</Tooltip>\n\t\t\t\t\t</div>\n\t\t\t\t\t<div className=\"bg-background text-foreground flex flex-1 items-center border-x p-3 leading-none\">\n\t\t\t\t\t\t<a href={iframeSrcUrl.toString()} target=\"_blank\" rel=\"noreferrer\">\n\t\t\t\t\t\t\t{iframeSrcUrl.toString()}\n\t\t\t\t\t\t</a>\n\t\t\t\t\t</div>\n\t\t\t\t\t<AppStopper name={name} />\n\t\t\t\t\t<Tooltip>\n\t\t\t\t\t\t<TooltipTrigger asChild>\n\t\t\t\t\t\t\t<a\n\t\t\t\t\t\t\t\thref={iframeSrcUrl.toString()}\n\t\t\t\t\t\t\t\ttarget=\"_blank\"\n\t\t\t\t\t\t\t\trel=\"noreferrer\"\n\t\t\t\t\t\t\t\tclassName={clsx(\n\t\t\t\t\t\t\t\t\t'flex aspect-square items-center justify-center px-3.5',\n\t\t\t\t\t\t\t\t)}\n\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t<Icon name=\"ExternalLink\" />\n\t\t\t\t\t\t\t</a>\n\t\t\t\t\t\t</TooltipTrigger>\n\t\t\t\t\t\t<TooltipContent>Open in new tab</TooltipContent>\n\t\t\t\t\t</Tooltip>\n\t\t\t\t</div>\n\t\t\t\t<div className=\"bg-background flex h-full w-full grow\">\n\t\t\t\t\t<iframe\n\t\t\t\t\t\ttitle={name}\n\t\t\t\t\t\tkey={iframeKey}\n\t\t\t\t\t\tref={iframeRef}\n\t\t\t\t\t\tsrc={iframeSrcUrl.toString()}\n\t\t\t\t\t\tclassName=\"bg-background h-full w-full grow\"\n\t\t\t\t\t\tstyle={{ colorScheme: theme }}\n\t\t\t\t\t\tallow=\"clipboard-write\"\n\t\t\t\t\t/>\n\t\t\t\t</div>\n\t\t\t</div>\n\t\t</TooltipProvider>\n\t)\n}\n","import { type BaseExerciseStepApp } from '@epic-web/workshop-utils/apps.server'\nimport { useState } from 'react'\nimport { useSearchParams } from 'react-router'\nimport { Icon } from '#app/components/icons'\nimport {\n\tInBrowserBrowser,\n\ttype InBrowserBrowserRef,\n} from '#app/components/in-browser-browser.tsx'\nimport { Loading } from '#app/components/loading.tsx'\nimport { useTheme } from '#app/routes/theme/index.tsx'\nimport { cn, getBaseUrl } from '#app/utils/misc.tsx'\nimport { useRequestInfo } from '#app/utils/root-loader.ts'\n\nexport function Preview({\n\tid,\n\tappInfo,\n\tinBrowserBrowserRef,\n}: {\n\tid?: string\n\tappInfo: {\n\t\tisRunning: boolean\n\t\tappName?: string\n\t\tname: string\n\t\ttitle: string\n\t\tportIsAvailable: boolean | null\n\t\ttype: string\n\t\tfullPath: string\n\t\tdev: BaseExerciseStepApp['dev']\n\t\ttest: BaseExerciseStepApp['test']\n\t\tstackBlitzUrl: BaseExerciseStepApp['stackBlitzUrl']\n\t} | null\n\tinBrowserBrowserRef: React.RefObject<InBrowserBrowserRef | null>\n}) {\n\tconst requestInfo = useRequestInfo()\n\tconst [searchParams] = useSearchParams()\n\tconst theme = useTheme()\n\tif (!appInfo) return <p>No app here. Sorry.</p>\n\tconst { isRunning, dev, name, portIsAvailable, title } = appInfo\n\n\tif (!dev) {\n\t\treturn (\n\t\t\t<div className=\"flex h-full items-center justify-center text-lg\">\n\t\t\t\t<p>No preview available for this app.</p>\n\t\t\t</div>\n\t\t)\n\t}\n\n\tif (ENV.EPICSHOP_DEPLOYED && appInfo.stackBlitzUrl) {\n\t\tconst url = new URL(appInfo.stackBlitzUrl)\n\t\turl.searchParams.set('embed', '1')\n\t\turl.searchParams.set('theme', theme)\n\n\t\treturn (\n\t\t\t<StackBlitzEmbed\n\t\t\t\ttitle={title}\n\t\t\t\turl={url.toString()}\n\t\t\t\tloadingContent={\n\t\t\t\t\t<Loading>\n\t\t\t\t\t\t<span>\n\t\t\t\t\t\t\tLoading{' '}\n\t\t\t\t\t\t\t<a className=\"underline\" href={appInfo.stackBlitzUrl}>\n\t\t\t\t\t\t\t\t\"{title}\"\n\t\t\t\t\t\t\t</a>\n\t\t\t\t\t\t</span>\n\t\t\t\t\t</Loading>\n\t\t\t\t}\n\t\t\t/>\n\t\t)\n\t}\n\n\tif (dev.type === 'script') {\n\t\tconst baseUrl = getBaseUrl({\n\t\t\tdomain: requestInfo.domain,\n\t\t\tport: dev.portNumber,\n\t\t})\n\t\treturn (\n\t\t\t<InBrowserBrowser\n\t\t\t\tref={inBrowserBrowserRef}\n\t\t\t\tisRunning={isRunning}\n\t\t\t\tid={id ?? name}\n\t\t\t\tname={name}\n\t\t\t\tportIsAvailable={portIsAvailable}\n\t\t\t\tport={dev.portNumber}\n\t\t\t\tbaseUrl={baseUrl}\n\t\t\t\tinitialRoute={searchParams.get('pathname') ?? dev.initialRoute}\n\t\t\t/>\n\t\t)\n\t} else if (dev.type === 'browser' || dev.type === 'export') {\n\t\treturn (\n\t\t\t<div className=\"scrollbar-thin scrollbar-thumb-scrollbar relative h-full grow overflow-y-auto\">\n\t\t\t\t<a\n\t\t\t\t\thref={dev.pathname}\n\t\t\t\t\ttarget=\"_blank\"\n\t\t\t\t\trel=\"noreferrer\"\n\t\t\t\t\tclassName={cn(\n\t\t\t\t\t\t'bg-muted text-foreground hover:bg-muted/80 absolute right-5 bottom-5 flex items-center justify-center rounded-full p-2.5 transition',\n\t\t\t\t\t)}\n\t\t\t\t>\n\t\t\t\t\t<Icon name=\"ExternalLink\" aria-hidden=\"true\" />\n\t\t\t\t\t<span className=\"sr-only\">Open in New Window</span>\n\t\t\t\t</a>\n\t\t\t\t<iframe\n\t\t\t\t\ttitle={title}\n\t\t\t\t\tsrc={dev.pathname}\n\t\t\t\t\tclassName=\"bg-background h-full w-full grow\"\n\t\t\t\t\tstyle={{ colorScheme: theme }}\n\t\t\t\t\tallow=\"clipboard-write\"\n\t\t\t\t/>\n\t\t\t</div>\n\t\t)\n\t} else {\n\t\treturn (\n\t\t\t<div className=\"flex h-full items-center justify-center text-lg\">\n\t\t\t\t<p>\n\t\t\t\t\tPreview for dev type of <code>{dev.type}</code> not supported.\n\t\t\t\t</p>\n\t\t\t</div>\n\t\t)\n\t}\n}\n\nexport function StackBlitzEmbed({\n\turl,\n\ttitle,\n\tloadingContent,\n}: {\n\turl: string\n\ttitle?: string\n\tloadingContent: React.ReactNode\n}) {\n\tconst theme = useTheme()\n\tconst [iframeLoaded, setIframeLoaded] = useState(false)\n\n\treturn (\n\t\t<div className=\"h-full w-full grow\">\n\t\t\t{iframeLoaded ? null : (\n\t\t\t\t<div className=\"absolute inset-0 z-10 flex items-center justify-center\">\n\t\t\t\t\t{loadingContent}\n\t\t\t\t</div>\n\t\t\t)}\n\t\t\t<iframe\n\t\t\t\tonLoad={() => setIframeLoaded(true)}\n\t\t\t\t// show what would have shown if there is an error\n\t\t\t\tonError={() => setIframeLoaded(true)}\n\t\t\t\tsrc={url}\n\t\t\t\tclassName={cn(\n\t\t\t\t\t'h-full w-full grow transition-opacity duration-300',\n\t\t\t\t\tiframeLoaded ? 'opacity-100' : 'opacity-0',\n\t\t\t\t)}\n\t\t\t\ttitle={title}\n\t\t\t\tsandbox=\"allow-forms allow-scripts allow-same-origin allow-popups allow-popups-to-escape-sandbox\"\n\t\t\t\tallow=\"clipboard-write\"\n\t\t\t\tstyle={{ colorScheme: theme }}\n\t\t\t/>\n\t\t</div>\n\t)\n}\n"],"names":["AppStopper","name","fetcher","useFetcher","peRedirectInput","usePERedirectInput","inFlightIntent","formData","get","inFlightState","altDown","useAltDown","Form","method","action","children","showProgressBarField","type","value","jsx","className","PortStopper","port","Button","varient","state","AppStarter","data","status","error","Loading","InBrowserBrowser","portIsAvailable","isRunning","baseUrl","id","initialRoute","ref","requestInfo","useRequestInfo","showUnmanaged","setShowUnmanaged","useState","InBrowserBrowserForRealz","jsxs","getBaseUrl","LinkButton","theme","useTheme","iframeKeyNumber","setIframeKeyNumber","iframeKey","iframeRef","useRef","appUrl","iframeSrcUrl","setIframeSrcUrl","currentId","handleExtrnalNavigation","pathname","newUrl","prev","useImperativeHandle","TooltipProvider","Tooltip","TooltipTrigger","Icon","TooltipContent","clsx","Preview","appInfo","inBrowserBrowserRef","searchParams","useSearchParams","dev","title","url","StackBlitzEmbed","cn","loadingContent","iframeLoaded","setIframeLoaded"],"mappings":"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"}
1
+ {"version":3,"file":"preview-D11Pscbe.js","sources":["../../../app/routes/start.tsx","../../../app/components/in-browser-browser.tsx","../../../app/routes/_app+/exercise+/$exerciseNumber_.$stepNumber.$type+/__shared/preview.tsx"],"sourcesContent":["import { invariant, invariantResponse } from '@epic-web/invariant'\nimport { getAppByName } from '@epic-web/workshop-utils/apps.server'\nimport {\n\tcloseProcess,\n\trunAppDev,\n\tstopPort,\n\twaitOnApp,\n} from '@epic-web/workshop-utils/process-manager.server'\nimport { data, type ActionFunctionArgs, useFetcher } from 'react-router'\nimport { Button } from '#app/components/button.tsx'\nimport { Loading } from '#app/components/loading.tsx'\nimport { showProgressBarField } from '#app/components/progress-bar.tsx'\nimport { ensureUndeployed, useAltDown } from '#app/utils/misc.tsx'\nimport { dataWithPE, usePERedirectInput } from '#app/utils/pe.tsx'\nimport { createToastHeaders } from '#app/utils/toast.server'\n\nexport async function action({ request }: ActionFunctionArgs) {\n\tensureUndeployed()\n\tconst formData = await request.formData()\n\tconst intent = formData.get('intent')\n\tinvariantResponse(typeof intent === 'string', 'intent is required')\n\n\tif (intent === 'start' || intent === 'stop' || intent === 'restart') {\n\t\tconst name = formData.get('name')\n\t\tinvariantResponse(typeof name === 'string', 'name is required')\n\t\tconst app = await getAppByName(name)\n\t\tif (!app) {\n\t\t\tthrow new Response('Not found', { status: 404 })\n\t\t}\n\t\tif (app.dev.type !== 'script') {\n\t\t\tthrow new Response(`App \"${name}\" does not have a server`, {\n\t\t\t\tstatus: 400,\n\t\t\t})\n\t\t}\n\n\t\tasync function startApp() {\n\t\t\tinvariant(app, 'app must be defined')\n\t\t\tconst result = await runAppDev(app)\n\t\t\tif (result.running) {\n\t\t\t\tconst appRunningResult = await waitOnApp(app)\n\t\t\t\tif (appRunningResult?.status === 'success') {\n\t\t\t\t\t// wait another 200ms just in case the build output for assets isn't finished\n\t\t\t\t\tawait new Promise((resolve) => setTimeout(resolve, 200))\n\t\t\t\t\treturn dataWithPE(request, formData, {\n\t\t\t\t\t\tstatus: 'app-started',\n\t\t\t\t\t} as const)\n\t\t\t\t} else if (app.dev.type === 'script') {\n\t\t\t\t\tconst errorMessage = appRunningResult\n\t\t\t\t\t\t? appRunningResult.error\n\t\t\t\t\t\t: 'Unknown error'\n\t\t\t\t\treturn data(\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tstatus: 'app-not-started',\n\t\t\t\t\t\t\terror: errorMessage,\n\t\t\t\t\t\t\tport: app.dev.portNumber,\n\t\t\t\t\t\t} as const,\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tstatus: 500,\n\t\t\t\t\t\t\tstatusText: 'App did not start',\n\t\t\t\t\t\t\theaders: await createToastHeaders({\n\t\t\t\t\t\t\t\tdescription: errorMessage,\n\t\t\t\t\t\t\t\ttitle: 'App did not start',\n\t\t\t\t\t\t\t\ttype: 'error',\n\t\t\t\t\t\t\t}),\n\t\t\t\t\t\t},\n\t\t\t\t\t)\n\t\t\t\t}\n\t\t\t} else if (result.portNumber) {\n\t\t\t\treturn dataWithPE(request, formData, {\n\t\t\t\t\tstatus: 'app-not-started',\n\t\t\t\t\terror: result.status,\n\t\t\t\t\tport: result.portNumber,\n\t\t\t\t} as const)\n\t\t\t} else {\n\t\t\t\tthrow new Response(\n\t\t\t\t\t'Tried starting a server for an app that does not have one',\n\t\t\t\t\t{ status: 400 },\n\t\t\t\t)\n\t\t\t}\n\t\t}\n\n\t\tasync function stopApp() {\n\t\t\tinvariant(app, 'app must be defined')\n\t\t\tawait closeProcess(app.name)\n\t\t\treturn dataWithPE(request, formData, { status: 'app-stopped' } as const)\n\t\t}\n\n\t\tswitch (intent) {\n\t\t\tcase 'start': {\n\t\t\t\treturn startApp()\n\t\t\t}\n\t\t\tcase 'stop': {\n\t\t\t\treturn stopApp()\n\t\t\t}\n\t\t\tcase 'restart': {\n\t\t\t\tawait stopApp()\n\t\t\t\treturn startApp()\n\t\t\t}\n\t\t}\n\t}\n\n\tif (intent === 'stop-port') {\n\t\tconst port = formData.get('port')\n\t\tinvariantResponse(typeof port === 'string', 'port is required')\n\t\tawait stopPort(port)\n\t\treturn dataWithPE(request, formData, { status: 'port-stopped' } as const)\n\t}\n\tthrow new Error(`Unknown intent: ${intent}`)\n}\n\nexport function AppStopper({ name }: { name: string }) {\n\tconst fetcher = useFetcher<typeof action>()\n\tconst peRedirectInput = usePERedirectInput()\n\tconst inFlightIntent = fetcher.formData?.get('intent')\n\tconst inFlightState =\n\t\tinFlightIntent === 'stop'\n\t\t\t? 'Stopping App'\n\t\t\t: inFlightIntent === 'restart'\n\t\t\t\t? 'Restarting App'\n\t\t\t\t: null\n\tconst altDown = useAltDown()\n\treturn (\n\t\t<fetcher.Form method=\"POST\" action=\"/start\">\n\t\t\t{peRedirectInput}\n\t\t\t{showProgressBarField}\n\t\t\t<input type=\"hidden\" name=\"name\" value={name} />\n\t\t\t<button\n\t\t\t\ttype=\"submit\"\n\t\t\t\tname=\"intent\"\n\t\t\t\tvalue={altDown ? 'restart' : 'stop'}\n\t\t\t\tclassName=\"h-full border-r px-3 py-4 font-mono text-xs leading-none uppercase\"\n\t\t\t>\n\t\t\t\t{inFlightState ? inFlightState : altDown ? 'Restart App' : 'Stop App'}\n\t\t\t</button>\n\t\t</fetcher.Form>\n\t)\n}\n\nexport function PortStopper({ port }: { port: number | string }) {\n\tconst fetcher = useFetcher<typeof action>()\n\tconst peRedirectInput = usePERedirectInput()\n\treturn (\n\t\t<fetcher.Form method=\"POST\" action=\"/start\">\n\t\t\t{peRedirectInput}\n\t\t\t{showProgressBarField}\n\t\t\t<input type=\"hidden\" name=\"port\" value={port} />\n\t\t\t<Button varient=\"mono\" type=\"submit\" name=\"intent\" value=\"stop-port\">\n\t\t\t\t{fetcher.state === 'idle' ? 'Stop Port' : 'Stopping Port'}\n\t\t\t</Button>\n\t\t</fetcher.Form>\n\t)\n}\n\nexport function AppStarter({ name }: { name: string }) {\n\tconst fetcher = useFetcher<typeof action>()\n\tconst peRedirectInput = usePERedirectInput()\n\tif (fetcher.data?.status === 'app-not-started') {\n\t\tif (fetcher.data.error === 'port-unavailable') {\n\t\t\treturn (\n\t\t\t\t<div>\n\t\t\t\t\tThe port is unavailable. Would you like to stop whatever is running on\n\t\t\t\t\tthat port and try again?\n\t\t\t\t\t<PortStopper port={fetcher.data.port} />\n\t\t\t\t</div>\n\t\t\t)\n\t\t} else {\n\t\t\treturn <div>An unknown error has happened.</div>\n\t\t}\n\t}\n\treturn (\n\t\t<fetcher.Form method=\"POST\" action=\"/start\">\n\t\t\t{peRedirectInput}\n\t\t\t{showProgressBarField}\n\t\t\t<input type=\"hidden\" name=\"name\" value={name} />\n\t\t\t{fetcher.state === 'idle' ? (\n\t\t\t\t<Button type=\"submit\" name=\"intent\" value=\"start\" varient=\"mono\">\n\t\t\t\t\tStart App\n\t\t\t\t</Button>\n\t\t\t) : (\n\t\t\t\t<div>\n\t\t\t\t\t<Loading>Starting App</Loading>\n\t\t\t\t</div>\n\t\t\t)}\n\t\t</fetcher.Form>\n\t)\n}\n","import { clsx } from 'clsx'\nimport * as React from 'react'\nimport { useImperativeHandle, useRef, useState } from 'react'\nimport { Icon } from '#app/components/icons.tsx'\nimport { AppStarter, AppStopper, PortStopper } from '#app/routes/start.tsx'\nimport { useTheme } from '#app/routes/theme/index.tsx'\nimport { getBaseUrl } from '#app/utils/misc.tsx'\nimport { useRequestInfo } from '#app/utils/root-loader.ts'\nimport { LinkButton } from './button.tsx'\nimport {\n\tTooltip,\n\tTooltipContent,\n\tTooltipProvider,\n\tTooltipTrigger,\n} from './ui/tooltip.tsx'\n\nexport type InBrowserBrowserRef = {\n\thandleExtrnalNavigation: (pathname?: string) => void\n}\n\ntype Props = {\n\tid: string\n\tname: string\n\tport: number\n\tportIsAvailable: boolean | null\n\tisRunning: boolean\n\tbaseUrl: string\n\tinitialRoute: string\n\tref?: React.Ref<InBrowserBrowserRef>\n}\n\nexport function InBrowserBrowser({\n\tname,\n\tport,\n\tportIsAvailable,\n\tisRunning,\n\tbaseUrl,\n\tid,\n\tinitialRoute,\n\tref,\n}: Props) {\n\tconst requestInfo = useRequestInfo()\n\tconst [showUnmanaged, setShowUnmanaged] = useState(false)\n\tif (isRunning || showUnmanaged) {\n\t\treturn (\n\t\t\t<InBrowserBrowserForRealz\n\t\t\t\tbaseUrl={baseUrl}\n\t\t\t\tid={id}\n\t\t\t\tname={name}\n\t\t\t\tref={ref}\n\t\t\t\tinitialRoute={initialRoute}\n\t\t\t/>\n\t\t)\n\t} else if (portIsAvailable === false) {\n\t\treturn (\n\t\t\t<div className=\"flex flex-col items-center justify-center\">\n\t\t\t\t<p className=\"max-w-xs pb-5 text-center\" role=\"status\">\n\t\t\t\t\t{`The port for this app is unavailable. It could be that you're running it `}\n\t\t\t\t\t<a\n\t\t\t\t\t\thref={getBaseUrl({ domain: requestInfo.domain, port })}\n\t\t\t\t\t\tclassName=\"underline\"\n\t\t\t\t\t\ttarget=\"_blank\"\n\t\t\t\t\t\trel=\"noreferrer\"\n\t\t\t\t\t>\n\t\t\t\t\t\telsewhere\n\t\t\t\t\t</a>\n\t\t\t\t\t{'. '}\n\t\t\t\t\t<LinkButton onClick={() => setShowUnmanaged(true)}>\n\t\t\t\t\t\tShow here anyway\n\t\t\t\t\t</LinkButton>\n\t\t\t\t</p>\n\t\t\t\t<PortStopper port={port} />\n\t\t\t</div>\n\t\t)\n\t} else {\n\t\treturn (\n\t\t\t<div className=\"flex h-full flex-col items-center justify-center\">\n\t\t\t\t<AppStarter name={name} />\n\t\t\t</div>\n\t\t)\n\t}\n}\ntype RealBrowserProps = {\n\tbaseUrl: string\n\tid: string\n\tname: string\n\tinitialRoute: string\n\tref?: React.Ref<InBrowserBrowserRef>\n}\n\nfunction InBrowserBrowserForRealz({\n\tbaseUrl,\n\tid,\n\tname,\n\tinitialRoute,\n\tref,\n}: RealBrowserProps) {\n\tconst theme = useTheme()\n\tconst [iframeKeyNumber, setIframeKeyNumber] = useState(0)\n\tconst iframeKey = id + iframeKeyNumber\n\tconst iframeRef = useRef<HTMLIFrameElement>(null)\n\n\tconst appUrl = new URL(initialRoute, baseUrl)\n\tconst [iframeSrcUrl, setIframeSrcUrl] = useState(appUrl)\n\n\tconst currentId = useRef(id)\n\tif (currentId.current !== id) {\n\t\tcurrentId.current = id\n\t\tsetIframeSrcUrl(appUrl)\n\t}\n\n\tfunction handleExtrnalNavigation(pathname?: string) {\n\t\tif (pathname) {\n\t\t\tconst newUrl = new URL(pathname, baseUrl)\n\t\t\tsetIframeSrcUrl(newUrl)\n\t\t\tsetIframeKeyNumber((prev) => prev + 1)\n\t\t}\n\t}\n\n\tuseImperativeHandle(ref, () => ({ handleExtrnalNavigation }))\n\n\treturn (\n\t\t<TooltipProvider>\n\t\t\t<div className=\"flex h-full grow flex-col\">\n\t\t\t\t<div className=\"flex items-center justify-between border-b pl-1.5\">\n\t\t\t\t\t<div className=\"mr-2 flex items-center justify-center gap-2 px-1\">\n\t\t\t\t\t\t<Tooltip>\n\t\t\t\t\t\t\t<TooltipTrigger asChild>\n\t\t\t\t\t\t\t\t<button\n\t\t\t\t\t\t\t\t\ttype=\"button\"\n\t\t\t\t\t\t\t\t\tclassName=\"flex aspect-square h-full w-full items-center justify-center p-1 transition disabled:opacity-40\"\n\t\t\t\t\t\t\t\t\tonClick={() => {\n\t\t\t\t\t\t\t\t\t\tsetIframeKeyNumber((prev) => prev + 1)\n\t\t\t\t\t\t\t\t\t}}\n\t\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t\t<Icon name=\"Refresh\" aria-hidden=\"true\" />\n\t\t\t\t\t\t\t\t</button>\n\t\t\t\t\t\t\t</TooltipTrigger>\n\t\t\t\t\t\t\t<TooltipContent>Refresh</TooltipContent>\n\t\t\t\t\t\t</Tooltip>\n\t\t\t\t\t</div>\n\t\t\t\t\t<div className=\"bg-background text-foreground flex flex-1 items-center border-x p-3 leading-none\">\n\t\t\t\t\t\t<a href={iframeSrcUrl.toString()} target=\"_blank\" rel=\"noreferrer\">\n\t\t\t\t\t\t\t{iframeSrcUrl.toString()}\n\t\t\t\t\t\t</a>\n\t\t\t\t\t</div>\n\t\t\t\t\t<AppStopper name={name} />\n\t\t\t\t\t<Tooltip>\n\t\t\t\t\t\t<TooltipTrigger asChild>\n\t\t\t\t\t\t\t<a\n\t\t\t\t\t\t\t\thref={iframeSrcUrl.toString()}\n\t\t\t\t\t\t\t\ttarget=\"_blank\"\n\t\t\t\t\t\t\t\trel=\"noreferrer\"\n\t\t\t\t\t\t\t\tclassName={clsx(\n\t\t\t\t\t\t\t\t\t'flex aspect-square items-center justify-center px-3.5',\n\t\t\t\t\t\t\t\t)}\n\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t<Icon name=\"ExternalLink\" />\n\t\t\t\t\t\t\t</a>\n\t\t\t\t\t\t</TooltipTrigger>\n\t\t\t\t\t\t<TooltipContent>Open in new tab</TooltipContent>\n\t\t\t\t\t</Tooltip>\n\t\t\t\t</div>\n\t\t\t\t<div className=\"bg-background flex h-full w-full grow\">\n\t\t\t\t\t<iframe\n\t\t\t\t\t\ttitle={name}\n\t\t\t\t\t\tkey={iframeKey}\n\t\t\t\t\t\tref={iframeRef}\n\t\t\t\t\t\tsrc={iframeSrcUrl.toString()}\n\t\t\t\t\t\tclassName=\"bg-background h-full w-full grow\"\n\t\t\t\t\t\tstyle={{ colorScheme: theme }}\n\t\t\t\t\t\tallow=\"clipboard-write\"\n\t\t\t\t\t/>\n\t\t\t\t</div>\n\t\t\t</div>\n\t\t</TooltipProvider>\n\t)\n}\n","import { type BaseExerciseStepApp } from '@epic-web/workshop-utils/apps.server'\nimport { useState } from 'react'\nimport { useSearchParams } from 'react-router'\nimport { Icon } from '#app/components/icons'\nimport {\n\tInBrowserBrowser,\n\ttype InBrowserBrowserRef,\n} from '#app/components/in-browser-browser.tsx'\nimport { Loading } from '#app/components/loading.tsx'\nimport { useTheme } from '#app/routes/theme/index.tsx'\nimport { cn, getBaseUrl } from '#app/utils/misc.tsx'\nimport { useRequestInfo } from '#app/utils/root-loader.ts'\n\nexport function Preview({\n\tid,\n\tappInfo,\n\tinBrowserBrowserRef,\n}: {\n\tid?: string\n\tappInfo: {\n\t\tisRunning: boolean\n\t\tappName?: string\n\t\tname: string\n\t\ttitle: string\n\t\tportIsAvailable: boolean | null\n\t\ttype: string\n\t\tfullPath: string\n\t\tdev: BaseExerciseStepApp['dev']\n\t\ttest: BaseExerciseStepApp['test']\n\t\tstackBlitzUrl: BaseExerciseStepApp['stackBlitzUrl']\n\t} | null\n\tinBrowserBrowserRef: React.RefObject<InBrowserBrowserRef | null>\n}) {\n\tconst requestInfo = useRequestInfo()\n\tconst [searchParams] = useSearchParams()\n\tconst theme = useTheme()\n\tif (!appInfo) return <p>No app here. Sorry.</p>\n\tconst { isRunning, dev, name, portIsAvailable, title } = appInfo\n\n\tif (!dev) {\n\t\treturn (\n\t\t\t<div className=\"flex h-full items-center justify-center text-lg\">\n\t\t\t\t<p>No preview available for this app.</p>\n\t\t\t</div>\n\t\t)\n\t}\n\n\tif (ENV.EPICSHOP_DEPLOYED && appInfo.stackBlitzUrl) {\n\t\tconst url = new URL(appInfo.stackBlitzUrl)\n\t\turl.searchParams.set('embed', '1')\n\t\turl.searchParams.set('theme', theme)\n\n\t\treturn (\n\t\t\t<StackBlitzEmbed\n\t\t\t\ttitle={title}\n\t\t\t\turl={url.toString()}\n\t\t\t\tloadingContent={\n\t\t\t\t\t<Loading>\n\t\t\t\t\t\t<span>\n\t\t\t\t\t\t\tLoading{' '}\n\t\t\t\t\t\t\t<a className=\"underline\" href={appInfo.stackBlitzUrl}>\n\t\t\t\t\t\t\t\t\"{title}\"\n\t\t\t\t\t\t\t</a>\n\t\t\t\t\t\t</span>\n\t\t\t\t\t</Loading>\n\t\t\t\t}\n\t\t\t/>\n\t\t)\n\t}\n\n\tif (dev.type === 'script') {\n\t\tconst baseUrl = getBaseUrl({\n\t\t\tdomain: requestInfo.domain,\n\t\t\tport: dev.portNumber,\n\t\t})\n\t\treturn (\n\t\t\t<InBrowserBrowser\n\t\t\t\tref={inBrowserBrowserRef}\n\t\t\t\tisRunning={isRunning}\n\t\t\t\tid={id ?? name}\n\t\t\t\tname={name}\n\t\t\t\tportIsAvailable={portIsAvailable}\n\t\t\t\tport={dev.portNumber}\n\t\t\t\tbaseUrl={baseUrl}\n\t\t\t\tinitialRoute={searchParams.get('pathname') ?? dev.initialRoute}\n\t\t\t/>\n\t\t)\n\t} else if (dev.type === 'browser' || dev.type === 'export') {\n\t\treturn (\n\t\t\t<div className=\"scrollbar-thin scrollbar-thumb-scrollbar relative h-full grow overflow-y-auto\">\n\t\t\t\t<a\n\t\t\t\t\thref={dev.pathname}\n\t\t\t\t\ttarget=\"_blank\"\n\t\t\t\t\trel=\"noreferrer\"\n\t\t\t\t\tclassName={cn(\n\t\t\t\t\t\t'bg-muted text-foreground hover:bg-muted/80 absolute right-5 bottom-5 flex items-center justify-center rounded-full p-2.5 transition',\n\t\t\t\t\t)}\n\t\t\t\t>\n\t\t\t\t\t<Icon name=\"ExternalLink\" aria-hidden=\"true\" />\n\t\t\t\t\t<span className=\"sr-only\">Open in New Window</span>\n\t\t\t\t</a>\n\t\t\t\t<iframe\n\t\t\t\t\ttitle={title}\n\t\t\t\t\tsrc={dev.pathname}\n\t\t\t\t\tclassName=\"bg-background h-full w-full grow\"\n\t\t\t\t\tstyle={{ colorScheme: theme }}\n\t\t\t\t\tallow=\"clipboard-write\"\n\t\t\t\t/>\n\t\t\t</div>\n\t\t)\n\t} else {\n\t\treturn (\n\t\t\t<div className=\"flex h-full items-center justify-center text-lg\">\n\t\t\t\t<p>\n\t\t\t\t\tPreview for dev type of <code>{dev.type}</code> not supported.\n\t\t\t\t</p>\n\t\t\t</div>\n\t\t)\n\t}\n}\n\nexport function StackBlitzEmbed({\n\turl,\n\ttitle,\n\tloadingContent,\n}: {\n\turl: string\n\ttitle?: string\n\tloadingContent: React.ReactNode\n}) {\n\tconst theme = useTheme()\n\tconst [iframeLoaded, setIframeLoaded] = useState(false)\n\n\treturn (\n\t\t<div className=\"h-full w-full grow\">\n\t\t\t{iframeLoaded ? null : (\n\t\t\t\t<div className=\"absolute inset-0 z-10 flex items-center justify-center\">\n\t\t\t\t\t{loadingContent}\n\t\t\t\t</div>\n\t\t\t)}\n\t\t\t<iframe\n\t\t\t\tonLoad={() => setIframeLoaded(true)}\n\t\t\t\t// show what would have shown if there is an error\n\t\t\t\tonError={() => setIframeLoaded(true)}\n\t\t\t\tsrc={url}\n\t\t\t\tclassName={cn(\n\t\t\t\t\t'h-full w-full grow transition-opacity duration-300',\n\t\t\t\t\tiframeLoaded ? 'opacity-100' : 'opacity-0',\n\t\t\t\t)}\n\t\t\t\ttitle={title}\n\t\t\t\tsandbox=\"allow-forms allow-scripts allow-same-origin allow-popups allow-popups-to-escape-sandbox\"\n\t\t\t\tallow=\"clipboard-write\"\n\t\t\t\tstyle={{ colorScheme: theme }}\n\t\t\t/>\n\t\t</div>\n\t)\n}\n"],"names":["AppStopper","name","fetcher","useFetcher","peRedirectInput","usePERedirectInput","inFlightIntent","formData","get","inFlightState","altDown","useAltDown","Form","method","action","children","showProgressBarField","type","value","jsx","className","PortStopper","port","Button","varient","state","AppStarter","data","status","error","Loading","InBrowserBrowser","portIsAvailable","isRunning","baseUrl","id","initialRoute","ref","requestInfo","useRequestInfo","showUnmanaged","setShowUnmanaged","useState","InBrowserBrowserForRealz","jsxs","getBaseUrl","LinkButton","theme","useTheme","iframeKeyNumber","setIframeKeyNumber","iframeKey","iframeRef","useRef","appUrl","iframeSrcUrl","setIframeSrcUrl","currentId","handleExtrnalNavigation","pathname","newUrl","prev","useImperativeHandle","TooltipProvider","Tooltip","TooltipTrigger","Icon","TooltipContent","clsx","Preview","appInfo","inBrowserBrowserRef","searchParams","useSearchParams","dev","title","url","StackBlitzEmbed","cn","loadingContent","iframeLoaded","setIframeLoaded"],"mappings":"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"}
@@ -1,2 +1,2 @@
1
- import{j as e}from"./jsx-runtime-C5WNSv3b.js";import{u as g}from"./index-Cg-9mI3Y.js";import{c as r}from"./misc-CRhJChs6.js";import{u as p}from"./workshop-config-BP-vDuRo.js";const i={font:"w-[1em] h-[1em]",xs:"w-3 h-3",sm:"w-4 h-4",md:"w-5 h-5",lg:"w-6 h-6",xl:"w-7 h-7","2xl":"w-8 h-8"},x={font:"gap-1.5",xs:"gap-1.5",sm:"gap-1.5",md:"gap-2",lg:"gap-2",xl:"gap-3","2xl":"gap-4"};function w({size:s="font",style:c="themed",className:o,children:t,...m}){const{product:{logo:n,displayName:l}}=p(),h=g(),a=n.includes(".svg")?e.jsxs("svg",{...m,className:r(i[s],"inline self-center",o),children:[e.jsx("title",{children:l}),e.jsx("use",{href:`${n}#${c==="themed"?h:"monochrome"}`})]}):e.jsx("img",{src:n,alt:l,...m,className:r(i[s],"inline self-center",o)});return t?e.jsxs("span",{className:`inline-flex items-center ${x[s]}`,children:[a,t]}):a}export{w as L};
2
- //# sourceMappingURL=product-DlgtjMXY.js.map
1
+ import{j as e}from"./jsx-runtime-C5WNSv3b.js";import{u as g}from"./index-DVd41HZN.js";import{c as r}from"./misc-CRhJChs6.js";import{u as p}from"./workshop-config-BP-vDuRo.js";const i={font:"w-[1em] h-[1em]",xs:"w-3 h-3",sm:"w-4 h-4",md:"w-5 h-5",lg:"w-6 h-6",xl:"w-7 h-7","2xl":"w-8 h-8"},x={font:"gap-1.5",xs:"gap-1.5",sm:"gap-1.5",md:"gap-2",lg:"gap-2",xl:"gap-3","2xl":"gap-4"};function w({size:s="font",style:c="themed",className:o,children:t,...m}){const{product:{logo:n,displayName:l}}=p(),h=g(),a=n.includes(".svg")?e.jsxs("svg",{...m,className:r(i[s],"inline self-center",o),children:[e.jsx("title",{children:l}),e.jsx("use",{href:`${n}#${c==="themed"?h:"monochrome"}`})]}):e.jsx("img",{src:n,alt:l,...m,className:r(i[s],"inline self-center",o)});return t?e.jsxs("span",{className:`inline-flex items-center ${x[s]}`,children:[a,t]}):a}export{w as L};
2
+ //# sourceMappingURL=product-CNG57fZy.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"product-DlgtjMXY.js","sources":["../../../app/components/product.tsx"],"sourcesContent":["import { useTheme } from '#app/routes/theme/index.tsx'\nimport { cn } from '#app/utils/misc.tsx'\nimport { useWorkshopConfig } from './workshop-config.tsx'\n\ntype Sizes = 'font' | 'xs' | 'sm' | 'md' | 'lg' | 'xl' | '2xl'\n\nconst sizeClassName = {\n\tfont: 'w-[1em] h-[1em]',\n\txs: 'w-3 h-3',\n\tsm: 'w-4 h-4',\n\tmd: 'w-5 h-5',\n\tlg: 'w-6 h-6',\n\txl: 'w-7 h-7',\n\t'2xl': 'w-8 h-8',\n} as const\n\nconst childrenSizeClassName = {\n\tfont: 'gap-1.5',\n\txs: 'gap-1.5',\n\tsm: 'gap-1.5',\n\tmd: 'gap-2',\n\tlg: 'gap-2',\n\txl: 'gap-3',\n\t'2xl': 'gap-4',\n} satisfies Record<Sizes, string>\n\nexport function ProductName(props: React.HTMLAttributes<HTMLSpanElement>) {\n\tconst {\n\t\tproduct: { displayName },\n\t} = useWorkshopConfig()\n\treturn <span {...props}>{displayName}</span>\n}\n\nexport function Logo({\n\tsize = 'font',\n\tstyle = 'themed',\n\tclassName,\n\tchildren,\n\t...props\n}: React.SVGProps<SVGSVGElement> & {\n\tsize?: Sizes\n\tstyle?: 'themed' | 'monochrome'\n\tclassName?: string\n\tchildren?: React.ReactNode\n}) {\n\tconst {\n\t\tproduct: { logo, displayName },\n\t} = useWorkshopConfig()\n\tconst theme = useTheme()\n\n\tconst logoElement = logo.includes('.svg') ? (\n\t\t<svg\n\t\t\t{...props}\n\t\t\tclassName={cn(sizeClassName[size], 'inline self-center', className)}\n\t\t>\n\t\t\t<title>{displayName}</title>\n\t\t\t<use href={`${logo}#${style === 'themed' ? theme : 'monochrome'}`} />\n\t\t</svg>\n\t) : (\n\t\t// @ts-expect-error - svg props can't all be applied to img... meh, probably won't ever be a real issue...\n\t\t<img\n\t\t\tsrc={logo}\n\t\t\talt={displayName}\n\t\t\t{...props}\n\t\t\tclassName={cn(sizeClassName[size], 'inline self-center', className)}\n\t\t/>\n\t)\n\n\tif (children) {\n\t\treturn (\n\t\t\t<span\n\t\t\t\tclassName={`inline-flex items-center ${childrenSizeClassName[size]}`}\n\t\t\t>\n\t\t\t\t{logoElement}\n\t\t\t\t{children}\n\t\t\t</span>\n\t\t)\n\t}\n\n\treturn logoElement\n}\n"],"names":["sizeClassName","childrenSizeClassName","Logo","size","style","className","children","props","logo","displayName","useWorkshopConfig","theme","useTheme","logoElement","jsxs","cn","jsx"],"mappings":"+KAMA,MAAMA,EAAgB,CACrB,KAAM,kBACN,GAAI,UACJ,GAAI,UACJ,GAAI,UACJ,GAAI,UACJ,GAAI,UACJ,MAAO,SACR,EAEMC,EAAwB,CAC7B,KAAM,UACN,GAAI,UACJ,GAAI,UACJ,GAAI,QACJ,GAAI,QACJ,GAAI,QACJ,MAAO,OACR,EASO,SAASC,EAAK,CACpB,KAAAC,EAAO,OACP,MAAAC,EAAQ,SACR,UAAAC,EACA,SAAAC,EACA,GAAGC,CACJ,EAKG,CACF,KAAM,CACL,QAAS,CAAE,KAAAC,EAAM,YAAAC,CAAA,CAAY,EAC1BC,EAAA,EACEC,EAAQC,EAAA,EAERC,EAAcL,EAAK,SAAS,MAAM,EACvCM,EAAAA,KAAC,MAAA,CACC,GAAGP,EACJ,UAAWQ,EAAGf,EAAcG,CAAI,EAAG,qBAAsBE,CAAS,EAElE,SAAA,CAAAW,EAAAA,IAAC,SAAO,SAAAP,CAAA,CAAY,EACpBO,EAAAA,IAAC,MAAA,CAAI,KAAM,GAAGR,CAAI,IAAIJ,IAAU,SAAWO,EAAQ,YAAY,EAAA,CAAI,CAAA,CAAA,CAAA,EAIpEK,EAAAA,IAAC,MAAA,CACA,IAAKR,EACL,IAAKC,EACJ,GAAGF,EACJ,UAAWQ,EAAGf,EAAcG,CAAI,EAAG,qBAAsBE,CAAS,CAAA,CAAA,EAIpE,OAAIC,EAEFQ,EAAAA,KAAC,OAAA,CACA,UAAW,4BAA4Bb,EAAsBE,CAAI,CAAC,GAEjE,SAAA,CAAAU,EACAP,CAAA,CAAA,CAAA,EAKGO,CACR"}
1
+ {"version":3,"file":"product-CNG57fZy.js","sources":["../../../app/components/product.tsx"],"sourcesContent":["import { useTheme } from '#app/routes/theme/index.tsx'\nimport { cn } from '#app/utils/misc.tsx'\nimport { useWorkshopConfig } from './workshop-config.tsx'\n\ntype Sizes = 'font' | 'xs' | 'sm' | 'md' | 'lg' | 'xl' | '2xl'\n\nconst sizeClassName = {\n\tfont: 'w-[1em] h-[1em]',\n\txs: 'w-3 h-3',\n\tsm: 'w-4 h-4',\n\tmd: 'w-5 h-5',\n\tlg: 'w-6 h-6',\n\txl: 'w-7 h-7',\n\t'2xl': 'w-8 h-8',\n} as const\n\nconst childrenSizeClassName = {\n\tfont: 'gap-1.5',\n\txs: 'gap-1.5',\n\tsm: 'gap-1.5',\n\tmd: 'gap-2',\n\tlg: 'gap-2',\n\txl: 'gap-3',\n\t'2xl': 'gap-4',\n} satisfies Record<Sizes, string>\n\nexport function ProductName(props: React.HTMLAttributes<HTMLSpanElement>) {\n\tconst {\n\t\tproduct: { displayName },\n\t} = useWorkshopConfig()\n\treturn <span {...props}>{displayName}</span>\n}\n\nexport function Logo({\n\tsize = 'font',\n\tstyle = 'themed',\n\tclassName,\n\tchildren,\n\t...props\n}: React.SVGProps<SVGSVGElement> & {\n\tsize?: Sizes\n\tstyle?: 'themed' | 'monochrome'\n\tclassName?: string\n\tchildren?: React.ReactNode\n}) {\n\tconst {\n\t\tproduct: { logo, displayName },\n\t} = useWorkshopConfig()\n\tconst theme = useTheme()\n\n\tconst logoElement = logo.includes('.svg') ? (\n\t\t<svg\n\t\t\t{...props}\n\t\t\tclassName={cn(sizeClassName[size], 'inline self-center', className)}\n\t\t>\n\t\t\t<title>{displayName}</title>\n\t\t\t<use href={`${logo}#${style === 'themed' ? theme : 'monochrome'}`} />\n\t\t</svg>\n\t) : (\n\t\t// @ts-expect-error - svg props can't all be applied to img... meh, probably won't ever be a real issue...\n\t\t<img\n\t\t\tsrc={logo}\n\t\t\talt={displayName}\n\t\t\t{...props}\n\t\t\tclassName={cn(sizeClassName[size], 'inline self-center', className)}\n\t\t/>\n\t)\n\n\tif (children) {\n\t\treturn (\n\t\t\t<span\n\t\t\t\tclassName={`inline-flex items-center ${childrenSizeClassName[size]}`}\n\t\t\t>\n\t\t\t\t{logoElement}\n\t\t\t\t{children}\n\t\t\t</span>\n\t\t)\n\t}\n\n\treturn logoElement\n}\n"],"names":["sizeClassName","childrenSizeClassName","Logo","size","style","className","children","props","logo","displayName","useWorkshopConfig","theme","useTheme","logoElement","jsxs","cn","jsx"],"mappings":"+KAMA,MAAMA,EAAgB,CACrB,KAAM,kBACN,GAAI,UACJ,GAAI,UACJ,GAAI,UACJ,GAAI,UACJ,GAAI,UACJ,MAAO,SACR,EAEMC,EAAwB,CAC7B,KAAM,UACN,GAAI,UACJ,GAAI,UACJ,GAAI,QACJ,GAAI,QACJ,GAAI,QACJ,MAAO,OACR,EASO,SAASC,EAAK,CACpB,KAAAC,EAAO,OACP,MAAAC,EAAQ,SACR,UAAAC,EACA,SAAAC,EACA,GAAGC,CACJ,EAKG,CACF,KAAM,CACL,QAAS,CAAE,KAAAC,EAAM,YAAAC,CAAA,CAAY,EAC1BC,EAAA,EACEC,EAAQC,EAAA,EAERC,EAAcL,EAAK,SAAS,MAAM,EACvCM,EAAAA,KAAC,MAAA,CACC,GAAGP,EACJ,UAAWQ,EAAGf,EAAcG,CAAI,EAAG,qBAAsBE,CAAS,EAElE,SAAA,CAAAW,EAAAA,IAAC,SAAO,SAAAP,CAAA,CAAY,EACpBO,EAAAA,IAAC,MAAA,CAAI,KAAM,GAAGR,CAAI,IAAIJ,IAAU,SAAWO,EAAQ,YAAY,EAAA,CAAI,CAAA,CAAA,CAAA,EAIpEK,EAAAA,IAAC,MAAA,CACA,IAAKR,EACL,IAAKC,EACJ,GAAGF,EACJ,UAAWQ,EAAGf,EAAcG,CAAI,EAAG,qBAAsBE,CAAS,CAAA,CAAA,EAIpE,OAAIC,EAEFQ,EAAAA,KAAC,OAAA,CACA,UAAW,4BAA4Bb,EAAsBE,CAAI,CAAC,GAEjE,SAAA,CAAAU,EACAP,CAAA,CAAA,CAAA,EAKGO,CACR"}