@epic-web/workshop-app 6.71.2 → 6.71.4

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 (39) hide show
  1. package/build/client/assets/{_exerciseNumber-DOydVFcz.js → _exerciseNumber-FdJ9Amz3.js} +2 -2
  2. package/build/client/assets/{_exerciseNumber-DOydVFcz.js.map → _exerciseNumber-FdJ9Amz3.js.map} +1 -1
  3. package/build/client/assets/{_exerciseNumber_.finished-OYmKydkm.js → _exerciseNumber_.finished-Z7QZ9wk-.js} +2 -2
  4. package/build/client/assets/{_exerciseNumber_.finished-OYmKydkm.js.map → _exerciseNumber_.finished-Z7QZ9wk-.js.map} +1 -1
  5. package/build/client/assets/{_extra-DAAdPX1Q.js → _extra-UkIdJCI9.js} +2 -2
  6. package/build/client/assets/{_extra-DAAdPX1Q.js.map → _extra-UkIdJCI9.js.map} +1 -1
  7. package/build/client/assets/{_layout-CeuWC4em.js → _layout-DQM0capK.js} +2 -2
  8. package/build/client/assets/{_layout-CeuWC4em.js.map → _layout-DQM0capK.js.map} +1 -1
  9. package/build/client/assets/{diff-CLewaNfR.js → diff-DwJn8fSQ.js} +2 -2
  10. package/build/client/assets/{diff-CLewaNfR.js.map → diff-DwJn8fSQ.js.map} +1 -1
  11. package/build/client/assets/{diff-DrdM1MAZ.js → diff-HIgoC1PO.js} +2 -2
  12. package/build/client/assets/{diff-DrdM1MAZ.js.map → diff-HIgoC1PO.js.map} +1 -1
  13. package/build/client/assets/{entry.client-Dbw2ihVI.js → entry.client-DSlySyW6.js} +4 -4
  14. package/build/client/assets/entry.client-DSlySyW6.js.map +1 -0
  15. package/build/client/assets/{epic-video-BO6oqwle.js → epic-video-DEq93iL_.js} +2 -2
  16. package/build/client/assets/{epic-video-BO6oqwle.js.map → epic-video-DEq93iL_.js.map} +1 -1
  17. package/build/client/assets/{epic-video-Ca_s42j5.js → epic-video-DnXXh6qE.js} +68 -68
  18. package/build/client/assets/{epic-video-Ca_s42j5.js.map → epic-video-DnXXh6qE.js.map} +1 -1
  19. package/build/client/assets/{finished-CqdoWQ9b.js → finished-PFz2gTpr.js} +2 -2
  20. package/build/client/assets/{finished-CqdoWQ9b.js.map → finished-PFz2gTpr.js.map} +1 -1
  21. package/build/client/assets/{index-o922xZRF.js → index-CATk0s1i.js} +2 -2
  22. package/build/client/assets/{index-o922xZRF.js.map → index-CATk0s1i.js.map} +1 -1
  23. package/build/client/assets/{index-BHfJ4hna.js → index-DfT8l3cx.js} +2 -2
  24. package/build/client/assets/{index-BHfJ4hna.js.map → index-DfT8l3cx.js.map} +1 -1
  25. package/build/client/assets/{index-BRVfMMSd.js → index-DkDXAMak.js} +2 -2
  26. package/build/client/assets/{index-BRVfMMSd.js.map → index-DkDXAMak.js.map} +1 -1
  27. package/build/client/assets/{manifest-49708768.js → manifest-31b392f2.js} +1 -1
  28. package/build/client/assets/{mdx-BGwe7vvs.js → mdx-Dun3ONG_.js} +2 -2
  29. package/build/client/assets/{mdx-BGwe7vvs.js.map → mdx-Dun3ONG_.js.map} +1 -1
  30. package/build/client/assets/root-BwuJUAM7.js.map +1 -1
  31. package/build/client/assets/{test-CvHPFyBI.js → test-BU7jE-eU.js} +2 -2
  32. package/build/client/assets/{test-CvHPFyBI.js.map → test-BU7jE-eU.js.map} +1 -1
  33. package/build/client/assets/{tests-DlDV-wXQ.js → tests-1-kVRtTc.js} +2 -2
  34. package/build/client/assets/{tests-DlDV-wXQ.js.map → tests-1-kVRtTc.js.map} +1 -1
  35. package/build/server/index.js +48 -21
  36. package/build/server/index.js.map +1 -1
  37. package/instrument.js +5 -0
  38. package/package.json +3 -3
  39. package/build/client/assets/entry.client-Dbw2ihVI.js.map +0 -1
