@epic-web/workshop-app 6.23.1 → 6.23.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (24) hide show
  1. package/build/client/assets/{_exerciseNumber-DLQcM4v6.js → _exerciseNumber-Cnmd182F.js} +2 -2
  2. package/build/client/assets/{_exerciseNumber-DLQcM4v6.js.map → _exerciseNumber-Cnmd182F.js.map} +1 -1
  3. package/build/client/assets/{_exerciseNumber_.finished-DaOTQdWd.js → _exerciseNumber_.finished-D078JW2f.js} +2 -2
  4. package/build/client/assets/{_exerciseNumber_.finished-DaOTQdWd.js.map → _exerciseNumber_.finished-D078JW2f.js.map} +1 -1
  5. package/build/client/assets/{_layout-CJr4y8eX.js → _layout-CcWrk4kg.js} +2 -2
  6. package/build/client/assets/{_layout-CJr4y8eX.js.map → _layout-CcWrk4kg.js.map} +1 -1
  7. package/build/client/assets/{diff-Dwb3EWYp.js → diff-0XgucEQg.js} +2 -2
  8. package/build/client/assets/{diff-Dwb3EWYp.js.map → diff-0XgucEQg.js.map} +1 -1
  9. package/build/client/assets/{diff-Tx3FhzEy.js → diff-C84h1q-R.js} +2 -2
  10. package/build/client/assets/{diff-Tx3FhzEy.js.map → diff-C84h1q-R.js.map} +1 -1
  11. package/build/client/assets/{finished-33U_fnqH.js → finished-CzDipjN1.js} +2 -2
  12. package/build/client/assets/{finished-33U_fnqH.js.map → finished-CzDipjN1.js.map} +1 -1
  13. package/build/client/assets/{index-Dlyr-xKB.js → index-BQT6Cv4C.js} +2 -2
  14. package/build/client/assets/{index-Dlyr-xKB.js.map → index-BQT6Cv4C.js.map} +1 -1
  15. package/build/client/assets/{index-CNnVvQvr.js → index-D13MNswH.js} +2 -2
  16. package/build/client/assets/{index-CNnVvQvr.js.map → index-D13MNswH.js.map} +1 -1
  17. package/build/client/assets/{manifest-23b26aed.js → manifest-5865a9d7.js} +1 -1
  18. package/build/client/assets/mdx-BDFRig3X.js +3 -0
  19. package/build/client/assets/mdx-BDFRig3X.js.map +1 -0
  20. package/build/server/index.js +2 -2
  21. package/build/server/index.js.map +1 -1
  22. package/package.json +3 -3
  23. package/build/client/assets/mdx-Bbi38W8y.js +0 -3
  24. package/build/client/assets/mdx-Bbi38W8y.js.map +0 -1
