@epic-web/workshop-app 4.5.1 → 4.6.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/bin/epicshop.js +3 -3
- package/build/client/assets/_exerciseNumber-rfzZiDNa.js +2 -0
- package/build/client/assets/_exerciseNumber-rfzZiDNa.js.map +1 -0
- package/build/client/assets/_exerciseNumber_._stepNumber-C37pli7_.js.map +1 -1
- package/build/client/assets/_exerciseNumber_.finished-B7SgnqdS.js +2 -0
- package/build/client/assets/_exerciseNumber_.finished-B7SgnqdS.js.map +1 -0
- package/build/client/assets/_layout-BG1Jwh7V.js +2 -0
- package/build/client/assets/_layout-BG1Jwh7V.js.map +1 -0
- package/build/client/assets/_layout-CNgYirUN.js.map +1 -1
- package/build/client/assets/_layout-D0zbQZjf.js.map +1 -1
- package/build/client/assets/{diff-tDYfSlOc.js → diff-BKsbFB6w.js} +2 -2
- package/build/client/assets/diff-BKsbFB6w.js.map +1 -0
- package/build/client/assets/{diff-DZFtsH-a.js → diff-KDzcgGYL.js} +2 -2
- package/build/client/assets/diff-KDzcgGYL.js.map +1 -0
- package/build/client/assets/epic-video-BwtXsHGU.js.map +1 -1
- package/build/client/assets/error-boundary-Bcric_4t.js.map +1 -1
- package/build/client/assets/finished-BI2-0Ykt.js +2 -0
- package/build/client/assets/finished-BI2-0Ykt.js.map +1 -0
- package/build/client/assets/index-BQRtqn3g.js.map +1 -1
- package/build/client/assets/index-Bg9MMnnf.js.map +1 -1
- package/build/client/assets/manifest-1a2446b9.js +1 -0
- package/build/client/assets/mdx-BYvGbvEr.js.map +1 -1
- package/build/client/assets/misc-DNgC2Frq.js.map +1 -1
- package/build/client/assets/og-l0sNRNKZ.js +2 -0
- package/build/client/assets/og-l0sNRNKZ.js.map +1 -0
- package/build/client/assets/presence-BJPzwbUy.js.map +1 -1
- package/build/client/assets/progress-CF9Xwfxf.js.map +1 -1
- package/build/client/assets/progress-bar-7LK87ZMh.js.map +1 -1
- package/build/client/assets/{root-BJrmef-V.js → root-BXq0yevS.js} +4 -4
- package/build/client/assets/root-BXq0yevS.js.map +1 -0
- package/build/client/assets/seo-CHrqghsC.js +2 -0
- package/build/client/assets/seo-CHrqghsC.js.map +1 -0
- package/build/client/img/epicweb-og-background.png +0 -0
- package/build/server/index.js +465 -100
- package/build/server/index.js.map +1 -1
- package/node_modules/tslib/package.json +1 -1
- package/node_modules/tslib/tslib.d.ts +1 -1
- package/node_modules/tslib/tslib.es6.js +7 -3
- package/node_modules/tslib/tslib.es6.mjs +10 -7
- package/node_modules/tslib/tslib.js +7 -4
- package/package.json +4 -3
- package/start.js +2 -2
- package/build/client/assets/_exerciseNumber-jTT5JRgC.js +0 -2
- package/build/client/assets/_exerciseNumber-jTT5JRgC.js.map +0 -1
- package/build/client/assets/_exerciseNumber_.finished-zgJKkJ7I.js +0 -2
- package/build/client/assets/_exerciseNumber_.finished-zgJKkJ7I.js.map +0 -1
- package/build/client/assets/_layout-CGUp6BkS.js +0 -2
- package/build/client/assets/_layout-CGUp6BkS.js.map +0 -1
- package/build/client/assets/diff-DZFtsH-a.js.map +0 -1
- package/build/client/assets/diff-tDYfSlOc.js.map +0 -1
- package/build/client/assets/finished-BSWdtBA4.js +0 -2
- package/build/client/assets/finished-BSWdtBA4.js.map +0 -1
- package/build/client/assets/manifest-03cfc48d.js +0 -1
- package/build/client/assets/root-BJrmef-V.js.map +0 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"_layout-CNgYirUN.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\tjson,\n\ttype HeadersFunction,\n\ttype LoaderFunctionArgs,\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\tmotion,\n\tuseAnimationControls,\n\ttype AnimationControls,\n} from 'framer-motion'\nimport * as React from 'react'\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 { usePresence, type User } from '#app/utils/presence.tsx'\nimport {\n\tuseExerciseProgressClassName,\n\tuseNextExerciseRoute,\n\tuseProgressItemClassName,\n\ttype ProgressItemSearch,\n} from '../progress.tsx'\nimport { ThemeSwitch } from '../theme/index.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=\"/img/tiffany.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 ${user.location?.origin?.includes('epicweb.dev') ? 'learning' : '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\t// @ts-expect-error framer-motion + latest typescript types has issues\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\t// @ts-expect-error framer-motion + latest typescript types has issues\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\t// @ts-expect-error framer-motion + latest typescript types has issues\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\t// @ts-expect-error framer-motion + latest typescript types has issues\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\t// @ts-expect-error framer-motion + latest typescript types has issues\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\t// @ts-expect-error framer-motion + latest typescript types has issues\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\t// @ts-expect-error framer-motion + latest typescript types has issues\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\t// @ts-expect-error framer-motion + latest typescript types has issues\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","Math","round","length","shadowNumber","cn","FacePile","isMenuOpened","loggedInUser","useOptionalUser","users","usePresence","limit","numberOverLimit","tiffany","jsx","Link","target","rel","to","children","alt","className","src","overLimitLabel","TooltipProvider","slice","map","user","scoreClassNames","locationLabel","getLocationLabel","location","Tooltip","TooltipTrigger","asChild","avatarUrl","tabIndex","name","Icon","TooltipContent","jsxs","origin","includes","id","line1","line2","App","setMenuOpened","React","EpicWebBanner","ENV","EPICSHOP_DEPLOYED","Navigation","onMenuOpenChange","Outlet","exercise","exercisePortion","exerciseNumber","stepNumber","filter","Boolean","s","toString","padStart","join","type","workshopTitle","size","EPICSHOP_GITHUB_ROOT","itemVariants","hidden","opacity","x","visible","NavigationExerciseListItem","progressClassName","useExerciseProgressClassName","motion","li","variants","NavigationExerciseStepListItem","progressItemSearch","useProgressItemClassName","OPENED_MENU_WIDTH","data","useLoaderData","nextExerciseRoute","useNextExerciseRoute","params","useParams","exercises","find","e","Number","app","solutions","problems","p","menuControls","menuVariants","close","width","open","listVariants","transition","duration","when","staggerChildren","exNum","div","initial","animate","NavToggle","title","style","ul","steps","isActive","showPlayground","playground","exerciseNum","prefetch","clsx","step","isPlayground","appName","NavLink","SimpleTooltip","content","email","state","from","ThemeSwitch","path01Variants","d","closed","path02Variants","moving","path01Controls","path02Controls","toggleMenu","start","latestToggleMenu","current","handleKeyUp","event","document","addEventListener","removeEventListener","onClick","height","viewBox","path","stroke","strokeWidth","delay","y"],"mappings":"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","x_google_ignoreList":[0,1]}
|
|
1
|
+
{"version":3,"file":"_layout-CNgYirUN.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\tjson,\n\ttype HeadersFunction,\n\ttype LoaderFunctionArgs,\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\tmotion,\n\tuseAnimationControls,\n\ttype AnimationControls,\n} from 'framer-motion'\nimport * as React from 'react'\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 { usePresence, type User } from '#app/utils/presence.tsx'\nimport {\n\tuseExerciseProgressClassName,\n\tuseNextExerciseRoute,\n\tuseProgressItemClassName,\n\ttype ProgressItemSearch,\n} from '../progress.tsx'\nimport { ThemeSwitch } from '../theme/index.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=\"/img/tiffany.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 ${user.location?.origin?.includes('epicweb.dev') ? 'learning' : '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\t// @ts-expect-error framer-motion + latest typescript types has issues\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\t// @ts-expect-error framer-motion + latest typescript types has issues\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\t(e) => 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\t(s) => 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\t(p) => 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\t// @ts-expect-error framer-motion + latest typescript types has issues\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\t// @ts-expect-error framer-motion + latest typescript types has issues\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\t// @ts-expect-error framer-motion + latest typescript types has issues\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\t// @ts-expect-error framer-motion + latest typescript types has issues\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\t// @ts-expect-error framer-motion + latest typescript types has issues\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\t// @ts-expect-error framer-motion + latest typescript types has issues\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","Math","round","length","shadowNumber","cn","FacePile","isMenuOpened","loggedInUser","useOptionalUser","users","usePresence","limit","numberOverLimit","tiffany","jsx","Link","target","rel","to","children","alt","className","src","overLimitLabel","TooltipProvider","slice","map","user","scoreClassNames","locationLabel","getLocationLabel","location","Tooltip","TooltipTrigger","asChild","avatarUrl","tabIndex","name","Icon","TooltipContent","jsxs","origin","includes","id","line1","line2","App","setMenuOpened","React","EpicWebBanner","ENV","EPICSHOP_DEPLOYED","Navigation","onMenuOpenChange","Outlet","exercise","exercisePortion","exerciseNumber","stepNumber","filter","Boolean","s","toString","padStart","join","type","workshopTitle","size","EPICSHOP_GITHUB_ROOT","itemVariants","hidden","opacity","x","visible","NavigationExerciseListItem","progressClassName","useExerciseProgressClassName","motion","li","variants","NavigationExerciseStepListItem","progressItemSearch","useProgressItemClassName","OPENED_MENU_WIDTH","data","useLoaderData","nextExerciseRoute","useNextExerciseRoute","params","useParams","exercises","find","e","Number","app","solutions","problems","p","menuControls","menuVariants","close","width","open","listVariants","transition","duration","when","staggerChildren","exNum","div","initial","animate","NavToggle","title","style","ul","steps","isActive","showPlayground","playground","exerciseNum","prefetch","clsx","step","isPlayground","appName","NavLink","SimpleTooltip","content","email","state","from","ThemeSwitch","path01Variants","d","closed","path02Variants","moving","path01Controls","path02Controls","toggleMenu","start","latestToggleMenu","current","handleKeyUp","event","document","addEventListener","removeEventListener","onClick","height","viewBox","path","stroke","strokeWidth","delay","y"],"mappings":"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","x_google_ignoreList":[0,1]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"_layout-D0zbQZjf.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\tjson,\n\ttype ActionFunctionArgs,\n\ttype LoaderFunctionArgs,\n\ttype MetaFunction,\n} from '@remix-run/node'\nimport { Form, Link, useLoaderData, useNavigation } from '@remix-run/react'\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\tuseEpicProgress,\n\ttype SerializedProgress,\n} from '#app/routes/progress.tsx'\nimport { ensureUndeployed } from '#app/utils/misc.tsx'\nimport {\n\tclearCaches,\n\tclearData,\n\tstartInspector,\n\tstopInspector,\n} from './admin-utils.server.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\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","find","m","id","data","title","workshopTitle","sortProgress","a","b","type","linkProgress","progress","exerciseNumber","toString","padStart","stepNumber","AdminLayout","useLoaderData","navigation","useNavigation","epicProgress","useEpicProgress","isStartingInspector","formData","get","isStoppingInspector","progressStatus","completed","incomplete","jsxs","className","children","jsx","Link","to","sort","map","epicUrl","workshopSlug","epicSectionSlug","epicLessonSlug","status","epicCompletedAt","label","filter","Boolean","join","SimpleTooltip","content","Icon","name","Form","method","value","inspectorRunning","apps","app","processes","Pinger","Object","entries","key","process","port","pid","color","testProcesses","exitCode","colors","running","pinger","circle","starting","stopped","taken"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"_layout-D0zbQZjf.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\tjson,\n\ttype ActionFunctionArgs,\n\ttype LoaderFunctionArgs,\n\ttype MetaFunction,\n} from '@remix-run/node'\nimport { Form, Link, useLoaderData, useNavigation } from '@remix-run/react'\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\tuseEpicProgress,\n\ttype SerializedProgress,\n} from '#app/routes/progress.tsx'\nimport { ensureUndeployed } from '#app/utils/misc.tsx'\nimport {\n\tclearCaches,\n\tclearData,\n\tstartInspector,\n\tstopInspector,\n} from './admin-utils.server.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\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","find","m","id","data","title","workshopTitle","sortProgress","a","b","type","linkProgress","progress","exerciseNumber","toString","padStart","stepNumber","AdminLayout","useLoaderData","navigation","useNavigation","epicProgress","useEpicProgress","isStartingInspector","formData","get","isStoppingInspector","progressStatus","completed","incomplete","jsxs","className","children","jsx","Link","to","sort","map","epicUrl","workshopSlug","epicSectionSlug","epicLessonSlug","status","epicCompletedAt","label","filter","Boolean","join","SimpleTooltip","content","Icon","name","Form","method","value","inspectorRunning","apps","app","processes","Pinger","Object","entries","key","process","port","pid","color","testProcesses","exitCode","colors","running","pinger","circle","starting","stopped","taken"],"mappings":"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"}
|
|
@@ -38,5 +38,5 @@ import{r,R as S,j as g,c as Xt}from"./index-D6ygCrVn.js";import{g as M,_ as I,$
|
|
|
38
38
|
`)},ft=function(){var e=parseInt(document.body.getAttribute(ie)||"0",10);return isFinite(e)?e:0},Io=function(){r.useEffect(function(){return document.body.setAttribute(ie,(ft()+1).toString()),function(){var e=ft()-1;e<=0?document.body.removeAttribute(ie):document.body.setAttribute(ie,e.toString())}},[])},Ro=function(e){var n=e.noRelative,t=e.noImportant,o=e.gapMode,c=o===void 0?"margin":o;Io();var s=r.useMemo(function(){return Co(c)},[c]);return r.createElement(Eo,{styles:yo(s,!n,c,t?"":"!important")})},ze=!1;if(typeof window<"u")try{var xe=Object.defineProperty({},"passive",{get:function(){return ze=!0,!0}});window.addEventListener("test",xe,xe),window.removeEventListener("test",xe,xe)}catch{ze=!1}var se=ze?{passive:!1}:!1,_o=function(e){return e.tagName==="TEXTAREA"},Vt=function(e,n){var t=window.getComputedStyle(e);return t[n]!=="hidden"&&!(t.overflowY===t.overflowX&&!_o(e)&&t[n]==="visible")},To=function(e){return Vt(e,"overflowY")},Po=function(e){return Vt(e,"overflowX")},pt=function(e,n){var t=n;do{typeof ShadowRoot<"u"&&t instanceof ShadowRoot&&(t=t.host);var o=Ft(e,t);if(o){var c=Bt(e,t),s=c[1],l=c[2];if(s>l)return!0}t=t.parentNode}while(t&&t!==document.body);return!1},Ao=function(e){var n=e.scrollTop,t=e.scrollHeight,o=e.clientHeight;return[n,t,o]},No=function(e){var n=e.scrollLeft,t=e.scrollWidth,o=e.clientWidth;return[n,t,o]},Ft=function(e,n){return e==="v"?To(n):Po(n)},Bt=function(e,n){return e==="v"?Ao(n):No(n)},Mo=function(e,n){return e==="h"&&n==="rtl"?-1:1},Oo=function(e,n,t,o,c){var s=Mo(e,window.getComputedStyle(n).direction),l=s*o,a=t.target,d=n.contains(a),u=!1,v=l>0,$=0,w=0;do{var x=Bt(e,a),h=x[0],i=x[1],m=x[2],p=i-m-s*h;(h||p)&&Ft(e,a)&&($+=p,w+=h),a=a.parentNode}while(!d&&a!==document.body||d&&(n.contains(a)||n===a));return(v&&($===0||!c)||!v&&(w===0||!c))&&(u=!0),u},we=function(e){return"changedTouches"in e?[e.changedTouches[0].clientX,e.changedTouches[0].clientY]:[0,0]},mt=function(e){return[e.deltaX,e.deltaY]},vt=function(e){return e&&"current"in e?e.current:e},ko=function(e,n){return e[0]===n[0]&&e[1]===n[1]},Do=function(e){return`
|
|
39
39
|
.block-interactivity-`.concat(e,` {pointer-events: none;}
|
|
40
40
|
.allow-interactivity-`).concat(e,` {pointer-events: all;}
|
|
41
|
-
`)},Lo=0,le=[];function jo(e){var n=r.useRef([]),t=r.useRef([0,0]),o=r.useRef(),c=r.useState(Lo++)[0],s=r.useState(function(){return jt()})[0],l=r.useRef(e);r.useEffect(function(){l.current=e},[e]),r.useEffect(function(){if(e.inert){document.body.classList.add("block-interactivity-".concat(c));var i=ro([e.lockRef.current],(e.shards||[]).map(vt),!0).filter(Boolean);return i.forEach(function(m){return m.classList.add("allow-interactivity-".concat(c))}),function(){document.body.classList.remove("block-interactivity-".concat(c)),i.forEach(function(m){return m.classList.remove("allow-interactivity-".concat(c))})}}},[e.inert,e.lockRef.current,e.shards]);var a=r.useCallback(function(i,m){if("touches"in i&&i.touches.length===2)return!l.current.allowPinchZoom;var p=we(i),f=t.current,b="deltaX"in i?i.deltaX:f[0]-p[0],E="deltaY"in i?i.deltaY:f[1]-p[1],y,j=i.target,T=Math.abs(b)>Math.abs(E)?"h":"v";if("touches"in i&&T==="h"&&j.type==="range")return!1;var N=pt(T,j);if(!N)return!0;if(N?y=T:(y=T==="v"?"h":"v",N=pt(T,j)),!N)return!1;if(!o.current&&"changedTouches"in i&&(b||E)&&(o.current=y),!y)return!0;var L=o.current||y;return Oo(L,m,i,L==="h"?b:E,!0)},[]),d=r.useCallback(function(i){var m=i;if(!(!le.length||le[le.length-1]!==s)){var p="deltaY"in m?mt(m):we(m),f=n.current.filter(function(y){return y.name===m.type&&y.target===m.target&&ko(y.delta,p)})[0];if(f&&f.should){m.cancelable&&m.preventDefault();return}if(!f){var b=(l.current.shards||[]).map(vt).filter(Boolean).filter(function(y){return y.contains(m.target)}),E=b.length>0?a(m,b[0]):!l.current.noIsolation;E&&m.cancelable&&m.preventDefault()}}},[]),u=r.useCallback(function(i,m,p,f){var b={name:i,delta:m,target:p,should:f};n.current.push(b),setTimeout(function(){n.current=n.current.filter(function(E){return E!==b})},1)},[]),v=r.useCallback(function(i){t.current=we(i),o.current=void 0},[]),$=r.useCallback(function(i){u(i.type,mt(i),i.target,a(i,e.lockRef.current))},[]),w=r.useCallback(function(i){u(i.type,we(i),i.target,a(i,e.lockRef.current))},[]);r.useEffect(function(){return le.push(s),e.setCallbacks({onScrollCapture:$,onWheelCapture:$,onTouchMoveCapture:w}),document.addEventListener("wheel",d,se),document.addEventListener("touchmove",d,se),document.addEventListener("touchstart",v,se),function(){le=le.filter(function(i){return i!==s}),document.removeEventListener("wheel",d,se),document.removeEventListener("touchmove",d,se),document.removeEventListener("touchstart",v,se)}},[]);var x=e.removeScrollBar,h=e.inert;return r.createElement(r.Fragment,null,h?r.createElement(s,{styles:Do(c)}):null,x?r.createElement(Ro,{gapMode:"margin"}):null)}const Vo=mo(Lt,jo);var Ht=r.forwardRef(function(e,n){return r.createElement(_e,G({},e,{ref:n,sideCar:Vo}))});Ht.classNames=_e.classNames;const Fo=[" ","Enter","ArrowUp","ArrowDown"],Bo=[" ","Enter"],Te="Select",[Pe,Ae,Ho]=Ct(Te),[ue,Gr]=ye(Te,[Ho,wt]),tt=wt(),[Wo,ne]=ue(Te),[Ko,Uo]=ue(Te),Go=e=>{const{__scopeSelect:n,children:t,open:o,defaultOpen:c,onOpenChange:s,value:l,defaultValue:a,onValueChange:d,dir:u,name:v,autoComplete:$,disabled:w,required:x}=e,h=tt(n),[i,m]=r.useState(null),[p,f]=r.useState(null),[b,E]=r.useState(!1),y=Et(u),[j=!1,T]=pe({prop:o,defaultProp:c,onChange:s}),[N,L]=pe({prop:l,defaultProp:a,onChange:d}),W=r.useRef(null),te=i?!!i.closest("form"):!0,[K,X]=r.useState(new Set),Z=Array.from(K).map(k=>k.props.value).join(";");return r.createElement(Qt,h,r.createElement(Wo,{required:x,scope:n,trigger:i,onTriggerChange:m,valueNode:p,onValueNodeChange:f,valueNodeHasChildren:b,onValueNodeHasChildrenChange:E,contentId:me(),value:N,onValueChange:L,open:j,onOpenChange:T,dir:y,triggerPointerDownPosRef:W,disabled:w},r.createElement(Pe.Provider,{scope:n},r.createElement(Ko,{scope:e.__scopeSelect,onNativeOptionAdd:r.useCallback(k=>{X(U=>new Set(U).add(k))},[]),onNativeOptionRemove:r.useCallback(k=>{X(U=>{const Y=new Set(U);return Y.delete(k),Y})},[])},t)),te?r.createElement(Yt,{key:Z,"aria-hidden":!0,required:x,tabIndex:-1,name:v,autoComplete:$,value:N,onChange:k=>L(k.target.value),disabled:w},N===void 0?r.createElement("option",{value:""}):null,Array.from(K)):null))},Yo="SelectTrigger",zo=r.forwardRef((e,n)=>{const{__scopeSelect:t,disabled:o=!1,...c}=e,s=tt(t),l=ne(Yo,t),a=l.disabled||o,d=D(n,l.onTriggerChange),u=Ae(t),[v,$,w]=zt(h=>{const i=u().filter(f=>!f.disabled),m=i.find(f=>f.value===l.value),p=qt(i,h,m);p!==void 0&&l.onValueChange(p.value)}),x=()=>{a||(l.onOpenChange(!0),w())};return r.createElement(Jt,I({asChild:!0},s),r.createElement(M.button,I({type:"button",role:"combobox","aria-controls":l.contentId,"aria-expanded":l.open,"aria-required":l.required,"aria-autocomplete":"none",dir:l.dir,"data-state":l.open?"open":"closed",disabled:a,"data-disabled":a?"":void 0,"data-placeholder":Gt(l.value)?"":void 0},c,{ref:d,onClick:O(c.onClick,h=>{h.currentTarget.focus()}),onPointerDown:O(c.onPointerDown,h=>{const i=h.target;i.hasPointerCapture(h.pointerId)&&i.releasePointerCapture(h.pointerId),h.button===0&&h.ctrlKey===!1&&(x(),l.triggerPointerDownPosRef.current={x:Math.round(h.pageX),y:Math.round(h.pageY)},h.preventDefault())}),onKeyDown:O(c.onKeyDown,h=>{const i=v.current!=="";!(h.ctrlKey||h.altKey||h.metaKey)&&h.key.length===1&&$(h.key),!(i&&h.key===" ")&&Fo.includes(h.key)&&(x(),h.preventDefault())})})))}),qo="SelectValue",Xo=r.forwardRef((e,n)=>{const{__scopeSelect:t,className:o,style:c,children:s,placeholder:l="",...a}=e,d=ne(qo,t),{onValueNodeHasChildrenChange:u}=d,v=s!==void 0,$=D(n,d.onValueNodeChange);return q(()=>{u(v)},[u,v]),r.createElement(M.span,I({},a,{ref:$,style:{pointerEvents:"none"}}),Gt(d.value)?r.createElement(r.Fragment,null,l):s)}),Zo=r.forwardRef((e,n)=>{const{__scopeSelect:t,children:o,...c}=e;return r.createElement(M.span,I({"aria-hidden":!0},c,{ref:n}),o||"▼")}),Qo=e=>r.createElement(pn,I({asChild:!0},e)),de="SelectContent",Jo=r.forwardRef((e,n)=>{const t=ne(de,e.__scopeSelect),[o,c]=r.useState();if(q(()=>{c(new DocumentFragment)},[]),!t.open){const s=o;return s?St.createPortal(r.createElement(Wt,{scope:e.__scopeSelect},r.createElement(Pe.Slot,{scope:e.__scopeSelect},r.createElement("div",null,e.children))),s):null}return r.createElement(er,I({},e,{ref:n}))}),z=10,[Wt,oe]=ue(de),er=r.forwardRef((e,n)=>{const{__scopeSelect:t,position:o="item-aligned",onCloseAutoFocus:c,onEscapeKeyDown:s,onPointerDownOutside:l,side:a,sideOffset:d,align:u,alignOffset:v,arrowPadding:$,collisionBoundary:w,collisionPadding:x,sticky:h,hideWhenDetached:i,avoidCollisions:m,...p}=e,f=ne(de,t),[b,E]=r.useState(null),[y,j]=r.useState(null),T=D(n,C=>E(C)),[N,L]=r.useState(null),[W,te]=r.useState(null),K=Ae(t),[X,Z]=r.useState(!1),k=r.useRef(!1);r.useEffect(()=>{if(b)return oo(b)},[b]),Un();const U=r.useCallback(C=>{const[P,...V]=K().map(_=>_.ref.current),[A]=V.slice(-1),R=document.activeElement;for(const _ of C)if(_===R||(_==null||_.scrollIntoView({block:"nearest"}),_===P&&y&&(y.scrollTop=0),_===A&&y&&(y.scrollTop=y.scrollHeight),_==null||_.focus(),document.activeElement!==R))return},[K,y]),Y=r.useCallback(()=>U([N,b]),[U,N,b]);r.useEffect(()=>{X&&Y()},[X,Y]);const{onOpenChange:re,triggerPointerDownPosRef:Q}=f;r.useEffect(()=>{if(b){let C={x:0,y:0};const P=A=>{var R,_,B,H;C={x:Math.abs(Math.round(A.pageX)-((R=(_=Q.current)===null||_===void 0?void 0:_.x)!==null&&R!==void 0?R:0)),y:Math.abs(Math.round(A.pageY)-((B=(H=Q.current)===null||H===void 0?void 0:H.y)!==null&&B!==void 0?B:0))}},V=A=>{C.x<=10&&C.y<=10?A.preventDefault():b.contains(A.target)||re(!1),document.removeEventListener("pointermove",P),Q.current=null};return Q.current!==null&&(document.addEventListener("pointermove",P),document.addEventListener("pointerup",V,{capture:!0,once:!0})),()=>{document.removeEventListener("pointermove",P),document.removeEventListener("pointerup",V,{capture:!0})}}},[b,re,Q]),r.useEffect(()=>{const C=()=>re(!1);return window.addEventListener("blur",C),window.addEventListener("resize",C),()=>{window.removeEventListener("blur",C),window.removeEventListener("resize",C)}},[re]);const[Ne,he]=zt(C=>{const P=K().filter(R=>!R.disabled),V=P.find(R=>R.ref.current===document.activeElement),A=qt(P,C,V);A&&setTimeout(()=>A.ref.current.focus())}),Me=r.useCallback((C,P,V)=>{const A=!k.current&&!V;(f.value!==void 0&&f.value===P||A)&&(L(C),A&&(k.current=!0))},[f.value]),Oe=r.useCallback(()=>b==null?void 0:b.focus(),[b]),ce=r.useCallback((C,P,V)=>{const A=!k.current&&!V;(f.value!==void 0&&f.value===P||A)&&te(C)},[f.value]),be=o==="popper"?ht:tr,fe=be===ht?{side:a,sideOffset:d,align:u,alignOffset:v,arrowPadding:$,collisionBoundary:w,collisionPadding:x,sticky:h,hideWhenDetached:i,avoidCollisions:m}:{};return r.createElement(Wt,{scope:t,content:b,viewport:y,onViewportChange:j,itemRefCallback:Me,selectedItem:N,onItemLeave:Oe,itemTextRefCallback:ce,focusSelectedItem:Y,selectedItemText:W,position:o,isPositioned:X,searchRef:Ne},r.createElement(Ht,{as:Ue,allowPinchZoom:!0},r.createElement(Gn,{asChild:!0,trapped:f.open,onMountAutoFocus:C=>{C.preventDefault()},onUnmountAutoFocus:O(c,C=>{var P;(P=f.trigger)===null||P===void 0||P.focus({preventScroll:!0}),C.preventDefault()})},r.createElement(en,{asChild:!0,disableOutsidePointerEvents:!0,onEscapeKeyDown:s,onPointerDownOutside:l,onFocusOutside:C=>C.preventDefault(),onDismiss:()=>f.onOpenChange(!1)},r.createElement(be,I({role:"listbox",id:f.contentId,"data-state":f.open?"open":"closed",dir:f.dir,onContextMenu:C=>C.preventDefault()},p,fe,{onPlaced:()=>Z(!0),ref:T,style:{display:"flex",flexDirection:"column",outline:"none",...p.style},onKeyDown:O(p.onKeyDown,C=>{const P=C.ctrlKey||C.altKey||C.metaKey;if(C.key==="Tab"&&C.preventDefault(),!P&&C.key.length===1&&he(C.key),["ArrowUp","ArrowDown","Home","End"].includes(C.key)){let A=K().filter(R=>!R.disabled).map(R=>R.ref.current);if(["ArrowUp","End"].includes(C.key)&&(A=A.slice().reverse()),["ArrowUp","ArrowDown"].includes(C.key)){const R=C.target,_=A.indexOf(R);A=A.slice(_+1)}setTimeout(()=>U(A)),C.preventDefault()}})}))))))}),tr=r.forwardRef((e,n)=>{const{__scopeSelect:t,onPlaced:o,...c}=e,s=ne(de,t),l=oe(de,t),[a,d]=r.useState(null),[u,v]=r.useState(null),$=D(n,T=>v(T)),w=Ae(t),x=r.useRef(!1),h=r.useRef(!0),{viewport:i,selectedItem:m,selectedItemText:p,focusSelectedItem:f}=l,b=r.useCallback(()=>{if(s.trigger&&s.valueNode&&a&&u&&i&&m&&p){const T=s.trigger.getBoundingClientRect(),N=u.getBoundingClientRect(),L=s.valueNode.getBoundingClientRect(),W=p.getBoundingClientRect();if(s.dir!=="rtl"){const R=W.left-N.left,_=L.left-R,B=T.left-_,H=T.width+B,ke=Math.max(H,N.width),De=window.innerWidth-z,Le=ct(_,[z,De-ke]);a.style.minWidth=H+"px",a.style.left=Le+"px"}else{const R=N.right-W.right,_=window.innerWidth-L.right-R,B=window.innerWidth-T.right-_,H=T.width+B,ke=Math.max(H,N.width),De=window.innerWidth-z,Le=ct(_,[z,De-ke]);a.style.minWidth=H+"px",a.style.right=Le+"px"}const te=w(),K=window.innerHeight-z*2,X=i.scrollHeight,Z=window.getComputedStyle(u),k=parseInt(Z.borderTopWidth,10),U=parseInt(Z.paddingTop,10),Y=parseInt(Z.borderBottomWidth,10),re=parseInt(Z.paddingBottom,10),Q=k+U+X+re+Y,Ne=Math.min(m.offsetHeight*5,Q),he=window.getComputedStyle(i),Me=parseInt(he.paddingTop,10),Oe=parseInt(he.paddingBottom,10),ce=T.top+T.height/2-z,be=K-ce,fe=m.offsetHeight/2,C=m.offsetTop+fe,P=k+U+C,V=Q-P;if(P<=ce){const R=m===te[te.length-1].ref.current;a.style.bottom="0px";const _=u.clientHeight-i.offsetTop-i.offsetHeight,B=Math.max(be,fe+(R?Oe:0)+_+Y),H=P+B;a.style.height=H+"px"}else{const R=m===te[0].ref.current;a.style.top="0px";const B=Math.max(ce,k+i.offsetTop+(R?Me:0)+fe)+V;a.style.height=B+"px",i.scrollTop=P-ce+i.offsetTop}a.style.margin=`${z}px 0`,a.style.minHeight=Ne+"px",a.style.maxHeight=K+"px",o==null||o(),requestAnimationFrame(()=>x.current=!0)}},[w,s.trigger,s.valueNode,a,u,i,m,p,s.dir,o]);q(()=>b(),[b]);const[E,y]=r.useState();q(()=>{u&&y(window.getComputedStyle(u).zIndex)},[u]);const j=r.useCallback(T=>{T&&h.current===!0&&(b(),f==null||f(),h.current=!1)},[b,f]);return r.createElement(nr,{scope:t,contentWrapper:a,shouldExpandOnScrollRef:x,onScrollButtonChange:j},r.createElement("div",{ref:d,style:{display:"flex",flexDirection:"column",position:"fixed",zIndex:E}},r.createElement(M.div,I({},c,{ref:$,style:{boxSizing:"border-box",maxHeight:"100%",...c.style}}))))}),ht=r.forwardRef((e,n)=>{const{__scopeSelect:t,align:o="start",collisionPadding:c=z,...s}=e,l=tt(t);return r.createElement(nn,I({},l,s,{ref:n,align:o,collisionPadding:c,style:{boxSizing:"border-box",...s.style,"--radix-select-content-transform-origin":"var(--radix-popper-transform-origin)","--radix-select-content-available-width":"var(--radix-popper-available-width)","--radix-select-content-available-height":"var(--radix-popper-available-height)","--radix-select-trigger-width":"var(--radix-popper-anchor-width)","--radix-select-trigger-height":"var(--radix-popper-anchor-height)"}}))}),[nr,nt]=ue(de,{}),bt="SelectViewport",or=r.forwardRef((e,n)=>{const{__scopeSelect:t,...o}=e,c=oe(bt,t),s=nt(bt,t),l=D(n,c.onViewportChange),a=r.useRef(0);return r.createElement(r.Fragment,null,r.createElement("style",{dangerouslySetInnerHTML:{__html:"[data-radix-select-viewport]{scrollbar-width:none;-ms-overflow-style:none;-webkit-overflow-scrolling:touch;}[data-radix-select-viewport]::-webkit-scrollbar{display:none}"}}),r.createElement(Pe.Slot,{scope:t},r.createElement(M.div,I({"data-radix-select-viewport":"",role:"presentation"},o,{ref:l,style:{position:"relative",flex:1,overflow:"auto",...o.style},onScroll:O(o.onScroll,d=>{const u=d.currentTarget,{contentWrapper:v,shouldExpandOnScrollRef:$}=s;if($!=null&&$.current&&v){const w=Math.abs(a.current-u.scrollTop);if(w>0){const x=window.innerHeight-z*2,h=parseFloat(v.style.minHeight),i=parseFloat(v.style.height),m=Math.max(h,i);if(m<x){const p=m+w,f=Math.min(x,p),b=p-f;v.style.height=f+"px",v.style.bottom==="0px"&&(u.scrollTop=b>0?b:0,v.style.justifyContent="flex-end")}}}a.current=u.scrollTop})}))))}),rr="SelectGroup",[cr,ar]=ue(rr),sr=r.forwardRef((e,n)=>{const{__scopeSelect:t,...o}=e,c=me();return r.createElement(cr,{scope:t,id:c},r.createElement(M.div,I({role:"group","aria-labelledby":c},o,{ref:n})))}),lr="SelectLabel",ir=r.forwardRef((e,n)=>{const{__scopeSelect:t,...o}=e,c=ar(lr,t);return r.createElement(M.div,I({id:c.id},o,{ref:n}))}),qe="SelectItem",[dr,Kt]=ue(qe),ur=r.forwardRef((e,n)=>{const{__scopeSelect:t,value:o,disabled:c=!1,textValue:s,...l}=e,a=ne(qe,t),d=oe(qe,t),u=a.value===o,[v,$]=r.useState(s??""),[w,x]=r.useState(!1),h=D(n,p=>{var f;return(f=d.itemRefCallback)===null||f===void 0?void 0:f.call(d,p,o,c)}),i=me(),m=()=>{c||(a.onValueChange(o),a.onOpenChange(!1))};if(o==="")throw new Error("A <Select.Item /> must have a value prop that is not an empty string. This is because the Select value can be set to an empty string to clear the selection and show the placeholder.");return r.createElement(dr,{scope:t,value:o,disabled:c,textId:i,isSelected:u,onItemTextChange:r.useCallback(p=>{$(f=>{var b;return f||((b=p==null?void 0:p.textContent)!==null&&b!==void 0?b:"").trim()})},[])},r.createElement(Pe.ItemSlot,{scope:t,value:o,disabled:c,textValue:v},r.createElement(M.div,I({role:"option","aria-labelledby":i,"data-highlighted":w?"":void 0,"aria-selected":u&&w,"data-state":u?"checked":"unchecked","aria-disabled":c||void 0,"data-disabled":c?"":void 0,tabIndex:c?void 0:-1},l,{ref:h,onFocus:O(l.onFocus,()=>x(!0)),onBlur:O(l.onBlur,()=>x(!1)),onPointerUp:O(l.onPointerUp,m),onPointerMove:O(l.onPointerMove,p=>{if(c){var f;(f=d.onItemLeave)===null||f===void 0||f.call(d)}else p.currentTarget.focus({preventScroll:!0})}),onPointerLeave:O(l.onPointerLeave,p=>{if(p.currentTarget===document.activeElement){var f;(f=d.onItemLeave)===null||f===void 0||f.call(d)}}),onKeyDown:O(l.onKeyDown,p=>{var f;((f=d.searchRef)===null||f===void 0?void 0:f.current)!==""&&p.key===" "||(Bo.includes(p.key)&&m(),p.key===" "&&p.preventDefault())})}))))}),Se="SelectItemText",fr=r.forwardRef((e,n)=>{const{__scopeSelect:t,className:o,style:c,...s}=e,l=ne(Se,t),a=oe(Se,t),d=Kt(Se,t),u=Uo(Se,t),[v,$]=r.useState(null),w=D(n,p=>$(p),d.onItemTextChange,p=>{var f;return(f=a.itemTextRefCallback)===null||f===void 0?void 0:f.call(a,p,d.value,d.disabled)}),x=v==null?void 0:v.textContent,h=r.useMemo(()=>r.createElement("option",{key:d.value,value:d.value,disabled:d.disabled},x),[d.disabled,d.value,x]),{onNativeOptionAdd:i,onNativeOptionRemove:m}=u;return q(()=>(i(h),()=>m(h)),[i,m,h]),r.createElement(r.Fragment,null,r.createElement(M.span,I({id:d.textId},s,{ref:w})),d.isSelected&&l.valueNode&&!l.valueNodeHasChildren?St.createPortal(s.children,l.valueNode):null)}),pr="SelectItemIndicator",mr=r.forwardRef((e,n)=>{const{__scopeSelect:t,...o}=e;return Kt(pr,t).isSelected?r.createElement(M.span,I({"aria-hidden":!0},o,{ref:n})):null}),$t="SelectScrollUpButton",vr=r.forwardRef((e,n)=>{const t=oe($t,e.__scopeSelect),o=nt($t,e.__scopeSelect),[c,s]=r.useState(!1),l=D(n,o.onScrollButtonChange);return q(()=>{if(t.viewport&&t.isPositioned){let d=function(){const u=a.scrollTop>0;s(u)};const a=t.viewport;return d(),a.addEventListener("scroll",d),()=>a.removeEventListener("scroll",d)}},[t.viewport,t.isPositioned]),c?r.createElement(Ut,I({},e,{ref:l,onAutoScroll:()=>{const{viewport:a,selectedItem:d}=t;a&&d&&(a.scrollTop=a.scrollTop-d.offsetHeight)}})):null}),gt="SelectScrollDownButton",hr=r.forwardRef((e,n)=>{const t=oe(gt,e.__scopeSelect),o=nt(gt,e.__scopeSelect),[c,s]=r.useState(!1),l=D(n,o.onScrollButtonChange);return q(()=>{if(t.viewport&&t.isPositioned){let d=function(){const u=a.scrollHeight-a.clientHeight,v=Math.ceil(a.scrollTop)<u;s(v)};const a=t.viewport;return d(),a.addEventListener("scroll",d),()=>a.removeEventListener("scroll",d)}},[t.viewport,t.isPositioned]),c?r.createElement(Ut,I({},e,{ref:l,onAutoScroll:()=>{const{viewport:a,selectedItem:d}=t;a&&d&&(a.scrollTop=a.scrollTop+d.offsetHeight)}})):null}),Ut=r.forwardRef((e,n)=>{const{__scopeSelect:t,onAutoScroll:o,...c}=e,s=oe("SelectScrollButton",t),l=r.useRef(null),a=Ae(t),d=r.useCallback(()=>{l.current!==null&&(window.clearInterval(l.current),l.current=null)},[]);return r.useEffect(()=>()=>d(),[d]),q(()=>{var u;const v=a().find($=>$.ref.current===document.activeElement);v==null||(u=v.ref.current)===null||u===void 0||u.scrollIntoView({block:"nearest"})},[a]),r.createElement(M.div,I({"aria-hidden":!0},c,{ref:n,style:{flexShrink:0,...c.style},onPointerDown:O(c.onPointerDown,()=>{l.current===null&&(l.current=window.setInterval(o,50))}),onPointerMove:O(c.onPointerMove,()=>{var u;(u=s.onItemLeave)===null||u===void 0||u.call(s),l.current===null&&(l.current=window.setInterval(o,50))}),onPointerLeave:O(c.onPointerLeave,()=>{d()})}))});function Gt(e){return e===""||e===void 0}const Yt=r.forwardRef((e,n)=>{const{value:t,...o}=e,c=r.useRef(null),s=D(n,c),l=Jn(t);return r.useEffect(()=>{const a=c.current,d=window.HTMLSelectElement.prototype,v=Object.getOwnPropertyDescriptor(d,"value").set;if(l!==t&&v){const $=new Event("change",{bubbles:!0});v.call(a,t),a.dispatchEvent($)}},[l,t]),r.createElement(tn,{asChild:!0},r.createElement("select",I({},o,{ref:s,defaultValue:t})))});Yt.displayName="BubbleSelect";function zt(e){const n=Ge(e),t=r.useRef(""),o=r.useRef(0),c=r.useCallback(l=>{const a=t.current+l;n(a),function d(u){t.current=u,window.clearTimeout(o.current),u!==""&&(o.current=window.setTimeout(()=>d(""),1e3))}(a)},[n]),s=r.useCallback(()=>{t.current="",window.clearTimeout(o.current)},[]);return r.useEffect(()=>()=>window.clearTimeout(o.current),[]),[t,c,s]}function qt(e,n,t){const c=n.length>1&&Array.from(n).every(u=>u===n[0])?n[0]:n,s=t?e.indexOf(t):-1;let l=br(e,Math.max(s,0));c.length===1&&(l=l.filter(u=>u!==t));const d=l.find(u=>u.textValue.toLowerCase().startsWith(c.toLowerCase()));return d!==t?d:void 0}function br(e,n){return e.map((t,o)=>e[(n+o)%e.length])}const $r=Go,gr=zo,xr=Xo,wr=Zo,Sr=Qo,Cr=Jo,Er=or,yr=sr,Ir=ir,Rr=ur,_r=fr,Tr=mr,Pr=vr,Ar=hr,Nr=({title:e,children:n,variant:t,icon:o,forceMount:c=!1})=>{const s=()=>{switch(t){case"changed":return g.jsx(F,{name:"Modified","aria-label":"Modified",className:"text-[#fb923c]"});case"renamed":return g.jsx(F,{name:"Renamed","aria-label":"Renamed",className:"text-[#fb923c]"});case"added":return g.jsx(F,{name:"Added","aria-label":"Added",className:"text-[#10b981]"});case"deleted":return g.jsx(F,{name:"Deleted","aria-label":"Deleted",className:"text-[#ef4444]"});default:return g.jsx(F,{name:"Modified","aria-label":"Modified",className:"text-[#fb923c]"})}},l=()=>{switch(t){case"changed":return"modified";default:return t}},a=e.replace(/\\\\/g,"\\");return g.jsxs(Bn,{value:e,children:[g.jsxs(Mr,{variant:l(),children:[o||s()," ",a]}),g.jsx(Or,{forceMount:c,className:ve("prose max-w-none whitespace-pre-wrap dark:prose-invert prose-pre:m-0 prose-pre:mb-1 prose-pre:rounded-none",{"radix-state-closed:hidden":c}),children:n})]})},Mr=r.forwardRef(({children:e,className:n,variant:t,...o},c)=>g.jsx(Hn,{className:"flex",asChild:!0,children:g.jsxs(Wn,{className:ve("group flex w-full items-center justify-between border-b p-4 pr-3 font-mono text-sm font-medium leading-none hover:bg-foreground/20",n),...o,ref:c,children:[g.jsx("div",{className:"flex items-center gap-1.5",children:e}),g.jsxs("div",{className:"flex items-center gap-2",children:[g.jsx("span",{className:"font-mono text-xs font-normal uppercase text-muted-foreground",children:t}),g.jsx(F,{name:"TriangleDownSmall",className:"transition group-radix-state-open:rotate-180","aria-hidden":!0})]})]})})),Or=r.forwardRef(({children:e,className:n,...t},o)=>g.jsx(Kn,{className:ve("",n),...t,ref:o,children:g.jsx("div",{children:e})})),kr=e=>g.jsx("pre",{...e}),Dr={Accordion:Nr,pre:kr};function Yr({diff:e,allApps:n}){const t=rn(),[o]=cn(),c=new URLSearchParams(o);c.set("forceFresh","diff");const s=Xt(),l=dn.useSpinDelay(s.state!=="idle",{delay:0,minDuration:1e3}),a=[];for(const[d,u]of o.entries())d==="app1"||d==="app2"||a.push(g.jsx("input",{type:"hidden",name:d,value:u},d));return g.jsx(r.Suspense,{fallback:g.jsx("div",{className:"flex items-center justify-center p-8",children:g.jsx(ot,{content:"Loading diff",children:g.jsx(F,{name:"Refresh",className:"animate-spin"})})}),children:g.jsx(an,{resolve:e,errorElement:g.jsx("p",{className:"p-6 text-foreground-danger",children:"There was an error calculating the diff. Sorry."}),children:d=>g.jsxs("div",{className:"flex h-full w-full flex-col",children:[g.jsxs("div",{className:"flex h-14 min-h-14 w-full overflow-x-hidden border-b",children:[g.jsx("div",{className:"border-r",children:g.jsx(ot,{content:"Reload diff",children:g.jsx(sn,{to:`.?${c}`,className:"flex h-full w-14 items-center justify-center",children:g.jsx(F,{name:"Refresh",className:un({"animate-spin":l})})})})}),g.jsxs(ln,{onChange:u=>t(u.currentTarget),className:"flex h-full flex-1 items-center overflow-x-auto scrollbar-thin scrollbar-thumb-scrollbar",children:[a,g.jsx(xt,{name:"app1",label:"App 1",className:"border-r",allApps:n,defaultValue:d.app1}),g.jsx(xt,{name:"app2",label:"App 2",allApps:n,defaultValue:d.app2})]},`${d.app1}${d.app2}`)]}),g.jsx("div",{className:"flex-grow overflow-y-scroll scrollbar-thin scrollbar-thumb-scrollbar",children:d.diffCode?g.jsx("div",{children:g.jsx(Fn,{className:"w-full",type:"multiple",children:g.jsx(fn,{code:d.diffCode,components:Dr})})}):d.app1&&d.app2?g.jsx("p",{className:"m-5 inline-flex items-center justify-center bg-foreground px-1 py-0.5 font-mono text-sm uppercase text-background",children:"There was a problem generating the diff"}):g.jsx("p",{className:"m-5 inline-flex items-center justify-center bg-foreground px-1 py-0.5 font-mono text-sm uppercase text-background",children:"Select two apps to compare"})})]})})})}function xt({name:e,label:n,className:t,allApps:o,defaultValue:c}){return g.jsxs($r,{name:e,defaultValue:c,children:[g.jsxs(gr,{className:ve("flex h-full w-full max-w-[50%] items-center justify-between px-3 text-left radix-placeholder:text-gray-500 focus-visible:outline-none",t),"aria-label":`Select ${n} for git Diff`,children:[g.jsxs("span",{className:"overflow-hidden text-ellipsis whitespace-nowrap",children:[n,": "," ",g.jsx(jr,{placeholder:`Select ${n}`,className:"inline-block w-40 text-ellipsis"})]}),g.jsx(wr,{className:"",children:g.jsx(F,{name:"TriangleDownSmall"})})]}),g.jsx(Sr,{children:g.jsxs(Cr,{position:"popper",align:"start",className:"z-20 max-h-[50vh] bg-black text-white lg:max-h-[70vh]",children:[g.jsx(Pr,{className:"flex h-5 cursor-default items-center justify-center ",children:g.jsx(F,{name:"ChevronUp"})}),g.jsx(Er,{className:"p-3",children:g.jsxs(yr,{children:[g.jsx(Ir,{className:"px-5 pb-3 font-mono uppercase",children:n}),o.map(s=>g.jsx(Lr,{value:s.name,children:s.displayName},s.name))]})}),g.jsx(Ar,{className:"flex h-5 cursor-default items-center justify-center ",children:g.jsx(F,{name:"ChevronDown"})})]})})]})}const Lr=S.forwardRef(({children:e,className:n,...t},o)=>g.jsxs(Rr,{className:ve("relative flex cursor-pointer select-none items-center rounded px-10 py-2 leading-none opacity-80 radix-disabled:text-red-500 radix-highlighted:opacity-100 radix-highlighted:outline-none radix-state-checked:opacity-100",n),...t,ref:o,children:[g.jsx(_r,{children:e}),g.jsx(Tr,{className:"absolute left-0 inline-flex w-[25px] items-center justify-center",children:g.jsx(F,{name:"CheckSmall"})})]})),jr=S.forwardRef(({children:e,className:n,...t},o)=>g.jsx(xr,{...t,ref:o,children:t.value}));export{Ct as $,Nr as A,Yr as D,Ht as R,Et as a,$r as b,gr as c,xr as d,wr as e,Sr as f,Cr as g,Pr as h,Er as i,yr as j,Ir as k,Ar as l,Rr as m,_r as n,Tr as o,Fn as p,pn as q,oo as r,Un as s,Gn as t};
|
|
42
|
-
//# sourceMappingURL=diff-
|
|
41
|
+
`)},Lo=0,le=[];function jo(e){var n=r.useRef([]),t=r.useRef([0,0]),o=r.useRef(),c=r.useState(Lo++)[0],s=r.useState(function(){return jt()})[0],l=r.useRef(e);r.useEffect(function(){l.current=e},[e]),r.useEffect(function(){if(e.inert){document.body.classList.add("block-interactivity-".concat(c));var i=ro([e.lockRef.current],(e.shards||[]).map(vt),!0).filter(Boolean);return i.forEach(function(m){return m.classList.add("allow-interactivity-".concat(c))}),function(){document.body.classList.remove("block-interactivity-".concat(c)),i.forEach(function(m){return m.classList.remove("allow-interactivity-".concat(c))})}}},[e.inert,e.lockRef.current,e.shards]);var a=r.useCallback(function(i,m){if("touches"in i&&i.touches.length===2)return!l.current.allowPinchZoom;var p=we(i),f=t.current,b="deltaX"in i?i.deltaX:f[0]-p[0],E="deltaY"in i?i.deltaY:f[1]-p[1],y,j=i.target,T=Math.abs(b)>Math.abs(E)?"h":"v";if("touches"in i&&T==="h"&&j.type==="range")return!1;var N=pt(T,j);if(!N)return!0;if(N?y=T:(y=T==="v"?"h":"v",N=pt(T,j)),!N)return!1;if(!o.current&&"changedTouches"in i&&(b||E)&&(o.current=y),!y)return!0;var L=o.current||y;return Oo(L,m,i,L==="h"?b:E,!0)},[]),d=r.useCallback(function(i){var m=i;if(!(!le.length||le[le.length-1]!==s)){var p="deltaY"in m?mt(m):we(m),f=n.current.filter(function(y){return y.name===m.type&&y.target===m.target&&ko(y.delta,p)})[0];if(f&&f.should){m.cancelable&&m.preventDefault();return}if(!f){var b=(l.current.shards||[]).map(vt).filter(Boolean).filter(function(y){return y.contains(m.target)}),E=b.length>0?a(m,b[0]):!l.current.noIsolation;E&&m.cancelable&&m.preventDefault()}}},[]),u=r.useCallback(function(i,m,p,f){var b={name:i,delta:m,target:p,should:f};n.current.push(b),setTimeout(function(){n.current=n.current.filter(function(E){return E!==b})},1)},[]),v=r.useCallback(function(i){t.current=we(i),o.current=void 0},[]),$=r.useCallback(function(i){u(i.type,mt(i),i.target,a(i,e.lockRef.current))},[]),w=r.useCallback(function(i){u(i.type,we(i),i.target,a(i,e.lockRef.current))},[]);r.useEffect(function(){return le.push(s),e.setCallbacks({onScrollCapture:$,onWheelCapture:$,onTouchMoveCapture:w}),document.addEventListener("wheel",d,se),document.addEventListener("touchmove",d,se),document.addEventListener("touchstart",v,se),function(){le=le.filter(function(i){return i!==s}),document.removeEventListener("wheel",d,se),document.removeEventListener("touchmove",d,se),document.removeEventListener("touchstart",v,se)}},[]);var x=e.removeScrollBar,h=e.inert;return r.createElement(r.Fragment,null,h?r.createElement(s,{styles:Do(c)}):null,x?r.createElement(Ro,{gapMode:"margin"}):null)}const Vo=mo(Lt,jo);var Ht=r.forwardRef(function(e,n){return r.createElement(_e,G({},e,{ref:n,sideCar:Vo}))});Ht.classNames=_e.classNames;const Fo=[" ","Enter","ArrowUp","ArrowDown"],Bo=[" ","Enter"],Te="Select",[Pe,Ae,Ho]=Ct(Te),[ue,Gr]=ye(Te,[Ho,wt]),tt=wt(),[Wo,ne]=ue(Te),[Ko,Uo]=ue(Te),Go=e=>{const{__scopeSelect:n,children:t,open:o,defaultOpen:c,onOpenChange:s,value:l,defaultValue:a,onValueChange:d,dir:u,name:v,autoComplete:$,disabled:w,required:x}=e,h=tt(n),[i,m]=r.useState(null),[p,f]=r.useState(null),[b,E]=r.useState(!1),y=Et(u),[j=!1,T]=pe({prop:o,defaultProp:c,onChange:s}),[N,L]=pe({prop:l,defaultProp:a,onChange:d}),W=r.useRef(null),te=i?!!i.closest("form"):!0,[K,X]=r.useState(new Set),Z=Array.from(K).map(k=>k.props.value).join(";");return r.createElement(Qt,h,r.createElement(Wo,{required:x,scope:n,trigger:i,onTriggerChange:m,valueNode:p,onValueNodeChange:f,valueNodeHasChildren:b,onValueNodeHasChildrenChange:E,contentId:me(),value:N,onValueChange:L,open:j,onOpenChange:T,dir:y,triggerPointerDownPosRef:W,disabled:w},r.createElement(Pe.Provider,{scope:n},r.createElement(Ko,{scope:e.__scopeSelect,onNativeOptionAdd:r.useCallback(k=>{X(U=>new Set(U).add(k))},[]),onNativeOptionRemove:r.useCallback(k=>{X(U=>{const Y=new Set(U);return Y.delete(k),Y})},[])},t)),te?r.createElement(Yt,{key:Z,"aria-hidden":!0,required:x,tabIndex:-1,name:v,autoComplete:$,value:N,onChange:k=>L(k.target.value),disabled:w},N===void 0?r.createElement("option",{value:""}):null,Array.from(K)):null))},Yo="SelectTrigger",zo=r.forwardRef((e,n)=>{const{__scopeSelect:t,disabled:o=!1,...c}=e,s=tt(t),l=ne(Yo,t),a=l.disabled||o,d=D(n,l.onTriggerChange),u=Ae(t),[v,$,w]=zt(h=>{const i=u().filter(f=>!f.disabled),m=i.find(f=>f.value===l.value),p=qt(i,h,m);p!==void 0&&l.onValueChange(p.value)}),x=()=>{a||(l.onOpenChange(!0),w())};return r.createElement(Jt,I({asChild:!0},s),r.createElement(M.button,I({type:"button",role:"combobox","aria-controls":l.contentId,"aria-expanded":l.open,"aria-required":l.required,"aria-autocomplete":"none",dir:l.dir,"data-state":l.open?"open":"closed",disabled:a,"data-disabled":a?"":void 0,"data-placeholder":Gt(l.value)?"":void 0},c,{ref:d,onClick:O(c.onClick,h=>{h.currentTarget.focus()}),onPointerDown:O(c.onPointerDown,h=>{const i=h.target;i.hasPointerCapture(h.pointerId)&&i.releasePointerCapture(h.pointerId),h.button===0&&h.ctrlKey===!1&&(x(),l.triggerPointerDownPosRef.current={x:Math.round(h.pageX),y:Math.round(h.pageY)},h.preventDefault())}),onKeyDown:O(c.onKeyDown,h=>{const i=v.current!=="";!(h.ctrlKey||h.altKey||h.metaKey)&&h.key.length===1&&$(h.key),!(i&&h.key===" ")&&Fo.includes(h.key)&&(x(),h.preventDefault())})})))}),qo="SelectValue",Xo=r.forwardRef((e,n)=>{const{__scopeSelect:t,className:o,style:c,children:s,placeholder:l="",...a}=e,d=ne(qo,t),{onValueNodeHasChildrenChange:u}=d,v=s!==void 0,$=D(n,d.onValueNodeChange);return q(()=>{u(v)},[u,v]),r.createElement(M.span,I({},a,{ref:$,style:{pointerEvents:"none"}}),Gt(d.value)?r.createElement(r.Fragment,null,l):s)}),Zo=r.forwardRef((e,n)=>{const{__scopeSelect:t,children:o,...c}=e;return r.createElement(M.span,I({"aria-hidden":!0},c,{ref:n}),o||"▼")}),Qo=e=>r.createElement(pn,I({asChild:!0},e)),de="SelectContent",Jo=r.forwardRef((e,n)=>{const t=ne(de,e.__scopeSelect),[o,c]=r.useState();if(q(()=>{c(new DocumentFragment)},[]),!t.open){const s=o;return s?St.createPortal(r.createElement(Wt,{scope:e.__scopeSelect},r.createElement(Pe.Slot,{scope:e.__scopeSelect},r.createElement("div",null,e.children))),s):null}return r.createElement(er,I({},e,{ref:n}))}),z=10,[Wt,oe]=ue(de),er=r.forwardRef((e,n)=>{const{__scopeSelect:t,position:o="item-aligned",onCloseAutoFocus:c,onEscapeKeyDown:s,onPointerDownOutside:l,side:a,sideOffset:d,align:u,alignOffset:v,arrowPadding:$,collisionBoundary:w,collisionPadding:x,sticky:h,hideWhenDetached:i,avoidCollisions:m,...p}=e,f=ne(de,t),[b,E]=r.useState(null),[y,j]=r.useState(null),T=D(n,C=>E(C)),[N,L]=r.useState(null),[W,te]=r.useState(null),K=Ae(t),[X,Z]=r.useState(!1),k=r.useRef(!1);r.useEffect(()=>{if(b)return oo(b)},[b]),Un();const U=r.useCallback(C=>{const[P,...V]=K().map(_=>_.ref.current),[A]=V.slice(-1),R=document.activeElement;for(const _ of C)if(_===R||(_==null||_.scrollIntoView({block:"nearest"}),_===P&&y&&(y.scrollTop=0),_===A&&y&&(y.scrollTop=y.scrollHeight),_==null||_.focus(),document.activeElement!==R))return},[K,y]),Y=r.useCallback(()=>U([N,b]),[U,N,b]);r.useEffect(()=>{X&&Y()},[X,Y]);const{onOpenChange:re,triggerPointerDownPosRef:Q}=f;r.useEffect(()=>{if(b){let C={x:0,y:0};const P=A=>{var R,_,B,H;C={x:Math.abs(Math.round(A.pageX)-((R=(_=Q.current)===null||_===void 0?void 0:_.x)!==null&&R!==void 0?R:0)),y:Math.abs(Math.round(A.pageY)-((B=(H=Q.current)===null||H===void 0?void 0:H.y)!==null&&B!==void 0?B:0))}},V=A=>{C.x<=10&&C.y<=10?A.preventDefault():b.contains(A.target)||re(!1),document.removeEventListener("pointermove",P),Q.current=null};return Q.current!==null&&(document.addEventListener("pointermove",P),document.addEventListener("pointerup",V,{capture:!0,once:!0})),()=>{document.removeEventListener("pointermove",P),document.removeEventListener("pointerup",V,{capture:!0})}}},[b,re,Q]),r.useEffect(()=>{const C=()=>re(!1);return window.addEventListener("blur",C),window.addEventListener("resize",C),()=>{window.removeEventListener("blur",C),window.removeEventListener("resize",C)}},[re]);const[Ne,he]=zt(C=>{const P=K().filter(R=>!R.disabled),V=P.find(R=>R.ref.current===document.activeElement),A=qt(P,C,V);A&&setTimeout(()=>A.ref.current.focus())}),Me=r.useCallback((C,P,V)=>{const A=!k.current&&!V;(f.value!==void 0&&f.value===P||A)&&(L(C),A&&(k.current=!0))},[f.value]),Oe=r.useCallback(()=>b==null?void 0:b.focus(),[b]),ce=r.useCallback((C,P,V)=>{const A=!k.current&&!V;(f.value!==void 0&&f.value===P||A)&&te(C)},[f.value]),be=o==="popper"?ht:tr,fe=be===ht?{side:a,sideOffset:d,align:u,alignOffset:v,arrowPadding:$,collisionBoundary:w,collisionPadding:x,sticky:h,hideWhenDetached:i,avoidCollisions:m}:{};return r.createElement(Wt,{scope:t,content:b,viewport:y,onViewportChange:j,itemRefCallback:Me,selectedItem:N,onItemLeave:Oe,itemTextRefCallback:ce,focusSelectedItem:Y,selectedItemText:W,position:o,isPositioned:X,searchRef:Ne},r.createElement(Ht,{as:Ue,allowPinchZoom:!0},r.createElement(Gn,{asChild:!0,trapped:f.open,onMountAutoFocus:C=>{C.preventDefault()},onUnmountAutoFocus:O(c,C=>{var P;(P=f.trigger)===null||P===void 0||P.focus({preventScroll:!0}),C.preventDefault()})},r.createElement(en,{asChild:!0,disableOutsidePointerEvents:!0,onEscapeKeyDown:s,onPointerDownOutside:l,onFocusOutside:C=>C.preventDefault(),onDismiss:()=>f.onOpenChange(!1)},r.createElement(be,I({role:"listbox",id:f.contentId,"data-state":f.open?"open":"closed",dir:f.dir,onContextMenu:C=>C.preventDefault()},p,fe,{onPlaced:()=>Z(!0),ref:T,style:{display:"flex",flexDirection:"column",outline:"none",...p.style},onKeyDown:O(p.onKeyDown,C=>{const P=C.ctrlKey||C.altKey||C.metaKey;if(C.key==="Tab"&&C.preventDefault(),!P&&C.key.length===1&&he(C.key),["ArrowUp","ArrowDown","Home","End"].includes(C.key)){let A=K().filter(R=>!R.disabled).map(R=>R.ref.current);if(["ArrowUp","End"].includes(C.key)&&(A=A.slice().reverse()),["ArrowUp","ArrowDown"].includes(C.key)){const R=C.target,_=A.indexOf(R);A=A.slice(_+1)}setTimeout(()=>U(A)),C.preventDefault()}})}))))))}),tr=r.forwardRef((e,n)=>{const{__scopeSelect:t,onPlaced:o,...c}=e,s=ne(de,t),l=oe(de,t),[a,d]=r.useState(null),[u,v]=r.useState(null),$=D(n,T=>v(T)),w=Ae(t),x=r.useRef(!1),h=r.useRef(!0),{viewport:i,selectedItem:m,selectedItemText:p,focusSelectedItem:f}=l,b=r.useCallback(()=>{if(s.trigger&&s.valueNode&&a&&u&&i&&m&&p){const T=s.trigger.getBoundingClientRect(),N=u.getBoundingClientRect(),L=s.valueNode.getBoundingClientRect(),W=p.getBoundingClientRect();if(s.dir!=="rtl"){const R=W.left-N.left,_=L.left-R,B=T.left-_,H=T.width+B,ke=Math.max(H,N.width),De=window.innerWidth-z,Le=ct(_,[z,De-ke]);a.style.minWidth=H+"px",a.style.left=Le+"px"}else{const R=N.right-W.right,_=window.innerWidth-L.right-R,B=window.innerWidth-T.right-_,H=T.width+B,ke=Math.max(H,N.width),De=window.innerWidth-z,Le=ct(_,[z,De-ke]);a.style.minWidth=H+"px",a.style.right=Le+"px"}const te=w(),K=window.innerHeight-z*2,X=i.scrollHeight,Z=window.getComputedStyle(u),k=parseInt(Z.borderTopWidth,10),U=parseInt(Z.paddingTop,10),Y=parseInt(Z.borderBottomWidth,10),re=parseInt(Z.paddingBottom,10),Q=k+U+X+re+Y,Ne=Math.min(m.offsetHeight*5,Q),he=window.getComputedStyle(i),Me=parseInt(he.paddingTop,10),Oe=parseInt(he.paddingBottom,10),ce=T.top+T.height/2-z,be=K-ce,fe=m.offsetHeight/2,C=m.offsetTop+fe,P=k+U+C,V=Q-P;if(P<=ce){const R=m===te[te.length-1].ref.current;a.style.bottom="0px";const _=u.clientHeight-i.offsetTop-i.offsetHeight,B=Math.max(be,fe+(R?Oe:0)+_+Y),H=P+B;a.style.height=H+"px"}else{const R=m===te[0].ref.current;a.style.top="0px";const B=Math.max(ce,k+i.offsetTop+(R?Me:0)+fe)+V;a.style.height=B+"px",i.scrollTop=P-ce+i.offsetTop}a.style.margin=`${z}px 0`,a.style.minHeight=Ne+"px",a.style.maxHeight=K+"px",o==null||o(),requestAnimationFrame(()=>x.current=!0)}},[w,s.trigger,s.valueNode,a,u,i,m,p,s.dir,o]);q(()=>b(),[b]);const[E,y]=r.useState();q(()=>{u&&y(window.getComputedStyle(u).zIndex)},[u]);const j=r.useCallback(T=>{T&&h.current===!0&&(b(),f==null||f(),h.current=!1)},[b,f]);return r.createElement(nr,{scope:t,contentWrapper:a,shouldExpandOnScrollRef:x,onScrollButtonChange:j},r.createElement("div",{ref:d,style:{display:"flex",flexDirection:"column",position:"fixed",zIndex:E}},r.createElement(M.div,I({},c,{ref:$,style:{boxSizing:"border-box",maxHeight:"100%",...c.style}}))))}),ht=r.forwardRef((e,n)=>{const{__scopeSelect:t,align:o="start",collisionPadding:c=z,...s}=e,l=tt(t);return r.createElement(nn,I({},l,s,{ref:n,align:o,collisionPadding:c,style:{boxSizing:"border-box",...s.style,"--radix-select-content-transform-origin":"var(--radix-popper-transform-origin)","--radix-select-content-available-width":"var(--radix-popper-available-width)","--radix-select-content-available-height":"var(--radix-popper-available-height)","--radix-select-trigger-width":"var(--radix-popper-anchor-width)","--radix-select-trigger-height":"var(--radix-popper-anchor-height)"}}))}),[nr,nt]=ue(de,{}),bt="SelectViewport",or=r.forwardRef((e,n)=>{const{__scopeSelect:t,...o}=e,c=oe(bt,t),s=nt(bt,t),l=D(n,c.onViewportChange),a=r.useRef(0);return r.createElement(r.Fragment,null,r.createElement("style",{dangerouslySetInnerHTML:{__html:"[data-radix-select-viewport]{scrollbar-width:none;-ms-overflow-style:none;-webkit-overflow-scrolling:touch;}[data-radix-select-viewport]::-webkit-scrollbar{display:none}"}}),r.createElement(Pe.Slot,{scope:t},r.createElement(M.div,I({"data-radix-select-viewport":"",role:"presentation"},o,{ref:l,style:{position:"relative",flex:1,overflow:"auto",...o.style},onScroll:O(o.onScroll,d=>{const u=d.currentTarget,{contentWrapper:v,shouldExpandOnScrollRef:$}=s;if($!=null&&$.current&&v){const w=Math.abs(a.current-u.scrollTop);if(w>0){const x=window.innerHeight-z*2,h=parseFloat(v.style.minHeight),i=parseFloat(v.style.height),m=Math.max(h,i);if(m<x){const p=m+w,f=Math.min(x,p),b=p-f;v.style.height=f+"px",v.style.bottom==="0px"&&(u.scrollTop=b>0?b:0,v.style.justifyContent="flex-end")}}}a.current=u.scrollTop})}))))}),rr="SelectGroup",[cr,ar]=ue(rr),sr=r.forwardRef((e,n)=>{const{__scopeSelect:t,...o}=e,c=me();return r.createElement(cr,{scope:t,id:c},r.createElement(M.div,I({role:"group","aria-labelledby":c},o,{ref:n})))}),lr="SelectLabel",ir=r.forwardRef((e,n)=>{const{__scopeSelect:t,...o}=e,c=ar(lr,t);return r.createElement(M.div,I({id:c.id},o,{ref:n}))}),qe="SelectItem",[dr,Kt]=ue(qe),ur=r.forwardRef((e,n)=>{const{__scopeSelect:t,value:o,disabled:c=!1,textValue:s,...l}=e,a=ne(qe,t),d=oe(qe,t),u=a.value===o,[v,$]=r.useState(s??""),[w,x]=r.useState(!1),h=D(n,p=>{var f;return(f=d.itemRefCallback)===null||f===void 0?void 0:f.call(d,p,o,c)}),i=me(),m=()=>{c||(a.onValueChange(o),a.onOpenChange(!1))};if(o==="")throw new Error("A <Select.Item /> must have a value prop that is not an empty string. This is because the Select value can be set to an empty string to clear the selection and show the placeholder.");return r.createElement(dr,{scope:t,value:o,disabled:c,textId:i,isSelected:u,onItemTextChange:r.useCallback(p=>{$(f=>{var b;return f||((b=p==null?void 0:p.textContent)!==null&&b!==void 0?b:"").trim()})},[])},r.createElement(Pe.ItemSlot,{scope:t,value:o,disabled:c,textValue:v},r.createElement(M.div,I({role:"option","aria-labelledby":i,"data-highlighted":w?"":void 0,"aria-selected":u&&w,"data-state":u?"checked":"unchecked","aria-disabled":c||void 0,"data-disabled":c?"":void 0,tabIndex:c?void 0:-1},l,{ref:h,onFocus:O(l.onFocus,()=>x(!0)),onBlur:O(l.onBlur,()=>x(!1)),onPointerUp:O(l.onPointerUp,m),onPointerMove:O(l.onPointerMove,p=>{if(c){var f;(f=d.onItemLeave)===null||f===void 0||f.call(d)}else p.currentTarget.focus({preventScroll:!0})}),onPointerLeave:O(l.onPointerLeave,p=>{if(p.currentTarget===document.activeElement){var f;(f=d.onItemLeave)===null||f===void 0||f.call(d)}}),onKeyDown:O(l.onKeyDown,p=>{var f;((f=d.searchRef)===null||f===void 0?void 0:f.current)!==""&&p.key===" "||(Bo.includes(p.key)&&m(),p.key===" "&&p.preventDefault())})}))))}),Se="SelectItemText",fr=r.forwardRef((e,n)=>{const{__scopeSelect:t,className:o,style:c,...s}=e,l=ne(Se,t),a=oe(Se,t),d=Kt(Se,t),u=Uo(Se,t),[v,$]=r.useState(null),w=D(n,p=>$(p),d.onItemTextChange,p=>{var f;return(f=a.itemTextRefCallback)===null||f===void 0?void 0:f.call(a,p,d.value,d.disabled)}),x=v==null?void 0:v.textContent,h=r.useMemo(()=>r.createElement("option",{key:d.value,value:d.value,disabled:d.disabled},x),[d.disabled,d.value,x]),{onNativeOptionAdd:i,onNativeOptionRemove:m}=u;return q(()=>(i(h),()=>m(h)),[i,m,h]),r.createElement(r.Fragment,null,r.createElement(M.span,I({id:d.textId},s,{ref:w})),d.isSelected&&l.valueNode&&!l.valueNodeHasChildren?St.createPortal(s.children,l.valueNode):null)}),pr="SelectItemIndicator",mr=r.forwardRef((e,n)=>{const{__scopeSelect:t,...o}=e;return Kt(pr,t).isSelected?r.createElement(M.span,I({"aria-hidden":!0},o,{ref:n})):null}),$t="SelectScrollUpButton",vr=r.forwardRef((e,n)=>{const t=oe($t,e.__scopeSelect),o=nt($t,e.__scopeSelect),[c,s]=r.useState(!1),l=D(n,o.onScrollButtonChange);return q(()=>{if(t.viewport&&t.isPositioned){let d=function(){const u=a.scrollTop>0;s(u)};const a=t.viewport;return d(),a.addEventListener("scroll",d),()=>a.removeEventListener("scroll",d)}},[t.viewport,t.isPositioned]),c?r.createElement(Ut,I({},e,{ref:l,onAutoScroll:()=>{const{viewport:a,selectedItem:d}=t;a&&d&&(a.scrollTop=a.scrollTop-d.offsetHeight)}})):null}),gt="SelectScrollDownButton",hr=r.forwardRef((e,n)=>{const t=oe(gt,e.__scopeSelect),o=nt(gt,e.__scopeSelect),[c,s]=r.useState(!1),l=D(n,o.onScrollButtonChange);return q(()=>{if(t.viewport&&t.isPositioned){let d=function(){const u=a.scrollHeight-a.clientHeight,v=Math.ceil(a.scrollTop)<u;s(v)};const a=t.viewport;return d(),a.addEventListener("scroll",d),()=>a.removeEventListener("scroll",d)}},[t.viewport,t.isPositioned]),c?r.createElement(Ut,I({},e,{ref:l,onAutoScroll:()=>{const{viewport:a,selectedItem:d}=t;a&&d&&(a.scrollTop=a.scrollTop+d.offsetHeight)}})):null}),Ut=r.forwardRef((e,n)=>{const{__scopeSelect:t,onAutoScroll:o,...c}=e,s=oe("SelectScrollButton",t),l=r.useRef(null),a=Ae(t),d=r.useCallback(()=>{l.current!==null&&(window.clearInterval(l.current),l.current=null)},[]);return r.useEffect(()=>()=>d(),[d]),q(()=>{var u;const v=a().find($=>$.ref.current===document.activeElement);v==null||(u=v.ref.current)===null||u===void 0||u.scrollIntoView({block:"nearest"})},[a]),r.createElement(M.div,I({"aria-hidden":!0},c,{ref:n,style:{flexShrink:0,...c.style},onPointerDown:O(c.onPointerDown,()=>{l.current===null&&(l.current=window.setInterval(o,50))}),onPointerMove:O(c.onPointerMove,()=>{var u;(u=s.onItemLeave)===null||u===void 0||u.call(s),l.current===null&&(l.current=window.setInterval(o,50))}),onPointerLeave:O(c.onPointerLeave,()=>{d()})}))});function Gt(e){return e===""||e===void 0}const Yt=r.forwardRef((e,n)=>{const{value:t,...o}=e,c=r.useRef(null),s=D(n,c),l=Jn(t);return r.useEffect(()=>{const a=c.current,d=window.HTMLSelectElement.prototype,v=Object.getOwnPropertyDescriptor(d,"value").set;if(l!==t&&v){const $=new Event("change",{bubbles:!0});v.call(a,t),a.dispatchEvent($)}},[l,t]),r.createElement(tn,{asChild:!0},r.createElement("select",I({},o,{ref:s,defaultValue:t})))});Yt.displayName="BubbleSelect";function zt(e){const n=Ge(e),t=r.useRef(""),o=r.useRef(0),c=r.useCallback(l=>{const a=t.current+l;n(a),function d(u){t.current=u,window.clearTimeout(o.current),u!==""&&(o.current=window.setTimeout(()=>d(""),1e3))}(a)},[n]),s=r.useCallback(()=>{t.current="",window.clearTimeout(o.current)},[]);return r.useEffect(()=>()=>window.clearTimeout(o.current),[]),[t,c,s]}function qt(e,n,t){const c=n.length>1&&Array.from(n).every(u=>u===n[0])?n[0]:n,s=t?e.indexOf(t):-1;let l=br(e,Math.max(s,0));c.length===1&&(l=l.filter(u=>u!==t));const d=l.find(u=>u.textValue.toLowerCase().startsWith(c.toLowerCase()));return d!==t?d:void 0}function br(e,n){return e.map((t,o)=>e[(n+o)%e.length])}const $r=Go,gr=zo,xr=Xo,wr=Zo,Sr=Qo,Cr=Jo,Er=or,yr=sr,Ir=ir,Rr=ur,_r=fr,Tr=mr,Pr=vr,Ar=hr,Nr=({title:e,children:n,variant:t,icon:o,forceMount:c=!1})=>{const s=()=>{switch(t){case"changed":return g.jsx(F,{name:"Modified","aria-label":"Modified",className:"text-[#fb923c]"});case"renamed":return g.jsx(F,{name:"Renamed","aria-label":"Renamed",className:"text-[#fb923c]"});case"added":return g.jsx(F,{name:"Added","aria-label":"Added",className:"text-[#10b981]"});case"deleted":return g.jsx(F,{name:"Deleted","aria-label":"Deleted",className:"text-[#ef4444]"});default:return g.jsx(F,{name:"Modified","aria-label":"Modified",className:"text-[#fb923c]"})}},l=()=>{switch(t){case"changed":return"modified";default:return t}},a=e.replace(/\\\\/g,"\\");return g.jsxs(Bn,{value:e,children:[g.jsxs(Mr,{variant:l(),children:[o||s()," ",a]}),g.jsx(Or,{forceMount:c,className:ve("prose max-w-none whitespace-pre-wrap dark:prose-invert prose-pre:m-0 prose-pre:mb-1 prose-pre:rounded-none",{"radix-state-closed:hidden":c}),children:n})]})},Mr=r.forwardRef(({children:e,className:n,variant:t,...o},c)=>g.jsx(Hn,{className:"flex",asChild:!0,children:g.jsxs(Wn,{className:ve("group flex w-full items-center justify-between border-b p-4 pr-3 font-mono text-sm font-medium leading-none hover:bg-foreground/20",n),...o,ref:c,children:[g.jsx("div",{className:"flex items-center gap-1.5",children:e}),g.jsxs("div",{className:"flex items-center gap-2",children:[g.jsx("span",{className:"font-mono text-xs font-normal uppercase text-muted-foreground",children:t}),g.jsx(F,{name:"TriangleDownSmall",className:"transition group-radix-state-open:rotate-180","aria-hidden":!0})]})]})})),Or=r.forwardRef(({children:e,className:n,...t},o)=>g.jsx(Kn,{className:ve("",n),...t,ref:o,children:g.jsx("div",{children:e})})),kr=e=>g.jsx("pre",{...e}),Dr={Accordion:Nr,pre:kr};function Yr({diff:e,allApps:n}){const t=rn(),[o]=cn(),c=new URLSearchParams(o);c.set("forceFresh","diff");const s=Xt(),l=dn.useSpinDelay(s.state!=="idle",{delay:0,minDuration:1e3}),a=[];for(const[d,u]of o.entries())d==="app1"||d==="app2"||a.push(g.jsx("input",{type:"hidden",name:d,value:u},d));return g.jsx(r.Suspense,{fallback:g.jsx("div",{className:"flex items-center justify-center p-8",children:g.jsx(ot,{content:"Loading diff",children:g.jsx(F,{name:"Refresh",className:"animate-spin"})})}),children:g.jsx(an,{resolve:e,errorElement:g.jsx("p",{className:"p-6 text-foreground-danger",children:"There was an error calculating the diff. Sorry."}),children:d=>g.jsxs("div",{className:"flex h-full w-full flex-col",children:[g.jsxs("div",{className:"flex h-14 min-h-14 w-full overflow-x-hidden border-b",children:[g.jsx("div",{className:"border-r",children:g.jsx(ot,{content:"Reload diff",children:g.jsx(sn,{to:`.?${c}`,className:"flex h-full w-14 items-center justify-center",children:g.jsx(F,{name:"Refresh",className:un({"animate-spin":l})})})})}),g.jsxs(ln,{onChange:u=>t(u.currentTarget),className:"flex h-full flex-1 items-center overflow-x-auto scrollbar-thin scrollbar-thumb-scrollbar",children:[a,g.jsx(xt,{name:"app1",label:"App 1",className:"border-r",allApps:n,defaultValue:d.app1}),g.jsx(xt,{name:"app2",label:"App 2",allApps:n,defaultValue:d.app2})]},`${d.app1}${d.app2}`)]}),g.jsx("div",{className:"flex-grow overflow-y-scroll scrollbar-thin scrollbar-thumb-scrollbar",children:d.diffCode?g.jsx("div",{children:g.jsx(Fn,{className:"w-full",type:"multiple",children:g.jsx(fn,{code:d.diffCode,components:Dr})})}):d.app1&&d.app2?g.jsx("p",{className:"m-5 inline-flex items-center justify-center bg-foreground px-1 py-0.5 font-mono text-sm uppercase text-background",children:"There was a problem generating the diff"}):g.jsx("p",{className:"m-5 inline-flex items-center justify-center bg-foreground px-1 py-0.5 font-mono text-sm uppercase text-background",children:"Select two apps to compare"})})]})})})}function xt({name:e,label:n,className:t,allApps:o,defaultValue:c}){return g.jsxs($r,{name:e,defaultValue:c,children:[g.jsxs(gr,{className:ve("flex h-full w-full max-w-[50%] items-center justify-between px-3 text-left radix-placeholder:text-gray-500 focus-visible:outline-none",t),"aria-label":`Select ${n} for git Diff`,children:[g.jsxs("span",{className:"overflow-hidden text-ellipsis whitespace-nowrap",children:[n,":"," ",g.jsx(jr,{placeholder:`Select ${n}`,className:"inline-block w-40 text-ellipsis"})]}),g.jsx(wr,{className:"",children:g.jsx(F,{name:"TriangleDownSmall"})})]}),g.jsx(Sr,{children:g.jsxs(Cr,{position:"popper",align:"start",className:"z-20 max-h-[50vh] bg-black text-white lg:max-h-[70vh]",children:[g.jsx(Pr,{className:"flex h-5 cursor-default items-center justify-center ",children:g.jsx(F,{name:"ChevronUp"})}),g.jsx(Er,{className:"p-3",children:g.jsxs(yr,{children:[g.jsx(Ir,{className:"px-5 pb-3 font-mono uppercase",children:n}),o.map(s=>g.jsx(Lr,{value:s.name,children:s.displayName},s.name))]})}),g.jsx(Ar,{className:"flex h-5 cursor-default items-center justify-center ",children:g.jsx(F,{name:"ChevronDown"})})]})})]})}const Lr=S.forwardRef(({children:e,className:n,...t},o)=>g.jsxs(Rr,{className:ve("relative flex cursor-pointer select-none items-center rounded px-10 py-2 leading-none opacity-80 radix-disabled:text-red-500 radix-highlighted:opacity-100 radix-highlighted:outline-none radix-state-checked:opacity-100",n),...t,ref:o,children:[g.jsx(_r,{children:e}),g.jsx(Tr,{className:"absolute left-0 inline-flex w-[25px] items-center justify-center",children:g.jsx(F,{name:"CheckSmall"})})]})),jr=S.forwardRef(({children:e,className:n,...t},o)=>g.jsx(xr,{...t,ref:o,children:t.value}));export{Ct as $,Nr as A,Yr as D,Ht as R,Et as a,$r as b,gr as c,xr as d,wr as e,Sr as f,Cr as g,Pr as h,Er as i,yr as j,Ir as k,Ar as l,Rr as m,_r as n,Tr as o,Fn as p,pn as q,oo as r,Un as s,Gn as t};
|
|
42
|
+
//# sourceMappingURL=diff-BKsbFB6w.js.map
|