@@ -1,2 +1,2 @@
1
- import{w as n,L as l}from"./chunk-EPOLDU6W-BCLmut3y.js";import{j as e}from"./jsx-runtime-C5WNSv3b.js";import{E as a}from"./index-CEVyDj51.js";import{r as c}from"./index-CqIc3cxq.js";import{E as m}from"./epic-video-Ca_s42j5.js";import{I as d,c as p}from"./misc-W4055b-0.js";import{L as f}from"./loading-CDNzW5oO.js";import{N as h}from"./nav-chevrons-Dk4GtZwQ.js";import{u as x}from"./revalidation-ws-BJWJviUX.js";import{M as u}from"./mdx-BGwe7vvs.js";import{u as j}from"./online-DiNLkgTC.js";import{g as b}from"./root-loader-BOzEMapJ.js";import{g}from"./seo-t5J-DRxw.js";import{E as v}from"./launch-editor-D2exGfVu.js";import{P as w}from"./progress-ILaVQtOO.js";import{u as N}from"./index-CdzVFL-Z.js";import"./use-event-source-BuD4_2SF.js";import"./index-DzdDahau.js";import"./index-vDCSPjrM.js";import"./schemas-Uj5SZtvt.js";import"./tooltip-Tlsyx2YO.js";import"./user-BsPobzjB.js";import"./workshop-config-Zfc8zU0x.js";import"./preload-helper-BXl3LOEh.js";import"./progress-bar-DpWhcyhC.js";import"./pe-CIZUOJMr.js";const Z={getSitemapEntries:()=>[{route:"/finished"}]},_=({matches:r})=>{const s=b(r);return s?g({title:`🎉 ${s?.workshopTitle}`,description:`Elaboration for ${s?.workshopTitle}`,ogTitle:`Finished ${s?.workshopTitle}`,ogDescription:"You finished! Time to submit feedback.",instructor:s.instructor,requestInfo:s.requestInfo}):[]},k={h1:()=>null},ee=n(function({loaderData:s}){return x({watchPaths:["./exercises/FINISHED.mdx"]}),e.jsx("div",{className:"flex h-full grow flex-col",children:e.jsxs("main",{className:"grid h-full grow grid-cols-1 grid-rows-2 lg:grid-cols-2 lg:grid-rows-1",children:[e.jsxs("div",{className:"relative col-span-1 row-span-1 flex h-full flex-col lg:border-r",children:[e.jsx("h1",{className:"h-14 border-b pr-5 pl-10 text-sm leading-none font-medium uppercase",children:e.jsx("div",{className:"flex h-14 flex-wrap items-center justify-between gap-x-2 py-2",children:e.jsxs("div",{className:"flex items-center justify-start gap-x-2",children:[e.jsx(l,{to:"/",className:"hover:underline",children:s.workshopTitle}),e.jsx("span",{children:"/"}),e.jsx("span",{children:"Elaboration"})]})})}),e.jsx("article",{className:"shadow-on-scrollbox scrollbar-thin scrollbar-thumb-scrollbar h-full w-full max-w-none flex-1 scroll-pt-6 space-y-6 overflow-y-auto p-2 sm:p-10 sm:pt-8",id:s.articleId,children:s.finishedCode?e.jsx(m,{epicVideoInfosPromise:s.epicVideoInfosPromise,children:e.jsx("div",{className:"prose dark:prose-invert sm:prose-lg",children:e.jsx(u,{code:s.finishedCode,components:k})})}):"No finished instructions yet..."}),e.jsx(a,{elementQuery:`#${s.articleId}`}),e.jsx(w,{type:"workshop-finished",className:"h-14 border-t px-6"}),e.jsxs("div",{className:"@container flex h-16 justify-between border-t border-b-4 lg:border-b-0",children:[e.jsx("div",{}),s.workshopFinished.status==="success"?e.jsx(v,{file:s.workshopFinished.file,relativePath:s.workshopFinished.relativePath}):null,e.jsx(h,{prev:s.prevStepLink,next:{to:"/"}})]})]}),e.jsx(E,{workshopTitle:s.workshopTitle,workshopFormEmbedUrl:s.workshopFormEmbedUrl})]})})});function E({workshopTitle:r,workshopFormEmbedUrl:s}){const t=N(),[o,i]=c.useState(!1);return j()?e.jsxs("div",{className:"relative shrink-0",children:[o?null:e.jsx("div",{className:"absolute inset-0 z-10 flex items-center justify-center",children:e.jsx(f,{children:e.jsxs("span",{children:["Loading ",r," Elaboration form"]})})}),e.jsx("iframe",{onLoad:()=>i(!0),onError:()=>i(!0),title:"Elaboration",src:s,className:p("absolute inset-0 flex h-full w-full transition-opacity duration-300",o?"opacity-100":"opacity-0"),style:{colorScheme:t}})]}):e.jsx("div",{className:"relative shrink-0",children:e.jsx("div",{className:"text-foreground-destructive absolute inset-0 z-10 flex items-center justify-center",children:e.jsx(d,{name:"WifiNoConnection",size:"xl",children:e.jsxs("span",{children:["Unable to load the ",e.jsx("a",{href:s,className:"underline",children:`${r} feedback form`})," when offline"]})})})})}export{ee as default,Z as handle,_ as meta};
2
- //# sourceMappingURL=finished-CqdoWQ9b.js.map
1
+ import{w as n,L as l}from"./chunk-EPOLDU6W-BCLmut3y.js";import{j as e}from"./jsx-runtime-C5WNSv3b.js";import{E as a}from"./index-CEVyDj51.js";import{r as c}from"./index-CqIc3cxq.js";import{E as m}from"./epic-video-DnXXh6qE.js";import{I as d,c as p}from"./misc-W4055b-0.js";import{L as f}from"./loading-CDNzW5oO.js";import{N as h}from"./nav-chevrons-Dk4GtZwQ.js";import{u as x}from"./revalidation-ws-BJWJviUX.js";import{M as u}from"./mdx-Dun3ONG_.js";import{u as j}from"./online-DiNLkgTC.js";import{g as b}from"./root-loader-BOzEMapJ.js";import{g}from"./seo-t5J-DRxw.js";import{E as v}from"./launch-editor-D2exGfVu.js";import{P as w}from"./progress-ILaVQtOO.js";import{u as N}from"./index-CdzVFL-Z.js";import"./use-event-source-BuD4_2SF.js";import"./index-DzdDahau.js";import"./index-vDCSPjrM.js";import"./schemas-Uj5SZtvt.js";import"./tooltip-Tlsyx2YO.js";import"./user-BsPobzjB.js";import"./workshop-config-Zfc8zU0x.js";import"./preload-helper-BXl3LOEh.js";import"./progress-bar-DpWhcyhC.js";import"./pe-CIZUOJMr.js";const Z={getSitemapEntries:()=>[{route:"/finished"}]},_=({matches:r})=>{const s=b(r);return s?g({title:`🎉 ${s?.workshopTitle}`,description:`Elaboration for ${s?.workshopTitle}`,ogTitle:`Finished ${s?.workshopTitle}`,ogDescription:"You finished! Time to submit feedback.",instructor:s.instructor,requestInfo:s.requestInfo}):[]},k={h1:()=>null},ee=n(function({loaderData:s}){return x({watchPaths:["./exercises/FINISHED.mdx"]}),e.jsx("div",{className:"flex h-full grow flex-col",children:e.jsxs("main",{className:"grid h-full grow grid-cols-1 grid-rows-2 lg:grid-cols-2 lg:grid-rows-1",children:[e.jsxs("div",{className:"relative col-span-1 row-span-1 flex h-full flex-col lg:border-r",children:[e.jsx("h1",{className:"h-14 border-b pr-5 pl-10 text-sm leading-none font-medium uppercase",children:e.jsx("div",{className:"flex h-14 flex-wrap items-center justify-between gap-x-2 py-2",children:e.jsxs("div",{className:"flex items-center justify-start gap-x-2",children:[e.jsx(l,{to:"/",className:"hover:underline",children:s.workshopTitle}),e.jsx("span",{children:"/"}),e.jsx("span",{children:"Elaboration"})]})})}),e.jsx("article",{className:"shadow-on-scrollbox scrollbar-thin scrollbar-thumb-scrollbar h-full w-full max-w-none flex-1 scroll-pt-6 space-y-6 overflow-y-auto p-2 sm:p-10 sm:pt-8",id:s.articleId,children:s.finishedCode?e.jsx(m,{epicVideoInfosPromise:s.epicVideoInfosPromise,children:e.jsx("div",{className:"prose dark:prose-invert sm:prose-lg",children:e.jsx(u,{code:s.finishedCode,components:k})})}):"No finished instructions yet..."}),e.jsx(a,{elementQuery:`#${s.articleId}`}),e.jsx(w,{type:"workshop-finished",className:"h-14 border-t px-6"}),e.jsxs("div",{className:"@container flex h-16 justify-between border-t border-b-4 lg:border-b-0",children:[e.jsx("div",{}),s.workshopFinished.status==="success"?e.jsx(v,{file:s.workshopFinished.file,relativePath:s.workshopFinished.relativePath}):null,e.jsx(h,{prev:s.prevStepLink,next:{to:"/"}})]})]}),e.jsx(E,{workshopTitle:s.workshopTitle,workshopFormEmbedUrl:s.workshopFormEmbedUrl})]})})});function E({workshopTitle:r,workshopFormEmbedUrl:s}){const t=N(),[o,i]=c.useState(!1);return j()?e.jsxs("div",{className:"relative shrink-0",children:[o?null:e.jsx("div",{className:"absolute inset-0 z-10 flex items-center justify-center",children:e.jsx(f,{children:e.jsxs("span",{children:["Loading ",r," Elaboration form"]})})}),e.jsx("iframe",{onLoad:()=>i(!0),onError:()=>i(!0),title:"Elaboration",src:s,className:p("absolute inset-0 flex h-full w-full transition-opacity duration-300",o?"opacity-100":"opacity-0"),style:{colorScheme:t}})]}):e.jsx("div",{className:"relative shrink-0",children:e.jsx("div",{className:"text-foreground-destructive absolute inset-0 z-10 flex items-center justify-center",children:e.jsx(d,{name:"WifiNoConnection",size:"xl",children:e.jsxs("span",{children:["Unable to load the ",e.jsx("a",{href:s,className:"underline",children:`${r} feedback form`})," when offline"]})})})})}export{ee as default,Z as handle,_ as meta};
2
+ //# sourceMappingURL=finished-PFz2gTpr.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"finished-CqdoWQ9b.js","sources":["../../../app/routes/_app+/finished.tsx"],"sourcesContent":["import { ElementScrollRestoration } from '@epic-web/restore-scroll'\nimport {\n\tgetExercises,\n\tgetWorkshopFinished,\n} from '@epic-web/workshop-utils/apps.server'\nimport { getWorkshopConfig } from '@epic-web/workshop-utils/config.server'\nimport { getEpicVideoInfos } from '@epic-web/workshop-utils/epic-api.server'\nimport {\n\tcombineServerTimings,\n\tgetServerTimeHeader,\n\tmakeTimings,\n\ttime,\n} from '@epic-web/workshop-utils/timing.server'\nimport { type SEOHandle } from '@nasa-gcn/remix-seo'\nimport slugify from '@sindresorhus/slugify'\nimport * as React from 'react'\nimport { data, type HeadersFunction, Link } from 'react-router'\nimport { EpicVideoInfoProvider } from '#app/components/epic-video.tsx'\nimport { Icon } from '#app/components/icons.tsx'\nimport { Loading } from '#app/components/loading.tsx'\nimport { NavChevrons } from '#app/components/nav-chevrons.tsx'\nimport { useRevalidationWS } from '#app/components/revalidation-ws.tsx'\nimport { Mdx } from '#app/utils/mdx.tsx'\nimport { cn } from '#app/utils/misc.tsx'\nimport { useIsOnline } from '#app/utils/online.ts'\nimport { getRootMatchLoaderData } from '#app/utils/root-loader.ts'\nimport { getSeoMetaTags } from '#app/utils/seo.ts'\nimport { EditFileOnGitHub } from '../launch-editor.tsx'\nimport { ProgressToggle } from '../progress.tsx'\nimport { useTheme } from '../theme/index.tsx'\nimport { type Route } from './+types/finished.tsx'\n\nexport const handle: SEOHandle = {\n\tgetSitemapEntries: () => [{ route: '/finished' }],\n}\n\nexport const meta: Route.MetaFunction = ({ matches }) => {\n\tconst rootData = getRootMatchLoaderData(matches)\n\tif (!rootData) return []\n\n\treturn getSeoMetaTags({\n\t\ttitle: `🎉 ${rootData?.workshopTitle}`,\n\t\tdescription: `Elaboration for ${rootData?.workshopTitle}`,\n\t\togTitle: `Finished ${rootData?.workshopTitle}`,\n\t\togDescription: `You finished! Time to submit feedback.`,\n\t\tinstructor: rootData.instructor,\n\t\trequestInfo: rootData.requestInfo,\n\t})\n}\n\nexport async function loader({ request }: Route.LoaderArgs) {\n\tconst timings = makeTimings('finishedLoader')\n\tconst exercises = await getExercises({ request, timings })\n\tconst compiledFinished = await time(() => getWorkshopFinished({ request }), {\n\t\ttimings,\n\t\ttype: 'compileMdx',\n\t\tdesc: 'compileMdx in finished',\n\t})\n\n\tconst lastExercises = exercises[exercises.length - 1]\n\tconst workshopConfig = getWorkshopConfig()\n\tconst workshopTitle = workshopConfig.title\n\tconst workshopFormTemplate = workshopConfig.forms.workshop\n\tconst workshopFormEmbedUrl = workshopFormTemplate.replace(\n\t\t'{workshopTitle}',\n\t\tencodeURIComponent(workshopTitle),\n\t)\n\treturn data(\n\t\t{\n\t\t\tarticleId: `workshop-${slugify(workshopTitle)}-finished`,\n\t\t\tworkshopTitle,\n\t\t\tworkshopFormEmbedUrl,\n\t\t\tfinishedCode:\n\t\t\t\tcompiledFinished.compiled.status === 'success'\n\t\t\t\t\t? compiledFinished.compiled.code\n\t\t\t\t\t: null,\n\t\t\tepicVideoInfosPromise:\n\t\t\t\tcompiledFinished.compiled.status === 'success'\n\t\t\t\t\t? getEpicVideoInfos(compiledFinished.compiled.epicVideoEmbeds, {\n\t\t\t\t\t\t\trequest,\n\t\t\t\t\t\t})\n\t\t\t\t\t: null,\n\t\t\tworkshopFinished: {\n\t\t\t\tstatus: compiledFinished.compiled.status,\n\t\t\t\tfile: compiledFinished.file,\n\t\t\t\trelativePath: compiledFinished.relativePath,\n\t\t\t},\n\t\t\tprevStepLink: lastExercises\n\t\t\t\t? {\n\t\t\t\t\t\tto: `/${lastExercises.exerciseNumber}/finished`,\n\t\t\t\t\t}\n\t\t\t\t: null,\n\t\t},\n\t\t{\n\t\t\theaders: {\n\t\t\t\t'Server-Timing': getServerTimeHeader(timings),\n\t\t\t},\n\t\t},\n\t)\n}\n\nexport const headers: HeadersFunction = ({ loaderHeaders, parentHeaders }) => {\n\tconst headers = {\n\t\t'Cache-Control': loaderHeaders.get('Cache-Control') ?? '',\n\t\t'Server-Timing': combineServerTimings(loaderHeaders, parentHeaders),\n\t}\n\treturn headers\n}\n\nconst mdxComponents = { h1: () => null }\n\nexport default function ExerciseFinished({\n\tloaderData: data,\n}: Route.ComponentProps) {\n\tuseRevalidationWS({ watchPaths: ['./exercises/FINISHED.mdx'] })\n\treturn (\n\t\t<div className=\"flex h-full grow flex-col\">\n\t\t\t<main className=\"grid h-full grow grid-cols-1 grid-rows-2 lg:grid-cols-2 lg:grid-rows-1\">\n\t\t\t\t<div className=\"relative col-span-1 row-span-1 flex h-full flex-col lg:border-r\">\n\t\t\t\t\t<h1 className=\"h-14 border-b pr-5 pl-10 text-sm leading-none font-medium uppercase\">\n\t\t\t\t\t\t<div className=\"flex h-14 flex-wrap items-center justify-between gap-x-2 py-2\">\n\t\t\t\t\t\t\t<div className=\"flex items-center justify-start gap-x-2\">\n\t\t\t\t\t\t\t\t<Link to=\"/\" className=\"hover:underline\">\n\t\t\t\t\t\t\t\t\t{data.workshopTitle}\n\t\t\t\t\t\t\t\t</Link>\n\t\t\t\t\t\t\t\t<span>/</span>\n\t\t\t\t\t\t\t\t<span>Elaboration</span>\n\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t</div>\n\t\t\t\t\t</h1>\n\t\t\t\t\t<article\n\t\t\t\t\t\tclassName=\"shadow-on-scrollbox scrollbar-thin scrollbar-thumb-scrollbar h-full w-full max-w-none flex-1 scroll-pt-6 space-y-6 overflow-y-auto p-2 sm:p-10 sm:pt-8\"\n\t\t\t\t\t\tid={data.articleId}\n\t\t\t\t\t>\n\t\t\t\t\t\t{data.finishedCode ? (\n\t\t\t\t\t\t\t<EpicVideoInfoProvider\n\t\t\t\t\t\t\t\tepicVideoInfosPromise={data.epicVideoInfosPromise}\n\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t<div className=\"prose dark:prose-invert sm:prose-lg\">\n\t\t\t\t\t\t\t\t\t<Mdx code={data.finishedCode} components={mdxComponents} />\n\t\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t\t</EpicVideoInfoProvider>\n\t\t\t\t\t\t) : (\n\t\t\t\t\t\t\t// TODO: render a random dad joke...\n\t\t\t\t\t\t\t'No finished instructions yet...'\n\t\t\t\t\t\t)}\n\t\t\t\t\t</article>\n\t\t\t\t\t<ElementScrollRestoration elementQuery={`#${data.articleId}`} />\n\t\t\t\t\t<ProgressToggle\n\t\t\t\t\t\ttype=\"workshop-finished\"\n\t\t\t\t\t\tclassName=\"h-14 border-t px-6\"\n\t\t\t\t\t/>\n\t\t\t\t\t<div className=\"@container flex h-16 justify-between border-t border-b-4 lg:border-b-0\">\n\t\t\t\t\t\t<div />\n\t\t\t\t\t\t{data.workshopFinished.status === 'success' ? (\n\t\t\t\t\t\t\t<EditFileOnGitHub\n\t\t\t\t\t\t\t\tfile={data.workshopFinished.file}\n\t\t\t\t\t\t\t\trelativePath={data.workshopFinished.relativePath}\n\t\t\t\t\t\t\t/>\n\t\t\t\t\t\t) : null}\n\t\t\t\t\t\t<NavChevrons prev={data.prevStepLink} next={{ to: '/' }} />\n\t\t\t\t\t</div>\n\t\t\t\t</div>\n\t\t\t\t<Survey\n\t\t\t\t\tworkshopTitle={data.workshopTitle}\n\t\t\t\t\tworkshopFormEmbedUrl={data.workshopFormEmbedUrl}\n\t\t\t\t/>\n\t\t\t</main>\n\t\t</div>\n\t)\n}\n\nfunction Survey({\n\tworkshopTitle,\n\tworkshopFormEmbedUrl,\n}: {\n\tworkshopTitle: string\n\tworkshopFormEmbedUrl: string\n}) {\n\tconst theme = useTheme()\n\tconst [iframeLoaded, setIframeLoaded] = React.useState(false)\n\tconst isOnline = useIsOnline()\n\tif (!isOnline) {\n\t\treturn (\n\t\t\t<div className=\"relative shrink-0\">\n\t\t\t\t<div className=\"text-foreground-destructive absolute inset-0 z-10 flex items-center justify-center\">\n\t\t\t\t\t<Icon name=\"WifiNoConnection\" size=\"xl\">\n\t\t\t\t\t\t<span>\n\t\t\t\t\t\t\t{'Unable to load the '}\n\t\t\t\t\t\t\t<a href={workshopFormEmbedUrl} className=\"underline\">\n\t\t\t\t\t\t\t\t{`${workshopTitle} feedback form`}\n\t\t\t\t\t\t\t</a>\n\t\t\t\t\t\t\t{' when offline'}\n\t\t\t\t\t\t</span>\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=\"relative shrink-0\">\n\t\t\t{!iframeLoaded ? (\n\t\t\t\t<div className=\"absolute inset-0 z-10 flex items-center justify-center\">\n\t\t\t\t\t<Loading>\n\t\t\t\t\t\t<span>Loading {workshopTitle} Elaboration form</span>\n\t\t\t\t\t</Loading>\n\t\t\t\t</div>\n\t\t\t) : null}\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\ttitle=\"Elaboration\"\n\t\t\t\tsrc={workshopFormEmbedUrl}\n\t\t\t\tclassName={cn(\n\t\t\t\t\t'absolute inset-0 flex h-full w-full transition-opacity duration-300',\n\t\t\t\t\tiframeLoaded ? 'opacity-100' : 'opacity-0',\n\t\t\t\t)}\n\t\t\t\tstyle={{ colorScheme: theme }}\n\t\t\t/>\n\t\t</div>\n\t)\n}\n"],"names":["handle","getSitemapEntries","route","meta","matches","rootData","getRootMatchLoaderData","getSeoMetaTags","title","workshopTitle","description","ogTitle","ogDescription","instructor","requestInfo","mdxComponents","h1","finished","_UNSAFE_withComponentProps","loaderData","data","useRevalidationWS","watchPaths","className","children","jsxs","jsx","Link","to","id","articleId","finishedCode","EpicVideoInfoProvider","epicVideoInfosPromise","Mdx","code","components","ElementScrollRestoration","elementQuery","ProgressToggle","type","workshopFinished","status","EditFileOnGitHub","file","relativePath","NavChevrons","prev","prevStepLink","next","Survey","workshopFormEmbedUrl","theme","useTheme","iframeLoaded","setIframeLoaded","React","useIsOnline","Loading","onLoad","onError","src","cn","style","colorScheme","Icon","name","size","href"],"mappings":"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"}
1
+ {"version":3,"file":"finished-PFz2gTpr.js","sources":["../../../app/routes/_app+/finished.tsx"],"sourcesContent":["import { ElementScrollRestoration } from '@epic-web/restore-scroll'\nimport {\n\tgetExercises,\n\tgetWorkshopFinished,\n} from '@epic-web/workshop-utils/apps.server'\nimport { getWorkshopConfig } from '@epic-web/workshop-utils/config.server'\nimport { getEpicVideoInfos } from '@epic-web/workshop-utils/epic-api.server'\nimport {\n\tcombineServerTimings,\n\tgetServerTimeHeader,\n\tmakeTimings,\n\ttime,\n} from '@epic-web/workshop-utils/timing.server'\nimport { type SEOHandle } from '@nasa-gcn/remix-seo'\nimport slugify from '@sindresorhus/slugify'\nimport * as React from 'react'\nimport { data, type HeadersFunction, Link } from 'react-router'\nimport { EpicVideoInfoProvider } from '#app/components/epic-video.tsx'\nimport { Icon } from '#app/components/icons.tsx'\nimport { Loading } from '#app/components/loading.tsx'\nimport { NavChevrons } from '#app/components/nav-chevrons.tsx'\nimport { useRevalidationWS } from '#app/components/revalidation-ws.tsx'\nimport { Mdx } from '#app/utils/mdx.tsx'\nimport { cn } from '#app/utils/misc.tsx'\nimport { useIsOnline } from '#app/utils/online.ts'\nimport { getRootMatchLoaderData } from '#app/utils/root-loader.ts'\nimport { getSeoMetaTags } from '#app/utils/seo.ts'\nimport { EditFileOnGitHub } from '../launch-editor.tsx'\nimport { ProgressToggle } from '../progress.tsx'\nimport { useTheme } from '../theme/index.tsx'\nimport { type Route } from './+types/finished.tsx'\n\nexport const handle: SEOHandle = {\n\tgetSitemapEntries: () => [{ route: '/finished' }],\n}\n\nexport const meta: Route.MetaFunction = ({ matches }) => {\n\tconst rootData = getRootMatchLoaderData(matches)\n\tif (!rootData) return []\n\n\treturn getSeoMetaTags({\n\t\ttitle: `🎉 ${rootData?.workshopTitle}`,\n\t\tdescription: `Elaboration for ${rootData?.workshopTitle}`,\n\t\togTitle: `Finished ${rootData?.workshopTitle}`,\n\t\togDescription: `You finished! Time to submit feedback.`,\n\t\tinstructor: rootData.instructor,\n\t\trequestInfo: rootData.requestInfo,\n\t})\n}\n\nexport async function loader({ request }: Route.LoaderArgs) {\n\tconst timings = makeTimings('finishedLoader')\n\tconst exercises = await getExercises({ request, timings })\n\tconst compiledFinished = await time(() => getWorkshopFinished({ request }), {\n\t\ttimings,\n\t\ttype: 'compileMdx',\n\t\tdesc: 'compileMdx in finished',\n\t})\n\n\tconst lastExercises = exercises[exercises.length - 1]\n\tconst workshopConfig = getWorkshopConfig()\n\tconst workshopTitle = workshopConfig.title\n\tconst workshopFormTemplate = workshopConfig.forms.workshop\n\tconst workshopFormEmbedUrl = workshopFormTemplate.replace(\n\t\t'{workshopTitle}',\n\t\tencodeURIComponent(workshopTitle),\n\t)\n\treturn data(\n\t\t{\n\t\t\tarticleId: `workshop-${slugify(workshopTitle)}-finished`,\n\t\t\tworkshopTitle,\n\t\t\tworkshopFormEmbedUrl,\n\t\t\tfinishedCode:\n\t\t\t\tcompiledFinished.compiled.status === 'success'\n\t\t\t\t\t? compiledFinished.compiled.code\n\t\t\t\t\t: null,\n\t\t\tepicVideoInfosPromise:\n\t\t\t\tcompiledFinished.compiled.status === 'success'\n\t\t\t\t\t? getEpicVideoInfos(compiledFinished.compiled.epicVideoEmbeds, {\n\t\t\t\t\t\t\trequest,\n\t\t\t\t\t\t})\n\t\t\t\t\t: null,\n\t\t\tworkshopFinished: {\n\t\t\t\tstatus: compiledFinished.compiled.status,\n\t\t\t\tfile: compiledFinished.file,\n\t\t\t\trelativePath: compiledFinished.relativePath,\n\t\t\t},\n\t\t\tprevStepLink: lastExercises\n\t\t\t\t? {\n\t\t\t\t\t\tto: `/${lastExercises.exerciseNumber}/finished`,\n\t\t\t\t\t}\n\t\t\t\t: null,\n\t\t},\n\t\t{\n\t\t\theaders: {\n\t\t\t\t'Server-Timing': getServerTimeHeader(timings),\n\t\t\t},\n\t\t},\n\t)\n}\n\nexport const headers: HeadersFunction = ({ loaderHeaders, parentHeaders }) => {\n\tconst headers = {\n\t\t'Cache-Control': loaderHeaders.get('Cache-Control') ?? '',\n\t\t'Server-Timing': combineServerTimings(loaderHeaders, parentHeaders),\n\t}\n\treturn headers\n}\n\nconst mdxComponents = { h1: () => null }\n\nexport default function ExerciseFinished({\n\tloaderData: data,\n}: Route.ComponentProps) {\n\tuseRevalidationWS({ watchPaths: ['./exercises/FINISHED.mdx'] })\n\treturn (\n\t\t<div className=\"flex h-full grow flex-col\">\n\t\t\t<main className=\"grid h-full grow grid-cols-1 grid-rows-2 lg:grid-cols-2 lg:grid-rows-1\">\n\t\t\t\t<div className=\"relative col-span-1 row-span-1 flex h-full flex-col lg:border-r\">\n\t\t\t\t\t<h1 className=\"h-14 border-b pr-5 pl-10 text-sm leading-none font-medium uppercase\">\n\t\t\t\t\t\t<div className=\"flex h-14 flex-wrap items-center justify-between gap-x-2 py-2\">\n\t\t\t\t\t\t\t<div className=\"flex items-center justify-start gap-x-2\">\n\t\t\t\t\t\t\t\t<Link to=\"/\" className=\"hover:underline\">\n\t\t\t\t\t\t\t\t\t{data.workshopTitle}\n\t\t\t\t\t\t\t\t</Link>\n\t\t\t\t\t\t\t\t<span>/</span>\n\t\t\t\t\t\t\t\t<span>Elaboration</span>\n\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t</div>\n\t\t\t\t\t</h1>\n\t\t\t\t\t<article\n\t\t\t\t\t\tclassName=\"shadow-on-scrollbox scrollbar-thin scrollbar-thumb-scrollbar h-full w-full max-w-none flex-1 scroll-pt-6 space-y-6 overflow-y-auto p-2 sm:p-10 sm:pt-8\"\n\t\t\t\t\t\tid={data.articleId}\n\t\t\t\t\t>\n\t\t\t\t\t\t{data.finishedCode ? (\n\t\t\t\t\t\t\t<EpicVideoInfoProvider\n\t\t\t\t\t\t\t\tepicVideoInfosPromise={data.epicVideoInfosPromise}\n\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t<div className=\"prose dark:prose-invert sm:prose-lg\">\n\t\t\t\t\t\t\t\t\t<Mdx code={data.finishedCode} components={mdxComponents} />\n\t\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t\t</EpicVideoInfoProvider>\n\t\t\t\t\t\t) : (\n\t\t\t\t\t\t\t// TODO: render a random dad joke...\n\t\t\t\t\t\t\t'No finished instructions yet...'\n\t\t\t\t\t\t)}\n\t\t\t\t\t</article>\n\t\t\t\t\t<ElementScrollRestoration elementQuery={`#${data.articleId}`} />\n\t\t\t\t\t<ProgressToggle\n\t\t\t\t\t\ttype=\"workshop-finished\"\n\t\t\t\t\t\tclassName=\"h-14 border-t px-6\"\n\t\t\t\t\t/>\n\t\t\t\t\t<div className=\"@container flex h-16 justify-between border-t border-b-4 lg:border-b-0\">\n\t\t\t\t\t\t<div />\n\t\t\t\t\t\t{data.workshopFinished.status === 'success' ? (\n\t\t\t\t\t\t\t<EditFileOnGitHub\n\t\t\t\t\t\t\t\tfile={data.workshopFinished.file}\n\t\t\t\t\t\t\t\trelativePath={data.workshopFinished.relativePath}\n\t\t\t\t\t\t\t/>\n\t\t\t\t\t\t) : null}\n\t\t\t\t\t\t<NavChevrons prev={data.prevStepLink} next={{ to: '/' }} />\n\t\t\t\t\t</div>\n\t\t\t\t</div>\n\t\t\t\t<Survey\n\t\t\t\t\tworkshopTitle={data.workshopTitle}\n\t\t\t\t\tworkshopFormEmbedUrl={data.workshopFormEmbedUrl}\n\t\t\t\t/>\n\t\t\t</main>\n\t\t</div>\n\t)\n}\n\nfunction Survey({\n\tworkshopTitle,\n\tworkshopFormEmbedUrl,\n}: {\n\tworkshopTitle: string\n\tworkshopFormEmbedUrl: string\n}) {\n\tconst theme = useTheme()\n\tconst [iframeLoaded, setIframeLoaded] = React.useState(false)\n\tconst isOnline = useIsOnline()\n\tif (!isOnline) {\n\t\treturn (\n\t\t\t<div className=\"relative shrink-0\">\n\t\t\t\t<div className=\"text-foreground-destructive absolute inset-0 z-10 flex items-center justify-center\">\n\t\t\t\t\t<Icon name=\"WifiNoConnection\" size=\"xl\">\n\t\t\t\t\t\t<span>\n\t\t\t\t\t\t\t{'Unable to load the '}\n\t\t\t\t\t\t\t<a href={workshopFormEmbedUrl} className=\"underline\">\n\t\t\t\t\t\t\t\t{`${workshopTitle} feedback form`}\n\t\t\t\t\t\t\t</a>\n\t\t\t\t\t\t\t{' when offline'}\n\t\t\t\t\t\t</span>\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=\"relative shrink-0\">\n\t\t\t{!iframeLoaded ? (\n\t\t\t\t<div className=\"absolute inset-0 z-10 flex items-center justify-center\">\n\t\t\t\t\t<Loading>\n\t\t\t\t\t\t<span>Loading {workshopTitle} Elaboration form</span>\n\t\t\t\t\t</Loading>\n\t\t\t\t</div>\n\t\t\t) : null}\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\ttitle=\"Elaboration\"\n\t\t\t\tsrc={workshopFormEmbedUrl}\n\t\t\t\tclassName={cn(\n\t\t\t\t\t'absolute inset-0 flex h-full w-full transition-opacity duration-300',\n\t\t\t\t\tiframeLoaded ? 'opacity-100' : 'opacity-0',\n\t\t\t\t)}\n\t\t\t\tstyle={{ colorScheme: theme }}\n\t\t\t/>\n\t\t</div>\n\t)\n}\n"],"names":["handle","getSitemapEntries","route","meta","matches","rootData","getRootMatchLoaderData","getSeoMetaTags","title","workshopTitle","description","ogTitle","ogDescription","instructor","requestInfo","mdxComponents","h1","finished","_UNSAFE_withComponentProps","loaderData","data","useRevalidationWS","watchPaths","className","children","jsxs","jsx","Link","to","id","articleId","finishedCode","EpicVideoInfoProvider","epicVideoInfosPromise","Mdx","code","components","ElementScrollRestoration","elementQuery","ProgressToggle","type","workshopFinished","status","EditFileOnGitHub","file","relativePath","NavChevrons","prev","prevStepLink","next","Survey","workshopFormEmbedUrl","theme","useTheme","iframeLoaded","setIframeLoaded","React","useIsOnline","Loading","onLoad","onError","src","cn","style","colorScheme","Icon","name","size","href"],"mappings":"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"}
@@ -1,2 +1,2 @@
1
- import{w as s,a,b as i,L as l}from"./chunk-EPOLDU6W-BCLmut3y.js";import{j as e}from"./jsx-runtime-C5WNSv3b.js";import{E as n}from"./index-CEVyDj51.js";import{E as m}from"./epic-video-Ca_s42j5.js";import{G as d}from"./error-boundary-DVp6wKiz.js";import{u as c}from"./revalidation-ws-BJWJviUX.js";import{E as x}from"./launch-editor-D2exGfVu.js";import{M as p}from"./mdx-BGwe7vvs.js";import{c as f}from"./misc-W4055b-0.js";import{g as u}from"./root-loader-BOzEMapJ.js";import{g as h}from"./seo-t5J-DRxw.js";import"./index-CqIc3cxq.js";import"./use-event-source-BuD4_2SF.js";import"./index-DzdDahau.js";import"./index-vDCSPjrM.js";import"./index-CdzVFL-Z.js";import"./tooltip-Tlsyx2YO.js";import"./pe-CIZUOJMr.js";import"./schemas-Uj5SZtvt.js";import"./online-DiNLkgTC.js";import"./loading-CDNzW5oO.js";import"./user-BsPobzjB.js";import"./workshop-config-Zfc8zU0x.js";import"./preload-helper-BXl3LOEh.js";import"./progress-bar-DpWhcyhC.js";const Q=o=>{const r=o.data,t=u(o.matches);return!r||!t?[{title:"🦉 | Error"}]:h({title:`📚 | ${r.title} | ${t.workshopTitle}`,description:`Extras for ${t.workshopTitle}`,ogTitle:r.title,ogDescription:`Extras for ${t.workshopTitle}`,instructor:t.instructor,requestInfo:t.requestInfo})};function j({extra:o}){return e.jsx("li",{children:e.jsxs(l,{className:f("relative flex items-center gap-4 px-4 py-3 text-lg font-semibold transition","hover:bg-muted/60 focus:bg-muted/60"),prefetch:"intent",to:o.dirName,children:[e.jsx("span",{className:"text-muted-foreground text-xs font-normal tabular-nums",children:"•"}),e.jsx("span",{className:"truncate",children:o.title})]})})}const v={h1:()=>null},W=s(function(){const r=i();return c({watchPaths:["./extra","./example","./examples"]}),e.jsxs("main",{className:"relative flex h-full w-full max-w-5xl flex-col justify-between border-r md:w-3/4 xl:w-2/3",children:[e.jsxs("article",{id:r.articleId,className:"shadow-on-scrollbox scrollbar-thin scrollbar-thumb-scrollbar flex w-full flex-1 flex-col gap-12 overflow-y-scroll px-3 py-4 pt-6 md:px-10 md:py-12 md:pt-16",children:[e.jsx("div",{children:e.jsx("h1",{className:"text-[clamp(3rem,6vw,7.5rem)] leading-none font-extrabold",children:r.title})}),e.jsx("div",{children:r.extrasReadme.compiled.status==="success"&&r.extrasReadme.compiled.code?e.jsx(m,{epicVideoInfosPromise:r.epicVideoInfosPromise,children:e.jsx("div",{className:"prose dark:prose-invert sm:prose-lg",children:e.jsx(p,{code:r.extrasReadme.compiled.code,components:v})})}):r.extrasReadme.compiled.status==="error"?e.jsxs("div",{className:"text-foreground-destructive",children:["There was an error:",e.jsx("pre",{children:r.extrasReadme.compiled.error})]}):"No extras overview yet..."}),e.jsxs("div",{className:"pt-6",children:[e.jsx("h2",{className:"pb-4 font-mono text-xs font-semibold uppercase",children:"Extras"}),r.extras.length?e.jsx("ul",{className:"divide-border dark:divide-border/50 flex flex-col divide-y",children:r.extras.map(t=>e.jsx(j,{extra:t},t.dirName))}):e.jsx("p",{className:"text-muted-foreground",children:"No extras yet. Add one to get started."})]})]}),e.jsx(n,{elementQuery:`#${r.articleId}`}),e.jsx("div",{className:"@container flex h-16 justify-center border-t",children:e.jsx(x,{file:r.extrasReadme.file,relativePath:r.extrasReadme.relativePath})})]})}),z=a(function(){return e.jsx(d,{})});export{z as ErrorBoundary,W as default,Q as meta};
2
- //# sourceMappingURL=index-o922xZRF.js.map
1
+ import{w as s,a,b as i,L as l}from"./chunk-EPOLDU6W-BCLmut3y.js";import{j as e}from"./jsx-runtime-C5WNSv3b.js";import{E as n}from"./index-CEVyDj51.js";import{E as m}from"./epic-video-DnXXh6qE.js";import{G as d}from"./error-boundary-DVp6wKiz.js";import{u as c}from"./revalidation-ws-BJWJviUX.js";import{E as x}from"./launch-editor-D2exGfVu.js";import{M as p}from"./mdx-Dun3ONG_.js";import{c as f}from"./misc-W4055b-0.js";import{g as u}from"./root-loader-BOzEMapJ.js";import{g as h}from"./seo-t5J-DRxw.js";import"./index-CqIc3cxq.js";import"./use-event-source-BuD4_2SF.js";import"./index-DzdDahau.js";import"./index-vDCSPjrM.js";import"./index-CdzVFL-Z.js";import"./tooltip-Tlsyx2YO.js";import"./pe-CIZUOJMr.js";import"./schemas-Uj5SZtvt.js";import"./online-DiNLkgTC.js";import"./loading-CDNzW5oO.js";import"./user-BsPobzjB.js";import"./workshop-config-Zfc8zU0x.js";import"./preload-helper-BXl3LOEh.js";import"./progress-bar-DpWhcyhC.js";const Q=o=>{const r=o.data,t=u(o.matches);return!r||!t?[{title:"🦉 | Error"}]:h({title:`📚 | ${r.title} | ${t.workshopTitle}`,description:`Extras for ${t.workshopTitle}`,ogTitle:r.title,ogDescription:`Extras for ${t.workshopTitle}`,instructor:t.instructor,requestInfo:t.requestInfo})};function j({extra:o}){return e.jsx("li",{children:e.jsxs(l,{className:f("relative flex items-center gap-4 px-4 py-3 text-lg font-semibold transition","hover:bg-muted/60 focus:bg-muted/60"),prefetch:"intent",to:o.dirName,children:[e.jsx("span",{className:"text-muted-foreground text-xs font-normal tabular-nums",children:"•"}),e.jsx("span",{className:"truncate",children:o.title})]})})}const v={h1:()=>null},W=s(function(){const r=i();return c({watchPaths:["./extra","./example","./examples"]}),e.jsxs("main",{className:"relative flex h-full w-full max-w-5xl flex-col justify-between border-r md:w-3/4 xl:w-2/3",children:[e.jsxs("article",{id:r.articleId,className:"shadow-on-scrollbox scrollbar-thin scrollbar-thumb-scrollbar flex w-full flex-1 flex-col gap-12 overflow-y-scroll px-3 py-4 pt-6 md:px-10 md:py-12 md:pt-16",children:[e.jsx("div",{children:e.jsx("h1",{className:"text-[clamp(3rem,6vw,7.5rem)] leading-none font-extrabold",children:r.title})}),e.jsx("div",{children:r.extrasReadme.compiled.status==="success"&&r.extrasReadme.compiled.code?e.jsx(m,{epicVideoInfosPromise:r.epicVideoInfosPromise,children:e.jsx("div",{className:"prose dark:prose-invert sm:prose-lg",children:e.jsx(p,{code:r.extrasReadme.compiled.code,components:v})})}):r.extrasReadme.compiled.status==="error"?e.jsxs("div",{className:"text-foreground-destructive",children:["There was an error:",e.jsx("pre",{children:r.extrasReadme.compiled.error})]}):"No extras overview yet..."}),e.jsxs("div",{className:"pt-6",children:[e.jsx("h2",{className:"pb-4 font-mono text-xs font-semibold uppercase",children:"Extras"}),r.extras.length?e.jsx("ul",{className:"divide-border dark:divide-border/50 flex flex-col divide-y",children:r.extras.map(t=>e.jsx(j,{extra:t},t.dirName))}):e.jsx("p",{className:"text-muted-foreground",children:"No extras yet. Add one to get started."})]})]}),e.jsx(n,{elementQuery:`#${r.articleId}`}),e.jsx("div",{className:"@container flex h-16 justify-center border-t",children:e.jsx(x,{file:r.extrasReadme.file,relativePath:r.extrasReadme.relativePath})})]})}),z=a(function(){return e.jsx(d,{})});export{z as ErrorBoundary,W as default,Q as meta};
2
+ //# sourceMappingURL=index-CATk0s1i.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"index-o922xZRF.js","sources":["../../../app/routes/_app+/extra+/index.tsx"],"sourcesContent":["import { ElementScrollRestoration } from '@epic-web/restore-scroll'\nimport {\n\tgetApps,\n\tgetExtrasInstructions,\n\tisExtraApp,\n} from '@epic-web/workshop-utils/apps.server'\nimport { getWorkshopConfig } from '@epic-web/workshop-utils/config.server'\nimport { getEpicVideoInfos } from '@epic-web/workshop-utils/epic-api.server'\nimport {\n\tcombineServerTimings,\n\tgetServerTimeHeader,\n\tmakeTimings,\n\ttime,\n} from '@epic-web/workshop-utils/timing.server'\nimport slugify from '@sindresorhus/slugify'\nimport {\n\tdata,\n\ttype HeadersFunction,\n\tLink,\n\ttype LoaderFunctionArgs,\n\ttype MetaFunction,\n\tuseLoaderData,\n} from 'react-router'\nimport { EpicVideoInfoProvider } from '#app/components/epic-video.tsx'\nimport { GeneralErrorBoundary } from '#app/components/error-boundary.tsx'\nimport { useRevalidationWS } from '#app/components/revalidation-ws.tsx'\nimport { EditFileOnGitHub } from '#app/routes/launch-editor.tsx'\nimport { Mdx } from '#app/utils/mdx.tsx'\nimport { cn } from '#app/utils/misc.tsx'\nimport { getRootMatchLoaderData } from '#app/utils/root-loader.ts'\nimport { getSeoMetaTags } from '#app/utils/seo.ts'\n\nexport const meta: MetaFunction<typeof loader> = (args) => {\n\tconst loaderData = args.data\n\tconst rootData = getRootMatchLoaderData(args.matches)\n\tif (!loaderData || !rootData) return [{ title: '🦉 | Error' }]\n\n\treturn getSeoMetaTags({\n\t\ttitle: `📚 | ${loaderData.title} | ${rootData.workshopTitle}`,\n\t\tdescription: `Extras for ${rootData.workshopTitle}`,\n\t\togTitle: loaderData.title,\n\t\togDescription: `Extras for ${rootData.workshopTitle}`,\n\t\tinstructor: rootData.instructor,\n\t\trequestInfo: rootData.requestInfo,\n\t})\n}\n\nexport async function loader({ request }: LoaderFunctionArgs) {\n\tconst timings = makeTimings('extrasIndexLoader')\n\tconst { title: workshopTitle } = getWorkshopConfig()\n\tconst [extrasReadme, apps] = await Promise.all([\n\t\ttime(() => getExtrasInstructions({ request }), {\n\t\t\ttimings,\n\t\t\ttype: 'compileMdx',\n\t\t\tdesc: 'compileMdx in extras index',\n\t\t}),\n\t\ttime(() => getApps({ request, timings }), {\n\t\t\ttimings,\n\t\t\ttype: 'getApps',\n\t\t\tdesc: 'getApps in extras index',\n\t\t}),\n\t])\n\n\tconst extras = apps\n\t\t.filter(isExtraApp)\n\t\t.sort((a, b) =>\n\t\t\ta.title.localeCompare(b.title, undefined, {\n\t\t\t\tnumeric: true,\n\t\t\t\tsensitivity: 'base',\n\t\t\t}),\n\t\t)\n\t\t.map((extra) => ({\n\t\t\tdirName: extra.dirName,\n\t\t\ttitle: extra.title,\n\t\t}))\n\n\tconst title =\n\t\textrasReadme.compiled.status === 'success'\n\t\t\t? (extrasReadme.compiled.title ?? 'Extras')\n\t\t\t: 'Extras'\n\n\treturn data(\n\t\t{\n\t\t\tarticleId: `workshop-${slugify(workshopTitle)}-extras`,\n\t\t\ttitle,\n\t\t\textras,\n\t\t\textrasReadme,\n\t\t\tepicVideoInfosPromise:\n\t\t\t\textrasReadme.compiled.status === 'success'\n\t\t\t\t\t? getEpicVideoInfos(extrasReadme.compiled.epicVideoEmbeds, {\n\t\t\t\t\t\t\trequest,\n\t\t\t\t\t\t})\n\t\t\t\t\t: null,\n\t\t},\n\t\t{\n\t\t\theaders: {\n\t\t\t\t'Server-Timing': getServerTimeHeader(timings),\n\t\t\t},\n\t\t},\n\t)\n}\n\nexport const headers: HeadersFunction = ({ loaderHeaders, parentHeaders }) => {\n\tconst headers = {\n\t\t'Cache-Control': loaderHeaders.get('Cache-Control') ?? '',\n\t\t'Server-Timing': combineServerTimings(loaderHeaders, parentHeaders),\n\t}\n\treturn headers\n}\n\nfunction ExtraListItem({\n\textra,\n}: {\n\textra: { dirName: string; title: string }\n}) {\n\treturn (\n\t\t<li>\n\t\t\t<Link\n\t\t\t\tclassName={cn(\n\t\t\t\t\t'relative flex items-center gap-4 px-4 py-3 text-lg font-semibold transition',\n\t\t\t\t\t'hover:bg-muted/60 focus:bg-muted/60',\n\t\t\t\t)}\n\t\t\t\tprefetch=\"intent\"\n\t\t\t\tto={extra.dirName}\n\t\t\t>\n\t\t\t\t<span className=\"text-muted-foreground text-xs font-normal tabular-nums\">\n\t\t\t\t\t•\n\t\t\t\t</span>\n\t\t\t\t<span className=\"truncate\">{extra.title}</span>\n\t\t\t</Link>\n\t\t</li>\n\t)\n}\n\nconst mdxComponents = { h1: () => null }\n\nexport default function ExtrasIndex() {\n\tconst data = useLoaderData<typeof loader>()\n\tuseRevalidationWS({ watchPaths: ['./extra', './example', './examples'] })\n\n\treturn (\n\t\t<main className=\"relative flex h-full w-full max-w-5xl flex-col justify-between border-r md:w-3/4 xl:w-2/3\">\n\t\t\t<article\n\t\t\t\tid={data.articleId}\n\t\t\t\tclassName=\"shadow-on-scrollbox scrollbar-thin scrollbar-thumb-scrollbar flex w-full flex-1 flex-col gap-12 overflow-y-scroll px-3 py-4 pt-6 md:px-10 md:py-12 md:pt-16\"\n\t\t\t>\n\t\t\t\t<div>\n\t\t\t\t\t<h1 className=\"text-[clamp(3rem,6vw,7.5rem)] leading-none font-extrabold\">\n\t\t\t\t\t\t{data.title}\n\t\t\t\t\t</h1>\n\t\t\t\t</div>\n\t\t\t\t<div>\n\t\t\t\t\t{data.extrasReadme.compiled.status === 'success' &&\n\t\t\t\t\tdata.extrasReadme.compiled.code ? (\n\t\t\t\t\t\t<EpicVideoInfoProvider\n\t\t\t\t\t\t\tepicVideoInfosPromise={data.epicVideoInfosPromise}\n\t\t\t\t\t\t>\n\t\t\t\t\t\t\t<div className=\"prose dark:prose-invert sm:prose-lg\">\n\t\t\t\t\t\t\t\t<Mdx\n\t\t\t\t\t\t\t\t\tcode={data.extrasReadme.compiled.code}\n\t\t\t\t\t\t\t\t\tcomponents={mdxComponents}\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</EpicVideoInfoProvider>\n\t\t\t\t\t) : data.extrasReadme.compiled.status === 'error' ? (\n\t\t\t\t\t\t<div className=\"text-foreground-destructive\">\n\t\t\t\t\t\t\tThere was an error:\n\t\t\t\t\t\t\t<pre>{data.extrasReadme.compiled.error}</pre>\n\t\t\t\t\t\t</div>\n\t\t\t\t\t) : (\n\t\t\t\t\t\t'No extras overview yet...'\n\t\t\t\t\t)}\n\t\t\t\t</div>\n\t\t\t\t<div className=\"pt-6\">\n\t\t\t\t\t<h2 className=\"pb-4 font-mono text-xs font-semibold uppercase\">\n\t\t\t\t\t\tExtras\n\t\t\t\t\t</h2>\n\t\t\t\t\t{data.extras.length ? (\n\t\t\t\t\t\t<ul className=\"divide-border dark:divide-border/50 flex flex-col divide-y\">\n\t\t\t\t\t\t\t{data.extras.map((extra) => (\n\t\t\t\t\t\t\t\t<ExtraListItem key={extra.dirName} extra={extra} />\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\t\t<p className=\"text-muted-foreground\">\n\t\t\t\t\t\t\tNo extras yet. Add one to get started.\n\t\t\t\t\t\t</p>\n\t\t\t\t\t)}\n\t\t\t\t</div>\n\t\t\t</article>\n\t\t\t<ElementScrollRestoration elementQuery={`#${data.articleId}`} />\n\t\t\t<div className=\"@container flex h-16 justify-center border-t\">\n\t\t\t\t<EditFileOnGitHub\n\t\t\t\t\tfile={data.extrasReadme.file}\n\t\t\t\t\trelativePath={data.extrasReadme.relativePath}\n\t\t\t\t/>\n\t\t\t</div>\n\t\t</main>\n\t)\n}\n\nexport function ErrorBoundary() {\n\treturn <GeneralErrorBoundary />\n}\n"],"names":["meta","args","loaderData","data","rootData","getRootMatchLoaderData","matches","title","getSeoMetaTags","workshopTitle","description","ogTitle","ogDescription","instructor","requestInfo","ExtraListItem","extra","children","jsxs","Link","className","cn","prefetch","to","dirName","jsx","mdxComponents","h1","index","_UNSAFE_withComponentProps","useLoaderData","useRevalidationWS","watchPaths","id","articleId","extrasReadme","compiled","status","code","EpicVideoInfoProvider","epicVideoInfosPromise","Mdx","components","error","extras","length","map","ElementScrollRestoration","elementQuery","EditFileOnGitHub","file","relativePath","ErrorBoundary","_UNSAFE_withErrorBoundaryProps","GeneralErrorBoundary"],"mappings":"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"}
1
+ {"version":3,"file":"index-CATk0s1i.js","sources":["../../../app/routes/_app+/extra+/index.tsx"],"sourcesContent":["import { ElementScrollRestoration } from '@epic-web/restore-scroll'\nimport {\n\tgetApps,\n\tgetExtrasInstructions,\n\tisExtraApp,\n} from '@epic-web/workshop-utils/apps.server'\nimport { getWorkshopConfig } from '@epic-web/workshop-utils/config.server'\nimport { getEpicVideoInfos } from '@epic-web/workshop-utils/epic-api.server'\nimport {\n\tcombineServerTimings,\n\tgetServerTimeHeader,\n\tmakeTimings,\n\ttime,\n} from '@epic-web/workshop-utils/timing.server'\nimport slugify from '@sindresorhus/slugify'\nimport {\n\tdata,\n\ttype HeadersFunction,\n\tLink,\n\ttype LoaderFunctionArgs,\n\ttype MetaFunction,\n\tuseLoaderData,\n} from 'react-router'\nimport { EpicVideoInfoProvider } from '#app/components/epic-video.tsx'\nimport { GeneralErrorBoundary } from '#app/components/error-boundary.tsx'\nimport { useRevalidationWS } from '#app/components/revalidation-ws.tsx'\nimport { EditFileOnGitHub } from '#app/routes/launch-editor.tsx'\nimport { Mdx } from '#app/utils/mdx.tsx'\nimport { cn } from '#app/utils/misc.tsx'\nimport { getRootMatchLoaderData } from '#app/utils/root-loader.ts'\nimport { getSeoMetaTags } from '#app/utils/seo.ts'\n\nexport const meta: MetaFunction<typeof loader> = (args) => {\n\tconst loaderData = args.data\n\tconst rootData = getRootMatchLoaderData(args.matches)\n\tif (!loaderData || !rootData) return [{ title: '🦉 | Error' }]\n\n\treturn getSeoMetaTags({\n\t\ttitle: `📚 | ${loaderData.title} | ${rootData.workshopTitle}`,\n\t\tdescription: `Extras for ${rootData.workshopTitle}`,\n\t\togTitle: loaderData.title,\n\t\togDescription: `Extras for ${rootData.workshopTitle}`,\n\t\tinstructor: rootData.instructor,\n\t\trequestInfo: rootData.requestInfo,\n\t})\n}\n\nexport async function loader({ request }: LoaderFunctionArgs) {\n\tconst timings = makeTimings('extrasIndexLoader')\n\tconst { title: workshopTitle } = getWorkshopConfig()\n\tconst [extrasReadme, apps] = await Promise.all([\n\t\ttime(() => getExtrasInstructions({ request }), {\n\t\t\ttimings,\n\t\t\ttype: 'compileMdx',\n\t\t\tdesc: 'compileMdx in extras index',\n\t\t}),\n\t\ttime(() => getApps({ request, timings }), {\n\t\t\ttimings,\n\t\t\ttype: 'getApps',\n\t\t\tdesc: 'getApps in extras index',\n\t\t}),\n\t])\n\n\tconst extras = apps\n\t\t.filter(isExtraApp)\n\t\t.sort((a, b) =>\n\t\t\ta.title.localeCompare(b.title, undefined, {\n\t\t\t\tnumeric: true,\n\t\t\t\tsensitivity: 'base',\n\t\t\t}),\n\t\t)\n\t\t.map((extra) => ({\n\t\t\tdirName: extra.dirName,\n\t\t\ttitle: extra.title,\n\t\t}))\n\n\tconst title =\n\t\textrasReadme.compiled.status === 'success'\n\t\t\t? (extrasReadme.compiled.title ?? 'Extras')\n\t\t\t: 'Extras'\n\n\treturn data(\n\t\t{\n\t\t\tarticleId: `workshop-${slugify(workshopTitle)}-extras`,\n\t\t\ttitle,\n\t\t\textras,\n\t\t\textrasReadme,\n\t\t\tepicVideoInfosPromise:\n\t\t\t\textrasReadme.compiled.status === 'success'\n\t\t\t\t\t? getEpicVideoInfos(extrasReadme.compiled.epicVideoEmbeds, {\n\t\t\t\t\t\t\trequest,\n\t\t\t\t\t\t})\n\t\t\t\t\t: null,\n\t\t},\n\t\t{\n\t\t\theaders: {\n\t\t\t\t'Server-Timing': getServerTimeHeader(timings),\n\t\t\t},\n\t\t},\n\t)\n}\n\nexport const headers: HeadersFunction = ({ loaderHeaders, parentHeaders }) => {\n\tconst headers = {\n\t\t'Cache-Control': loaderHeaders.get('Cache-Control') ?? '',\n\t\t'Server-Timing': combineServerTimings(loaderHeaders, parentHeaders),\n\t}\n\treturn headers\n}\n\nfunction ExtraListItem({\n\textra,\n}: {\n\textra: { dirName: string; title: string }\n}) {\n\treturn (\n\t\t<li>\n\t\t\t<Link\n\t\t\t\tclassName={cn(\n\t\t\t\t\t'relative flex items-center gap-4 px-4 py-3 text-lg font-semibold transition',\n\t\t\t\t\t'hover:bg-muted/60 focus:bg-muted/60',\n\t\t\t\t)}\n\t\t\t\tprefetch=\"intent\"\n\t\t\t\tto={extra.dirName}\n\t\t\t>\n\t\t\t\t<span className=\"text-muted-foreground text-xs font-normal tabular-nums\">\n\t\t\t\t\t•\n\t\t\t\t</span>\n\t\t\t\t<span className=\"truncate\">{extra.title}</span>\n\t\t\t</Link>\n\t\t</li>\n\t)\n}\n\nconst mdxComponents = { h1: () => null }\n\nexport default function ExtrasIndex() {\n\tconst data = useLoaderData<typeof loader>()\n\tuseRevalidationWS({ watchPaths: ['./extra', './example', './examples'] })\n\n\treturn (\n\t\t<main className=\"relative flex h-full w-full max-w-5xl flex-col justify-between border-r md:w-3/4 xl:w-2/3\">\n\t\t\t<article\n\t\t\t\tid={data.articleId}\n\t\t\t\tclassName=\"shadow-on-scrollbox scrollbar-thin scrollbar-thumb-scrollbar flex w-full flex-1 flex-col gap-12 overflow-y-scroll px-3 py-4 pt-6 md:px-10 md:py-12 md:pt-16\"\n\t\t\t>\n\t\t\t\t<div>\n\t\t\t\t\t<h1 className=\"text-[clamp(3rem,6vw,7.5rem)] leading-none font-extrabold\">\n\t\t\t\t\t\t{data.title}\n\t\t\t\t\t</h1>\n\t\t\t\t</div>\n\t\t\t\t<div>\n\t\t\t\t\t{data.extrasReadme.compiled.status === 'success' &&\n\t\t\t\t\tdata.extrasReadme.compiled.code ? (\n\t\t\t\t\t\t<EpicVideoInfoProvider\n\t\t\t\t\t\t\tepicVideoInfosPromise={data.epicVideoInfosPromise}\n\t\t\t\t\t\t>\n\t\t\t\t\t\t\t<div className=\"prose dark:prose-invert sm:prose-lg\">\n\t\t\t\t\t\t\t\t<Mdx\n\t\t\t\t\t\t\t\t\tcode={data.extrasReadme.compiled.code}\n\t\t\t\t\t\t\t\t\tcomponents={mdxComponents}\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</EpicVideoInfoProvider>\n\t\t\t\t\t) : data.extrasReadme.compiled.status === 'error' ? (\n\t\t\t\t\t\t<div className=\"text-foreground-destructive\">\n\t\t\t\t\t\t\tThere was an error:\n\t\t\t\t\t\t\t<pre>{data.extrasReadme.compiled.error}</pre>\n\t\t\t\t\t\t</div>\n\t\t\t\t\t) : (\n\t\t\t\t\t\t'No extras overview yet...'\n\t\t\t\t\t)}\n\t\t\t\t</div>\n\t\t\t\t<div className=\"pt-6\">\n\t\t\t\t\t<h2 className=\"pb-4 font-mono text-xs font-semibold uppercase\">\n\t\t\t\t\t\tExtras\n\t\t\t\t\t</h2>\n\t\t\t\t\t{data.extras.length ? (\n\t\t\t\t\t\t<ul className=\"divide-border dark:divide-border/50 flex flex-col divide-y\">\n\t\t\t\t\t\t\t{data.extras.map((extra) => (\n\t\t\t\t\t\t\t\t<ExtraListItem key={extra.dirName} extra={extra} />\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\t\t<p className=\"text-muted-foreground\">\n\t\t\t\t\t\t\tNo extras yet. Add one to get started.\n\t\t\t\t\t\t</p>\n\t\t\t\t\t)}\n\t\t\t\t</div>\n\t\t\t</article>\n\t\t\t<ElementScrollRestoration elementQuery={`#${data.articleId}`} />\n\t\t\t<div className=\"@container flex h-16 justify-center border-t\">\n\t\t\t\t<EditFileOnGitHub\n\t\t\t\t\tfile={data.extrasReadme.file}\n\t\t\t\t\trelativePath={data.extrasReadme.relativePath}\n\t\t\t\t/>\n\t\t\t</div>\n\t\t</main>\n\t)\n}\n\nexport function ErrorBoundary() {\n\treturn <GeneralErrorBoundary />\n}\n"],"names":["meta","args","loaderData","data","rootData","getRootMatchLoaderData","matches","title","getSeoMetaTags","workshopTitle","description","ogTitle","ogDescription","instructor","requestInfo","ExtraListItem","extra","children","jsxs","Link","className","cn","prefetch","to","dirName","jsx","mdxComponents","h1","index","_UNSAFE_withComponentProps","useLoaderData","useRevalidationWS","watchPaths","id","articleId","extrasReadme","compiled","status","code","EpicVideoInfoProvider","epicVideoInfosPromise","Mdx","components","error","extras","length","map","ElementScrollRestoration","elementQuery","EditFileOnGitHub","file","relativePath","ErrorBoundary","_UNSAFE_withErrorBoundaryProps","GeneralErrorBoundary"],"mappings":"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"}
@@ -1,2 +1,2 @@
1
- import{w as l,a as m,L as n}from"./chunk-EPOLDU6W-BCLmut3y.js";import{j as e}from"./jsx-runtime-C5WNSv3b.js";import{E as a}from"./index-CEVyDj51.js";import{E as c}from"./epic-video-Ca_s42j5.js";import{G as p}from"./error-boundary-DVp6wKiz.js";import{E as d}from"./launch-editor-D2exGfVu.js";import{M as x}from"./mdx-BGwe7vvs.js";import{c as f}from"./misc-W4055b-0.js";import{P as h,u}from"./progress-ILaVQtOO.js";import"./index-CqIc3cxq.js";import"./use-event-source-BuD4_2SF.js";import"./index-DzdDahau.js";import"./index-vDCSPjrM.js";import"./index-CdzVFL-Z.js";import"./tooltip-Tlsyx2YO.js";import"./root-loader-BOzEMapJ.js";import"./pe-CIZUOJMr.js";import"./schemas-Uj5SZtvt.js";import"./online-DiNLkgTC.js";import"./loading-CDNzW5oO.js";import"./user-BsPobzjB.js";import"./workshop-config-Zfc8zU0x.js";import"./preload-helper-BXl3LOEh.js";import"./progress-bar-DpWhcyhC.js";function b({index:o,exercise:r}){const s=u(r.exerciseNumber);return e.jsx("li",{children:e.jsxs(n,{className:f("hover:bg-muted/60 relative flex items-center gap-4 px-4 py-3 text-lg font-semibold transition after:absolute after:right-10 after:-translate-x-2 after:opacity-0 after:transition after:content-['→'] hover:after:translate-x-0 hover:after:opacity-100",s),to:`${r.exerciseNumber.toString().padStart(2,"0")}`,"data-keyboard-action":o===0?"g+n":void 0,children:[e.jsx("span",{className:"text-xs font-normal tabular-nums opacity-50",children:r.exerciseNumber}),e.jsx("span",{children:r.title})]})},r.exerciseNumber)}const j={h1:()=>null},q=l(function({loaderData:r}){const s=e.jsxs("ul",{className:"divide-border dark:divide-border/50 flex flex-col divide-y",children:[e.jsx("strong",{className:"px-10 pb-3 font-mono text-xs uppercase",children:"Exercises"}),r.exercises.map((t,i)=>e.jsx(b,{index:i,exercise:t},t.exerciseNumber))]});return e.jsxs("main",{className:"relative flex h-full w-full max-w-5xl flex-col justify-between border-r md:w-3/4 xl:w-2/3",children:[e.jsxs("article",{id:r.articleId,className:"shadow-on-scrollbox scrollbar-thin scrollbar-thumb-scrollbar flex w-full flex-1 flex-col gap-12 overflow-y-scroll px-3 py-4 pt-6 md:px-10 md:py-12 md:pt-16",children:[e.jsx("div",{children:e.jsx("h1",{className:"px-10 text-[clamp(3rem,6vw,7.5rem)] leading-none font-extrabold",children:r.title})}),e.jsxs("div",{className:"w-full max-w-none scroll-pt-6 border-t px-3 pt-3 md:px-10 md:pt-8",children:[e.jsx("h2",{className:"pb-5 font-mono text-xs font-semibold uppercase",children:"Intro"}),r.workshopReadme.compiled.status==="success"&&r.workshopReadme.compiled.code?e.jsx(c,{epicVideoInfosPromise:r.epicVideoInfosPromise,children:e.jsx("div",{className:"prose dark:prose-invert sm:prose-lg",children:e.jsx(x,{code:r.workshopReadme.compiled.code,components:j})})}):r.workshopReadme.compiled.status==="error"?e.jsxs("div",{className:"text-foreground-destructive",children:["There was an error:",e.jsx("pre",{children:r.workshopReadme.compiled.error})]}):"No instructions yet..."]}),e.jsx("div",{className:"pt-10 pb-5",children:r.workshopReadme.compiled.status==="success"&&r.workshopReadme.compiled.code&&r.workshopReadme.compiled.code.length>500?s:null})]}),e.jsx(a,{elementQuery:`#${r.articleId}`}),e.jsx(h,{type:"workshop-instructions",className:"h-14 border-t px-6"}),e.jsx("div",{className:"@container flex h-16 justify-center border-t",children:e.jsx(d,{file:r.workshopReadme.file,relativePath:r.workshopReadme.relativePath})})]})}),z=m(function(){return e.jsx(p,{})});export{z as ErrorBoundary,q as default};
2
- //# sourceMappingURL=index-BHfJ4hna.js.map
1
+ import{w as l,a as m,L as n}from"./chunk-EPOLDU6W-BCLmut3y.js";import{j as e}from"./jsx-runtime-C5WNSv3b.js";import{E as a}from"./index-CEVyDj51.js";import{E as c}from"./epic-video-DnXXh6qE.js";import{G as p}from"./error-boundary-DVp6wKiz.js";import{E as d}from"./launch-editor-D2exGfVu.js";import{M as x}from"./mdx-Dun3ONG_.js";import{c as f}from"./misc-W4055b-0.js";import{P as h,u}from"./progress-ILaVQtOO.js";import"./index-CqIc3cxq.js";import"./use-event-source-BuD4_2SF.js";import"./index-DzdDahau.js";import"./index-vDCSPjrM.js";import"./index-CdzVFL-Z.js";import"./tooltip-Tlsyx2YO.js";import"./root-loader-BOzEMapJ.js";import"./pe-CIZUOJMr.js";import"./schemas-Uj5SZtvt.js";import"./online-DiNLkgTC.js";import"./loading-CDNzW5oO.js";import"./user-BsPobzjB.js";import"./workshop-config-Zfc8zU0x.js";import"./preload-helper-BXl3LOEh.js";import"./progress-bar-DpWhcyhC.js";function b({index:o,exercise:r}){const s=u(r.exerciseNumber);return e.jsx("li",{children:e.jsxs(n,{className:f("hover:bg-muted/60 relative flex items-center gap-4 px-4 py-3 text-lg font-semibold transition after:absolute after:right-10 after:-translate-x-2 after:opacity-0 after:transition after:content-['→'] hover:after:translate-x-0 hover:after:opacity-100",s),to:`${r.exerciseNumber.toString().padStart(2,"0")}`,"data-keyboard-action":o===0?"g+n":void 0,children:[e.jsx("span",{className:"text-xs font-normal tabular-nums opacity-50",children:r.exerciseNumber}),e.jsx("span",{children:r.title})]})},r.exerciseNumber)}const j={h1:()=>null},q=l(function({loaderData:r}){const s=e.jsxs("ul",{className:"divide-border dark:divide-border/50 flex flex-col divide-y",children:[e.jsx("strong",{className:"px-10 pb-3 font-mono text-xs uppercase",children:"Exercises"}),r.exercises.map((t,i)=>e.jsx(b,{index:i,exercise:t},t.exerciseNumber))]});return e.jsxs("main",{className:"relative flex h-full w-full max-w-5xl flex-col justify-between border-r md:w-3/4 xl:w-2/3",children:[e.jsxs("article",{id:r.articleId,className:"shadow-on-scrollbox scrollbar-thin scrollbar-thumb-scrollbar flex w-full flex-1 flex-col gap-12 overflow-y-scroll px-3 py-4 pt-6 md:px-10 md:py-12 md:pt-16",children:[e.jsx("div",{children:e.jsx("h1",{className:"px-10 text-[clamp(3rem,6vw,7.5rem)] leading-none font-extrabold",children:r.title})}),e.jsxs("div",{className:"w-full max-w-none scroll-pt-6 border-t px-3 pt-3 md:px-10 md:pt-8",children:[e.jsx("h2",{className:"pb-5 font-mono text-xs font-semibold uppercase",children:"Intro"}),r.workshopReadme.compiled.status==="success"&&r.workshopReadme.compiled.code?e.jsx(c,{epicVideoInfosPromise:r.epicVideoInfosPromise,children:e.jsx("div",{className:"prose dark:prose-invert sm:prose-lg",children:e.jsx(x,{code:r.workshopReadme.compiled.code,components:j})})}):r.workshopReadme.compiled.status==="error"?e.jsxs("div",{className:"text-foreground-destructive",children:["There was an error:",e.jsx("pre",{children:r.workshopReadme.compiled.error})]}):"No instructions yet..."]}),e.jsx("div",{className:"pt-10 pb-5",children:r.workshopReadme.compiled.status==="success"&&r.workshopReadme.compiled.code&&r.workshopReadme.compiled.code.length>500?s:null})]}),e.jsx(a,{elementQuery:`#${r.articleId}`}),e.jsx(h,{type:"workshop-instructions",className:"h-14 border-t px-6"}),e.jsx("div",{className:"@container flex h-16 justify-center border-t",children:e.jsx(d,{file:r.workshopReadme.file,relativePath:r.workshopReadme.relativePath})})]})}),z=m(function(){return e.jsx(p,{})});export{z as ErrorBoundary,q as default};
2
+ //# sourceMappingURL=index-DfT8l3cx.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"index-BHfJ4hna.js","sources":["../../../app/routes/_app+/index.tsx"],"sourcesContent":["import { ElementScrollRestoration } from '@epic-web/restore-scroll'\nimport {\n\tgetExercises,\n\tgetWorkshopInstructions,\n} from '@epic-web/workshop-utils/apps.server'\nimport { getWorkshopConfig } from '@epic-web/workshop-utils/config.server'\nimport { getEpicVideoInfos } from '@epic-web/workshop-utils/epic-api.server'\nimport {\n\tcombineServerTimings,\n\tgetServerTimeHeader,\n\tmakeTimings,\n\ttime,\n} from '@epic-web/workshop-utils/timing.server'\nimport slugify from '@sindresorhus/slugify'\nimport { data, type HeadersFunction, Link } from 'react-router'\nimport { EpicVideoInfoProvider } from '#app/components/epic-video.tsx'\nimport { GeneralErrorBoundary } from '#app/components/error-boundary.tsx'\nimport { EditFileOnGitHub } from '#app/routes/launch-editor.tsx'\nimport { Mdx } from '#app/utils/mdx.tsx'\nimport { cn } from '#app/utils/misc.tsx'\nimport { ProgressToggle, useExerciseProgressClassName } from '../progress.tsx'\nimport { type Route } from './+types/index.tsx'\n\nexport async function loader({ request }: Route.LoaderArgs) {\n\tconst timings = makeTimings('indexLoader')\n\tconst { title } = getWorkshopConfig()\n\tconst [exercises, workshopReadme] = await Promise.all([\n\t\ttime(() => getExercises({ request, timings }), {\n\t\t\ttimings,\n\t\t\ttype: 'getExercises',\n\t\t\tdesc: 'getExercises in index',\n\t\t}),\n\t\ttime(() => getWorkshopInstructions({ request }), {\n\t\t\ttimings,\n\t\t\ttype: 'compileMdx',\n\t\t\tdesc: 'compileMdx in index',\n\t\t}),\n\t])\n\n\treturn data(\n\t\t{\n\t\t\tarticleId: `workshop-${slugify(title)}-instructions`,\n\t\t\ttitle:\n\t\t\t\tworkshopReadme.compiled.status === 'success'\n\t\t\t\t\t? workshopReadme.compiled.title\n\t\t\t\t\t: title,\n\t\t\texercises: exercises.map((e) => ({\n\t\t\t\texerciseNumber: e.exerciseNumber,\n\t\t\t\ttitle: e.title,\n\t\t\t})),\n\t\t\tworkshopReadme,\n\t\t\tepicVideoInfosPromise:\n\t\t\t\tworkshopReadme.compiled.status === 'success'\n\t\t\t\t\t? getEpicVideoInfos(workshopReadme.compiled.epicVideoEmbeds, {\n\t\t\t\t\t\t\trequest,\n\t\t\t\t\t\t})\n\t\t\t\t\t: null,\n\t\t},\n\t\t{\n\t\t\theaders: {\n\t\t\t\t'Server-Timing': getServerTimeHeader(timings),\n\t\t\t},\n\t\t},\n\t)\n}\n\nexport const headers: HeadersFunction = ({ loaderHeaders, parentHeaders }) => {\n\tconst headers = {\n\t\t'Cache-Control': loaderHeaders.get('Cache-Control') ?? '',\n\t\t'Server-Timing': combineServerTimings(loaderHeaders, parentHeaders),\n\t}\n\treturn headers\n}\n\nfunction ExerciseListItem({\n\tindex,\n\texercise,\n}: {\n\tindex: number\n\texercise: Awaited<Route.ComponentProps['loaderData']>['exercises'][number]\n}) {\n\tconst progressClassName = useExerciseProgressClassName(\n\t\texercise.exerciseNumber,\n\t)\n\treturn (\n\t\t<li key={exercise.exerciseNumber}>\n\t\t\t<Link\n\t\t\t\tclassName={cn(\n\t\t\t\t\t\"hover:bg-muted/60 relative flex items-center gap-4 px-4 py-3 text-lg font-semibold transition after:absolute after:right-10 after:-translate-x-2 after:opacity-0 after:transition after:content-['→'] hover:after:translate-x-0 hover:after:opacity-100\",\n\t\t\t\t\tprogressClassName,\n\t\t\t\t)}\n\t\t\t\tto={`${exercise.exerciseNumber.toString().padStart(2, '0')}`}\n\t\t\t\tdata-keyboard-action={index === 0 ? 'g+n' : undefined}\n\t\t\t>\n\t\t\t\t<span className=\"text-xs font-normal tabular-nums opacity-50\">\n\t\t\t\t\t{exercise.exerciseNumber}\n\t\t\t\t</span>\n\t\t\t\t<span>{exercise.title}</span>\n\t\t\t</Link>\n\t\t</li>\n\t)\n}\n\nconst mdxComponents = { h1: () => null }\n\nexport default function Index({ loaderData: data }: Route.ComponentProps) {\n\tconst exerciseLinks = (\n\t\t<ul className=\"divide-border dark:divide-border/50 flex flex-col divide-y\">\n\t\t\t<strong className=\"px-10 pb-3 font-mono text-xs uppercase\">\n\t\t\t\tExercises\n\t\t\t</strong>\n\t\t\t{data.exercises.map((exercise, index) => (\n\t\t\t\t<ExerciseListItem\n\t\t\t\t\tkey={exercise.exerciseNumber}\n\t\t\t\t\tindex={index}\n\t\t\t\t\texercise={exercise}\n\t\t\t\t/>\n\t\t\t))}\n\t\t</ul>\n\t)\n\treturn (\n\t\t<main className=\"relative flex h-full w-full max-w-5xl flex-col justify-between border-r md:w-3/4 xl:w-2/3\">\n\t\t\t<article\n\t\t\t\tid={data.articleId}\n\t\t\t\tclassName=\"shadow-on-scrollbox scrollbar-thin scrollbar-thumb-scrollbar flex w-full flex-1 flex-col gap-12 overflow-y-scroll px-3 py-4 pt-6 md:px-10 md:py-12 md:pt-16\"\n\t\t\t>\n\t\t\t\t<div>\n\t\t\t\t\t<h1 className=\"px-10 text-[clamp(3rem,6vw,7.5rem)] leading-none font-extrabold\">\n\t\t\t\t\t\t{data.title}\n\t\t\t\t\t</h1>\n\t\t\t\t</div>\n\t\t\t\t<div className=\"w-full max-w-none scroll-pt-6 border-t px-3 pt-3 md:px-10 md:pt-8\">\n\t\t\t\t\t<h2 className=\"pb-5 font-mono text-xs font-semibold uppercase\">\n\t\t\t\t\t\tIntro\n\t\t\t\t\t</h2>\n\t\t\t\t\t{data.workshopReadme.compiled.status === 'success' &&\n\t\t\t\t\tdata.workshopReadme.compiled.code ? (\n\t\t\t\t\t\t<EpicVideoInfoProvider\n\t\t\t\t\t\t\tepicVideoInfosPromise={data.epicVideoInfosPromise}\n\t\t\t\t\t\t>\n\t\t\t\t\t\t\t<div className=\"prose dark:prose-invert sm:prose-lg\">\n\t\t\t\t\t\t\t\t<Mdx\n\t\t\t\t\t\t\t\t\tcode={data.workshopReadme.compiled.code}\n\t\t\t\t\t\t\t\t\tcomponents={mdxComponents}\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</EpicVideoInfoProvider>\n\t\t\t\t\t) : data.workshopReadme.compiled.status === 'error' ? (\n\t\t\t\t\t\t<div className=\"text-foreground-destructive\">\n\t\t\t\t\t\t\tThere was an error:\n\t\t\t\t\t\t\t<pre>{data.workshopReadme.compiled.error}</pre>\n\t\t\t\t\t\t</div>\n\t\t\t\t\t) : (\n\t\t\t\t\t\t'No instructions yet...'\n\t\t\t\t\t)}\n\t\t\t\t</div>\n\t\t\t\t<div className=\"pt-10 pb-5\">\n\t\t\t\t\t{data.workshopReadme.compiled.status === 'success' &&\n\t\t\t\t\tdata.workshopReadme.compiled.code &&\n\t\t\t\t\tdata.workshopReadme.compiled.code.length > 500\n\t\t\t\t\t\t? exerciseLinks\n\t\t\t\t\t\t: null}\n\t\t\t\t</div>\n\t\t\t</article>\n\t\t\t<ElementScrollRestoration elementQuery={`#${data.articleId}`} />\n\t\t\t<ProgressToggle\n\t\t\t\ttype=\"workshop-instructions\"\n\t\t\t\tclassName=\"h-14 border-t px-6\"\n\t\t\t/>\n\t\t\t<div className=\"@container flex h-16 justify-center border-t\">\n\t\t\t\t<EditFileOnGitHub\n\t\t\t\t\tfile={data.workshopReadme.file}\n\t\t\t\t\trelativePath={data.workshopReadme.relativePath}\n\t\t\t\t/>\n\t\t\t</div>\n\t\t</main>\n\t)\n}\n\nexport function ErrorBoundary() {\n\treturn <GeneralErrorBoundary />\n}\n"],"names":["ExerciseListItem","index","exercise","progressClassName","useExerciseProgressClassName","exerciseNumber","children","jsxs","Link","className","cn","to","toString","padStart","jsx","title","mdxComponents","h1","_UNSAFE_withComponentProps","loaderData","data","exerciseLinks","exercises","map","id","articleId","workshopReadme","compiled","status","code","EpicVideoInfoProvider","epicVideoInfosPromise","Mdx","components","error","length","ElementScrollRestoration","elementQuery","ProgressToggle","type","EditFileOnGitHub","file","relativePath","ErrorBoundary","_UNSAFE_withErrorBoundaryProps","GeneralErrorBoundary"],"mappings":"+2BA0EA,SAASA,EAAiB,CACzBC,MAAAA,EACAC,SAAAA,CACD,EAGG,CACF,MAAMC,EAAoBC,EACzBF,EAASG,cACV,EACA,aACE,KAAA,CACAC,SAAAC,EAAAA,KAACC,EAAA,CACAC,UAAWC,EACV,0PACAP,CACD,EACAQ,GAAI,GAAGT,EAASG,eAAeO,WAAWC,SAAS,EAAG,GAAG,CAAC,GAC1D,uBAAsBZ,IAAU,EAAI,MAAQ,OAE5CK,SAAA,CAAAQ,EAAAA,IAAC,OAAA,CAAKL,UAAU,8CACdH,SAAAJ,EAASG,cAAA,CACX,EACAS,EAAAA,IAAC,OAAA,CAAMR,SAAAJ,EAASa,KAAA,CAAM,CAAA,EACvB,CAAA,EAbQb,EAASG,cAclB,CAEF,CAEA,MAAMW,EAAgB,CAAEC,GAAIA,IAAM,IAAK,EAEvChB,EAAAiB,EAAA,SAA8B,CAAEC,WAAYC,CAAK,EAAyB,CACzE,MAAMC,EACLd,EAAAA,KAAC,KAAA,CAAGE,UAAU,6DACbH,SAAA,CAAAQ,EAAAA,IAAC,SAAA,CAAOL,UAAU,yCAAyCH,SAAA,WAAA,CAE3D,EACCc,EAAKE,UAAUC,IAAI,CAACrB,EAAUD,IAC9Ba,EAAAA,IAACd,EAAA,CAEAC,MAAAA,EACAC,SAAAA,CAAA,EAFKA,EAASG,cAGf,CACA,CAAA,CAAA,CACF,EAED,OACCE,EAAAA,KAAC,OAAA,CAAKE,UAAU,4FACfH,SAAA,CAAAC,EAAAA,KAAC,UAAA,CACAiB,GAAIJ,EAAKK,UACThB,UAAU,8JAEVH,SAAA,CAAAQ,EAAAA,IAAC,MAAA,CACAR,eAAC,KAAA,CAAGG,UAAU,kEACZH,SAAAc,EAAKL,MACP,CAAA,CACD,EACAR,EAAAA,KAAC,MAAA,CAAIE,UAAU,oEACdH,SAAA,CAAAQ,EAAAA,IAAC,KAAA,CAAGL,UAAU,iDAAiDH,SAAA,QAE/D,EACCc,EAAKM,eAAeC,SAASC,SAAW,WACzCR,EAAKM,eAAeC,SAASE,KAC5Bf,EAAAA,IAACgB,EAAA,CACAC,sBAAuBX,EAAKW,sBAE5BzB,SAAAQ,EAAAA,IAAC,MAAA,CAAIL,UAAU,sCACdH,SAAAQ,EAAAA,IAACkB,EAAA,CACAH,KAAMT,EAAKM,eAAeC,SAASE,KACnCI,WAAYjB,EACb,EACD,CAAA,CACD,EACGI,EAAKM,eAAeC,SAASC,SAAW,QAC3CrB,EAAAA,KAAC,MAAA,CAAIE,UAAU,8BAA8BH,SAAA,CAAA,4BAE3C,MAAA,CAAKA,SAAAc,EAAKM,eAAeC,SAASO,KAAA,CAAM,CAAA,EAC1C,EAEA,wBAAA,CAAA,CAEF,EACApB,EAAAA,IAAC,OAAIL,UAAU,aACbH,SAAAc,EAAKM,eAAeC,SAASC,SAAW,WACzCR,EAAKM,eAAeC,SAASE,MAC7BT,EAAKM,eAAeC,SAASE,KAAKM,OAAS,IACxCd,EACA,IAAA,CACJ,CAAA,CAAA,CACD,QACCe,EAAA,CAAyBC,aAAc,IAAIjB,EAAKK,SAAS,EAAA,CAAI,EAC9DX,EAAAA,IAACwB,EAAA,CACAC,KAAK,wBACL9B,UAAU,oBAAA,CACX,EACAK,EAAAA,IAAC,MAAA,CAAIL,UAAU,+CACdH,SAAAQ,EAAAA,IAAC0B,EAAA,CACAC,KAAMrB,EAAKM,eAAee,KAC1BC,aAActB,EAAKM,eAAegB,aACnC,CAAA,CACD,CAAA,CAAA,CACD,CAEF,CAAA,EAEOC,EAAAC,EAAA,UAAyB,CAC/B,aAAQC,EAAA,EAAqB,CAC9B,CAAA"}
1
+ {"version":3,"file":"index-DfT8l3cx.js","sources":["../../../app/routes/_app+/index.tsx"],"sourcesContent":["import { ElementScrollRestoration } from '@epic-web/restore-scroll'\nimport {\n\tgetExercises,\n\tgetWorkshopInstructions,\n} from '@epic-web/workshop-utils/apps.server'\nimport { getWorkshopConfig } from '@epic-web/workshop-utils/config.server'\nimport { getEpicVideoInfos } from '@epic-web/workshop-utils/epic-api.server'\nimport {\n\tcombineServerTimings,\n\tgetServerTimeHeader,\n\tmakeTimings,\n\ttime,\n} from '@epic-web/workshop-utils/timing.server'\nimport slugify from '@sindresorhus/slugify'\nimport { data, type HeadersFunction, Link } from 'react-router'\nimport { EpicVideoInfoProvider } from '#app/components/epic-video.tsx'\nimport { GeneralErrorBoundary } from '#app/components/error-boundary.tsx'\nimport { EditFileOnGitHub } from '#app/routes/launch-editor.tsx'\nimport { Mdx } from '#app/utils/mdx.tsx'\nimport { cn } from '#app/utils/misc.tsx'\nimport { ProgressToggle, useExerciseProgressClassName } from '../progress.tsx'\nimport { type Route } from './+types/index.tsx'\n\nexport async function loader({ request }: Route.LoaderArgs) {\n\tconst timings = makeTimings('indexLoader')\n\tconst { title } = getWorkshopConfig()\n\tconst [exercises, workshopReadme] = await Promise.all([\n\t\ttime(() => getExercises({ request, timings }), {\n\t\t\ttimings,\n\t\t\ttype: 'getExercises',\n\t\t\tdesc: 'getExercises in index',\n\t\t}),\n\t\ttime(() => getWorkshopInstructions({ request }), {\n\t\t\ttimings,\n\t\t\ttype: 'compileMdx',\n\t\t\tdesc: 'compileMdx in index',\n\t\t}),\n\t])\n\n\treturn data(\n\t\t{\n\t\t\tarticleId: `workshop-${slugify(title)}-instructions`,\n\t\t\ttitle:\n\t\t\t\tworkshopReadme.compiled.status === 'success'\n\t\t\t\t\t? workshopReadme.compiled.title\n\t\t\t\t\t: title,\n\t\t\texercises: exercises.map((e) => ({\n\t\t\t\texerciseNumber: e.exerciseNumber,\n\t\t\t\ttitle: e.title,\n\t\t\t})),\n\t\t\tworkshopReadme,\n\t\t\tepicVideoInfosPromise:\n\t\t\t\tworkshopReadme.compiled.status === 'success'\n\t\t\t\t\t? getEpicVideoInfos(workshopReadme.compiled.epicVideoEmbeds, {\n\t\t\t\t\t\t\trequest,\n\t\t\t\t\t\t})\n\t\t\t\t\t: null,\n\t\t},\n\t\t{\n\t\t\theaders: {\n\t\t\t\t'Server-Timing': getServerTimeHeader(timings),\n\t\t\t},\n\t\t},\n\t)\n}\n\nexport const headers: HeadersFunction = ({ loaderHeaders, parentHeaders }) => {\n\tconst headers = {\n\t\t'Cache-Control': loaderHeaders.get('Cache-Control') ?? '',\n\t\t'Server-Timing': combineServerTimings(loaderHeaders, parentHeaders),\n\t}\n\treturn headers\n}\n\nfunction ExerciseListItem({\n\tindex,\n\texercise,\n}: {\n\tindex: number\n\texercise: Awaited<Route.ComponentProps['loaderData']>['exercises'][number]\n}) {\n\tconst progressClassName = useExerciseProgressClassName(\n\t\texercise.exerciseNumber,\n\t)\n\treturn (\n\t\t<li key={exercise.exerciseNumber}>\n\t\t\t<Link\n\t\t\t\tclassName={cn(\n\t\t\t\t\t\"hover:bg-muted/60 relative flex items-center gap-4 px-4 py-3 text-lg font-semibold transition after:absolute after:right-10 after:-translate-x-2 after:opacity-0 after:transition after:content-['→'] hover:after:translate-x-0 hover:after:opacity-100\",\n\t\t\t\t\tprogressClassName,\n\t\t\t\t)}\n\t\t\t\tto={`${exercise.exerciseNumber.toString().padStart(2, '0')}`}\n\t\t\t\tdata-keyboard-action={index === 0 ? 'g+n' : undefined}\n\t\t\t>\n\t\t\t\t<span className=\"text-xs font-normal tabular-nums opacity-50\">\n\t\t\t\t\t{exercise.exerciseNumber}\n\t\t\t\t</span>\n\t\t\t\t<span>{exercise.title}</span>\n\t\t\t</Link>\n\t\t</li>\n\t)\n}\n\nconst mdxComponents = { h1: () => null }\n\nexport default function Index({ loaderData: data }: Route.ComponentProps) {\n\tconst exerciseLinks = (\n\t\t<ul className=\"divide-border dark:divide-border/50 flex flex-col divide-y\">\n\t\t\t<strong className=\"px-10 pb-3 font-mono text-xs uppercase\">\n\t\t\t\tExercises\n\t\t\t</strong>\n\t\t\t{data.exercises.map((exercise, index) => (\n\t\t\t\t<ExerciseListItem\n\t\t\t\t\tkey={exercise.exerciseNumber}\n\t\t\t\t\tindex={index}\n\t\t\t\t\texercise={exercise}\n\t\t\t\t/>\n\t\t\t))}\n\t\t</ul>\n\t)\n\treturn (\n\t\t<main className=\"relative flex h-full w-full max-w-5xl flex-col justify-between border-r md:w-3/4 xl:w-2/3\">\n\t\t\t<article\n\t\t\t\tid={data.articleId}\n\t\t\t\tclassName=\"shadow-on-scrollbox scrollbar-thin scrollbar-thumb-scrollbar flex w-full flex-1 flex-col gap-12 overflow-y-scroll px-3 py-4 pt-6 md:px-10 md:py-12 md:pt-16\"\n\t\t\t>\n\t\t\t\t<div>\n\t\t\t\t\t<h1 className=\"px-10 text-[clamp(3rem,6vw,7.5rem)] leading-none font-extrabold\">\n\t\t\t\t\t\t{data.title}\n\t\t\t\t\t</h1>\n\t\t\t\t</div>\n\t\t\t\t<div className=\"w-full max-w-none scroll-pt-6 border-t px-3 pt-3 md:px-10 md:pt-8\">\n\t\t\t\t\t<h2 className=\"pb-5 font-mono text-xs font-semibold uppercase\">\n\t\t\t\t\t\tIntro\n\t\t\t\t\t</h2>\n\t\t\t\t\t{data.workshopReadme.compiled.status === 'success' &&\n\t\t\t\t\tdata.workshopReadme.compiled.code ? (\n\t\t\t\t\t\t<EpicVideoInfoProvider\n\t\t\t\t\t\t\tepicVideoInfosPromise={data.epicVideoInfosPromise}\n\t\t\t\t\t\t>\n\t\t\t\t\t\t\t<div className=\"prose dark:prose-invert sm:prose-lg\">\n\t\t\t\t\t\t\t\t<Mdx\n\t\t\t\t\t\t\t\t\tcode={data.workshopReadme.compiled.code}\n\t\t\t\t\t\t\t\t\tcomponents={mdxComponents}\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</EpicVideoInfoProvider>\n\t\t\t\t\t) : data.workshopReadme.compiled.status === 'error' ? (\n\t\t\t\t\t\t<div className=\"text-foreground-destructive\">\n\t\t\t\t\t\t\tThere was an error:\n\t\t\t\t\t\t\t<pre>{data.workshopReadme.compiled.error}</pre>\n\t\t\t\t\t\t</div>\n\t\t\t\t\t) : (\n\t\t\t\t\t\t'No instructions yet...'\n\t\t\t\t\t)}\n\t\t\t\t</div>\n\t\t\t\t<div className=\"pt-10 pb-5\">\n\t\t\t\t\t{data.workshopReadme.compiled.status === 'success' &&\n\t\t\t\t\tdata.workshopReadme.compiled.code &&\n\t\t\t\t\tdata.workshopReadme.compiled.code.length > 500\n\t\t\t\t\t\t? exerciseLinks\n\t\t\t\t\t\t: null}\n\t\t\t\t</div>\n\t\t\t</article>\n\t\t\t<ElementScrollRestoration elementQuery={`#${data.articleId}`} />\n\t\t\t<ProgressToggle\n\t\t\t\ttype=\"workshop-instructions\"\n\t\t\t\tclassName=\"h-14 border-t px-6\"\n\t\t\t/>\n\t\t\t<div className=\"@container flex h-16 justify-center border-t\">\n\t\t\t\t<EditFileOnGitHub\n\t\t\t\t\tfile={data.workshopReadme.file}\n\t\t\t\t\trelativePath={data.workshopReadme.relativePath}\n\t\t\t\t/>\n\t\t\t</div>\n\t\t</main>\n\t)\n}\n\nexport function ErrorBoundary() {\n\treturn <GeneralErrorBoundary />\n}\n"],"names":["ExerciseListItem","index","exercise","progressClassName","useExerciseProgressClassName","exerciseNumber","children","jsxs","Link","className","cn","to","toString","padStart","jsx","title","mdxComponents","h1","_UNSAFE_withComponentProps","loaderData","data","exerciseLinks","exercises","map","id","articleId","workshopReadme","compiled","status","code","EpicVideoInfoProvider","epicVideoInfosPromise","Mdx","components","error","length","ElementScrollRestoration","elementQuery","ProgressToggle","type","EditFileOnGitHub","file","relativePath","ErrorBoundary","_UNSAFE_withErrorBoundaryProps","GeneralErrorBoundary"],"mappings":"+2BA0EA,SAASA,EAAiB,CACzBC,MAAAA,EACAC,SAAAA,CACD,EAGG,CACF,MAAMC,EAAoBC,EACzBF,EAASG,cACV,EACA,aACE,KAAA,CACAC,SAAAC,EAAAA,KAACC,EAAA,CACAC,UAAWC,EACV,0PACAP,CACD,EACAQ,GAAI,GAAGT,EAASG,eAAeO,WAAWC,SAAS,EAAG,GAAG,CAAC,GAC1D,uBAAsBZ,IAAU,EAAI,MAAQ,OAE5CK,SAAA,CAAAQ,EAAAA,IAAC,OAAA,CAAKL,UAAU,8CACdH,SAAAJ,EAASG,cAAA,CACX,EACAS,EAAAA,IAAC,OAAA,CAAMR,SAAAJ,EAASa,KAAA,CAAM,CAAA,EACvB,CAAA,EAbQb,EAASG,cAclB,CAEF,CAEA,MAAMW,EAAgB,CAAEC,GAAIA,IAAM,IAAK,EAEvChB,EAAAiB,EAAA,SAA8B,CAAEC,WAAYC,CAAK,EAAyB,CACzE,MAAMC,EACLd,EAAAA,KAAC,KAAA,CAAGE,UAAU,6DACbH,SAAA,CAAAQ,EAAAA,IAAC,SAAA,CAAOL,UAAU,yCAAyCH,SAAA,WAAA,CAE3D,EACCc,EAAKE,UAAUC,IAAI,CAACrB,EAAUD,IAC9Ba,EAAAA,IAACd,EAAA,CAEAC,MAAAA,EACAC,SAAAA,CAAA,EAFKA,EAASG,cAGf,CACA,CAAA,CAAA,CACF,EAED,OACCE,EAAAA,KAAC,OAAA,CAAKE,UAAU,4FACfH,SAAA,CAAAC,EAAAA,KAAC,UAAA,CACAiB,GAAIJ,EAAKK,UACThB,UAAU,8JAEVH,SAAA,CAAAQ,EAAAA,IAAC,MAAA,CACAR,eAAC,KAAA,CAAGG,UAAU,kEACZH,SAAAc,EAAKL,MACP,CAAA,CACD,EACAR,EAAAA,KAAC,MAAA,CAAIE,UAAU,oEACdH,SAAA,CAAAQ,EAAAA,IAAC,KAAA,CAAGL,UAAU,iDAAiDH,SAAA,QAE/D,EACCc,EAAKM,eAAeC,SAASC,SAAW,WACzCR,EAAKM,eAAeC,SAASE,KAC5Bf,EAAAA,IAACgB,EAAA,CACAC,sBAAuBX,EAAKW,sBAE5BzB,SAAAQ,EAAAA,IAAC,MAAA,CAAIL,UAAU,sCACdH,SAAAQ,EAAAA,IAACkB,EAAA,CACAH,KAAMT,EAAKM,eAAeC,SAASE,KACnCI,WAAYjB,EACb,EACD,CAAA,CACD,EACGI,EAAKM,eAAeC,SAASC,SAAW,QAC3CrB,EAAAA,KAAC,MAAA,CAAIE,UAAU,8BAA8BH,SAAA,CAAA,4BAE3C,MAAA,CAAKA,SAAAc,EAAKM,eAAeC,SAASO,KAAA,CAAM,CAAA,EAC1C,EAEA,wBAAA,CAAA,CAEF,EACApB,EAAAA,IAAC,OAAIL,UAAU,aACbH,SAAAc,EAAKM,eAAeC,SAASC,SAAW,WACzCR,EAAKM,eAAeC,SAASE,MAC7BT,EAAKM,eAAeC,SAASE,KAAKM,OAAS,IACxCd,EACA,IAAA,CACJ,CAAA,CAAA,CACD,QACCe,EAAA,CAAyBC,aAAc,IAAIjB,EAAKK,SAAS,EAAA,CAAI,EAC9DX,EAAAA,IAACwB,EAAA,CACAC,KAAK,wBACL9B,UAAU,oBAAA,CACX,EACAK,EAAAA,IAAC,MAAA,CAAIL,UAAU,+CACdH,SAAAQ,EAAAA,IAAC0B,EAAA,CACAC,KAAMrB,EAAKM,eAAee,KAC1BC,aAActB,EAAKM,eAAegB,aACnC,CAAA,CACD,CAAA,CAAA,CACD,CAEF,CAAA,EAEOC,EAAAC,EAAA,UAAyB,CAC/B,aAAQC,EAAA,EAAqB,CAC9B,CAAA"}
@@ -1,2 +1,2 @@
1
- import{w as j,a as E,c as A,d as C,e as N}from"./chunk-EPOLDU6W-BCLmut3y.js";import{j as r}from"./jsx-runtime-C5WNSv3b.js";import{g as T,R as H,P as U,C as t,a as b,D as B}from"./playground-DmEAkxG1.js";import{U as I}from"./diff-DrdM1MAZ.js";import{G as R}from"./error-boundary-DVp6wKiz.js";import{u as S}from"./workshop-config-Zfc8zU0x.js";import{u as O}from"./misc-W4055b-0.js";import{P as a}from"./preview-fhmjENlm.js";import{T as k}from"./tests-DlDV-wXQ.js";import"./index-CqIc3cxq.js";import"./loading-CDNzW5oO.js";import"./index-CdzVFL-Z.js";import"./tooltip-Tlsyx2YO.js";import"./index-vDCSPjrM.js";import"./root-loader-BOzEMapJ.js";import"./pe-CIZUOJMr.js";import"./schemas-Uj5SZtvt.js";import"./discord-BJkw0IrB.js";import"./user-BsPobzjB.js";import"./online-DiNLkgTC.js";import"./index-CJDOQ1bl.js";import"./index-ynYvVAOK.js";import"./status-indicator-C6DiLYL5.js";import"./index-DzdDahau.js";import"./set-playground-BSGwH9dH.js";import"./button-Cd-ekki5.js";import"./onboarding-indicator-B-XR90_G.js";import"./progress-bar-DpWhcyhC.js";import"./dialog-CzO65Z5w.js";import"./playground-window-x2mQ5o1O.js";import"./accordion-CQ7oujC6.js";import"./mdx-BGwe7vvs.js";import"./epic-video-Ca_s42j5.js";import"./use-event-source-BuD4_2SF.js";import"./preload-helper-BXl3LOEh.js";import"./launch-editor-D2exGfVu.js";import"./revalidation-ws-BJWJviUX.js";const l=["playground","problem","solution","tests","diff","chat"],L=n=>!!(n&&l.includes(n)),Ps=j(function({loaderData:e}){const{inBrowserBrowserRef:p}=A(),d=S(),[u]=C(),f=u.get("preview"),h=O(),x=N();function m(s){if(s==="tests")return ENV.EPICSHOP_DEPLOYED||!e.playground||e.playground.test.type==="none";if(s==="problem"||s==="solution"){if(e[s]?.dev.type==="none")return!0;if(ENV.EPICSHOP_DEPLOYED){const i=e[s]?.dev.type;return i!=="browser"&&i!=="export"&&!e[s]?.stackBlitzUrl}}return s==="playground"&&ENV.EPICSHOP_DEPLOYED?!0:s==="chat"?!d.product.discordChannelId:!1}function w(s){if(s==="tests"){if(!e.playground)return null;const{isTestRunning:i,testExitCode:o}=e.playground;return i?"running":o===0?"passed":o!==null&&o!==0?"failed":null}return(s==="problem"||s==="solution"||s==="playground")&&(s==="playground"?e.playground:e[s])?.isRunning?"running":null}const y=L(f)?f:l.find(s=>!m(s)),c=`/diff?${new URLSearchParams({app1:e.problem?.name??"",app2:e.solution?.name??""})}`;function g(s){s.altKey&&!s.ctrlKey&&!s.shiftKey&&!s.metaKey&&(s.preventDefault(),x(c))}const v=l.map(s=>{const i=m(s),o=w(s),P=s==="diff"&&h?c:`?${T(u,s,"playground")}`;return{id:s,label:s,hidden:i,status:o,to:P,onClick:s==="diff"?g:void 0}});return r.jsxs(H,{className:"relative flex min-h-0 min-w-0 flex-1 flex-col overflow-hidden sm:col-span-1 sm:row-span-1",value:y,children:[r.jsx(U,{tabs:v}),r.jsxs("div",{className:"relative z-10 flex min-h-0 flex-1 flex-col overflow-hidden",children:[r.jsx(t,{value:"playground",className:"radix-state-inactive:hidden flex min-h-0 w-full grow basis-0 items-stretch justify-center self-start",forceMount:!0,children:r.jsx(b,{appInfo:e.playground,problemAppName:e.problem?.name,inBrowserBrowserRef:p,allApps:e.allApps,isUpToDate:e.playground?.isUpToDate??!1})}),r.jsx(t,{value:"problem",className:"radix-state-inactive:hidden flex min-h-0 w-full grow basis-0 items-stretch justify-center self-start",forceMount:!0,children:r.jsx(a,{appInfo:e.problem,inBrowserBrowserRef:p})}),r.jsx(t,{value:"solution",className:"radix-state-inactive:hidden flex min-h-0 w-full grow basis-0 items-stretch justify-center self-start",forceMount:!0,children:r.jsx(a,{appInfo:e.solution,inBrowserBrowserRef:p})}),r.jsx(t,{value:"tests",className:"radix-state-inactive:hidden flex min-h-0 w-full grow basis-0 items-stretch justify-center self-start overflow-hidden",children:r.jsx(k,{appInfo:e.playground,problemAppName:e.problem?.name,allApps:e.allApps,isUpToDate:e.playground?.isUpToDate??!1,userHasAccessPromise:e.userHasAccessPromise})}),r.jsx(t,{value:"diff",className:"radix-state-inactive:hidden flex h-full min-h-0 w-full grow basis-0 items-stretch justify-center self-start",children:r.jsx(I,{diff:e.diff,allApps:e.allApps,userHasAccessPromise:e.userHasAccessPromise})}),r.jsx(t,{value:"chat",className:"radix-state-inactive:hidden flex h-full min-h-0 w-full grow basis-0 items-stretch justify-center self-start",children:r.jsx(B,{discordPostsPromise:e.discordPostsPromise})})]})]})}),js=E(function(){return r.jsx(R,{statusHandlers:{404:()=>r.jsx("p",{children:"Sorry, we couldn't find an app here."})}})});export{js as ErrorBoundary,Ps as default};
2
- //# sourceMappingURL=index-BRVfMMSd.js.map
1
+ import{w as j,a as E,c as A,d as C,e as N}from"./chunk-EPOLDU6W-BCLmut3y.js";import{j as r}from"./jsx-runtime-C5WNSv3b.js";import{g as T,R as H,P as U,C as t,a as b,D as B}from"./playground-DmEAkxG1.js";import{U as I}from"./diff-HIgoC1PO.js";import{G as R}from"./error-boundary-DVp6wKiz.js";import{u as S}from"./workshop-config-Zfc8zU0x.js";import{u as O}from"./misc-W4055b-0.js";import{P as a}from"./preview-fhmjENlm.js";import{T as k}from"./tests-1-kVRtTc.js";import"./index-CqIc3cxq.js";import"./loading-CDNzW5oO.js";import"./index-CdzVFL-Z.js";import"./tooltip-Tlsyx2YO.js";import"./index-vDCSPjrM.js";import"./root-loader-BOzEMapJ.js";import"./pe-CIZUOJMr.js";import"./schemas-Uj5SZtvt.js";import"./discord-BJkw0IrB.js";import"./user-BsPobzjB.js";import"./online-DiNLkgTC.js";import"./index-CJDOQ1bl.js";import"./index-ynYvVAOK.js";import"./status-indicator-C6DiLYL5.js";import"./index-DzdDahau.js";import"./set-playground-BSGwH9dH.js";import"./button-Cd-ekki5.js";import"./onboarding-indicator-B-XR90_G.js";import"./progress-bar-DpWhcyhC.js";import"./dialog-CzO65Z5w.js";import"./playground-window-x2mQ5o1O.js";import"./accordion-CQ7oujC6.js";import"./mdx-Dun3ONG_.js";import"./epic-video-DnXXh6qE.js";import"./use-event-source-BuD4_2SF.js";import"./preload-helper-BXl3LOEh.js";import"./launch-editor-D2exGfVu.js";import"./revalidation-ws-BJWJviUX.js";const l=["playground","problem","solution","tests","diff","chat"],L=n=>!!(n&&l.includes(n)),Ps=j(function({loaderData:e}){const{inBrowserBrowserRef:p}=A(),d=S(),[u]=C(),f=u.get("preview"),h=O(),x=N();function m(s){if(s==="tests")return ENV.EPICSHOP_DEPLOYED||!e.playground||e.playground.test.type==="none";if(s==="problem"||s==="solution"){if(e[s]?.dev.type==="none")return!0;if(ENV.EPICSHOP_DEPLOYED){const i=e[s]?.dev.type;return i!=="browser"&&i!=="export"&&!e[s]?.stackBlitzUrl}}return s==="playground"&&ENV.EPICSHOP_DEPLOYED?!0:s==="chat"?!d.product.discordChannelId:!1}function w(s){if(s==="tests"){if(!e.playground)return null;const{isTestRunning:i,testExitCode:o}=e.playground;return i?"running":o===0?"passed":o!==null&&o!==0?"failed":null}return(s==="problem"||s==="solution"||s==="playground")&&(s==="playground"?e.playground:e[s])?.isRunning?"running":null}const y=L(f)?f:l.find(s=>!m(s)),c=`/diff?${new URLSearchParams({app1:e.problem?.name??"",app2:e.solution?.name??""})}`;function g(s){s.altKey&&!s.ctrlKey&&!s.shiftKey&&!s.metaKey&&(s.preventDefault(),x(c))}const v=l.map(s=>{const i=m(s),o=w(s),P=s==="diff"&&h?c:`?${T(u,s,"playground")}`;return{id:s,label:s,hidden:i,status:o,to:P,onClick:s==="diff"?g:void 0}});return r.jsxs(H,{className:"relative flex min-h-0 min-w-0 flex-1 flex-col overflow-hidden sm:col-span-1 sm:row-span-1",value:y,children:[r.jsx(U,{tabs:v}),r.jsxs("div",{className:"relative z-10 flex min-h-0 flex-1 flex-col overflow-hidden",children:[r.jsx(t,{value:"playground",className:"radix-state-inactive:hidden flex min-h-0 w-full grow basis-0 items-stretch justify-center self-start",forceMount:!0,children:r.jsx(b,{appInfo:e.playground,problemAppName:e.problem?.name,inBrowserBrowserRef:p,allApps:e.allApps,isUpToDate:e.playground?.isUpToDate??!1})}),r.jsx(t,{value:"problem",className:"radix-state-inactive:hidden flex min-h-0 w-full grow basis-0 items-stretch justify-center self-start",forceMount:!0,children:r.jsx(a,{appInfo:e.problem,inBrowserBrowserRef:p})}),r.jsx(t,{value:"solution",className:"radix-state-inactive:hidden flex min-h-0 w-full grow basis-0 items-stretch justify-center self-start",forceMount:!0,children:r.jsx(a,{appInfo:e.solution,inBrowserBrowserRef:p})}),r.jsx(t,{value:"tests",className:"radix-state-inactive:hidden flex min-h-0 w-full grow basis-0 items-stretch justify-center self-start overflow-hidden",children:r.jsx(k,{appInfo:e.playground,problemAppName:e.problem?.name,allApps:e.allApps,isUpToDate:e.playground?.isUpToDate??!1,userHasAccessPromise:e.userHasAccessPromise})}),r.jsx(t,{value:"diff",className:"radix-state-inactive:hidden flex h-full min-h-0 w-full grow basis-0 items-stretch justify-center self-start",children:r.jsx(I,{diff:e.diff,allApps:e.allApps,userHasAccessPromise:e.userHasAccessPromise})}),r.jsx(t,{value:"chat",className:"radix-state-inactive:hidden flex h-full min-h-0 w-full grow basis-0 items-stretch justify-center self-start",children:r.jsx(B,{discordPostsPromise:e.discordPostsPromise})})]})]})}),js=E(function(){return r.jsx(R,{statusHandlers:{404:()=>r.jsx("p",{children:"Sorry, we couldn't find an app here."})}})});export{js as ErrorBoundary,Ps as default};
2
+ //# sourceMappingURL=index-DkDXAMak.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"index-BRVfMMSd.js","sources":["../../../app/routes/_app+/exercise+/$exerciseNumber_.$stepNumber.$type+/index.tsx"],"sourcesContent":["import {\n\tgetAppByName,\n\tgetAppDisplayName,\n\tgetApps,\n\tgetExerciseApp,\n\tisExerciseStepApp,\n\tisPlaygroundApp,\n\trequireExerciseApp,\n\ttype App,\n\ttype ExerciseStepApp,\n} from '@epic-web/workshop-utils/apps.server'\nimport { getDiffCode } from '@epic-web/workshop-utils/diff.server'\nimport { userHasAccessToExerciseStep } from '@epic-web/workshop-utils/epic-api.server'\nimport {\n\tcombineServerTimings,\n\tgetServerTimeHeader,\n\tmakeTimings,\n} from '@epic-web/workshop-utils/timing.server'\nimport * as Tabs from '@radix-ui/react-tabs'\nimport * as React from 'react'\nimport {\n\tuseNavigate,\n\tuseSearchParams,\n\tdata,\n\tredirect,\n\ttype HeadersFunction,\n\ttype LoaderFunctionArgs,\n\tuseOutletContext,\n} from 'react-router'\nimport { Diff } from '#app/components/diff.tsx'\nimport { DiscordChat } from '#app/components/discord-chat.tsx'\nimport { GeneralErrorBoundary } from '#app/components/error-boundary.tsx'\nimport { type InBrowserBrowserRef } from '#app/components/in-browser-browser.tsx'\nimport {\n\tgetPreviewSearchParams,\n\tPreviewTabsList,\n} from '#app/components/preview-tabs.tsx'\nimport { useWorkshopConfig } from '#app/components/workshop-config.tsx'\nimport { fetchDiscordPosts } from '#app/utils/discord.server.ts'\nimport { useAltDown } from '#app/utils/misc.tsx'\nimport { type Route } from './+types/index.ts'\nimport { Playground } from './__shared/playground.tsx'\nimport { Preview } from './__shared/preview.tsx'\nimport { Tests } from './__shared/tests.tsx'\nimport { getAppRunningState, getTestState } from './__shared/utils.tsx'\n\nexport async function loader({ request, params }: LoaderFunctionArgs) {\n\tconst timings = makeTimings('exerciseStepTypeIndexLoader')\n\tconst searchParams = new URL(request.url).searchParams\n\tconst cacheOptions = { request, timings }\n\n\tconst [exerciseStepApp, allAppsFull, problemApp, solutionApp] =\n\t\tawait Promise.all([\n\t\t\trequireExerciseApp(params, cacheOptions),\n\t\t\tgetApps(cacheOptions),\n\t\t\tgetExerciseApp({ ...params, type: 'problem' }, cacheOptions),\n\t\t\tgetExerciseApp({ ...params, type: 'solution' }, cacheOptions),\n\t\t])\n\n\tconst playgroundApp = allAppsFull.find(isPlaygroundApp)\n\tconst reqUrl = new URL(request.url)\n\n\tconst pathnameParam = reqUrl.searchParams.get('pathname')\n\tif (pathnameParam === '' || pathnameParam === '/') {\n\t\treqUrl.searchParams.delete('pathname')\n\t\tthrow redirect(reqUrl.toString())\n\t}\n\n\tconst app1Name = reqUrl.searchParams.get('app1')\n\tconst app2Name = reqUrl.searchParams.get('app2')\n\tconst app1 = app1Name\n\t\t? await getAppByName(app1Name)\n\t\t: playgroundApp || problemApp\n\tconst app2 = app2Name ? await getAppByName(app2Name) : solutionApp\n\n\tfunction getStepId(a: ExerciseStepApp) {\n\t\treturn (\n\t\t\ta.exerciseNumber * 1000 +\n\t\t\ta.stepNumber * 10 +\n\t\t\t(a.type === 'problem' ? 0 : 1)\n\t\t)\n\t}\n\n\tfunction getStepNameAndId(a: App) {\n\t\tif (isExerciseStepApp(a)) {\n\t\t\tconst exerciseNumberStr = String(a.exerciseNumber).padStart(2, '0')\n\t\t\tconst stepNumberStr = String(a.stepNumber).padStart(2, '0')\n\n\t\t\treturn {\n\t\t\t\tstepName: `${exerciseNumberStr}/${stepNumberStr}.${a.type}`,\n\t\t\t\tstepId: getStepId(a),\n\t\t\t}\n\t\t}\n\t\treturn { stepName: '', stepId: -1 }\n\t}\n\n\tconst allApps = allAppsFull\n\t\t.filter((a, i, ar) => ar.findIndex((b) => a.name === b.name) === i)\n\t\t.map((a) => ({\n\t\t\tdisplayName: getAppDisplayName(a, allAppsFull),\n\t\t\tname: a.name,\n\t\t\ttitle: a.title,\n\t\t\ttype: a.type,\n\t\t\t...getStepNameAndId(a),\n\t\t}))\n\n\tallApps.sort((a, b) => {\n\t\t// order them by their stepId\n\t\tif (a.stepId > 0 && b.stepId > 0) return a.stepId - b.stepId\n\n\t\t// non-step apps should come after step apps\n\t\tif (a.stepId > 0) return -1\n\t\tif (b.stepId > 0) return 1\n\n\t\treturn 0\n\t})\n\n\tasync function getDiffProp() {\n\t\tif (!app1 || !app2) {\n\t\t\treturn {\n\t\t\t\tapp1: app1?.name,\n\t\t\t\tapp2: app2?.name,\n\t\t\t\tdiffCode: null,\n\t\t\t}\n\t\t}\n\t\tconst diffCode = await getDiffCode(app1, app2, {\n\t\t\t...cacheOptions,\n\t\t\tforceFresh: searchParams.get('forceFresh') === 'diff',\n\t\t}).catch((e) => {\n\t\t\tconsole.error(e)\n\t\t\treturn null\n\t\t})\n\t\treturn {\n\t\t\tapp1: app1.name,\n\t\t\tapp2: app2.name,\n\t\t\tdiffCode,\n\t\t}\n\t}\n\n\treturn data(\n\t\t{\n\t\t\ttype: params.type as 'problem' | 'solution',\n\t\t\texerciseStepApp,\n\t\t\tallApps,\n\t\t\t// defer this promise so that we don't block the response from being sent\n\t\t\tdiscordPostsPromise: fetchDiscordPosts({ request }),\n\t\t\tuserHasAccessPromise: userHasAccessToExerciseStep({\n\t\t\t\texerciseNumber: Number(params.exerciseNumber),\n\t\t\t\tstepNumber: Number(params.stepNumber),\n\t\t\t\trequest,\n\t\t\t\ttimings,\n\t\t\t}),\n\t\t\tplayground: playgroundApp\n\t\t\t\t? ({\n\t\t\t\t\t\ttype: 'playground',\n\t\t\t\t\t\tfullPath: playgroundApp.fullPath,\n\t\t\t\t\t\tdev: playgroundApp.dev,\n\t\t\t\t\t\ttest: playgroundApp.test,\n\t\t\t\t\t\ttitle: playgroundApp.title,\n\t\t\t\t\t\tname: playgroundApp.name,\n\t\t\t\t\t\tappName: playgroundApp.appName,\n\t\t\t\t\t\tisUpToDate: playgroundApp.isUpToDate,\n\t\t\t\t\t\tstackBlitzUrl: playgroundApp.stackBlitzUrl,\n\t\t\t\t\t\t...(await getAppRunningState(playgroundApp)),\n\t\t\t\t\t\t...getTestState(playgroundApp),\n\t\t\t\t\t} as const)\n\t\t\t\t: null,\n\t\t\tproblem: problemApp\n\t\t\t\t? ({\n\t\t\t\t\t\ttype: 'problem',\n\t\t\t\t\t\tfullPath: problemApp.fullPath,\n\t\t\t\t\t\tdev: problemApp.dev,\n\t\t\t\t\t\ttest: problemApp.test,\n\t\t\t\t\t\ttitle: problemApp.title,\n\t\t\t\t\t\tname: problemApp.name,\n\t\t\t\t\t\tstackBlitzUrl: problemApp.stackBlitzUrl,\n\t\t\t\t\t\t...(await getAppRunningState(problemApp)),\n\t\t\t\t\t} as const)\n\t\t\t\t: null,\n\t\t\tsolution: solutionApp\n\t\t\t\t? ({\n\t\t\t\t\t\ttype: 'solution',\n\t\t\t\t\t\tfullPath: solutionApp.fullPath,\n\t\t\t\t\t\tdev: solutionApp.dev,\n\t\t\t\t\t\ttest: solutionApp.test,\n\t\t\t\t\t\ttitle: solutionApp.title,\n\t\t\t\t\t\tname: solutionApp.name,\n\t\t\t\t\t\tstackBlitzUrl: solutionApp.stackBlitzUrl,\n\t\t\t\t\t\t...(await getAppRunningState(solutionApp)),\n\t\t\t\t\t} as const)\n\t\t\t\t: null,\n\t\t\tdiff: getDiffProp(),\n\t\t} as const,\n\t\t{\n\t\t\theaders: {\n\t\t\t\t'Server-Timing': getServerTimeHeader(timings),\n\t\t\t},\n\t\t},\n\t)\n}\n\nexport const headers: HeadersFunction = ({ loaderHeaders, parentHeaders }) => {\n\tconst headers = {\n\t\t'Server-Timing': combineServerTimings(loaderHeaders, parentHeaders),\n\t}\n\treturn headers\n}\n\nconst tabs = [\n\t'playground',\n\t'problem',\n\t'solution',\n\t'tests',\n\t'diff',\n\t'chat',\n] as const\nconst isValidPreview = (s: string | null): s is (typeof tabs)[number] =>\n\tBoolean(s && tabs.includes(s as (typeof tabs)[number]))\n\nexport default function ExercisePartRoute({\n\tloaderData,\n}: Route.ComponentProps) {\n\tconst { inBrowserBrowserRef } = useOutletContext<{\n\t\tinBrowserBrowserRef: React.RefObject<InBrowserBrowserRef | null>\n\t}>()\n\tconst workshopConfig = useWorkshopConfig()\n\tconst [searchParams] = useSearchParams()\n\n\tconst preview = searchParams.get('preview')\n\n\tconst altDown = useAltDown()\n\tconst navigate = useNavigate()\n\n\tfunction shouldHideTab(tab: (typeof tabs)[number]) {\n\t\tif (tab === 'tests') {\n\t\t\treturn (\n\t\t\t\tENV.EPICSHOP_DEPLOYED ||\n\t\t\t\t!loaderData.playground ||\n\t\t\t\tloaderData.playground.test.type === 'none'\n\t\t\t)\n\t\t}\n\t\tif (tab === 'problem' || tab === 'solution') {\n\t\t\tif (loaderData[tab]?.dev.type === 'none') return true\n\t\t\tif (ENV.EPICSHOP_DEPLOYED) {\n\t\t\t\tconst devType = loaderData[tab]?.dev.type\n\t\t\t\treturn (\n\t\t\t\t\tdevType !== 'browser' &&\n\t\t\t\t\tdevType !== 'export' &&\n\t\t\t\t\t!loaderData[tab]?.stackBlitzUrl\n\t\t\t\t)\n\t\t\t}\n\t\t}\n\t\tif (tab === 'playground' && ENV.EPICSHOP_DEPLOYED) return true\n\n\t\tif (tab === 'chat') {\n\t\t\treturn !workshopConfig.product.discordChannelId\n\t\t}\n\t\treturn false\n\t}\n\n\tfunction getTabStatus(\n\t\ttab: (typeof tabs)[number],\n\t): 'running' | 'passed' | 'failed' | null {\n\t\tif (tab === 'tests') {\n\t\t\tif (!loaderData.playground) return null\n\t\t\tconst { isTestRunning, testExitCode } = loaderData.playground\n\t\t\tif (isTestRunning) return 'running'\n\t\t\tif (testExitCode === 0) return 'passed'\n\t\t\tif (testExitCode !== null && testExitCode !== 0) return 'failed'\n\t\t\treturn null\n\t\t}\n\t\tif (tab === 'problem' || tab === 'solution' || tab === 'playground') {\n\t\t\tconst appData =\n\t\t\t\ttab === 'playground' ? loaderData.playground : loaderData[tab]\n\t\t\tif (appData?.isRunning) return 'running'\n\t\t}\n\t\treturn null\n\t}\n\n\tconst activeTab = isValidPreview(preview)\n\t\t? preview\n\t\t: tabs.find((t) => !shouldHideTab(t))\n\n\t// when alt is held down, the diff tab should open to the full-page diff view\n\t// between the problem and solution (this is more for the instructor than the student)\n\tconst altDiffUrl = `/diff?${new URLSearchParams({\n\t\tapp1: loaderData.problem?.name ?? '',\n\t\tapp2: loaderData.solution?.name ?? '',\n\t})}`\n\n\tfunction handleDiffTabClick(event: React.MouseEvent<HTMLAnchorElement>) {\n\t\tif (event.altKey && !event.ctrlKey && !event.shiftKey && !event.metaKey) {\n\t\t\tevent.preventDefault()\n\t\t\tvoid navigate(altDiffUrl)\n\t\t}\n\t}\n\n\tconst previewTabs = tabs.map((tab) => {\n\t\tconst hidden = shouldHideTab(tab)\n\t\tconst status = getTabStatus(tab)\n\t\tconst to =\n\t\t\ttab === 'diff' && altDown\n\t\t\t\t? altDiffUrl\n\t\t\t\t: `?${getPreviewSearchParams(searchParams, tab, 'playground')}`\n\t\treturn {\n\t\t\tid: tab,\n\t\t\tlabel: tab,\n\t\t\thidden,\n\t\t\tstatus,\n\t\t\tto,\n\t\t\tonClick: tab === 'diff' ? handleDiffTabClick : undefined,\n\t\t}\n\t})\n\n\treturn (\n\t\t<Tabs.Root\n\t\t\tclassName=\"relative flex min-h-0 min-w-0 flex-1 flex-col overflow-hidden sm:col-span-1 sm:row-span-1\"\n\t\t\tvalue={activeTab}\n\t\t\t// intentionally no onValueChange here because the Link will trigger the\n\t\t\t// change.\n\t\t>\n\t\t\t<PreviewTabsList tabs={previewTabs} />\n\t\t\t<div className=\"relative z-10 flex min-h-0 flex-1 flex-col overflow-hidden\">\n\t\t\t\t<Tabs.Content\n\t\t\t\t\tvalue=\"playground\"\n\t\t\t\t\tclassName=\"radix-state-inactive:hidden flex min-h-0 w-full grow basis-0 items-stretch justify-center self-start\"\n\t\t\t\t\tforceMount\n\t\t\t\t>\n\t\t\t\t\t<Playground\n\t\t\t\t\t\tappInfo={loaderData.playground}\n\t\t\t\t\t\tproblemAppName={loaderData.problem?.name}\n\t\t\t\t\t\tinBrowserBrowserRef={inBrowserBrowserRef}\n\t\t\t\t\t\tallApps={loaderData.allApps}\n\t\t\t\t\t\tisUpToDate={loaderData.playground?.isUpToDate ?? false}\n\t\t\t\t\t/>\n\t\t\t\t</Tabs.Content>\n\t\t\t\t<Tabs.Content\n\t\t\t\t\tvalue=\"problem\"\n\t\t\t\t\tclassName=\"radix-state-inactive:hidden flex min-h-0 w-full grow basis-0 items-stretch justify-center self-start\"\n\t\t\t\t\tforceMount\n\t\t\t\t>\n\t\t\t\t\t<Preview\n\t\t\t\t\t\tappInfo={loaderData.problem}\n\t\t\t\t\t\tinBrowserBrowserRef={inBrowserBrowserRef}\n\t\t\t\t\t/>\n\t\t\t\t</Tabs.Content>\n\t\t\t\t<Tabs.Content\n\t\t\t\t\tvalue=\"solution\"\n\t\t\t\t\tclassName=\"radix-state-inactive:hidden flex min-h-0 w-full grow basis-0 items-stretch justify-center self-start\"\n\t\t\t\t\tforceMount\n\t\t\t\t>\n\t\t\t\t\t<Preview\n\t\t\t\t\t\tappInfo={loaderData.solution}\n\t\t\t\t\t\tinBrowserBrowserRef={inBrowserBrowserRef}\n\t\t\t\t\t/>\n\t\t\t\t</Tabs.Content>\n\t\t\t\t<Tabs.Content\n\t\t\t\t\tvalue=\"tests\"\n\t\t\t\t\tclassName=\"radix-state-inactive:hidden flex min-h-0 w-full grow basis-0 items-stretch justify-center self-start overflow-hidden\"\n\t\t\t\t>\n\t\t\t\t\t<Tests\n\t\t\t\t\t\tappInfo={loaderData.playground}\n\t\t\t\t\t\tproblemAppName={loaderData.problem?.name}\n\t\t\t\t\t\tallApps={loaderData.allApps}\n\t\t\t\t\t\tisUpToDate={loaderData.playground?.isUpToDate ?? false}\n\t\t\t\t\t\tuserHasAccessPromise={loaderData.userHasAccessPromise}\n\t\t\t\t\t/>\n\t\t\t\t</Tabs.Content>\n\t\t\t\t<Tabs.Content\n\t\t\t\t\tvalue=\"diff\"\n\t\t\t\t\tclassName=\"radix-state-inactive:hidden flex h-full min-h-0 w-full grow basis-0 items-stretch justify-center self-start\"\n\t\t\t\t>\n\t\t\t\t\t<Diff\n\t\t\t\t\t\tdiff={loaderData.diff}\n\t\t\t\t\t\tallApps={loaderData.allApps}\n\t\t\t\t\t\tuserHasAccessPromise={loaderData.userHasAccessPromise}\n\t\t\t\t\t/>\n\t\t\t\t</Tabs.Content>\n\t\t\t\t<Tabs.Content\n\t\t\t\t\tvalue=\"chat\"\n\t\t\t\t\tclassName=\"radix-state-inactive:hidden flex h-full min-h-0 w-full grow basis-0 items-stretch justify-center self-start\"\n\t\t\t\t>\n\t\t\t\t\t<DiscordChat discordPostsPromise={loaderData.discordPostsPromise} />\n\t\t\t\t</Tabs.Content>\n\t\t\t</div>\n\t\t</Tabs.Root>\n\t)\n}\n\nexport function ErrorBoundary() {\n\treturn (\n\t\t<GeneralErrorBoundary\n\t\t\tstatusHandlers={{\n\t\t\t\t404: () => <p>Sorry, we couldn't find an app here.</p>,\n\t\t\t}}\n\t\t/>\n\t)\n}\n"],"names":["tabs","isValidPreview","s","Boolean","includes","index","_UNSAFE_withComponentProps","loaderData","inBrowserBrowserRef","useOutletContext","workshopConfig","useWorkshopConfig","searchParams","useSearchParams","preview","get","altDown","useAltDown","navigate","useNavigate","shouldHideTab","tab","ENV","EPICSHOP_DEPLOYED","playground","test","type","dev","devType","stackBlitzUrl","product","discordChannelId","getTabStatus","isTestRunning","testExitCode","isRunning","activeTab","find","t","altDiffUrl","URLSearchParams","app1","problem","name","app2","solution","handleDiffTabClick","event","altKey","ctrlKey","shiftKey","metaKey","preventDefault","previewTabs","map","hidden","status","to","getPreviewSearchParams","id","label","onClick","jsxs","Tabs","className","value","children","jsx","PreviewTabsList","forceMount","Playground","appInfo","problemAppName","allApps","isUpToDate","Preview","Tests","userHasAccessPromise","Diff","diff","DiscordChat","discordPostsPromise","ErrorBoundary","_UNSAFE_withErrorBoundaryProps","GeneralErrorBoundary","statusHandlers"],"mappings":"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"}
1
+ {"version":3,"file":"index-DkDXAMak.js","sources":["../../../app/routes/_app+/exercise+/$exerciseNumber_.$stepNumber.$type+/index.tsx"],"sourcesContent":["import {\n\tgetAppByName,\n\tgetAppDisplayName,\n\tgetApps,\n\tgetExerciseApp,\n\tisExerciseStepApp,\n\tisPlaygroundApp,\n\trequireExerciseApp,\n\ttype App,\n\ttype ExerciseStepApp,\n} from '@epic-web/workshop-utils/apps.server'\nimport { getDiffCode } from '@epic-web/workshop-utils/diff.server'\nimport { userHasAccessToExerciseStep } from '@epic-web/workshop-utils/epic-api.server'\nimport {\n\tcombineServerTimings,\n\tgetServerTimeHeader,\n\tmakeTimings,\n} from '@epic-web/workshop-utils/timing.server'\nimport * as Tabs from '@radix-ui/react-tabs'\nimport * as React from 'react'\nimport {\n\tuseNavigate,\n\tuseSearchParams,\n\tdata,\n\tredirect,\n\ttype HeadersFunction,\n\ttype LoaderFunctionArgs,\n\tuseOutletContext,\n} from 'react-router'\nimport { Diff } from '#app/components/diff.tsx'\nimport { DiscordChat } from '#app/components/discord-chat.tsx'\nimport { GeneralErrorBoundary } from '#app/components/error-boundary.tsx'\nimport { type InBrowserBrowserRef } from '#app/components/in-browser-browser.tsx'\nimport {\n\tgetPreviewSearchParams,\n\tPreviewTabsList,\n} from '#app/components/preview-tabs.tsx'\nimport { useWorkshopConfig } from '#app/components/workshop-config.tsx'\nimport { fetchDiscordPosts } from '#app/utils/discord.server.ts'\nimport { useAltDown } from '#app/utils/misc.tsx'\nimport { type Route } from './+types/index.ts'\nimport { Playground } from './__shared/playground.tsx'\nimport { Preview } from './__shared/preview.tsx'\nimport { Tests } from './__shared/tests.tsx'\nimport { getAppRunningState, getTestState } from './__shared/utils.tsx'\n\nexport async function loader({ request, params }: LoaderFunctionArgs) {\n\tconst timings = makeTimings('exerciseStepTypeIndexLoader')\n\tconst searchParams = new URL(request.url).searchParams\n\tconst cacheOptions = { request, timings }\n\n\tconst [exerciseStepApp, allAppsFull, problemApp, solutionApp] =\n\t\tawait Promise.all([\n\t\t\trequireExerciseApp(params, cacheOptions),\n\t\t\tgetApps(cacheOptions),\n\t\t\tgetExerciseApp({ ...params, type: 'problem' }, cacheOptions),\n\t\t\tgetExerciseApp({ ...params, type: 'solution' }, cacheOptions),\n\t\t])\n\n\tconst playgroundApp = allAppsFull.find(isPlaygroundApp)\n\tconst reqUrl = new URL(request.url)\n\n\tconst pathnameParam = reqUrl.searchParams.get('pathname')\n\tif (pathnameParam === '' || pathnameParam === '/') {\n\t\treqUrl.searchParams.delete('pathname')\n\t\tthrow redirect(reqUrl.toString())\n\t}\n\n\tconst app1Name = reqUrl.searchParams.get('app1')\n\tconst app2Name = reqUrl.searchParams.get('app2')\n\tconst app1 = app1Name\n\t\t? await getAppByName(app1Name)\n\t\t: playgroundApp || problemApp\n\tconst app2 = app2Name ? await getAppByName(app2Name) : solutionApp\n\n\tfunction getStepId(a: ExerciseStepApp) {\n\t\treturn (\n\t\t\ta.exerciseNumber * 1000 +\n\t\t\ta.stepNumber * 10 +\n\t\t\t(a.type === 'problem' ? 0 : 1)\n\t\t)\n\t}\n\n\tfunction getStepNameAndId(a: App) {\n\t\tif (isExerciseStepApp(a)) {\n\t\t\tconst exerciseNumberStr = String(a.exerciseNumber).padStart(2, '0')\n\t\t\tconst stepNumberStr = String(a.stepNumber).padStart(2, '0')\n\n\t\t\treturn {\n\t\t\t\tstepName: `${exerciseNumberStr}/${stepNumberStr}.${a.type}`,\n\t\t\t\tstepId: getStepId(a),\n\t\t\t}\n\t\t}\n\t\treturn { stepName: '', stepId: -1 }\n\t}\n\n\tconst allApps = allAppsFull\n\t\t.filter((a, i, ar) => ar.findIndex((b) => a.name === b.name) === i)\n\t\t.map((a) => ({\n\t\t\tdisplayName: getAppDisplayName(a, allAppsFull),\n\t\t\tname: a.name,\n\t\t\ttitle: a.title,\n\t\t\ttype: a.type,\n\t\t\t...getStepNameAndId(a),\n\t\t}))\n\n\tallApps.sort((a, b) => {\n\t\t// order them by their stepId\n\t\tif (a.stepId > 0 && b.stepId > 0) return a.stepId - b.stepId\n\n\t\t// non-step apps should come after step apps\n\t\tif (a.stepId > 0) return -1\n\t\tif (b.stepId > 0) return 1\n\n\t\treturn 0\n\t})\n\n\tasync function getDiffProp() {\n\t\tif (!app1 || !app2) {\n\t\t\treturn {\n\t\t\t\tapp1: app1?.name,\n\t\t\t\tapp2: app2?.name,\n\t\t\t\tdiffCode: null,\n\t\t\t}\n\t\t}\n\t\tconst diffCode = await getDiffCode(app1, app2, {\n\t\t\t...cacheOptions,\n\t\t\tforceFresh: searchParams.get('forceFresh') === 'diff',\n\t\t}).catch((e) => {\n\t\t\tconsole.error(e)\n\t\t\treturn null\n\t\t})\n\t\treturn {\n\t\t\tapp1: app1.name,\n\t\t\tapp2: app2.name,\n\t\t\tdiffCode,\n\t\t}\n\t}\n\n\treturn data(\n\t\t{\n\t\t\ttype: params.type as 'problem' | 'solution',\n\t\t\texerciseStepApp,\n\t\t\tallApps,\n\t\t\t// defer this promise so that we don't block the response from being sent\n\t\t\tdiscordPostsPromise: fetchDiscordPosts({ request }),\n\t\t\tuserHasAccessPromise: userHasAccessToExerciseStep({\n\t\t\t\texerciseNumber: Number(params.exerciseNumber),\n\t\t\t\tstepNumber: Number(params.stepNumber),\n\t\t\t\trequest,\n\t\t\t\ttimings,\n\t\t\t}),\n\t\t\tplayground: playgroundApp\n\t\t\t\t? ({\n\t\t\t\t\t\ttype: 'playground',\n\t\t\t\t\t\tfullPath: playgroundApp.fullPath,\n\t\t\t\t\t\tdev: playgroundApp.dev,\n\t\t\t\t\t\ttest: playgroundApp.test,\n\t\t\t\t\t\ttitle: playgroundApp.title,\n\t\t\t\t\t\tname: playgroundApp.name,\n\t\t\t\t\t\tappName: playgroundApp.appName,\n\t\t\t\t\t\tisUpToDate: playgroundApp.isUpToDate,\n\t\t\t\t\t\tstackBlitzUrl: playgroundApp.stackBlitzUrl,\n\t\t\t\t\t\t...(await getAppRunningState(playgroundApp)),\n\t\t\t\t\t\t...getTestState(playgroundApp),\n\t\t\t\t\t} as const)\n\t\t\t\t: null,\n\t\t\tproblem: problemApp\n\t\t\t\t? ({\n\t\t\t\t\t\ttype: 'problem',\n\t\t\t\t\t\tfullPath: problemApp.fullPath,\n\t\t\t\t\t\tdev: problemApp.dev,\n\t\t\t\t\t\ttest: problemApp.test,\n\t\t\t\t\t\ttitle: problemApp.title,\n\t\t\t\t\t\tname: problemApp.name,\n\t\t\t\t\t\tstackBlitzUrl: problemApp.stackBlitzUrl,\n\t\t\t\t\t\t...(await getAppRunningState(problemApp)),\n\t\t\t\t\t} as const)\n\t\t\t\t: null,\n\t\t\tsolution: solutionApp\n\t\t\t\t? ({\n\t\t\t\t\t\ttype: 'solution',\n\t\t\t\t\t\tfullPath: solutionApp.fullPath,\n\t\t\t\t\t\tdev: solutionApp.dev,\n\t\t\t\t\t\ttest: solutionApp.test,\n\t\t\t\t\t\ttitle: solutionApp.title,\n\t\t\t\t\t\tname: solutionApp.name,\n\t\t\t\t\t\tstackBlitzUrl: solutionApp.stackBlitzUrl,\n\t\t\t\t\t\t...(await getAppRunningState(solutionApp)),\n\t\t\t\t\t} as const)\n\t\t\t\t: null,\n\t\t\tdiff: getDiffProp(),\n\t\t} as const,\n\t\t{\n\t\t\theaders: {\n\t\t\t\t'Server-Timing': getServerTimeHeader(timings),\n\t\t\t},\n\t\t},\n\t)\n}\n\nexport const headers: HeadersFunction = ({ loaderHeaders, parentHeaders }) => {\n\tconst headers = {\n\t\t'Server-Timing': combineServerTimings(loaderHeaders, parentHeaders),\n\t}\n\treturn headers\n}\n\nconst tabs = [\n\t'playground',\n\t'problem',\n\t'solution',\n\t'tests',\n\t'diff',\n\t'chat',\n] as const\nconst isValidPreview = (s: string | null): s is (typeof tabs)[number] =>\n\tBoolean(s && tabs.includes(s as (typeof tabs)[number]))\n\nexport default function ExercisePartRoute({\n\tloaderData,\n}: Route.ComponentProps) {\n\tconst { inBrowserBrowserRef } = useOutletContext<{\n\t\tinBrowserBrowserRef: React.RefObject<InBrowserBrowserRef | null>\n\t}>()\n\tconst workshopConfig = useWorkshopConfig()\n\tconst [searchParams] = useSearchParams()\n\n\tconst preview = searchParams.get('preview')\n\n\tconst altDown = useAltDown()\n\tconst navigate = useNavigate()\n\n\tfunction shouldHideTab(tab: (typeof tabs)[number]) {\n\t\tif (tab === 'tests') {\n\t\t\treturn (\n\t\t\t\tENV.EPICSHOP_DEPLOYED ||\n\t\t\t\t!loaderData.playground ||\n\t\t\t\tloaderData.playground.test.type === 'none'\n\t\t\t)\n\t\t}\n\t\tif (tab === 'problem' || tab === 'solution') {\n\t\t\tif (loaderData[tab]?.dev.type === 'none') return true\n\t\t\tif (ENV.EPICSHOP_DEPLOYED) {\n\t\t\t\tconst devType = loaderData[tab]?.dev.type\n\t\t\t\treturn (\n\t\t\t\t\tdevType !== 'browser' &&\n\t\t\t\t\tdevType !== 'export' &&\n\t\t\t\t\t!loaderData[tab]?.stackBlitzUrl\n\t\t\t\t)\n\t\t\t}\n\t\t}\n\t\tif (tab === 'playground' && ENV.EPICSHOP_DEPLOYED) return true\n\n\t\tif (tab === 'chat') {\n\t\t\treturn !workshopConfig.product.discordChannelId\n\t\t}\n\t\treturn false\n\t}\n\n\tfunction getTabStatus(\n\t\ttab: (typeof tabs)[number],\n\t): 'running' | 'passed' | 'failed' | null {\n\t\tif (tab === 'tests') {\n\t\t\tif (!loaderData.playground) return null\n\t\t\tconst { isTestRunning, testExitCode } = loaderData.playground\n\t\t\tif (isTestRunning) return 'running'\n\t\t\tif (testExitCode === 0) return 'passed'\n\t\t\tif (testExitCode !== null && testExitCode !== 0) return 'failed'\n\t\t\treturn null\n\t\t}\n\t\tif (tab === 'problem' || tab === 'solution' || tab === 'playground') {\n\t\t\tconst appData =\n\t\t\t\ttab === 'playground' ? loaderData.playground : loaderData[tab]\n\t\t\tif (appData?.isRunning) return 'running'\n\t\t}\n\t\treturn null\n\t}\n\n\tconst activeTab = isValidPreview(preview)\n\t\t? preview\n\t\t: tabs.find((t) => !shouldHideTab(t))\n\n\t// when alt is held down, the diff tab should open to the full-page diff view\n\t// between the problem and solution (this is more for the instructor than the student)\n\tconst altDiffUrl = `/diff?${new URLSearchParams({\n\t\tapp1: loaderData.problem?.name ?? '',\n\t\tapp2: loaderData.solution?.name ?? '',\n\t})}`\n\n\tfunction handleDiffTabClick(event: React.MouseEvent<HTMLAnchorElement>) {\n\t\tif (event.altKey && !event.ctrlKey && !event.shiftKey && !event.metaKey) {\n\t\t\tevent.preventDefault()\n\t\t\tvoid navigate(altDiffUrl)\n\t\t}\n\t}\n\n\tconst previewTabs = tabs.map((tab) => {\n\t\tconst hidden = shouldHideTab(tab)\n\t\tconst status = getTabStatus(tab)\n\t\tconst to =\n\t\t\ttab === 'diff' && altDown\n\t\t\t\t? altDiffUrl\n\t\t\t\t: `?${getPreviewSearchParams(searchParams, tab, 'playground')}`\n\t\treturn {\n\t\t\tid: tab,\n\t\t\tlabel: tab,\n\t\t\thidden,\n\t\t\tstatus,\n\t\t\tto,\n\t\t\tonClick: tab === 'diff' ? handleDiffTabClick : undefined,\n\t\t}\n\t})\n\n\treturn (\n\t\t<Tabs.Root\n\t\t\tclassName=\"relative flex min-h-0 min-w-0 flex-1 flex-col overflow-hidden sm:col-span-1 sm:row-span-1\"\n\t\t\tvalue={activeTab}\n\t\t\t// intentionally no onValueChange here because the Link will trigger the\n\t\t\t// change.\n\t\t>\n\t\t\t<PreviewTabsList tabs={previewTabs} />\n\t\t\t<div className=\"relative z-10 flex min-h-0 flex-1 flex-col overflow-hidden\">\n\t\t\t\t<Tabs.Content\n\t\t\t\t\tvalue=\"playground\"\n\t\t\t\t\tclassName=\"radix-state-inactive:hidden flex min-h-0 w-full grow basis-0 items-stretch justify-center self-start\"\n\t\t\t\t\tforceMount\n\t\t\t\t>\n\t\t\t\t\t<Playground\n\t\t\t\t\t\tappInfo={loaderData.playground}\n\t\t\t\t\t\tproblemAppName={loaderData.problem?.name}\n\t\t\t\t\t\tinBrowserBrowserRef={inBrowserBrowserRef}\n\t\t\t\t\t\tallApps={loaderData.allApps}\n\t\t\t\t\t\tisUpToDate={loaderData.playground?.isUpToDate ?? false}\n\t\t\t\t\t/>\n\t\t\t\t</Tabs.Content>\n\t\t\t\t<Tabs.Content\n\t\t\t\t\tvalue=\"problem\"\n\t\t\t\t\tclassName=\"radix-state-inactive:hidden flex min-h-0 w-full grow basis-0 items-stretch justify-center self-start\"\n\t\t\t\t\tforceMount\n\t\t\t\t>\n\t\t\t\t\t<Preview\n\t\t\t\t\t\tappInfo={loaderData.problem}\n\t\t\t\t\t\tinBrowserBrowserRef={inBrowserBrowserRef}\n\t\t\t\t\t/>\n\t\t\t\t</Tabs.Content>\n\t\t\t\t<Tabs.Content\n\t\t\t\t\tvalue=\"solution\"\n\t\t\t\t\tclassName=\"radix-state-inactive:hidden flex min-h-0 w-full grow basis-0 items-stretch justify-center self-start\"\n\t\t\t\t\tforceMount\n\t\t\t\t>\n\t\t\t\t\t<Preview\n\t\t\t\t\t\tappInfo={loaderData.solution}\n\t\t\t\t\t\tinBrowserBrowserRef={inBrowserBrowserRef}\n\t\t\t\t\t/>\n\t\t\t\t</Tabs.Content>\n\t\t\t\t<Tabs.Content\n\t\t\t\t\tvalue=\"tests\"\n\t\t\t\t\tclassName=\"radix-state-inactive:hidden flex min-h-0 w-full grow basis-0 items-stretch justify-center self-start overflow-hidden\"\n\t\t\t\t>\n\t\t\t\t\t<Tests\n\t\t\t\t\t\tappInfo={loaderData.playground}\n\t\t\t\t\t\tproblemAppName={loaderData.problem?.name}\n\t\t\t\t\t\tallApps={loaderData.allApps}\n\t\t\t\t\t\tisUpToDate={loaderData.playground?.isUpToDate ?? false}\n\t\t\t\t\t\tuserHasAccessPromise={loaderData.userHasAccessPromise}\n\t\t\t\t\t/>\n\t\t\t\t</Tabs.Content>\n\t\t\t\t<Tabs.Content\n\t\t\t\t\tvalue=\"diff\"\n\t\t\t\t\tclassName=\"radix-state-inactive:hidden flex h-full min-h-0 w-full grow basis-0 items-stretch justify-center self-start\"\n\t\t\t\t>\n\t\t\t\t\t<Diff\n\t\t\t\t\t\tdiff={loaderData.diff}\n\t\t\t\t\t\tallApps={loaderData.allApps}\n\t\t\t\t\t\tuserHasAccessPromise={loaderData.userHasAccessPromise}\n\t\t\t\t\t/>\n\t\t\t\t</Tabs.Content>\n\t\t\t\t<Tabs.Content\n\t\t\t\t\tvalue=\"chat\"\n\t\t\t\t\tclassName=\"radix-state-inactive:hidden flex h-full min-h-0 w-full grow basis-0 items-stretch justify-center self-start\"\n\t\t\t\t>\n\t\t\t\t\t<DiscordChat discordPostsPromise={loaderData.discordPostsPromise} />\n\t\t\t\t</Tabs.Content>\n\t\t\t</div>\n\t\t</Tabs.Root>\n\t)\n}\n\nexport function ErrorBoundary() {\n\treturn (\n\t\t<GeneralErrorBoundary\n\t\t\tstatusHandlers={{\n\t\t\t\t404: () => <p>Sorry, we couldn't find an app here.</p>,\n\t\t\t}}\n\t\t/>\n\t)\n}\n"],"names":["tabs","isValidPreview","s","Boolean","includes","index","_UNSAFE_withComponentProps","loaderData","inBrowserBrowserRef","useOutletContext","workshopConfig","useWorkshopConfig","searchParams","useSearchParams","preview","get","altDown","useAltDown","navigate","useNavigate","shouldHideTab","tab","ENV","EPICSHOP_DEPLOYED","playground","test","type","dev","devType","stackBlitzUrl","product","discordChannelId","getTabStatus","isTestRunning","testExitCode","isRunning","activeTab","find","t","altDiffUrl","URLSearchParams","app1","problem","name","app2","solution","handleDiffTabClick","event","altKey","ctrlKey","shiftKey","metaKey","preventDefault","previewTabs","map","hidden","status","to","getPreviewSearchParams","id","label","onClick","jsxs","Tabs","className","value","children","jsx","PreviewTabsList","forceMount","Playground","appInfo","problemAppName","allApps","isUpToDate","Preview","Tests","userHasAccessPromise","Diff","diff","DiscordChat","discordPostsPromise","ErrorBoundary","_UNSAFE_withErrorBoundaryProps","GeneralErrorBoundary","statusHandlers"],"mappings":"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"}