@epic-web/workshop-app 4.2.8 → 4.2.9
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/build/client/assets/{_-CsdFvUbA.js → _-ByTWgb53.js} +2 -2
- package/build/client/assets/{_-CsdFvUbA.js.map → _-ByTWgb53.js.map} +1 -1
- package/build/client/assets/{_exerciseNumber-DWZNkWZM.js → _exerciseNumber-s_qbmGEJ.js} +2 -2
- package/build/client/assets/{_exerciseNumber-DWZNkWZM.js.map → _exerciseNumber-s_qbmGEJ.js.map} +1 -1
- package/build/client/assets/{_exerciseNumber_._stepNumber-P76hDsE6.js → _exerciseNumber_._stepNumber-D1wwEMQx.js} +2 -2
- package/build/client/assets/{_exerciseNumber_._stepNumber-P76hDsE6.js.map → _exerciseNumber_._stepNumber-D1wwEMQx.js.map} +1 -1
- package/build/client/assets/{_exerciseNumber_.finished-CpC-flTW.js → _exerciseNumber_.finished-DJgT9oaU.js} +2 -2
- package/build/client/assets/{_exerciseNumber_.finished-CpC-flTW.js.map → _exerciseNumber_.finished-DJgT9oaU.js.map} +1 -1
- package/build/client/assets/{_layout-BSoUgboG.js → _layout-49l6Rvwp.js} +2 -2
- package/build/client/assets/{_layout-BSoUgboG.js.map → _layout-49l6Rvwp.js.map} +1 -1
- package/build/client/assets/{_layout-DEZ-aTmx.js → _layout-BaPtC79F.js} +2 -2
- package/build/client/assets/{_layout-DEZ-aTmx.js.map → _layout-BaPtC79F.js.map} +1 -1
- package/build/client/assets/_layout-Bj9PyQQD.js +2 -0
- package/build/client/assets/{_layout-D1A2zp9y.js.map → _layout-Bj9PyQQD.js.map} +1 -1
- package/build/client/assets/{_layout-C8fK4Z98.js → _layout-D7Qo_r0X.js} +2 -2
- package/build/client/assets/{_layout-C8fK4Z98.js.map → _layout-D7Qo_r0X.js.map} +1 -1
- package/build/client/assets/{account-BeKnQB9r.js → account-Bk4o4AzZ.js} +2 -2
- package/build/client/assets/{account-BeKnQB9r.js.map → account-Bk4o4AzZ.js.map} +1 -1
- package/build/client/assets/{button-Da1iG51o.js → button-DnQOyJAN.js} +2 -2
- package/build/client/assets/{button-Da1iG51o.js.map → button-DnQOyJAN.js.map} +1 -1
- package/build/client/assets/{client-hints-B2pbEa_9.js → client-hints-KnbHFIgn.js} +2 -2
- package/build/client/assets/{client-hints-B2pbEa_9.js.map → client-hints-KnbHFIgn.js.map} +1 -1
- package/build/client/assets/{components-BM_XUa9h.js → components-Dj3sm47B.js} +15 -15
- package/build/client/assets/{components-BM_XUa9h.js.map → components-Dj3sm47B.js.map} +1 -1
- package/build/client/assets/diff-CLRdJhCn.js +2 -0
- package/build/client/assets/{diff-BDeBUdSw.js.map → diff-CLRdJhCn.js.map} +1 -1
- package/build/client/assets/{diff-BQhWtDyS.js → diff-CT3-9rtW.js} +2 -2
- package/build/client/assets/{diff-BQhWtDyS.js.map → diff-CT3-9rtW.js.map} +1 -1
- package/build/client/assets/discord-CK7yz4w6.js +2 -0
- package/build/client/assets/discord-CK7yz4w6.js.map +1 -0
- package/build/client/assets/{discord-BMNnObT9.js → discord-CsluX01E.js} +2 -2
- package/build/client/assets/{discord-BMNnObT9.js.map → discord-CsluX01E.js.map} +1 -1
- package/build/client/assets/{entry.client-XC5tKTFs.js → entry.client-DBBrAxtJ.js} +2 -2
- package/build/client/assets/{entry.client-XC5tKTFs.js.map → entry.client-DBBrAxtJ.js.map} +1 -1
- package/build/client/assets/{epic-video-CxRPT-8l.js → epic-video-Df7qGSN7.js} +2 -2
- package/build/client/assets/{epic-video-CxRPT-8l.js.map → epic-video-Df7qGSN7.js.map} +1 -1
- package/build/client/assets/{error-boundary-tJSWbP6w.js → error-boundary-Bg54_knF.js} +2 -2
- package/build/client/assets/{error-boundary-tJSWbP6w.js.map → error-boundary-Bg54_knF.js.map} +1 -1
- package/build/client/assets/{finished-CMGRmsnb.js → finished-Dw3SJA8A.js} +2 -2
- package/build/client/assets/{finished-CMGRmsnb.js.map → finished-Dw3SJA8A.js.map} +1 -1
- package/build/client/assets/{index-B8G3eD8F.js → index-BL4aE6WC.js} +2 -2
- package/build/client/assets/{index-B8G3eD8F.js.map → index-BL4aE6WC.js.map} +1 -1
- package/build/client/assets/{index-BymJEf3X.js → index-BfoHqrT5.js} +2 -2
- package/build/client/assets/{index-BymJEf3X.js.map → index-BfoHqrT5.js.map} +1 -1
- package/build/client/assets/{index-Dc59VwXx.js → index-CLnz0tXz.js} +2 -2
- package/build/client/assets/{index-Dc59VwXx.js.map → index-CLnz0tXz.js.map} +1 -1
- package/build/client/assets/index-D1WEsmVZ.js +36 -0
- package/build/client/assets/{index-BDqSZ0-h.js.map → index-D1WEsmVZ.js.map} +1 -1
- package/build/client/assets/{index-CQZ5FyEE.js → index-YgRENgjt.js} +2 -2
- package/build/client/assets/{index-CQZ5FyEE.js.map → index-YgRENgjt.js.map} +1 -1
- package/build/client/assets/{loading-DsjO-T0W.js → loading-D-DClzm1.js} +2 -2
- package/build/client/assets/{loading-DsjO-T0W.js.map → loading-D-DClzm1.js.map} +1 -1
- package/build/client/assets/{login-CcuvIoiW.js → login-CjvZj820.js} +2 -2
- package/build/client/assets/{login-CcuvIoiW.js.map → login-CjvZj820.js.map} +1 -1
- package/build/client/assets/{manifest-1656ae4d.js → manifest-db6261a7.js} +1 -1
- package/build/client/assets/mdx-ytg-y2nh.js +2 -0
- package/build/client/assets/{mdx-CZ_BPVoS.js.map → mdx-ytg-y2nh.js.map} +1 -1
- package/build/client/assets/misc-CXGQ7VS9.js +2 -0
- package/build/client/assets/{misc-C1rq7sPa.js.map → misc-CXGQ7VS9.js.map} +1 -1
- package/build/client/assets/{nav-chevrons-C-dN3WfT.js → nav-chevrons-D8c9lJW6.js} +2 -2
- package/build/client/assets/{nav-chevrons-C-dN3WfT.js.map → nav-chevrons-D8c9lJW6.js.map} +1 -1
- package/build/client/assets/{onboarding-CfXLKsN3.js → onboarding-BxcIdiGj.js} +2 -2
- package/build/client/assets/{onboarding-CfXLKsN3.js.map → onboarding-BxcIdiGj.js.map} +1 -1
- package/build/client/assets/{presence-BF7lWuVd.js → presence-u-05JV3Z.js} +2 -2
- package/build/client/assets/{presence-BF7lWuVd.js.map → presence-u-05JV3Z.js.map} +1 -1
- package/build/client/assets/{progress-mfa_5CZx.js → progress-CBZt2pmu.js} +2 -2
- package/build/client/assets/{progress-mfa_5CZx.js.map → progress-CBZt2pmu.js.map} +1 -1
- package/build/client/assets/{progress-bar-BmszwN_j.js → progress-bar-DX6yYES2.js} +2 -2
- package/build/client/assets/{progress-bar-BmszwN_j.js.map → progress-bar-DX6yYES2.js.map} +1 -1
- package/build/client/assets/{root-1Cc21xa6.js → root-B02acrJe.js} +2 -2
- package/build/client/assets/{root-1Cc21xa6.js.map → root-B02acrJe.js.map} +1 -1
- package/build/client/assets/{support--jou3sWH.js → support-QTdmLyE7.js} +2 -2
- package/build/client/assets/{support--jou3sWH.js.map → support-QTdmLyE7.js.map} +1 -1
- package/build/client/assets/{tooltip-BlVFw-is.js → tooltip-CVFWPOu0.js} +2 -2
- package/build/client/assets/{tooltip-BlVFw-is.js.map → tooltip-CVFWPOu0.js.map} +1 -1
- package/build/client/assets/{use-event-source-DPLyo0Bh.js → use-event-source-DXlRuRq2.js} +2 -2
- package/build/client/assets/{use-event-source-DPLyo0Bh.js.map → use-event-source-DXlRuRq2.js.map} +1 -1
- package/build/client/assets/{user-p2QVtDZI.js → user-DiGtbaa7.js} +2 -2
- package/build/client/assets/{user-p2QVtDZI.js.map → user-DiGtbaa7.js.map} +1 -1
- package/build/server/index.js +3 -2
- package/build/server/index.js.map +1 -1
- package/package.json +3 -3
- package/build/client/assets/_layout-D1A2zp9y.js +0 -2
- package/build/client/assets/diff-BDeBUdSw.js +0 -2
- package/build/client/assets/discord-DdAReDkL.js +0 -2
- package/build/client/assets/discord-DdAReDkL.js.map +0 -1
- package/build/client/assets/index-BDqSZ0-h.js +0 -36
- package/build/client/assets/mdx-CZ_BPVoS.js +0 -2
- package/build/client/assets/misc-C1rq7sPa.js +0 -2
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import{c as b,j as e}from"./index-
|
|
2
|
-
//# sourceMappingURL=_layout-
|
|
1
|
+
import{c as b,j as e}from"./index-D1WEsmVZ.js";import{I as m}from"./misc-CXGQ7VS9.js";import{S as f}from"./tooltip-CVFWPOu0.js";import{a as g}from"./progress-CBZt2pmu.js";import{u as N,L as i,F as c}from"./components-Dj3sm47B.js";import"./clsx-B-dksMZM.js";const L=({matches:n})=>{var r;const l=(r=n.find(o=>o.id==="root"))==null?void 0:r.data;return[{title:`👷 | ${l==null?void 0:l.workshopTitle}`}]};function S(n,l){return n.type==="unknown"&&l.type==="unknown"?0:n.type==="unknown"?-1:l.type==="unknown"?1:0}function w(n){switch(n.type){case"workshop-instructions":return"/";case"workshop-finished":return"/finished";case"instructions":return`/${n.exerciseNumber.toString().padStart(2,"0")}`;case"step":return`/${n.exerciseNumber.toString().padStart(2,"0")}/${n.stepNumber.toString().padStart(2,"0")}`;case"finished":return`/${n.exerciseNumber.toString().padStart(2,"0")}/finished`;default:return""}}function T(){var a,d;const n=N(),l=b(),r=g(),o=((a=l.formData)==null?void 0:a.get("intent"))==="inspect",u=((d=l.formData)==null?void 0:d.get("intent"))==="stop-inspect",j={completed:"bg-blue-500",incomplete:"bg-yellow-500"};return e.jsxs("main",{className:"container mx-auto mt-8",children:[e.jsx("h1",{className:"text-4xl font-bold",children:"Admin"}),e.jsxs("div",{className:"flex flex-col gap-4",children:[e.jsx("nav",{children:e.jsxs("ul",{className:"flex gap-3",children:[e.jsx("li",{children:e.jsx(i,{className:"underline",to:"/",children:"Home"})}),e.jsx("li",{children:e.jsx(i,{className:"underline",to:"/diff",children:"Diff Viewer"})})]})}),e.jsxs("div",{children:[e.jsx("h2",{className:"text-lg font-bold",children:"Progress"}),r?e.jsx("ul",{className:"flex max-h-72 flex-col gap-2 overflow-y-scroll border-2 p-8 scrollbar-thin scrollbar-thumb-scrollbar",children:r.sort(S).map(s=>{const t=`https://www.epicweb.dev/workshops/${n.workshopSlug}/${s.epicSectionSlug}/${s.epicLessonSlug}`,p=s.epicCompletedAt?"completed":"incomplete",h=[`${s.epicSectionSlug}/${s.epicLessonSlug}`,s.epicCompletedAt?`(${s.epicCompletedAt})`:null].filter(Boolean).join(" ");return e.jsxs("li",{className:"flex items-center gap-2",children:[e.jsx("span",{className:`h-3 w-3 rounded-full ${j[p]}`,title:p}),s.type==="unknown"?e.jsxs("span",{className:"flex items-center gap-1",children:[h,e.jsx("span",{className:"text-red-500",children:e.jsx(f,{content:"This video is in the workshop on EpicWeb.dev, but not in the local workshop.",children:e.jsx(m,{name:"Close"})})})]}):e.jsx(i,{to:w(s),children:h}),e.jsx(i,{to:t,children:e.jsx(m,{name:"ExternalLink"})})]},s.epicLessonSlug)})}):e.jsx("p",{children:"No progress data"})]}),e.jsxs("div",{children:[e.jsx("h2",{className:"text-lg font-bold",children:"Commands"}),e.jsxs("ul",{className:"max-h-48 overflow-y-scroll border-2 p-8 scrollbar-thin scrollbar-thumb-scrollbar",children:[e.jsx("li",{children:e.jsx(c,{method:"POST",children:e.jsx("button",{name:"intent",value:"clear-caches",children:"Clear local caches"})})}),e.jsx("li",{children:e.jsx(c,{method:"POST",children:e.jsx("button",{name:"intent",value:"clear-data",children:"Clear all local data (including auth data)"})})}),e.jsx("li",{children:n.inspectorRunning?e.jsx(c,{method:"POST",children:e.jsx("button",{name:"intent",value:"stop-inspect",children:o?"Stopping inspector...":"Stop inspector"})}):e.jsx(c,{method:"POST",children:e.jsx("button",{name:"intent",value:"inspect",children:u?"Starting inspector...":"Start inspector"})})})]})]}),e.jsxs("div",{children:[e.jsx("h2",{className:"text-lg font-bold",children:"Apps"}),e.jsx("ul",{className:"max-h-48 list-none overflow-y-scroll border-2 p-8 scrollbar-thin scrollbar-thumb-scrollbar",children:n.apps.map(s=>e.jsxs("li",{className:"flex items-center gap-2 py-1",children:[n.processes[s.name]?e.jsx(x,{status:"running"}):e.jsx(x,{status:"stopped"}),s.name]},s.name))})]}),e.jsxs("div",{children:[e.jsx("h2",{className:"text-lg font-bold",children:"Processes"}),e.jsx("ul",{className:"overflow-y-scroll border-2 p-8 scrollbar-thin scrollbar-thumb-scrollbar",children:Object.entries(n.processes).map(([s,t])=>e.jsx("li",{children:e.jsxs("span",{children:[s," - Port: ",t.port," - PID ",t.pid," -"," ",t.color]})},s))})]}),e.jsxs("div",{children:[e.jsx("h2",{className:"text-lg font-bold",children:"Test Processes"}),e.jsx("ul",{className:"overflow-y-scroll border-2 p-8 scrollbar-thin scrollbar-thumb-scrollbar",children:Object.entries(n.testProcesses).map(([s,t])=>e.jsx("li",{children:e.jsxs("span",{children:[s," - PID ",t.pid," - Exit code: ",t.exitCode]})},s))})]})]})]})}function x({status:n}){const l={running:{pinger:"bg-green-400",circle:"bg-green-500"},starting:{pinger:"bg-sky-400",circle:"bg-sky-500"},stopped:{circle:"bg-gray-500"},taken:{pinger:"bg-red-400",circle:"bg-red-500"}}[n];return e.jsxs("span",{className:"relative flex h-3 w-3",children:[l.pinger?e.jsx("span",{className:`absolute inline-flex h-full w-full animate-ping rounded-full ${l.pinger} opacity-75`}):null,e.jsx("span",{className:`relative inline-flex h-3 w-3 rounded-full ${l.circle}`})]})}export{T as default,L as meta};
|
|
2
|
+
//# sourceMappingURL=_layout-BaPtC79F.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"_layout-DEZ-aTmx.js","sources":["../../../app/routes/admin+/_layout.tsx"],"sourcesContent":["import {\n\tgetApps,\n\tgetEpicWorkshopSlug,\n} from '@epic-web/workshop-utils/apps.server'\nimport { getProcesses } from '@epic-web/workshop-utils/process-manager.server'\nimport {\n\tgetServerTimeHeader,\n\tmakeTimings,\n} from '@epic-web/workshop-utils/timing.server'\nimport {\n\ttype ActionFunctionArgs,\n\ttype LoaderFunctionArgs,\n\ttype MetaFunction,\n\tjson,\n} from '@remix-run/node'\nimport { Form, Link, useLoaderData, useNavigation } from '@remix-run/react'\nimport {\n\tclearCaches,\n\tclearData,\n\tstartInspector,\n\tstopInspector,\n} from './admin-utils.server.tsx'\nimport { Icon } from '#app/components/icons.tsx'\nimport { SimpleTooltip } from '#app/components/ui/tooltip.tsx'\nimport { type loader as rootLoader } from '#app/root.tsx'\nimport {\n\ttype SerializedProgress,\n\tuseEpicProgress,\n} from '#app/routes/progress.tsx'\nimport { ensureUndeployed } from '#app/utils/misc.tsx'\n\ndeclare global {\n\tvar __inspector_open__: boolean | undefined\n}\n\nexport const meta: MetaFunction<typeof loader, { root: typeof rootLoader }> = ({\n\tmatches,\n}) => {\n\t// eslint-disable-next-line @typescript-eslint/no-unnecessary-condition\n\tconst rootData = matches.find(m => m.id === 'root')?.data\n\treturn [{ title: `👷 | ${rootData?.workshopTitle}` }]\n}\n\nexport async function loader({ request }: LoaderFunctionArgs) {\n\tensureUndeployed()\n\tconst timings = makeTimings('adminLoader')\n\tconst workshopSlug = (await getEpicWorkshopSlug()) ?? 'Unkown'\n\tconst apps = (await getApps({ request, timings })).filter(\n\t\t(a, i, ar) => ar.findIndex(b => a.name === b.name) === i,\n\t)\n\tconst processes: Record<\n\t\tstring,\n\t\t{ port: number; pid?: number; color: string }\n\t> = {}\n\tconst testProcesses: Record<\n\t\tstring,\n\t\t{ pid?: number; exitCode?: number | null }\n\t> = {}\n\tfor (const [\n\t\tname,\n\t\t{ port, process, color },\n\t] of getProcesses().devProcesses.entries()) {\n\t\tprocesses[name] = { port, pid: process.pid, color }\n\t}\n\n\tfor (const [\n\t\tname,\n\t\t{ process, exitCode },\n\t] of getProcesses().testProcesses.entries()) {\n\t\ttestProcesses[name] = { pid: process?.pid, exitCode }\n\t}\n\treturn json(\n\t\t{\n\t\t\tapps,\n\t\t\tprocesses,\n\t\t\tworkshopSlug,\n\t\t\ttestProcesses,\n\t\t\tinspectorRunning: global.__inspector_open__,\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 async function action({ request }: ActionFunctionArgs) {\n\tensureUndeployed()\n\tconst formData = await request.formData()\n\tconst intent = formData.get('intent')\n\tswitch (intent) {\n\t\tcase 'clear-data': {\n\t\t\tawait clearData()\n\t\t\treturn json({ success: true })\n\t\t}\n\t\tcase 'clear-caches': {\n\t\t\tawait clearCaches()\n\t\t\treturn json({ success: true })\n\t\t}\n\t\tcase 'inspect': {\n\t\t\tawait startInspector()\n\t\t\treturn json({ success: true })\n\t\t}\n\t\tcase 'stop-inspect': {\n\t\t\tawait stopInspector()\n\t\t\treturn json({ success: true })\n\t\t}\n\t\tdefault: {\n\t\t\tthrow new Error(`Unknown intent: ${intent}`)\n\t\t}\n\t}\n}\n\nfunction sortProgress(a: SerializedProgress, b: SerializedProgress) {\n\treturn a.type === 'unknown' && b.type === 'unknown'\n\t\t? 0\n\t\t: a.type === 'unknown'\n\t\t\t? -1\n\t\t\t: b.type === 'unknown'\n\t\t\t\t? 1\n\t\t\t\t: 0\n}\n\nfunction linkProgress(progress: SerializedProgress) {\n\tswitch (progress.type) {\n\t\tcase 'workshop-instructions':\n\t\t\treturn '/'\n\t\tcase 'workshop-finished':\n\t\t\treturn '/finished'\n\t\tcase 'instructions':\n\t\t\treturn `/${progress.exerciseNumber.toString().padStart(2, '0')}`\n\t\tcase 'step':\n\t\t\treturn `/${progress.exerciseNumber\n\t\t\t\t.toString()\n\t\t\t\t.padStart(2, '0')}/${progress.stepNumber.toString().padStart(2, '0')}`\n\t\tcase 'finished':\n\t\t\treturn `/${progress.exerciseNumber.toString().padStart(2, '0')}/finished`\n\t\tdefault:\n\t\t\treturn ''\n\t}\n}\n\nexport default function AdminLayout() {\n\tconst data = useLoaderData<typeof loader>()\n\tconst navigation = useNavigation()\n\tconst epicProgress = useEpicProgress()\n\n\tconst isStartingInspector = navigation.formData?.get('intent') === 'inspect'\n\tconst isStoppingInspector =\n\t\tnavigation.formData?.get('intent') === 'stop-inspect'\n\n\tconst progressStatus = {\n\t\tcompleted: 'bg-blue-500',\n\t\tincomplete: 'bg-yellow-500',\n\t}\n\n\treturn (\n\t\t<main className=\"container mx-auto mt-8\">\n\t\t\t<h1 className=\"text-4xl font-bold\">Admin</h1>\n\t\t\t<div className=\"flex flex-col gap-4\">\n\t\t\t\t<nav>\n\t\t\t\t\t<ul className=\"flex gap-3\">\n\t\t\t\t\t\t<li>\n\t\t\t\t\t\t\t<Link className=\"underline\" to=\"/\">\n\t\t\t\t\t\t\t\tHome\n\t\t\t\t\t\t\t</Link>\n\t\t\t\t\t\t</li>\n\t\t\t\t\t\t<li>\n\t\t\t\t\t\t\t<Link className=\"underline\" to=\"/diff\">\n\t\t\t\t\t\t\t\tDiff Viewer\n\t\t\t\t\t\t\t</Link>\n\t\t\t\t\t\t</li>\n\t\t\t\t\t</ul>\n\t\t\t\t</nav>\n\t\t\t\t<div>\n\t\t\t\t\t<h2 className=\"text-lg font-bold\">Progress</h2>\n\t\t\t\t\t{epicProgress ? (\n\t\t\t\t\t\t<ul className=\"flex max-h-72 flex-col gap-2 overflow-y-scroll border-2 p-8 scrollbar-thin scrollbar-thumb-scrollbar\">\n\t\t\t\t\t\t\t{epicProgress.sort(sortProgress).map(progress => {\n\t\t\t\t\t\t\t\tconst epicUrl = `https://www.epicweb.dev/workshops/${data.workshopSlug}/${progress.epicSectionSlug}/${progress.epicLessonSlug}`\n\t\t\t\t\t\t\t\tconst status = progress.epicCompletedAt\n\t\t\t\t\t\t\t\t\t? 'completed'\n\t\t\t\t\t\t\t\t\t: 'incomplete'\n\t\t\t\t\t\t\t\tconst label = [\n\t\t\t\t\t\t\t\t\t`${progress.epicSectionSlug}/${progress.epicLessonSlug}`,\n\t\t\t\t\t\t\t\t\tprogress.epicCompletedAt\n\t\t\t\t\t\t\t\t\t\t? `(${progress.epicCompletedAt})`\n\t\t\t\t\t\t\t\t\t\t: null,\n\t\t\t\t\t\t\t\t]\n\t\t\t\t\t\t\t\t\t.filter(Boolean)\n\t\t\t\t\t\t\t\t\t.join(' ')\n\t\t\t\t\t\t\t\treturn (\n\t\t\t\t\t\t\t\t\t<li\n\t\t\t\t\t\t\t\t\t\tkey={progress.epicLessonSlug}\n\t\t\t\t\t\t\t\t\t\tclassName=\"flex items-center gap-2\"\n\t\t\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t\t\t<span\n\t\t\t\t\t\t\t\t\t\t\tclassName={`h-3 w-3 rounded-full ${progressStatus[status]}`}\n\t\t\t\t\t\t\t\t\t\t\ttitle={status}\n\t\t\t\t\t\t\t\t\t\t/>\n\t\t\t\t\t\t\t\t\t\t{progress.type === 'unknown' ? (\n\t\t\t\t\t\t\t\t\t\t\t<span className=\"flex items-center gap-1\">\n\t\t\t\t\t\t\t\t\t\t\t\t{label}\n\t\t\t\t\t\t\t\t\t\t\t\t<span className=\"text-red-500\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t<SimpleTooltip content=\"This video is in the workshop on EpicWeb.dev, but not in the local workshop.\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t<Icon name=\"Close\" />\n\t\t\t\t\t\t\t\t\t\t\t\t\t</SimpleTooltip>\n\t\t\t\t\t\t\t\t\t\t\t\t</span>\n\t\t\t\t\t\t\t\t\t\t\t</span>\n\t\t\t\t\t\t\t\t\t\t) : (\n\t\t\t\t\t\t\t\t\t\t\t<Link to={linkProgress(progress)}>{label}</Link>\n\t\t\t\t\t\t\t\t\t\t)}\n\t\t\t\t\t\t\t\t\t\t<Link to={epicUrl}>\n\t\t\t\t\t\t\t\t\t\t\t<Icon name=\"ExternalLink\"></Icon>\n\t\t\t\t\t\t\t\t\t\t</Link>\n\t\t\t\t\t\t\t\t\t</li>\n\t\t\t\t\t\t\t\t)\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>No progress data</p>\n\t\t\t\t\t)}\n\t\t\t\t</div>\n\t\t\t\t<div>\n\t\t\t\t\t<h2 className=\"text-lg font-bold\">Commands</h2>\n\t\t\t\t\t<ul className=\"max-h-48 overflow-y-scroll border-2 p-8 scrollbar-thin scrollbar-thumb-scrollbar\">\n\t\t\t\t\t\t<li>\n\t\t\t\t\t\t\t<Form method=\"POST\">\n\t\t\t\t\t\t\t\t<button name=\"intent\" value=\"clear-caches\">\n\t\t\t\t\t\t\t\t\tClear local caches\n\t\t\t\t\t\t\t\t</button>\n\t\t\t\t\t\t\t</Form>\n\t\t\t\t\t\t</li>\n\t\t\t\t\t\t<li>\n\t\t\t\t\t\t\t<Form method=\"POST\">\n\t\t\t\t\t\t\t\t<button name=\"intent\" value=\"clear-data\">\n\t\t\t\t\t\t\t\t\tClear all local data (including auth data)\n\t\t\t\t\t\t\t\t</button>\n\t\t\t\t\t\t\t</Form>\n\t\t\t\t\t\t</li>\n\t\t\t\t\t\t<li>\n\t\t\t\t\t\t\t{data.inspectorRunning ? (\n\t\t\t\t\t\t\t\t<Form method=\"POST\">\n\t\t\t\t\t\t\t\t\t<button name=\"intent\" value=\"stop-inspect\">\n\t\t\t\t\t\t\t\t\t\t{isStartingInspector\n\t\t\t\t\t\t\t\t\t\t\t? 'Stopping inspector...'\n\t\t\t\t\t\t\t\t\t\t\t: 'Stop inspector'}\n\t\t\t\t\t\t\t\t\t</button>\n\t\t\t\t\t\t\t\t</Form>\n\t\t\t\t\t\t\t) : (\n\t\t\t\t\t\t\t\t<Form method=\"POST\">\n\t\t\t\t\t\t\t\t\t<button name=\"intent\" value=\"inspect\">\n\t\t\t\t\t\t\t\t\t\t{isStoppingInspector\n\t\t\t\t\t\t\t\t\t\t\t? 'Starting inspector...'\n\t\t\t\t\t\t\t\t\t\t\t: 'Start inspector'}\n\t\t\t\t\t\t\t\t\t</button>\n\t\t\t\t\t\t\t\t</Form>\n\t\t\t\t\t\t\t)}\n\t\t\t\t\t\t</li>\n\t\t\t\t\t</ul>\n\t\t\t\t</div>\n\t\t\t\t<div>\n\t\t\t\t\t<h2 className=\"text-lg font-bold\">Apps</h2>\n\t\t\t\t\t<ul className=\"max-h-48 list-none overflow-y-scroll border-2 p-8 scrollbar-thin scrollbar-thumb-scrollbar\">\n\t\t\t\t\t\t{data.apps.map(app => (\n\t\t\t\t\t\t\t<li key={app.name} className=\"flex items-center gap-2 py-1\">\n\t\t\t\t\t\t\t\t{data.processes[app.name] ? (\n\t\t\t\t\t\t\t\t\t<Pinger status=\"running\" />\n\t\t\t\t\t\t\t\t) : (\n\t\t\t\t\t\t\t\t\t<Pinger status=\"stopped\" />\n\t\t\t\t\t\t\t\t)}\n\t\t\t\t\t\t\t\t{app.name}\n\t\t\t\t\t\t\t</li>\n\t\t\t\t\t\t))}\n\t\t\t\t\t</ul>\n\t\t\t\t</div>\n\t\t\t\t<div>\n\t\t\t\t\t<h2 className=\"text-lg font-bold\">Processes</h2>\n\t\t\t\t\t<ul className=\"overflow-y-scroll border-2 p-8 scrollbar-thin scrollbar-thumb-scrollbar\">\n\t\t\t\t\t\t{Object.entries(data.processes).map(([key, process]) => (\n\t\t\t\t\t\t\t<li key={key}>\n\t\t\t\t\t\t\t\t<span>\n\t\t\t\t\t\t\t\t\t{key} - Port: {process.port} - PID {process.pid} -{' '}\n\t\t\t\t\t\t\t\t\t{process.color}\n\t\t\t\t\t\t\t\t</span>\n\t\t\t\t\t\t\t</li>\n\t\t\t\t\t\t))}\n\t\t\t\t\t</ul>\n\t\t\t\t</div>\n\t\t\t\t<div>\n\t\t\t\t\t<h2 className=\"text-lg font-bold\">Test Processes</h2>\n\t\t\t\t\t<ul className=\"overflow-y-scroll border-2 p-8 scrollbar-thin scrollbar-thumb-scrollbar\">\n\t\t\t\t\t\t{Object.entries(data.testProcesses).map(([key, process]) => (\n\t\t\t\t\t\t\t<li key={key}>\n\t\t\t\t\t\t\t\t<span>\n\t\t\t\t\t\t\t\t\t{key} - PID {process.pid} - Exit code: {process.exitCode}\n\t\t\t\t\t\t\t\t</span>\n\t\t\t\t\t\t\t</li>\n\t\t\t\t\t\t))}\n\t\t\t\t\t</ul>\n\t\t\t\t</div>\n\t\t\t</div>\n\t\t</main>\n\t)\n}\n\nfunction Pinger({\n\tstatus,\n}: {\n\tstatus: 'running' | 'starting' | 'stopped' | 'taken'\n}) {\n\tconst colors = {\n\t\trunning: {\n\t\t\tpinger: 'bg-green-400',\n\t\t\tcircle: 'bg-green-500',\n\t\t},\n\t\tstarting: {\n\t\t\tpinger: 'bg-sky-400',\n\t\t\tcircle: 'bg-sky-500',\n\t\t},\n\t\tstopped: {\n\t\t\tcircle: 'bg-gray-500',\n\t\t},\n\t\ttaken: {\n\t\t\tpinger: 'bg-red-400',\n\t\t\tcircle: 'bg-red-500',\n\t\t},\n\t}[status]\n\treturn (\n\t\t<span className=\"relative flex h-3 w-3\">\n\t\t\t{colors.pinger ? (\n\t\t\t\t<span\n\t\t\t\t\tclassName={`absolute inline-flex h-full w-full animate-ping rounded-full ${colors.pinger} opacity-75`}\n\t\t\t\t/>\n\t\t\t) : null}\n\t\t\t<span\n\t\t\t\tclassName={`relative inline-flex h-3 w-3 rounded-full ${colors.circle}`}\n\t\t\t/>\n\t\t</span>\n\t)\n}\n"],"names":["meta","matches","rootData","_a","m","sortProgress","a","b","linkProgress","progress","AdminLayout","data","useLoaderData","navigation","epicProgress","useEpicProgress","isStartingInspector","isStoppingInspector","_b","progressStatus","jsxs","jsx","Link","epicUrl","status","label","SimpleTooltip","Icon","Form","app","Pinger","key","process","colors"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"_layout-BaPtC79F.js","sources":["../../../app/routes/admin+/_layout.tsx"],"sourcesContent":["import {\n\tgetApps,\n\tgetEpicWorkshopSlug,\n} from '@epic-web/workshop-utils/apps.server'\nimport { getProcesses } from '@epic-web/workshop-utils/process-manager.server'\nimport {\n\tgetServerTimeHeader,\n\tmakeTimings,\n} from '@epic-web/workshop-utils/timing.server'\nimport {\n\ttype ActionFunctionArgs,\n\ttype LoaderFunctionArgs,\n\ttype MetaFunction,\n\tjson,\n} from '@remix-run/node'\nimport { Form, Link, useLoaderData, useNavigation } from '@remix-run/react'\nimport {\n\tclearCaches,\n\tclearData,\n\tstartInspector,\n\tstopInspector,\n} from './admin-utils.server.tsx'\nimport { Icon } from '#app/components/icons.tsx'\nimport { SimpleTooltip } from '#app/components/ui/tooltip.tsx'\nimport { type loader as rootLoader } from '#app/root.tsx'\nimport {\n\ttype SerializedProgress,\n\tuseEpicProgress,\n} from '#app/routes/progress.tsx'\nimport { ensureUndeployed } from '#app/utils/misc.tsx'\n\ndeclare global {\n\tvar __inspector_open__: boolean | undefined\n}\n\nexport const meta: MetaFunction<typeof loader, { root: typeof rootLoader }> = ({\n\tmatches,\n}) => {\n\t// eslint-disable-next-line @typescript-eslint/no-unnecessary-condition\n\tconst rootData = matches.find(m => m.id === 'root')?.data\n\treturn [{ title: `👷 | ${rootData?.workshopTitle}` }]\n}\n\nexport async function loader({ request }: LoaderFunctionArgs) {\n\tensureUndeployed()\n\tconst timings = makeTimings('adminLoader')\n\tconst workshopSlug = (await getEpicWorkshopSlug()) ?? 'Unkown'\n\tconst apps = (await getApps({ request, timings })).filter(\n\t\t(a, i, ar) => ar.findIndex(b => a.name === b.name) === i,\n\t)\n\tconst processes: Record<\n\t\tstring,\n\t\t{ port: number; pid?: number; color: string }\n\t> = {}\n\tconst testProcesses: Record<\n\t\tstring,\n\t\t{ pid?: number; exitCode?: number | null }\n\t> = {}\n\tfor (const [\n\t\tname,\n\t\t{ port, process, color },\n\t] of getProcesses().devProcesses.entries()) {\n\t\tprocesses[name] = { port, pid: process.pid, color }\n\t}\n\n\tfor (const [\n\t\tname,\n\t\t{ process, exitCode },\n\t] of getProcesses().testProcesses.entries()) {\n\t\ttestProcesses[name] = { pid: process?.pid, exitCode }\n\t}\n\treturn json(\n\t\t{\n\t\t\tapps,\n\t\t\tprocesses,\n\t\t\tworkshopSlug,\n\t\t\ttestProcesses,\n\t\t\tinspectorRunning: global.__inspector_open__,\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 async function action({ request }: ActionFunctionArgs) {\n\tensureUndeployed()\n\tconst formData = await request.formData()\n\tconst intent = formData.get('intent')\n\tswitch (intent) {\n\t\tcase 'clear-data': {\n\t\t\tawait clearData()\n\t\t\treturn json({ success: true })\n\t\t}\n\t\tcase 'clear-caches': {\n\t\t\tawait clearCaches()\n\t\t\treturn json({ success: true })\n\t\t}\n\t\tcase 'inspect': {\n\t\t\tawait startInspector()\n\t\t\treturn json({ success: true })\n\t\t}\n\t\tcase 'stop-inspect': {\n\t\t\tawait stopInspector()\n\t\t\treturn json({ success: true })\n\t\t}\n\t\tdefault: {\n\t\t\tthrow new Error(`Unknown intent: ${intent}`)\n\t\t}\n\t}\n}\n\nfunction sortProgress(a: SerializedProgress, b: SerializedProgress) {\n\treturn a.type === 'unknown' && b.type === 'unknown'\n\t\t? 0\n\t\t: a.type === 'unknown'\n\t\t\t? -1\n\t\t\t: b.type === 'unknown'\n\t\t\t\t? 1\n\t\t\t\t: 0\n}\n\nfunction linkProgress(progress: SerializedProgress) {\n\tswitch (progress.type) {\n\t\tcase 'workshop-instructions':\n\t\t\treturn '/'\n\t\tcase 'workshop-finished':\n\t\t\treturn '/finished'\n\t\tcase 'instructions':\n\t\t\treturn `/${progress.exerciseNumber.toString().padStart(2, '0')}`\n\t\tcase 'step':\n\t\t\treturn `/${progress.exerciseNumber\n\t\t\t\t.toString()\n\t\t\t\t.padStart(2, '0')}/${progress.stepNumber.toString().padStart(2, '0')}`\n\t\tcase 'finished':\n\t\t\treturn `/${progress.exerciseNumber.toString().padStart(2, '0')}/finished`\n\t\tdefault:\n\t\t\treturn ''\n\t}\n}\n\nexport default function AdminLayout() {\n\tconst data = useLoaderData<typeof loader>()\n\tconst navigation = useNavigation()\n\tconst epicProgress = useEpicProgress()\n\n\tconst isStartingInspector = navigation.formData?.get('intent') === 'inspect'\n\tconst isStoppingInspector =\n\t\tnavigation.formData?.get('intent') === 'stop-inspect'\n\n\tconst progressStatus = {\n\t\tcompleted: 'bg-blue-500',\n\t\tincomplete: 'bg-yellow-500',\n\t}\n\n\treturn (\n\t\t<main className=\"container mx-auto mt-8\">\n\t\t\t<h1 className=\"text-4xl font-bold\">Admin</h1>\n\t\t\t<div className=\"flex flex-col gap-4\">\n\t\t\t\t<nav>\n\t\t\t\t\t<ul className=\"flex gap-3\">\n\t\t\t\t\t\t<li>\n\t\t\t\t\t\t\t<Link className=\"underline\" to=\"/\">\n\t\t\t\t\t\t\t\tHome\n\t\t\t\t\t\t\t</Link>\n\t\t\t\t\t\t</li>\n\t\t\t\t\t\t<li>\n\t\t\t\t\t\t\t<Link className=\"underline\" to=\"/diff\">\n\t\t\t\t\t\t\t\tDiff Viewer\n\t\t\t\t\t\t\t</Link>\n\t\t\t\t\t\t</li>\n\t\t\t\t\t</ul>\n\t\t\t\t</nav>\n\t\t\t\t<div>\n\t\t\t\t\t<h2 className=\"text-lg font-bold\">Progress</h2>\n\t\t\t\t\t{epicProgress ? (\n\t\t\t\t\t\t<ul className=\"flex max-h-72 flex-col gap-2 overflow-y-scroll border-2 p-8 scrollbar-thin scrollbar-thumb-scrollbar\">\n\t\t\t\t\t\t\t{epicProgress.sort(sortProgress).map(progress => {\n\t\t\t\t\t\t\t\tconst epicUrl = `https://www.epicweb.dev/workshops/${data.workshopSlug}/${progress.epicSectionSlug}/${progress.epicLessonSlug}`\n\t\t\t\t\t\t\t\tconst status = progress.epicCompletedAt\n\t\t\t\t\t\t\t\t\t? 'completed'\n\t\t\t\t\t\t\t\t\t: 'incomplete'\n\t\t\t\t\t\t\t\tconst label = [\n\t\t\t\t\t\t\t\t\t`${progress.epicSectionSlug}/${progress.epicLessonSlug}`,\n\t\t\t\t\t\t\t\t\tprogress.epicCompletedAt\n\t\t\t\t\t\t\t\t\t\t? `(${progress.epicCompletedAt})`\n\t\t\t\t\t\t\t\t\t\t: null,\n\t\t\t\t\t\t\t\t]\n\t\t\t\t\t\t\t\t\t.filter(Boolean)\n\t\t\t\t\t\t\t\t\t.join(' ')\n\t\t\t\t\t\t\t\treturn (\n\t\t\t\t\t\t\t\t\t<li\n\t\t\t\t\t\t\t\t\t\tkey={progress.epicLessonSlug}\n\t\t\t\t\t\t\t\t\t\tclassName=\"flex items-center gap-2\"\n\t\t\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t\t\t<span\n\t\t\t\t\t\t\t\t\t\t\tclassName={`h-3 w-3 rounded-full ${progressStatus[status]}`}\n\t\t\t\t\t\t\t\t\t\t\ttitle={status}\n\t\t\t\t\t\t\t\t\t\t/>\n\t\t\t\t\t\t\t\t\t\t{progress.type === 'unknown' ? (\n\t\t\t\t\t\t\t\t\t\t\t<span className=\"flex items-center gap-1\">\n\t\t\t\t\t\t\t\t\t\t\t\t{label}\n\t\t\t\t\t\t\t\t\t\t\t\t<span className=\"text-red-500\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t<SimpleTooltip content=\"This video is in the workshop on EpicWeb.dev, but not in the local workshop.\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t<Icon name=\"Close\" />\n\t\t\t\t\t\t\t\t\t\t\t\t\t</SimpleTooltip>\n\t\t\t\t\t\t\t\t\t\t\t\t</span>\n\t\t\t\t\t\t\t\t\t\t\t</span>\n\t\t\t\t\t\t\t\t\t\t) : (\n\t\t\t\t\t\t\t\t\t\t\t<Link to={linkProgress(progress)}>{label}</Link>\n\t\t\t\t\t\t\t\t\t\t)}\n\t\t\t\t\t\t\t\t\t\t<Link to={epicUrl}>\n\t\t\t\t\t\t\t\t\t\t\t<Icon name=\"ExternalLink\"></Icon>\n\t\t\t\t\t\t\t\t\t\t</Link>\n\t\t\t\t\t\t\t\t\t</li>\n\t\t\t\t\t\t\t\t)\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>No progress data</p>\n\t\t\t\t\t)}\n\t\t\t\t</div>\n\t\t\t\t<div>\n\t\t\t\t\t<h2 className=\"text-lg font-bold\">Commands</h2>\n\t\t\t\t\t<ul className=\"max-h-48 overflow-y-scroll border-2 p-8 scrollbar-thin scrollbar-thumb-scrollbar\">\n\t\t\t\t\t\t<li>\n\t\t\t\t\t\t\t<Form method=\"POST\">\n\t\t\t\t\t\t\t\t<button name=\"intent\" value=\"clear-caches\">\n\t\t\t\t\t\t\t\t\tClear local caches\n\t\t\t\t\t\t\t\t</button>\n\t\t\t\t\t\t\t</Form>\n\t\t\t\t\t\t</li>\n\t\t\t\t\t\t<li>\n\t\t\t\t\t\t\t<Form method=\"POST\">\n\t\t\t\t\t\t\t\t<button name=\"intent\" value=\"clear-data\">\n\t\t\t\t\t\t\t\t\tClear all local data (including auth data)\n\t\t\t\t\t\t\t\t</button>\n\t\t\t\t\t\t\t</Form>\n\t\t\t\t\t\t</li>\n\t\t\t\t\t\t<li>\n\t\t\t\t\t\t\t{data.inspectorRunning ? (\n\t\t\t\t\t\t\t\t<Form method=\"POST\">\n\t\t\t\t\t\t\t\t\t<button name=\"intent\" value=\"stop-inspect\">\n\t\t\t\t\t\t\t\t\t\t{isStartingInspector\n\t\t\t\t\t\t\t\t\t\t\t? 'Stopping inspector...'\n\t\t\t\t\t\t\t\t\t\t\t: 'Stop inspector'}\n\t\t\t\t\t\t\t\t\t</button>\n\t\t\t\t\t\t\t\t</Form>\n\t\t\t\t\t\t\t) : (\n\t\t\t\t\t\t\t\t<Form method=\"POST\">\n\t\t\t\t\t\t\t\t\t<button name=\"intent\" value=\"inspect\">\n\t\t\t\t\t\t\t\t\t\t{isStoppingInspector\n\t\t\t\t\t\t\t\t\t\t\t? 'Starting inspector...'\n\t\t\t\t\t\t\t\t\t\t\t: 'Start inspector'}\n\t\t\t\t\t\t\t\t\t</button>\n\t\t\t\t\t\t\t\t</Form>\n\t\t\t\t\t\t\t)}\n\t\t\t\t\t\t</li>\n\t\t\t\t\t</ul>\n\t\t\t\t</div>\n\t\t\t\t<div>\n\t\t\t\t\t<h2 className=\"text-lg font-bold\">Apps</h2>\n\t\t\t\t\t<ul className=\"max-h-48 list-none overflow-y-scroll border-2 p-8 scrollbar-thin scrollbar-thumb-scrollbar\">\n\t\t\t\t\t\t{data.apps.map(app => (\n\t\t\t\t\t\t\t<li key={app.name} className=\"flex items-center gap-2 py-1\">\n\t\t\t\t\t\t\t\t{data.processes[app.name] ? (\n\t\t\t\t\t\t\t\t\t<Pinger status=\"running\" />\n\t\t\t\t\t\t\t\t) : (\n\t\t\t\t\t\t\t\t\t<Pinger status=\"stopped\" />\n\t\t\t\t\t\t\t\t)}\n\t\t\t\t\t\t\t\t{app.name}\n\t\t\t\t\t\t\t</li>\n\t\t\t\t\t\t))}\n\t\t\t\t\t</ul>\n\t\t\t\t</div>\n\t\t\t\t<div>\n\t\t\t\t\t<h2 className=\"text-lg font-bold\">Processes</h2>\n\t\t\t\t\t<ul className=\"overflow-y-scroll border-2 p-8 scrollbar-thin scrollbar-thumb-scrollbar\">\n\t\t\t\t\t\t{Object.entries(data.processes).map(([key, process]) => (\n\t\t\t\t\t\t\t<li key={key}>\n\t\t\t\t\t\t\t\t<span>\n\t\t\t\t\t\t\t\t\t{key} - Port: {process.port} - PID {process.pid} -{' '}\n\t\t\t\t\t\t\t\t\t{process.color}\n\t\t\t\t\t\t\t\t</span>\n\t\t\t\t\t\t\t</li>\n\t\t\t\t\t\t))}\n\t\t\t\t\t</ul>\n\t\t\t\t</div>\n\t\t\t\t<div>\n\t\t\t\t\t<h2 className=\"text-lg font-bold\">Test Processes</h2>\n\t\t\t\t\t<ul className=\"overflow-y-scroll border-2 p-8 scrollbar-thin scrollbar-thumb-scrollbar\">\n\t\t\t\t\t\t{Object.entries(data.testProcesses).map(([key, process]) => (\n\t\t\t\t\t\t\t<li key={key}>\n\t\t\t\t\t\t\t\t<span>\n\t\t\t\t\t\t\t\t\t{key} - PID {process.pid} - Exit code: {process.exitCode}\n\t\t\t\t\t\t\t\t</span>\n\t\t\t\t\t\t\t</li>\n\t\t\t\t\t\t))}\n\t\t\t\t\t</ul>\n\t\t\t\t</div>\n\t\t\t</div>\n\t\t</main>\n\t)\n}\n\nfunction Pinger({\n\tstatus,\n}: {\n\tstatus: 'running' | 'starting' | 'stopped' | 'taken'\n}) {\n\tconst colors = {\n\t\trunning: {\n\t\t\tpinger: 'bg-green-400',\n\t\t\tcircle: 'bg-green-500',\n\t\t},\n\t\tstarting: {\n\t\t\tpinger: 'bg-sky-400',\n\t\t\tcircle: 'bg-sky-500',\n\t\t},\n\t\tstopped: {\n\t\t\tcircle: 'bg-gray-500',\n\t\t},\n\t\ttaken: {\n\t\t\tpinger: 'bg-red-400',\n\t\t\tcircle: 'bg-red-500',\n\t\t},\n\t}[status]\n\treturn (\n\t\t<span className=\"relative flex h-3 w-3\">\n\t\t\t{colors.pinger ? (\n\t\t\t\t<span\n\t\t\t\t\tclassName={`absolute inline-flex h-full w-full animate-ping rounded-full ${colors.pinger} opacity-75`}\n\t\t\t\t/>\n\t\t\t) : null}\n\t\t\t<span\n\t\t\t\tclassName={`relative inline-flex h-3 w-3 rounded-full ${colors.circle}`}\n\t\t\t/>\n\t\t</span>\n\t)\n}\n"],"names":["meta","matches","rootData","_a","m","sortProgress","a","b","linkProgress","progress","AdminLayout","data","useLoaderData","navigation","epicProgress","useEpicProgress","isStartingInspector","isStoppingInspector","_b","progressStatus","jsxs","jsx","Link","epicUrl","status","label","SimpleTooltip","Icon","Form","app","Pinger","key","process","colors"],"mappings":"iQAI6B,MAAAA,EAAA,CAAA,CAC7B,QAAAC,CAAA,IACC,OACA,MAAAC,GAAAC,EAAAF,EAAA,KAAAG,GAAAA,EAAA,KAAA,MAAA,IAAA,YAAAD,EAAA,KACM,MAAA,CAAA,CACP,MAAA,QAAAD,GAAA,YAAAA,EAAA,aAAA,EAAA,CAIC,CAAA,EAED,SAASG,EAAYC,EAAAC,EAAA,CACrB,OAAAD,EAAA,OAAA,WAAAC,EAAA,OAAA,UAAA,EAAAD,EAAA,OAAA,UAAA,GAAAC,EAAA,OAAA,UAAA,EAAA,CAAA,CACC,SACAC,EAAAC,EAAA,CACA,OAAAA,EAAA,KAAA,CACA,IAAA,wBACM,MAAA,IACP,IAAS,oBACT,MAA8B,YAE9B,IAAA,eAEC,MAAA,IAAAA,EAAA,eAAA,WAAA,SAAA,EAAA,GAAA,CAAA,GACM,IAAA,OACP,MAAiC,IAAAA,EAAA,eAAA,WAAA,SAAA,EAAA,GAAA,CAAA,IAAAA,EAAA,WAAA,SAAA,EAAA,SAAA,EAAA,GAAA,CAAA,GAM1B,IAAA,WACN,MAAA,IAAAA,EAAA,eAAA,SAAA,EAAA,SAAA,EAAA,GAAA,CAAA,YACK,QAEL,QACA,CACD,CAEsB,SAAAC,GAAS,SACb,MAAAC,EAAAC,IACXC,MACAC,EAAgBC,IAChBC,IAAsBb,EAAAU,EAAW,WAAX,YAAAV,EAAuB,IAAA,aAAA,UAC9Cc,IAAuBC,EAAAL,EAAO,WAAP,YAAAK,EAAkB,IAAI,aAAM,eACxDC,EAAA,CACA,wBAIA,0BAIA,EACC,OAAAC,EAAAA,KAAA,OAAA,CACA,UAAQ,yBACJ,SAAA,CAAeC,EAAA,IAAA,MACnB,+BACD,SAAA,OAEA,CAAW,EAAAD,EAAA,KAAA,MAAA,CACV,UAAA,sBACE,SAAkB,CAAAC,EAAA,IAAA,MAAA,CAChB,SAAeD,YAAsB,CACzC,uBACD,SAAA,CAAAC,EAAA,IAAA,KAAA,CACO,SAAAA,EAAA,IAAAC,EAAA,CACN,UAAA,YACC,GAAA,IACA,SAAA,MAAA,CACA,CAAA,CACA,EAAAD,EAAA,IAAA,KAAA,UACyBA,EAAA,IAAAC,EAAA,CAC1B,UAAA,YACA,GAAA,QACU,SAAA,aAAA,CACR,CAA4C,CAC7C,CAAA,CAAA,CACD,CAAA,CACD,EAAAF,EAAA,KAAA,MAAA,CACD,SAAA,CAAAC,EAAA,IAAA,KAAA,CAEsB,UAAA,oBACJ,SAAA,UACjB,CAAM,EAAAP,EAAkCO,EAAA,IAAA,KAAA,CAClC,UAAkB,uGAChB,SAAQP,EAAA,KAAAT,CAAA,EAAA,IAAAI,GAAA,CACI,MAAAc,EAAA,qCAAAZ,EAAA,YAAA,IAAAF,EAAA,eAAA,IAAAA,EAAA,cAAA,GACFe,EAAAf,EAAA,gBAAA,YAAA,aACJgB,EAAW,CAAA,GAAAhB,EAAM,eAAA,IAAAA,EAAA,cAAA,GAAAA,EAAA,gBAAA,IAAAA,EAAA,eAAA,IAAA,IAAA,EAAA,OAAA,OAAA,EAAA,KAAA,GAAA,EAC9B,OAAAW,EAAAA,KAAA,KAAA,CACqB,UAAA,0BACF,SAAA,CAAAC,EAAA,IAAA,OAAA,CACN,UAAW,wBAAMF,EAAAK,CAAA,CAAA,GAC9B,MAAAA,CACgB,CAAA,EAAAf,EAAA,OAAA,UAAAW,EAAAA,KAAA,OAAA,CACM,UAAA,0BACT,SAAW,CAAAK,EAAMJ,EAAA,IAAA,OAAA,CAC9B,UAAA,eACqB,SAAAA,EAAA,IAAAK,EAAA,CACA,QAAA,+EACN,SAAeL,EAAA,IAAAM,EAAA,CAC9B,KAAA,OAAA,CACS,CACR,CAAU,CAAiC,CAC5C,CAAA,CAAA,CACD,EAAAN,EAAA,IAAAC,EAAA,CACD,GAAAd,EAAAC,CAAA,EAES,SAA2DgB,CACnE,CAAS,EAAsBJ,SAOhC,GAAAE,WAEoDF,EAAA,IAAAM,EAAA,MAC5B,cAAA,CACjB,CACJ,CAAO,CAAA,CAAA,EACHlB,EAAA,cAAA,CACJ,CAAO,CAAA,CACH,EAAAY,EAAA,IAAA,IAAA,CACG,2BAAuD,CAC1D,CAAA,CACJ,CAAA,EAAoBD,EAAA,KAAA,MAAA,CAGhB,SAAA,CAAAC,EAAA,IAAA,KAAA,CACG,8BACR,SAAA,UACC,CAAO,EAAAD,EAAA,KAAA,KAAA,CACT,UAAA,mFACD,SAAA,CAAAC,EAAA,IAAA,KAAA,CAEA,SAAsCA,EAAA,IAAAO,EAAA,QACK,gBACTP,EAAA,IAAA,SAAA,eAGL,MAAA,eAE3B,SAAA,oBAED,CAAuB,CAAA,CACX,CAAA,CACC,EAAAA,EAAA,IAAA,KAAA,CACb,SAAAA,EAAA,IAAAO,EAAA,CAGC,OAAA,OACE,SAAaP,EAAA,IAAA,SAAA,CACd,KAAA,SACC,MAAA,aAEG,SAAA,4CAID,CACA,CAIA,CAEF,CAAA,GAECA,EAAA,IAAA,KAAA,CAAC,SAAAV,EAAA,iBAAaU,EAAAA,IAAAO,EAA4B,CACzC,OAAA,OAGQ,yBACA,KAAA,SAGA,MAAQ,eACV,SAAwBZ,0BAA2B,gBAAA,CAC7C,CAEN,CAEF,IACQ,IAAAY,EAAA,CAET,OAAA,OAAC,SAAAP,EAAA,IAAA,SAAA,CAAA,KAAA,SAEU,MAAA,UAEV,SAAAJ,EAAA,wBAAA,iBAAA,CAAA,CAAA,CAAC,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CACyD,CAAA,EAClDG,EAAA,KAAA,MAAA,CAAA,SAAA,CAAAC,EAAA,IAAA,KAAA,CACR,UAAA,oBAAA,eAGG,CAAA,EAAAA,EAAA,IAAA,KAAA,CAAA,UACA,6FAID,WAGA,KAAA,IAAAQ,GAAsBT,EAAA,KAAA,KAAA,CAExB,UAAA,+BAEA,SAAA,CAAAT,EAAA,UAAAkB,EAAA,IAAA,EAAAR,EAAA,IAAAS,EAAA,CAAA,OAAA,SAAA,CArBc,EAAAT,EAAA,IAAAS,EAAA,CAsBf,OAAA,SAAA,CAKH,EAAAD,EAAA,IAAA,CAAmB,EAErBA,EAAA,IAAA,CAAA,CAAA,GAEC,CAAC,EAAAT,EAAA,KAAA,MAAa,CACd,SAAA,CAAIC,EAAA,IAAA,KAAA,CACH,UAAA,oBAOA,SAAC,WAMD,CAAA,EACCA,EAAA,IAAA,KAAA,CAmBF,UAAA,0EACD,SAAA,OAAA,QAAAV,EAAA,SAAA,EAAA,IAAA,CAAA,CAAAoB,EAAAC,CAAA,IAAAX,EAAAA,IAAA,KAAA,UAECD,EAAA,KAAA,OAAA,CAAC,SAAA,CAAAW,EAAA,YAAaC,EAAA,KAAA,UAAoBA,EAAI,IAAA,KAAA,IAAAA,EAAA,KAAA,CAAA,CACtC,CAGI,EAAAD,CAAe,CAAA,CAGU,CAAA,CAEzB,CAAI,CANG,EASXX,EAAA,KAAA,MAAA,CACD,SAAA,CAAAC,EAAA,IAAA,KAAA,+BAEE,SAAA,gBAA0C,KACvC,IAAA,KAAA,CAIC,UAAA,0EAAI,SAAA,OAAA,QAAAV,EAAA,aAAA,EAAA,IAAA,CAAA,CAAAoB,EAAAC,CAAA,IAAAX,EAAAA,IAAA,KAAA,CAAkB,SAAAD,EAAA,KAAA,OAAA,CAAK,SAAA,CAAAW,EAAA,UAAAC,EAAA,IAAA,iBAAAA,EAAA,QAAA,CAAA,CAAgB,CAAI,EAAAD,CAAA,CAAA,CAAA,CAAG,CAAA,CAAA,CAAA,CAAA,CAC1C,CACV,CAAA,CAGH,CACD,CAAA,CAEC,SAACD,EAAA,CAA+C,OAAAN,CAK3C,EAAA,CAAI,MAAAS,EAAA,CAAA,QAAgB,CAAI,OAAA,eAAA,OAAuB,cACjD,EAIJ,SAAA,CACD,OAAA,aACD,OAAA,YAEF,EAEA,QAAgB,CACf,OAAA,aAGE,EACF,MAAe,CACL,OAAA,aACR,OAAQ,YAAA,CAET,EAAAT,CAAA,EAAA,OACUJ,EAAAA,KAAA,OAAA,CAAA,UACD,wBAAA,SACA,CAAAa,EAAA,OAAAZ,EAAAA,IAAA,OAAA,CACT,UAAA,gEAAAY,EAAA,MAAA,aAAA,CACS,EAAA,KAAAZ,EAAA,IAAA,OAAA,CACR,UAAQ,6CAAAY,EAAA,MAAA,EAAA,CACT,CAAA,CAAA,CAAA,CACO"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"_layout-
|
|
1
|
+
{"version":3,"file":"_layout-Bj9PyQQD.js","sources":["../../../app/routes/_app+/_exercises+/_layout.tsx"],"sourcesContent":["import { Outlet } from '@remix-run/react'\n\nexport default function ExercisesLayout() {\n\treturn (\n\t\t<div className=\"flex h-full flex-grow\">\n\t\t\t<Outlet />\n\t\t</div>\n\t)\n}\n"],"names":["ExercisesLayout"],"mappings":"+CAEA,SAAwBA,GAAkB,CACzC,mBACM,CAIP,UAAA"}
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import{r as j,j as e,O as K,b as Q}from"./index-BDqSZ0-h.js";import{c as x}from"./clsx-B-dksMZM.js";import{b as q,s as Y,c as X,d as Z,e as M,m as h,u as ee,f as te}from"./progress-mfa_5CZx.js";import{T as se}from"./index-Dc59VwXx.js";import{c as f,I as b}from"./misc-C1rq7sPa.js";import{S as I,T as ne,a as D,b as $,c as V}from"./tooltip-BlVFw-is.js";import{b as S}from"./user-p2QVtDZI.js";import{a as O}from"./presence-BF7lWuVd.js";import{L as u,u as ae,N as W}from"./components-BM_XUa9h.js";import"./index-B8k-Gd1G.js";import"./client-hints-B2pbEa_9.js";function re(t){t.values.forEach(s=>s.stop())}function P(t,s){[...s].reverse().forEach(o=>{const l=t.getVariant(o);l&&Y(t,l),t.variantChildren&&t.variantChildren.forEach(r=>{P(r,s)})})}function oe(t,s){if(Array.isArray(s))return P(t,s);if(typeof s=="string")return P(t,[s]);Y(t,s)}function le(){const t=new Set,s={subscribe(n){return t.add(n),()=>void t.delete(n)},start(n,o){const l=[];return t.forEach(r=>{l.push(q(r,n,{transitionOverride:o}))}),Promise.all(l)},set(n){return t.forEach(o=>{oe(o,n)})},stop(){t.forEach(n=>{re(n)})},mount(){return()=>{s.stop()}}};return s}function _(){const t=X(le);return Z(t.mount,[]),t}const H=["opacity-70","opacity-80","opacity-90","opacity-100"],U=["shadow-[0_0_2px_0_rgba(0,0,0,0.3)]","shadow-[0_0_4px_0_rgba(0,0,0,0.3)]","shadow-[0_0_7px_0_rgba(0,0,0,0.3)]","shadow-[0_0_10px_0_rgba(0,0,0,0.3)]"];function A(t){const s=Math.round(t*H.length-1),n=Math.round(t*U.length-1);return f("shadow-purple-700 hover:opacity-100 focus:opacity-100 dark:shadow-purple-200",H[s]??"opacity-60",U[n]??"shadow-none",t===1?"animate-pulse hover:animate-none focus:animate-none":null)}function ie({isMenuOpened:t}){const s=S(),{users:n}=O(),o=t?17:0,l=n.length-o;if(!n.length)return null;const r=t&&n.length===1?e.jsx(u,{target:"_blank",rel:"noopener noreferrer",to:"https://www.youtube.com/watch?v=w6Q3mHyzn78",children:e.jsx("img",{alt:"Tiffany Tunes",className:f("h-8 w-8 rounded-full border object-cover",A(1)),src:"https://github-production-user-asset-6210df.s3.amazonaws.com/1500684/277090714-b26e5961-4ee5-4c20-abdb-b04c1c480f2b.png"})}):null,m=`${l}${t?" more ":" "}Epic Web Dev${l===1?"":"s"} working now`;return e.jsx("div",{className:"flex flex-wrap items-center gap-2",children:e.jsxs(ne,{children:[n.slice(0,o).map(({user:a,score:c})=>{const p=A(c),d=ce(a.location);return e.jsxs(D,{children:[e.jsx($,{asChild:!0,children:a.avatarUrl?e.jsx("img",{tabIndex:0,alt:a.name||"Epic Web Dev",className:f("h-8 w-8 rounded-full border object-cover",p),src:a.avatarUrl}):e.jsx("div",{tabIndex:0,"aria-label":a.name||"Epic Web Dev",className:f("flex h-8 w-8 items-center justify-center rounded-full border",p),children:e.jsx(b,{name:"User"})})}),e.jsx(V,{children:e.jsxs("span",{className:"flex flex-col items-center justify-center gap-1",children:[e.jsxs("span",{children:[a.name||"An EPIC Web Dev"," ",d?` is working ${c===1&&(s==null?void 0:s.id)!==a.id?"with you":""} on`:null]}),d!=null&&d.line1?e.jsx("span",{children:d.line1}):null,d!=null&&d.line2?e.jsx("span",{children:d.line2}):null]})})]},a.id)}),r,l>0?e.jsxs(D,{children:[e.jsx($,{asChild:!0,children:e.jsx("div",{tabIndex:0,"aria-label":m,className:f("flex items-center justify-center rounded-full border bg-accent text-xs text-accent-foreground",t?"h-8 w-8":"h-6 w-6"),children:e.jsx("span",{className:f("pointer-events-none overflow-hidden text-ellipsis whitespace-nowrap text-center",t?"w-8":"w-6"),children:t?`+${l}`:l})})}),e.jsx(V,{children:m})]}):null]})})}function Ce(){const t=S(),[s,n]=j.useState(!1);return e.jsxs("div",{className:"flex flex-col",children:[t?null:e.jsx(de,{}),e.jsxs("div",{className:f("flex flex-grow",{"h-[calc(100vh-64px-env(safe-area-inset-top)-env(safe-area-inset-bottom))]":!t,"h-[calc(100vh-112px-env(safe-area-inset-top)-env(safe-area-inset-bottom))] sm:h-[calc(100vh-64px-env(safe-area-inset-top)-env(safe-area-inset-bottom))]":ENV.EPICSHOP_DEPLOYED,"h-[calc(100vh-env(safe-area-inset-top)-env(safe-area-inset-bottom))]":t}),children:[e.jsx(fe,{isMenuOpened:s,onMenuOpenChange:n}),e.jsx("div",{className:f("h-full w-full max-w-[calc(100%-56px)]",s?"hidden md:block":""),children:e.jsx(K,{})})]})]})}function ce(t){if(!t)return null;const{exercise:s}=t,n=[s?[s.exerciseNumber,s.stepNumber].filter(Boolean).map(o=>o.toString().padStart(2,"0")).join("/"):null,s==null?void 0:s.type].filter(Boolean).join(" - ");return{line1:t.workshopTitle,line2:n}}function de(){return e.jsxs("div",{className:f("z-10 flex items-center justify-between border-b bg-gradient-to-tr from-blue-500 to-indigo-500 pl-4 text-white",ENV.EPICSHOP_DEPLOYED?"h-[112px] md:h-[64px]":"h-16"),children:[e.jsxs("div",{className:"flex flex-1 flex-wrap items-center gap-4",children:[e.jsx(b,{name:"EpicWeb",size:"lg"}),e.jsxs("div",{className:"flex flex-1 flex-wrap items-center",children:[e.jsxs("p",{className:"mr-2",children:["Welcome to the"," ",e.jsx(u,{to:"https://www.epicweb.dev",className:"underline",target:"_blank",children:"EpicWeb.dev"})," ","Workshop app!"]}),ENV.EPICSHOP_DEPLOYED?e.jsxs("small",{className:"text-sm",children:["This is the deployed version."," ",ENV.EPICSHOP_GITHUB_ROOT?e.jsx(u,{className:"underline",target:"_blank",rel:"noopener noreferrer",to:ENV.EPICSHOP_GITHUB_ROOT,children:"Run locally"}):null," ","for full experience."]}):null]})]}),e.jsxs("div",{className:"flex h-full flex-col items-center md:flex-row",children:[e.jsxs(u,{to:"https://www.epicweb.dev",target:"_blank",className:"flex h-full items-center justify-center space-x-1.5 px-5 text-sm font-semibold",children:[e.jsx("span",{className:"drop-shadow-sm",children:"Join Epic Web"}),e.jsx("span",{children:"↗︎"})]}),e.jsxs(u,{to:ENV.EPICSHOP_DEPLOYED?"https://www.epicweb.dev/login":"/login",className:"flex h-full items-center justify-center space-x-1.5 bg-white/20 px-5 text-sm font-semibold shadow-md transition hover:bg-white/30",children:[e.jsx(b,{name:"User",size:"lg"}),e.jsx("span",{className:"drop-shadow-sm",children:"Login"})]})]})]})}const z={hidden:{opacity:0,x:-20},visible:{opacity:1,x:0}};function ue({exerciseNumber:t,children:s}){const n=ee(t);return e.jsx(h.li,{variants:z,className:f("py-[6px] first:pt-3 last:pb-3",n?`${n} before:border-t`:null),children:e.jsx("span",{className:"ml-2",children:s})})}function C({children:t,...s}){const n=te(s);return e.jsx(h.li,{variants:z,className:f("py-[6px] first:pt-3 last:pb-3",n?`${n} before:border-t`:null),children:e.jsx("span",{className:"ml-2",children:t})})}const k=400;function fe({isMenuOpened:t,onMenuOpenChange:s}){const n=ae(),o=S(),l=M(),r=Q(),{users:m}=O(),a=n.exercises.find(i=>i.exerciseNumber===Number(r.exerciseNumber)),c=r.type==="solution"?a==null?void 0:a.solutions.find(i=>i.stepNumber===Number(r.stepNumber)):r.type==="problem"?a==null?void 0:a.problems.find(i=>i.stepNumber===Number(r.stepNumber)):null,p=_(),d={close:{width:56},open:{width:k}},g={visible:{opacity:1,transition:{duration:.05,when:"beforeChildren",staggerChildren:.03}},hidden:{opacity:0}},L=Number(r.exerciseNumber).toString().padStart(2,"0");return e.jsx("nav",{className:"flex border-r",children:e.jsx(h.div,{initial:t?"open":"close",variants:d,animate:p,children:e.jsxs("div",{className:"flex h-full flex-col items-center justify-between",children:[e.jsx(he,{title:n.workshopTitle,menuControls:p,isMenuOpened:t,setMenuOpened:s}),t&&e.jsxs(h.div,{style:{width:k},className:"flex flex-grow flex-col justify-between overflow-y-auto p-6 scrollbar-thin scrollbar-thumb-scrollbar",initial:{opacity:0},animate:{opacity:1},children:[e.jsx(h.ul,{variants:g,initial:"hidden",animate:"visible",className:"flex flex-col",children:n.exercises.map(({exerciseNumber:i,title:B,steps:R})=>{const N=Number(r.exerciseNumber)===i,F=!N&&n.playground.exerciseNumber===i,v=i.toString().padStart(2,"0");return e.jsxs(ue,{exerciseNumber:i,children:[e.jsxs(u,{prefetch:"intent",to:`/${v}`,className:x("relative whitespace-nowrap px-2 py-0.5 pr-3 text-2xl font-bold outline-none hover:underline focus:underline",'after:absolute after:-bottom-2.5 after:-right-2.5 after:h-5 after:w-5 after:rotate-45 after:scale-75 after:bg-background after:content-[""] hover:underline focus:underline',{"bg-foreground text-background":N}),children:[B,F?" 🛝":null]}),N?e.jsxs(h.ul,{variants:g,initial:"hidden",animate:"visible",className:"ml-4 mt-4 flex flex-col",children:[e.jsx(C,{type:"instructions",exerciseNumber:i,children:e.jsx(u,{to:`/${v}`,prefetch:"intent",className:x('relative whitespace-nowrap px-2 py-0.5 pr-3 text-xl font-medium outline-none after:absolute after:-bottom-2.5 after:-right-2.5 after:h-5 after:w-5 after:rotate-45 after:scale-75 after:bg-background after:content-[""] hover:underline focus:underline',{"bg-foreground text-background":!r.stepNumber}),children:"Intro"})},i),R.filter(Boolean).map(({name:y,stepNumber:w,title:T})=>{const G=Number(r.stepNumber)===w,E=w.toString().padStart(2,"0"),J=y===n.playground.appName;return e.jsx(C,{type:"step",stepNumber:w,exerciseNumber:i,children:e.jsx(u,{to:`/${v}/${E}`,prefetch:"intent",className:x('relative whitespace-nowrap px-2 py-0.5 pr-3 text-xl font-medium outline-none after:absolute after:-bottom-2.5 after:-right-2.5 after:h-5 after:w-5 after:rotate-45 after:scale-75 after:bg-background after:content-[""] hover:underline focus:underline',{"bg-foreground text-background":G}),children:J?`${E}. ${T} 🛝`:`${E}. ${T}`})},w)}),e.jsx(C,{type:"finished",exerciseNumber:i,children:e.jsx(W,{to:`/${v}/finished`,prefetch:"intent",className:({isActive:y})=>x('relative whitespace-nowrap px-2 py-0.5 pr-3 text-base font-medium outline-none after:absolute after:-bottom-2.5 after:-right-2.5 after:h-5 after:w-5 after:rotate-45 after:scale-75 after:bg-background after:content-[""] hover:underline focus:underline',{"bg-foreground text-background":y}),children:"📝 Elaboration"})})]}):null]},i)})}),e.jsx("div",{className:"mt-6",children:e.jsx(W,{to:"/finished",className:({isActive:i})=>x("relative whitespace-nowrap text-lg font-bold outline-none hover:underline focus:underline",{'bg-black text-white after:absolute after:-bottom-2.5 after:-right-2.5 after:h-5 after:w-5 after:rotate-45 after:scale-75 after:bg-background after:content-[""]':i}),children:"📝 Workshop Feedback"})})]}),!t&&e.jsx("div",{className:"flex flex-grow flex-col justify-center",children:e.jsxs("div",{className:"orientation-sideways w-full font-mono text-sm font-medium uppercase leading-none",children:[a!=null&&a.title?e.jsx(u,{to:`/${L}`,children:a.title}):null,a!=null&&a.title&&(c!=null&&c.title)?" — ":null,c!=null&&c.title?e.jsx(u,{to:`/${L}/${c.stepNumber.toString().padStart(2,"0")}`,children:c.title}):null]})}),e.jsx("div",{className:f("flex w-full items-center justify-start border-t p-4 transition-[height]",t&&m.length>4?"h-28":"h-14"),style:t?{width:k}:{},children:e.jsx(ie,{isMenuOpened:t})}),ENV.EPICSHOP_DEPLOYED?null:o?e.jsx(I,{content:t?null:"Your account",children:e.jsxs(u,{className:"flex h-14 w-full items-center justify-start space-x-3 border-t px-4 py-4 text-center no-underline hover:underline",to:"/account",children:[o.avatarUrl?e.jsx("img",{alt:o.name??o.email,src:o.avatarUrl,className:"h-full rounded-full"}):e.jsx(b,{name:"User",className:"flex-shrink-0",size:"lg"}),t?e.jsx(h.div,{className:"flex items-center whitespace-nowrap",initial:{opacity:0},animate:{opacity:1},children:"Your Account"}):e.jsx("span",{className:"sr-only",children:"Your account"})]})}):null,ENV.EPICSHOP_DEPLOYED?null:o&&l?e.jsx(I,{content:t?null:"Continue to next lesson",children:e.jsxs(u,{to:l,prefetch:"intent",className:x("flex h-14 w-full items-center space-x-3 border-t px-4 py-4 pl-[18px] no-underline hover:underline"),state:{from:"continue next lesson button"},children:[e.jsx(b,{name:"FastForward",className:"flex-shrink-0",size:"md"}),t?e.jsx(h.div,{className:"flex items-center whitespace-nowrap",initial:{opacity:0},animate:{opacity:1},children:"Continue to next lesson"}):e.jsx("span",{className:"sr-only",children:"Continue to next lesson"})]})}):null,e.jsx("div",{className:"mb-4 w-full self-start border-t pl-3 pt-[15px]",children:e.jsx(se,{})})]})})})}function he({title:t,isMenuOpened:s,setMenuOpened:n,menuControls:o}){const l={open:{d:"M3.06061 2.99999L21.0606 21"},closed:{d:"M0 9.5L24 9.5"}},r={open:{d:"M3.00006 21.0607L21 3.06064"},moving:{d:"M0 14.5L24 14.5"},closed:{d:"M0 14.5L15 14.5"}},m=_(),a=_();async function c(){o.start(s?"close":"open"),n(!s),s?(m.start(l.closed),await a.start(r.moving),a.start(r.closed)):(await a.start(r.moving),m.start(l.open),a.start(r.open))}const p=j.useRef(c);return j.useEffect(()=>{p.current=c}),j.useEffect(()=>{if(!s)return;function d(g){g.key==="Escape"&&p.current()}return document.addEventListener("keyup",d),()=>document.removeEventListener("keyup",d)},[s]),e.jsxs("div",{className:"relative inline-flex h-14 w-full items-center justify-between overflow-hidden border-b",children:[e.jsx("button",{className:"flex h-14 w-14 items-center justify-center","aria-label":"Open Navigation menu",onClick:c,children:e.jsxs("svg",{width:"24",height:"24",viewBox:"0 0 24 24",children:[e.jsx(h.path,{...l.closed,animate:m,transition:{duration:.2},stroke:"currentColor",strokeWidth:1.5}),e.jsx(h.path,{...r.closed,animate:a,transition:{duration:.2},stroke:"currentColor",strokeWidth:1.5})]})}),s&&e.jsx(h.p,{transition:{delay:.2},initial:{opacity:0,y:5},animate:{opacity:1,y:0},className:"absolute right-5 whitespace-nowrap font-mono text-sm uppercase",children:e.jsx(u,{to:"/",children:t})})]})}export{Ce as default};
|
|
2
|
-
//# sourceMappingURL=_layout-
|
|
1
|
+
import{r as j,j as e,O as K,b as Q}from"./index-D1WEsmVZ.js";import{c as x}from"./clsx-B-dksMZM.js";import{b as q,s as Y,c as X,d as Z,e as M,m as h,u as ee,f as te}from"./progress-CBZt2pmu.js";import{T as se}from"./index-CLnz0tXz.js";import{c as f,I as b}from"./misc-CXGQ7VS9.js";import{S as I,T as ne,a as D,b as $,c as V}from"./tooltip-CVFWPOu0.js";import{b as S}from"./user-DiGtbaa7.js";import{a as O}from"./presence-u-05JV3Z.js";import{L as u,u as ae,N as W}from"./components-Dj3sm47B.js";import"./index-B8k-Gd1G.js";import"./client-hints-KnbHFIgn.js";function re(t){t.values.forEach(s=>s.stop())}function P(t,s){[...s].reverse().forEach(o=>{const l=t.getVariant(o);l&&Y(t,l),t.variantChildren&&t.variantChildren.forEach(r=>{P(r,s)})})}function oe(t,s){if(Array.isArray(s))return P(t,s);if(typeof s=="string")return P(t,[s]);Y(t,s)}function le(){const t=new Set,s={subscribe(n){return t.add(n),()=>void t.delete(n)},start(n,o){const l=[];return t.forEach(r=>{l.push(q(r,n,{transitionOverride:o}))}),Promise.all(l)},set(n){return t.forEach(o=>{oe(o,n)})},stop(){t.forEach(n=>{re(n)})},mount(){return()=>{s.stop()}}};return s}function _(){const t=X(le);return Z(t.mount,[]),t}const H=["opacity-70","opacity-80","opacity-90","opacity-100"],U=["shadow-[0_0_2px_0_rgba(0,0,0,0.3)]","shadow-[0_0_4px_0_rgba(0,0,0,0.3)]","shadow-[0_0_7px_0_rgba(0,0,0,0.3)]","shadow-[0_0_10px_0_rgba(0,0,0,0.3)]"];function A(t){const s=Math.round(t*H.length-1),n=Math.round(t*U.length-1);return f("shadow-purple-700 hover:opacity-100 focus:opacity-100 dark:shadow-purple-200",H[s]??"opacity-60",U[n]??"shadow-none",t===1?"animate-pulse hover:animate-none focus:animate-none":null)}function ie({isMenuOpened:t}){const s=S(),{users:n}=O(),o=t?17:0,l=n.length-o;if(!n.length)return null;const r=t&&n.length===1?e.jsx(u,{target:"_blank",rel:"noopener noreferrer",to:"https://www.youtube.com/watch?v=w6Q3mHyzn78",children:e.jsx("img",{alt:"Tiffany Tunes",className:f("h-8 w-8 rounded-full border object-cover",A(1)),src:"https://github-production-user-asset-6210df.s3.amazonaws.com/1500684/277090714-b26e5961-4ee5-4c20-abdb-b04c1c480f2b.png"})}):null,m=`${l}${t?" more ":" "}Epic Web Dev${l===1?"":"s"} working now`;return e.jsx("div",{className:"flex flex-wrap items-center gap-2",children:e.jsxs(ne,{children:[n.slice(0,o).map(({user:a,score:c})=>{const p=A(c),d=ce(a.location);return e.jsxs(D,{children:[e.jsx($,{asChild:!0,children:a.avatarUrl?e.jsx("img",{tabIndex:0,alt:a.name||"Epic Web Dev",className:f("h-8 w-8 rounded-full border object-cover",p),src:a.avatarUrl}):e.jsx("div",{tabIndex:0,"aria-label":a.name||"Epic Web Dev",className:f("flex h-8 w-8 items-center justify-center rounded-full border",p),children:e.jsx(b,{name:"User"})})}),e.jsx(V,{children:e.jsxs("span",{className:"flex flex-col items-center justify-center gap-1",children:[e.jsxs("span",{children:[a.name||"An EPIC Web Dev"," ",d?` is working ${c===1&&(s==null?void 0:s.id)!==a.id?"with you":""} on`:null]}),d!=null&&d.line1?e.jsx("span",{children:d.line1}):null,d!=null&&d.line2?e.jsx("span",{children:d.line2}):null]})})]},a.id)}),r,l>0?e.jsxs(D,{children:[e.jsx($,{asChild:!0,children:e.jsx("div",{tabIndex:0,"aria-label":m,className:f("flex items-center justify-center rounded-full border bg-accent text-xs text-accent-foreground",t?"h-8 w-8":"h-6 w-6"),children:e.jsx("span",{className:f("pointer-events-none overflow-hidden text-ellipsis whitespace-nowrap text-center",t?"w-8":"w-6"),children:t?`+${l}`:l})})}),e.jsx(V,{children:m})]}):null]})})}function Ce(){const t=S(),[s,n]=j.useState(!1);return e.jsxs("div",{className:"flex flex-col",children:[t?null:e.jsx(de,{}),e.jsxs("div",{className:f("flex flex-grow",{"h-[calc(100vh-64px-env(safe-area-inset-top)-env(safe-area-inset-bottom))]":!t,"h-[calc(100vh-112px-env(safe-area-inset-top)-env(safe-area-inset-bottom))] sm:h-[calc(100vh-64px-env(safe-area-inset-top)-env(safe-area-inset-bottom))]":ENV.EPICSHOP_DEPLOYED,"h-[calc(100vh-env(safe-area-inset-top)-env(safe-area-inset-bottom))]":t}),children:[e.jsx(fe,{isMenuOpened:s,onMenuOpenChange:n}),e.jsx("div",{className:f("h-full w-full max-w-[calc(100%-56px)]",s?"hidden md:block":""),children:e.jsx(K,{})})]})]})}function ce(t){if(!t)return null;const{exercise:s}=t,n=[s?[s.exerciseNumber,s.stepNumber].filter(Boolean).map(o=>o.toString().padStart(2,"0")).join("/"):null,s==null?void 0:s.type].filter(Boolean).join(" - ");return{line1:t.workshopTitle,line2:n}}function de(){return e.jsxs("div",{className:f("z-10 flex items-center justify-between border-b bg-gradient-to-tr from-blue-500 to-indigo-500 pl-4 text-white",ENV.EPICSHOP_DEPLOYED?"h-[112px] md:h-[64px]":"h-16"),children:[e.jsxs("div",{className:"flex flex-1 flex-wrap items-center gap-4",children:[e.jsx(b,{name:"EpicWeb",size:"lg"}),e.jsxs("div",{className:"flex flex-1 flex-wrap items-center",children:[e.jsxs("p",{className:"mr-2",children:["Welcome to the"," ",e.jsx(u,{to:"https://www.epicweb.dev",className:"underline",target:"_blank",children:"EpicWeb.dev"})," ","Workshop app!"]}),ENV.EPICSHOP_DEPLOYED?e.jsxs("small",{className:"text-sm",children:["This is the deployed version."," ",ENV.EPICSHOP_GITHUB_ROOT?e.jsx(u,{className:"underline",target:"_blank",rel:"noopener noreferrer",to:ENV.EPICSHOP_GITHUB_ROOT,children:"Run locally"}):null," ","for full experience."]}):null]})]}),e.jsxs("div",{className:"flex h-full flex-col items-center md:flex-row",children:[e.jsxs(u,{to:"https://www.epicweb.dev",target:"_blank",className:"flex h-full items-center justify-center space-x-1.5 px-5 text-sm font-semibold",children:[e.jsx("span",{className:"drop-shadow-sm",children:"Join Epic Web"}),e.jsx("span",{children:"↗︎"})]}),e.jsxs(u,{to:ENV.EPICSHOP_DEPLOYED?"https://www.epicweb.dev/login":"/login",className:"flex h-full items-center justify-center space-x-1.5 bg-white/20 px-5 text-sm font-semibold shadow-md transition hover:bg-white/30",children:[e.jsx(b,{name:"User",size:"lg"}),e.jsx("span",{className:"drop-shadow-sm",children:"Login"})]})]})]})}const z={hidden:{opacity:0,x:-20},visible:{opacity:1,x:0}};function ue({exerciseNumber:t,children:s}){const n=ee(t);return e.jsx(h.li,{variants:z,className:f("py-[6px] first:pt-3 last:pb-3",n?`${n} before:border-t`:null),children:e.jsx("span",{className:"ml-2",children:s})})}function C({children:t,...s}){const n=te(s);return e.jsx(h.li,{variants:z,className:f("py-[6px] first:pt-3 last:pb-3",n?`${n} before:border-t`:null),children:e.jsx("span",{className:"ml-2",children:t})})}const k=400;function fe({isMenuOpened:t,onMenuOpenChange:s}){const n=ae(),o=S(),l=M(),r=Q(),{users:m}=O(),a=n.exercises.find(i=>i.exerciseNumber===Number(r.exerciseNumber)),c=r.type==="solution"?a==null?void 0:a.solutions.find(i=>i.stepNumber===Number(r.stepNumber)):r.type==="problem"?a==null?void 0:a.problems.find(i=>i.stepNumber===Number(r.stepNumber)):null,p=_(),d={close:{width:56},open:{width:k}},g={visible:{opacity:1,transition:{duration:.05,when:"beforeChildren",staggerChildren:.03}},hidden:{opacity:0}},L=Number(r.exerciseNumber).toString().padStart(2,"0");return e.jsx("nav",{className:"flex border-r",children:e.jsx(h.div,{initial:t?"open":"close",variants:d,animate:p,children:e.jsxs("div",{className:"flex h-full flex-col items-center justify-between",children:[e.jsx(he,{title:n.workshopTitle,menuControls:p,isMenuOpened:t,setMenuOpened:s}),t&&e.jsxs(h.div,{style:{width:k},className:"flex flex-grow flex-col justify-between overflow-y-auto p-6 scrollbar-thin scrollbar-thumb-scrollbar",initial:{opacity:0},animate:{opacity:1},children:[e.jsx(h.ul,{variants:g,initial:"hidden",animate:"visible",className:"flex flex-col",children:n.exercises.map(({exerciseNumber:i,title:B,steps:R})=>{const N=Number(r.exerciseNumber)===i,F=!N&&n.playground.exerciseNumber===i,v=i.toString().padStart(2,"0");return e.jsxs(ue,{exerciseNumber:i,children:[e.jsxs(u,{prefetch:"intent",to:`/${v}`,className:x("relative whitespace-nowrap px-2 py-0.5 pr-3 text-2xl font-bold outline-none hover:underline focus:underline",'after:absolute after:-bottom-2.5 after:-right-2.5 after:h-5 after:w-5 after:rotate-45 after:scale-75 after:bg-background after:content-[""] hover:underline focus:underline',{"bg-foreground text-background":N}),children:[B,F?" 🛝":null]}),N?e.jsxs(h.ul,{variants:g,initial:"hidden",animate:"visible",className:"ml-4 mt-4 flex flex-col",children:[e.jsx(C,{type:"instructions",exerciseNumber:i,children:e.jsx(u,{to:`/${v}`,prefetch:"intent",className:x('relative whitespace-nowrap px-2 py-0.5 pr-3 text-xl font-medium outline-none after:absolute after:-bottom-2.5 after:-right-2.5 after:h-5 after:w-5 after:rotate-45 after:scale-75 after:bg-background after:content-[""] hover:underline focus:underline',{"bg-foreground text-background":!r.stepNumber}),children:"Intro"})},i),R.filter(Boolean).map(({name:y,stepNumber:w,title:T})=>{const G=Number(r.stepNumber)===w,E=w.toString().padStart(2,"0"),J=y===n.playground.appName;return e.jsx(C,{type:"step",stepNumber:w,exerciseNumber:i,children:e.jsx(u,{to:`/${v}/${E}`,prefetch:"intent",className:x('relative whitespace-nowrap px-2 py-0.5 pr-3 text-xl font-medium outline-none after:absolute after:-bottom-2.5 after:-right-2.5 after:h-5 after:w-5 after:rotate-45 after:scale-75 after:bg-background after:content-[""] hover:underline focus:underline',{"bg-foreground text-background":G}),children:J?`${E}. ${T} 🛝`:`${E}. ${T}`})},w)}),e.jsx(C,{type:"finished",exerciseNumber:i,children:e.jsx(W,{to:`/${v}/finished`,prefetch:"intent",className:({isActive:y})=>x('relative whitespace-nowrap px-2 py-0.5 pr-3 text-base font-medium outline-none after:absolute after:-bottom-2.5 after:-right-2.5 after:h-5 after:w-5 after:rotate-45 after:scale-75 after:bg-background after:content-[""] hover:underline focus:underline',{"bg-foreground text-background":y}),children:"📝 Elaboration"})})]}):null]},i)})}),e.jsx("div",{className:"mt-6",children:e.jsx(W,{to:"/finished",className:({isActive:i})=>x("relative whitespace-nowrap text-lg font-bold outline-none hover:underline focus:underline",{'bg-black text-white after:absolute after:-bottom-2.5 after:-right-2.5 after:h-5 after:w-5 after:rotate-45 after:scale-75 after:bg-background after:content-[""]':i}),children:"📝 Workshop Feedback"})})]}),!t&&e.jsx("div",{className:"flex flex-grow flex-col justify-center",children:e.jsxs("div",{className:"orientation-sideways w-full font-mono text-sm font-medium uppercase leading-none",children:[a!=null&&a.title?e.jsx(u,{to:`/${L}`,children:a.title}):null,a!=null&&a.title&&(c!=null&&c.title)?" — ":null,c!=null&&c.title?e.jsx(u,{to:`/${L}/${c.stepNumber.toString().padStart(2,"0")}`,children:c.title}):null]})}),e.jsx("div",{className:f("flex w-full items-center justify-start border-t p-4 transition-[height]",t&&m.length>4?"h-28":"h-14"),style:t?{width:k}:{},children:e.jsx(ie,{isMenuOpened:t})}),ENV.EPICSHOP_DEPLOYED?null:o?e.jsx(I,{content:t?null:"Your account",children:e.jsxs(u,{className:"flex h-14 w-full items-center justify-start space-x-3 border-t px-4 py-4 text-center no-underline hover:underline",to:"/account",children:[o.avatarUrl?e.jsx("img",{alt:o.name??o.email,src:o.avatarUrl,className:"h-full rounded-full"}):e.jsx(b,{name:"User",className:"flex-shrink-0",size:"lg"}),t?e.jsx(h.div,{className:"flex items-center whitespace-nowrap",initial:{opacity:0},animate:{opacity:1},children:"Your Account"}):e.jsx("span",{className:"sr-only",children:"Your account"})]})}):null,ENV.EPICSHOP_DEPLOYED?null:o&&l?e.jsx(I,{content:t?null:"Continue to next lesson",children:e.jsxs(u,{to:l,prefetch:"intent",className:x("flex h-14 w-full items-center space-x-3 border-t px-4 py-4 pl-[18px] no-underline hover:underline"),state:{from:"continue next lesson button"},children:[e.jsx(b,{name:"FastForward",className:"flex-shrink-0",size:"md"}),t?e.jsx(h.div,{className:"flex items-center whitespace-nowrap",initial:{opacity:0},animate:{opacity:1},children:"Continue to next lesson"}):e.jsx("span",{className:"sr-only",children:"Continue to next lesson"})]})}):null,e.jsx("div",{className:"mb-4 w-full self-start border-t pl-3 pt-[15px]",children:e.jsx(se,{})})]})})})}function he({title:t,isMenuOpened:s,setMenuOpened:n,menuControls:o}){const l={open:{d:"M3.06061 2.99999L21.0606 21"},closed:{d:"M0 9.5L24 9.5"}},r={open:{d:"M3.00006 21.0607L21 3.06064"},moving:{d:"M0 14.5L24 14.5"},closed:{d:"M0 14.5L15 14.5"}},m=_(),a=_();async function c(){o.start(s?"close":"open"),n(!s),s?(m.start(l.closed),await a.start(r.moving),a.start(r.closed)):(await a.start(r.moving),m.start(l.open),a.start(r.open))}const p=j.useRef(c);return j.useEffect(()=>{p.current=c}),j.useEffect(()=>{if(!s)return;function d(g){g.key==="Escape"&&p.current()}return document.addEventListener("keyup",d),()=>document.removeEventListener("keyup",d)},[s]),e.jsxs("div",{className:"relative inline-flex h-14 w-full items-center justify-between overflow-hidden border-b",children:[e.jsx("button",{className:"flex h-14 w-14 items-center justify-center","aria-label":"Open Navigation menu",onClick:c,children:e.jsxs("svg",{width:"24",height:"24",viewBox:"0 0 24 24",children:[e.jsx(h.path,{...l.closed,animate:m,transition:{duration:.2},stroke:"currentColor",strokeWidth:1.5}),e.jsx(h.path,{...r.closed,animate:a,transition:{duration:.2},stroke:"currentColor",strokeWidth:1.5})]})}),s&&e.jsx(h.p,{transition:{delay:.2},initial:{opacity:0,y:5},animate:{opacity:1,y:0},className:"absolute right-5 whitespace-nowrap font-mono text-sm uppercase",children:e.jsx(u,{to:"/",children:t})})]})}export{Ce as default};
|
|
2
|
+
//# sourceMappingURL=_layout-D7Qo_r0X.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"_layout-C8fK4Z98.js","sources":["../../../../../node_modules/framer-motion/dist/es/animation/hooks/animation-controls.mjs","../../../../../node_modules/framer-motion/dist/es/animation/hooks/use-animation.mjs","../../../app/routes/_app+/_layout.tsx"],"sourcesContent":["import { invariant } from '../../utils/errors.mjs';\nimport { setTarget } from '../../render/utils/setters.mjs';\nimport { animateVisualElement } from '../interfaces/visual-element.mjs';\n\nfunction stopAnimation(visualElement) {\n visualElement.values.forEach((value) => value.stop());\n}\nfunction setVariants(visualElement, variantLabels) {\n const reversedLabels = [...variantLabels].reverse();\n reversedLabels.forEach((key) => {\n const variant = visualElement.getVariant(key);\n variant && setTarget(visualElement, variant);\n if (visualElement.variantChildren) {\n visualElement.variantChildren.forEach((child) => {\n setVariants(child, variantLabels);\n });\n }\n });\n}\nfunction setValues(visualElement, definition) {\n if (Array.isArray(definition)) {\n return setVariants(visualElement, definition);\n }\n else if (typeof definition === \"string\") {\n return setVariants(visualElement, [definition]);\n }\n else {\n setTarget(visualElement, definition);\n }\n}\n/**\n * @public\n */\nfunction animationControls() {\n /**\n * Track whether the host component has mounted.\n */\n let hasMounted = false;\n /**\n * A collection of linked component animation controls.\n */\n const subscribers = new Set();\n const controls = {\n subscribe(visualElement) {\n subscribers.add(visualElement);\n return () => void subscribers.delete(visualElement);\n },\n start(definition, transitionOverride) {\n invariant(hasMounted, \"controls.start() should only be called after a component has mounted. Consider calling within a useEffect hook.\");\n const animations = [];\n subscribers.forEach((visualElement) => {\n animations.push(animateVisualElement(visualElement, definition, {\n transitionOverride,\n }));\n });\n return Promise.all(animations);\n },\n set(definition) {\n invariant(hasMounted, \"controls.set() should only be called after a component has mounted. Consider calling within a useEffect hook.\");\n return subscribers.forEach((visualElement) => {\n setValues(visualElement, definition);\n });\n },\n stop() {\n subscribers.forEach((visualElement) => {\n stopAnimation(visualElement);\n });\n },\n mount() {\n hasMounted = true;\n return () => {\n hasMounted = false;\n controls.stop();\n };\n },\n };\n return controls;\n}\n\nexport { animationControls, setValues };\n","import { animationControls } from './animation-controls.mjs';\nimport { useConstant } from '../../utils/use-constant.mjs';\nimport { useIsomorphicLayoutEffect } from '../../utils/use-isomorphic-effect.mjs';\n\n/**\n * Creates `AnimationControls`, which can be used to manually start, stop\n * and sequence animations on one or more components.\n *\n * The returned `AnimationControls` should be passed to the `animate` property\n * of the components you want to animate.\n *\n * These components can then be animated with the `start` method.\n *\n * ```jsx\n * import * as React from 'react'\n * import { motion, useAnimation } from 'framer-motion'\n *\n * export function MyComponent(props) {\n * const controls = useAnimation()\n *\n * controls.start({\n * x: 100,\n * transition: { duration: 0.5 },\n * })\n *\n * return <motion.div animate={controls} />\n * }\n * ```\n *\n * @returns Animation controller with `start` and `stop` methods\n *\n * @public\n */\nfunction useAnimationControls() {\n const controls = useConstant(animationControls);\n useIsomorphicLayoutEffect(controls.mount, []);\n return controls;\n}\nconst useAnimation = useAnimationControls;\n\nexport { useAnimation, useAnimationControls };\n","import {\n\textractNumbersAndTypeFromAppNameOrPath,\n\tgetExercises,\n\tgetPlaygroundAppName,\n\tgetWorkshopTitle,\n} from '@epic-web/workshop-utils/apps.server'\nimport {\n\tcombineServerTimings,\n\tgetServerTimeHeader,\n\tmakeTimings,\n} from '@epic-web/workshop-utils/timing.server'\nimport {\n\ttype LoaderFunctionArgs,\n\ttype HeadersFunction,\n\tjson,\n} from '@remix-run/node'\nimport {\n\tLink,\n\tNavLink,\n\tOutlet,\n\tuseLoaderData,\n\tuseParams,\n} from '@remix-run/react'\nimport { clsx } from 'clsx'\nimport {\n\ttype AnimationControls,\n\tmotion,\n\tuseAnimationControls,\n} from 'framer-motion'\nimport * as React from 'react'\nimport {\n\tuseNextExerciseRoute,\n\tuseExerciseProgressClassName,\n\ttype ProgressItemSearch,\n\tuseProgressItemClassName,\n} from '../progress.tsx'\nimport { ThemeSwitch } from '../theme/index.tsx'\nimport { Icon } from '#app/components/icons.tsx'\nimport {\n\tSimpleTooltip,\n\tTooltip,\n\tTooltipContent,\n\tTooltipProvider,\n\tTooltipTrigger,\n} from '#app/components/ui/tooltip.tsx'\nimport { useOptionalUser } from '#app/components/user.tsx'\nimport { cn } from '#app/utils/misc.tsx'\nimport { type User, usePresence } from '#app/utils/presence.tsx'\n\nexport async function loader({ request }: LoaderFunctionArgs) {\n\tconst timings = makeTimings('stepLoader')\n\tconst [exercises, workshopTitle, playgroundAppName] = await Promise.all([\n\t\tgetExercises({ request, timings }),\n\t\tgetWorkshopTitle(),\n\t\tgetPlaygroundAppName(),\n\t])\n\n\tconst playground = {\n\t\tappName: playgroundAppName,\n\t\texerciseNumber: Number(\n\t\t\textractNumbersAndTypeFromAppNameOrPath(playgroundAppName ?? '')\n\t\t\t\t?.exerciseNumber,\n\t\t),\n\t}\n\n\tconst result = json(\n\t\t{\n\t\t\tworkshopTitle,\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\tsolutions: e.solutions.map(({ stepNumber, title, name }) => ({\n\t\t\t\t\tstepNumber,\n\t\t\t\t\ttitle,\n\t\t\t\t\tname,\n\t\t\t\t})),\n\t\t\t\tproblems: e.problems.map(({ stepNumber, title, name }) => ({\n\t\t\t\t\tstepNumber,\n\t\t\t\t\ttitle,\n\t\t\t\t\tname,\n\t\t\t\t})),\n\t\t\t\tsteps: e.steps.map(({ stepNumber, problem, solution }) => ({\n\t\t\t\t\tstepNumber,\n\t\t\t\t\ttitle: problem?.title ?? solution?.title ?? 'Unknown',\n\t\t\t\t\tname: problem?.name ?? solution?.name ?? 'Unknown',\n\t\t\t\t})),\n\t\t\t})),\n\t\t\tplayground,\n\t\t},\n\t\t{\n\t\t\theaders: {\n\t\t\t\tVary: 'Cookie',\n\t\t\t\t'Server-Timing': getServerTimeHeader(timings),\n\t\t\t},\n\t\t},\n\t)\n\treturn result\n}\n\nexport const headers: HeadersFunction = ({ loaderHeaders, parentHeaders }) => {\n\tconst headers = {\n\t\t'Cache-Control': loaderHeaders.get('Cache-Control') ?? '',\n\t\tVary: 'Cookie',\n\t\t'Server-Timing': combineServerTimings(loaderHeaders, parentHeaders),\n\t}\n\treturn headers\n}\n\nconst opacities = ['opacity-70', 'opacity-80', 'opacity-90', 'opacity-100']\nconst shadows = [\n\t'shadow-[0_0_2px_0_rgba(0,0,0,0.3)]',\n\t'shadow-[0_0_4px_0_rgba(0,0,0,0.3)]',\n\t'shadow-[0_0_7px_0_rgba(0,0,0,0.3)]',\n\t'shadow-[0_0_10px_0_rgba(0,0,0,0.3)]',\n]\nfunction getScoreClassNames(score: number) {\n\tconst opacityNumber = Math.round(score * opacities.length - 1)\n\tconst shadowNumber = Math.round(score * shadows.length - 1)\n\treturn cn(\n\t\t'shadow-purple-700 hover:opacity-100 focus:opacity-100 dark:shadow-purple-200',\n\t\topacities[opacityNumber] ?? 'opacity-60',\n\t\tshadows[shadowNumber] ?? 'shadow-none',\n\t\tscore === 1 ? 'animate-pulse hover:animate-none focus:animate-none' : null,\n\t)\n}\n\nfunction FacePile({ isMenuOpened }: { isMenuOpened: boolean }) {\n\tconst loggedInUser = useOptionalUser()\n\tconst { users } = usePresence()\n\tconst limit = isMenuOpened ? 17 : 0\n\tconst numberOverLimit = users.length - limit\n\tif (!users.length) return null\n\tconst tiffany =\n\t\tisMenuOpened && users.length === 1 ? (\n\t\t\t<Link\n\t\t\t\ttarget=\"_blank\"\n\t\t\t\trel=\"noopener noreferrer\"\n\t\t\t\tto=\"https://www.youtube.com/watch?v=w6Q3mHyzn78\"\n\t\t\t>\n\t\t\t\t<img\n\t\t\t\t\talt=\"Tiffany Tunes\"\n\t\t\t\t\tclassName={cn(\n\t\t\t\t\t\t'h-8 w-8 rounded-full border object-cover',\n\t\t\t\t\t\tgetScoreClassNames(1),\n\t\t\t\t\t)}\n\t\t\t\t\tsrc=\"https://github-production-user-asset-6210df.s3.amazonaws.com/1500684/277090714-b26e5961-4ee5-4c20-abdb-b04c1c480f2b.png\"\n\t\t\t\t/>\n\t\t\t</Link>\n\t\t) : null\n\tconst overLimitLabel = `${numberOverLimit}${\n\t\tisMenuOpened ? ' more ' : ' '\n\t}Epic Web Dev${numberOverLimit === 1 ? '' : 's'} working now`\n\treturn (\n\t\t<div className=\"flex flex-wrap items-center gap-2\">\n\t\t\t<TooltipProvider>\n\t\t\t\t{users.slice(0, limit).map(({ user, score }) => {\n\t\t\t\t\tconst scoreClassNames = getScoreClassNames(score)\n\t\t\t\t\tconst locationLabel = getLocationLabel(user.location)\n\t\t\t\t\treturn (\n\t\t\t\t\t\t<Tooltip key={user.id}>\n\t\t\t\t\t\t\t<TooltipTrigger asChild>\n\t\t\t\t\t\t\t\t{user.avatarUrl ? (\n\t\t\t\t\t\t\t\t\t<img\n\t\t\t\t\t\t\t\t\t\ttabIndex={0}\n\t\t\t\t\t\t\t\t\t\talt={user.name || 'Epic Web Dev'}\n\t\t\t\t\t\t\t\t\t\tclassName={cn(\n\t\t\t\t\t\t\t\t\t\t\t'h-8 w-8 rounded-full border object-cover',\n\t\t\t\t\t\t\t\t\t\t\tscoreClassNames,\n\t\t\t\t\t\t\t\t\t\t)}\n\t\t\t\t\t\t\t\t\t\tsrc={user.avatarUrl}\n\t\t\t\t\t\t\t\t\t/>\n\t\t\t\t\t\t\t\t) : (\n\t\t\t\t\t\t\t\t\t<div\n\t\t\t\t\t\t\t\t\t\ttabIndex={0}\n\t\t\t\t\t\t\t\t\t\taria-label={user.name || 'Epic Web Dev'}\n\t\t\t\t\t\t\t\t\t\tclassName={cn(\n\t\t\t\t\t\t\t\t\t\t\t'flex h-8 w-8 items-center justify-center rounded-full border',\n\t\t\t\t\t\t\t\t\t\t\tscoreClassNames,\n\t\t\t\t\t\t\t\t\t\t)}\n\t\t\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t\t\t<Icon name=\"User\" />\n\t\t\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t\t\t)}\n\t\t\t\t\t\t\t</TooltipTrigger>\n\t\t\t\t\t\t\t<TooltipContent>\n\t\t\t\t\t\t\t\t<span className=\"flex flex-col items-center justify-center gap-1\">\n\t\t\t\t\t\t\t\t\t<span>\n\t\t\t\t\t\t\t\t\t\t{user.name || 'An EPIC Web Dev'}{' '}\n\t\t\t\t\t\t\t\t\t\t{locationLabel\n\t\t\t\t\t\t\t\t\t\t\t? ` is working ${\n\t\t\t\t\t\t\t\t\t\t\t\t\tscore === 1 && loggedInUser?.id !== user.id\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t? 'with you'\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t: ''\n\t\t\t\t\t\t\t\t\t\t\t\t} on`\n\t\t\t\t\t\t\t\t\t\t\t: null}\n\t\t\t\t\t\t\t\t\t</span>\n\t\t\t\t\t\t\t\t\t{locationLabel?.line1 ? (\n\t\t\t\t\t\t\t\t\t\t<span>{locationLabel.line1}</span>\n\t\t\t\t\t\t\t\t\t) : null}\n\t\t\t\t\t\t\t\t\t{locationLabel?.line2 ? (\n\t\t\t\t\t\t\t\t\t\t<span>{locationLabel.line2}</span>\n\t\t\t\t\t\t\t\t\t) : null}\n\t\t\t\t\t\t\t\t</span>\n\t\t\t\t\t\t\t</TooltipContent>\n\t\t\t\t\t\t</Tooltip>\n\t\t\t\t\t)\n\t\t\t\t})}\n\t\t\t\t{tiffany}\n\t\t\t\t{numberOverLimit > 0 ? (\n\t\t\t\t\t<Tooltip>\n\t\t\t\t\t\t<TooltipTrigger asChild>\n\t\t\t\t\t\t\t<div\n\t\t\t\t\t\t\t\ttabIndex={0}\n\t\t\t\t\t\t\t\taria-label={overLimitLabel}\n\t\t\t\t\t\t\t\tclassName={cn(\n\t\t\t\t\t\t\t\t\t'flex items-center justify-center rounded-full border bg-accent text-xs text-accent-foreground',\n\t\t\t\t\t\t\t\t\tisMenuOpened ? 'h-8 w-8' : 'h-6 w-6',\n\t\t\t\t\t\t\t\t)}\n\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t<span\n\t\t\t\t\t\t\t\t\tclassName={cn(\n\t\t\t\t\t\t\t\t\t\t'pointer-events-none overflow-hidden text-ellipsis whitespace-nowrap text-center',\n\t\t\t\t\t\t\t\t\t\tisMenuOpened ? 'w-8' : 'w-6',\n\t\t\t\t\t\t\t\t\t)}\n\t\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t\t{isMenuOpened ? `+${numberOverLimit}` : numberOverLimit}\n\t\t\t\t\t\t\t\t</span>\n\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t</TooltipTrigger>\n\t\t\t\t\t\t<TooltipContent>{overLimitLabel}</TooltipContent>\n\t\t\t\t\t</Tooltip>\n\t\t\t\t) : null}\n\t\t\t</TooltipProvider>\n\t\t</div>\n\t)\n}\n\nexport default function App() {\n\tconst user = useOptionalUser()\n\n\tconst [isMenuOpened, setMenuOpened] = React.useState(false)\n\n\treturn (\n\t\t<div className=\"flex flex-col\">\n\t\t\t{user ? null : <EpicWebBanner />}\n\t\t\t<div\n\t\t\t\tclassName={cn('flex flex-grow', {\n\t\t\t\t\t'h-[calc(100vh-64px-env(safe-area-inset-top)-env(safe-area-inset-bottom))]':\n\t\t\t\t\t\t!user,\n\t\t\t\t\t'h-[calc(100vh-112px-env(safe-area-inset-top)-env(safe-area-inset-bottom))] sm:h-[calc(100vh-64px-env(safe-area-inset-top)-env(safe-area-inset-bottom))]':\n\t\t\t\t\t\tENV.EPICSHOP_DEPLOYED,\n\t\t\t\t\t'h-[calc(100vh-env(safe-area-inset-top)-env(safe-area-inset-bottom))]':\n\t\t\t\t\t\tuser,\n\t\t\t\t})}\n\t\t\t>\n\t\t\t\t<Navigation\n\t\t\t\t\tisMenuOpened={isMenuOpened}\n\t\t\t\t\tonMenuOpenChange={setMenuOpened}\n\t\t\t\t/>\n\t\t\t\t<div\n\t\t\t\t\tclassName={cn(\n\t\t\t\t\t\t'h-full w-full max-w-[calc(100%-56px)]',\n\t\t\t\t\t\tisMenuOpened ? 'hidden md:block' : '',\n\t\t\t\t\t)}\n\t\t\t\t>\n\t\t\t\t\t<Outlet />\n\t\t\t\t</div>\n\t\t\t</div>\n\t\t</div>\n\t)\n}\n\nfunction getLocationLabel(location: User['location']) {\n\tif (!location) return null\n\n\tconst { exercise } = location\n\n\tconst exercisePortion = [\n\t\texercise\n\t\t\t? [exercise.exerciseNumber, exercise.stepNumber]\n\t\t\t\t\t.filter(Boolean)\n\t\t\t\t\t.map(s => s.toString().padStart(2, '0'))\n\t\t\t\t\t.join('/')\n\t\t\t: null,\n\t\texercise?.type,\n\t]\n\t\t.filter(Boolean)\n\t\t.join(' - ')\n\treturn { line1: location.workshopTitle, line2: exercisePortion }\n}\n\nfunction EpicWebBanner() {\n\treturn (\n\t\t<div\n\t\t\tclassName={cn(\n\t\t\t\t'z-10 flex items-center justify-between border-b bg-gradient-to-tr from-blue-500 to-indigo-500 pl-4 text-white',\n\t\t\t\tENV.EPICSHOP_DEPLOYED ? 'h-[112px] md:h-[64px]' : 'h-16',\n\t\t\t)}\n\t\t>\n\t\t\t<div className=\"flex flex-1 flex-wrap items-center gap-4\">\n\t\t\t\t<Icon name=\"EpicWeb\" size=\"lg\" />\n\t\t\t\t<div className=\"flex flex-1 flex-wrap items-center\">\n\t\t\t\t\t<p className=\"mr-2\">\n\t\t\t\t\t\tWelcome to the{' '}\n\t\t\t\t\t\t<Link\n\t\t\t\t\t\t\tto=\"https://www.epicweb.dev\"\n\t\t\t\t\t\t\tclassName=\"underline\"\n\t\t\t\t\t\t\ttarget=\"_blank\"\n\t\t\t\t\t\t>\n\t\t\t\t\t\t\tEpicWeb.dev\n\t\t\t\t\t\t</Link>{' '}\n\t\t\t\t\t\tWorkshop app!\n\t\t\t\t\t</p>\n\t\t\t\t\t{ENV.EPICSHOP_DEPLOYED ? (\n\t\t\t\t\t\t<small className=\"text-sm\">\n\t\t\t\t\t\t\tThis is the deployed version.{' '}\n\t\t\t\t\t\t\t{ENV.EPICSHOP_GITHUB_ROOT ? (\n\t\t\t\t\t\t\t\t<Link\n\t\t\t\t\t\t\t\t\tclassName=\"underline\"\n\t\t\t\t\t\t\t\t\ttarget=\"_blank\"\n\t\t\t\t\t\t\t\t\trel=\"noopener noreferrer\"\n\t\t\t\t\t\t\t\t\tto={ENV.EPICSHOP_GITHUB_ROOT}\n\t\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t\tRun locally\n\t\t\t\t\t\t\t\t</Link>\n\t\t\t\t\t\t\t) : null}{' '}\n\t\t\t\t\t\t\tfor full experience.\n\t\t\t\t\t\t</small>\n\t\t\t\t\t) : null}\n\t\t\t\t</div>\n\t\t\t</div>\n\t\t\t<div className=\"flex h-full flex-col items-center md:flex-row\">\n\t\t\t\t<Link\n\t\t\t\t\tto=\"https://www.epicweb.dev\"\n\t\t\t\t\ttarget=\"_blank\"\n\t\t\t\t\tclassName=\"flex h-full items-center justify-center space-x-1.5 px-5 text-sm font-semibold\"\n\t\t\t\t>\n\t\t\t\t\t<span className=\"drop-shadow-sm\">Join Epic Web</span>\n\t\t\t\t\t<span>↗︎</span>\n\t\t\t\t</Link>\n\t\t\t\t<Link\n\t\t\t\t\tto={\n\t\t\t\t\t\tENV.EPICSHOP_DEPLOYED ? 'https://www.epicweb.dev/login' : '/login'\n\t\t\t\t\t}\n\t\t\t\t\tclassName=\"flex h-full items-center justify-center space-x-1.5 bg-white/20 px-5 text-sm font-semibold shadow-md transition hover:bg-white/30\"\n\t\t\t\t>\n\t\t\t\t\t<Icon name=\"User\" size=\"lg\" />\n\t\t\t\t\t<span className=\"drop-shadow-sm\">Login</span>\n\t\t\t\t</Link>\n\t\t\t</div>\n\t\t</div>\n\t)\n}\n\nconst itemVariants = {\n\thidden: { opacity: 0, x: -20 },\n\tvisible: { opacity: 1, x: 0 },\n}\nfunction NavigationExerciseListItem({\n\texerciseNumber,\n\tchildren,\n}: {\n\texerciseNumber: number\n\tchildren: React.ReactNode\n}) {\n\tconst progressClassName = useExerciseProgressClassName(exerciseNumber)\n\treturn (\n\t\t<motion.li\n\t\t\tvariants={itemVariants}\n\t\t\tclassName={cn(\n\t\t\t\t// add gap of 3 to children, but using padding so the progress extends through the whole height\n\t\t\t\t'py-[6px] first:pt-3 last:pb-3',\n\t\t\t\tprogressClassName ? `${progressClassName} before:border-t` : null,\n\t\t\t)}\n\t\t>\n\t\t\t<span className=\"ml-2\">{children}</span>\n\t\t</motion.li>\n\t)\n}\n\nfunction NavigationExerciseStepListItem({\n\tchildren,\n\t...progressItemSearch\n}: {\n\tchildren: React.ReactNode\n} & ProgressItemSearch) {\n\tconst progressClassName = useProgressItemClassName(progressItemSearch)\n\treturn (\n\t\t<motion.li\n\t\t\tvariants={itemVariants}\n\t\t\tclassName={cn(\n\t\t\t\t// add gap of 3 to children, but using padding so the progress extends through the whole height\n\t\t\t\t'py-[6px] first:pt-3 last:pb-3',\n\t\t\t\tprogressClassName ? `${progressClassName} before:border-t` : null,\n\t\t\t)}\n\t\t>\n\t\t\t<span className=\"ml-2\">{children}</span>\n\t\t</motion.li>\n\t)\n}\n\nconst OPENED_MENU_WIDTH = 400\n\nfunction Navigation({\n\tisMenuOpened,\n\tonMenuOpenChange: setMenuOpened,\n}: {\n\tisMenuOpened: boolean\n\tonMenuOpenChange: (change: boolean) => void\n}) {\n\tconst data = useLoaderData<typeof loader>()\n\tconst user = useOptionalUser()\n\tconst nextExerciseRoute = useNextExerciseRoute()\n\tconst params = useParams()\n\tconst { users } = usePresence()\n\n\tconst exercise = data.exercises.find(\n\t\te => e.exerciseNumber === Number(params.exerciseNumber),\n\t)\n\tconst app =\n\t\tparams.type === 'solution'\n\t\t\t? exercise?.solutions.find(\n\t\t\t\t\ts => s.stepNumber === Number(params.stepNumber),\n\t\t\t\t)\n\t\t\t: params.type === 'problem'\n\t\t\t\t? exercise?.problems.find(\n\t\t\t\t\t\tp => p.stepNumber === Number(params.stepNumber),\n\t\t\t\t\t)\n\t\t\t\t: null\n\n\t// container\n\tconst menuControls = useAnimationControls()\n\tconst menuVariants = {\n\t\tclose: { width: 56 },\n\t\topen: { width: OPENED_MENU_WIDTH },\n\t}\n\n\t// items\n\tconst listVariants = {\n\t\tvisible: {\n\t\t\topacity: 1,\n\t\t\ttransition: {\n\t\t\t\tduration: 0.05,\n\t\t\t\twhen: 'beforeChildren',\n\t\t\t\tstaggerChildren: 0.03,\n\t\t\t},\n\t\t},\n\t\thidden: {\n\t\t\topacity: 0,\n\t\t},\n\t}\n\tconst exNum = Number(params.exerciseNumber).toString().padStart(2, '0')\n\n\treturn (\n\t\t<nav className=\"flex border-r\">\n\t\t\t<motion.div\n\t\t\t\tinitial={isMenuOpened ? 'open' : 'close'}\n\t\t\t\tvariants={menuVariants}\n\t\t\t\tanimate={menuControls}\n\t\t\t>\n\t\t\t\t<div className=\"flex h-full flex-col items-center justify-between\">\n\t\t\t\t\t<NavToggle\n\t\t\t\t\t\ttitle={data.workshopTitle}\n\t\t\t\t\t\tmenuControls={menuControls}\n\t\t\t\t\t\tisMenuOpened={isMenuOpened}\n\t\t\t\t\t\tsetMenuOpened={setMenuOpened}\n\t\t\t\t\t/>\n\t\t\t\t\t{isMenuOpened && (\n\t\t\t\t\t\t<motion.div\n\t\t\t\t\t\t\tstyle={{ width: OPENED_MENU_WIDTH }}\n\t\t\t\t\t\t\tclassName=\"flex flex-grow flex-col justify-between overflow-y-auto p-6 scrollbar-thin scrollbar-thumb-scrollbar\"\n\t\t\t\t\t\t\tinitial={{ opacity: 0 }}\n\t\t\t\t\t\t\tanimate={{ opacity: 1 }}\n\t\t\t\t\t\t>\n\t\t\t\t\t\t\t<motion.ul\n\t\t\t\t\t\t\t\tvariants={listVariants}\n\t\t\t\t\t\t\t\tinitial=\"hidden\"\n\t\t\t\t\t\t\t\tanimate=\"visible\"\n\t\t\t\t\t\t\t\tclassName=\"flex flex-col\"\n\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t{data.exercises.map(({ exerciseNumber, title, steps }) => {\n\t\t\t\t\t\t\t\t\tconst isActive =\n\t\t\t\t\t\t\t\t\t\tNumber(params.exerciseNumber) === exerciseNumber\n\t\t\t\t\t\t\t\t\tconst showPlayground =\n\t\t\t\t\t\t\t\t\t\t!isActive &&\n\t\t\t\t\t\t\t\t\t\tdata.playground.exerciseNumber === exerciseNumber\n\t\t\t\t\t\t\t\t\tconst exerciseNum = exerciseNumber.toString().padStart(2, '0')\n\t\t\t\t\t\t\t\t\treturn (\n\t\t\t\t\t\t\t\t\t\t<NavigationExerciseListItem\n\t\t\t\t\t\t\t\t\t\t\tkey={exerciseNumber}\n\t\t\t\t\t\t\t\t\t\t\texerciseNumber={exerciseNumber}\n\t\t\t\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t\t\t\t<Link\n\t\t\t\t\t\t\t\t\t\t\t\tprefetch=\"intent\"\n\t\t\t\t\t\t\t\t\t\t\t\tto={`/${exerciseNum}`}\n\t\t\t\t\t\t\t\t\t\t\t\tclassName={clsx(\n\t\t\t\t\t\t\t\t\t\t\t\t\t'relative whitespace-nowrap px-2 py-0.5 pr-3 text-2xl font-bold outline-none hover:underline focus:underline',\n\t\t\t\t\t\t\t\t\t\t\t\t\t'after:absolute after:-bottom-2.5 after:-right-2.5 after:h-5 after:w-5 after:rotate-45 after:scale-75 after:bg-background after:content-[\"\"] hover:underline focus:underline',\n\t\t\t\t\t\t\t\t\t\t\t\t\t{ 'bg-foreground text-background': isActive },\n\t\t\t\t\t\t\t\t\t\t\t\t)}\n\t\t\t\t\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t\t\t\t\t{title}\n\t\t\t\t\t\t\t\t\t\t\t\t{showPlayground ? ' 🛝' : null}\n\t\t\t\t\t\t\t\t\t\t\t</Link>\n\t\t\t\t\t\t\t\t\t\t\t{isActive ? (\n\t\t\t\t\t\t\t\t\t\t\t\t<motion.ul\n\t\t\t\t\t\t\t\t\t\t\t\t\tvariants={listVariants}\n\t\t\t\t\t\t\t\t\t\t\t\t\tinitial=\"hidden\"\n\t\t\t\t\t\t\t\t\t\t\t\t\tanimate=\"visible\"\n\t\t\t\t\t\t\t\t\t\t\t\t\tclassName=\"ml-4 mt-4 flex flex-col\"\n\t\t\t\t\t\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t\t\t\t\t\t<NavigationExerciseStepListItem\n\t\t\t\t\t\t\t\t\t\t\t\t\t\tkey={exerciseNumber}\n\t\t\t\t\t\t\t\t\t\t\t\t\t\ttype=\"instructions\"\n\t\t\t\t\t\t\t\t\t\t\t\t\t\texerciseNumber={exerciseNumber}\n\t\t\t\t\t\t\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t<Link\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tto={`/${exerciseNum}`}\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tprefetch=\"intent\"\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tclassName={clsx(\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t'relative whitespace-nowrap px-2 py-0.5 pr-3 text-xl font-medium outline-none after:absolute after:-bottom-2.5 after:-right-2.5 after:h-5 after:w-5 after:rotate-45 after:scale-75 after:bg-background after:content-[\"\"] hover:underline focus:underline',\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t'bg-foreground text-background':\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t!params.stepNumber,\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t)}\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tIntro\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t</Link>\n\t\t\t\t\t\t\t\t\t\t\t\t\t</NavigationExerciseStepListItem>\n\t\t\t\t\t\t\t\t\t\t\t\t\t{steps\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t.filter(Boolean)\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t.map(({ name, stepNumber, title }) => {\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tconst isActive =\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tNumber(params.stepNumber) === stepNumber\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tconst step = stepNumber\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t.toString()\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t.padStart(2, '0')\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tconst isPlayground =\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tname === data.playground.appName\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\treturn (\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<NavigationExerciseStepListItem\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tkey={stepNumber}\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\ttype=\"step\"\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tstepNumber={stepNumber}\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\texerciseNumber={exerciseNumber}\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<Link\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tto={`/${exerciseNum}/${step}`}\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tprefetch=\"intent\"\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tclassName={clsx(\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t'relative whitespace-nowrap px-2 py-0.5 pr-3 text-xl font-medium outline-none after:absolute after:-bottom-2.5 after:-right-2.5 after:h-5 after:w-5 after:rotate-45 after:scale-75 after:bg-background after:content-[\"\"] hover:underline focus:underline',\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t'bg-foreground text-background':\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tisActive,\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t)}\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t{isPlayground\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t? `${step}. ${title} 🛝`\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t: `${step}. ${title}`}\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</Link>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</NavigationExerciseStepListItem>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t)\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t})}\n\t\t\t\t\t\t\t\t\t\t\t\t\t<NavigationExerciseStepListItem\n\t\t\t\t\t\t\t\t\t\t\t\t\t\ttype=\"finished\"\n\t\t\t\t\t\t\t\t\t\t\t\t\t\texerciseNumber={exerciseNumber}\n\t\t\t\t\t\t\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t<NavLink\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tto={`/${exerciseNum}/finished`}\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tprefetch=\"intent\"\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tclassName={({ isActive }) =>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tclsx(\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t'relative whitespace-nowrap px-2 py-0.5 pr-3 text-base font-medium outline-none after:absolute after:-bottom-2.5 after:-right-2.5 after:h-5 after:w-5 after:rotate-45 after:scale-75 after:bg-background after:content-[\"\"] hover:underline focus:underline',\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t'bg-foreground text-background': isActive,\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t)\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t📝 Elaboration\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t</NavLink>\n\t\t\t\t\t\t\t\t\t\t\t\t\t</NavigationExerciseStepListItem>\n\t\t\t\t\t\t\t\t\t\t\t\t</motion.ul>\n\t\t\t\t\t\t\t\t\t\t\t) : null}\n\t\t\t\t\t\t\t\t\t\t</NavigationExerciseListItem>\n\t\t\t\t\t\t\t\t\t)\n\t\t\t\t\t\t\t\t})}\n\t\t\t\t\t\t\t</motion.ul>\n\t\t\t\t\t\t\t<div className=\"mt-6\">\n\t\t\t\t\t\t\t\t<NavLink\n\t\t\t\t\t\t\t\t\tto=\"/finished\"\n\t\t\t\t\t\t\t\t\tclassName={({ isActive }) =>\n\t\t\t\t\t\t\t\t\t\tclsx(\n\t\t\t\t\t\t\t\t\t\t\t'relative whitespace-nowrap text-lg font-bold outline-none hover:underline focus:underline',\n\t\t\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t\t\t'bg-black text-white after:absolute after:-bottom-2.5 after:-right-2.5 after:h-5 after:w-5 after:rotate-45 after:scale-75 after:bg-background after:content-[\"\"]':\n\t\t\t\t\t\t\t\t\t\t\t\t\tisActive,\n\t\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\t)\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t\t📝 Workshop Feedback\n\t\t\t\t\t\t\t\t</NavLink>\n\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t</motion.div>\n\t\t\t\t\t)}\n\t\t\t\t\t{!isMenuOpened && (\n\t\t\t\t\t\t<div className=\"flex flex-grow flex-col justify-center\">\n\t\t\t\t\t\t\t<div className=\"orientation-sideways w-full font-mono text-sm font-medium uppercase leading-none\">\n\t\t\t\t\t\t\t\t{exercise?.title ? (\n\t\t\t\t\t\t\t\t\t<Link to={`/${exNum}`}>{exercise.title}</Link>\n\t\t\t\t\t\t\t\t) : null}\n\t\t\t\t\t\t\t\t{exercise?.title && app?.title ? ' — ' : null}\n\t\t\t\t\t\t\t\t{app?.title ? (\n\t\t\t\t\t\t\t\t\t<Link\n\t\t\t\t\t\t\t\t\t\tto={`/${exNum}/${app.stepNumber\n\t\t\t\t\t\t\t\t\t\t\t.toString()\n\t\t\t\t\t\t\t\t\t\t\t.padStart(2, '0')}`}\n\t\t\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t\t\t{app.title}\n\t\t\t\t\t\t\t\t\t</Link>\n\t\t\t\t\t\t\t\t) : null}\n\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t</div>\n\t\t\t\t\t)}\n\t\t\t\t\t<div\n\t\t\t\t\t\tclassName={cn(\n\t\t\t\t\t\t\t'flex w-full items-center justify-start border-t p-4 transition-[height]',\n\t\t\t\t\t\t\tisMenuOpened && users.length > 4 ? 'h-28' : 'h-14',\n\t\t\t\t\t\t)}\n\t\t\t\t\t\tstyle={isMenuOpened ? { width: OPENED_MENU_WIDTH } : {}}\n\t\t\t\t\t>\n\t\t\t\t\t\t<FacePile isMenuOpened={isMenuOpened} />\n\t\t\t\t\t</div>\n\t\t\t\t\t{ENV.EPICSHOP_DEPLOYED ? null : user ? (\n\t\t\t\t\t\t<SimpleTooltip content={isMenuOpened ? null : 'Your account'}>\n\t\t\t\t\t\t\t<Link\n\t\t\t\t\t\t\t\tclassName=\"flex h-14 w-full items-center justify-start space-x-3 border-t px-4 py-4 text-center no-underline hover:underline\"\n\t\t\t\t\t\t\t\tto=\"/account\"\n\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t{user.avatarUrl ? (\n\t\t\t\t\t\t\t\t\t<img\n\t\t\t\t\t\t\t\t\t\talt={user.name ?? user.email}\n\t\t\t\t\t\t\t\t\t\tsrc={user.avatarUrl}\n\t\t\t\t\t\t\t\t\t\tclassName=\"h-full rounded-full\"\n\t\t\t\t\t\t\t\t\t/>\n\t\t\t\t\t\t\t\t) : (\n\t\t\t\t\t\t\t\t\t<Icon name=\"User\" className=\"flex-shrink-0\" size=\"lg\" />\n\t\t\t\t\t\t\t\t)}\n\t\t\t\t\t\t\t\t{isMenuOpened ? (\n\t\t\t\t\t\t\t\t\t<motion.div\n\t\t\t\t\t\t\t\t\t\tclassName=\"flex items-center whitespace-nowrap\"\n\t\t\t\t\t\t\t\t\t\tinitial={{ opacity: 0 }}\n\t\t\t\t\t\t\t\t\t\tanimate={{ opacity: 1 }}\n\t\t\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t\t\tYour Account\n\t\t\t\t\t\t\t\t\t</motion.div>\n\t\t\t\t\t\t\t\t) : (\n\t\t\t\t\t\t\t\t\t<span className=\"sr-only\">Your account</span>\n\t\t\t\t\t\t\t\t)}\n\t\t\t\t\t\t\t</Link>\n\t\t\t\t\t\t</SimpleTooltip>\n\t\t\t\t\t) : null}\n\t\t\t\t\t{ENV.EPICSHOP_DEPLOYED ? null : user && nextExerciseRoute ? (\n\t\t\t\t\t\t<SimpleTooltip\n\t\t\t\t\t\t\tcontent={isMenuOpened ? null : 'Continue to next lesson'}\n\t\t\t\t\t\t>\n\t\t\t\t\t\t\t<Link\n\t\t\t\t\t\t\t\tto={nextExerciseRoute}\n\t\t\t\t\t\t\t\tprefetch=\"intent\"\n\t\t\t\t\t\t\t\tclassName={clsx(\n\t\t\t\t\t\t\t\t\t'flex h-14 w-full items-center space-x-3 border-t px-4 py-4 pl-[18px] no-underline hover:underline',\n\t\t\t\t\t\t\t\t)}\n\t\t\t\t\t\t\t\tstate={{ from: 'continue next lesson button' }}\n\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t<Icon name=\"FastForward\" className=\"flex-shrink-0\" size=\"md\" />\n\t\t\t\t\t\t\t\t{isMenuOpened ? (\n\t\t\t\t\t\t\t\t\t<motion.div\n\t\t\t\t\t\t\t\t\t\tclassName=\"flex items-center whitespace-nowrap\"\n\t\t\t\t\t\t\t\t\t\tinitial={{ opacity: 0 }}\n\t\t\t\t\t\t\t\t\t\tanimate={{ opacity: 1 }}\n\t\t\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t\t\tContinue to next lesson\n\t\t\t\t\t\t\t\t\t</motion.div>\n\t\t\t\t\t\t\t\t) : (\n\t\t\t\t\t\t\t\t\t<span className=\"sr-only\">Continue to next lesson</span>\n\t\t\t\t\t\t\t\t)}\n\t\t\t\t\t\t\t</Link>\n\t\t\t\t\t\t</SimpleTooltip>\n\t\t\t\t\t) : null}\n\t\t\t\t\t<div className=\"mb-4 w-full self-start border-t pl-3 pt-[15px]\">\n\t\t\t\t\t\t<ThemeSwitch />\n\t\t\t\t\t</div>\n\t\t\t\t</div>\n\t\t\t</motion.div>\n\t\t</nav>\n\t)\n}\n\nfunction NavToggle({\n\ttitle,\n\tisMenuOpened,\n\tsetMenuOpened,\n\tmenuControls,\n}: {\n\ttitle: string\n\tisMenuOpened: boolean\n\tsetMenuOpened: (value: boolean) => void\n\tmenuControls: AnimationControls\n}) {\n\tconst path01Variants = {\n\t\topen: { d: 'M3.06061 2.99999L21.0606 21' },\n\t\tclosed: { d: 'M0 9.5L24 9.5' },\n\t}\n\tconst path02Variants = {\n\t\topen: { d: 'M3.00006 21.0607L21 3.06064' },\n\t\tmoving: { d: 'M0 14.5L24 14.5' },\n\t\tclosed: { d: 'M0 14.5L15 14.5' },\n\t}\n\tconst path01Controls = useAnimationControls()\n\tconst path02Controls = useAnimationControls()\n\n\tasync function toggleMenu() {\n\t\tvoid menuControls.start(isMenuOpened ? 'close' : 'open')\n\t\tsetMenuOpened(!isMenuOpened)\n\t\tif (isMenuOpened) {\n\t\t\tvoid path01Controls.start(path01Variants.closed)\n\t\t\tawait path02Controls.start(path02Variants.moving)\n\t\t\tvoid path02Controls.start(path02Variants.closed)\n\t\t} else {\n\t\t\tawait path02Controls.start(path02Variants.moving)\n\t\t\tvoid path01Controls.start(path01Variants.open)\n\t\t\tvoid path02Controls.start(path02Variants.open)\n\t\t}\n\t}\n\n\tconst latestToggleMenu = React.useRef(toggleMenu)\n\tReact.useEffect(() => {\n\t\tlatestToggleMenu.current = toggleMenu\n\t})\n\n\tReact.useEffect(() => {\n\t\tif (!isMenuOpened) return\n\n\t\tfunction handleKeyUp(event: KeyboardEvent) {\n\t\t\tif (event.key === 'Escape') {\n\t\t\t\tvoid latestToggleMenu.current()\n\t\t\t}\n\t\t}\n\t\tdocument.addEventListener('keyup', handleKeyUp)\n\t\treturn () => document.removeEventListener('keyup', handleKeyUp)\n\t}, [isMenuOpened])\n\n\treturn (\n\t\t<div className=\"relative inline-flex h-14 w-full items-center justify-between overflow-hidden border-b\">\n\t\t\t<button\n\t\t\t\tclassName=\"flex h-14 w-14 items-center justify-center\"\n\t\t\t\taria-label=\"Open Navigation menu\"\n\t\t\t\tonClick={toggleMenu}\n\t\t\t>\n\t\t\t\t<svg width=\"24\" height=\"24\" viewBox=\"0 0 24 24\">\n\t\t\t\t\t<motion.path\n\t\t\t\t\t\t{...path01Variants.closed}\n\t\t\t\t\t\tanimate={path01Controls}\n\t\t\t\t\t\ttransition={{ duration: 0.2 }}\n\t\t\t\t\t\tstroke=\"currentColor\"\n\t\t\t\t\t\tstrokeWidth={1.5}\n\t\t\t\t\t/>\n\t\t\t\t\t<motion.path\n\t\t\t\t\t\t{...path02Variants.closed}\n\t\t\t\t\t\tanimate={path02Controls}\n\t\t\t\t\t\ttransition={{ duration: 0.2 }}\n\t\t\t\t\t\tstroke=\"currentColor\"\n\t\t\t\t\t\tstrokeWidth={1.5}\n\t\t\t\t\t/>\n\t\t\t\t</svg>\n\t\t\t</button>\n\t\t\t{isMenuOpened && (\n\t\t\t\t<motion.p\n\t\t\t\t\ttransition={{ delay: 0.2 }}\n\t\t\t\t\tinitial={{ opacity: 0, y: 5 }}\n\t\t\t\t\tanimate={{ opacity: 1, y: 0 }}\n\t\t\t\t\tclassName=\"absolute right-5 whitespace-nowrap font-mono text-sm uppercase\"\n\t\t\t\t>\n\t\t\t\t\t<Link to=\"/\">{title}</Link>\n\t\t\t\t</motion.p>\n\t\t\t)}\n\t\t</div>\n\t)\n}\n"],"names":["stopAnimation","visualElement","value","setVariants","variantLabels","key","variant","setTarget","child","setValues","definition","animationControls","subscribers","controls","transitionOverride","animations","animateVisualElement","useAnimationControls","useConstant","useIsomorphicLayoutEffect","opacities","shadows","getScoreClassNames","score","opacityNumber","shadowNumber","cn","FacePile","isMenuOpened","loggedInUser","useOptionalUser","users","usePresence","limit","numberOverLimit","tiffany","jsx","Link","overLimitLabel","jsxs","TooltipProvider","user","scoreClassNames","locationLabel","getLocationLabel","Tooltip","TooltipTrigger","Icon","TooltipContent","headers","setMenuOpened","React.useState","EpicWebBanner","Navigation","Outlet","location","exercise","exercisePortion","s","itemVariants","NavigationExerciseListItem","exerciseNumber","children","progressClassName","motion","progressItemSearch","useProgressItemClassName","OPENED_MENU_WIDTH","data","useLoaderData","nextExerciseRoute","useNextExerciseRoute","params","useParams","e","app","p","menuControls","menuVariants","listVariants","exNum","NavToggle","title","steps","isActive","showPlayground","exerciseNum","clsx","NavigationExerciseStepListItem","name","stepNumber","title2","isPlayground","step","isActive2","NavLink","SimpleTooltip","ThemeSwitch","path01Variants","path02Variants","path01Controls","path02Controls","toggleMenu","latestToggleMenu","React.useRef","React.useEffect","handleKeyUp","event"],"mappings":"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","x_google_ignoreList":[0,1]}
|
|
1
|
+
{"version":3,"file":"_layout-D7Qo_r0X.js","sources":["../../../../../node_modules/framer-motion/dist/es/animation/hooks/animation-controls.mjs","../../../../../node_modules/framer-motion/dist/es/animation/hooks/use-animation.mjs","../../../app/routes/_app+/_layout.tsx"],"sourcesContent":["import { invariant } from '../../utils/errors.mjs';\nimport { setTarget } from '../../render/utils/setters.mjs';\nimport { animateVisualElement } from '../interfaces/visual-element.mjs';\n\nfunction stopAnimation(visualElement) {\n visualElement.values.forEach((value) => value.stop());\n}\nfunction setVariants(visualElement, variantLabels) {\n const reversedLabels = [...variantLabels].reverse();\n reversedLabels.forEach((key) => {\n const variant = visualElement.getVariant(key);\n variant && setTarget(visualElement, variant);\n if (visualElement.variantChildren) {\n visualElement.variantChildren.forEach((child) => {\n setVariants(child, variantLabels);\n });\n }\n });\n}\nfunction setValues(visualElement, definition) {\n if (Array.isArray(definition)) {\n return setVariants(visualElement, definition);\n }\n else if (typeof definition === \"string\") {\n return setVariants(visualElement, [definition]);\n }\n else {\n setTarget(visualElement, definition);\n }\n}\n/**\n * @public\n */\nfunction animationControls() {\n /**\n * Track whether the host component has mounted.\n */\n let hasMounted = false;\n /**\n * A collection of linked component animation controls.\n */\n const subscribers = new Set();\n const controls = {\n subscribe(visualElement) {\n subscribers.add(visualElement);\n return () => void subscribers.delete(visualElement);\n },\n start(definition, transitionOverride) {\n invariant(hasMounted, \"controls.start() should only be called after a component has mounted. Consider calling within a useEffect hook.\");\n const animations = [];\n subscribers.forEach((visualElement) => {\n animations.push(animateVisualElement(visualElement, definition, {\n transitionOverride,\n }));\n });\n return Promise.all(animations);\n },\n set(definition) {\n invariant(hasMounted, \"controls.set() should only be called after a component has mounted. Consider calling within a useEffect hook.\");\n return subscribers.forEach((visualElement) => {\n setValues(visualElement, definition);\n });\n },\n stop() {\n subscribers.forEach((visualElement) => {\n stopAnimation(visualElement);\n });\n },\n mount() {\n hasMounted = true;\n return () => {\n hasMounted = false;\n controls.stop();\n };\n },\n };\n return controls;\n}\n\nexport { animationControls, setValues };\n","import { animationControls } from './animation-controls.mjs';\nimport { useConstant } from '../../utils/use-constant.mjs';\nimport { useIsomorphicLayoutEffect } from '../../utils/use-isomorphic-effect.mjs';\n\n/**\n * Creates `AnimationControls`, which can be used to manually start, stop\n * and sequence animations on one or more components.\n *\n * The returned `AnimationControls` should be passed to the `animate` property\n * of the components you want to animate.\n *\n * These components can then be animated with the `start` method.\n *\n * ```jsx\n * import * as React from 'react'\n * import { motion, useAnimation } from 'framer-motion'\n *\n * export function MyComponent(props) {\n * const controls = useAnimation()\n *\n * controls.start({\n * x: 100,\n * transition: { duration: 0.5 },\n * })\n *\n * return <motion.div animate={controls} />\n * }\n * ```\n *\n * @returns Animation controller with `start` and `stop` methods\n *\n * @public\n */\nfunction useAnimationControls() {\n const controls = useConstant(animationControls);\n useIsomorphicLayoutEffect(controls.mount, []);\n return controls;\n}\nconst useAnimation = useAnimationControls;\n\nexport { useAnimation, useAnimationControls };\n","import {\n\textractNumbersAndTypeFromAppNameOrPath,\n\tgetExercises,\n\tgetPlaygroundAppName,\n\tgetWorkshopTitle,\n} from '@epic-web/workshop-utils/apps.server'\nimport {\n\tcombineServerTimings,\n\tgetServerTimeHeader,\n\tmakeTimings,\n} from '@epic-web/workshop-utils/timing.server'\nimport {\n\ttype LoaderFunctionArgs,\n\ttype HeadersFunction,\n\tjson,\n} from '@remix-run/node'\nimport {\n\tLink,\n\tNavLink,\n\tOutlet,\n\tuseLoaderData,\n\tuseParams,\n} from '@remix-run/react'\nimport { clsx } from 'clsx'\nimport {\n\ttype AnimationControls,\n\tmotion,\n\tuseAnimationControls,\n} from 'framer-motion'\nimport * as React from 'react'\nimport {\n\tuseNextExerciseRoute,\n\tuseExerciseProgressClassName,\n\ttype ProgressItemSearch,\n\tuseProgressItemClassName,\n} from '../progress.tsx'\nimport { ThemeSwitch } from '../theme/index.tsx'\nimport { Icon } from '#app/components/icons.tsx'\nimport {\n\tSimpleTooltip,\n\tTooltip,\n\tTooltipContent,\n\tTooltipProvider,\n\tTooltipTrigger,\n} from '#app/components/ui/tooltip.tsx'\nimport { useOptionalUser } from '#app/components/user.tsx'\nimport { cn } from '#app/utils/misc.tsx'\nimport { type User, usePresence } from '#app/utils/presence.tsx'\n\nexport async function loader({ request }: LoaderFunctionArgs) {\n\tconst timings = makeTimings('stepLoader')\n\tconst [exercises, workshopTitle, playgroundAppName] = await Promise.all([\n\t\tgetExercises({ request, timings }),\n\t\tgetWorkshopTitle(),\n\t\tgetPlaygroundAppName(),\n\t])\n\n\tconst playground = {\n\t\tappName: playgroundAppName,\n\t\texerciseNumber: Number(\n\t\t\textractNumbersAndTypeFromAppNameOrPath(playgroundAppName ?? '')\n\t\t\t\t?.exerciseNumber,\n\t\t),\n\t}\n\n\tconst result = json(\n\t\t{\n\t\t\tworkshopTitle,\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\tsolutions: e.solutions.map(({ stepNumber, title, name }) => ({\n\t\t\t\t\tstepNumber,\n\t\t\t\t\ttitle,\n\t\t\t\t\tname,\n\t\t\t\t})),\n\t\t\t\tproblems: e.problems.map(({ stepNumber, title, name }) => ({\n\t\t\t\t\tstepNumber,\n\t\t\t\t\ttitle,\n\t\t\t\t\tname,\n\t\t\t\t})),\n\t\t\t\tsteps: e.steps.map(({ stepNumber, problem, solution }) => ({\n\t\t\t\t\tstepNumber,\n\t\t\t\t\ttitle: problem?.title ?? solution?.title ?? 'Unknown',\n\t\t\t\t\tname: problem?.name ?? solution?.name ?? 'Unknown',\n\t\t\t\t})),\n\t\t\t})),\n\t\t\tplayground,\n\t\t},\n\t\t{\n\t\t\theaders: {\n\t\t\t\tVary: 'Cookie',\n\t\t\t\t'Server-Timing': getServerTimeHeader(timings),\n\t\t\t},\n\t\t},\n\t)\n\treturn result\n}\n\nexport const headers: HeadersFunction = ({ loaderHeaders, parentHeaders }) => {\n\tconst headers = {\n\t\t'Cache-Control': loaderHeaders.get('Cache-Control') ?? '',\n\t\tVary: 'Cookie',\n\t\t'Server-Timing': combineServerTimings(loaderHeaders, parentHeaders),\n\t}\n\treturn headers\n}\n\nconst opacities = ['opacity-70', 'opacity-80', 'opacity-90', 'opacity-100']\nconst shadows = [\n\t'shadow-[0_0_2px_0_rgba(0,0,0,0.3)]',\n\t'shadow-[0_0_4px_0_rgba(0,0,0,0.3)]',\n\t'shadow-[0_0_7px_0_rgba(0,0,0,0.3)]',\n\t'shadow-[0_0_10px_0_rgba(0,0,0,0.3)]',\n]\nfunction getScoreClassNames(score: number) {\n\tconst opacityNumber = Math.round(score * opacities.length - 1)\n\tconst shadowNumber = Math.round(score * shadows.length - 1)\n\treturn cn(\n\t\t'shadow-purple-700 hover:opacity-100 focus:opacity-100 dark:shadow-purple-200',\n\t\topacities[opacityNumber] ?? 'opacity-60',\n\t\tshadows[shadowNumber] ?? 'shadow-none',\n\t\tscore === 1 ? 'animate-pulse hover:animate-none focus:animate-none' : null,\n\t)\n}\n\nfunction FacePile({ isMenuOpened }: { isMenuOpened: boolean }) {\n\tconst loggedInUser = useOptionalUser()\n\tconst { users } = usePresence()\n\tconst limit = isMenuOpened ? 17 : 0\n\tconst numberOverLimit = users.length - limit\n\tif (!users.length) return null\n\tconst tiffany =\n\t\tisMenuOpened && users.length === 1 ? (\n\t\t\t<Link\n\t\t\t\ttarget=\"_blank\"\n\t\t\t\trel=\"noopener noreferrer\"\n\t\t\t\tto=\"https://www.youtube.com/watch?v=w6Q3mHyzn78\"\n\t\t\t>\n\t\t\t\t<img\n\t\t\t\t\talt=\"Tiffany Tunes\"\n\t\t\t\t\tclassName={cn(\n\t\t\t\t\t\t'h-8 w-8 rounded-full border object-cover',\n\t\t\t\t\t\tgetScoreClassNames(1),\n\t\t\t\t\t)}\n\t\t\t\t\tsrc=\"https://github-production-user-asset-6210df.s3.amazonaws.com/1500684/277090714-b26e5961-4ee5-4c20-abdb-b04c1c480f2b.png\"\n\t\t\t\t/>\n\t\t\t</Link>\n\t\t) : null\n\tconst overLimitLabel = `${numberOverLimit}${\n\t\tisMenuOpened ? ' more ' : ' '\n\t}Epic Web Dev${numberOverLimit === 1 ? '' : 's'} working now`\n\treturn (\n\t\t<div className=\"flex flex-wrap items-center gap-2\">\n\t\t\t<TooltipProvider>\n\t\t\t\t{users.slice(0, limit).map(({ user, score }) => {\n\t\t\t\t\tconst scoreClassNames = getScoreClassNames(score)\n\t\t\t\t\tconst locationLabel = getLocationLabel(user.location)\n\t\t\t\t\treturn (\n\t\t\t\t\t\t<Tooltip key={user.id}>\n\t\t\t\t\t\t\t<TooltipTrigger asChild>\n\t\t\t\t\t\t\t\t{user.avatarUrl ? (\n\t\t\t\t\t\t\t\t\t<img\n\t\t\t\t\t\t\t\t\t\ttabIndex={0}\n\t\t\t\t\t\t\t\t\t\talt={user.name || 'Epic Web Dev'}\n\t\t\t\t\t\t\t\t\t\tclassName={cn(\n\t\t\t\t\t\t\t\t\t\t\t'h-8 w-8 rounded-full border object-cover',\n\t\t\t\t\t\t\t\t\t\t\tscoreClassNames,\n\t\t\t\t\t\t\t\t\t\t)}\n\t\t\t\t\t\t\t\t\t\tsrc={user.avatarUrl}\n\t\t\t\t\t\t\t\t\t/>\n\t\t\t\t\t\t\t\t) : (\n\t\t\t\t\t\t\t\t\t<div\n\t\t\t\t\t\t\t\t\t\ttabIndex={0}\n\t\t\t\t\t\t\t\t\t\taria-label={user.name || 'Epic Web Dev'}\n\t\t\t\t\t\t\t\t\t\tclassName={cn(\n\t\t\t\t\t\t\t\t\t\t\t'flex h-8 w-8 items-center justify-center rounded-full border',\n\t\t\t\t\t\t\t\t\t\t\tscoreClassNames,\n\t\t\t\t\t\t\t\t\t\t)}\n\t\t\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t\t\t<Icon name=\"User\" />\n\t\t\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t\t\t)}\n\t\t\t\t\t\t\t</TooltipTrigger>\n\t\t\t\t\t\t\t<TooltipContent>\n\t\t\t\t\t\t\t\t<span className=\"flex flex-col items-center justify-center gap-1\">\n\t\t\t\t\t\t\t\t\t<span>\n\t\t\t\t\t\t\t\t\t\t{user.name || 'An EPIC Web Dev'}{' '}\n\t\t\t\t\t\t\t\t\t\t{locationLabel\n\t\t\t\t\t\t\t\t\t\t\t? ` is working ${\n\t\t\t\t\t\t\t\t\t\t\t\t\tscore === 1 && loggedInUser?.id !== user.id\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t? 'with you'\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t: ''\n\t\t\t\t\t\t\t\t\t\t\t\t} on`\n\t\t\t\t\t\t\t\t\t\t\t: null}\n\t\t\t\t\t\t\t\t\t</span>\n\t\t\t\t\t\t\t\t\t{locationLabel?.line1 ? (\n\t\t\t\t\t\t\t\t\t\t<span>{locationLabel.line1}</span>\n\t\t\t\t\t\t\t\t\t) : null}\n\t\t\t\t\t\t\t\t\t{locationLabel?.line2 ? (\n\t\t\t\t\t\t\t\t\t\t<span>{locationLabel.line2}</span>\n\t\t\t\t\t\t\t\t\t) : null}\n\t\t\t\t\t\t\t\t</span>\n\t\t\t\t\t\t\t</TooltipContent>\n\t\t\t\t\t\t</Tooltip>\n\t\t\t\t\t)\n\t\t\t\t})}\n\t\t\t\t{tiffany}\n\t\t\t\t{numberOverLimit > 0 ? (\n\t\t\t\t\t<Tooltip>\n\t\t\t\t\t\t<TooltipTrigger asChild>\n\t\t\t\t\t\t\t<div\n\t\t\t\t\t\t\t\ttabIndex={0}\n\t\t\t\t\t\t\t\taria-label={overLimitLabel}\n\t\t\t\t\t\t\t\tclassName={cn(\n\t\t\t\t\t\t\t\t\t'flex items-center justify-center rounded-full border bg-accent text-xs text-accent-foreground',\n\t\t\t\t\t\t\t\t\tisMenuOpened ? 'h-8 w-8' : 'h-6 w-6',\n\t\t\t\t\t\t\t\t)}\n\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t<span\n\t\t\t\t\t\t\t\t\tclassName={cn(\n\t\t\t\t\t\t\t\t\t\t'pointer-events-none overflow-hidden text-ellipsis whitespace-nowrap text-center',\n\t\t\t\t\t\t\t\t\t\tisMenuOpened ? 'w-8' : 'w-6',\n\t\t\t\t\t\t\t\t\t)}\n\t\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t\t{isMenuOpened ? `+${numberOverLimit}` : numberOverLimit}\n\t\t\t\t\t\t\t\t</span>\n\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t</TooltipTrigger>\n\t\t\t\t\t\t<TooltipContent>{overLimitLabel}</TooltipContent>\n\t\t\t\t\t</Tooltip>\n\t\t\t\t) : null}\n\t\t\t</TooltipProvider>\n\t\t</div>\n\t)\n}\n\nexport default function App() {\n\tconst user = useOptionalUser()\n\n\tconst [isMenuOpened, setMenuOpened] = React.useState(false)\n\n\treturn (\n\t\t<div className=\"flex flex-col\">\n\t\t\t{user ? null : <EpicWebBanner />}\n\t\t\t<div\n\t\t\t\tclassName={cn('flex flex-grow', {\n\t\t\t\t\t'h-[calc(100vh-64px-env(safe-area-inset-top)-env(safe-area-inset-bottom))]':\n\t\t\t\t\t\t!user,\n\t\t\t\t\t'h-[calc(100vh-112px-env(safe-area-inset-top)-env(safe-area-inset-bottom))] sm:h-[calc(100vh-64px-env(safe-area-inset-top)-env(safe-area-inset-bottom))]':\n\t\t\t\t\t\tENV.EPICSHOP_DEPLOYED,\n\t\t\t\t\t'h-[calc(100vh-env(safe-area-inset-top)-env(safe-area-inset-bottom))]':\n\t\t\t\t\t\tuser,\n\t\t\t\t})}\n\t\t\t>\n\t\t\t\t<Navigation\n\t\t\t\t\tisMenuOpened={isMenuOpened}\n\t\t\t\t\tonMenuOpenChange={setMenuOpened}\n\t\t\t\t/>\n\t\t\t\t<div\n\t\t\t\t\tclassName={cn(\n\t\t\t\t\t\t'h-full w-full max-w-[calc(100%-56px)]',\n\t\t\t\t\t\tisMenuOpened ? 'hidden md:block' : '',\n\t\t\t\t\t)}\n\t\t\t\t>\n\t\t\t\t\t<Outlet />\n\t\t\t\t</div>\n\t\t\t</div>\n\t\t</div>\n\t)\n}\n\nfunction getLocationLabel(location: User['location']) {\n\tif (!location) return null\n\n\tconst { exercise } = location\n\n\tconst exercisePortion = [\n\t\texercise\n\t\t\t? [exercise.exerciseNumber, exercise.stepNumber]\n\t\t\t\t\t.filter(Boolean)\n\t\t\t\t\t.map(s => s.toString().padStart(2, '0'))\n\t\t\t\t\t.join('/')\n\t\t\t: null,\n\t\texercise?.type,\n\t]\n\t\t.filter(Boolean)\n\t\t.join(' - ')\n\treturn { line1: location.workshopTitle, line2: exercisePortion }\n}\n\nfunction EpicWebBanner() {\n\treturn (\n\t\t<div\n\t\t\tclassName={cn(\n\t\t\t\t'z-10 flex items-center justify-between border-b bg-gradient-to-tr from-blue-500 to-indigo-500 pl-4 text-white',\n\t\t\t\tENV.EPICSHOP_DEPLOYED ? 'h-[112px] md:h-[64px]' : 'h-16',\n\t\t\t)}\n\t\t>\n\t\t\t<div className=\"flex flex-1 flex-wrap items-center gap-4\">\n\t\t\t\t<Icon name=\"EpicWeb\" size=\"lg\" />\n\t\t\t\t<div className=\"flex flex-1 flex-wrap items-center\">\n\t\t\t\t\t<p className=\"mr-2\">\n\t\t\t\t\t\tWelcome to the{' '}\n\t\t\t\t\t\t<Link\n\t\t\t\t\t\t\tto=\"https://www.epicweb.dev\"\n\t\t\t\t\t\t\tclassName=\"underline\"\n\t\t\t\t\t\t\ttarget=\"_blank\"\n\t\t\t\t\t\t>\n\t\t\t\t\t\t\tEpicWeb.dev\n\t\t\t\t\t\t</Link>{' '}\n\t\t\t\t\t\tWorkshop app!\n\t\t\t\t\t</p>\n\t\t\t\t\t{ENV.EPICSHOP_DEPLOYED ? (\n\t\t\t\t\t\t<small className=\"text-sm\">\n\t\t\t\t\t\t\tThis is the deployed version.{' '}\n\t\t\t\t\t\t\t{ENV.EPICSHOP_GITHUB_ROOT ? (\n\t\t\t\t\t\t\t\t<Link\n\t\t\t\t\t\t\t\t\tclassName=\"underline\"\n\t\t\t\t\t\t\t\t\ttarget=\"_blank\"\n\t\t\t\t\t\t\t\t\trel=\"noopener noreferrer\"\n\t\t\t\t\t\t\t\t\tto={ENV.EPICSHOP_GITHUB_ROOT}\n\t\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t\tRun locally\n\t\t\t\t\t\t\t\t</Link>\n\t\t\t\t\t\t\t) : null}{' '}\n\t\t\t\t\t\t\tfor full experience.\n\t\t\t\t\t\t</small>\n\t\t\t\t\t) : null}\n\t\t\t\t</div>\n\t\t\t</div>\n\t\t\t<div className=\"flex h-full flex-col items-center md:flex-row\">\n\t\t\t\t<Link\n\t\t\t\t\tto=\"https://www.epicweb.dev\"\n\t\t\t\t\ttarget=\"_blank\"\n\t\t\t\t\tclassName=\"flex h-full items-center justify-center space-x-1.5 px-5 text-sm font-semibold\"\n\t\t\t\t>\n\t\t\t\t\t<span className=\"drop-shadow-sm\">Join Epic Web</span>\n\t\t\t\t\t<span>↗︎</span>\n\t\t\t\t</Link>\n\t\t\t\t<Link\n\t\t\t\t\tto={\n\t\t\t\t\t\tENV.EPICSHOP_DEPLOYED ? 'https://www.epicweb.dev/login' : '/login'\n\t\t\t\t\t}\n\t\t\t\t\tclassName=\"flex h-full items-center justify-center space-x-1.5 bg-white/20 px-5 text-sm font-semibold shadow-md transition hover:bg-white/30\"\n\t\t\t\t>\n\t\t\t\t\t<Icon name=\"User\" size=\"lg\" />\n\t\t\t\t\t<span className=\"drop-shadow-sm\">Login</span>\n\t\t\t\t</Link>\n\t\t\t</div>\n\t\t</div>\n\t)\n}\n\nconst itemVariants = {\n\thidden: { opacity: 0, x: -20 },\n\tvisible: { opacity: 1, x: 0 },\n}\nfunction NavigationExerciseListItem({\n\texerciseNumber,\n\tchildren,\n}: {\n\texerciseNumber: number\n\tchildren: React.ReactNode\n}) {\n\tconst progressClassName = useExerciseProgressClassName(exerciseNumber)\n\treturn (\n\t\t<motion.li\n\t\t\tvariants={itemVariants}\n\t\t\tclassName={cn(\n\t\t\t\t// add gap of 3 to children, but using padding so the progress extends through the whole height\n\t\t\t\t'py-[6px] first:pt-3 last:pb-3',\n\t\t\t\tprogressClassName ? `${progressClassName} before:border-t` : null,\n\t\t\t)}\n\t\t>\n\t\t\t<span className=\"ml-2\">{children}</span>\n\t\t</motion.li>\n\t)\n}\n\nfunction NavigationExerciseStepListItem({\n\tchildren,\n\t...progressItemSearch\n}: {\n\tchildren: React.ReactNode\n} & ProgressItemSearch) {\n\tconst progressClassName = useProgressItemClassName(progressItemSearch)\n\treturn (\n\t\t<motion.li\n\t\t\tvariants={itemVariants}\n\t\t\tclassName={cn(\n\t\t\t\t// add gap of 3 to children, but using padding so the progress extends through the whole height\n\t\t\t\t'py-[6px] first:pt-3 last:pb-3',\n\t\t\t\tprogressClassName ? `${progressClassName} before:border-t` : null,\n\t\t\t)}\n\t\t>\n\t\t\t<span className=\"ml-2\">{children}</span>\n\t\t</motion.li>\n\t)\n}\n\nconst OPENED_MENU_WIDTH = 400\n\nfunction Navigation({\n\tisMenuOpened,\n\tonMenuOpenChange: setMenuOpened,\n}: {\n\tisMenuOpened: boolean\n\tonMenuOpenChange: (change: boolean) => void\n}) {\n\tconst data = useLoaderData<typeof loader>()\n\tconst user = useOptionalUser()\n\tconst nextExerciseRoute = useNextExerciseRoute()\n\tconst params = useParams()\n\tconst { users } = usePresence()\n\n\tconst exercise = data.exercises.find(\n\t\te => e.exerciseNumber === Number(params.exerciseNumber),\n\t)\n\tconst app =\n\t\tparams.type === 'solution'\n\t\t\t? exercise?.solutions.find(\n\t\t\t\t\ts => s.stepNumber === Number(params.stepNumber),\n\t\t\t\t)\n\t\t\t: params.type === 'problem'\n\t\t\t\t? exercise?.problems.find(\n\t\t\t\t\t\tp => p.stepNumber === Number(params.stepNumber),\n\t\t\t\t\t)\n\t\t\t\t: null\n\n\t// container\n\tconst menuControls = useAnimationControls()\n\tconst menuVariants = {\n\t\tclose: { width: 56 },\n\t\topen: { width: OPENED_MENU_WIDTH },\n\t}\n\n\t// items\n\tconst listVariants = {\n\t\tvisible: {\n\t\t\topacity: 1,\n\t\t\ttransition: {\n\t\t\t\tduration: 0.05,\n\t\t\t\twhen: 'beforeChildren',\n\t\t\t\tstaggerChildren: 0.03,\n\t\t\t},\n\t\t},\n\t\thidden: {\n\t\t\topacity: 0,\n\t\t},\n\t}\n\tconst exNum = Number(params.exerciseNumber).toString().padStart(2, '0')\n\n\treturn (\n\t\t<nav className=\"flex border-r\">\n\t\t\t<motion.div\n\t\t\t\tinitial={isMenuOpened ? 'open' : 'close'}\n\t\t\t\tvariants={menuVariants}\n\t\t\t\tanimate={menuControls}\n\t\t\t>\n\t\t\t\t<div className=\"flex h-full flex-col items-center justify-between\">\n\t\t\t\t\t<NavToggle\n\t\t\t\t\t\ttitle={data.workshopTitle}\n\t\t\t\t\t\tmenuControls={menuControls}\n\t\t\t\t\t\tisMenuOpened={isMenuOpened}\n\t\t\t\t\t\tsetMenuOpened={setMenuOpened}\n\t\t\t\t\t/>\n\t\t\t\t\t{isMenuOpened && (\n\t\t\t\t\t\t<motion.div\n\t\t\t\t\t\t\tstyle={{ width: OPENED_MENU_WIDTH }}\n\t\t\t\t\t\t\tclassName=\"flex flex-grow flex-col justify-between overflow-y-auto p-6 scrollbar-thin scrollbar-thumb-scrollbar\"\n\t\t\t\t\t\t\tinitial={{ opacity: 0 }}\n\t\t\t\t\t\t\tanimate={{ opacity: 1 }}\n\t\t\t\t\t\t>\n\t\t\t\t\t\t\t<motion.ul\n\t\t\t\t\t\t\t\tvariants={listVariants}\n\t\t\t\t\t\t\t\tinitial=\"hidden\"\n\t\t\t\t\t\t\t\tanimate=\"visible\"\n\t\t\t\t\t\t\t\tclassName=\"flex flex-col\"\n\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t{data.exercises.map(({ exerciseNumber, title, steps }) => {\n\t\t\t\t\t\t\t\t\tconst isActive =\n\t\t\t\t\t\t\t\t\t\tNumber(params.exerciseNumber) === exerciseNumber\n\t\t\t\t\t\t\t\t\tconst showPlayground =\n\t\t\t\t\t\t\t\t\t\t!isActive &&\n\t\t\t\t\t\t\t\t\t\tdata.playground.exerciseNumber === exerciseNumber\n\t\t\t\t\t\t\t\t\tconst exerciseNum = exerciseNumber.toString().padStart(2, '0')\n\t\t\t\t\t\t\t\t\treturn (\n\t\t\t\t\t\t\t\t\t\t<NavigationExerciseListItem\n\t\t\t\t\t\t\t\t\t\t\tkey={exerciseNumber}\n\t\t\t\t\t\t\t\t\t\t\texerciseNumber={exerciseNumber}\n\t\t\t\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t\t\t\t<Link\n\t\t\t\t\t\t\t\t\t\t\t\tprefetch=\"intent\"\n\t\t\t\t\t\t\t\t\t\t\t\tto={`/${exerciseNum}`}\n\t\t\t\t\t\t\t\t\t\t\t\tclassName={clsx(\n\t\t\t\t\t\t\t\t\t\t\t\t\t'relative whitespace-nowrap px-2 py-0.5 pr-3 text-2xl font-bold outline-none hover:underline focus:underline',\n\t\t\t\t\t\t\t\t\t\t\t\t\t'after:absolute after:-bottom-2.5 after:-right-2.5 after:h-5 after:w-5 after:rotate-45 after:scale-75 after:bg-background after:content-[\"\"] hover:underline focus:underline',\n\t\t\t\t\t\t\t\t\t\t\t\t\t{ 'bg-foreground text-background': isActive },\n\t\t\t\t\t\t\t\t\t\t\t\t)}\n\t\t\t\t\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t\t\t\t\t{title}\n\t\t\t\t\t\t\t\t\t\t\t\t{showPlayground ? ' 🛝' : null}\n\t\t\t\t\t\t\t\t\t\t\t</Link>\n\t\t\t\t\t\t\t\t\t\t\t{isActive ? (\n\t\t\t\t\t\t\t\t\t\t\t\t<motion.ul\n\t\t\t\t\t\t\t\t\t\t\t\t\tvariants={listVariants}\n\t\t\t\t\t\t\t\t\t\t\t\t\tinitial=\"hidden\"\n\t\t\t\t\t\t\t\t\t\t\t\t\tanimate=\"visible\"\n\t\t\t\t\t\t\t\t\t\t\t\t\tclassName=\"ml-4 mt-4 flex flex-col\"\n\t\t\t\t\t\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t\t\t\t\t\t<NavigationExerciseStepListItem\n\t\t\t\t\t\t\t\t\t\t\t\t\t\tkey={exerciseNumber}\n\t\t\t\t\t\t\t\t\t\t\t\t\t\ttype=\"instructions\"\n\t\t\t\t\t\t\t\t\t\t\t\t\t\texerciseNumber={exerciseNumber}\n\t\t\t\t\t\t\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t<Link\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tto={`/${exerciseNum}`}\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tprefetch=\"intent\"\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tclassName={clsx(\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t'relative whitespace-nowrap px-2 py-0.5 pr-3 text-xl font-medium outline-none after:absolute after:-bottom-2.5 after:-right-2.5 after:h-5 after:w-5 after:rotate-45 after:scale-75 after:bg-background after:content-[\"\"] hover:underline focus:underline',\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t'bg-foreground text-background':\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t!params.stepNumber,\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t)}\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tIntro\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t</Link>\n\t\t\t\t\t\t\t\t\t\t\t\t\t</NavigationExerciseStepListItem>\n\t\t\t\t\t\t\t\t\t\t\t\t\t{steps\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t.filter(Boolean)\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t.map(({ name, stepNumber, title }) => {\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tconst isActive =\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tNumber(params.stepNumber) === stepNumber\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tconst step = stepNumber\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t.toString()\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t.padStart(2, '0')\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tconst isPlayground =\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tname === data.playground.appName\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\treturn (\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<NavigationExerciseStepListItem\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tkey={stepNumber}\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\ttype=\"step\"\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tstepNumber={stepNumber}\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\texerciseNumber={exerciseNumber}\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<Link\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tto={`/${exerciseNum}/${step}`}\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tprefetch=\"intent\"\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tclassName={clsx(\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t'relative whitespace-nowrap px-2 py-0.5 pr-3 text-xl font-medium outline-none after:absolute after:-bottom-2.5 after:-right-2.5 after:h-5 after:w-5 after:rotate-45 after:scale-75 after:bg-background after:content-[\"\"] hover:underline focus:underline',\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t'bg-foreground text-background':\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tisActive,\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t)}\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t{isPlayground\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t? `${step}. ${title} 🛝`\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t: `${step}. ${title}`}\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</Link>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</NavigationExerciseStepListItem>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t)\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t})}\n\t\t\t\t\t\t\t\t\t\t\t\t\t<NavigationExerciseStepListItem\n\t\t\t\t\t\t\t\t\t\t\t\t\t\ttype=\"finished\"\n\t\t\t\t\t\t\t\t\t\t\t\t\t\texerciseNumber={exerciseNumber}\n\t\t\t\t\t\t\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t<NavLink\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tto={`/${exerciseNum}/finished`}\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tprefetch=\"intent\"\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tclassName={({ isActive }) =>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tclsx(\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t'relative whitespace-nowrap px-2 py-0.5 pr-3 text-base font-medium outline-none after:absolute after:-bottom-2.5 after:-right-2.5 after:h-5 after:w-5 after:rotate-45 after:scale-75 after:bg-background after:content-[\"\"] hover:underline focus:underline',\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t'bg-foreground text-background': isActive,\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t)\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t📝 Elaboration\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t</NavLink>\n\t\t\t\t\t\t\t\t\t\t\t\t\t</NavigationExerciseStepListItem>\n\t\t\t\t\t\t\t\t\t\t\t\t</motion.ul>\n\t\t\t\t\t\t\t\t\t\t\t) : null}\n\t\t\t\t\t\t\t\t\t\t</NavigationExerciseListItem>\n\t\t\t\t\t\t\t\t\t)\n\t\t\t\t\t\t\t\t})}\n\t\t\t\t\t\t\t</motion.ul>\n\t\t\t\t\t\t\t<div className=\"mt-6\">\n\t\t\t\t\t\t\t\t<NavLink\n\t\t\t\t\t\t\t\t\tto=\"/finished\"\n\t\t\t\t\t\t\t\t\tclassName={({ isActive }) =>\n\t\t\t\t\t\t\t\t\t\tclsx(\n\t\t\t\t\t\t\t\t\t\t\t'relative whitespace-nowrap text-lg font-bold outline-none hover:underline focus:underline',\n\t\t\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t\t\t'bg-black text-white after:absolute after:-bottom-2.5 after:-right-2.5 after:h-5 after:w-5 after:rotate-45 after:scale-75 after:bg-background after:content-[\"\"]':\n\t\t\t\t\t\t\t\t\t\t\t\t\tisActive,\n\t\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\t)\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t\t📝 Workshop Feedback\n\t\t\t\t\t\t\t\t</NavLink>\n\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t</motion.div>\n\t\t\t\t\t)}\n\t\t\t\t\t{!isMenuOpened && (\n\t\t\t\t\t\t<div className=\"flex flex-grow flex-col justify-center\">\n\t\t\t\t\t\t\t<div className=\"orientation-sideways w-full font-mono text-sm font-medium uppercase leading-none\">\n\t\t\t\t\t\t\t\t{exercise?.title ? (\n\t\t\t\t\t\t\t\t\t<Link to={`/${exNum}`}>{exercise.title}</Link>\n\t\t\t\t\t\t\t\t) : null}\n\t\t\t\t\t\t\t\t{exercise?.title && app?.title ? ' — ' : null}\n\t\t\t\t\t\t\t\t{app?.title ? (\n\t\t\t\t\t\t\t\t\t<Link\n\t\t\t\t\t\t\t\t\t\tto={`/${exNum}/${app.stepNumber\n\t\t\t\t\t\t\t\t\t\t\t.toString()\n\t\t\t\t\t\t\t\t\t\t\t.padStart(2, '0')}`}\n\t\t\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t\t\t{app.title}\n\t\t\t\t\t\t\t\t\t</Link>\n\t\t\t\t\t\t\t\t) : null}\n\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t</div>\n\t\t\t\t\t)}\n\t\t\t\t\t<div\n\t\t\t\t\t\tclassName={cn(\n\t\t\t\t\t\t\t'flex w-full items-center justify-start border-t p-4 transition-[height]',\n\t\t\t\t\t\t\tisMenuOpened && users.length > 4 ? 'h-28' : 'h-14',\n\t\t\t\t\t\t)}\n\t\t\t\t\t\tstyle={isMenuOpened ? { width: OPENED_MENU_WIDTH } : {}}\n\t\t\t\t\t>\n\t\t\t\t\t\t<FacePile isMenuOpened={isMenuOpened} />\n\t\t\t\t\t</div>\n\t\t\t\t\t{ENV.EPICSHOP_DEPLOYED ? null : user ? (\n\t\t\t\t\t\t<SimpleTooltip content={isMenuOpened ? null : 'Your account'}>\n\t\t\t\t\t\t\t<Link\n\t\t\t\t\t\t\t\tclassName=\"flex h-14 w-full items-center justify-start space-x-3 border-t px-4 py-4 text-center no-underline hover:underline\"\n\t\t\t\t\t\t\t\tto=\"/account\"\n\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t{user.avatarUrl ? (\n\t\t\t\t\t\t\t\t\t<img\n\t\t\t\t\t\t\t\t\t\talt={user.name ?? user.email}\n\t\t\t\t\t\t\t\t\t\tsrc={user.avatarUrl}\n\t\t\t\t\t\t\t\t\t\tclassName=\"h-full rounded-full\"\n\t\t\t\t\t\t\t\t\t/>\n\t\t\t\t\t\t\t\t) : (\n\t\t\t\t\t\t\t\t\t<Icon name=\"User\" className=\"flex-shrink-0\" size=\"lg\" />\n\t\t\t\t\t\t\t\t)}\n\t\t\t\t\t\t\t\t{isMenuOpened ? (\n\t\t\t\t\t\t\t\t\t<motion.div\n\t\t\t\t\t\t\t\t\t\tclassName=\"flex items-center whitespace-nowrap\"\n\t\t\t\t\t\t\t\t\t\tinitial={{ opacity: 0 }}\n\t\t\t\t\t\t\t\t\t\tanimate={{ opacity: 1 }}\n\t\t\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t\t\tYour Account\n\t\t\t\t\t\t\t\t\t</motion.div>\n\t\t\t\t\t\t\t\t) : (\n\t\t\t\t\t\t\t\t\t<span className=\"sr-only\">Your account</span>\n\t\t\t\t\t\t\t\t)}\n\t\t\t\t\t\t\t</Link>\n\t\t\t\t\t\t</SimpleTooltip>\n\t\t\t\t\t) : null}\n\t\t\t\t\t{ENV.EPICSHOP_DEPLOYED ? null : user && nextExerciseRoute ? (\n\t\t\t\t\t\t<SimpleTooltip\n\t\t\t\t\t\t\tcontent={isMenuOpened ? null : 'Continue to next lesson'}\n\t\t\t\t\t\t>\n\t\t\t\t\t\t\t<Link\n\t\t\t\t\t\t\t\tto={nextExerciseRoute}\n\t\t\t\t\t\t\t\tprefetch=\"intent\"\n\t\t\t\t\t\t\t\tclassName={clsx(\n\t\t\t\t\t\t\t\t\t'flex h-14 w-full items-center space-x-3 border-t px-4 py-4 pl-[18px] no-underline hover:underline',\n\t\t\t\t\t\t\t\t)}\n\t\t\t\t\t\t\t\tstate={{ from: 'continue next lesson button' }}\n\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t<Icon name=\"FastForward\" className=\"flex-shrink-0\" size=\"md\" />\n\t\t\t\t\t\t\t\t{isMenuOpened ? (\n\t\t\t\t\t\t\t\t\t<motion.div\n\t\t\t\t\t\t\t\t\t\tclassName=\"flex items-center whitespace-nowrap\"\n\t\t\t\t\t\t\t\t\t\tinitial={{ opacity: 0 }}\n\t\t\t\t\t\t\t\t\t\tanimate={{ opacity: 1 }}\n\t\t\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t\t\tContinue to next lesson\n\t\t\t\t\t\t\t\t\t</motion.div>\n\t\t\t\t\t\t\t\t) : (\n\t\t\t\t\t\t\t\t\t<span className=\"sr-only\">Continue to next lesson</span>\n\t\t\t\t\t\t\t\t)}\n\t\t\t\t\t\t\t</Link>\n\t\t\t\t\t\t</SimpleTooltip>\n\t\t\t\t\t) : null}\n\t\t\t\t\t<div className=\"mb-4 w-full self-start border-t pl-3 pt-[15px]\">\n\t\t\t\t\t\t<ThemeSwitch />\n\t\t\t\t\t</div>\n\t\t\t\t</div>\n\t\t\t</motion.div>\n\t\t</nav>\n\t)\n}\n\nfunction NavToggle({\n\ttitle,\n\tisMenuOpened,\n\tsetMenuOpened,\n\tmenuControls,\n}: {\n\ttitle: string\n\tisMenuOpened: boolean\n\tsetMenuOpened: (value: boolean) => void\n\tmenuControls: AnimationControls\n}) {\n\tconst path01Variants = {\n\t\topen: { d: 'M3.06061 2.99999L21.0606 21' },\n\t\tclosed: { d: 'M0 9.5L24 9.5' },\n\t}\n\tconst path02Variants = {\n\t\topen: { d: 'M3.00006 21.0607L21 3.06064' },\n\t\tmoving: { d: 'M0 14.5L24 14.5' },\n\t\tclosed: { d: 'M0 14.5L15 14.5' },\n\t}\n\tconst path01Controls = useAnimationControls()\n\tconst path02Controls = useAnimationControls()\n\n\tasync function toggleMenu() {\n\t\tvoid menuControls.start(isMenuOpened ? 'close' : 'open')\n\t\tsetMenuOpened(!isMenuOpened)\n\t\tif (isMenuOpened) {\n\t\t\tvoid path01Controls.start(path01Variants.closed)\n\t\t\tawait path02Controls.start(path02Variants.moving)\n\t\t\tvoid path02Controls.start(path02Variants.closed)\n\t\t} else {\n\t\t\tawait path02Controls.start(path02Variants.moving)\n\t\t\tvoid path01Controls.start(path01Variants.open)\n\t\t\tvoid path02Controls.start(path02Variants.open)\n\t\t}\n\t}\n\n\tconst latestToggleMenu = React.useRef(toggleMenu)\n\tReact.useEffect(() => {\n\t\tlatestToggleMenu.current = toggleMenu\n\t})\n\n\tReact.useEffect(() => {\n\t\tif (!isMenuOpened) return\n\n\t\tfunction handleKeyUp(event: KeyboardEvent) {\n\t\t\tif (event.key === 'Escape') {\n\t\t\t\tvoid latestToggleMenu.current()\n\t\t\t}\n\t\t}\n\t\tdocument.addEventListener('keyup', handleKeyUp)\n\t\treturn () => document.removeEventListener('keyup', handleKeyUp)\n\t}, [isMenuOpened])\n\n\treturn (\n\t\t<div className=\"relative inline-flex h-14 w-full items-center justify-between overflow-hidden border-b\">\n\t\t\t<button\n\t\t\t\tclassName=\"flex h-14 w-14 items-center justify-center\"\n\t\t\t\taria-label=\"Open Navigation menu\"\n\t\t\t\tonClick={toggleMenu}\n\t\t\t>\n\t\t\t\t<svg width=\"24\" height=\"24\" viewBox=\"0 0 24 24\">\n\t\t\t\t\t<motion.path\n\t\t\t\t\t\t{...path01Variants.closed}\n\t\t\t\t\t\tanimate={path01Controls}\n\t\t\t\t\t\ttransition={{ duration: 0.2 }}\n\t\t\t\t\t\tstroke=\"currentColor\"\n\t\t\t\t\t\tstrokeWidth={1.5}\n\t\t\t\t\t/>\n\t\t\t\t\t<motion.path\n\t\t\t\t\t\t{...path02Variants.closed}\n\t\t\t\t\t\tanimate={path02Controls}\n\t\t\t\t\t\ttransition={{ duration: 0.2 }}\n\t\t\t\t\t\tstroke=\"currentColor\"\n\t\t\t\t\t\tstrokeWidth={1.5}\n\t\t\t\t\t/>\n\t\t\t\t</svg>\n\t\t\t</button>\n\t\t\t{isMenuOpened && (\n\t\t\t\t<motion.p\n\t\t\t\t\ttransition={{ delay: 0.2 }}\n\t\t\t\t\tinitial={{ opacity: 0, y: 5 }}\n\t\t\t\t\tanimate={{ opacity: 1, y: 0 }}\n\t\t\t\t\tclassName=\"absolute right-5 whitespace-nowrap font-mono text-sm uppercase\"\n\t\t\t\t>\n\t\t\t\t\t<Link to=\"/\">{title}</Link>\n\t\t\t\t</motion.p>\n\t\t\t)}\n\t\t</div>\n\t)\n}\n"],"names":["stopAnimation","visualElement","value","setVariants","variantLabels","key","variant","setTarget","child","setValues","definition","animationControls","subscribers","controls","transitionOverride","animations","animateVisualElement","useAnimationControls","useConstant","useIsomorphicLayoutEffect","opacities","shadows","getScoreClassNames","score","opacityNumber","shadowNumber","cn","FacePile","isMenuOpened","loggedInUser","useOptionalUser","users","usePresence","limit","numberOverLimit","tiffany","jsx","Link","overLimitLabel","jsxs","TooltipProvider","user","scoreClassNames","locationLabel","getLocationLabel","Tooltip","TooltipTrigger","Icon","TooltipContent","headers","setMenuOpened","React.useState","EpicWebBanner","Navigation","Outlet","location","exercise","exercisePortion","s","itemVariants","NavigationExerciseListItem","exerciseNumber","children","progressClassName","motion","progressItemSearch","useProgressItemClassName","OPENED_MENU_WIDTH","data","useLoaderData","nextExerciseRoute","useNextExerciseRoute","params","useParams","e","app","p","menuControls","menuVariants","listVariants","exNum","NavToggle","title","steps","isActive","showPlayground","exerciseNum","clsx","NavigationExerciseStepListItem","name","stepNumber","title2","isPlayground","step","isActive2","NavLink","SimpleTooltip","ThemeSwitch","path01Variants","path02Variants","path01Controls","path02Controls","toggleMenu","latestToggleMenu","React.useRef","React.useEffect","handleKeyUp","event"],"mappings":"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","x_google_ignoreList":[0,1]}
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import{j as e}from"./index-
|
|
2
|
-
//# sourceMappingURL=account-
|
|
1
|
+
import{j as e}from"./index-D1WEsmVZ.js";import{B as i}from"./button-DnQOyJAN.js";import{I as c}from"./misc-CXGQ7VS9.js";import{u as d,a as m}from"./user-DiGtbaa7.js";import{u}from"./presence-u-05JV3Z.js";import{u as x,a as h,L as o,F as a}from"./components-Dj3sm47B.js";import"./clsx-B-dksMZM.js";import"./index-B8k-Gd1G.js";function O(){const r=x(),l=h(),s=d(),t=m(),n=u();return e.jsxs("main",{className:"container flex h-full w-full max-w-3xl flex-grow flex-col items-center justify-center gap-4",children:[e.jsx("img",{className:"h-36 w-36 rounded-full",alt:(t==null?void 0:t.displayName)??s.name??s.email,src:s.avatarUrl}),e.jsx("h1",{className:"mb-1 text-2xl",children:"Your Account"}),e.jsx("p",{className:"text-center text-gray-700 dark:text-gray-300",children:s.name?`Hi ${(t==null?void 0:t.displayName)??s.name}, your device is logged in with ${s.email}.`:`Your device is logged in with ${s.email}.`}),t?e.jsxs(e.Fragment,{children:[e.jsxs("p",{className:"text-center text-gray-700 dark:text-gray-300",children:["And you are connected to discord as ",t.displayName," (",t.id,")."]}),e.jsx(l.Form,{method:"post",className:"mt-2",children:e.jsx(i,{varient:"mono",name:"intent",value:"disconnect-discord",children:"Disconnect Discord"})})]}):e.jsxs(o,{to:r.discordAuthUrl,className:"inline-flex items-center gap-2 underline",children:[e.jsx(c,{name:"Discord",size:"lg"}),"Connect Discord"]}),e.jsxs(a,{method:"POST",children:[e.jsx("input",{name:"optOut",type:"hidden",value:n!=null&&n.optOut?"false":"true"}),e.jsxs(i,{varient:"mono",name:"intent",value:"presence-opt-out",children:[n!=null&&n.optOut?"Opt in to":"Opt out of"," presence"]})]}),e.jsx("p",{children:e.jsxs("small",{children:["Note: it is your ",e.jsx("i",{className:"italic",children:"device"})," that's logged in, not your browser. So all browsers on this device will be logged in with the same account on this device."]})}),e.jsx(a,{method:"post",className:"mt-2",children:e.jsx(i,{varient:"primary",name:"intent",value:"logout",children:"Log out"})}),e.jsxs("p",{children:["Check"," ",e.jsx(o,{to:"/onboarding",className:"underline",children:"/onboarding"})," ","if you'd like to review onboarding again."]}),e.jsxs("p",{children:["Check"," ",e.jsx(o,{to:"/support",className:"underline",children:"/support"})," ","if you need support."]})]})}export{O as default};
|
|
2
|
+
//# sourceMappingURL=account-Bk4o4AzZ.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"account-
|
|
1
|
+
{"version":3,"file":"account-Bk4o4AzZ.js","sources":["../../../app/routes/_app+/account.tsx"],"sourcesContent":["import { deleteCache } from '@epic-web/workshop-utils/cache.server'\nimport {\n\tdeleteDb,\n\tdeleteDiscordInfo,\n\trequireAuthInfo,\n\tsetPresencePreferences,\n} from '@epic-web/workshop-utils/db.server'\nimport { json, redirect, type LoaderFunctionArgs } from '@remix-run/node'\nimport { Form, Link, useFetcher, useLoaderData } from '@remix-run/react'\nimport { getDiscordAuthURL } from '../discord.callback.ts'\nimport { Button } from '#app/components/button.tsx'\nimport { Icon } from '#app/components/icons.tsx'\nimport { useOptionalDiscordMember, useUser } from '#app/components/user.tsx'\nimport { ensureUndeployed } from '#app/utils/misc.tsx'\nimport { usePresencePreferences } from '#app/utils/presence.tsx'\nimport { redirectWithToast } from '#app/utils/toast.server.ts'\n\nexport async function loader({ request }: LoaderFunctionArgs) {\n\tensureUndeployed()\n\tawait requireAuthInfo({ request })\n\treturn json({ discordAuthUrl: getDiscordAuthURL() })\n}\n\nexport async function action({ request }: { request: Request }) {\n\tensureUndeployed()\n\tconst formData = await request.formData()\n\tconst intent = formData.get('intent')\n\tif (intent === 'disconnect-discord') {\n\t\tawait deleteDiscordInfo()\n\t\treturn redirectWithToast('/account', {\n\t\t\ttype: 'success',\n\t\t\ttitle: 'Disconnected',\n\t\t\tdescription: 'Local discord data has been deleted.',\n\t\t})\n\t} else if (intent === 'logout') {\n\t\tawait deleteDb()\n\t\tawait deleteCache()\n\t\treturn redirectWithToast('/login', {\n\t\t\ttype: 'success',\n\t\t\ttitle: 'Logged out',\n\t\t\tdescription: 'Goodbye! Come back soon!',\n\t\t})\n\t} else if (intent === 'presence-opt-out') {\n\t\tconst optOut = formData.get('optOut') === 'true'\n\t\tawait setPresencePreferences({ optOut })\n\t\treturn redirectWithToast('/account', {\n\t\t\ttitle: optOut ? 'Opted out' : 'Opted in',\n\t\t\tdescription: `You are now ${optOut ? 'invisible' : 'visible'}.`,\n\t\t\ttype: 'success',\n\t\t})\n\t}\n\n\treturn redirect('/account')\n}\n\nexport default function Account() {\n\tconst data = useLoaderData<typeof loader>()\n\tconst disconnectFetcher = useFetcher()\n\tconst user = useUser()\n\tconst discordMember = useOptionalDiscordMember()\n\tconst presencePreferences = usePresencePreferences()\n\treturn (\n\t\t<main className=\"container flex h-full w-full max-w-3xl flex-grow flex-col items-center justify-center gap-4\">\n\t\t\t<img\n\t\t\t\tclassName=\"h-36 w-36 rounded-full\"\n\t\t\t\talt={discordMember?.displayName ?? user.name ?? user.email}\n\t\t\t\tsrc={user.avatarUrl}\n\t\t\t/>\n\t\t\t<h1 className=\"mb-1 text-2xl\">Your Account</h1>\n\t\t\t<p className=\"text-center text-gray-700 dark:text-gray-300\">\n\t\t\t\t{user.name\n\t\t\t\t\t? `Hi ${\n\t\t\t\t\t\t\tdiscordMember?.displayName ?? user.name\n\t\t\t\t\t\t}, your device is logged in with ${user.email}.`\n\t\t\t\t\t: `Your device is logged in with ${user.email}.`}\n\t\t\t</p>\n\t\t\t{discordMember ? (\n\t\t\t\t<>\n\t\t\t\t\t<p className=\"text-center text-gray-700 dark:text-gray-300\">\n\t\t\t\t\t\tAnd you are connected to discord as {discordMember.displayName} (\n\t\t\t\t\t\t{discordMember.id}).\n\t\t\t\t\t</p>\n\t\t\t\t\t<disconnectFetcher.Form method=\"post\" className=\"mt-2\">\n\t\t\t\t\t\t<Button varient=\"mono\" name=\"intent\" value=\"disconnect-discord\">\n\t\t\t\t\t\t\tDisconnect Discord\n\t\t\t\t\t\t</Button>\n\t\t\t\t\t</disconnectFetcher.Form>\n\t\t\t\t</>\n\t\t\t) : (\n\t\t\t\t<Link\n\t\t\t\t\tto={data.discordAuthUrl}\n\t\t\t\t\tclassName=\"inline-flex items-center gap-2 underline\"\n\t\t\t\t>\n\t\t\t\t\t<Icon name=\"Discord\" size=\"lg\" />\n\t\t\t\t\tConnect Discord\n\t\t\t\t</Link>\n\t\t\t)}\n\t\t\t<Form method=\"POST\">\n\t\t\t\t<input\n\t\t\t\t\tname=\"optOut\"\n\t\t\t\t\ttype=\"hidden\"\n\t\t\t\t\tvalue={presencePreferences?.optOut ? 'false' : 'true'}\n\t\t\t\t/>\n\t\t\t\t<Button varient=\"mono\" name=\"intent\" value=\"presence-opt-out\">\n\t\t\t\t\t{presencePreferences?.optOut ? 'Opt in to' : 'Opt out of'} presence\n\t\t\t\t</Button>\n\t\t\t</Form>\n\t\t\t<p>\n\t\t\t\t<small>\n\t\t\t\t\tNote: it is your <i className=\"italic\">device</i> that's logged in,\n\t\t\t\t\tnot your browser. So all browsers on this device will be logged in\n\t\t\t\t\twith the same account on this device.\n\t\t\t\t</small>\n\t\t\t</p>\n\t\t\t<Form method=\"post\" className=\"mt-2\">\n\t\t\t\t<Button varient=\"primary\" name=\"intent\" value=\"logout\">\n\t\t\t\t\tLog out\n\t\t\t\t</Button>\n\t\t\t</Form>\n\t\t\t<p>\n\t\t\t\tCheck{' '}\n\t\t\t\t<Link to=\"/onboarding\" className=\"underline\">\n\t\t\t\t\t/onboarding\n\t\t\t\t</Link>{' '}\n\t\t\t\tif you'd like to review onboarding again.\n\t\t\t</p>\n\t\t\t<p>\n\t\t\t\tCheck{' '}\n\t\t\t\t<Link to=\"/support\" className=\"underline\">\n\t\t\t\t\t/support\n\t\t\t\t</Link>{' '}\n\t\t\t\tif you need support.\n\t\t\t</p>\n\t\t</main>\n\t)\n}\n"],"names":["Account","data","useLoaderData","disconnectFetcher","useFetcher","user","useUser","discordMember","useOptionalDiscordMember","presencePreferences","usePresencePreferences","jsxs","jsx","Fragment","Button","Link","Icon","Form"],"mappings":"qUAKC,SAAAA,GAAA,CACM,MAAAC,EAAAC,IACPC,EAAwDC,IAC/CC,EAAMC,IACfC,EAAkCC,IAClCC,EAAuBC,IACvB,OAAqBC,EAAAA,KAAA,OAAA,CACrB,wGACA,SAAiC,CAAAC,EAAA,IAAA,MAAA,CACjC,UAAuC,yBACvC,KAAkCL,GAAA,YAAAA,EAAA,cAAAF,EAAA,MAAAA,EAAA,MAEZ,IAAAA,EAAA,SACrB,CAAiB,EAAAO,EAAA,IAAA,KAAA,CACX,UAAA,gBACN,SAAc,cACf,CAAA,EAAAA,EAAA,IAAA,IAAA,CAEsB,UAAA,+CACJ,SAAAP,EAAA,KAAA,OAAAE,GAAA,YAAAA,EAAA,cAAAF,EAAA,IAAA,mCAAAA,EAAA,KAAA,IAAA,iCAAAA,EAAA,KAAA,GACjB,CAAM,EAAAE,EAAkCI,EAAA,KAAAE,WAAA,CAClC,SAAA,CAA8BF,EAAA,KAAA,IAAA,WACC,+CACpC,SAAwB,CAAA,uCAAAJ,EAAA,YAAA,KAAAA,EAAA,GAAA,IAAA,CACxB,CAAA,QAAyBJ,EAAY,KAAA,CAC9B,OAAA,OACC,UAAA,OACM,SAAAS,EAAA,IAAAE,EAAA,CACb,QAAA,OACF,cACO,MAAS,qBACT,SAAY,oBAClB,CAAA,CAAmC,CAC5B,CAAA,CAAA,CAAA,EACCH,EAAA,KAAAI,EAAA,CACP,GAAad,EAAA,eACb,UAAA,2CACF,UAA0CW,EAAA,IAAAI,EAAA,CACzC,KAAe,UACT,KAAA,IACN,CAAA,EAAA,kBAAqC,CACpC,EAA8BL,EAAA,KAAAM,EAAA,CAC9B,OAAa,OACb,SAAM,CAAAL,EAAA,IAAA,QAAA,CACN,KAAA,SACF,KAAA,SAEA,iBAA0B,OAAA,QAAA,MAC3B,CAAA,EAAAD,EAAA,KAAAG,EAAA,CAEA,QAAA,OACO,cACA,yBACA,SAAe,CAAAL,GAAA,MAAAA,EAAA,OAAA,YAAA,aAAA,WAAA,CACrB,CAAA,CAAM,CACN,CAAA,YAAmD,CAElD,SAAME,EAAA,KAAA,QAAA,CACL,SAAA,CAAA,oBAAAC,EAAA,IAAA,IAAA,CAAC,UAAA,SAAA,SAAA,QACU,CAAA,EAAA,6HAAA,CAAA,CAAA,CAC2C,CAAA,EAC3CA,EAAA,IAAAK,EAAA,CAAA,OAAA,OACX,UAAA,OACC,SAAAL,EAAa,IAAAE,EAAA,iCAUX,MAAA,SAA2D,SAAA,SAAA,CAAA,CACR,CAAY,EAAAH,EAAA,KAAA,IAAA,CAAA,SAChD,CAAA,QAAA,IAAAC,EAAAA,IAAAG,EAAA,CAAG,GAAA,cACnB,UAAA,kCAKA,CACD,EAEA,IAAA,2CAAA,CAAA,CAAC,EAAAJ,EAAA,KAAA,IAAA,CAAA,SAAA,CAAA,QAAA,IAAAC,EAAAA,IAAAG,EAAA,CACA,GAAI,WACJ,UAAU,YAEV,SAAA,UAAA,CAAA,EAAA,IAAA,sBAAM,CAAyB,CAAE,CAAA,CAAA,CAAA,CAAA"}
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import{j as n}from"./index-
|
|
2
|
-
//# sourceMappingURL=button-
|
|
1
|
+
import{j as n}from"./index-D1WEsmVZ.js";import{c as r}from"./clsx-B-dksMZM.js";import{L as u}from"./components-Dj3sm47B.js";function l(){return n.jsx("span",{className:"inline-block animate-spin",children:"🌀"})}function d(){return n.jsx("span",{children:"✅"})}function m(){return n.jsx("span",{children:"❌"})}function a({varient:e,clip:o=!0}){const t="inline-flex bg-foreground text-background outline-none hover:bg-background hover:text-foreground focus:bg-background focus:text-foreground",s="px-8 py-4 font-bold",c="px-8 py-4 text-xl font-bold",i="px-8 py-4 font-mono text-sm uppercase";return r(t,{"clip-path-button":o,[s]:e==="primary",[c]:e==="big",[i]:e==="mono"})}function g({varient:e,status:o="idle",...t}){const s={pending:n.jsx(l,{}),success:n.jsx(d,{}),error:n.jsx(m,{}),idle:null}[o];return n.jsx("div",{className:"clip-path-button-outer w-fit border-2 border-foreground bg-foreground",children:n.jsxs("button",{...t,className:r(t.className,a({varient:e}),"flex justify-center gap-4"),children:[n.jsx("div",{children:t.children}),s]})})}function j({varient:e,...o}){return n.jsx("div",{className:"clip-path-button-outer w-fit border-2 border-foreground bg-foreground",children:n.jsx(u,{...o,className:r(o.className,a({varient:e}))})})}export{g as B,j as a};
|
|
2
|
+
//# sourceMappingURL=button-DnQOyJAN.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"button-
|
|
1
|
+
{"version":3,"file":"button-DnQOyJAN.js","sources":["../../../app/components/button.tsx"],"sourcesContent":["import { Link } from '@remix-run/react'\nimport { clsx } from 'clsx'\n\nfunction PendingState() {\n\treturn <span className=\"inline-block animate-spin\">🌀</span>\n}\n\nfunction SuccessState() {\n\treturn <span>✅</span>\n}\n\nfunction ErrorState() {\n\treturn <span>❌</span>\n}\n\nexport function getButtonClassName({\n\tvarient,\n\tclip = true,\n}: {\n\tvarient: 'primary' | 'big' | 'mono'\n\tclip?: boolean\n}) {\n\tconst baseClassName =\n\t\t'inline-flex bg-foreground text-background outline-none hover:bg-background hover:text-foreground focus:bg-background focus:text-foreground'\n\tconst primaryClassName = 'px-8 py-4 font-bold'\n\tconst bigClassName = 'px-8 py-4 text-xl font-bold'\n\tconst monoClassName = 'px-8 py-4 font-mono text-sm uppercase'\n\tconst className = clsx(baseClassName, {\n\t\t'clip-path-button': clip,\n\t\t[primaryClassName]: varient === 'primary',\n\t\t[bigClassName]: varient === 'big',\n\t\t[monoClassName]: varient === 'mono',\n\t})\n\treturn className\n}\n\nexport function Button({\n\tvarient,\n\tstatus = 'idle',\n\t...props\n}: React.ComponentPropsWithoutRef<'button'> &\n\tParameters<typeof getButtonClassName>[0] & {\n\t\tstatus?: 'pending' | 'success' | 'error' | 'idle'\n\t}) {\n\tconst companion = {\n\t\tpending: <PendingState />,\n\t\tsuccess: <SuccessState />,\n\t\terror: <ErrorState />,\n\t\tidle: null,\n\t}[status]\n\treturn (\n\t\t<div className=\"clip-path-button-outer w-fit border-2 border-foreground bg-foreground\">\n\t\t\t<button\n\t\t\t\t{...props}\n\t\t\t\tclassName={clsx(\n\t\t\t\t\tprops.className,\n\t\t\t\t\tgetButtonClassName({ varient }),\n\t\t\t\t\t'flex justify-center gap-4',\n\t\t\t\t)}\n\t\t\t>\n\t\t\t\t<div>{props.children}</div>\n\t\t\t\t{companion}\n\t\t\t</button>\n\t\t</div>\n\t)\n}\n\nexport function ButtonLink({\n\tvarient,\n\t...props\n}: React.ComponentPropsWithoutRef<typeof Link> &\n\tParameters<typeof getButtonClassName>[0]) {\n\treturn (\n\t\t<div className=\"clip-path-button-outer w-fit border-2 border-foreground bg-foreground\">\n\t\t\t<Link\n\t\t\t\t{...props}\n\t\t\t\tclassName={clsx(props.className, getButtonClassName({ varient }))}\n\t\t\t/>\n\t\t</div>\n\t)\n}\n"],"names":["PendingState","jsx","SuccessState","ErrorState","getButtonClassName","varient","clip","baseClassName","primaryClassName","bigClassName","monoClassName","clsx","Button","status","props","companion","jsxs","ButtonLink","Link"],"mappings":"4HAGA,SAASA,GAAe,CACvB,OAAQC,EAAAA,IAAA,OAAA,CAAK,UAAU,4BAA4B,SAAE,IAAA,CAAA,CACtD,CAEA,SAASC,GAAe,CAChB,OAAAD,EAAA,IAAC,QAAK,SAAC,GAAA,CAAA,CACf,CAEA,SAASE,GAAa,CACd,OAAAF,EAAA,IAAC,QAAK,SAAC,GAAA,CAAA,CACf,CAEO,SAASG,EAAmB,CAClC,QAAAC,EACA,KAAAC,EAAO,EACR,EAGG,CACF,MAAMC,EACL,6IACKC,EAAmB,sBACnBC,EAAe,8BACfC,EAAgB,wCAOf,OANWC,EAAKJ,EAAe,CACrC,mBAAoBD,EACpB,CAACE,CAAgB,EAAGH,IAAY,UAChC,CAACI,CAAY,EAAGJ,IAAY,MAC5B,CAACK,CAAa,EAAGL,IAAY,MAAA,CAC7B,CAEF,CAEO,SAASO,EAAO,CACtB,QAAAP,EACA,OAAAQ,EAAS,OACT,GAAGC,CACJ,EAGI,CACH,MAAMC,EAAY,CACjB,cAAUf,EAAa,EAAA,EACvB,cAAUE,EAAa,EAAA,EACvB,YAAQC,EAAW,EAAA,EACnB,KAAM,MACLU,CAAM,EAEP,OAAAZ,EAAAA,IAAC,MAAI,CAAA,UAAU,wEACd,SAAAe,EAAA,KAAC,SAAA,CACC,GAAGF,EACJ,UAAWH,EACVG,EAAM,UACNV,EAAmB,CAAE,QAAAC,EAAS,EAC9B,2BACD,EAEA,SAAA,CAACJ,EAAAA,IAAA,MAAA,CAAK,WAAM,QAAS,CAAA,EACpBc,CAAA,CAAA,CAEH,CAAA,CAAA,CAEF,CAEO,SAASE,EAAW,CAC1B,QAAAZ,EACA,GAAGS,CACJ,EAC2C,CAEzC,OAAAb,EAAAA,IAAC,MAAI,CAAA,UAAU,wEACd,SAAAA,EAAA,IAACiB,EAAA,CACC,GAAGJ,EACJ,UAAWH,EAAKG,EAAM,UAAWV,EAAmB,CAAE,QAAAC,CAAA,CAAS,CAAC,CAAA,CAElE,CAAA,CAAA,CAEF"}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import{e as k,r as d,j as p}from"./index-
|
|
1
|
+
import{e as k,r as d,j as p}from"./index-D1WEsmVZ.js";import{b as C}from"./components-Dj3sm47B.js";function g(e){function r(o,t){var a;const s=e[t];if(!s)throw new Error(`Unknown client hint: ${typeof t=="string"?t:"Unknown"}`);const u=(a=o.split(";").map(c=>c.trim()).find(c=>c.startsWith(s.cookieName+"=")))==null?void 0:a.split("=")[1];return u?decodeURIComponent(u):null}function n(o){const t=typeof document<"u"?document.cookie:typeof o<"u"?o.headers.get("Cookie")??"":"";return Object.entries(e).reduce((s,[u,a])=>{const c=u;return"transform"in a?s[c]=a.transform(r(t,c)??a.fallback):s[c]=r(t,c)??a.fallback,s},{})}function i(){return`
|
|
2
2
|
// This block of code allows us to check if the client hints have changed and
|
|
3
3
|
// force a reload of the page with updated hints if they have so you don't get
|
|
4
4
|
// a flash of incorrect content.
|
|
@@ -33,4 +33,4 @@ function checkClientHints() {
|
|
|
33
33
|
|
|
34
34
|
checkClientHints();
|
|
35
35
|
`}return{getHints:n,getClientHintCheckScript:i}}const l={cookieName:"CH-prefers-color-scheme",getValueCode:"window.matchMedia('(prefers-color-scheme: dark)').matches ? 'dark' : 'light'",fallback:"light",transform(e){return e==="dark"?"dark":"light"}};function v(e,r=l.cookieName){const n=window.matchMedia("(prefers-color-scheme: dark)");function i(){const o=n.matches?"dark":"light";document.cookie=`${r}=${o}; Max-Age=31536000; Path=/`,e(o)}return n.addEventListener("change",i),function(){n.removeEventListener("change",i)}}const m={cookieName:"CH-reduced-motion",getValueCode:"window.matchMedia('(prefers-reduced-motion: reduce)').matches ? 'reduce' : 'no-preference'",fallback:"no-preference",transform(e){return e==="reduce"?"reduce":"no-preference"}};function H(e,r=m.cookieName){const n=window.matchMedia("(prefers-reduced-motion: reduce)");function i(){const o=n.matches?"reduce":"no-preference";document.cookie=`${r}=${o}; Max-Age=31536000; Path=/`,e(o)}return n.addEventListener("change",i),function(){n.removeEventListener("change",i)}}const S={cookieName:"CH-time-zone",getValueCode:"Intl.DateTimeFormat().resolvedOptions().timeZone",fallback:"UTC"};function w(){return C("root").requestInfo}const h="EpicShop_CH-prefers-color-scheme",f="EpicShop_CH-reduced-motion",M=g({theme:{...l,cookieName:h},timeZone:{...S,cookieName:"EpicShop_CH-time-zone"},reducedMotion:{...m,cookieName:f}});function E(){return w().hints}function $(){const{revalidate:e}=k();return d.useEffect(()=>v(()=>e(),h),[e]),d.useEffect(()=>H(()=>e(),f),[e]),p.jsx("script",{dangerouslySetInnerHTML:{__html:M.getClientHintCheckScript()}})}export{$ as C,w as a,E as u};
|
|
36
|
-
//# sourceMappingURL=client-hints-
|
|
36
|
+
//# sourceMappingURL=client-hints-KnbHFIgn.js.map
|