@@ -1 +1 @@
1
- {"version":3,"file":"_layout-CJr4y8eX.js","sources":["../../../app/routes/_app+/exercise+/$exerciseNumber_.$stepNumber.$type+/__shared/step-mdx.tsx","../../../../../node_modules/@radix-ui/react-popover/dist/index.mjs","../../../app/routes/_app+/exercise+/$exerciseNumber_.$stepNumber.$type+/__shared/touched-files.tsx","../../../app/routes/_app+/exercise+/$exerciseNumber_.$stepNumber.$type+/_layout.tsx"],"sourcesContent":["import * as React from 'react'\nimport { type PropsWithChildren } from 'react'\nimport {\n\tLink,\n\tuseLoaderData,\n\tuseSearchParams,\n\ttype LinkProps,\n} from 'react-router'\nimport iconsSvg from '#app/assets/icons.svg'\nimport { EpicVideoInfoProvider } from '#app/components/epic-video.tsx'\nimport { Icon } from '#app/components/icons.tsx'\nimport { type InBrowserBrowserRef } from '#app/components/in-browser-browser.tsx'\nimport { SimpleTooltip } from '#app/components/ui/tooltip.tsx'\nimport { LaunchEditor } from '#app/routes/launch-editor.tsx'\nimport { Mdx } from '#app/utils/mdx.tsx'\nimport { cn, getBaseUrl } from '#app/utils/misc.tsx'\nimport { useRequestInfo } from '#app/utils/request-info.ts'\nimport { type loader } from '../_layout.tsx'\n\ntype StepContextType = {\n\tinBrowserBrowserRef: React.RefObject<InBrowserBrowserRef | null>\n}\nconst StepContext = React.createContext<StepContextType | null>(null)\n\nfunction useStepContext() {\n\tconst context = React.useContext(StepContext)\n\tif (!context) {\n\t\tthrow new Error('useStepContext must be used within a StepContext.Provider')\n\t}\n\treturn context\n}\n\nfunction StepContextProvider({\n\tchildren,\n\tinBrowserBrowserRef,\n}: {\n\tchildren: React.ReactNode\n\tinBrowserBrowserRef: React.RefObject<InBrowserBrowserRef | null>\n}) {\n\treturn (\n\t\t<StepContext.Provider value={{ inBrowserBrowserRef }}>\n\t\t\t{children}\n\t\t</StepContext.Provider>\n\t)\n}\n\nconst stepMdxComponents = {\n\tDiffLink,\n\tPrevDiffLink,\n\tNextDiffLink,\n\tInlineFile,\n\tLinkToApp,\n}\n\nexport function StepMdx({\n\tinBrowserBrowserRef,\n}: {\n\tinBrowserBrowserRef: React.RefObject<InBrowserBrowserRef | null>\n}) {\n\tconst data = useLoaderData<typeof loader>()\n\tif (!data.exerciseStepApp.instructionsCode) return null\n\treturn (\n\t\t<StepContextProvider inBrowserBrowserRef={inBrowserBrowserRef}>\n\t\t\t<EpicVideoInfoProvider epicVideoInfosPromise={data.epicVideoInfosPromise}>\n\t\t\t\t<div className=\"prose dark:prose-invert sm:prose-lg\">\n\t\t\t\t\t<Mdx\n\t\t\t\t\t\tcode={data.exerciseStepApp.instructionsCode}\n\t\t\t\t\t\tcomponents={stepMdxComponents}\n\t\t\t\t\t/>\n\t\t\t\t</div>\n\t\t\t</EpicVideoInfoProvider>\n\t\t</StepContextProvider>\n\t)\n}\n\nfunction withParam(\n\tsearchParams: URLSearchParams,\n\tkey: string,\n\tvalue: string | null,\n) {\n\tconst newSearchParams = new URLSearchParams(searchParams)\n\tif (value === null) {\n\t\tnewSearchParams.delete(key)\n\t} else {\n\t\tnewSearchParams.set(key, value)\n\t}\n\treturn newSearchParams\n}\n\nfunction NextDiffLink({\n\tapp = 0,\n\tfullPage = false,\n\tchildren,\n}: {\n\tapp: number\n\tfullPage?: boolean\n\tchildren?: React.ReactNode\n}) {\n\treturn (\n\t\t<DiffLink app1={app} app2={app + 1} fullPage={fullPage}>\n\t\t\t{children}\n\t\t</DiffLink>\n\t)\n}\n\nfunction PrevDiffLink({\n\tapp = -1,\n\tfullPage = false,\n\tchildren,\n}: {\n\tapp: number\n\tfullPage?: boolean\n\tchildren?: React.ReactNode\n}) {\n\treturn (\n\t\t<DiffLink app1={app} app2={app + 1} fullPage={fullPage}>\n\t\t\t{children}\n\t\t</DiffLink>\n\t)\n}\n\nfunction DiffLink({\n\tapp1 = 0,\n\tapp2 = 1,\n\tchildren,\n\tfullPage = false,\n\tto,\n}: {\n\tapp1?: string | number | null\n\tapp2?: string | number | null\n\tto?: string\n\tfullPage?: boolean\n\tchildren?: React.ReactNode\n}) {\n\tconst data = useLoaderData<typeof loader>()\n\tif (!to && !app1 && !app2) {\n\t\treturn (\n\t\t\t// @ts-expect-error 🤷‍♂️\n\t\t\t<callout-danger className=\"notification\">\n\t\t\t\t<div className=\"title\">DiffLink Error: invalid input</div>\n\t\t\t\t{/* @ts-expect-error 🤷‍♂️ */}\n\t\t\t</callout-danger>\n\t\t)\n\t}\n\n\tfunction getAppName(input: typeof app1) {\n\t\tif (typeof input === 'number') {\n\t\t\tconst stepIndex = data.exerciseIndex + input\n\t\t\treturn data.allApps[stepIndex]?.name\n\t\t}\n\t\tif (!input) return null\n\t\tfor (const { name, stepName } of data.allApps) {\n\t\t\tif (input === name || input === stepName) {\n\t\t\t\treturn name\n\t\t\t}\n\t\t}\n\t\treturn null\n\t}\n\n\tif (to) {\n\t\tconst params = new URLSearchParams(to)\n\t\tapp1 = params.get('app1')\n\t\tapp2 = params.get('app2')\n\t}\n\tconst app1Name = getAppName(app1)\n\tconst app2Name = getAppName(app2)\n\tif (!app1Name || !app2Name) {\n\t\treturn (\n\t\t\t// @ts-expect-error 🤷‍♂️\n\t\t\t<callout-danger className=\"notification\">\n\t\t\t\t<div className=\"title\">DiffLink Error: invalid input</div>\n\t\t\t\t{!app1Name && <div>app1: \"{app1}\" is not a valid app name</div>}\n\t\t\t\t{!app2Name && <div>app2: \"{app2}\" is not a valid app name</div>}\n\t\t\t\t{/* @ts-expect-error 🤷‍♂️ */}\n\t\t\t</callout-danger>\n\t\t)\n\t}\n\n\tif (!to) {\n\t\tto = `app1=${app1Name}&app2=${app2Name}`\n\t}\n\tconst pathToDiff = fullPage\n\t\t? `/diff?${to}`\n\t\t: `?${decodeURIComponent(\n\t\t\t\twithParam(new URLSearchParams(), 'preview', `diff&${to}`).toString(),\n\t\t\t)}`\n\n\tif (!children) {\n\t\tchildren = (\n\t\t\t<span>\n\t\t\t\tGo to Diff {fullPage ? '' : 'Preview'} from: <code>{app1Name}</code> to:{' '}\n\t\t\t\t<code>{app2Name}</code>\n\t\t\t</span>\n\t\t)\n\t}\n\n\treturn <Link to={pathToDiff}>{children}</Link>\n}\n\nfunction InlineFile({\n\tfile,\n\ttype = 'playground',\n\tchildren = <code>{file}</code>,\n\t...props\n}: Omit<PropsWithChildren<typeof LaunchEditor>, 'appName'> & {\n\tfile: string\n\ttype?: 'playground' | 'solution' | 'problem'\n}) {\n\tconst data = useLoaderData<typeof loader>()\n\tconst app = data[type] || data[data.type]\n\n\tconst info = (\n\t\t<div className=\"launch-editor-button-wrapper flex underline underline-offset-4\">\n\t\t\t{children}{' '}\n\t\t\t<svg height={24} width={24}>\n\t\t\t\t<use href={`${iconsSvg}#Keyboard`} />\n\t\t\t</svg>\n\t\t</div>\n\t)\n\n\treturn ENV.EPICSHOP_DEPLOYED && app ? (\n\t\t<div className=\"inline-block grow\">\n\t\t\t<LaunchEditor appFile={file} appName={app.name} {...props}>\n\t\t\t\t{info}\n\t\t\t</LaunchEditor>\n\t\t</div>\n\t) : app ? (\n\t\t<div className=\"inline-block grow\">\n\t\t\t<LaunchEditor appFile={file} appName={app.name} {...props}>\n\t\t\t\t{info}\n\t\t\t</LaunchEditor>\n\t\t</div>\n\t) : type === 'playground' ? (\n\t\t// playground does not exist yet\n\t\t<SimpleTooltip content=\"You must 'Set to Playground' before opening a file\">\n\t\t\t<div className=\"inline-block grow cursor-not-allowed\">{info}</div>\n\t\t</SimpleTooltip>\n\t) : (\n\t\t<>children</>\n\t)\n}\n\nfunction getPreviewType(\n\tpreview: string | null,\n): 'playground' | 'problem' | 'solution' {\n\tif (preview === 'problem') return 'problem'\n\tif (preview === 'solution') return 'solution'\n\treturn 'playground'\n}\n\nfunction LinkToApp({\n\tto: appTo,\n\tchildren = <code>{appTo.toString()}</code>,\n\t...props\n}: LinkProps) {\n\tconst [searchParams] = useSearchParams()\n\tconst to = `?${withParam(\n\t\tsearchParams,\n\t\t'pathname',\n\t\tappTo.toString(),\n\t).toString()}`\n\tconst data = useLoaderData<typeof loader>()\n\tconst type = getPreviewType(searchParams.get('preview'))\n\tconst requestInfo = useRequestInfo()\n\tconst app = data[type]\n\tconst previewAppUrl =\n\t\tapp?.dev.type === 'script'\n\t\t\t? getBaseUrl({\n\t\t\t\t\tdomain: requestInfo.domain,\n\t\t\t\t\tport: app.dev.portNumber,\n\t\t\t\t})\n\t\t\t: data.playground?.dev.type === 'browser'\n\t\t\t\t? data.playground.dev.pathname\n\t\t\t\t: null\n\tconst { inBrowserBrowserRef } = useStepContext()\n\tconst href = previewAppUrl\n\t\t? previewAppUrl.slice(0, -1) + appTo.toString()\n\t\t: null\n\treturn (\n\t\t<div className=\"inline-flex items-center justify-between gap-1\">\n\t\t\t<Link\n\t\t\t\tto={to}\n\t\t\t\t{...props}\n\t\t\t\tclassName={cn(props.className, {\n\t\t\t\t\t'cursor-not-allowed': ENV.EPICSHOP_DEPLOYED,\n\t\t\t\t})}\n\t\t\t\ttitle={\n\t\t\t\t\tENV.EPICSHOP_DEPLOYED\n\t\t\t\t\t\t? 'Cannot link to app in deployed version'\n\t\t\t\t\t\t: undefined\n\t\t\t\t}\n\t\t\t\tonClick={(event) => {\n\t\t\t\t\tif (ENV.EPICSHOP_DEPLOYED) event.preventDefault()\n\n\t\t\t\t\tprops.onClick?.(event)\n\t\t\t\t\tinBrowserBrowserRef.current?.handleExtrnalNavigation(appTo.toString())\n\t\t\t\t}}\n\t\t\t>\n\t\t\t\t{children}\n\t\t\t</Link>\n\t\t\t{href ? (\n\t\t\t\t<SimpleTooltip content=\"Open in new tab\">\n\t\t\t\t\t<a\n\t\t\t\t\t\thref={href}\n\t\t\t\t\t\ttarget=\"_blank\"\n\t\t\t\t\t\trel=\"noreferrer\"\n\t\t\t\t\t\tclassName={cn('flex aspect-square items-center justify-center', {\n\t\t\t\t\t\t\t'cursor-not-allowed': ENV.EPICSHOP_DEPLOYED,\n\t\t\t\t\t\t})}\n\t\t\t\t\t\ttitle={\n\t\t\t\t\t\t\tENV.EPICSHOP_DEPLOYED\n\t\t\t\t\t\t\t\t? 'Cannot link to app in deployed version'\n\t\t\t\t\t\t\t\t: 'Open in new tab'\n\t\t\t\t\t\t}\n\t\t\t\t\t\tonClick={(event) => {\n\t\t\t\t\t\t\tif (ENV.EPICSHOP_DEPLOYED) event.preventDefault()\n\t\t\t\t\t\t}}\n\t\t\t\t\t>\n\t\t\t\t\t\t<Icon name=\"ExternalLink\" />\n\t\t\t\t\t</a>\n\t\t\t\t</SimpleTooltip>\n\t\t\t) : null}\n\t\t</div>\n\t)\n}\n","\"use client\";\n\n// src/popover.tsx\nimport * as React from \"react\";\nimport { composeEventHandlers } from \"@radix-ui/primitive\";\nimport { useComposedRefs } from \"@radix-ui/react-compose-refs\";\nimport { createContextScope } from \"@radix-ui/react-context\";\nimport { DismissableLayer } from \"@radix-ui/react-dismissable-layer\";\nimport { useFocusGuards } from \"@radix-ui/react-focus-guards\";\nimport { FocusScope } from \"@radix-ui/react-focus-scope\";\nimport { useId } from \"@radix-ui/react-id\";\nimport * as PopperPrimitive from \"@radix-ui/react-popper\";\nimport { createPopperScope } from \"@radix-ui/react-popper\";\nimport { Portal as PortalPrimitive } from \"@radix-ui/react-portal\";\nimport { Presence } from \"@radix-ui/react-presence\";\nimport { Primitive } from \"@radix-ui/react-primitive\";\nimport { createSlot } from \"@radix-ui/react-slot\";\nimport { useControllableState } from \"@radix-ui/react-use-controllable-state\";\nimport { hideOthers } from \"aria-hidden\";\nimport { RemoveScroll } from \"react-remove-scroll\";\nimport { jsx } from \"react/jsx-runtime\";\nvar POPOVER_NAME = \"Popover\";\nvar [createPopoverContext, createPopoverScope] = createContextScope(POPOVER_NAME, [\n createPopperScope\n]);\nvar usePopperScope = createPopperScope();\nvar [PopoverProvider, usePopoverContext] = createPopoverContext(POPOVER_NAME);\nvar Popover = (props) => {\n const {\n __scopePopover,\n children,\n open: openProp,\n defaultOpen,\n onOpenChange,\n modal = false\n } = props;\n const popperScope = usePopperScope(__scopePopover);\n const triggerRef = React.useRef(null);\n const [hasCustomAnchor, setHasCustomAnchor] = React.useState(false);\n const [open, setOpen] = useControllableState({\n prop: openProp,\n defaultProp: defaultOpen ?? false,\n onChange: onOpenChange,\n caller: POPOVER_NAME\n });\n return /* @__PURE__ */ jsx(PopperPrimitive.Root, { ...popperScope, children: /* @__PURE__ */ jsx(\n PopoverProvider,\n {\n scope: __scopePopover,\n contentId: useId(),\n triggerRef,\n open,\n onOpenChange: setOpen,\n onOpenToggle: React.useCallback(() => setOpen((prevOpen) => !prevOpen), [setOpen]),\n hasCustomAnchor,\n onCustomAnchorAdd: React.useCallback(() => setHasCustomAnchor(true), []),\n onCustomAnchorRemove: React.useCallback(() => setHasCustomAnchor(false), []),\n modal,\n children\n }\n ) });\n};\nPopover.displayName = POPOVER_NAME;\nvar ANCHOR_NAME = \"PopoverAnchor\";\nvar PopoverAnchor = React.forwardRef(\n (props, forwardedRef) => {\n const { __scopePopover, ...anchorProps } = props;\n const context = usePopoverContext(ANCHOR_NAME, __scopePopover);\n const popperScope = usePopperScope(__scopePopover);\n const { onCustomAnchorAdd, onCustomAnchorRemove } = context;\n React.useEffect(() => {\n onCustomAnchorAdd();\n return () => onCustomAnchorRemove();\n }, [onCustomAnchorAdd, onCustomAnchorRemove]);\n return /* @__PURE__ */ jsx(PopperPrimitive.Anchor, { ...popperScope, ...anchorProps, ref: forwardedRef });\n }\n);\nPopoverAnchor.displayName = ANCHOR_NAME;\nvar TRIGGER_NAME = \"PopoverTrigger\";\nvar PopoverTrigger = React.forwardRef(\n (props, forwardedRef) => {\n const { __scopePopover, ...triggerProps } = props;\n const context = usePopoverContext(TRIGGER_NAME, __scopePopover);\n const popperScope = usePopperScope(__scopePopover);\n const composedTriggerRef = useComposedRefs(forwardedRef, context.triggerRef);\n const trigger = /* @__PURE__ */ jsx(\n Primitive.button,\n {\n type: \"button\",\n \"aria-haspopup\": \"dialog\",\n \"aria-expanded\": context.open,\n \"aria-controls\": context.contentId,\n \"data-state\": getState(context.open),\n ...triggerProps,\n ref: composedTriggerRef,\n onClick: composeEventHandlers(props.onClick, context.onOpenToggle)\n }\n );\n return context.hasCustomAnchor ? trigger : /* @__PURE__ */ jsx(PopperPrimitive.Anchor, { asChild: true, ...popperScope, children: trigger });\n }\n);\nPopoverTrigger.displayName = TRIGGER_NAME;\nvar PORTAL_NAME = \"PopoverPortal\";\nvar [PortalProvider, usePortalContext] = createPopoverContext(PORTAL_NAME, {\n forceMount: void 0\n});\nvar PopoverPortal = (props) => {\n const { __scopePopover, forceMount, children, container } = props;\n const context = usePopoverContext(PORTAL_NAME, __scopePopover);\n return /* @__PURE__ */ jsx(PortalProvider, { scope: __scopePopover, forceMount, children: /* @__PURE__ */ jsx(Presence, { present: forceMount || context.open, children: /* @__PURE__ */ jsx(PortalPrimitive, { asChild: true, container, children }) }) });\n};\nPopoverPortal.displayName = PORTAL_NAME;\nvar CONTENT_NAME = \"PopoverContent\";\nvar PopoverContent = React.forwardRef(\n (props, forwardedRef) => {\n const portalContext = usePortalContext(CONTENT_NAME, props.__scopePopover);\n const { forceMount = portalContext.forceMount, ...contentProps } = props;\n const context = usePopoverContext(CONTENT_NAME, props.__scopePopover);\n return /* @__PURE__ */ jsx(Presence, { present: forceMount || context.open, children: context.modal ? /* @__PURE__ */ jsx(PopoverContentModal, { ...contentProps, ref: forwardedRef }) : /* @__PURE__ */ jsx(PopoverContentNonModal, { ...contentProps, ref: forwardedRef }) });\n }\n);\nPopoverContent.displayName = CONTENT_NAME;\nvar Slot = createSlot(\"PopoverContent.RemoveScroll\");\nvar PopoverContentModal = React.forwardRef(\n (props, forwardedRef) => {\n const context = usePopoverContext(CONTENT_NAME, props.__scopePopover);\n const contentRef = React.useRef(null);\n const composedRefs = useComposedRefs(forwardedRef, contentRef);\n const isRightClickOutsideRef = React.useRef(false);\n React.useEffect(() => {\n const content = contentRef.current;\n if (content) return hideOthers(content);\n }, []);\n return /* @__PURE__ */ jsx(RemoveScroll, { as: Slot, allowPinchZoom: true, children: /* @__PURE__ */ jsx(\n PopoverContentImpl,\n {\n ...props,\n ref: composedRefs,\n trapFocus: context.open,\n disableOutsidePointerEvents: true,\n onCloseAutoFocus: composeEventHandlers(props.onCloseAutoFocus, (event) => {\n event.preventDefault();\n if (!isRightClickOutsideRef.current) context.triggerRef.current?.focus();\n }),\n onPointerDownOutside: composeEventHandlers(\n props.onPointerDownOutside,\n (event) => {\n const originalEvent = event.detail.originalEvent;\n const ctrlLeftClick = originalEvent.button === 0 && originalEvent.ctrlKey === true;\n const isRightClick = originalEvent.button === 2 || ctrlLeftClick;\n isRightClickOutsideRef.current = isRightClick;\n },\n { checkForDefaultPrevented: false }\n ),\n onFocusOutside: composeEventHandlers(\n props.onFocusOutside,\n (event) => event.preventDefault(),\n { checkForDefaultPrevented: false }\n )\n }\n ) });\n }\n);\nvar PopoverContentNonModal = React.forwardRef(\n (props, forwardedRef) => {\n const context = usePopoverContext(CONTENT_NAME, props.__scopePopover);\n const hasInteractedOutsideRef = React.useRef(false);\n const hasPointerDownOutsideRef = React.useRef(false);\n return /* @__PURE__ */ jsx(\n PopoverContentImpl,\n {\n ...props,\n ref: forwardedRef,\n trapFocus: false,\n disableOutsidePointerEvents: false,\n onCloseAutoFocus: (event) => {\n props.onCloseAutoFocus?.(event);\n if (!event.defaultPrevented) {\n if (!hasInteractedOutsideRef.current) context.triggerRef.current?.focus();\n event.preventDefault();\n }\n hasInteractedOutsideRef.current = false;\n hasPointerDownOutsideRef.current = false;\n },\n onInteractOutside: (event) => {\n props.onInteractOutside?.(event);\n if (!event.defaultPrevented) {\n hasInteractedOutsideRef.current = true;\n if (event.detail.originalEvent.type === \"pointerdown\") {\n hasPointerDownOutsideRef.current = true;\n }\n }\n const target = event.target;\n const targetIsTrigger = context.triggerRef.current?.contains(target);\n if (targetIsTrigger) event.preventDefault();\n if (event.detail.originalEvent.type === \"focusin\" && hasPointerDownOutsideRef.current) {\n event.preventDefault();\n }\n }\n }\n );\n }\n);\nvar PopoverContentImpl = React.forwardRef(\n (props, forwardedRef) => {\n const {\n __scopePopover,\n trapFocus,\n onOpenAutoFocus,\n onCloseAutoFocus,\n disableOutsidePointerEvents,\n onEscapeKeyDown,\n onPointerDownOutside,\n onFocusOutside,\n onInteractOutside,\n ...contentProps\n } = props;\n const context = usePopoverContext(CONTENT_NAME, __scopePopover);\n const popperScope = usePopperScope(__scopePopover);\n useFocusGuards();\n return /* @__PURE__ */ jsx(\n FocusScope,\n {\n asChild: true,\n loop: true,\n trapped: trapFocus,\n onMountAutoFocus: onOpenAutoFocus,\n onUnmountAutoFocus: onCloseAutoFocus,\n children: /* @__PURE__ */ jsx(\n DismissableLayer,\n {\n asChild: true,\n disableOutsidePointerEvents,\n onInteractOutside,\n onEscapeKeyDown,\n onPointerDownOutside,\n onFocusOutside,\n onDismiss: () => context.onOpenChange(false),\n children: /* @__PURE__ */ jsx(\n PopperPrimitive.Content,\n {\n \"data-state\": getState(context.open),\n role: \"dialog\",\n id: context.contentId,\n ...popperScope,\n ...contentProps,\n ref: forwardedRef,\n style: {\n ...contentProps.style,\n // re-namespace exposed content custom properties\n ...{\n \"--radix-popover-content-transform-origin\": \"var(--radix-popper-transform-origin)\",\n \"--radix-popover-content-available-width\": \"var(--radix-popper-available-width)\",\n \"--radix-popover-content-available-height\": \"var(--radix-popper-available-height)\",\n \"--radix-popover-trigger-width\": \"var(--radix-popper-anchor-width)\",\n \"--radix-popover-trigger-height\": \"var(--radix-popper-anchor-height)\"\n }\n }\n }\n )\n }\n )\n }\n );\n }\n);\nvar CLOSE_NAME = \"PopoverClose\";\nvar PopoverClose = React.forwardRef(\n (props, forwardedRef) => {\n const { __scopePopover, ...closeProps } = props;\n const context = usePopoverContext(CLOSE_NAME, __scopePopover);\n return /* @__PURE__ */ jsx(\n Primitive.button,\n {\n type: \"button\",\n ...closeProps,\n ref: forwardedRef,\n onClick: composeEventHandlers(props.onClick, () => context.onOpenChange(false))\n }\n );\n }\n);\nPopoverClose.displayName = CLOSE_NAME;\nvar ARROW_NAME = \"PopoverArrow\";\nvar PopoverArrow = React.forwardRef(\n (props, forwardedRef) => {\n const { __scopePopover, ...arrowProps } = props;\n const popperScope = usePopperScope(__scopePopover);\n return /* @__PURE__ */ jsx(PopperPrimitive.Arrow, { ...popperScope, ...arrowProps, ref: forwardedRef });\n }\n);\nPopoverArrow.displayName = ARROW_NAME;\nfunction getState(open) {\n return open ? \"open\" : \"closed\";\n}\nvar Root2 = Popover;\nvar Anchor2 = PopoverAnchor;\nvar Trigger = PopoverTrigger;\nvar Portal = PopoverPortal;\nvar Content2 = PopoverContent;\nvar Close = PopoverClose;\nvar Arrow2 = PopoverArrow;\nexport {\n Anchor2 as Anchor,\n Arrow2 as Arrow,\n Close,\n Content2 as Content,\n Popover,\n PopoverAnchor,\n PopoverArrow,\n PopoverClose,\n PopoverContent,\n PopoverPortal,\n PopoverTrigger,\n Portal,\n Root2 as Root,\n Trigger,\n createPopoverScope\n};\n//# sourceMappingURL=index.mjs.map\n","import * as Popover from '@radix-ui/react-popover'\nimport * as React from 'react'\nimport { Await, useLoaderData } from 'react-router'\nimport { Icon } from '#app/components/icons.tsx'\nimport { SimpleTooltip } from '#app/components/ui/tooltip.tsx'\nimport { LaunchEditor } from '#app/routes/launch-editor.tsx'\nimport { SetAppToPlayground } from '#app/routes/set-playground.tsx'\nimport { type Route as LayoutRoute } from '../+types/_layout.tsx'\n\nfunction TouchedFiles({\n\tdiffFilesPromise,\n\tcompact = false,\n}: {\n\tdiffFilesPromise: LayoutRoute.ComponentProps['loaderData']['diffFiles']\n\tcompact?: boolean\n}) {\n\tconst data = useLoaderData<LayoutRoute.ComponentProps['loaderData']>()\n\n\tconst [open, setOpen] = React.useState(false)\n\tconst contentRef = React.useRef<HTMLDivElement>(null)\n\n\tfunction handleLaunchUpdate() {\n\t\tsetOpen(false)\n\t}\n\n\tconst appName = data.playground?.appName\n\n\treturn (\n\t\t<>\n\t\t\t<Popover.Root open={open} onOpenChange={setOpen}>\n\t\t\t\t<Popover.Trigger asChild>\n\t\t\t\t\t<button\n\t\t\t\t\t\tclassName=\"flex h-full items-center gap-1 border-r px-6 py-3 font-mono text-sm uppercase\"\n\t\t\t\t\t\taria-label=\"Relevant Files\"\n\t\t\t\t\t>\n\t\t\t\t\t\t<Icon name=\"Files\" />\n\t\t\t\t\t\t{compact ? null : <span className=\"hidden xl:inline\">Files</span>}\n\t\t\t\t\t</button>\n\t\t\t\t</Popover.Trigger>\n\t\t\t\t<Popover.Portal>\n\t\t\t\t\t<Popover.Content\n\t\t\t\t\t\tref={contentRef}\n\t\t\t\t\t\tclassName=\"slideRightContent lg:slideUpContent invert-theme z-10 select-none rounded bg-background px-9 py-8 text-foreground\"\n\t\t\t\t\t\talign=\"start\"\n\t\t\t\t\t\tsideOffset={5}\n\t\t\t\t\t>\n\t\t\t\t\t\t<div className=\"launch-editor-wrapper\">\n\t\t\t\t\t\t\t<strong className=\"inline-block px-2 pb-4 font-semibold uppercase\">\n\t\t\t\t\t\t\t\tRelevant Files\n\t\t\t\t\t\t\t</strong>\n\t\t\t\t\t\t\t{data.problem &&\n\t\t\t\t\t\t\tdata.playground?.appName !== data.problem.name ? (\n\t\t\t\t\t\t\t\t<div className=\"mb-2 rounded p-1 font-mono font-medium\">\n\t\t\t\t\t\t\t\t\t<SetAppToPlayground appName={data.problem.name} />\n\t\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t\t) : null}\n\t\t\t\t\t\t\t<div id=\"files\">\n\t\t\t\t\t\t\t\t<React.Suspense\n\t\t\t\t\t\t\t\t\tfallback={\n\t\t\t\t\t\t\t\t\t\t<SimpleTooltip content=\"Loading diff\">\n\t\t\t\t\t\t\t\t\t\t\t<div className=\"flex justify-center\">\n\t\t\t\t\t\t\t\t\t\t\t\t<Icon name=\"Refresh\" className=\"h-8 w-8 animate-spin\" />\n\t\t\t\t\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t\t\t\t\t</SimpleTooltip>\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<Await\n\t\t\t\t\t\t\t\t\t\tresolve={diffFilesPromise}\n\t\t\t\t\t\t\t\t\t\terrorElement={\n\t\t\t\t\t\t\t\t\t\t\t<div className=\"text-foreground-destructive\">\n\t\t\t\t\t\t\t\t\t\t\t\tSomething went wrong.\n\t\t\t\t\t\t\t\t\t\t\t</div>\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{(diffFiles) => {\n\t\t\t\t\t\t\t\t\t\t\tif (!diffFiles) {\n\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<p className=\"text-foreground-destructive\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\tUnable to determine diff\n\t\t\t\t\t\t\t\t\t\t\t\t\t</p>\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\tif (typeof diffFiles === 'string') {\n\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<p className=\"text-foreground-destructive\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t{diffFiles}\n\t\t\t\t\t\t\t\t\t\t\t\t\t</p>\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\tif (!diffFiles.length) {\n\t\t\t\t\t\t\t\t\t\t\t\treturn <p>No files changed</p>\n\t\t\t\t\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\t\t\t\t\tconst props =\n\t\t\t\t\t\t\t\t\t\t\t\tappName || ENV.EPICSHOP_GITHUB_ROOT\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: {\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\ttitle:\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\"You must 'Set to Playground' before opening a file\",\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tclassName: 'not-allowed',\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\treturn (\n\t\t\t\t\t\t\t\t\t\t\t\t<ul {...props}>\n\t\t\t\t\t\t\t\t\t\t\t\t\t{diffFiles.length > 1 && !ENV.EPICSHOP_DEPLOYED ? (\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t<div className=\"mb-2 border-b border-b-gray-50 border-opacity-50 pb-2 font-sans\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<LaunchEditor\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tappFile={diffFiles.map(\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t(file) => `${file.path},${file.line},1`,\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\tappName=\"playground\"\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tonUpdate={handleLaunchUpdate}\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\t\t<p>Open All Files</p>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</LaunchEditor>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t\t\t\t\t\t\t\t) : null}\n\t\t\t\t\t\t\t\t\t\t\t\t\t{diffFiles.map((file) => (\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t<li key={file.path} data-state={file.status}>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<LaunchEditor\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tappFile={`${file.path},${file.line},1`}\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tappName={\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tENV.EPICSHOP_DEPLOYED\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t? (data.problem?.name ?? 'playground')\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t: 'playground'\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\tonUpdate={handleLaunchUpdate}\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\t\t<code>{file.path}</code>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</LaunchEditor>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t</li>\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</ul>\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</Await>\n\t\t\t\t\t\t\t\t</React.Suspense>\n\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t</div>\n\t\t\t\t\t</Popover.Content>\n\t\t\t\t</Popover.Portal>\n\t\t\t</Popover.Root>\n\t\t</>\n\t)\n}\n\nexport default TouchedFiles\n","import { ElementScrollRestoration } from '@epic-web/restore-scroll'\nimport {\n\tgetAppDisplayName,\n\tgetAppPageRoute,\n\tgetApps,\n\tgetExerciseApp,\n\tgetNextExerciseApp,\n\tgetPrevExerciseApp,\n\tisExerciseStepApp,\n\tisPlaygroundApp,\n\trequireExercise,\n\trequireExerciseApp,\n\ttype App,\n\ttype ExerciseStepApp,\n} from '@epic-web/workshop-utils/apps.server'\nimport { getWorkshopConfig } from '@epic-web/workshop-utils/config.server'\nimport { getDiffFiles } from '@epic-web/workshop-utils/diff.server'\nimport { getEpicVideoInfos } from '@epic-web/workshop-utils/epic-api.server'\nimport {\n\tcombineServerTimings,\n\tgetServerTimeHeader,\n\tmakeTimings,\n} from '@epic-web/workshop-utils/timing.server'\nimport slugify from '@sindresorhus/slugify'\nimport * as cookie from 'cookie'\nimport { useEffect, useRef, useState } from 'react'\nimport {\n\tdata,\n\tredirect,\n\ttype HeadersFunction,\n\tLink,\n\tOutlet,\n} from 'react-router'\nimport { GeneralErrorBoundary } from '#app/components/error-boundary.tsx'\nimport { type InBrowserBrowserRef } from '#app/components/in-browser-browser.tsx'\nimport { NavChevrons } from '#app/components/nav-chevrons.tsx'\nimport { useRevalidationWS } from '#app/components/revalidation-ws.js'\nimport { type RootLoaderData } from '#app/root.tsx'\nimport { EditFileOnGitHub } from '#app/routes/launch-editor.tsx'\nimport { ProgressToggle } from '#app/routes/progress.tsx'\nimport { SetAppToPlayground } from '#app/routes/set-playground.tsx'\nimport { getExercisePath } from '#app/utils/misc.tsx'\nimport { getSeoMetaTags } from '#app/utils/seo.js'\nimport { type Route } from './+types/_layout.tsx'\nimport { StepMdx } from './__shared/step-mdx.tsx'\nimport TouchedFiles from './__shared/touched-files.tsx'\n\n// shared split state helpers\nconst splitCookieName = 'es_split_pct'\nfunction computeSplitPercent(input: unknown, defaultValue = 50): number {\n\tconst value = typeof input === 'number' ? input : Number(input)\n\tif (Number.isFinite(value)) {\n\t\treturn Math.min(80, Math.max(20, Math.round(value * 100) / 100))\n\t}\n\treturn defaultValue\n}\n\nfunction pageTitle(\n\tdata: Awaited<Route.ComponentProps['loaderData']> | undefined,\n\tworkshopTitle?: string,\n) {\n\tconst exerciseNumber =\n\t\tdata?.exerciseStepApp.exerciseNumber.toString().padStart(2, '0') ?? '00'\n\tconst stepNumber =\n\t\tdata?.exerciseStepApp.stepNumber.toString().padStart(2, '0') ?? '00'\n\tconst emoji = (\n\t\t{\n\t\t\tproblem: '💪',\n\t\t\tsolution: '🏁',\n\t\t} as const\n\t)[data?.type ?? 'problem']\n\tconst title = data?.[data.type]?.title ?? 'N/A'\n\treturn {\n\t\temoji,\n\t\tstepNumber,\n\t\ttitle,\n\t\texerciseNumber,\n\t\texerciseTitle: data?.exerciseTitle ?? 'Unknown exercise',\n\t\tworkshopTitle,\n\t\ttype: data?.type ?? 'problem',\n\t}\n}\n\nexport const meta: Route.MetaFunction = ({ data, matches, params }) => {\n\tconst rootData = matches.find((m) => m?.id === 'root')?.data as RootLoaderData\n\tif (!data || !rootData) return [{ title: '🦉 | Error' }]\n\tconst { emoji, stepNumber, title, exerciseNumber, exerciseTitle } =\n\t\tpageTitle(data)\n\n\treturn getSeoMetaTags({\n\t\ttitle: `${emoji} | ${stepNumber}. ${title} | ${exerciseNumber}. ${exerciseTitle} | ${rootData.workshopTitle}`,\n\t\tdescription: `${params.type} step for exercise ${exerciseNumber}. ${exerciseTitle}`,\n\t\togTitle: title,\n\t\togDescription: `${exerciseTitle} step ${Number(stepNumber)} ${params.type}`,\n\t\tinstructor: rootData.instructor,\n\t\trequestInfo: rootData.requestInfo,\n\t})\n}\n\nexport async function loader({ request, params }: Route.LoaderArgs) {\n\tconst timings = makeTimings('exerciseStepTypeLayoutLoader')\n\tconst url = new URL(request.url)\n\tconst { title: workshopTitle } = getWorkshopConfig()\n\n\tconst cacheOptions = { request, timings }\n\n\tconst [exerciseStepApp, allAppsFull, problemApp, solutionApp] =\n\t\tawait Promise.all([\n\t\t\trequireExerciseApp(params, cacheOptions),\n\t\t\tgetApps(cacheOptions),\n\t\t\tgetExerciseApp({ ...params, type: 'problem' }, cacheOptions),\n\t\t\tgetExerciseApp({ ...params, type: 'solution' }, cacheOptions),\n\t\t])\n\n\tconst reqUrl = new URL(request.url)\n\tconst pathnameParam = reqUrl.searchParams.get('pathname')\n\tif (pathnameParam === '' || pathnameParam === '/') {\n\t\treqUrl.searchParams.delete('pathname')\n\t\tthrow redirect(reqUrl.toString())\n\t}\n\n\tif (!problemApp && !solutionApp) {\n\t\tthrow new Response('Not found', { status: 404 })\n\t}\n\n\tconst playgroundApp = allAppsFull.find(isPlaygroundApp)\n\n\tfunction getStepId(a: ExerciseStepApp) {\n\t\treturn (\n\t\t\ta.exerciseNumber * 1000 +\n\t\t\ta.stepNumber * 10 +\n\t\t\t(a.type === 'problem' ? 0 : 1)\n\t\t)\n\t}\n\n\tfunction getStepNameAndId(a: App) {\n\t\tif (isExerciseStepApp(a)) {\n\t\t\tconst exerciseNumberStr = String(a.exerciseNumber).padStart(2, '0')\n\t\t\tconst stepNumberStr = String(a.stepNumber).padStart(2, '0')\n\n\t\t\treturn {\n\t\t\t\tstepName: `${exerciseNumberStr}/${stepNumberStr}.${a.type}`,\n\t\t\t\tstepId: getStepId(a),\n\t\t\t}\n\t\t}\n\t\treturn { stepName: '', stepId: -1 }\n\t}\n\n\tconst allApps = allAppsFull\n\t\t.filter((a, i, ar) => ar.findIndex((b) => a.name === b.name) === i)\n\t\t.map((a) => ({\n\t\t\tdisplayName: getAppDisplayName(a, allAppsFull),\n\t\t\tname: a.name,\n\t\t\ttitle: a.title,\n\t\t\ttype: a.type,\n\t\t\t...getStepNameAndId(a),\n\t\t}))\n\n\tallApps.sort((a, b) => {\n\t\t// order them by their stepId\n\t\tif (a.stepId > 0 && b.stepId > 0) return a.stepId - b.stepId\n\n\t\t// non-step apps should come after step apps\n\t\tif (a.stepId > 0) return -1\n\t\tif (b.stepId > 0) return 1\n\n\t\treturn 0\n\t})\n\tconst exerciseId = getStepId(exerciseStepApp)\n\tconst exerciseIndex = allApps.findIndex((step) => step.stepId === exerciseId)\n\n\t// These depend on exerciseStepApp\n\tconst [exercise, nextApp, prevApp] = await Promise.all([\n\t\trequireExercise(exerciseStepApp.exerciseNumber, cacheOptions),\n\t\tgetNextExerciseApp(exerciseStepApp, cacheOptions),\n\t\tgetPrevExerciseApp(exerciseStepApp, cacheOptions),\n\t])\n\n\tconst exerciseApps = allAppsFull\n\t\t.filter(isExerciseStepApp)\n\t\t.filter((app) => app.exerciseNumber === exerciseStepApp.exerciseNumber)\n\tconst isLastStep =\n\t\texerciseApps[exerciseApps.length - 1]?.name === exerciseStepApp.name\n\tconst isFirstStep = exerciseApps[0]?.name === exerciseStepApp.name\n\n\tconst articleId = `workshop-${slugify(workshopTitle)}-${\n\t\texercise.exerciseNumber\n\t}-${exerciseStepApp.stepNumber}-${exerciseStepApp.type}`\n\n\tconst subroute = url.pathname.split(\n\t\t`/exercise/${params.exerciseNumber}/${params.stepNumber}/${params.type}/`,\n\t)[1]\n\n\t// read persisted split percentage from cookie (10-90, default 50)\n\tconst cookieHeader = request.headers.get('cookie')\n\tconst rawSplit = cookieHeader\n\t\t? cookie.parse(cookieHeader)[splitCookieName]\n\t\t: null\n\tconst splitPercent = computeSplitPercent(rawSplit, 50)\n\n\treturn data(\n\t\t{\n\t\t\tarticleId,\n\t\t\ttype: params.type as 'problem' | 'solution',\n\t\t\texerciseStepApp,\n\t\t\texerciseTitle: exercise.title,\n\t\t\tepicVideoInfosPromise: getEpicVideoInfos(exerciseStepApp.epicVideoEmbeds),\n\t\t\texerciseIndex,\n\t\t\tallApps,\n\t\t\tsplitPercent,\n\t\t\tprevStepLink: isFirstStep\n\t\t\t\t? {\n\t\t\t\t\t\tto: `/exercise/${exerciseStepApp.exerciseNumber\n\t\t\t\t\t\t\t.toString()\n\t\t\t\t\t\t\t.padStart(2, '0')}`,\n\t\t\t\t\t}\n\t\t\t\t: prevApp\n\t\t\t\t\t? {\n\t\t\t\t\t\t\tto: getAppPageRoute(prevApp, {\n\t\t\t\t\t\t\t\tsubroute,\n\t\t\t\t\t\t\t\tsearchParams: url.searchParams,\n\t\t\t\t\t\t\t}),\n\t\t\t\t\t\t}\n\t\t\t\t\t: null,\n\t\t\tnextStepLink: isLastStep\n\t\t\t\t? {\n\t\t\t\t\t\tto: `/exercise/${exerciseStepApp.exerciseNumber\n\t\t\t\t\t\t\t.toString()\n\t\t\t\t\t\t\t.padStart(2, '0')}/finished`,\n\t\t\t\t\t}\n\t\t\t\t: nextApp\n\t\t\t\t\t? {\n\t\t\t\t\t\t\tto: getAppPageRoute(nextApp, {\n\t\t\t\t\t\t\t\tsubroute,\n\t\t\t\t\t\t\t\tsearchParams: url.searchParams,\n\t\t\t\t\t\t\t}),\n\t\t\t\t\t\t}\n\t\t\t\t\t: null,\n\t\t\tplayground: playgroundApp\n\t\t\t\t? ({\n\t\t\t\t\t\ttype: 'playground',\n\t\t\t\t\t\tappName: playgroundApp.appName,\n\t\t\t\t\t\tname: playgroundApp.name,\n\t\t\t\t\t\tfullPath: playgroundApp.fullPath,\n\t\t\t\t\t\tdev: playgroundApp.dev,\n\t\t\t\t\t} as const)\n\t\t\t\t: null,\n\t\t\tproblem: problemApp\n\t\t\t\t? ({\n\t\t\t\t\t\ttype: 'problem',\n\t\t\t\t\t\ttitle: problemApp.title,\n\t\t\t\t\t\tname: problemApp.name,\n\t\t\t\t\t\tfullPath: problemApp.fullPath,\n\t\t\t\t\t\tdev: problemApp.dev,\n\t\t\t\t\t} as const)\n\t\t\t\t: null,\n\t\t\tsolution: solutionApp\n\t\t\t\t? ({\n\t\t\t\t\t\ttype: 'solution',\n\t\t\t\t\t\ttitle: solutionApp.title,\n\t\t\t\t\t\tname: solutionApp.name,\n\t\t\t\t\t\tfullPath: solutionApp.fullPath,\n\t\t\t\t\t\tdev: solutionApp.dev,\n\t\t\t\t\t} as const)\n\t\t\t\t: null,\n\t\t\tdiffFiles:\n\t\t\t\tproblemApp && solutionApp\n\t\t\t\t\t? getDiffFiles(problemApp, solutionApp, {\n\t\t\t\t\t\t\t...cacheOptions,\n\t\t\t\t\t\t\tforceFresh: url.searchParams.get('forceFresh') === 'diff',\n\t\t\t\t\t\t}).catch((e) => {\n\t\t\t\t\t\t\tconsole.error(e)\n\t\t\t\t\t\t\treturn 'There was a problem generating the diff (check the terminal output)'\n\t\t\t\t\t\t})\n\t\t\t\t\t: 'No diff available',\n\t\t} as const,\n\t\t{\n\t\t\theaders: {\n\t\t\t\t'Server-Timing': getServerTimeHeader(timings),\n\t\t\t},\n\t\t},\n\t)\n}\n\nexport const headers: HeadersFunction = ({ loaderHeaders, parentHeaders }) => {\n\tconst headers = {\n\t\t'Server-Timing': combineServerTimings(loaderHeaders, parentHeaders),\n\t}\n\treturn headers\n}\n\nexport default function ExercisePartRoute({\n\tloaderData: data,\n}: Route.ComponentProps) {\n\tconst inBrowserBrowserRef = useRef<InBrowserBrowserRef>(null)\n\tconst containerRef = useRef<HTMLDivElement>(null)\n\tconst leftPaneRef = useRef<HTMLDivElement>(null)\n\tconst [splitPercent, setSplitPercent] = useState<number>(data.splitPercent)\n\tconst [leftWidthPx, setLeftWidthPx] = useState<number>(0)\n\n\tuseEffect(() => {\n\t\tconst left = leftPaneRef.current\n\t\tif (!left) return\n\t\tconst ro = new ResizeObserver((entries) => {\n\t\t\tfor (const entry of entries) {\n\t\t\t\tsetLeftWidthPx(entry.contentRect.width)\n\t\t\t}\n\t\t})\n\t\tro.observe(left)\n\t\tsetLeftWidthPx(left.getBoundingClientRect().width)\n\t\treturn () => ro.disconnect()\n\t}, [])\n\n\tfunction setCookie(percent: number) {\n\t\tconst clamped = computeSplitPercent(percent)\n\t\tdocument.cookie = `${splitCookieName}=${clamped}; path=/; SameSite=Lax;`\n\t}\n\n\tfunction startDrag(initialClientX: number) {\n\t\tconst container = containerRef.current\n\t\tif (!container) return\n\t\tconst rect = container.getBoundingClientRect()\n\t\tlet dragging = true\n\n\t\t// Disable pointer events on iframes so the drag keeps receiving events\n\t\tconst iframes = Array.from(\n\t\t\tdocument.querySelectorAll('iframe'),\n\t\t) as HTMLIFrameElement[]\n\t\tconst originalPointerEvents = iframes.map((el) => el.style.pointerEvents)\n\t\tiframes.forEach((el) => (el.style.pointerEvents = 'none'))\n\n\t\tfunction handleMove(clientX: number) {\n\t\t\t// Safety check: ensure user is still dragging\n\t\t\tif (!dragging) {\n\t\t\t\tcleanup()\n\t\t\t\treturn\n\t\t\t}\n\n\t\t\tconst relativeX = clientX - rect.left\n\t\t\tconst percent = (relativeX / rect.width) * 100\n\t\t\tconst clamped = computeSplitPercent(percent)\n\t\t\tsetSplitPercent(clamped)\n\t\t\tsetCookie(clamped)\n\t\t}\n\n\t\tfunction onMouseMove(e: MouseEvent) {\n\t\t\tif (!dragging || e.buttons === 0) {\n\t\t\t\tcleanup()\n\t\t\t\treturn\n\t\t\t}\n\t\t\thandleMove(e.clientX)\n\t\t}\n\t\tfunction onTouchMove(e: TouchEvent) {\n\t\t\tconst firstTouch = e.touches?.[0]\n\t\t\tif (!dragging || !firstTouch) {\n\t\t\t\tcleanup()\n\t\t\t\treturn\n\t\t\t}\n\t\t\thandleMove(firstTouch.clientX)\n\t\t}\n\t\tfunction cleanup() {\n\t\t\tif (!dragging) return\n\t\t\tdragging = false\n\t\t\tiframes.forEach(\n\t\t\t\t(el, i) => (el.style.pointerEvents = originalPointerEvents[i] ?? ''),\n\t\t\t)\n\t\t\twindow.removeEventListener('mousemove', onMouseMove)\n\t\t\twindow.removeEventListener('mouseup', cleanup)\n\t\t\twindow.removeEventListener('touchmove', onTouchMove)\n\t\t\twindow.removeEventListener('touchend', cleanup)\n\t\t\tdocument.body.style.cursor = ''\n\t\t\tdocument.body.style.userSelect = ''\n\t\t}\n\n\t\twindow.addEventListener('mousemove', onMouseMove)\n\t\twindow.addEventListener('mouseup', cleanup)\n\t\twindow.addEventListener('touchmove', onTouchMove)\n\t\twindow.addEventListener('touchend', cleanup)\n\t\tdocument.body.style.cursor = 'col-resize'\n\t\tdocument.body.style.userSelect = 'none'\n\t\thandleMove(initialClientX)\n\t}\n\n\tconst titleBits = pageTitle(data)\n\n\tuseRevalidationWS({\n\t\twatchPaths: [`${data.exerciseStepApp.relativePath}/README.mdx`],\n\t})\n\n\treturn (\n\t\t<div className=\"flex max-w-full flex-grow flex-col\">\n\t\t\t<main\n\t\t\t\tref={containerRef}\n\t\t\t\tclassName=\"flex flex-grow flex-col sm:h-full sm:min-h-[800px] md:min-h-[unset] lg:flex-row\"\n\t\t\t>\n\t\t\t\t<div\n\t\t\t\t\tclassName=\"relative flex min-w-0 flex-none basis-full flex-col sm:col-span-1 sm:row-span-1 sm:h-full lg:basis-[var(--split-pct)]\"\n\t\t\t\t\tstyle={{ ['--split-pct' as any]: `${splitPercent}%` }}\n\t\t\t\t\tref={leftPaneRef}\n\t\t\t\t>\n\t\t\t\t\t<h1 className=\"h-14 border-b pl-10 pr-5 text-sm font-medium leading-tight\">\n\t\t\t\t\t\t<div className=\"flex h-14 items-center justify-between gap-x-2 overflow-x-auto whitespace-nowrap py-2\">\n\t\t\t\t\t\t\t<div className=\"flex items-center justify-start gap-x-2 uppercase\">\n\t\t\t\t\t\t\t\t<Link\n\t\t\t\t\t\t\t\t\tto={getExercisePath(data.exerciseStepApp.exerciseNumber)}\n\t\t\t\t\t\t\t\t\tclassName=\"hover:underline\"\n\t\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t\t{titleBits.exerciseNumber}. {titleBits.exerciseTitle}\n\t\t\t\t\t\t\t\t</Link>\n\t\t\t\t\t\t\t\t{'/'}\n\t\t\t\t\t\t\t\t<Link to=\".\" className=\"hover:underline\">\n\t\t\t\t\t\t\t\t\t{titleBits.stepNumber}. {titleBits.title}\n\t\t\t\t\t\t\t\t\t{' ('}\n\t\t\t\t\t\t\t\t\t{titleBits.emoji} {titleBits.type}\n\t\t\t\t\t\t\t\t\t{')'}\n\t\t\t\t\t\t\t\t</Link>\n\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t\t{data.problem &&\n\t\t\t\t\t\t\tdata.playground?.appName !== data.problem.name ? (\n\t\t\t\t\t\t\t\t<div className=\"hidden md:block\">\n\t\t\t\t\t\t\t\t\t<SetAppToPlayground appName={data.problem.name} />\n\t\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t\t) : null}\n\t\t\t\t\t\t</div>\n\t\t\t\t\t</h1>\n\t\t\t\t\t<article\n\t\t\t\t\t\tid={data.articleId}\n\t\t\t\t\t\tkey={data.articleId}\n\t\t\t\t\t\tclassName=\"shadow-on-scrollbox flex h-full w-full max-w-none flex-1 scroll-pt-6 flex-col justify-between space-y-6 overflow-y-auto p-2 scrollbar-thin scrollbar-thumb-scrollbar sm:p-10 sm:pt-8\"\n\t\t\t\t\t>\n\t\t\t\t\t\t{data.exerciseStepApp.instructionsCode ? (\n\t\t\t\t\t\t\t<StepMdx inBrowserBrowserRef={inBrowserBrowserRef} />\n\t\t\t\t\t\t) : (\n\t\t\t\t\t\t\t<div className=\"flex h-full items-center justify-center text-lg\">\n\t\t\t\t\t\t\t\t<p>No instructions yet...</p>\n\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t)}\n\t\t\t\t\t\t<div className=\"mt-auto flex justify-between\">\n\t\t\t\t\t\t\t{data.prevStepLink ? (\n\t\t\t\t\t\t\t\t<Link\n\t\t\t\t\t\t\t\t\tto={data.prevStepLink.to}\n\t\t\t\t\t\t\t\t\taria-label=\"Previous Step\"\n\t\t\t\t\t\t\t\t\tprefetch=\"intent\"\n\t\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t\t<span aria-hidden>←</span>\n\t\t\t\t\t\t\t\t\t<span className=\"hidden xl:inline\"> Previous</span>\n\t\t\t\t\t\t\t\t</Link>\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)}\n\t\t\t\t\t\t\t{data.nextStepLink ? (\n\t\t\t\t\t\t\t\t<Link\n\t\t\t\t\t\t\t\t\tto={data.nextStepLink.to}\n\t\t\t\t\t\t\t\t\taria-label=\"Next Step\"\n\t\t\t\t\t\t\t\t\tprefetch=\"intent\"\n\t\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t\t<span className=\"hidden xl:inline\">Next </span>\n\t\t\t\t\t\t\t\t\t<span aria-hidden>→</span>\n\t\t\t\t\t\t\t\t</Link>\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)}\n\t\t\t\t\t\t</div>\n\t\t\t\t\t</article>\n\t\t\t\t\t<ElementScrollRestoration\n\t\t\t\t\t\telementQuery={`#${data.articleId}`}\n\t\t\t\t\t\tkey={`scroll-${data.articleId}`}\n\t\t\t\t\t/>\n\t\t\t\t\t{data.type === 'solution' ? (\n\t\t\t\t\t\t<ProgressToggle\n\t\t\t\t\t\t\ttype=\"step\"\n\t\t\t\t\t\t\texerciseNumber={data.exerciseStepApp.exerciseNumber}\n\t\t\t\t\t\t\tstepNumber={data.exerciseStepApp.stepNumber}\n\t\t\t\t\t\t\tclassName=\"h-14 border-t px-6\"\n\t\t\t\t\t\t/>\n\t\t\t\t\t) : null}\n\t\t\t\t\t<div className=\"flex h-16 justify-between border-b-4 border-t lg:border-b-0\">\n\t\t\t\t\t\t<div>\n\t\t\t\t\t\t\t<div className=\"h-full\">\n\t\t\t\t\t\t\t\t<TouchedFiles\n\t\t\t\t\t\t\t\t\tdiffFilesPromise={data.diffFiles}\n\t\t\t\t\t\t\t\t\tcompact={leftWidthPx < 640}\n\t\t\t\t\t\t\t\t/>\n\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t</div>\n\t\t\t\t\t\t<EditFileOnGitHub\n\t\t\t\t\t\t\tappName={data.exerciseStepApp.name}\n\t\t\t\t\t\t\trelativePath={data.exerciseStepApp.relativePath}\n\t\t\t\t\t\t\tcompact={leftWidthPx < 720}\n\t\t\t\t\t\t/>\n\t\t\t\t\t\t<NavChevrons\n\t\t\t\t\t\t\tprev={\n\t\t\t\t\t\t\t\tdata.prevStepLink\n\t\t\t\t\t\t\t\t\t? {\n\t\t\t\t\t\t\t\t\t\t\tto: data.prevStepLink.to,\n\t\t\t\t\t\t\t\t\t\t\t'aria-label': 'Previous Step',\n\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t: null\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tnext={\n\t\t\t\t\t\t\t\tdata.nextStepLink\n\t\t\t\t\t\t\t\t\t? {\n\t\t\t\t\t\t\t\t\t\t\tto: data.nextStepLink.to,\n\t\t\t\t\t\t\t\t\t\t\t'aria-label': 'Next Step',\n\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t: null\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t/>\n\t\t\t\t\t</div>\n\t\t\t\t</div>\n\t\t\t\t<div\n\t\t\t\t\trole=\"separator\"\n\t\t\t\t\taria-orientation=\"vertical\"\n\t\t\t\t\ttitle=\"Drag to resize\"\n\t\t\t\t\tclassName=\"hidden w-1 cursor-col-resize bg-border hover:bg-accent lg:block\"\n\t\t\t\t\tonMouseDown={(e) => startDrag(e.clientX)}\n\t\t\t\t\tonDoubleClick={() => {\n\t\t\t\t\t\tsetSplitPercent(50)\n\t\t\t\t\t\tsetCookie(50)\n\t\t\t\t\t}}\n\t\t\t\t\tonTouchStart={(e) => {\n\t\t\t\t\t\tconst firstTouch = e.touches?.[0]\n\t\t\t\t\t\tif (firstTouch) startDrag(firstTouch.clientX)\n\t\t\t\t\t}}\n\t\t\t\t/>\n\t\t\t\t<div className=\"flex min-w-0 flex-1\">\n\t\t\t\t\t<Outlet />\n\t\t\t\t</div>\n\t\t\t</main>\n\t\t</div>\n\t)\n}\n\nexport function ErrorBoundary() {\n\treturn (\n\t\t<GeneralErrorBoundary\n\t\t\tstatusHandlers={{\n\t\t\t\t404: () => <p>Sorry, we couldn't find an app here.</p>,\n\t\t\t\t503: () => (\n\t\t\t\t\t<div>\n\t\t\t\t\t\t<h1>Service Unavailable</h1>\n\t\t\t\t\t\t<p>\n\t\t\t\t\t\t\tSorry, we're having a temporary problem. Please try again later.\n\t\t\t\t\t\t</p>\n\t\t\t\t\t\t<button onClick={() => window.location.reload()}>Refresh</button>\n\t\t\t\t\t</div>\n\t\t\t\t),\n\t\t\t}}\n\t\t/>\n\t)\n}\n"],"names":["StepContext","React.createContext","useStepContext","context","React.useContext","StepContextProvider","children","inBrowserBrowserRef","jsx","stepMdxComponents","DiffLink","PrevDiffLink","NextDiffLink","InlineFile","LinkToApp","StepMdx","data","useLoaderData","EpicVideoInfoProvider","Mdx","withParam","searchParams","key","value","newSearchParams","app","fullPage","app1","app2","to","getAppName","input","stepIndex","name","stepName","params","app1Name","app2Name","jsxs","pathToDiff","Link","file","type","props","info","iconsSvg","LaunchEditor","SimpleTooltip","getPreviewType","preview","appTo","useSearchParams","requestInfo","useRequestInfo","previewAppUrl","getBaseUrl","href","cn","event","Icon","POPOVER_NAME","createPopoverContext","createPopoverScope","createContextScope","createPopperScope","usePopperScope","PopoverProvider","usePopoverContext","Popover","__scopePopover","openProp","defaultOpen","onOpenChange","modal","popperScope","triggerRef","React.useRef","hasCustomAnchor","setHasCustomAnchor","React.useState","open","setOpen","useControllableState","PopperPrimitive.Root","useId","React.useCallback","prevOpen","ANCHOR_NAME","PopoverAnchor","React.forwardRef","forwardedRef","anchorProps","onCustomAnchorAdd","onCustomAnchorRemove","React.useEffect","PopperPrimitive.Anchor","TRIGGER_NAME","PopoverTrigger","triggerProps","composedTriggerRef","useComposedRefs","trigger","Primitive","getState","composeEventHandlers","PORTAL_NAME","PortalProvider","usePortalContext","PopoverPortal","forceMount","container","Presence","PortalPrimitive","CONTENT_NAME","PopoverContent","portalContext","contentProps","PopoverContentModal","PopoverContentNonModal","Slot","createSlot","contentRef","composedRefs","isRightClickOutsideRef","content","hideOthers","RemoveScroll","PopoverContentImpl","originalEvent","ctrlLeftClick","isRightClick","hasInteractedOutsideRef","hasPointerDownOutsideRef","target","trapFocus","onOpenAutoFocus","onCloseAutoFocus","disableOutsidePointerEvents","onEscapeKeyDown","onPointerDownOutside","onFocusOutside","onInteractOutside","useFocusGuards","FocusScope","DismissableLayer","PopperPrimitive.Content","CLOSE_NAME","PopoverClose","closeProps","ARROW_NAME","PopoverArrow","arrowProps","PopperPrimitive.Arrow","Root2","Trigger","Portal","Content2","TouchedFiles","diffFilesPromise","compact","handleLaunchUpdate","appName","Popover.Root","Popover.Trigger","Popover.Portal","Popover.Content","SetAppToPlayground","React.Suspense","Await","diffFiles","splitCookieName","computeSplitPercent","defaultValue","Number","isFinite","Math","min","max","round","pageTitle","workshopTitle","exerciseNumber","exerciseStepApp","toString","padStart","stepNumber","emoji","problem","solution","title","exerciseTitle","meta","matches","rootData","find","m","id","getSeoMetaTags","description","ogTitle","ogDescription","instructor","_layout","_UNSAFE_withComponentProps","loaderData","useRef","containerRef","leftPaneRef","splitPercent","setSplitPercent","useState","leftWidthPx","setLeftWidthPx","useEffect","left","current","ro","ResizeObserver","entries","entry","contentRect","width","observe","getBoundingClientRect","disconnect","setCookie","percent","clamped","document","cookie","startDrag","initialClientX","rect","dragging","iframes","Array","from","querySelectorAll","originalPointerEvents","map","el","style","pointerEvents","forEach","handleMove","clientX","cleanup","onMouseMove","e","buttons","onTouchMove","firstTouch","touches","i","window","removeEventListener","body","cursor","userSelect","addEventListener","titleBits","useRevalidationWS","watchPaths","relativePath","className","ref","getExercisePath","playground","articleId","instructionsCode","prevStepLink","prefetch","nextStepLink","ElementScrollRestoration","elementQuery","ProgressToggle","EditFileOnGitHub","NavChevrons","prev","next","role","onMouseDown","onDoubleClick","onTouchStart","Outlet","ErrorBoundary","_UNSAFE_withErrorBoundaryProps","GeneralErrorBoundary","statusHandlers","onClick","location","reload"],"mappings":"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","x_google_ignoreList":[1]}
1
+ {"version":3,"file":"_layout-CcWrk4kg.js","sources":["../../../app/routes/_app+/exercise+/$exerciseNumber_.$stepNumber.$type+/__shared/step-mdx.tsx","../../../../../node_modules/@radix-ui/react-popover/dist/index.mjs","../../../app/routes/_app+/exercise+/$exerciseNumber_.$stepNumber.$type+/__shared/touched-files.tsx","../../../app/routes/_app+/exercise+/$exerciseNumber_.$stepNumber.$type+/_layout.tsx"],"sourcesContent":["import * as React from 'react'\nimport { type PropsWithChildren } from 'react'\nimport {\n\tLink,\n\tuseLoaderData,\n\tuseSearchParams,\n\ttype LinkProps,\n} from 'react-router'\nimport iconsSvg from '#app/assets/icons.svg'\nimport { EpicVideoInfoProvider } from '#app/components/epic-video.tsx'\nimport { Icon } from '#app/components/icons.tsx'\nimport { type InBrowserBrowserRef } from '#app/components/in-browser-browser.tsx'\nimport { SimpleTooltip } from '#app/components/ui/tooltip.tsx'\nimport { LaunchEditor } from '#app/routes/launch-editor.tsx'\nimport { Mdx } from '#app/utils/mdx.tsx'\nimport { cn, getBaseUrl } from '#app/utils/misc.tsx'\nimport { useRequestInfo } from '#app/utils/request-info.ts'\nimport { type loader } from '../_layout.tsx'\n\ntype StepContextType = {\n\tinBrowserBrowserRef: React.RefObject<InBrowserBrowserRef | null>\n}\nconst StepContext = React.createContext<StepContextType | null>(null)\n\nfunction useStepContext() {\n\tconst context = React.useContext(StepContext)\n\tif (!context) {\n\t\tthrow new Error('useStepContext must be used within a StepContext.Provider')\n\t}\n\treturn context\n}\n\nfunction StepContextProvider({\n\tchildren,\n\tinBrowserBrowserRef,\n}: {\n\tchildren: React.ReactNode\n\tinBrowserBrowserRef: React.RefObject<InBrowserBrowserRef | null>\n}) {\n\treturn (\n\t\t<StepContext.Provider value={{ inBrowserBrowserRef }}>\n\t\t\t{children}\n\t\t</StepContext.Provider>\n\t)\n}\n\nconst stepMdxComponents = {\n\tDiffLink,\n\tPrevDiffLink,\n\tNextDiffLink,\n\tInlineFile,\n\tLinkToApp,\n}\n\nexport function StepMdx({\n\tinBrowserBrowserRef,\n}: {\n\tinBrowserBrowserRef: React.RefObject<InBrowserBrowserRef | null>\n}) {\n\tconst data = useLoaderData<typeof loader>()\n\tif (!data.exerciseStepApp.instructionsCode) return null\n\treturn (\n\t\t<StepContextProvider inBrowserBrowserRef={inBrowserBrowserRef}>\n\t\t\t<EpicVideoInfoProvider epicVideoInfosPromise={data.epicVideoInfosPromise}>\n\t\t\t\t<div className=\"prose dark:prose-invert sm:prose-lg\">\n\t\t\t\t\t<Mdx\n\t\t\t\t\t\tcode={data.exerciseStepApp.instructionsCode}\n\t\t\t\t\t\tcomponents={stepMdxComponents}\n\t\t\t\t\t/>\n\t\t\t\t</div>\n\t\t\t</EpicVideoInfoProvider>\n\t\t</StepContextProvider>\n\t)\n}\n\nfunction withParam(\n\tsearchParams: URLSearchParams,\n\tkey: string,\n\tvalue: string | null,\n) {\n\tconst newSearchParams = new URLSearchParams(searchParams)\n\tif (value === null) {\n\t\tnewSearchParams.delete(key)\n\t} else {\n\t\tnewSearchParams.set(key, value)\n\t}\n\treturn newSearchParams\n}\n\nfunction NextDiffLink({\n\tapp = 0,\n\tfullPage = false,\n\tchildren,\n}: {\n\tapp: number\n\tfullPage?: boolean\n\tchildren?: React.ReactNode\n}) {\n\treturn (\n\t\t<DiffLink app1={app} app2={app + 1} fullPage={fullPage}>\n\t\t\t{children}\n\t\t</DiffLink>\n\t)\n}\n\nfunction PrevDiffLink({\n\tapp = -1,\n\tfullPage = false,\n\tchildren,\n}: {\n\tapp: number\n\tfullPage?: boolean\n\tchildren?: React.ReactNode\n}) {\n\treturn (\n\t\t<DiffLink app1={app} app2={app + 1} fullPage={fullPage}>\n\t\t\t{children}\n\t\t</DiffLink>\n\t)\n}\n\nfunction DiffLink({\n\tapp1 = 0,\n\tapp2 = 1,\n\tchildren,\n\tfullPage = false,\n\tto,\n}: {\n\tapp1?: string | number | null\n\tapp2?: string | number | null\n\tto?: string\n\tfullPage?: boolean\n\tchildren?: React.ReactNode\n}) {\n\tconst data = useLoaderData<typeof loader>()\n\tif (!to && !app1 && !app2) {\n\t\treturn (\n\t\t\t// @ts-expect-error 🤷‍♂️\n\t\t\t<callout-danger className=\"notification\">\n\t\t\t\t<div className=\"title\">DiffLink Error: invalid input</div>\n\t\t\t\t{/* @ts-expect-error 🤷‍♂️ */}\n\t\t\t</callout-danger>\n\t\t)\n\t}\n\n\tfunction getAppName(input: typeof app1) {\n\t\tif (typeof input === 'number') {\n\t\t\tconst stepIndex = data.exerciseIndex + input\n\t\t\treturn data.allApps[stepIndex]?.name\n\t\t}\n\t\tif (!input) return null\n\t\tfor (const { name, stepName } of data.allApps) {\n\t\t\tif (input === name || input === stepName) {\n\t\t\t\treturn name\n\t\t\t}\n\t\t}\n\t\treturn null\n\t}\n\n\tif (to) {\n\t\tconst params = new URLSearchParams(to)\n\t\tapp1 = params.get('app1')\n\t\tapp2 = params.get('app2')\n\t}\n\tconst app1Name = getAppName(app1)\n\tconst app2Name = getAppName(app2)\n\tif (!app1Name || !app2Name) {\n\t\treturn (\n\t\t\t// @ts-expect-error 🤷‍♂️\n\t\t\t<callout-danger className=\"notification\">\n\t\t\t\t<div className=\"title\">DiffLink Error: invalid input</div>\n\t\t\t\t{!app1Name && <div>app1: \"{app1}\" is not a valid app name</div>}\n\t\t\t\t{!app2Name && <div>app2: \"{app2}\" is not a valid app name</div>}\n\t\t\t\t{/* @ts-expect-error 🤷‍♂️ */}\n\t\t\t</callout-danger>\n\t\t)\n\t}\n\n\tif (!to) {\n\t\tto = `app1=${app1Name}&app2=${app2Name}`\n\t}\n\tconst pathToDiff = fullPage\n\t\t? `/diff?${to}`\n\t\t: `?${decodeURIComponent(\n\t\t\t\twithParam(new URLSearchParams(), 'preview', `diff&${to}`).toString(),\n\t\t\t)}`\n\n\tif (!children) {\n\t\tchildren = (\n\t\t\t<span>\n\t\t\t\tGo to Diff {fullPage ? '' : 'Preview'} from: <code>{app1Name}</code> to:{' '}\n\t\t\t\t<code>{app2Name}</code>\n\t\t\t</span>\n\t\t)\n\t}\n\n\treturn <Link to={pathToDiff}>{children}</Link>\n}\n\nfunction InlineFile({\n\tfile,\n\ttype = 'playground',\n\tchildren = <code>{file}</code>,\n\t...props\n}: Omit<PropsWithChildren<typeof LaunchEditor>, 'appName'> & {\n\tfile: string\n\ttype?: 'playground' | 'solution' | 'problem'\n}) {\n\tconst data = useLoaderData<typeof loader>()\n\tconst app = data[type] || data[data.type]\n\n\tconst info = (\n\t\t<div className=\"launch-editor-button-wrapper flex underline underline-offset-4\">\n\t\t\t{children}{' '}\n\t\t\t<svg height={24} width={24}>\n\t\t\t\t<use href={`${iconsSvg}#Keyboard`} />\n\t\t\t</svg>\n\t\t</div>\n\t)\n\n\treturn ENV.EPICSHOP_DEPLOYED && app ? (\n\t\t<div className=\"inline-block grow\">\n\t\t\t<LaunchEditor appFile={file} appName={app.name} {...props}>\n\t\t\t\t{info}\n\t\t\t</LaunchEditor>\n\t\t</div>\n\t) : app ? (\n\t\t<div className=\"inline-block grow\">\n\t\t\t<LaunchEditor appFile={file} appName={app.name} {...props}>\n\t\t\t\t{info}\n\t\t\t</LaunchEditor>\n\t\t</div>\n\t) : type === 'playground' ? (\n\t\t// playground does not exist yet\n\t\t<SimpleTooltip content=\"You must 'Set to Playground' before opening a file\">\n\t\t\t<div className=\"inline-block grow cursor-not-allowed\">{info}</div>\n\t\t</SimpleTooltip>\n\t) : (\n\t\t<>children</>\n\t)\n}\n\nfunction getPreviewType(\n\tpreview: string | null,\n): 'playground' | 'problem' | 'solution' {\n\tif (preview === 'problem') return 'problem'\n\tif (preview === 'solution') return 'solution'\n\treturn 'playground'\n}\n\nfunction LinkToApp({\n\tto: appTo,\n\tchildren = <code>{appTo.toString()}</code>,\n\t...props\n}: LinkProps) {\n\tconst [searchParams] = useSearchParams()\n\tconst to = `?${withParam(\n\t\tsearchParams,\n\t\t'pathname',\n\t\tappTo.toString(),\n\t).toString()}`\n\tconst data = useLoaderData<typeof loader>()\n\tconst type = getPreviewType(searchParams.get('preview'))\n\tconst requestInfo = useRequestInfo()\n\tconst app = data[type]\n\tconst previewAppUrl =\n\t\tapp?.dev.type === 'script'\n\t\t\t? getBaseUrl({\n\t\t\t\t\tdomain: requestInfo.domain,\n\t\t\t\t\tport: app.dev.portNumber,\n\t\t\t\t})\n\t\t\t: data.playground?.dev.type === 'browser'\n\t\t\t\t? data.playground.dev.pathname\n\t\t\t\t: null\n\tconst { inBrowserBrowserRef } = useStepContext()\n\tconst href = previewAppUrl\n\t\t? previewAppUrl.slice(0, -1) + appTo.toString()\n\t\t: null\n\treturn (\n\t\t<div className=\"inline-flex items-center justify-between gap-1\">\n\t\t\t<Link\n\t\t\t\tto={to}\n\t\t\t\t{...props}\n\t\t\t\tclassName={cn(props.className, {\n\t\t\t\t\t'cursor-not-allowed': ENV.EPICSHOP_DEPLOYED,\n\t\t\t\t})}\n\t\t\t\ttitle={\n\t\t\t\t\tENV.EPICSHOP_DEPLOYED\n\t\t\t\t\t\t? 'Cannot link to app in deployed version'\n\t\t\t\t\t\t: undefined\n\t\t\t\t}\n\t\t\t\tonClick={(event) => {\n\t\t\t\t\tif (ENV.EPICSHOP_DEPLOYED) event.preventDefault()\n\n\t\t\t\t\tprops.onClick?.(event)\n\t\t\t\t\tinBrowserBrowserRef.current?.handleExtrnalNavigation(appTo.toString())\n\t\t\t\t}}\n\t\t\t>\n\t\t\t\t{children}\n\t\t\t</Link>\n\t\t\t{href ? (\n\t\t\t\t<SimpleTooltip content=\"Open in new tab\">\n\t\t\t\t\t<a\n\t\t\t\t\t\thref={href}\n\t\t\t\t\t\ttarget=\"_blank\"\n\t\t\t\t\t\trel=\"noreferrer\"\n\t\t\t\t\t\tclassName={cn('flex aspect-square items-center justify-center', {\n\t\t\t\t\t\t\t'cursor-not-allowed': ENV.EPICSHOP_DEPLOYED,\n\t\t\t\t\t\t})}\n\t\t\t\t\t\ttitle={\n\t\t\t\t\t\t\tENV.EPICSHOP_DEPLOYED\n\t\t\t\t\t\t\t\t? 'Cannot link to app in deployed version'\n\t\t\t\t\t\t\t\t: 'Open in new tab'\n\t\t\t\t\t\t}\n\t\t\t\t\t\tonClick={(event) => {\n\t\t\t\t\t\t\tif (ENV.EPICSHOP_DEPLOYED) event.preventDefault()\n\t\t\t\t\t\t}}\n\t\t\t\t\t>\n\t\t\t\t\t\t<Icon name=\"ExternalLink\" />\n\t\t\t\t\t</a>\n\t\t\t\t</SimpleTooltip>\n\t\t\t) : null}\n\t\t</div>\n\t)\n}\n","\"use client\";\n\n// src/popover.tsx\nimport * as React from \"react\";\nimport { composeEventHandlers } from \"@radix-ui/primitive\";\nimport { useComposedRefs } from \"@radix-ui/react-compose-refs\";\nimport { createContextScope } from \"@radix-ui/react-context\";\nimport { DismissableLayer } from \"@radix-ui/react-dismissable-layer\";\nimport { useFocusGuards } from \"@radix-ui/react-focus-guards\";\nimport { FocusScope } from \"@radix-ui/react-focus-scope\";\nimport { useId } from \"@radix-ui/react-id\";\nimport * as PopperPrimitive from \"@radix-ui/react-popper\";\nimport { createPopperScope } from \"@radix-ui/react-popper\";\nimport { Portal as PortalPrimitive } from \"@radix-ui/react-portal\";\nimport { Presence } from \"@radix-ui/react-presence\";\nimport { Primitive } from \"@radix-ui/react-primitive\";\nimport { createSlot } from \"@radix-ui/react-slot\";\nimport { useControllableState } from \"@radix-ui/react-use-controllable-state\";\nimport { hideOthers } from \"aria-hidden\";\nimport { RemoveScroll } from \"react-remove-scroll\";\nimport { jsx } from \"react/jsx-runtime\";\nvar POPOVER_NAME = \"Popover\";\nvar [createPopoverContext, createPopoverScope] = createContextScope(POPOVER_NAME, [\n createPopperScope\n]);\nvar usePopperScope = createPopperScope();\nvar [PopoverProvider, usePopoverContext] = createPopoverContext(POPOVER_NAME);\nvar Popover = (props) => {\n const {\n __scopePopover,\n children,\n open: openProp,\n defaultOpen,\n onOpenChange,\n modal = false\n } = props;\n const popperScope = usePopperScope(__scopePopover);\n const triggerRef = React.useRef(null);\n const [hasCustomAnchor, setHasCustomAnchor] = React.useState(false);\n const [open, setOpen] = useControllableState({\n prop: openProp,\n defaultProp: defaultOpen ?? false,\n onChange: onOpenChange,\n caller: POPOVER_NAME\n });\n return /* @__PURE__ */ jsx(PopperPrimitive.Root, { ...popperScope, children: /* @__PURE__ */ jsx(\n PopoverProvider,\n {\n scope: __scopePopover,\n contentId: useId(),\n triggerRef,\n open,\n onOpenChange: setOpen,\n onOpenToggle: React.useCallback(() => setOpen((prevOpen) => !prevOpen), [setOpen]),\n hasCustomAnchor,\n onCustomAnchorAdd: React.useCallback(() => setHasCustomAnchor(true), []),\n onCustomAnchorRemove: React.useCallback(() => setHasCustomAnchor(false), []),\n modal,\n children\n }\n ) });\n};\nPopover.displayName = POPOVER_NAME;\nvar ANCHOR_NAME = \"PopoverAnchor\";\nvar PopoverAnchor = React.forwardRef(\n (props, forwardedRef) => {\n const { __scopePopover, ...anchorProps } = props;\n const context = usePopoverContext(ANCHOR_NAME, __scopePopover);\n const popperScope = usePopperScope(__scopePopover);\n const { onCustomAnchorAdd, onCustomAnchorRemove } = context;\n React.useEffect(() => {\n onCustomAnchorAdd();\n return () => onCustomAnchorRemove();\n }, [onCustomAnchorAdd, onCustomAnchorRemove]);\n return /* @__PURE__ */ jsx(PopperPrimitive.Anchor, { ...popperScope, ...anchorProps, ref: forwardedRef });\n }\n);\nPopoverAnchor.displayName = ANCHOR_NAME;\nvar TRIGGER_NAME = \"PopoverTrigger\";\nvar PopoverTrigger = React.forwardRef(\n (props, forwardedRef) => {\n const { __scopePopover, ...triggerProps } = props;\n const context = usePopoverContext(TRIGGER_NAME, __scopePopover);\n const popperScope = usePopperScope(__scopePopover);\n const composedTriggerRef = useComposedRefs(forwardedRef, context.triggerRef);\n const trigger = /* @__PURE__ */ jsx(\n Primitive.button,\n {\n type: \"button\",\n \"aria-haspopup\": \"dialog\",\n \"aria-expanded\": context.open,\n \"aria-controls\": context.contentId,\n \"data-state\": getState(context.open),\n ...triggerProps,\n ref: composedTriggerRef,\n onClick: composeEventHandlers(props.onClick, context.onOpenToggle)\n }\n );\n return context.hasCustomAnchor ? trigger : /* @__PURE__ */ jsx(PopperPrimitive.Anchor, { asChild: true, ...popperScope, children: trigger });\n }\n);\nPopoverTrigger.displayName = TRIGGER_NAME;\nvar PORTAL_NAME = \"PopoverPortal\";\nvar [PortalProvider, usePortalContext] = createPopoverContext(PORTAL_NAME, {\n forceMount: void 0\n});\nvar PopoverPortal = (props) => {\n const { __scopePopover, forceMount, children, container } = props;\n const context = usePopoverContext(PORTAL_NAME, __scopePopover);\n return /* @__PURE__ */ jsx(PortalProvider, { scope: __scopePopover, forceMount, children: /* @__PURE__ */ jsx(Presence, { present: forceMount || context.open, children: /* @__PURE__ */ jsx(PortalPrimitive, { asChild: true, container, children }) }) });\n};\nPopoverPortal.displayName = PORTAL_NAME;\nvar CONTENT_NAME = \"PopoverContent\";\nvar PopoverContent = React.forwardRef(\n (props, forwardedRef) => {\n const portalContext = usePortalContext(CONTENT_NAME, props.__scopePopover);\n const { forceMount = portalContext.forceMount, ...contentProps } = props;\n const context = usePopoverContext(CONTENT_NAME, props.__scopePopover);\n return /* @__PURE__ */ jsx(Presence, { present: forceMount || context.open, children: context.modal ? /* @__PURE__ */ jsx(PopoverContentModal, { ...contentProps, ref: forwardedRef }) : /* @__PURE__ */ jsx(PopoverContentNonModal, { ...contentProps, ref: forwardedRef }) });\n }\n);\nPopoverContent.displayName = CONTENT_NAME;\nvar Slot = createSlot(\"PopoverContent.RemoveScroll\");\nvar PopoverContentModal = React.forwardRef(\n (props, forwardedRef) => {\n const context = usePopoverContext(CONTENT_NAME, props.__scopePopover);\n const contentRef = React.useRef(null);\n const composedRefs = useComposedRefs(forwardedRef, contentRef);\n const isRightClickOutsideRef = React.useRef(false);\n React.useEffect(() => {\n const content = contentRef.current;\n if (content) return hideOthers(content);\n }, []);\n return /* @__PURE__ */ jsx(RemoveScroll, { as: Slot, allowPinchZoom: true, children: /* @__PURE__ */ jsx(\n PopoverContentImpl,\n {\n ...props,\n ref: composedRefs,\n trapFocus: context.open,\n disableOutsidePointerEvents: true,\n onCloseAutoFocus: composeEventHandlers(props.onCloseAutoFocus, (event) => {\n event.preventDefault();\n if (!isRightClickOutsideRef.current) context.triggerRef.current?.focus();\n }),\n onPointerDownOutside: composeEventHandlers(\n props.onPointerDownOutside,\n (event) => {\n const originalEvent = event.detail.originalEvent;\n const ctrlLeftClick = originalEvent.button === 0 && originalEvent.ctrlKey === true;\n const isRightClick = originalEvent.button === 2 || ctrlLeftClick;\n isRightClickOutsideRef.current = isRightClick;\n },\n { checkForDefaultPrevented: false }\n ),\n onFocusOutside: composeEventHandlers(\n props.onFocusOutside,\n (event) => event.preventDefault(),\n { checkForDefaultPrevented: false }\n )\n }\n ) });\n }\n);\nvar PopoverContentNonModal = React.forwardRef(\n (props, forwardedRef) => {\n const context = usePopoverContext(CONTENT_NAME, props.__scopePopover);\n const hasInteractedOutsideRef = React.useRef(false);\n const hasPointerDownOutsideRef = React.useRef(false);\n return /* @__PURE__ */ jsx(\n PopoverContentImpl,\n {\n ...props,\n ref: forwardedRef,\n trapFocus: false,\n disableOutsidePointerEvents: false,\n onCloseAutoFocus: (event) => {\n props.onCloseAutoFocus?.(event);\n if (!event.defaultPrevented) {\n if (!hasInteractedOutsideRef.current) context.triggerRef.current?.focus();\n event.preventDefault();\n }\n hasInteractedOutsideRef.current = false;\n hasPointerDownOutsideRef.current = false;\n },\n onInteractOutside: (event) => {\n props.onInteractOutside?.(event);\n if (!event.defaultPrevented) {\n hasInteractedOutsideRef.current = true;\n if (event.detail.originalEvent.type === \"pointerdown\") {\n hasPointerDownOutsideRef.current = true;\n }\n }\n const target = event.target;\n const targetIsTrigger = context.triggerRef.current?.contains(target);\n if (targetIsTrigger) event.preventDefault();\n if (event.detail.originalEvent.type === \"focusin\" && hasPointerDownOutsideRef.current) {\n event.preventDefault();\n }\n }\n }\n );\n }\n);\nvar PopoverContentImpl = React.forwardRef(\n (props, forwardedRef) => {\n const {\n __scopePopover,\n trapFocus,\n onOpenAutoFocus,\n onCloseAutoFocus,\n disableOutsidePointerEvents,\n onEscapeKeyDown,\n onPointerDownOutside,\n onFocusOutside,\n onInteractOutside,\n ...contentProps\n } = props;\n const context = usePopoverContext(CONTENT_NAME, __scopePopover);\n const popperScope = usePopperScope(__scopePopover);\n useFocusGuards();\n return /* @__PURE__ */ jsx(\n FocusScope,\n {\n asChild: true,\n loop: true,\n trapped: trapFocus,\n onMountAutoFocus: onOpenAutoFocus,\n onUnmountAutoFocus: onCloseAutoFocus,\n children: /* @__PURE__ */ jsx(\n DismissableLayer,\n {\n asChild: true,\n disableOutsidePointerEvents,\n onInteractOutside,\n onEscapeKeyDown,\n onPointerDownOutside,\n onFocusOutside,\n onDismiss: () => context.onOpenChange(false),\n children: /* @__PURE__ */ jsx(\n PopperPrimitive.Content,\n {\n \"data-state\": getState(context.open),\n role: \"dialog\",\n id: context.contentId,\n ...popperScope,\n ...contentProps,\n ref: forwardedRef,\n style: {\n ...contentProps.style,\n // re-namespace exposed content custom properties\n ...{\n \"--radix-popover-content-transform-origin\": \"var(--radix-popper-transform-origin)\",\n \"--radix-popover-content-available-width\": \"var(--radix-popper-available-width)\",\n \"--radix-popover-content-available-height\": \"var(--radix-popper-available-height)\",\n \"--radix-popover-trigger-width\": \"var(--radix-popper-anchor-width)\",\n \"--radix-popover-trigger-height\": \"var(--radix-popper-anchor-height)\"\n }\n }\n }\n )\n }\n )\n }\n );\n }\n);\nvar CLOSE_NAME = \"PopoverClose\";\nvar PopoverClose = React.forwardRef(\n (props, forwardedRef) => {\n const { __scopePopover, ...closeProps } = props;\n const context = usePopoverContext(CLOSE_NAME, __scopePopover);\n return /* @__PURE__ */ jsx(\n Primitive.button,\n {\n type: \"button\",\n ...closeProps,\n ref: forwardedRef,\n onClick: composeEventHandlers(props.onClick, () => context.onOpenChange(false))\n }\n );\n }\n);\nPopoverClose.displayName = CLOSE_NAME;\nvar ARROW_NAME = \"PopoverArrow\";\nvar PopoverArrow = React.forwardRef(\n (props, forwardedRef) => {\n const { __scopePopover, ...arrowProps } = props;\n const popperScope = usePopperScope(__scopePopover);\n return /* @__PURE__ */ jsx(PopperPrimitive.Arrow, { ...popperScope, ...arrowProps, ref: forwardedRef });\n }\n);\nPopoverArrow.displayName = ARROW_NAME;\nfunction getState(open) {\n return open ? \"open\" : \"closed\";\n}\nvar Root2 = Popover;\nvar Anchor2 = PopoverAnchor;\nvar Trigger = PopoverTrigger;\nvar Portal = PopoverPortal;\nvar Content2 = PopoverContent;\nvar Close = PopoverClose;\nvar Arrow2 = PopoverArrow;\nexport {\n Anchor2 as Anchor,\n Arrow2 as Arrow,\n Close,\n Content2 as Content,\n Popover,\n PopoverAnchor,\n PopoverArrow,\n PopoverClose,\n PopoverContent,\n PopoverPortal,\n PopoverTrigger,\n Portal,\n Root2 as Root,\n Trigger,\n createPopoverScope\n};\n//# sourceMappingURL=index.mjs.map\n","import * as Popover from '@radix-ui/react-popover'\nimport * as React from 'react'\nimport { Await, useLoaderData } from 'react-router'\nimport { Icon } from '#app/components/icons.tsx'\nimport { SimpleTooltip } from '#app/components/ui/tooltip.tsx'\nimport { LaunchEditor } from '#app/routes/launch-editor.tsx'\nimport { SetAppToPlayground } from '#app/routes/set-playground.tsx'\nimport { type Route as LayoutRoute } from '../+types/_layout.tsx'\n\nfunction TouchedFiles({\n\tdiffFilesPromise,\n\tcompact = false,\n}: {\n\tdiffFilesPromise: LayoutRoute.ComponentProps['loaderData']['diffFiles']\n\tcompact?: boolean\n}) {\n\tconst data = useLoaderData<LayoutRoute.ComponentProps['loaderData']>()\n\n\tconst [open, setOpen] = React.useState(false)\n\tconst contentRef = React.useRef<HTMLDivElement>(null)\n\n\tfunction handleLaunchUpdate() {\n\t\tsetOpen(false)\n\t}\n\n\tconst appName = data.playground?.appName\n\n\treturn (\n\t\t<>\n\t\t\t<Popover.Root open={open} onOpenChange={setOpen}>\n\t\t\t\t<Popover.Trigger asChild>\n\t\t\t\t\t<button\n\t\t\t\t\t\tclassName=\"flex h-full items-center gap-1 border-r px-6 py-3 font-mono text-sm uppercase\"\n\t\t\t\t\t\taria-label=\"Relevant Files\"\n\t\t\t\t\t>\n\t\t\t\t\t\t<Icon name=\"Files\" />\n\t\t\t\t\t\t{compact ? null : <span className=\"hidden xl:inline\">Files</span>}\n\t\t\t\t\t</button>\n\t\t\t\t</Popover.Trigger>\n\t\t\t\t<Popover.Portal>\n\t\t\t\t\t<Popover.Content\n\t\t\t\t\t\tref={contentRef}\n\t\t\t\t\t\tclassName=\"slideRightContent lg:slideUpContent invert-theme z-10 select-none rounded bg-background px-9 py-8 text-foreground\"\n\t\t\t\t\t\talign=\"start\"\n\t\t\t\t\t\tsideOffset={5}\n\t\t\t\t\t>\n\t\t\t\t\t\t<div className=\"launch-editor-wrapper\">\n\t\t\t\t\t\t\t<strong className=\"inline-block px-2 pb-4 font-semibold uppercase\">\n\t\t\t\t\t\t\t\tRelevant Files\n\t\t\t\t\t\t\t</strong>\n\t\t\t\t\t\t\t{data.problem &&\n\t\t\t\t\t\t\tdata.playground?.appName !== data.problem.name ? (\n\t\t\t\t\t\t\t\t<div className=\"mb-2 rounded p-1 font-mono font-medium\">\n\t\t\t\t\t\t\t\t\t<SetAppToPlayground appName={data.problem.name} />\n\t\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t\t) : null}\n\t\t\t\t\t\t\t<div id=\"files\">\n\t\t\t\t\t\t\t\t<React.Suspense\n\t\t\t\t\t\t\t\t\tfallback={\n\t\t\t\t\t\t\t\t\t\t<SimpleTooltip content=\"Loading diff\">\n\t\t\t\t\t\t\t\t\t\t\t<div className=\"flex justify-center\">\n\t\t\t\t\t\t\t\t\t\t\t\t<Icon name=\"Refresh\" className=\"h-8 w-8 animate-spin\" />\n\t\t\t\t\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t\t\t\t\t</SimpleTooltip>\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<Await\n\t\t\t\t\t\t\t\t\t\tresolve={diffFilesPromise}\n\t\t\t\t\t\t\t\t\t\terrorElement={\n\t\t\t\t\t\t\t\t\t\t\t<div className=\"text-foreground-destructive\">\n\t\t\t\t\t\t\t\t\t\t\t\tSomething went wrong.\n\t\t\t\t\t\t\t\t\t\t\t</div>\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{(diffFiles) => {\n\t\t\t\t\t\t\t\t\t\t\tif (!diffFiles) {\n\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<p className=\"text-foreground-destructive\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\tUnable to determine diff\n\t\t\t\t\t\t\t\t\t\t\t\t\t</p>\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\tif (typeof diffFiles === 'string') {\n\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<p className=\"text-foreground-destructive\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t{diffFiles}\n\t\t\t\t\t\t\t\t\t\t\t\t\t</p>\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\tif (!diffFiles.length) {\n\t\t\t\t\t\t\t\t\t\t\t\treturn <p>No files changed</p>\n\t\t\t\t\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\t\t\t\t\tconst props =\n\t\t\t\t\t\t\t\t\t\t\t\tappName || ENV.EPICSHOP_GITHUB_ROOT\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: {\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\ttitle:\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\"You must 'Set to Playground' before opening a file\",\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tclassName: 'not-allowed',\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\treturn (\n\t\t\t\t\t\t\t\t\t\t\t\t<ul {...props}>\n\t\t\t\t\t\t\t\t\t\t\t\t\t{diffFiles.length > 1 && !ENV.EPICSHOP_DEPLOYED ? (\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t<div className=\"mb-2 border-b border-b-gray-50 border-opacity-50 pb-2 font-sans\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<LaunchEditor\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tappFile={diffFiles.map(\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t(file) => `${file.path},${file.line},1`,\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\tappName=\"playground\"\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tonUpdate={handleLaunchUpdate}\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\t\t<p>Open All Files</p>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</LaunchEditor>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t\t\t\t\t\t\t\t) : null}\n\t\t\t\t\t\t\t\t\t\t\t\t\t{diffFiles.map((file) => (\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t<li key={file.path} data-state={file.status}>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<LaunchEditor\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tappFile={`${file.path},${file.line},1`}\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tappName={\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tENV.EPICSHOP_DEPLOYED\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t? (data.problem?.name ?? 'playground')\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t: 'playground'\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\tonUpdate={handleLaunchUpdate}\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\t\t<code>{file.path}</code>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</LaunchEditor>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t</li>\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</ul>\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</Await>\n\t\t\t\t\t\t\t\t</React.Suspense>\n\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t</div>\n\t\t\t\t\t</Popover.Content>\n\t\t\t\t</Popover.Portal>\n\t\t\t</Popover.Root>\n\t\t</>\n\t)\n}\n\nexport default TouchedFiles\n","import { ElementScrollRestoration } from '@epic-web/restore-scroll'\nimport {\n\tgetAppDisplayName,\n\tgetAppPageRoute,\n\tgetApps,\n\tgetExerciseApp,\n\tgetNextExerciseApp,\n\tgetPrevExerciseApp,\n\tisExerciseStepApp,\n\tisPlaygroundApp,\n\trequireExercise,\n\trequireExerciseApp,\n\ttype App,\n\ttype ExerciseStepApp,\n} from '@epic-web/workshop-utils/apps.server'\nimport { getWorkshopConfig } from '@epic-web/workshop-utils/config.server'\nimport { getDiffFiles } from '@epic-web/workshop-utils/diff.server'\nimport { getEpicVideoInfos } from '@epic-web/workshop-utils/epic-api.server'\nimport {\n\tcombineServerTimings,\n\tgetServerTimeHeader,\n\tmakeTimings,\n} from '@epic-web/workshop-utils/timing.server'\nimport slugify from '@sindresorhus/slugify'\nimport * as cookie from 'cookie'\nimport { useEffect, useRef, useState } from 'react'\nimport {\n\tdata,\n\tredirect,\n\ttype HeadersFunction,\n\tLink,\n\tOutlet,\n} from 'react-router'\nimport { GeneralErrorBoundary } from '#app/components/error-boundary.tsx'\nimport { type InBrowserBrowserRef } from '#app/components/in-browser-browser.tsx'\nimport { NavChevrons } from '#app/components/nav-chevrons.tsx'\nimport { useRevalidationWS } from '#app/components/revalidation-ws.js'\nimport { type RootLoaderData } from '#app/root.tsx'\nimport { EditFileOnGitHub } from '#app/routes/launch-editor.tsx'\nimport { ProgressToggle } from '#app/routes/progress.tsx'\nimport { SetAppToPlayground } from '#app/routes/set-playground.tsx'\nimport { getExercisePath } from '#app/utils/misc.tsx'\nimport { getSeoMetaTags } from '#app/utils/seo.js'\nimport { type Route } from './+types/_layout.tsx'\nimport { StepMdx } from './__shared/step-mdx.tsx'\nimport TouchedFiles from './__shared/touched-files.tsx'\n\n// shared split state helpers\nconst splitCookieName = 'es_split_pct'\nfunction computeSplitPercent(input: unknown, defaultValue = 50): number {\n\tconst value = typeof input === 'number' ? input : Number(input)\n\tif (Number.isFinite(value)) {\n\t\treturn Math.min(80, Math.max(20, Math.round(value * 100) / 100))\n\t}\n\treturn defaultValue\n}\n\nfunction pageTitle(\n\tdata: Awaited<Route.ComponentProps['loaderData']> | undefined,\n\tworkshopTitle?: string,\n) {\n\tconst exerciseNumber =\n\t\tdata?.exerciseStepApp.exerciseNumber.toString().padStart(2, '0') ?? '00'\n\tconst stepNumber =\n\t\tdata?.exerciseStepApp.stepNumber.toString().padStart(2, '0') ?? '00'\n\tconst emoji = (\n\t\t{\n\t\t\tproblem: '💪',\n\t\t\tsolution: '🏁',\n\t\t} as const\n\t)[data?.type ?? 'problem']\n\tconst title = data?.[data.type]?.title ?? 'N/A'\n\treturn {\n\t\temoji,\n\t\tstepNumber,\n\t\ttitle,\n\t\texerciseNumber,\n\t\texerciseTitle: data?.exerciseTitle ?? 'Unknown exercise',\n\t\tworkshopTitle,\n\t\ttype: data?.type ?? 'problem',\n\t}\n}\n\nexport const meta: Route.MetaFunction = ({ data, matches, params }) => {\n\tconst rootData = matches.find((m) => m?.id === 'root')?.data as RootLoaderData\n\tif (!data || !rootData) return [{ title: '🦉 | Error' }]\n\tconst { emoji, stepNumber, title, exerciseNumber, exerciseTitle } =\n\t\tpageTitle(data)\n\n\treturn getSeoMetaTags({\n\t\ttitle: `${emoji} | ${stepNumber}. ${title} | ${exerciseNumber}. ${exerciseTitle} | ${rootData.workshopTitle}`,\n\t\tdescription: `${params.type} step for exercise ${exerciseNumber}. ${exerciseTitle}`,\n\t\togTitle: title,\n\t\togDescription: `${exerciseTitle} step ${Number(stepNumber)} ${params.type}`,\n\t\tinstructor: rootData.instructor,\n\t\trequestInfo: rootData.requestInfo,\n\t})\n}\n\nexport async function loader({ request, params }: Route.LoaderArgs) {\n\tconst timings = makeTimings('exerciseStepTypeLayoutLoader')\n\tconst url = new URL(request.url)\n\tconst { title: workshopTitle } = getWorkshopConfig()\n\n\tconst cacheOptions = { request, timings }\n\n\tconst [exerciseStepApp, allAppsFull, problemApp, solutionApp] =\n\t\tawait Promise.all([\n\t\t\trequireExerciseApp(params, cacheOptions),\n\t\t\tgetApps(cacheOptions),\n\t\t\tgetExerciseApp({ ...params, type: 'problem' }, cacheOptions),\n\t\t\tgetExerciseApp({ ...params, type: 'solution' }, cacheOptions),\n\t\t])\n\n\tconst reqUrl = new URL(request.url)\n\tconst pathnameParam = reqUrl.searchParams.get('pathname')\n\tif (pathnameParam === '' || pathnameParam === '/') {\n\t\treqUrl.searchParams.delete('pathname')\n\t\tthrow redirect(reqUrl.toString())\n\t}\n\n\tif (!problemApp && !solutionApp) {\n\t\tthrow new Response('Not found', { status: 404 })\n\t}\n\n\tconst playgroundApp = allAppsFull.find(isPlaygroundApp)\n\n\tfunction getStepId(a: ExerciseStepApp) {\n\t\treturn (\n\t\t\ta.exerciseNumber * 1000 +\n\t\t\ta.stepNumber * 10 +\n\t\t\t(a.type === 'problem' ? 0 : 1)\n\t\t)\n\t}\n\n\tfunction getStepNameAndId(a: App) {\n\t\tif (isExerciseStepApp(a)) {\n\t\t\tconst exerciseNumberStr = String(a.exerciseNumber).padStart(2, '0')\n\t\t\tconst stepNumberStr = String(a.stepNumber).padStart(2, '0')\n\n\t\t\treturn {\n\t\t\t\tstepName: `${exerciseNumberStr}/${stepNumberStr}.${a.type}`,\n\t\t\t\tstepId: getStepId(a),\n\t\t\t}\n\t\t}\n\t\treturn { stepName: '', stepId: -1 }\n\t}\n\n\tconst allApps = allAppsFull\n\t\t.filter((a, i, ar) => ar.findIndex((b) => a.name === b.name) === i)\n\t\t.map((a) => ({\n\t\t\tdisplayName: getAppDisplayName(a, allAppsFull),\n\t\t\tname: a.name,\n\t\t\ttitle: a.title,\n\t\t\ttype: a.type,\n\t\t\t...getStepNameAndId(a),\n\t\t}))\n\n\tallApps.sort((a, b) => {\n\t\t// order them by their stepId\n\t\tif (a.stepId > 0 && b.stepId > 0) return a.stepId - b.stepId\n\n\t\t// non-step apps should come after step apps\n\t\tif (a.stepId > 0) return -1\n\t\tif (b.stepId > 0) return 1\n\n\t\treturn 0\n\t})\n\tconst exerciseId = getStepId(exerciseStepApp)\n\tconst exerciseIndex = allApps.findIndex((step) => step.stepId === exerciseId)\n\n\t// These depend on exerciseStepApp\n\tconst [exercise, nextApp, prevApp] = await Promise.all([\n\t\trequireExercise(exerciseStepApp.exerciseNumber, cacheOptions),\n\t\tgetNextExerciseApp(exerciseStepApp, cacheOptions),\n\t\tgetPrevExerciseApp(exerciseStepApp, cacheOptions),\n\t])\n\n\tconst exerciseApps = allAppsFull\n\t\t.filter(isExerciseStepApp)\n\t\t.filter((app) => app.exerciseNumber === exerciseStepApp.exerciseNumber)\n\tconst isLastStep =\n\t\texerciseApps[exerciseApps.length - 1]?.name === exerciseStepApp.name\n\tconst isFirstStep = exerciseApps[0]?.name === exerciseStepApp.name\n\n\tconst articleId = `workshop-${slugify(workshopTitle)}-${\n\t\texercise.exerciseNumber\n\t}-${exerciseStepApp.stepNumber}-${exerciseStepApp.type}`\n\n\tconst subroute = url.pathname.split(\n\t\t`/exercise/${params.exerciseNumber}/${params.stepNumber}/${params.type}/`,\n\t)[1]\n\n\t// read persisted split percentage from cookie (10-90, default 50)\n\tconst cookieHeader = request.headers.get('cookie')\n\tconst rawSplit = cookieHeader\n\t\t? cookie.parse(cookieHeader)[splitCookieName]\n\t\t: null\n\tconst splitPercent = computeSplitPercent(rawSplit, 50)\n\n\treturn data(\n\t\t{\n\t\t\tarticleId,\n\t\t\ttype: params.type as 'problem' | 'solution',\n\t\t\texerciseStepApp,\n\t\t\texerciseTitle: exercise.title,\n\t\t\tepicVideoInfosPromise: getEpicVideoInfos(exerciseStepApp.epicVideoEmbeds),\n\t\t\texerciseIndex,\n\t\t\tallApps,\n\t\t\tsplitPercent,\n\t\t\tprevStepLink: isFirstStep\n\t\t\t\t? {\n\t\t\t\t\t\tto: `/exercise/${exerciseStepApp.exerciseNumber\n\t\t\t\t\t\t\t.toString()\n\t\t\t\t\t\t\t.padStart(2, '0')}`,\n\t\t\t\t\t}\n\t\t\t\t: prevApp\n\t\t\t\t\t? {\n\t\t\t\t\t\t\tto: getAppPageRoute(prevApp, {\n\t\t\t\t\t\t\t\tsubroute,\n\t\t\t\t\t\t\t\tsearchParams: url.searchParams,\n\t\t\t\t\t\t\t}),\n\t\t\t\t\t\t}\n\t\t\t\t\t: null,\n\t\t\tnextStepLink: isLastStep\n\t\t\t\t? {\n\t\t\t\t\t\tto: `/exercise/${exerciseStepApp.exerciseNumber\n\t\t\t\t\t\t\t.toString()\n\t\t\t\t\t\t\t.padStart(2, '0')}/finished`,\n\t\t\t\t\t}\n\t\t\t\t: nextApp\n\t\t\t\t\t? {\n\t\t\t\t\t\t\tto: getAppPageRoute(nextApp, {\n\t\t\t\t\t\t\t\tsubroute,\n\t\t\t\t\t\t\t\tsearchParams: url.searchParams,\n\t\t\t\t\t\t\t}),\n\t\t\t\t\t\t}\n\t\t\t\t\t: null,\n\t\t\tplayground: playgroundApp\n\t\t\t\t? ({\n\t\t\t\t\t\ttype: 'playground',\n\t\t\t\t\t\tappName: playgroundApp.appName,\n\t\t\t\t\t\tname: playgroundApp.name,\n\t\t\t\t\t\tfullPath: playgroundApp.fullPath,\n\t\t\t\t\t\tdev: playgroundApp.dev,\n\t\t\t\t\t} as const)\n\t\t\t\t: null,\n\t\t\tproblem: problemApp\n\t\t\t\t? ({\n\t\t\t\t\t\ttype: 'problem',\n\t\t\t\t\t\ttitle: problemApp.title,\n\t\t\t\t\t\tname: problemApp.name,\n\t\t\t\t\t\tfullPath: problemApp.fullPath,\n\t\t\t\t\t\tdev: problemApp.dev,\n\t\t\t\t\t} as const)\n\t\t\t\t: null,\n\t\t\tsolution: solutionApp\n\t\t\t\t? ({\n\t\t\t\t\t\ttype: 'solution',\n\t\t\t\t\t\ttitle: solutionApp.title,\n\t\t\t\t\t\tname: solutionApp.name,\n\t\t\t\t\t\tfullPath: solutionApp.fullPath,\n\t\t\t\t\t\tdev: solutionApp.dev,\n\t\t\t\t\t} as const)\n\t\t\t\t: null,\n\t\t\tdiffFiles:\n\t\t\t\tproblemApp && solutionApp\n\t\t\t\t\t? getDiffFiles(problemApp, solutionApp, {\n\t\t\t\t\t\t\t...cacheOptions,\n\t\t\t\t\t\t\tforceFresh: url.searchParams.get('forceFresh') === 'diff',\n\t\t\t\t\t\t}).catch((e) => {\n\t\t\t\t\t\t\tconsole.error(e)\n\t\t\t\t\t\t\treturn 'There was a problem generating the diff (check the terminal output)'\n\t\t\t\t\t\t})\n\t\t\t\t\t: 'No diff available',\n\t\t} as const,\n\t\t{\n\t\t\theaders: {\n\t\t\t\t'Server-Timing': getServerTimeHeader(timings),\n\t\t\t},\n\t\t},\n\t)\n}\n\nexport const headers: HeadersFunction = ({ loaderHeaders, parentHeaders }) => {\n\tconst headers = {\n\t\t'Server-Timing': combineServerTimings(loaderHeaders, parentHeaders),\n\t}\n\treturn headers\n}\n\nexport default function ExercisePartRoute({\n\tloaderData: data,\n}: Route.ComponentProps) {\n\tconst inBrowserBrowserRef = useRef<InBrowserBrowserRef>(null)\n\tconst containerRef = useRef<HTMLDivElement>(null)\n\tconst leftPaneRef = useRef<HTMLDivElement>(null)\n\tconst [splitPercent, setSplitPercent] = useState<number>(data.splitPercent)\n\tconst [leftWidthPx, setLeftWidthPx] = useState<number>(0)\n\n\tuseEffect(() => {\n\t\tconst left = leftPaneRef.current\n\t\tif (!left) return\n\t\tconst ro = new ResizeObserver((entries) => {\n\t\t\tfor (const entry of entries) {\n\t\t\t\tsetLeftWidthPx(entry.contentRect.width)\n\t\t\t}\n\t\t})\n\t\tro.observe(left)\n\t\tsetLeftWidthPx(left.getBoundingClientRect().width)\n\t\treturn () => ro.disconnect()\n\t}, [])\n\n\tfunction setCookie(percent: number) {\n\t\tconst clamped = computeSplitPercent(percent)\n\t\tdocument.cookie = `${splitCookieName}=${clamped}; path=/; SameSite=Lax;`\n\t}\n\n\tfunction startDrag(initialClientX: number) {\n\t\tconst container = containerRef.current\n\t\tif (!container) return\n\t\tconst rect = container.getBoundingClientRect()\n\t\tlet dragging = true\n\n\t\t// Disable pointer events on iframes so the drag keeps receiving events\n\t\tconst iframes = Array.from(\n\t\t\tdocument.querySelectorAll('iframe'),\n\t\t) as HTMLIFrameElement[]\n\t\tconst originalPointerEvents = iframes.map((el) => el.style.pointerEvents)\n\t\tiframes.forEach((el) => (el.style.pointerEvents = 'none'))\n\n\t\tfunction handleMove(clientX: number) {\n\t\t\t// Safety check: ensure user is still dragging\n\t\t\tif (!dragging) {\n\t\t\t\tcleanup()\n\t\t\t\treturn\n\t\t\t}\n\n\t\t\tconst relativeX = clientX - rect.left\n\t\t\tconst percent = (relativeX / rect.width) * 100\n\t\t\tconst clamped = computeSplitPercent(percent)\n\t\t\tsetSplitPercent(clamped)\n\t\t\tsetCookie(clamped)\n\t\t}\n\n\t\tfunction onMouseMove(e: MouseEvent) {\n\t\t\tif (!dragging || e.buttons === 0) {\n\t\t\t\tcleanup()\n\t\t\t\treturn\n\t\t\t}\n\t\t\thandleMove(e.clientX)\n\t\t}\n\t\tfunction onTouchMove(e: TouchEvent) {\n\t\t\tconst firstTouch = e.touches?.[0]\n\t\t\tif (!dragging || !firstTouch) {\n\t\t\t\tcleanup()\n\t\t\t\treturn\n\t\t\t}\n\t\t\thandleMove(firstTouch.clientX)\n\t\t}\n\t\tfunction cleanup() {\n\t\t\tif (!dragging) return\n\t\t\tdragging = false\n\t\t\tiframes.forEach(\n\t\t\t\t(el, i) => (el.style.pointerEvents = originalPointerEvents[i] ?? ''),\n\t\t\t)\n\t\t\twindow.removeEventListener('mousemove', onMouseMove)\n\t\t\twindow.removeEventListener('mouseup', cleanup)\n\t\t\twindow.removeEventListener('touchmove', onTouchMove)\n\t\t\twindow.removeEventListener('touchend', cleanup)\n\t\t\tdocument.body.style.cursor = ''\n\t\t\tdocument.body.style.userSelect = ''\n\t\t}\n\n\t\twindow.addEventListener('mousemove', onMouseMove)\n\t\twindow.addEventListener('mouseup', cleanup)\n\t\twindow.addEventListener('touchmove', onTouchMove)\n\t\twindow.addEventListener('touchend', cleanup)\n\t\tdocument.body.style.cursor = 'col-resize'\n\t\tdocument.body.style.userSelect = 'none'\n\t\thandleMove(initialClientX)\n\t}\n\n\tconst titleBits = pageTitle(data)\n\n\tuseRevalidationWS({\n\t\twatchPaths: [`${data.exerciseStepApp.relativePath}/README.mdx`],\n\t})\n\n\treturn (\n\t\t<div className=\"flex max-w-full flex-grow flex-col\">\n\t\t\t<main\n\t\t\t\tref={containerRef}\n\t\t\t\tclassName=\"flex flex-grow flex-col sm:h-full sm:min-h-[800px] md:min-h-[unset] lg:flex-row\"\n\t\t\t>\n\t\t\t\t<div\n\t\t\t\t\tclassName=\"relative flex min-w-0 flex-none basis-full flex-col sm:col-span-1 sm:row-span-1 sm:h-full lg:basis-[var(--split-pct)]\"\n\t\t\t\t\tstyle={{ ['--split-pct' as any]: `${splitPercent}%` }}\n\t\t\t\t\tref={leftPaneRef}\n\t\t\t\t>\n\t\t\t\t\t<h1 className=\"h-14 border-b pl-10 pr-5 text-sm font-medium leading-tight\">\n\t\t\t\t\t\t<div className=\"flex h-14 items-center justify-between gap-x-2 overflow-x-auto whitespace-nowrap py-2\">\n\t\t\t\t\t\t\t<div className=\"flex items-center justify-start gap-x-2 uppercase\">\n\t\t\t\t\t\t\t\t<Link\n\t\t\t\t\t\t\t\t\tto={getExercisePath(data.exerciseStepApp.exerciseNumber)}\n\t\t\t\t\t\t\t\t\tclassName=\"hover:underline\"\n\t\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t\t{titleBits.exerciseNumber}. {titleBits.exerciseTitle}\n\t\t\t\t\t\t\t\t</Link>\n\t\t\t\t\t\t\t\t{'/'}\n\t\t\t\t\t\t\t\t<Link to=\".\" className=\"hover:underline\">\n\t\t\t\t\t\t\t\t\t{titleBits.stepNumber}. {titleBits.title}\n\t\t\t\t\t\t\t\t\t{' ('}\n\t\t\t\t\t\t\t\t\t{titleBits.emoji} {titleBits.type}\n\t\t\t\t\t\t\t\t\t{')'}\n\t\t\t\t\t\t\t\t</Link>\n\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t\t{data.problem &&\n\t\t\t\t\t\t\tdata.playground?.appName !== data.problem.name ? (\n\t\t\t\t\t\t\t\t<div className=\"hidden md:block\">\n\t\t\t\t\t\t\t\t\t<SetAppToPlayground appName={data.problem.name} />\n\t\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t\t) : null}\n\t\t\t\t\t\t</div>\n\t\t\t\t\t</h1>\n\t\t\t\t\t<article\n\t\t\t\t\t\tid={data.articleId}\n\t\t\t\t\t\tkey={data.articleId}\n\t\t\t\t\t\tclassName=\"shadow-on-scrollbox flex h-full w-full max-w-none flex-1 scroll-pt-6 flex-col justify-between space-y-6 overflow-y-auto p-2 scrollbar-thin scrollbar-thumb-scrollbar sm:p-10 sm:pt-8\"\n\t\t\t\t\t>\n\t\t\t\t\t\t{data.exerciseStepApp.instructionsCode ? (\n\t\t\t\t\t\t\t<StepMdx inBrowserBrowserRef={inBrowserBrowserRef} />\n\t\t\t\t\t\t) : (\n\t\t\t\t\t\t\t<div className=\"flex h-full items-center justify-center text-lg\">\n\t\t\t\t\t\t\t\t<p>No instructions yet...</p>\n\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t)}\n\t\t\t\t\t\t<div className=\"mt-auto flex justify-between\">\n\t\t\t\t\t\t\t{data.prevStepLink ? (\n\t\t\t\t\t\t\t\t<Link\n\t\t\t\t\t\t\t\t\tto={data.prevStepLink.to}\n\t\t\t\t\t\t\t\t\taria-label=\"Previous Step\"\n\t\t\t\t\t\t\t\t\tprefetch=\"intent\"\n\t\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t\t<span aria-hidden>←</span>\n\t\t\t\t\t\t\t\t\t<span className=\"hidden xl:inline\"> Previous</span>\n\t\t\t\t\t\t\t\t</Link>\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)}\n\t\t\t\t\t\t\t{data.nextStepLink ? (\n\t\t\t\t\t\t\t\t<Link\n\t\t\t\t\t\t\t\t\tto={data.nextStepLink.to}\n\t\t\t\t\t\t\t\t\taria-label=\"Next Step\"\n\t\t\t\t\t\t\t\t\tprefetch=\"intent\"\n\t\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t\t<span className=\"hidden xl:inline\">Next </span>\n\t\t\t\t\t\t\t\t\t<span aria-hidden>→</span>\n\t\t\t\t\t\t\t\t</Link>\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)}\n\t\t\t\t\t\t</div>\n\t\t\t\t\t</article>\n\t\t\t\t\t<ElementScrollRestoration\n\t\t\t\t\t\telementQuery={`#${data.articleId}`}\n\t\t\t\t\t\tkey={`scroll-${data.articleId}`}\n\t\t\t\t\t/>\n\t\t\t\t\t{data.type === 'solution' ? (\n\t\t\t\t\t\t<ProgressToggle\n\t\t\t\t\t\t\ttype=\"step\"\n\t\t\t\t\t\t\texerciseNumber={data.exerciseStepApp.exerciseNumber}\n\t\t\t\t\t\t\tstepNumber={data.exerciseStepApp.stepNumber}\n\t\t\t\t\t\t\tclassName=\"h-14 border-t px-6\"\n\t\t\t\t\t\t/>\n\t\t\t\t\t) : null}\n\t\t\t\t\t<div className=\"flex h-16 justify-between border-b-4 border-t lg:border-b-0\">\n\t\t\t\t\t\t<div>\n\t\t\t\t\t\t\t<div className=\"h-full\">\n\t\t\t\t\t\t\t\t<TouchedFiles\n\t\t\t\t\t\t\t\t\tdiffFilesPromise={data.diffFiles}\n\t\t\t\t\t\t\t\t\tcompact={leftWidthPx < 640}\n\t\t\t\t\t\t\t\t/>\n\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t</div>\n\t\t\t\t\t\t<EditFileOnGitHub\n\t\t\t\t\t\t\tappName={data.exerciseStepApp.name}\n\t\t\t\t\t\t\trelativePath={data.exerciseStepApp.relativePath}\n\t\t\t\t\t\t\tcompact={leftWidthPx < 720}\n\t\t\t\t\t\t/>\n\t\t\t\t\t\t<NavChevrons\n\t\t\t\t\t\t\tprev={\n\t\t\t\t\t\t\t\tdata.prevStepLink\n\t\t\t\t\t\t\t\t\t? {\n\t\t\t\t\t\t\t\t\t\t\tto: data.prevStepLink.to,\n\t\t\t\t\t\t\t\t\t\t\t'aria-label': 'Previous Step',\n\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t: null\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tnext={\n\t\t\t\t\t\t\t\tdata.nextStepLink\n\t\t\t\t\t\t\t\t\t? {\n\t\t\t\t\t\t\t\t\t\t\tto: data.nextStepLink.to,\n\t\t\t\t\t\t\t\t\t\t\t'aria-label': 'Next Step',\n\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t: null\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t/>\n\t\t\t\t\t</div>\n\t\t\t\t</div>\n\t\t\t\t<div\n\t\t\t\t\trole=\"separator\"\n\t\t\t\t\taria-orientation=\"vertical\"\n\t\t\t\t\ttitle=\"Drag to resize\"\n\t\t\t\t\tclassName=\"hidden w-1 cursor-col-resize bg-border hover:bg-accent lg:block\"\n\t\t\t\t\tonMouseDown={(e) => startDrag(e.clientX)}\n\t\t\t\t\tonDoubleClick={() => {\n\t\t\t\t\t\tsetSplitPercent(50)\n\t\t\t\t\t\tsetCookie(50)\n\t\t\t\t\t}}\n\t\t\t\t\tonTouchStart={(e) => {\n\t\t\t\t\t\tconst firstTouch = e.touches?.[0]\n\t\t\t\t\t\tif (firstTouch) startDrag(firstTouch.clientX)\n\t\t\t\t\t}}\n\t\t\t\t/>\n\t\t\t\t<div className=\"flex min-w-0 flex-1\">\n\t\t\t\t\t<Outlet />\n\t\t\t\t</div>\n\t\t\t</main>\n\t\t</div>\n\t)\n}\n\nexport function ErrorBoundary() {\n\treturn (\n\t\t<GeneralErrorBoundary\n\t\t\tstatusHandlers={{\n\t\t\t\t404: () => <p>Sorry, we couldn't find an app here.</p>,\n\t\t\t\t503: () => (\n\t\t\t\t\t<div>\n\t\t\t\t\t\t<h1>Service Unavailable</h1>\n\t\t\t\t\t\t<p>\n\t\t\t\t\t\t\tSorry, we're having a temporary problem. Please try again later.\n\t\t\t\t\t\t</p>\n\t\t\t\t\t\t<button onClick={() => window.location.reload()}>Refresh</button>\n\t\t\t\t\t</div>\n\t\t\t\t),\n\t\t\t}}\n\t\t/>\n\t)\n}\n"],"names":["StepContext","React.createContext","useStepContext","context","React.useContext","StepContextProvider","children","inBrowserBrowserRef","jsx","stepMdxComponents","DiffLink","PrevDiffLink","NextDiffLink","InlineFile","LinkToApp","StepMdx","data","useLoaderData","EpicVideoInfoProvider","Mdx","withParam","searchParams","key","value","newSearchParams","app","fullPage","app1","app2","to","getAppName","input","stepIndex","name","stepName","params","app1Name","app2Name","jsxs","pathToDiff","Link","file","type","props","info","iconsSvg","LaunchEditor","SimpleTooltip","getPreviewType","preview","appTo","useSearchParams","requestInfo","useRequestInfo","previewAppUrl","getBaseUrl","href","cn","event","Icon","POPOVER_NAME","createPopoverContext","createPopoverScope","createContextScope","createPopperScope","usePopperScope","PopoverProvider","usePopoverContext","Popover","__scopePopover","openProp","defaultOpen","onOpenChange","modal","popperScope","triggerRef","React.useRef","hasCustomAnchor","setHasCustomAnchor","React.useState","open","setOpen","useControllableState","PopperPrimitive.Root","useId","React.useCallback","prevOpen","ANCHOR_NAME","PopoverAnchor","React.forwardRef","forwardedRef","anchorProps","onCustomAnchorAdd","onCustomAnchorRemove","React.useEffect","PopperPrimitive.Anchor","TRIGGER_NAME","PopoverTrigger","triggerProps","composedTriggerRef","useComposedRefs","trigger","Primitive","getState","composeEventHandlers","PORTAL_NAME","PortalProvider","usePortalContext","PopoverPortal","forceMount","container","Presence","PortalPrimitive","CONTENT_NAME","PopoverContent","portalContext","contentProps","PopoverContentModal","PopoverContentNonModal","Slot","createSlot","contentRef","composedRefs","isRightClickOutsideRef","content","hideOthers","RemoveScroll","PopoverContentImpl","originalEvent","ctrlLeftClick","isRightClick","hasInteractedOutsideRef","hasPointerDownOutsideRef","target","trapFocus","onOpenAutoFocus","onCloseAutoFocus","disableOutsidePointerEvents","onEscapeKeyDown","onPointerDownOutside","onFocusOutside","onInteractOutside","useFocusGuards","FocusScope","DismissableLayer","PopperPrimitive.Content","CLOSE_NAME","PopoverClose","closeProps","ARROW_NAME","PopoverArrow","arrowProps","PopperPrimitive.Arrow","Root2","Trigger","Portal","Content2","TouchedFiles","diffFilesPromise","compact","handleLaunchUpdate","appName","Popover.Root","Popover.Trigger","Popover.Portal","Popover.Content","SetAppToPlayground","React.Suspense","Await","diffFiles","splitCookieName","computeSplitPercent","defaultValue","Number","isFinite","Math","min","max","round","pageTitle","workshopTitle","exerciseNumber","exerciseStepApp","toString","padStart","stepNumber","emoji","problem","solution","title","exerciseTitle","meta","matches","rootData","find","m","id","getSeoMetaTags","description","ogTitle","ogDescription","instructor","_layout","_UNSAFE_withComponentProps","loaderData","useRef","containerRef","leftPaneRef","splitPercent","setSplitPercent","useState","leftWidthPx","setLeftWidthPx","useEffect","left","current","ro","ResizeObserver","entries","entry","contentRect","width","observe","getBoundingClientRect","disconnect","setCookie","percent","clamped","document","cookie","startDrag","initialClientX","rect","dragging","iframes","Array","from","querySelectorAll","originalPointerEvents","map","el","style","pointerEvents","forEach","handleMove","clientX","cleanup","onMouseMove","e","buttons","onTouchMove","firstTouch","touches","i","window","removeEventListener","body","cursor","userSelect","addEventListener","titleBits","useRevalidationWS","watchPaths","relativePath","className","ref","getExercisePath","playground","articleId","instructionsCode","prevStepLink","prefetch","nextStepLink","ElementScrollRestoration","elementQuery","ProgressToggle","EditFileOnGitHub","NavChevrons","prev","next","role","onMouseDown","onDoubleClick","onTouchStart","Outlet","ErrorBoundary","_UNSAFE_withErrorBoundaryProps","GeneralErrorBoundary","statusHandlers","onClick","location","reload"],"mappings":"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","x_google_ignoreList":[1]}
@@ -1,2 +1,2 @@
1
- import{j as e}from"./jsx-runtime-EKYJJIwR.js";import{R as u,A as j}from"./accordion-BBn2ZFM9.js";import{R as w,T as b,I as g,P as N,C as v,S as y,a as S,G as k,L as D,b as R,V as A,c as C,d as I,e as T}from"./index-2USrBHAC.js";import{c as x}from"./clsx-B-dksMZM.js";import{r as P}from"./index-DatCARk7.js";import{k as V,l as $,f as L,A as E,L as F,F as U}from"./chunk-EF7DTUVF-ByhKO_Pl.js";import{d as B,I as o,c as G}from"./misc-DjWUkK1U.js";import{M as H,u as M}from"./mdx-Bbi38W8y.js";import{D as W}from"./epic-video-BODCgn-e.js";import{u as z}from"./revalidation-ws-BMyn5NqG.js";import{S as m}from"./tooltip-JIUlMcsz.js";import{b as Y}from"./user-CJVisi_Z.js";const q=t=>e.jsx("pre",{...t}),J={Accordion:j,pre:q};function K({app1:t,app2:a}){const n=M(),r=n.find(l=>l.name===t),i=n.find(l=>l.name===a);return z({watchPaths:[r?.fullPath,i?.fullPath].filter(Boolean)}),null}function ce({diff:t,allApps:a}){const n=Y(),r=V(),[i]=$(),l=new URLSearchParams(i);l.set("forceFresh","diff");const f=L(),h=B.useSpinDelay(f.state!=="idle",{delay:0,minDuration:1e3}),p=[];for(const[s,c]of i.entries())s==="app1"||s==="app2"||p.push(e.jsx("input",{type:"hidden",name:s,value:c},s));return n?e.jsx(P.Suspense,{fallback:e.jsx("div",{className:"flex items-center justify-center p-8",children:e.jsx(m,{content:"Loading diff",children:e.jsx(o,{name:"Refresh",className:"animate-spin"})})}),children:e.jsx(E,{resolve:t,errorElement:e.jsx("p",{className:"p-6 text-foreground-destructive",children:"There was an error calculating the diff. Sorry."}),children:s=>e.jsxs("div",{className:"flex h-full w-full flex-col",children:[e.jsxs("div",{className:"flex h-14 min-h-14 w-full overflow-x-hidden border-b",children:[e.jsx("div",{className:"border-r",children:e.jsx(m,{content:"Reload diff",children:e.jsx(F,{to:`.?${l}`,className:"flex h-full w-14 items-center justify-center",children:e.jsx(o,{name:"Refresh",className:G({"animate-spin":h})})})})}),e.jsxs(U,{onChange:c=>r(c.currentTarget),className:"flex h-full flex-1 items-center overflow-x-auto scrollbar-thin scrollbar-thumb-scrollbar",children:[p,e.jsx(d,{name:"app1",label:"App 1",className:"border-r",allApps:a,defaultValue:s.app1}),e.jsx(d,{name:"app2",label:"App 2",allApps:a,defaultValue:s.app2})]},`${s.app1}${s.app2}`)]}),e.jsx("div",{className:"flex-grow overflow-y-scroll scrollbar-thin scrollbar-thumb-scrollbar",children:s.diffCode?e.jsx("div",{children:e.jsx(u,{className:"w-full",type:"multiple",children:e.jsx(H,{code:s.diffCode,components:J})})}):s.app1&&s.app2?e.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"}):e.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"})}),e.jsx(K,{app1:s.app1,app2:s.app2})]})})}):e.jsxs("div",{className:"w-full p-12",children:[e.jsxs("div",{className:"flex w-full flex-col gap-4 text-center",children:[e.jsx("p",{className:"text-2xl font-bold",children:"Access Denied"}),e.jsx("p",{className:"text-lg",children:"You must login or register for the workshop to view the diff."})]}),e.jsx("div",{className:"h-16"}),e.jsx("p",{className:"pb-4",children:"Check out this video to see how the diff tab works."}),e.jsx(W,{url:"https://www.epicweb.dev/tips/epic-workshop-diff-tab-demo"})]})}function d({name:t,label:a,className:n,allApps:r,defaultValue:i}){return e.jsxs(w,{name:t,defaultValue:i,children:[e.jsxs(b,{className:x("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",n),"aria-label":`Select ${a} for git Diff`,children:[e.jsxs("span",{className:"overflow-hidden text-ellipsis whitespace-nowrap",children:[a,":"," ",e.jsx(Q,{placeholder:`Select ${a}`,className:"inline-block w-40 text-ellipsis"})]}),e.jsx(g,{className:"",children:e.jsx(o,{name:"TriangleDownSmall"})})]}),e.jsx(N,{children:e.jsxs(v,{position:"popper",align:"start",className:"z-20 max-h-[50vh] bg-black text-white lg:max-h-[70vh]",children:[e.jsx(y,{className:"flex h-5 cursor-default items-center justify-center",children:e.jsx(o,{name:"ChevronUp"})}),e.jsx(S,{className:"p-3",children:e.jsxs(k,{children:[e.jsx(D,{className:"px-5 pb-3 font-mono uppercase",children:a}),r.map(l=>e.jsx(O,{value:l.name,children:l.displayName},l.name))]})}),e.jsx(R,{className:"flex h-5 cursor-default items-center justify-center",children:e.jsx(o,{name:"ChevronDown"})})]})})]})}const O=({ref:t,children:a,className:n,...r})=>e.jsxs(C,{className:x("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),...r,ref:t,children:[e.jsx(I,{children:a}),e.jsx(T,{className:"absolute left-0 inline-flex w-[25px] items-center justify-center",children:e.jsx(o,{name:"CheckSmall"})})]}),Q=({ref:t,children:a,className:n,...r})=>e.jsx(A,{...r,ref:t,children:r.value});export{ce as D};
2
- //# sourceMappingURL=diff-Dwb3EWYp.js.map
1
+ import{j as e}from"./jsx-runtime-EKYJJIwR.js";import{R as u,A as j}from"./accordion-BBn2ZFM9.js";import{R as w,T as b,I as g,P as N,C as v,S as y,a as S,G as k,L as D,b as R,V as A,c as C,d as I,e as T}from"./index-2USrBHAC.js";import{c as x}from"./clsx-B-dksMZM.js";import{r as P}from"./index-DatCARk7.js";import{k as V,l as $,f as L,A as E,L as F,F as U}from"./chunk-EF7DTUVF-ByhKO_Pl.js";import{d as B,I as o,c as G}from"./misc-DjWUkK1U.js";import{M as H,u as M}from"./mdx-BDFRig3X.js";import{D as W}from"./epic-video-BODCgn-e.js";import{u as z}from"./revalidation-ws-BMyn5NqG.js";import{S as m}from"./tooltip-JIUlMcsz.js";import{b as Y}from"./user-CJVisi_Z.js";const q=t=>e.jsx("pre",{...t}),J={Accordion:j,pre:q};function K({app1:t,app2:a}){const n=M(),r=n.find(l=>l.name===t),i=n.find(l=>l.name===a);return z({watchPaths:[r?.fullPath,i?.fullPath].filter(Boolean)}),null}function ce({diff:t,allApps:a}){const n=Y(),r=V(),[i]=$(),l=new URLSearchParams(i);l.set("forceFresh","diff");const f=L(),h=B.useSpinDelay(f.state!=="idle",{delay:0,minDuration:1e3}),p=[];for(const[s,c]of i.entries())s==="app1"||s==="app2"||p.push(e.jsx("input",{type:"hidden",name:s,value:c},s));return n?e.jsx(P.Suspense,{fallback:e.jsx("div",{className:"flex items-center justify-center p-8",children:e.jsx(m,{content:"Loading diff",children:e.jsx(o,{name:"Refresh",className:"animate-spin"})})}),children:e.jsx(E,{resolve:t,errorElement:e.jsx("p",{className:"p-6 text-foreground-destructive",children:"There was an error calculating the diff. Sorry."}),children:s=>e.jsxs("div",{className:"flex h-full w-full flex-col",children:[e.jsxs("div",{className:"flex h-14 min-h-14 w-full overflow-x-hidden border-b",children:[e.jsx("div",{className:"border-r",children:e.jsx(m,{content:"Reload diff",children:e.jsx(F,{to:`.?${l}`,className:"flex h-full w-14 items-center justify-center",children:e.jsx(o,{name:"Refresh",className:G({"animate-spin":h})})})})}),e.jsxs(U,{onChange:c=>r(c.currentTarget),className:"flex h-full flex-1 items-center overflow-x-auto scrollbar-thin scrollbar-thumb-scrollbar",children:[p,e.jsx(d,{name:"app1",label:"App 1",className:"border-r",allApps:a,defaultValue:s.app1}),e.jsx(d,{name:"app2",label:"App 2",allApps:a,defaultValue:s.app2})]},`${s.app1}${s.app2}`)]}),e.jsx("div",{className:"flex-grow overflow-y-scroll scrollbar-thin scrollbar-thumb-scrollbar",children:s.diffCode?e.jsx("div",{children:e.jsx(u,{className:"w-full",type:"multiple",children:e.jsx(H,{code:s.diffCode,components:J})})}):s.app1&&s.app2?e.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"}):e.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"})}),e.jsx(K,{app1:s.app1,app2:s.app2})]})})}):e.jsxs("div",{className:"w-full p-12",children:[e.jsxs("div",{className:"flex w-full flex-col gap-4 text-center",children:[e.jsx("p",{className:"text-2xl font-bold",children:"Access Denied"}),e.jsx("p",{className:"text-lg",children:"You must login or register for the workshop to view the diff."})]}),e.jsx("div",{className:"h-16"}),e.jsx("p",{className:"pb-4",children:"Check out this video to see how the diff tab works."}),e.jsx(W,{url:"https://www.epicweb.dev/tips/epic-workshop-diff-tab-demo"})]})}function d({name:t,label:a,className:n,allApps:r,defaultValue:i}){return e.jsxs(w,{name:t,defaultValue:i,children:[e.jsxs(b,{className:x("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",n),"aria-label":`Select ${a} for git Diff`,children:[e.jsxs("span",{className:"overflow-hidden text-ellipsis whitespace-nowrap",children:[a,":"," ",e.jsx(Q,{placeholder:`Select ${a}`,className:"inline-block w-40 text-ellipsis"})]}),e.jsx(g,{className:"",children:e.jsx(o,{name:"TriangleDownSmall"})})]}),e.jsx(N,{children:e.jsxs(v,{position:"popper",align:"start",className:"z-20 max-h-[50vh] bg-black text-white lg:max-h-[70vh]",children:[e.jsx(y,{className:"flex h-5 cursor-default items-center justify-center",children:e.jsx(o,{name:"ChevronUp"})}),e.jsx(S,{className:"p-3",children:e.jsxs(k,{children:[e.jsx(D,{className:"px-5 pb-3 font-mono uppercase",children:a}),r.map(l=>e.jsx(O,{value:l.name,children:l.displayName},l.name))]})}),e.jsx(R,{className:"flex h-5 cursor-default items-center justify-center",children:e.jsx(o,{name:"ChevronDown"})})]})})]})}const O=({ref:t,children:a,className:n,...r})=>e.jsxs(C,{className:x("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),...r,ref:t,children:[e.jsx(I,{children:a}),e.jsx(T,{className:"absolute left-0 inline-flex w-[25px] items-center justify-center",children:e.jsx(o,{name:"CheckSmall"})})]}),Q=({ref:t,children:a,className:n,...r})=>e.jsx(A,{...r,ref:t,children:r.value});export{ce as D};
2
+ //# sourceMappingURL=diff-0XgucEQg.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"diff-Dwb3EWYp.js","sources":["../../../app/components/diff.tsx"],"sourcesContent":["import * as Accordion from '@radix-ui/react-accordion'\nimport * as Select from '@radix-ui/react-select'\nimport { clsx } from 'clsx'\nimport React, { Suspense } from 'react'\nimport {\n\tAwait,\n\tForm,\n\tLink,\n\tuseNavigation,\n\tuseSearchParams,\n\tuseSubmit,\n} from 'react-router'\nimport { useSpinDelay } from 'spin-delay'\nimport AccordionComponent from '#app/components/accordion.tsx'\nimport { Mdx } from '#app/utils/mdx.tsx'\nimport { cn } from '#app/utils/misc.tsx'\nimport { useApps } from './apps.tsx'\nimport { DeferredEpicVideo } from './epic-video.tsx'\nimport { Icon } from './icons.tsx'\nimport { useRevalidationWS } from './revalidation-ws.tsx'\nimport { SimpleTooltip } from './ui/tooltip.tsx'\nimport { useUserHasAccess } from './user.tsx'\n\ntype diffProp = {\n\tapp1?: string\n\tapp2?: string\n\tdiffCode?: string | null\n}\n\nconst pre = (props: any) => <pre {...props} />\n\nconst mdxComponents = {\n\tAccordion: AccordionComponent,\n\t// override the pre-with-buttons\n\tpre,\n}\n\nfunction RevalidateApps({\n\tapp1: app1Name,\n\tapp2: app2Name,\n}: {\n\tapp1?: string\n\tapp2?: string\n}) {\n\tconst apps = useApps()\n\tconst app1 = apps.find((app) => app.name === app1Name)\n\tconst app2 = apps.find((app) => app.name === app2Name)\n\n\tuseRevalidationWS({\n\t\twatchPaths: [app1?.fullPath, app2?.fullPath].filter(Boolean),\n\t})\n\treturn null\n}\n\nexport function Diff({\n\tdiff,\n\tallApps,\n}: {\n\tdiff: Promise<diffProp> | diffProp\n\tallApps: Array<{ name: string; displayName: string }>\n}) {\n\tconst userHasAccess = useUserHasAccess()\n\tconst submit = useSubmit()\n\tconst [params] = useSearchParams()\n\tconst paramsWithForcedRefresh = new URLSearchParams(params)\n\tparamsWithForcedRefresh.set('forceFresh', 'diff')\n\tconst navigation = useNavigation()\n\tconst spinnerNavigating = useSpinDelay(navigation.state !== 'idle', {\n\t\tdelay: 0,\n\t\tminDuration: 1000,\n\t})\n\n\tconst hiddenInputs: Array<React.ReactNode> = []\n\tfor (const [key, value] of params.entries()) {\n\t\tif (key === 'app1' || key === 'app2') continue\n\t\thiddenInputs.push(\n\t\t\t<input key={key} type=\"hidden\" name={key} value={value} />,\n\t\t)\n\t}\n\n\tif (!userHasAccess) {\n\t\treturn (\n\t\t\t<div className=\"w-full p-12\">\n\t\t\t\t<div className=\"flex w-full flex-col gap-4 text-center\">\n\t\t\t\t\t<p className=\"text-2xl font-bold\">Access Denied</p>\n\t\t\t\t\t<p className=\"text-lg\">\n\t\t\t\t\t\tYou must login or register for the workshop to view the diff.\n\t\t\t\t\t</p>\n\t\t\t\t</div>\n\t\t\t\t<div className=\"h-16\" />\n\t\t\t\t<p className=\"pb-4\">\n\t\t\t\t\tCheck out this video to see how the diff tab works.\n\t\t\t\t</p>\n\t\t\t\t<DeferredEpicVideo url=\"https://www.epicweb.dev/tips/epic-workshop-diff-tab-demo\" />\n\t\t\t</div>\n\t\t)\n\t}\n\n\treturn (\n\t\t<Suspense\n\t\t\tfallback={\n\t\t\t\t<div className=\"flex items-center justify-center p-8\">\n\t\t\t\t\t<SimpleTooltip content=\"Loading diff\">\n\t\t\t\t\t\t<Icon name=\"Refresh\" className=\"animate-spin\" />\n\t\t\t\t\t</SimpleTooltip>\n\t\t\t\t</div>\n\t\t\t}\n\t\t>\n\t\t\t<Await\n\t\t\t\tresolve={diff}\n\t\t\t\terrorElement={\n\t\t\t\t\t<p className=\"p-6 text-foreground-destructive\">\n\t\t\t\t\t\tThere was an error calculating the diff. Sorry.\n\t\t\t\t\t</p>\n\t\t\t\t}\n\t\t\t>\n\t\t\t\t{(diff) => (\n\t\t\t\t\t<div className=\"flex h-full w-full flex-col\">\n\t\t\t\t\t\t<div className=\"flex h-14 min-h-14 w-full overflow-x-hidden border-b\">\n\t\t\t\t\t\t\t<div className=\"border-r\">\n\t\t\t\t\t\t\t\t<SimpleTooltip content=\"Reload diff\">\n\t\t\t\t\t\t\t\t\t<Link\n\t\t\t\t\t\t\t\t\t\tto={`.?${paramsWithForcedRefresh}`}\n\t\t\t\t\t\t\t\t\t\tclassName=\"flex h-full w-14 items-center justify-center\"\n\t\t\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t\t\t<Icon\n\t\t\t\t\t\t\t\t\t\t\tname=\"Refresh\"\n\t\t\t\t\t\t\t\t\t\t\tclassName={cn({ 'animate-spin': spinnerNavigating })}\n\t\t\t\t\t\t\t\t\t\t/>\n\t\t\t\t\t\t\t\t\t</Link>\n\t\t\t\t\t\t\t\t</SimpleTooltip>\n\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t\t<Form\n\t\t\t\t\t\t\t\tonChange={(e) => submit(e.currentTarget)}\n\t\t\t\t\t\t\t\tclassName=\"flex h-full flex-1 items-center overflow-x-auto scrollbar-thin scrollbar-thumb-scrollbar\"\n\t\t\t\t\t\t\t\tkey={`${diff.app1}${diff.app2}`}\n\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t{hiddenInputs}\n\t\t\t\t\t\t\t\t<SelectFileToDiff\n\t\t\t\t\t\t\t\t\tname=\"app1\"\n\t\t\t\t\t\t\t\t\tlabel=\"App 1\"\n\t\t\t\t\t\t\t\t\tclassName=\"border-r\"\n\t\t\t\t\t\t\t\t\tallApps={allApps}\n\t\t\t\t\t\t\t\t\tdefaultValue={diff.app1}\n\t\t\t\t\t\t\t\t/>\n\t\t\t\t\t\t\t\t<SelectFileToDiff\n\t\t\t\t\t\t\t\t\tname=\"app2\"\n\t\t\t\t\t\t\t\t\tlabel=\"App 2\"\n\t\t\t\t\t\t\t\t\tallApps={allApps}\n\t\t\t\t\t\t\t\t\tdefaultValue={diff.app2}\n\t\t\t\t\t\t\t\t/>\n\t\t\t\t\t\t\t</Form>\n\t\t\t\t\t\t</div>\n\t\t\t\t\t\t<div className=\"flex-grow overflow-y-scroll scrollbar-thin scrollbar-thumb-scrollbar\">\n\t\t\t\t\t\t\t{diff.diffCode ? (\n\t\t\t\t\t\t\t\t<div>\n\t\t\t\t\t\t\t\t\t<Accordion.Root className=\"w-full\" type=\"multiple\">\n\t\t\t\t\t\t\t\t\t\t<Mdx code={diff.diffCode} components={mdxComponents} />\n\t\t\t\t\t\t\t\t\t</Accordion.Root>\n\t\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t\t) : diff.app1 && diff.app2 ? (\n\t\t\t\t\t\t\t\t<p className=\"m-5 inline-flex items-center justify-center bg-foreground px-1 py-0.5 font-mono text-sm uppercase text-background\">\n\t\t\t\t\t\t\t\t\tThere was a problem generating the diff\n\t\t\t\t\t\t\t\t</p>\n\t\t\t\t\t\t\t) : (\n\t\t\t\t\t\t\t\t<p className=\"m-5 inline-flex items-center justify-center bg-foreground px-1 py-0.5 font-mono text-sm uppercase text-background\">\n\t\t\t\t\t\t\t\t\tSelect two apps to compare\n\t\t\t\t\t\t\t\t</p>\n\t\t\t\t\t\t\t)}\n\t\t\t\t\t\t</div>\n\t\t\t\t\t\t<RevalidateApps app1={diff.app1} app2={diff.app2} />\n\t\t\t\t\t</div>\n\t\t\t\t)}\n\t\t\t</Await>\n\t\t</Suspense>\n\t)\n}\n\nfunction SelectFileToDiff({\n\tname,\n\tlabel,\n\tclassName,\n\tallApps,\n\tdefaultValue,\n}: {\n\tname: string\n\tlabel: string\n\tclassName?: string\n\tallApps: Array<{ name: string; displayName: string }>\n\tdefaultValue?: string\n}) {\n\treturn (\n\t\t<Select.Root name={name} defaultValue={defaultValue}>\n\t\t\t<Select.Trigger\n\t\t\t\tclassName={clsx(\n\t\t\t\t\t'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',\n\t\t\t\t\tclassName,\n\t\t\t\t)}\n\t\t\t\taria-label={`Select ${label} for git Diff`}\n\t\t\t>\n\t\t\t\t<span className=\"overflow-hidden text-ellipsis whitespace-nowrap\">\n\t\t\t\t\t{label}:{' '}\n\t\t\t\t\t<SelectValue\n\t\t\t\t\t\tplaceholder={`Select ${label}`}\n\t\t\t\t\t\tclassName=\"inline-block w-40 text-ellipsis\"\n\t\t\t\t\t/>\n\t\t\t\t</span>\n\t\t\t\t<Select.Icon className=\"\">\n\t\t\t\t\t<Icon name=\"TriangleDownSmall\" />\n\t\t\t\t</Select.Icon>\n\t\t\t</Select.Trigger>\n\t\t\t<Select.Portal>\n\t\t\t\t<Select.Content\n\t\t\t\t\tposition=\"popper\"\n\t\t\t\t\talign=\"start\"\n\t\t\t\t\tclassName=\"z-20 max-h-[50vh] bg-black text-white lg:max-h-[70vh]\"\n\t\t\t\t>\n\t\t\t\t\t<Select.ScrollUpButton className=\"flex h-5 cursor-default items-center justify-center\">\n\t\t\t\t\t\t<Icon name=\"ChevronUp\" />\n\t\t\t\t\t</Select.ScrollUpButton>\n\t\t\t\t\t<Select.Viewport className=\"p-3\">\n\t\t\t\t\t\t<Select.Group>\n\t\t\t\t\t\t\t<Select.Label className=\"px-5 pb-3 font-mono uppercase\">\n\t\t\t\t\t\t\t\t{label}\n\t\t\t\t\t\t\t</Select.Label>\n\t\t\t\t\t\t\t{allApps.map((app) => {\n\t\t\t\t\t\t\t\treturn (\n\t\t\t\t\t\t\t\t\t<SelectItem key={app.name} value={app.name}>\n\t\t\t\t\t\t\t\t\t\t{app.displayName}\n\t\t\t\t\t\t\t\t\t</SelectItem>\n\t\t\t\t\t\t\t\t)\n\t\t\t\t\t\t\t})}\n\t\t\t\t\t\t</Select.Group>\n\t\t\t\t\t</Select.Viewport>\n\t\t\t\t\t<Select.ScrollDownButton className=\"flex h-5 cursor-default items-center justify-center\">\n\t\t\t\t\t\t<Icon name=\"ChevronDown\" />\n\t\t\t\t\t</Select.ScrollDownButton>\n\t\t\t\t</Select.Content>\n\t\t\t</Select.Portal>\n\t\t</Select.Root>\n\t)\n}\n\nconst SelectItem: React.FC<any> = ({\n\tref: forwardedRef,\n\tchildren,\n\tclassName,\n\t...props\n}) => {\n\treturn (\n\t\t<Select.Item\n\t\t\tclassName={clsx(\n\t\t\t\t'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\n\t\t\t\tclassName,\n\t\t\t)}\n\t\t\t{...props}\n\t\t\tref={forwardedRef}\n\t\t>\n\t\t\t<Select.ItemText>{children}</Select.ItemText>\n\t\t\t<Select.ItemIndicator className=\"absolute left-0 inline-flex w-[25px] items-center justify-center\">\n\t\t\t\t<Icon name=\"CheckSmall\" />\n\t\t\t</Select.ItemIndicator>\n\t\t</Select.Item>\n\t)\n}\n\nconst SelectValue: React.FC<any> = ({\n\tref: forwardedRef,\n\tchildren,\n\tclassName,\n\t...props\n}) => {\n\treturn (\n\t\t<Select.Value {...props} ref={forwardedRef}>\n\t\t\t{props.value}\n\t\t</Select.Value>\n\t)\n}\n"],"names":["pre","props","jsx","mdxComponents","AccordionComponent","RevalidateApps","app1Name","app2Name","apps","useApps","app1","app","app2","useRevalidationWS","Diff","diff","allApps","userHasAccess","useUserHasAccess","submit","useSubmit","params","useSearchParams","paramsWithForcedRefresh","navigation","useNavigation","spinnerNavigating","useSpinDelay","hiddenInputs","key","value","Suspense","SimpleTooltip","Icon","Await","jsxs","Link","cn","Form","e","SelectFileToDiff","Accordion.Root","Mdx","DeferredEpicVideo","name","label","className","defaultValue","Select.Root","Select.Trigger","clsx","SelectValue","Select.Icon","Select.Portal","Select.Content","Select.ScrollUpButton","Select.Viewport","Select.Group","Select.Label","SelectItem","Select.ScrollDownButton","forwardedRef","children","Select.Item","Select.ItemText","Select.ItemIndicator","Select.Value"],"mappings":"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"}
1
+ {"version":3,"file":"diff-0XgucEQg.js","sources":["../../../app/components/diff.tsx"],"sourcesContent":["import * as Accordion from '@radix-ui/react-accordion'\nimport * as Select from '@radix-ui/react-select'\nimport { clsx } from 'clsx'\nimport React, { Suspense } from 'react'\nimport {\n\tAwait,\n\tForm,\n\tLink,\n\tuseNavigation,\n\tuseSearchParams,\n\tuseSubmit,\n} from 'react-router'\nimport { useSpinDelay } from 'spin-delay'\nimport AccordionComponent from '#app/components/accordion.tsx'\nimport { Mdx } from '#app/utils/mdx.tsx'\nimport { cn } from '#app/utils/misc.tsx'\nimport { useApps } from './apps.tsx'\nimport { DeferredEpicVideo } from './epic-video.tsx'\nimport { Icon } from './icons.tsx'\nimport { useRevalidationWS } from './revalidation-ws.tsx'\nimport { SimpleTooltip } from './ui/tooltip.tsx'\nimport { useUserHasAccess } from './user.tsx'\n\ntype diffProp = {\n\tapp1?: string\n\tapp2?: string\n\tdiffCode?: string | null\n}\n\nconst pre = (props: any) => <pre {...props} />\n\nconst mdxComponents = {\n\tAccordion: AccordionComponent,\n\t// override the pre-with-buttons\n\tpre,\n}\n\nfunction RevalidateApps({\n\tapp1: app1Name,\n\tapp2: app2Name,\n}: {\n\tapp1?: string\n\tapp2?: string\n}) {\n\tconst apps = useApps()\n\tconst app1 = apps.find((app) => app.name === app1Name)\n\tconst app2 = apps.find((app) => app.name === app2Name)\n\n\tuseRevalidationWS({\n\t\twatchPaths: [app1?.fullPath, app2?.fullPath].filter(Boolean),\n\t})\n\treturn null\n}\n\nexport function Diff({\n\tdiff,\n\tallApps,\n}: {\n\tdiff: Promise<diffProp> | diffProp\n\tallApps: Array<{ name: string; displayName: string }>\n}) {\n\tconst userHasAccess = useUserHasAccess()\n\tconst submit = useSubmit()\n\tconst [params] = useSearchParams()\n\tconst paramsWithForcedRefresh = new URLSearchParams(params)\n\tparamsWithForcedRefresh.set('forceFresh', 'diff')\n\tconst navigation = useNavigation()\n\tconst spinnerNavigating = useSpinDelay(navigation.state !== 'idle', {\n\t\tdelay: 0,\n\t\tminDuration: 1000,\n\t})\n\n\tconst hiddenInputs: Array<React.ReactNode> = []\n\tfor (const [key, value] of params.entries()) {\n\t\tif (key === 'app1' || key === 'app2') continue\n\t\thiddenInputs.push(\n\t\t\t<input key={key} type=\"hidden\" name={key} value={value} />,\n\t\t)\n\t}\n\n\tif (!userHasAccess) {\n\t\treturn (\n\t\t\t<div className=\"w-full p-12\">\n\t\t\t\t<div className=\"flex w-full flex-col gap-4 text-center\">\n\t\t\t\t\t<p className=\"text-2xl font-bold\">Access Denied</p>\n\t\t\t\t\t<p className=\"text-lg\">\n\t\t\t\t\t\tYou must login or register for the workshop to view the diff.\n\t\t\t\t\t</p>\n\t\t\t\t</div>\n\t\t\t\t<div className=\"h-16\" />\n\t\t\t\t<p className=\"pb-4\">\n\t\t\t\t\tCheck out this video to see how the diff tab works.\n\t\t\t\t</p>\n\t\t\t\t<DeferredEpicVideo url=\"https://www.epicweb.dev/tips/epic-workshop-diff-tab-demo\" />\n\t\t\t</div>\n\t\t)\n\t}\n\n\treturn (\n\t\t<Suspense\n\t\t\tfallback={\n\t\t\t\t<div className=\"flex items-center justify-center p-8\">\n\t\t\t\t\t<SimpleTooltip content=\"Loading diff\">\n\t\t\t\t\t\t<Icon name=\"Refresh\" className=\"animate-spin\" />\n\t\t\t\t\t</SimpleTooltip>\n\t\t\t\t</div>\n\t\t\t}\n\t\t>\n\t\t\t<Await\n\t\t\t\tresolve={diff}\n\t\t\t\terrorElement={\n\t\t\t\t\t<p className=\"p-6 text-foreground-destructive\">\n\t\t\t\t\t\tThere was an error calculating the diff. Sorry.\n\t\t\t\t\t</p>\n\t\t\t\t}\n\t\t\t>\n\t\t\t\t{(diff) => (\n\t\t\t\t\t<div className=\"flex h-full w-full flex-col\">\n\t\t\t\t\t\t<div className=\"flex h-14 min-h-14 w-full overflow-x-hidden border-b\">\n\t\t\t\t\t\t\t<div className=\"border-r\">\n\t\t\t\t\t\t\t\t<SimpleTooltip content=\"Reload diff\">\n\t\t\t\t\t\t\t\t\t<Link\n\t\t\t\t\t\t\t\t\t\tto={`.?${paramsWithForcedRefresh}`}\n\t\t\t\t\t\t\t\t\t\tclassName=\"flex h-full w-14 items-center justify-center\"\n\t\t\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t\t\t<Icon\n\t\t\t\t\t\t\t\t\t\t\tname=\"Refresh\"\n\t\t\t\t\t\t\t\t\t\t\tclassName={cn({ 'animate-spin': spinnerNavigating })}\n\t\t\t\t\t\t\t\t\t\t/>\n\t\t\t\t\t\t\t\t\t</Link>\n\t\t\t\t\t\t\t\t</SimpleTooltip>\n\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t\t<Form\n\t\t\t\t\t\t\t\tonChange={(e) => submit(e.currentTarget)}\n\t\t\t\t\t\t\t\tclassName=\"flex h-full flex-1 items-center overflow-x-auto scrollbar-thin scrollbar-thumb-scrollbar\"\n\t\t\t\t\t\t\t\tkey={`${diff.app1}${diff.app2}`}\n\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t{hiddenInputs}\n\t\t\t\t\t\t\t\t<SelectFileToDiff\n\t\t\t\t\t\t\t\t\tname=\"app1\"\n\t\t\t\t\t\t\t\t\tlabel=\"App 1\"\n\t\t\t\t\t\t\t\t\tclassName=\"border-r\"\n\t\t\t\t\t\t\t\t\tallApps={allApps}\n\t\t\t\t\t\t\t\t\tdefaultValue={diff.app1}\n\t\t\t\t\t\t\t\t/>\n\t\t\t\t\t\t\t\t<SelectFileToDiff\n\t\t\t\t\t\t\t\t\tname=\"app2\"\n\t\t\t\t\t\t\t\t\tlabel=\"App 2\"\n\t\t\t\t\t\t\t\t\tallApps={allApps}\n\t\t\t\t\t\t\t\t\tdefaultValue={diff.app2}\n\t\t\t\t\t\t\t\t/>\n\t\t\t\t\t\t\t</Form>\n\t\t\t\t\t\t</div>\n\t\t\t\t\t\t<div className=\"flex-grow overflow-y-scroll scrollbar-thin scrollbar-thumb-scrollbar\">\n\t\t\t\t\t\t\t{diff.diffCode ? (\n\t\t\t\t\t\t\t\t<div>\n\t\t\t\t\t\t\t\t\t<Accordion.Root className=\"w-full\" type=\"multiple\">\n\t\t\t\t\t\t\t\t\t\t<Mdx code={diff.diffCode} components={mdxComponents} />\n\t\t\t\t\t\t\t\t\t</Accordion.Root>\n\t\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t\t) : diff.app1 && diff.app2 ? (\n\t\t\t\t\t\t\t\t<p className=\"m-5 inline-flex items-center justify-center bg-foreground px-1 py-0.5 font-mono text-sm uppercase text-background\">\n\t\t\t\t\t\t\t\t\tThere was a problem generating the diff\n\t\t\t\t\t\t\t\t</p>\n\t\t\t\t\t\t\t) : (\n\t\t\t\t\t\t\t\t<p className=\"m-5 inline-flex items-center justify-center bg-foreground px-1 py-0.5 font-mono text-sm uppercase text-background\">\n\t\t\t\t\t\t\t\t\tSelect two apps to compare\n\t\t\t\t\t\t\t\t</p>\n\t\t\t\t\t\t\t)}\n\t\t\t\t\t\t</div>\n\t\t\t\t\t\t<RevalidateApps app1={diff.app1} app2={diff.app2} />\n\t\t\t\t\t</div>\n\t\t\t\t)}\n\t\t\t</Await>\n\t\t</Suspense>\n\t)\n}\n\nfunction SelectFileToDiff({\n\tname,\n\tlabel,\n\tclassName,\n\tallApps,\n\tdefaultValue,\n}: {\n\tname: string\n\tlabel: string\n\tclassName?: string\n\tallApps: Array<{ name: string; displayName: string }>\n\tdefaultValue?: string\n}) {\n\treturn (\n\t\t<Select.Root name={name} defaultValue={defaultValue}>\n\t\t\t<Select.Trigger\n\t\t\t\tclassName={clsx(\n\t\t\t\t\t'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',\n\t\t\t\t\tclassName,\n\t\t\t\t)}\n\t\t\t\taria-label={`Select ${label} for git Diff`}\n\t\t\t>\n\t\t\t\t<span className=\"overflow-hidden text-ellipsis whitespace-nowrap\">\n\t\t\t\t\t{label}:{' '}\n\t\t\t\t\t<SelectValue\n\t\t\t\t\t\tplaceholder={`Select ${label}`}\n\t\t\t\t\t\tclassName=\"inline-block w-40 text-ellipsis\"\n\t\t\t\t\t/>\n\t\t\t\t</span>\n\t\t\t\t<Select.Icon className=\"\">\n\t\t\t\t\t<Icon name=\"TriangleDownSmall\" />\n\t\t\t\t</Select.Icon>\n\t\t\t</Select.Trigger>\n\t\t\t<Select.Portal>\n\t\t\t\t<Select.Content\n\t\t\t\t\tposition=\"popper\"\n\t\t\t\t\talign=\"start\"\n\t\t\t\t\tclassName=\"z-20 max-h-[50vh] bg-black text-white lg:max-h-[70vh]\"\n\t\t\t\t>\n\t\t\t\t\t<Select.ScrollUpButton className=\"flex h-5 cursor-default items-center justify-center\">\n\t\t\t\t\t\t<Icon name=\"ChevronUp\" />\n\t\t\t\t\t</Select.ScrollUpButton>\n\t\t\t\t\t<Select.Viewport className=\"p-3\">\n\t\t\t\t\t\t<Select.Group>\n\t\t\t\t\t\t\t<Select.Label className=\"px-5 pb-3 font-mono uppercase\">\n\t\t\t\t\t\t\t\t{label}\n\t\t\t\t\t\t\t</Select.Label>\n\t\t\t\t\t\t\t{allApps.map((app) => {\n\t\t\t\t\t\t\t\treturn (\n\t\t\t\t\t\t\t\t\t<SelectItem key={app.name} value={app.name}>\n\t\t\t\t\t\t\t\t\t\t{app.displayName}\n\t\t\t\t\t\t\t\t\t</SelectItem>\n\t\t\t\t\t\t\t\t)\n\t\t\t\t\t\t\t})}\n\t\t\t\t\t\t</Select.Group>\n\t\t\t\t\t</Select.Viewport>\n\t\t\t\t\t<Select.ScrollDownButton className=\"flex h-5 cursor-default items-center justify-center\">\n\t\t\t\t\t\t<Icon name=\"ChevronDown\" />\n\t\t\t\t\t</Select.ScrollDownButton>\n\t\t\t\t</Select.Content>\n\t\t\t</Select.Portal>\n\t\t</Select.Root>\n\t)\n}\n\nconst SelectItem: React.FC<any> = ({\n\tref: forwardedRef,\n\tchildren,\n\tclassName,\n\t...props\n}) => {\n\treturn (\n\t\t<Select.Item\n\t\t\tclassName={clsx(\n\t\t\t\t'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\n\t\t\t\tclassName,\n\t\t\t)}\n\t\t\t{...props}\n\t\t\tref={forwardedRef}\n\t\t>\n\t\t\t<Select.ItemText>{children}</Select.ItemText>\n\t\t\t<Select.ItemIndicator className=\"absolute left-0 inline-flex w-[25px] items-center justify-center\">\n\t\t\t\t<Icon name=\"CheckSmall\" />\n\t\t\t</Select.ItemIndicator>\n\t\t</Select.Item>\n\t)\n}\n\nconst SelectValue: React.FC<any> = ({\n\tref: forwardedRef,\n\tchildren,\n\tclassName,\n\t...props\n}) => {\n\treturn (\n\t\t<Select.Value {...props} ref={forwardedRef}>\n\t\t\t{props.value}\n\t\t</Select.Value>\n\t)\n}\n"],"names":["pre","props","jsx","mdxComponents","AccordionComponent","RevalidateApps","app1Name","app2Name","apps","useApps","app1","app","app2","useRevalidationWS","Diff","diff","allApps","userHasAccess","useUserHasAccess","submit","useSubmit","params","useSearchParams","paramsWithForcedRefresh","navigation","useNavigation","spinnerNavigating","useSpinDelay","hiddenInputs","key","value","Suspense","SimpleTooltip","Icon","Await","jsxs","Link","cn","Form","e","SelectFileToDiff","Accordion.Root","Mdx","DeferredEpicVideo","name","label","className","defaultValue","Select.Root","Select.Trigger","clsx","SelectValue","Select.Icon","Select.Portal","Select.Content","Select.ScrollUpButton","Select.Viewport","Select.Group","Select.Label","SelectItem","Select.ScrollDownButton","forwardedRef","children","Select.Item","Select.ItemText","Select.ItemIndicator","Select.Value"],"mappings":"ypBA6BA,MAAMA,EAAOC,GAAeC,EAAAA,IAAC,MAAA,CAAK,GAAGD,EAAO,EAEtCE,EAAgB,CACrB,UAAWC,EAEX,IAAAJ,CACD,EAEA,SAASK,EAAe,CACvB,KAAMC,EACN,KAAMC,CACP,EAGG,CACF,MAAMC,EAAOC,EAAA,EACPC,EAAOF,EAAK,KAAMG,GAAQA,EAAI,OAASL,CAAQ,EAC/CM,EAAOJ,EAAK,KAAMG,GAAQA,EAAI,OAASJ,CAAQ,EAErD,OAAAM,EAAkB,CACjB,WAAY,CAACH,GAAM,SAAUE,GAAM,QAAQ,EAAE,OAAO,OAAO,CAAA,CAC3D,EACM,IACR,CAEO,SAASE,GAAK,CACpB,KAAAC,EACA,QAAAC,CACD,EAGG,CACF,MAAMC,EAAgBC,EAAA,EAChBC,EAASC,EAAA,EACT,CAACC,CAAM,EAAIC,EAAA,EACXC,EAA0B,IAAI,gBAAgBF,CAAM,EAC1DE,EAAwB,IAAI,aAAc,MAAM,EAChD,MAAMC,EAAaC,EAAA,EACbC,EAAoBC,EAAAA,aAAaH,EAAW,QAAU,OAAQ,CACnE,MAAO,EACP,YAAa,GAAA,CACb,EAEKI,EAAuC,CAAA,EAC7C,SAAW,CAACC,EAAKC,CAAK,IAAKT,EAAO,UAC7BQ,IAAQ,QAAUA,IAAQ,QAC9BD,EAAa,WACX,QAAA,CAAgB,KAAK,SAAS,KAAMC,EAAK,MAAAC,GAA9BD,CAA4C,CAAA,EAI1D,OAAKZ,EAmBJf,EAAAA,IAAC6B,EAAAA,SAAA,CACA,SACC7B,EAAAA,IAAC,MAAA,CAAI,UAAU,uCACd,eAAC8B,EAAA,CAAc,QAAQ,eACtB,SAAA9B,EAAAA,IAAC+B,GAAK,KAAK,UAAU,UAAU,cAAA,CAAe,EAC/C,EACD,EAGD,SAAA/B,EAAAA,IAACgC,EAAA,CACA,QAASnB,EACT,aACCb,EAAAA,IAAC,IAAA,CAAE,UAAU,kCAAkC,SAAA,kDAE/C,EAGA,SAACa,GACDoB,EAAAA,KAAC,MAAA,CAAI,UAAU,8BACd,SAAA,CAAAA,EAAAA,KAAC,MAAA,CAAI,UAAU,uDACd,SAAA,CAAAjC,EAAAA,IAAC,OAAI,UAAU,WACd,SAAAA,MAAC8B,EAAA,CAAc,QAAQ,cACtB,SAAA9B,EAAAA,IAACkC,EAAA,CACA,GAAI,KAAKb,CAAuB,GAChC,UAAU,+CAEV,SAAArB,EAAAA,IAAC+B,EAAA,CACA,KAAK,UACL,UAAWI,EAAG,CAAE,eAAgBX,EAAmB,CAAA,CAAA,CACpD,CAAA,EAEF,CAAA,CACD,EACAS,EAAAA,KAACG,EAAA,CACA,SAAWC,GAAMpB,EAAOoB,EAAE,aAAa,EACvC,UAAU,2FAGT,SAAA,CAAAX,EACD1B,EAAAA,IAACsC,EAAA,CACA,KAAK,OACL,MAAM,QACN,UAAU,WACV,QAAAxB,EACA,aAAcD,EAAK,IAAA,CAAA,EAEpBb,EAAAA,IAACsC,EAAA,CACA,KAAK,OACL,MAAM,QACN,QAAAxB,EACA,aAAcD,EAAK,IAAA,CAAA,CACpB,CAAA,EAfK,GAAGA,EAAK,IAAI,GAAGA,EAAK,IAAI,EAAA,CAgB9B,EACD,QACC,MAAA,CAAI,UAAU,uEACb,SAAAA,EAAK,SACLb,EAAAA,IAAC,MAAA,CACA,eAACuC,EAAA,CAAe,UAAU,SAAS,KAAK,WACvC,SAAAvC,EAAAA,IAACwC,GAAI,KAAM3B,EAAK,SAAU,WAAYZ,EAAe,CAAA,CACtD,CAAA,CACD,EACGY,EAAK,MAAQA,EAAK,KACrBb,MAAC,KAAE,UAAU,oHAAoH,mDAEjI,EAEAA,EAAAA,IAAC,KAAE,UAAU,oHAAoH,sCAEjI,CAAA,CAEF,QACCG,EAAA,CAAe,KAAMU,EAAK,KAAM,KAAMA,EAAK,IAAA,CAAM,CAAA,CAAA,CACnD,CAAA,CAAA,CAEF,CAAA,EA3FAoB,EAAAA,KAAC,MAAA,CAAI,UAAU,cACd,SAAA,CAAAA,EAAAA,KAAC,MAAA,CAAI,UAAU,yCACd,SAAA,CAAAjC,EAAAA,IAAC,IAAA,CAAE,UAAU,qBAAqB,SAAA,gBAAa,EAC/CA,EAAAA,IAAC,IAAA,CAAE,UAAU,UAAU,SAAA,+DAAA,CAEvB,CAAA,EACD,EACAA,EAAAA,IAAC,MAAA,CAAI,UAAU,MAAA,CAAO,EACtBA,EAAAA,IAAC,IAAA,CAAE,UAAU,OAAO,SAAA,sDAEpB,EACAA,EAAAA,IAACyC,EAAA,CAAkB,IAAI,0DAAA,CAA2D,CAAA,EACnF,CAkFH,CAEA,SAASH,EAAiB,CACzB,KAAAI,EACA,MAAAC,EACA,UAAAC,EACA,QAAA9B,EACA,aAAA+B,CACD,EAMG,CACF,OACCZ,EAAAA,KAACa,EAAA,CAAY,KAAAJ,EAAY,aAAAG,EACxB,SAAA,CAAAZ,EAAAA,KAACc,EAAA,CACA,UAAWC,EACV,wIACAJ,CAAA,EAED,aAAY,UAAUD,CAAK,gBAE3B,SAAA,CAAAV,EAAAA,KAAC,OAAA,CAAK,UAAU,kDACd,SAAA,CAAAU,EAAM,IAAE,IACT3C,EAAAA,IAACiD,EAAA,CACA,YAAa,UAAUN,CAAK,GAC5B,UAAU,iCAAA,CAAA,CACX,EACD,EACA3C,EAAAA,IAACkD,EAAA,CAAY,UAAU,GACtB,SAAAlD,EAAAA,IAAC+B,EAAA,CAAK,KAAK,mBAAA,CAAoB,CAAA,CAChC,CAAA,CAAA,CAAA,EAED/B,MAACmD,EAAA,CACA,SAAAlB,EAAAA,KAACmB,EAAA,CACA,SAAS,SACT,MAAM,QACN,UAAU,wDAEV,SAAA,CAAApD,EAAAA,IAACqD,EAAA,CAAsB,UAAU,sDAChC,SAAArD,MAAC+B,EAAA,CAAK,KAAK,WAAA,CAAY,CAAA,CACxB,EACA/B,MAACsD,EAAA,CAAgB,UAAU,MAC1B,SAAArB,EAAAA,KAACsB,EAAA,CACA,SAAA,CAAAvD,EAAAA,IAACwD,EAAA,CAAa,UAAU,gCACtB,SAAAb,EACF,EACC7B,EAAQ,IAAKL,GAEZT,MAACyD,GAA0B,MAAOhD,EAAI,KACpC,SAAAA,EAAI,aADWA,EAAI,IAErB,CAED,CAAA,CAAA,CACF,CAAA,CACD,EACAT,EAAAA,IAAC0D,EAAA,CAAwB,UAAU,sDAClC,SAAA1D,EAAAA,IAAC+B,EAAA,CAAK,KAAK,aAAA,CAAc,CAAA,CAC1B,CAAA,CAAA,CAAA,CACD,CACD,CAAA,EACD,CAEF,CAEA,MAAM0B,EAA4B,CAAC,CAClC,IAAKE,EACL,SAAAC,EACA,UAAAhB,EACA,GAAG7C,CACJ,IAEEkC,EAAAA,KAAC4B,EAAA,CACA,UAAWb,EACV,4NAEAJ,CAAA,EAEA,GAAG7C,EACJ,IAAK4D,EAEL,SAAA,CAAA3D,MAAC8D,EAAA,CAAiB,SAAAF,EAAS,EAC3B5D,EAAAA,IAAC+D,EAAA,CAAqB,UAAU,mEAC/B,SAAA/D,EAAAA,IAAC+B,EAAA,CAAK,KAAK,YAAA,CAAa,CAAA,CACzB,CAAA,CAAA,CAAA,EAKGkB,EAA6B,CAAC,CACnC,IAAKU,EACL,SAAAC,EACA,UAAAhB,EACA,GAAG7C,CACJ,IAEEC,EAAAA,IAACgE,EAAA,CAAc,GAAGjE,EAAO,IAAK4D,EAC5B,SAAA5D,EAAM,MACR"}
@@ -1,2 +1,2 @@
1
- import{w as a,c as e,l as m,f as p}from"./chunk-EF7DTUVF-ByhKO_Pl.js";import{j as r}from"./jsx-runtime-EKYJJIwR.js";import{d as n,c as f}from"./misc-DjWUkK1U.js";import{D as c}from"./diff-Dwb3EWYp.js";import{N as d}from"./nav-chevrons-BOkHwadX.js";import"./index-DatCARk7.js";import"./clsx-B-dksMZM.js";import"./accordion-BBn2ZFM9.js";import"./tooltip-JIUlMcsz.js";import"./index-DA15my8N.js";import"./index-2USrBHAC.js";import"./index-Be-5FhjB.js";import"./mdx-Bbi38W8y.js";import"./index-Bn6wT_6F.js";import"./epic-video-BODCgn-e.js";import"./index-MRSoBlHC.js";import"./pe-D3WpHDnY.js";import"./online-CxLmaFqb.js";import"./loading-DJq7N2Fo.js";import"./user-CJVisi_Z.js";import"./workshop-config-CcvXvaNp.js";import"./preload-helper-BXl3LOEh.js";import"./progress-bar-C8ErpL4p.js";import"./revalidation-ws-BMyn5NqG.js";const B=a(function(){const i=e(),[t]=m();new URLSearchParams(t).set("forceFresh","diff");const o=p(),s=n.useSpinDelay(o.state!=="idle",{delay:200,minDuration:200});return r.jsxs("div",{className:f("grid h-full grid-rows-[1fr,auto]",{"cursor-wait opacity-30":s}),children:[r.jsx("div",{className:"overflow-y-auto",children:r.jsx(c,{diff:i.diff,allApps:i.allApps})}),r.jsx("div",{className:"flex h-16 items-center justify-end border-t",children:r.jsx(d,{prev:i.prevLink,next:i.nextLink})})]})});export{B as default};
2
- //# sourceMappingURL=diff-Tx3FhzEy.js.map
1
+ import{w as a,c as e,l as m,f as p}from"./chunk-EF7DTUVF-ByhKO_Pl.js";import{j as r}from"./jsx-runtime-EKYJJIwR.js";import{d as n,c as f}from"./misc-DjWUkK1U.js";import{D as c}from"./diff-0XgucEQg.js";import{N as d}from"./nav-chevrons-BOkHwadX.js";import"./index-DatCARk7.js";import"./clsx-B-dksMZM.js";import"./accordion-BBn2ZFM9.js";import"./tooltip-JIUlMcsz.js";import"./index-DA15my8N.js";import"./index-2USrBHAC.js";import"./index-Be-5FhjB.js";import"./mdx-BDFRig3X.js";import"./index-Bn6wT_6F.js";import"./epic-video-BODCgn-e.js";import"./index-MRSoBlHC.js";import"./pe-D3WpHDnY.js";import"./online-CxLmaFqb.js";import"./loading-DJq7N2Fo.js";import"./user-CJVisi_Z.js";import"./workshop-config-CcvXvaNp.js";import"./preload-helper-BXl3LOEh.js";import"./progress-bar-C8ErpL4p.js";import"./revalidation-ws-BMyn5NqG.js";const B=a(function(){const i=e(),[t]=m();new URLSearchParams(t).set("forceFresh","diff");const o=p(),s=n.useSpinDelay(o.state!=="idle",{delay:200,minDuration:200});return r.jsxs("div",{className:f("grid h-full grid-rows-[1fr,auto]",{"cursor-wait opacity-30":s}),children:[r.jsx("div",{className:"overflow-y-auto",children:r.jsx(c,{diff:i.diff,allApps:i.allApps})}),r.jsx("div",{className:"flex h-16 items-center justify-end border-t",children:r.jsx(d,{prev:i.prevLink,next:i.nextLink})})]})});export{B as default};
2
+ //# sourceMappingURL=diff-C84h1q-R.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"diff-Tx3FhzEy.js","sources":["../../../app/routes/diff.tsx"],"sourcesContent":["import {\n\tgetAppByName,\n\tgetAppDisplayName,\n\tgetApps,\n\tisExerciseStepApp,\n} from '@epic-web/workshop-utils/apps.server'\nimport { getDiffCode } from '@epic-web/workshop-utils/diff.server'\nimport { makeTimings } from '@epic-web/workshop-utils/timing.server'\nimport {\n\ttype LoaderFunctionArgs,\n\tuseLoaderData,\n\tuseNavigation,\n\tuseSearchParams,\n} from 'react-router'\nimport { useSpinDelay } from 'spin-delay'\nimport { Diff } from '#app/components/diff.tsx'\nimport { NavChevrons } from '#app/components/nav-chevrons.tsx'\nimport { cn } from '#app/utils/misc.tsx'\n\nexport async function loader({ request }: LoaderFunctionArgs) {\n\tconst reqUrl = new URL(request.url)\n\tconst searchParams = reqUrl.searchParams\n\tconst timings = makeTimings('diffLoader')\n\tconst cacheOptions = { request, timings }\n\tconst allAppsFull = await getApps()\n\tconst app1Name = reqUrl.searchParams.get('app1')\n\tconst app2Name = reqUrl.searchParams.get('app2')\n\n\tconst usingDefaultApp1 = !app1Name\n\n\t// defaults to first problem app\n\tconst app1 = app1Name\n\t\t? await getAppByName(app1Name)\n\t\t: allAppsFull.filter(isExerciseStepApp).at(0)\n\n\t// defaults to last exercise step app\n\tconst app2 = app2Name\n\t\t? await getAppByName(app2Name)\n\t\t: allAppsFull.filter(isExerciseStepApp).at(-1)\n\n\tasync function getDiffProp() {\n\t\tif (!app1 || !app2) {\n\t\t\treturn {\n\t\t\t\tapp1: app1?.name,\n\t\t\t\tapp2: app2?.name,\n\t\t\t\tdiffCode: null,\n\t\t\t}\n\t\t}\n\t\tconst diffCode = await getDiffCode(app1, app2, {\n\t\t\t...cacheOptions,\n\t\t\tforceFresh: searchParams.get('forceFresh') === 'diff',\n\t\t}).catch((e) => {\n\t\t\tconsole.error(e)\n\t\t\treturn null\n\t\t})\n\t\treturn {\n\t\t\tapp1: app1.name,\n\t\t\tapp2: app2.name,\n\t\t\tdiffCode,\n\t\t}\n\t}\n\n\tconst allApps = allAppsFull\n\t\t.filter((a, i, ar) => ar.findIndex((b) => a.name === b.name) === i)\n\t\t.map((a) => ({\n\t\t\tdisplayName: getAppDisplayName(a, allAppsFull),\n\t\t\tname: a.name,\n\t\t\ttitle: a.title,\n\t\t\ttype: a.type,\n\t\t}))\n\n\tconst diff = getDiffProp()\n\tconst app1Index = allApps.findIndex((a) => a.name === app1?.name)\n\tconst prevApp1Index = usingDefaultApp1\n\t\t? allApps.length - 2\n\t\t: app1Index === 0\n\t\t\t? -2\n\t\t\t: app1Index - 1\n\tconst prevApp2Index = prevApp1Index + 1\n\tconst nextApp1Index = usingDefaultApp1\n\t\t? 0\n\t\t: app1Index + 1 < allApps.length\n\t\t\t? app1Index + 1\n\t\t\t: -2\n\tconst nextApp2Index = nextApp1Index + 1\n\tconst prevApp1 = allAppsFull[prevApp1Index]?.name\n\tconst prevApp2 = allAppsFull[prevApp2Index]?.name\n\tconst nextApp1 = allAppsFull[nextApp1Index]?.name\n\tconst nextApp2 = allAppsFull[nextApp2Index]?.name\n\tconst prevSearchParams = new URLSearchParams(reqUrl.searchParams)\n\tprevSearchParams.set('app1', prevApp1 ?? '')\n\tprevSearchParams.set('app2', prevApp2 ?? '')\n\tconst nextSearchParams = new URLSearchParams(reqUrl.searchParams)\n\tnextSearchParams.set('app1', nextApp1 ?? '')\n\tnextSearchParams.set('app2', nextApp2 ?? '')\n\treturn {\n\t\tallApps,\n\t\tdiff,\n\t\tprevLink:\n\t\t\tprevApp1 && prevApp2\n\t\t\t\t? { to: `/diff?${prevSearchParams}`, 'aria-label': 'Previous App' }\n\t\t\t\t: { to: '/diff' },\n\t\tnextLink:\n\t\t\tnextApp1 && nextApp2\n\t\t\t\t? { to: `/diff?${nextSearchParams}`, 'aria-label': 'Next App' }\n\t\t\t\t: { to: '/diff' },\n\t}\n}\n\nexport default function DiffViewer() {\n\tconst data = useLoaderData<typeof loader>()\n\tconst [params] = useSearchParams()\n\tconst paramsWithForcedRefresh = new URLSearchParams(params)\n\tparamsWithForcedRefresh.set('forceFresh', 'diff')\n\tconst navigation = useNavigation()\n\tconst isNavigating = useSpinDelay(navigation.state !== 'idle', {\n\t\tdelay: 200,\n\t\tminDuration: 200,\n\t})\n\n\treturn (\n\t\t<div\n\t\t\tclassName={cn('grid h-full grid-rows-[1fr,auto]', {\n\t\t\t\t'cursor-wait opacity-30': isNavigating,\n\t\t\t})}\n\t\t>\n\t\t\t<div className=\"overflow-y-auto\">\n\t\t\t\t<Diff diff={data.diff} allApps={data.allApps} />\n\t\t\t</div>\n\t\t\t<div className=\"flex h-16 items-center justify-end border-t\">\n\t\t\t\t<NavChevrons prev={data.prevLink} next={data.nextLink} />\n\t\t\t</div>\n\t\t</div>\n\t)\n}\n"],"names":["diff","_UNSAFE_withComponentProps","data","useLoaderData","params","useSearchParams","URLSearchParams","set","navigation","useNavigation","isNavigating","useSpinDelay","state","delay","minDuration","jsxs","className","cn","children","jsx","Diff","allApps","NavChevrons","prev","prevLink","next","nextLink"],"mappings":"uzBA6GA,MAAAA,EAAAC,EAAA,UAAqC,CACpC,MAAMC,EAAOC,EAAA,EACP,CAACC,CAAM,EAAIC,EAAA,EACe,IAAIC,gBAAgBF,CAAM,EAClCG,IAAI,aAAc,MAAM,EAChD,MAAMC,EAAaC,EAAA,EACbC,EAAeC,EAAAA,aAAaH,EAAWI,QAAU,OAAQ,CAC9DC,MAAO,IACPC,YAAa,GACd,CAAC,EAED,OACCC,EAAAA,KAAC,MAAA,CACAC,UAAWC,EAAG,mCAAoC,CACjD,yBAA0BP,CAC3B,CAAC,EAEDQ,SAAA,CAAAC,EAAAA,IAAC,MAAA,CAAIH,UAAU,kBACdE,SAAAC,EAAAA,IAACC,EAAA,CAAKpB,KAAME,EAAKF,KAAMqB,QAASnB,EAAKmB,QAAS,CAAA,CAC/C,EACAF,EAAAA,IAAC,MAAA,CAAIH,UAAU,8CACdE,SAAAC,EAAAA,IAACG,EAAA,CAAYC,KAAMrB,EAAKsB,SAAUC,KAAMvB,EAAKwB,SAAU,CAAA,CACxD,CAAA,CAAA,CACD,CAEF,CAAA"}
1
+ {"version":3,"file":"diff-C84h1q-R.js","sources":["../../../app/routes/diff.tsx"],"sourcesContent":["import {\n\tgetAppByName,\n\tgetAppDisplayName,\n\tgetApps,\n\tisExerciseStepApp,\n} from '@epic-web/workshop-utils/apps.server'\nimport { getDiffCode } from '@epic-web/workshop-utils/diff.server'\nimport { makeTimings } from '@epic-web/workshop-utils/timing.server'\nimport {\n\ttype LoaderFunctionArgs,\n\tuseLoaderData,\n\tuseNavigation,\n\tuseSearchParams,\n} from 'react-router'\nimport { useSpinDelay } from 'spin-delay'\nimport { Diff } from '#app/components/diff.tsx'\nimport { NavChevrons } from '#app/components/nav-chevrons.tsx'\nimport { cn } from '#app/utils/misc.tsx'\n\nexport async function loader({ request }: LoaderFunctionArgs) {\n\tconst reqUrl = new URL(request.url)\n\tconst searchParams = reqUrl.searchParams\n\tconst timings = makeTimings('diffLoader')\n\tconst cacheOptions = { request, timings }\n\tconst allAppsFull = await getApps()\n\tconst app1Name = reqUrl.searchParams.get('app1')\n\tconst app2Name = reqUrl.searchParams.get('app2')\n\n\tconst usingDefaultApp1 = !app1Name\n\n\t// defaults to first problem app\n\tconst app1 = app1Name\n\t\t? await getAppByName(app1Name)\n\t\t: allAppsFull.filter(isExerciseStepApp).at(0)\n\n\t// defaults to last exercise step app\n\tconst app2 = app2Name\n\t\t? await getAppByName(app2Name)\n\t\t: allAppsFull.filter(isExerciseStepApp).at(-1)\n\n\tasync function getDiffProp() {\n\t\tif (!app1 || !app2) {\n\t\t\treturn {\n\t\t\t\tapp1: app1?.name,\n\t\t\t\tapp2: app2?.name,\n\t\t\t\tdiffCode: null,\n\t\t\t}\n\t\t}\n\t\tconst diffCode = await getDiffCode(app1, app2, {\n\t\t\t...cacheOptions,\n\t\t\tforceFresh: searchParams.get('forceFresh') === 'diff',\n\t\t}).catch((e) => {\n\t\t\tconsole.error(e)\n\t\t\treturn null\n\t\t})\n\t\treturn {\n\t\t\tapp1: app1.name,\n\t\t\tapp2: app2.name,\n\t\t\tdiffCode,\n\t\t}\n\t}\n\n\tconst allApps = allAppsFull\n\t\t.filter((a, i, ar) => ar.findIndex((b) => a.name === b.name) === i)\n\t\t.map((a) => ({\n\t\t\tdisplayName: getAppDisplayName(a, allAppsFull),\n\t\t\tname: a.name,\n\t\t\ttitle: a.title,\n\t\t\ttype: a.type,\n\t\t}))\n\n\tconst diff = getDiffProp()\n\tconst app1Index = allApps.findIndex((a) => a.name === app1?.name)\n\tconst prevApp1Index = usingDefaultApp1\n\t\t? allApps.length - 2\n\t\t: app1Index === 0\n\t\t\t? -2\n\t\t\t: app1Index - 1\n\tconst prevApp2Index = prevApp1Index + 1\n\tconst nextApp1Index = usingDefaultApp1\n\t\t? 0\n\t\t: app1Index + 1 < allApps.length\n\t\t\t? app1Index + 1\n\t\t\t: -2\n\tconst nextApp2Index = nextApp1Index + 1\n\tconst prevApp1 = allAppsFull[prevApp1Index]?.name\n\tconst prevApp2 = allAppsFull[prevApp2Index]?.name\n\tconst nextApp1 = allAppsFull[nextApp1Index]?.name\n\tconst nextApp2 = allAppsFull[nextApp2Index]?.name\n\tconst prevSearchParams = new URLSearchParams(reqUrl.searchParams)\n\tprevSearchParams.set('app1', prevApp1 ?? '')\n\tprevSearchParams.set('app2', prevApp2 ?? '')\n\tconst nextSearchParams = new URLSearchParams(reqUrl.searchParams)\n\tnextSearchParams.set('app1', nextApp1 ?? '')\n\tnextSearchParams.set('app2', nextApp2 ?? '')\n\treturn {\n\t\tallApps,\n\t\tdiff,\n\t\tprevLink:\n\t\t\tprevApp1 && prevApp2\n\t\t\t\t? { to: `/diff?${prevSearchParams}`, 'aria-label': 'Previous App' }\n\t\t\t\t: { to: '/diff' },\n\t\tnextLink:\n\t\t\tnextApp1 && nextApp2\n\t\t\t\t? { to: `/diff?${nextSearchParams}`, 'aria-label': 'Next App' }\n\t\t\t\t: { to: '/diff' },\n\t}\n}\n\nexport default function DiffViewer() {\n\tconst data = useLoaderData<typeof loader>()\n\tconst [params] = useSearchParams()\n\tconst paramsWithForcedRefresh = new URLSearchParams(params)\n\tparamsWithForcedRefresh.set('forceFresh', 'diff')\n\tconst navigation = useNavigation()\n\tconst isNavigating = useSpinDelay(navigation.state !== 'idle', {\n\t\tdelay: 200,\n\t\tminDuration: 200,\n\t})\n\n\treturn (\n\t\t<div\n\t\t\tclassName={cn('grid h-full grid-rows-[1fr,auto]', {\n\t\t\t\t'cursor-wait opacity-30': isNavigating,\n\t\t\t})}\n\t\t>\n\t\t\t<div className=\"overflow-y-auto\">\n\t\t\t\t<Diff diff={data.diff} allApps={data.allApps} />\n\t\t\t</div>\n\t\t\t<div className=\"flex h-16 items-center justify-end border-t\">\n\t\t\t\t<NavChevrons prev={data.prevLink} next={data.nextLink} />\n\t\t\t</div>\n\t\t</div>\n\t)\n}\n"],"names":["diff","_UNSAFE_withComponentProps","data","useLoaderData","params","useSearchParams","URLSearchParams","set","navigation","useNavigation","isNavigating","useSpinDelay","state","delay","minDuration","jsxs","className","cn","children","jsx","Diff","allApps","NavChevrons","prev","prevLink","next","nextLink"],"mappings":"uzBA6GA,MAAAA,EAAAC,EAAA,UAAqC,CACpC,MAAMC,EAAOC,EAAA,EACP,CAACC,CAAM,EAAIC,EAAA,EACe,IAAIC,gBAAgBF,CAAM,EAClCG,IAAI,aAAc,MAAM,EAChD,MAAMC,EAAaC,EAAA,EACbC,EAAeC,EAAAA,aAAaH,EAAWI,QAAU,OAAQ,CAC9DC,MAAO,IACPC,YAAa,GACd,CAAC,EAED,OACCC,EAAAA,KAAC,MAAA,CACAC,UAAWC,EAAG,mCAAoC,CACjD,yBAA0BP,CAC3B,CAAC,EAEDQ,SAAA,CAAAC,EAAAA,IAAC,MAAA,CAAIH,UAAU,kBACdE,SAAAC,EAAAA,IAACC,EAAA,CAAKpB,KAAME,EAAKF,KAAMqB,QAASnB,EAAKmB,QAAS,CAAA,CAC/C,EACAF,EAAAA,IAAC,MAAA,CAAIH,UAAU,8CACdE,SAAAC,EAAAA,IAACG,EAAA,CAAYC,KAAMrB,EAAKsB,SAAUC,KAAMvB,EAAKwB,SAAU,CAAA,CACxD,CAAA,CAAA,CACD,CAEF,CAAA"}
@@ -1,2 +1,2 @@
1
- import{w as l,L as n}from"./chunk-EF7DTUVF-ByhKO_Pl.js";import{j as e}from"./jsx-runtime-EKYJJIwR.js";import{E as a}from"./index-CcWv7OrP.js";import{r as c}from"./index-DatCARk7.js";import{E as m}from"./epic-video-BODCgn-e.js";import{I as d,c as f}from"./misc-DjWUkK1U.js";import{L as p}from"./loading-DJq7N2Fo.js";import{N as h}from"./nav-chevrons-BOkHwadX.js";import{u as x}from"./revalidation-ws-BMyn5NqG.js";import{M as u,E as j}from"./mdx-Bbi38W8y.js";import{u as b}from"./online-CxLmaFqb.js";import{g}from"./seo-t5J-DRxw.js";import{P as v}from"./progress-CkGdQlTp.js";import{u as w}from"./index-MRSoBlHC.js";import"./user-CJVisi_Z.js";import"./workshop-config-CcvXvaNp.js";import"./clsx-B-dksMZM.js";import"./index-DA15my8N.js";import"./index-Bn6wT_6F.js";import"./preload-helper-BXl3LOEh.js";import"./progress-bar-C8ErpL4p.js";import"./pe-D3WpHDnY.js";import"./tooltip-JIUlMcsz.js";const B={getSitemapEntries:()=>[{route:"/finished"}]},J=({matches:r})=>{const s=r.find(o=>o?.id==="root")?.data;return s?g({title:`🎉 ${s?.workshopTitle}`,description:`Elaboration for ${s?.workshopTitle}`,ogTitle:`Finished ${s?.workshopTitle}`,ogDescription:"You finished! Time to submit feedback.",instructor:s.instructor,requestInfo:s.requestInfo}):[]},N={h1:()=>null},K=l(function({loaderData:s}){return x({watchPaths:["./exercises/FINISHED.mdx"]}),e.jsx("div",{className:"flex h-full flex-grow flex-col",children:e.jsxs("main",{className:"grid h-full flex-grow grid-cols-1 grid-rows-2 lg:grid-cols-2 lg:grid-rows-1",children:[e.jsxs("div",{className:"relative col-span-1 row-span-1 flex h-full flex-col lg:border-r",children:[e.jsx("h1",{className:"h-14 border-b pl-10 pr-5 text-sm font-medium uppercase leading-none",children:e.jsx("div",{className:"flex h-14 flex-wrap items-center justify-between gap-x-2 py-2",children:e.jsxs("div",{className:"flex items-center justify-start gap-x-2",children:[e.jsx(n,{to:"/",className:"hover:underline",children:s.workshopTitle}),e.jsx("span",{children:"/"}),e.jsx("span",{children:"Elaboration"})]})})}),e.jsx("article",{className:"shadow-on-scrollbox h-full w-full max-w-none flex-1 scroll-pt-6 space-y-6 overflow-y-auto p-2 scrollbar-thin scrollbar-thumb-scrollbar sm:p-10 sm:pt-8",id:s.articleId,children:s.finishedCode?e.jsx(m,{epicVideoInfosPromise:s.epicVideoInfosPromise,children:e.jsx("div",{className:"prose dark:prose-invert sm:prose-lg",children:e.jsx(u,{code:s.finishedCode,components:N})})}):"No finished instructions yet..."}),e.jsx(a,{elementQuery:`#${s.articleId}`}),e.jsx(v,{type:"workshop-finished",className:"h-14 border-t px-6"}),e.jsxs("div",{className:"flex h-16 justify-between border-b-4 border-t lg:border-b-0",children:[e.jsx("div",{}),s.workshopFinished.status==="success"?e.jsx(j,{file:s.workshopFinished.file,relativePath:s.workshopFinished.relativePath}):null,e.jsx(h,{prev:s.prevStepLink,next:{to:"/"}})]})]}),e.jsx(k,{workshopTitle:s.workshopTitle,workshopFormEmbedUrl:s.workshopFormEmbedUrl})]})})});function k({workshopTitle:r,workshopFormEmbedUrl:s}){const o=w(),[i,t]=c.useState(!1);return b()?e.jsxs("div",{className:"relative flex-shrink-0",children:[i?null:e.jsx("div",{className:"absolute inset-0 z-10 flex items-center justify-center",children:e.jsx(p,{children:e.jsxs("span",{children:["Loading ",r," Elaboration form"]})})}),e.jsx("iframe",{onLoad:()=>t(!0),onError:()=>t(!0),title:"Elaboration",src:s,className:f("absolute inset-0 flex h-full w-full transition-opacity duration-300",i?"opacity-100":"opacity-0"),style:{colorScheme:o}})]}):e.jsx("div",{className:"relative flex-shrink-0",children:e.jsx("div",{className:"absolute inset-0 z-10 flex items-center justify-center text-foreground-destructive",children:e.jsx(d,{name:"WifiNoConnection",size:"xl",children:e.jsxs("span",{children:["Unable to load the ",e.jsx("a",{href:s,className:"underline",children:`${r} feedback form`})," when offline"]})})})})}export{K as default,B as handle,J as meta};
2
- //# sourceMappingURL=finished-33U_fnqH.js.map
1
+ import{w as l,L as n}from"./chunk-EF7DTUVF-ByhKO_Pl.js";import{j as e}from"./jsx-runtime-EKYJJIwR.js";import{E as a}from"./index-CcWv7OrP.js";import{r as c}from"./index-DatCARk7.js";import{E as m}from"./epic-video-BODCgn-e.js";import{I as d,c as f}from"./misc-DjWUkK1U.js";import{L as p}from"./loading-DJq7N2Fo.js";import{N as h}from"./nav-chevrons-BOkHwadX.js";import{u as x}from"./revalidation-ws-BMyn5NqG.js";import{M as u,E as j}from"./mdx-BDFRig3X.js";import{u as b}from"./online-CxLmaFqb.js";import{g}from"./seo-t5J-DRxw.js";import{P as v}from"./progress-CkGdQlTp.js";import{u as w}from"./index-MRSoBlHC.js";import"./user-CJVisi_Z.js";import"./workshop-config-CcvXvaNp.js";import"./clsx-B-dksMZM.js";import"./index-DA15my8N.js";import"./index-Bn6wT_6F.js";import"./preload-helper-BXl3LOEh.js";import"./progress-bar-C8ErpL4p.js";import"./pe-D3WpHDnY.js";import"./tooltip-JIUlMcsz.js";const B={getSitemapEntries:()=>[{route:"/finished"}]},J=({matches:r})=>{const s=r.find(o=>o?.id==="root")?.data;return s?g({title:`🎉 ${s?.workshopTitle}`,description:`Elaboration for ${s?.workshopTitle}`,ogTitle:`Finished ${s?.workshopTitle}`,ogDescription:"You finished! Time to submit feedback.",instructor:s.instructor,requestInfo:s.requestInfo}):[]},N={h1:()=>null},K=l(function({loaderData:s}){return x({watchPaths:["./exercises/FINISHED.mdx"]}),e.jsx("div",{className:"flex h-full flex-grow flex-col",children:e.jsxs("main",{className:"grid h-full flex-grow grid-cols-1 grid-rows-2 lg:grid-cols-2 lg:grid-rows-1",children:[e.jsxs("div",{className:"relative col-span-1 row-span-1 flex h-full flex-col lg:border-r",children:[e.jsx("h1",{className:"h-14 border-b pl-10 pr-5 text-sm font-medium uppercase leading-none",children:e.jsx("div",{className:"flex h-14 flex-wrap items-center justify-between gap-x-2 py-2",children:e.jsxs("div",{className:"flex items-center justify-start gap-x-2",children:[e.jsx(n,{to:"/",className:"hover:underline",children:s.workshopTitle}),e.jsx("span",{children:"/"}),e.jsx("span",{children:"Elaboration"})]})})}),e.jsx("article",{className:"shadow-on-scrollbox h-full w-full max-w-none flex-1 scroll-pt-6 space-y-6 overflow-y-auto p-2 scrollbar-thin scrollbar-thumb-scrollbar sm:p-10 sm:pt-8",id:s.articleId,children:s.finishedCode?e.jsx(m,{epicVideoInfosPromise:s.epicVideoInfosPromise,children:e.jsx("div",{className:"prose dark:prose-invert sm:prose-lg",children:e.jsx(u,{code:s.finishedCode,components:N})})}):"No finished instructions yet..."}),e.jsx(a,{elementQuery:`#${s.articleId}`}),e.jsx(v,{type:"workshop-finished",className:"h-14 border-t px-6"}),e.jsxs("div",{className:"flex h-16 justify-between border-b-4 border-t lg:border-b-0",children:[e.jsx("div",{}),s.workshopFinished.status==="success"?e.jsx(j,{file:s.workshopFinished.file,relativePath:s.workshopFinished.relativePath}):null,e.jsx(h,{prev:s.prevStepLink,next:{to:"/"}})]})]}),e.jsx(k,{workshopTitle:s.workshopTitle,workshopFormEmbedUrl:s.workshopFormEmbedUrl})]})})});function k({workshopTitle:r,workshopFormEmbedUrl:s}){const o=w(),[i,t]=c.useState(!1);return b()?e.jsxs("div",{className:"relative flex-shrink-0",children:[i?null:e.jsx("div",{className:"absolute inset-0 z-10 flex items-center justify-center",children:e.jsx(p,{children:e.jsxs("span",{children:["Loading ",r," Elaboration form"]})})}),e.jsx("iframe",{onLoad:()=>t(!0),onError:()=>t(!0),title:"Elaboration",src:s,className:f("absolute inset-0 flex h-full w-full transition-opacity duration-300",i?"opacity-100":"opacity-0"),style:{colorScheme:o}})]}):e.jsx("div",{className:"relative flex-shrink-0",children:e.jsx("div",{className:"absolute inset-0 z-10 flex items-center justify-center text-foreground-destructive",children:e.jsx(d,{name:"WifiNoConnection",size:"xl",children:e.jsxs("span",{children:["Unable to load the ",e.jsx("a",{href:s,className:"underline",children:`${r} feedback form`})," when offline"]})})})})}export{K as default,B as handle,J as meta};
2
+ //# sourceMappingURL=finished-CzDipjN1.js.map