@epic-web/workshop-app 5.1.2 → 5.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/build/client/assets/{_exerciseNumber-DarnXgbX.js → _exerciseNumber-Byb05FGg.js} +2 -2
- package/build/client/assets/_exerciseNumber-Byb05FGg.js.map +1 -0
- package/build/client/assets/_exerciseNumber_._stepNumber-BA2Xhzqs.js.map +1 -1
- package/build/client/assets/{_exerciseNumber_.finished-DEzaS_Ji.js → _exerciseNumber_.finished-DUqyxjV2.js} +2 -2
- package/build/client/assets/_exerciseNumber_.finished-DUqyxjV2.js.map +1 -0
- package/build/client/assets/{_layout-BTrPWpBz.js → _layout-BwDoP7Kv.js} +2 -2
- package/build/client/assets/_layout-BwDoP7Kv.js.map +1 -0
- package/build/client/assets/_layout-DvQmiuTm.js +6 -0
- package/build/client/assets/_layout-DvQmiuTm.js.map +1 -0
- package/build/client/assets/_layout-gyrNluke.js.map +1 -1
- package/build/client/assets/account-DbdZ0Vhg.js +2 -0
- package/build/client/assets/account-DbdZ0Vhg.js.map +1 -0
- package/build/client/assets/app-CM8yuYni.js.map +1 -1
- package/build/client/assets/{diff-jlCv3hv0.js → diff-Cmd66hnY.js} +2 -2
- package/build/client/assets/diff-Cmd66hnY.js.map +1 -0
- package/build/client/assets/{diff-assn_bSK.js → diff-CzHloS9Q.js} +2 -2
- package/build/client/assets/{diff-assn_bSK.js.map → diff-CzHloS9Q.js.map} +1 -1
- package/build/client/assets/{discord-CHsbqaqM.js → discord-DGeGrHNb.js} +2 -2
- package/build/client/assets/discord-DGeGrHNb.js.map +1 -0
- package/build/client/assets/discord-arMqZKbH.js +2 -0
- package/build/client/assets/discord-arMqZKbH.js.map +1 -0
- package/build/client/assets/{epic-video-GDpD7_Qt.js → epic-video-Dw5Vkxid.js} +2 -2
- package/build/client/assets/{epic-video-GDpD7_Qt.js.map → epic-video-Dw5Vkxid.js.map} +1 -1
- package/build/client/assets/{finished-DVV0zwmP.js → finished-DbOxW5dc.js} +2 -2
- package/build/client/assets/finished-DbOxW5dc.js.map +1 -0
- package/build/client/assets/{index-KgMLc41c.js → index-Bfqa72Xl.js} +2 -2
- package/build/client/assets/index-Bfqa72Xl.js.map +1 -0
- package/build/client/assets/{index-DJF1fiZI.js → index-D-V8b9oA.js} +2 -2
- package/build/client/assets/index-D-V8b9oA.js.map +1 -0
- package/build/client/assets/index-_J-F_Dnc.js.map +1 -1
- package/build/client/assets/login-pZYDEC_l.js.map +1 -1
- package/build/client/assets/{manifest-3338a6ab.js → manifest-0d355395.js} +1 -1
- package/build/client/assets/{mdx-hW1uYjc1.js → mdx-C01HZJEv.js} +2 -2
- package/build/client/assets/{mdx-hW1uYjc1.js.map → mdx-C01HZJEv.js.map} +1 -1
- package/build/client/assets/{onboarding-DCuSqnkZ.js → onboarding-Dk74xvlh.js} +2 -2
- package/build/client/assets/onboarding-Dk74xvlh.js.map +1 -0
- package/build/client/assets/pe-ChIwTk8v.js.map +1 -1
- package/build/client/assets/presence-DyppfK2V.js +28 -0
- package/build/client/assets/presence-DyppfK2V.js.map +1 -0
- package/build/client/assets/preview-CW_12I0i.js.map +1 -1
- package/build/client/assets/progress-DAB3nDa2.js.map +1 -1
- package/build/client/assets/{root-DojjHZlY.js → root-DCfiv1cO.js} +2 -2
- package/build/client/assets/{root-DojjHZlY.js.map → root-DCfiv1cO.js.map} +1 -1
- package/build/client/assets/{set-playground-DgnOJqFN.js → set-playground-S_rIwJAa.js} +2 -2
- package/build/client/assets/set-playground-S_rIwJAa.js.map +1 -0
- package/build/client/assets/{test-DJ7oeeeg.js → test-D_qZ9Wu9.js} +2 -2
- package/build/client/assets/test-D_qZ9Wu9.js.map +1 -0
- package/build/client/assets/{tests-Bw1rCopV.js → tests-Cmesc4Yz.js} +2 -2
- package/build/client/assets/tests-Cmesc4Yz.js.map +1 -0
- package/build/client/assets/user-AF5-S38o.js +2 -0
- package/build/client/assets/user-AF5-S38o.js.map +1 -0
- package/build/server/index.js +392 -256
- package/build/server/index.js.map +1 -1
- package/dist/server/index.js +0 -2
- package/package.json +4 -4
- package/build/client/assets/_exerciseNumber-DarnXgbX.js.map +0 -1
- package/build/client/assets/_exerciseNumber_.finished-DEzaS_Ji.js.map +0 -1
- package/build/client/assets/_layout-BTrPWpBz.js.map +0 -1
- package/build/client/assets/_layout-T2hZtl0D.js +0 -6
- package/build/client/assets/_layout-T2hZtl0D.js.map +0 -1
- package/build/client/assets/account-CPFwPYf1.js +0 -2
- package/build/client/assets/account-CPFwPYf1.js.map +0 -1
- package/build/client/assets/diff-jlCv3hv0.js.map +0 -1
- package/build/client/assets/discord-CHsbqaqM.js.map +0 -1
- package/build/client/assets/discord-DoeazikD.js +0 -2
- package/build/client/assets/discord-DoeazikD.js.map +0 -1
- package/build/client/assets/finished-DVV0zwmP.js.map +0 -1
- package/build/client/assets/index-DJF1fiZI.js.map +0 -1
- package/build/client/assets/index-KgMLc41c.js.map +0 -1
- package/build/client/assets/onboarding-DCuSqnkZ.js.map +0 -1
- package/build/client/assets/presence-CdyMdOKk.js +0 -28
- package/build/client/assets/presence-CdyMdOKk.js.map +0 -1
- package/build/client/assets/set-playground-DgnOJqFN.js.map +0 -1
- package/build/client/assets/test-DJ7oeeeg.js.map +0 -1
- package/build/client/assets/tests-Bw1rCopV.js.map +0 -1
- package/build/client/assets/user-BBryXlM_.js +0 -2
- package/build/client/assets/user-BBryXlM_.js.map +0 -1
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"_layout-T2hZtl0D.js","sources":["../../../../../node_modules/framer-motion/dist/es/animation/hooks/animation-controls.mjs","../../../../../node_modules/framer-motion/dist/es/animation/hooks/use-animation.mjs","../../../app/components/media-query.ts","../../../../../node_modules/@radix-ui/react-dialog/dist/index.mjs","../../../app/components/ui/dialog.tsx","../../../app/routes/_app+/_layout.tsx"],"sourcesContent":["import { invariant } from '../../utils/errors.mjs';\nimport { setTarget } from '../../render/utils/setters.mjs';\nimport { animateVisualElement } from '../interfaces/visual-element.mjs';\n\nfunction stopAnimation(visualElement) {\n visualElement.values.forEach((value) => value.stop());\n}\nfunction setVariants(visualElement, variantLabels) {\n const reversedLabels = [...variantLabels].reverse();\n reversedLabels.forEach((key) => {\n const variant = visualElement.getVariant(key);\n variant && setTarget(visualElement, variant);\n if (visualElement.variantChildren) {\n visualElement.variantChildren.forEach((child) => {\n setVariants(child, variantLabels);\n });\n }\n });\n}\nfunction setValues(visualElement, definition) {\n if (Array.isArray(definition)) {\n return setVariants(visualElement, definition);\n }\n else if (typeof definition === \"string\") {\n return setVariants(visualElement, [definition]);\n }\n else {\n setTarget(visualElement, definition);\n }\n}\n/**\n * @public\n */\nfunction animationControls() {\n /**\n * Track whether the host component has mounted.\n */\n let hasMounted = false;\n /**\n * A collection of linked component animation controls.\n */\n const subscribers = new Set();\n const controls = {\n subscribe(visualElement) {\n subscribers.add(visualElement);\n return () => void subscribers.delete(visualElement);\n },\n start(definition, transitionOverride) {\n invariant(hasMounted, \"controls.start() should only be called after a component has mounted. Consider calling within a useEffect hook.\");\n const animations = [];\n subscribers.forEach((visualElement) => {\n animations.push(animateVisualElement(visualElement, definition, {\n transitionOverride,\n }));\n });\n return Promise.all(animations);\n },\n set(definition) {\n invariant(hasMounted, \"controls.set() should only be called after a component has mounted. Consider calling within a useEffect hook.\");\n return subscribers.forEach((visualElement) => {\n setValues(visualElement, definition);\n });\n },\n stop() {\n subscribers.forEach((visualElement) => {\n stopAnimation(visualElement);\n });\n },\n mount() {\n hasMounted = true;\n return () => {\n hasMounted = false;\n controls.stop();\n };\n },\n };\n return controls;\n}\n\nexport { animationControls, setValues };\n","import { animationControls } from './animation-controls.mjs';\nimport { useConstant } from '../../utils/use-constant.mjs';\nimport { useIsomorphicLayoutEffect } from '../../utils/use-isomorphic-effect.mjs';\n\n/**\n * Creates `AnimationControls`, which can be used to manually start, stop\n * and sequence animations on one or more components.\n *\n * The returned `AnimationControls` should be passed to the `animate` property\n * of the components you want to animate.\n *\n * These components can then be animated with the `start` method.\n *\n * ```jsx\n * import * as React from 'react'\n * import { motion, useAnimation } from 'framer-motion'\n *\n * export function MyComponent(props) {\n * const controls = useAnimation()\n *\n * controls.start({\n * x: 100,\n * transition: { duration: 0.5 },\n * })\n *\n * return <motion.div animate={controls} />\n * }\n * ```\n *\n * @returns Animation controller with `start` and `stop` methods\n *\n * @public\n */\nfunction useAnimationControls() {\n const controls = useConstant(animationControls);\n useIsomorphicLayoutEffect(controls.mount, []);\n return controls;\n}\nconst useAnimation = useAnimationControls;\n\nexport { useAnimation, useAnimationControls };\n","import { useSyncExternalStore } from 'react'\n\nexport function makeMediaQueryStore(\n\tmediaQuery: string,\n\tserverSnapshot: boolean,\n) {\n\tfunction getSnapshot() {\n\t\treturn window.matchMedia(mediaQuery).matches\n\t}\n\n\tfunction subscribe(callback: () => void) {\n\t\tconst mediaQueryList = window.matchMedia(mediaQuery)\n\t\tmediaQueryList.addEventListener('change', callback)\n\t\treturn () => {\n\t\t\tmediaQueryList.removeEventListener('change', callback)\n\t\t}\n\t}\n\n\treturn function useMediaQuery() {\n\t\treturn useSyncExternalStore(subscribe, getSnapshot, () => serverSnapshot)\n\t}\n}\n","\"use client\";\n\n// packages/react/dialog/src/Dialog.tsx\nimport * as React from \"react\";\nimport { composeEventHandlers } from \"@radix-ui/primitive\";\nimport { useComposedRefs } from \"@radix-ui/react-compose-refs\";\nimport { createContext, createContextScope } from \"@radix-ui/react-context\";\nimport { useId } from \"@radix-ui/react-id\";\nimport { useControllableState } from \"@radix-ui/react-use-controllable-state\";\nimport { DismissableLayer } from \"@radix-ui/react-dismissable-layer\";\nimport { FocusScope } from \"@radix-ui/react-focus-scope\";\nimport { Portal as PortalPrimitive } from \"@radix-ui/react-portal\";\nimport { Presence } from \"@radix-ui/react-presence\";\nimport { Primitive } from \"@radix-ui/react-primitive\";\nimport { useFocusGuards } from \"@radix-ui/react-focus-guards\";\nimport { RemoveScroll } from \"react-remove-scroll\";\nimport { hideOthers } from \"aria-hidden\";\nimport { Slot } from \"@radix-ui/react-slot\";\nimport { Fragment, jsx, jsxs } from \"react/jsx-runtime\";\nvar DIALOG_NAME = \"Dialog\";\nvar [createDialogContext, createDialogScope] = createContextScope(DIALOG_NAME);\nvar [DialogProvider, useDialogContext] = createDialogContext(DIALOG_NAME);\nvar Dialog = (props) => {\n const {\n __scopeDialog,\n children,\n open: openProp,\n defaultOpen,\n onOpenChange,\n modal = true\n } = props;\n const triggerRef = React.useRef(null);\n const contentRef = React.useRef(null);\n const [open = false, setOpen] = useControllableState({\n prop: openProp,\n defaultProp: defaultOpen,\n onChange: onOpenChange\n });\n return /* @__PURE__ */ jsx(\n DialogProvider,\n {\n scope: __scopeDialog,\n triggerRef,\n contentRef,\n contentId: useId(),\n titleId: useId(),\n descriptionId: useId(),\n open,\n onOpenChange: setOpen,\n onOpenToggle: React.useCallback(() => setOpen((prevOpen) => !prevOpen), [setOpen]),\n modal,\n children\n }\n );\n};\nDialog.displayName = DIALOG_NAME;\nvar TRIGGER_NAME = \"DialogTrigger\";\nvar DialogTrigger = React.forwardRef(\n (props, forwardedRef) => {\n const { __scopeDialog, ...triggerProps } = props;\n const context = useDialogContext(TRIGGER_NAME, __scopeDialog);\n const composedTriggerRef = useComposedRefs(forwardedRef, context.triggerRef);\n return /* @__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 }\n);\nDialogTrigger.displayName = TRIGGER_NAME;\nvar PORTAL_NAME = \"DialogPortal\";\nvar [PortalProvider, usePortalContext] = createDialogContext(PORTAL_NAME, {\n forceMount: void 0\n});\nvar DialogPortal = (props) => {\n const { __scopeDialog, forceMount, children, container } = props;\n const context = useDialogContext(PORTAL_NAME, __scopeDialog);\n return /* @__PURE__ */ jsx(PortalProvider, { scope: __scopeDialog, forceMount, children: React.Children.map(children, (child) => /* @__PURE__ */ jsx(Presence, { present: forceMount || context.open, children: /* @__PURE__ */ jsx(PortalPrimitive, { asChild: true, container, children: child }) })) });\n};\nDialogPortal.displayName = PORTAL_NAME;\nvar OVERLAY_NAME = \"DialogOverlay\";\nvar DialogOverlay = React.forwardRef(\n (props, forwardedRef) => {\n const portalContext = usePortalContext(OVERLAY_NAME, props.__scopeDialog);\n const { forceMount = portalContext.forceMount, ...overlayProps } = props;\n const context = useDialogContext(OVERLAY_NAME, props.__scopeDialog);\n return context.modal ? /* @__PURE__ */ jsx(Presence, { present: forceMount || context.open, children: /* @__PURE__ */ jsx(DialogOverlayImpl, { ...overlayProps, ref: forwardedRef }) }) : null;\n }\n);\nDialogOverlay.displayName = OVERLAY_NAME;\nvar DialogOverlayImpl = React.forwardRef(\n (props, forwardedRef) => {\n const { __scopeDialog, ...overlayProps } = props;\n const context = useDialogContext(OVERLAY_NAME, __scopeDialog);\n return (\n // Make sure `Content` is scrollable even when it doesn't live inside `RemoveScroll`\n // ie. when `Overlay` and `Content` are siblings\n /* @__PURE__ */ jsx(RemoveScroll, { as: Slot, allowPinchZoom: true, shards: [context.contentRef], children: /* @__PURE__ */ jsx(\n Primitive.div,\n {\n \"data-state\": getState(context.open),\n ...overlayProps,\n ref: forwardedRef,\n style: { pointerEvents: \"auto\", ...overlayProps.style }\n }\n ) })\n );\n }\n);\nvar CONTENT_NAME = \"DialogContent\";\nvar DialogContent = React.forwardRef(\n (props, forwardedRef) => {\n const portalContext = usePortalContext(CONTENT_NAME, props.__scopeDialog);\n const { forceMount = portalContext.forceMount, ...contentProps } = props;\n const context = useDialogContext(CONTENT_NAME, props.__scopeDialog);\n return /* @__PURE__ */ jsx(Presence, { present: forceMount || context.open, children: context.modal ? /* @__PURE__ */ jsx(DialogContentModal, { ...contentProps, ref: forwardedRef }) : /* @__PURE__ */ jsx(DialogContentNonModal, { ...contentProps, ref: forwardedRef }) });\n }\n);\nDialogContent.displayName = CONTENT_NAME;\nvar DialogContentModal = React.forwardRef(\n (props, forwardedRef) => {\n const context = useDialogContext(CONTENT_NAME, props.__scopeDialog);\n const contentRef = React.useRef(null);\n const composedRefs = useComposedRefs(forwardedRef, context.contentRef, contentRef);\n React.useEffect(() => {\n const content = contentRef.current;\n if (content) return hideOthers(content);\n }, []);\n return /* @__PURE__ */ jsx(\n DialogContentImpl,\n {\n ...props,\n ref: composedRefs,\n trapFocus: context.open,\n disableOutsidePointerEvents: true,\n onCloseAutoFocus: composeEventHandlers(props.onCloseAutoFocus, (event) => {\n event.preventDefault();\n context.triggerRef.current?.focus();\n }),\n onPointerDownOutside: composeEventHandlers(props.onPointerDownOutside, (event) => {\n const originalEvent = event.detail.originalEvent;\n const ctrlLeftClick = originalEvent.button === 0 && originalEvent.ctrlKey === true;\n const isRightClick = originalEvent.button === 2 || ctrlLeftClick;\n if (isRightClick) event.preventDefault();\n }),\n onFocusOutside: composeEventHandlers(\n props.onFocusOutside,\n (event) => event.preventDefault()\n )\n }\n );\n }\n);\nvar DialogContentNonModal = React.forwardRef(\n (props, forwardedRef) => {\n const context = useDialogContext(CONTENT_NAME, props.__scopeDialog);\n const hasInteractedOutsideRef = React.useRef(false);\n const hasPointerDownOutsideRef = React.useRef(false);\n return /* @__PURE__ */ jsx(\n DialogContentImpl,\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 DialogContentImpl = React.forwardRef(\n (props, forwardedRef) => {\n const { __scopeDialog, trapFocus, onOpenAutoFocus, onCloseAutoFocus, ...contentProps } = props;\n const context = useDialogContext(CONTENT_NAME, __scopeDialog);\n const contentRef = React.useRef(null);\n const composedRefs = useComposedRefs(forwardedRef, contentRef);\n useFocusGuards();\n return /* @__PURE__ */ jsxs(Fragment, { children: [\n /* @__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 role: \"dialog\",\n id: context.contentId,\n \"aria-describedby\": context.descriptionId,\n \"aria-labelledby\": context.titleId,\n \"data-state\": getState(context.open),\n ...contentProps,\n ref: composedRefs,\n onDismiss: () => context.onOpenChange(false)\n }\n )\n }\n ),\n /* @__PURE__ */ jsxs(Fragment, { children: [\n /* @__PURE__ */ jsx(TitleWarning, { titleId: context.titleId }),\n /* @__PURE__ */ jsx(DescriptionWarning, { contentRef, descriptionId: context.descriptionId })\n ] })\n ] });\n }\n);\nvar TITLE_NAME = \"DialogTitle\";\nvar DialogTitle = React.forwardRef(\n (props, forwardedRef) => {\n const { __scopeDialog, ...titleProps } = props;\n const context = useDialogContext(TITLE_NAME, __scopeDialog);\n return /* @__PURE__ */ jsx(Primitive.h2, { id: context.titleId, ...titleProps, ref: forwardedRef });\n }\n);\nDialogTitle.displayName = TITLE_NAME;\nvar DESCRIPTION_NAME = \"DialogDescription\";\nvar DialogDescription = React.forwardRef(\n (props, forwardedRef) => {\n const { __scopeDialog, ...descriptionProps } = props;\n const context = useDialogContext(DESCRIPTION_NAME, __scopeDialog);\n return /* @__PURE__ */ jsx(Primitive.p, { id: context.descriptionId, ...descriptionProps, ref: forwardedRef });\n }\n);\nDialogDescription.displayName = DESCRIPTION_NAME;\nvar CLOSE_NAME = \"DialogClose\";\nvar DialogClose = React.forwardRef(\n (props, forwardedRef) => {\n const { __scopeDialog, ...closeProps } = props;\n const context = useDialogContext(CLOSE_NAME, __scopeDialog);\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);\nDialogClose.displayName = CLOSE_NAME;\nfunction getState(open) {\n return open ? \"open\" : \"closed\";\n}\nvar TITLE_WARNING_NAME = \"DialogTitleWarning\";\nvar [WarningProvider, useWarningContext] = createContext(TITLE_WARNING_NAME, {\n contentName: CONTENT_NAME,\n titleName: TITLE_NAME,\n docsSlug: \"dialog\"\n});\nvar TitleWarning = ({ titleId }) => {\n const titleWarningContext = useWarningContext(TITLE_WARNING_NAME);\n const MESSAGE = `\\`${titleWarningContext.contentName}\\` requires a \\`${titleWarningContext.titleName}\\` for the component to be accessible for screen reader users.\n\nIf you want to hide the \\`${titleWarningContext.titleName}\\`, you can wrap it with our VisuallyHidden component.\n\nFor more information, see https://radix-ui.com/primitives/docs/components/${titleWarningContext.docsSlug}`;\n React.useEffect(() => {\n if (titleId) {\n const hasTitle = document.getElementById(titleId);\n if (!hasTitle) console.error(MESSAGE);\n }\n }, [MESSAGE, titleId]);\n return null;\n};\nvar DESCRIPTION_WARNING_NAME = \"DialogDescriptionWarning\";\nvar DescriptionWarning = ({ contentRef, descriptionId }) => {\n const descriptionWarningContext = useWarningContext(DESCRIPTION_WARNING_NAME);\n const MESSAGE = `Warning: Missing \\`Description\\` or \\`aria-describedby={undefined}\\` for {${descriptionWarningContext.contentName}}.`;\n React.useEffect(() => {\n const describedById = contentRef.current?.getAttribute(\"aria-describedby\");\n if (descriptionId && describedById) {\n const hasDescription = document.getElementById(descriptionId);\n if (!hasDescription) console.warn(MESSAGE);\n }\n }, [MESSAGE, contentRef, descriptionId]);\n return null;\n};\nvar Root = Dialog;\nvar Trigger = DialogTrigger;\nvar Portal = DialogPortal;\nvar Overlay = DialogOverlay;\nvar Content = DialogContent;\nvar Title = DialogTitle;\nvar Description = DialogDescription;\nvar Close = DialogClose;\nexport {\n Close,\n Content,\n Description,\n Dialog,\n DialogClose,\n DialogContent,\n DialogDescription,\n DialogOverlay,\n DialogPortal,\n DialogTitle,\n DialogTrigger,\n Overlay,\n Portal,\n Root,\n Title,\n Trigger,\n WarningProvider,\n createDialogScope\n};\n//# sourceMappingURL=index.mjs.map\n","import * as DialogPrimitive from '@radix-ui/react-dialog'\nimport * as React from 'react'\nimport { cn } from '#app/utils/misc.tsx'\nimport { Icon } from '../icons'\n\nconst Dialog = DialogPrimitive.Root\n\nconst DialogTrigger = DialogPrimitive.Trigger\n\nconst DialogPortal = DialogPrimitive.Portal\n\nconst DialogClose = DialogPrimitive.Close\n\nfunction DialogOverlay({\n\tclassName,\n\tref,\n\t...props\n}: React.ComponentProps<typeof DialogPrimitive.Overlay>) {\n\treturn (\n\t\t<DialogPrimitive.Overlay\n\t\t\tref={ref}\n\t\t\tclassName={cn(\n\t\t\t\t'fixed inset-0 z-50 bg-background/80 backdrop-blur-sm data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0',\n\t\t\t\tclassName,\n\t\t\t)}\n\t\t\t{...props}\n\t\t/>\n\t)\n}\nDialogOverlay.displayName = DialogPrimitive.Overlay.displayName\n\nfunction DialogContent({\n\tclassName,\n\tchildren,\n\tref,\n\t...props\n}: React.ComponentProps<typeof DialogPrimitive.Content>) {\n\treturn (\n\t\t<DialogPortal>\n\t\t\t<DialogOverlay />\n\t\t\t<DialogPrimitive.Content\n\t\t\t\tref={ref}\n\t\t\t\tclassName={cn(\n\t\t\t\t\t'fixed left-[50%] top-[50%] z-50 grid w-full max-w-lg translate-x-[-50%] translate-y-[-50%] gap-4 border bg-background p-6 shadow-lg duration-200 data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[state=closed]:slide-out-to-left-1/2 data-[state=closed]:slide-out-to-top-[48%] data-[state=open]:slide-in-from-left-1/2 data-[state=open]:slide-in-from-top-[48%] sm:rounded-lg md:w-full',\n\t\t\t\t\tclassName,\n\t\t\t\t)}\n\t\t\t\t{...props}\n\t\t\t>\n\t\t\t\t{children}\n\t\t\t\t<DialogPrimitive.Close className=\"absolute right-4 top-4 rounded-sm opacity-70 ring-offset-background transition-opacity data-[state=open]:bg-accent data-[state=open]:text-muted-foreground hover:opacity-100 focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2 disabled:pointer-events-none\">\n\t\t\t\t\t<Icon name=\"Close\" />\n\t\t\t\t\t<span className=\"sr-only\">Close</span>\n\t\t\t\t</DialogPrimitive.Close>\n\t\t\t</DialogPrimitive.Content>\n\t\t</DialogPortal>\n\t)\n}\nDialogContent.displayName = DialogPrimitive.Content.displayName\n\nfunction DialogHeader({\n\tclassName,\n\t...props\n}: React.HTMLAttributes<HTMLDivElement>) {\n\treturn (\n\t\t<div\n\t\t\tclassName={cn(\n\t\t\t\t'flex flex-col space-y-1.5 text-center sm:text-left',\n\t\t\t\tclassName,\n\t\t\t)}\n\t\t\t{...props}\n\t\t/>\n\t)\n}\nDialogHeader.displayName = 'DialogHeader'\n\nfunction DialogFooter({\n\tclassName,\n\t...props\n}: React.HTMLAttributes<HTMLDivElement>) {\n\treturn (\n\t\t<div\n\t\t\tclassName={cn(\n\t\t\t\t'flex flex-col-reverse sm:flex-row sm:justify-end sm:space-x-2',\n\t\t\t\tclassName,\n\t\t\t)}\n\t\t\t{...props}\n\t\t/>\n\t)\n}\nDialogFooter.displayName = 'DialogFooter'\n\nfunction DialogTitle({\n\tclassName,\n\tref,\n\t...props\n}: React.ComponentProps<typeof DialogPrimitive.Title>) {\n\treturn (\n\t\t<DialogPrimitive.Title\n\t\t\tref={ref}\n\t\t\tclassName={cn(\n\t\t\t\t'text-lg font-semibold leading-none tracking-tight',\n\t\t\t\tclassName,\n\t\t\t)}\n\t\t\t{...props}\n\t\t/>\n\t)\n}\nDialogTitle.displayName = DialogPrimitive.Title.displayName\n\nfunction DialogDescription({\n\tclassName,\n\tref,\n\t...props\n}: React.ComponentProps<typeof DialogPrimitive.Description>) {\n\treturn (\n\t\t<DialogPrimitive.Description\n\t\t\tref={ref}\n\t\t\tclassName={cn('text-sm text-muted-foreground', className)}\n\t\t\t{...props}\n\t\t/>\n\t)\n}\nDialogDescription.displayName = DialogPrimitive.Description.displayName\n\nexport {\n\tDialog,\n\tDialogClose,\n\tDialogContent,\n\tDialogDescription,\n\tDialogFooter,\n\tDialogHeader,\n\tDialogOverlay,\n\tDialogPortal,\n\tDialogTitle,\n\tDialogTrigger,\n}\n","import {\n\textractNumbersAndTypeFromAppNameOrPath,\n\tgetExercises,\n\tgetPlaygroundAppName,\n} from '@epic-web/workshop-utils/apps.server'\nimport { getWorkshopConfig } from '@epic-web/workshop-utils/config.server'\nimport {\n\tcombineServerTimings,\n\tgetServerTimeHeader,\n\tmakeTimings,\n} from '@epic-web/workshop-utils/timing.server'\nimport {\n\tjson,\n\ttype HeadersFunction,\n\ttype LoaderFunctionArgs,\n} from '@remix-run/node'\nimport {\n\tLink,\n\tNavLink,\n\tOutlet,\n\tuseLoaderData,\n\tuseParams,\n} from '@remix-run/react'\nimport { clsx } from 'clsx'\nimport {\n\tmotion,\n\tuseAnimationControls,\n\ttype AnimationControls,\n} from 'framer-motion'\nimport * as React from 'react'\nimport { useHydrated } from 'remix-utils/use-hydrated'\nimport { Icon } from '#app/components/icons.tsx'\nimport { makeMediaQueryStore } from '#app/components/media-query.ts'\nimport { Logo } from '#app/components/product.tsx'\nimport { useRevalidationWS } from '#app/components/revalidation-ws.js'\nimport {\n\tDialog,\n\tDialogContent,\n\tDialogDescription,\n\tDialogHeader,\n\tDialogTrigger,\n} from '#app/components/ui/dialog.js'\nimport {\n\tSimpleTooltip,\n\tTooltip,\n\tTooltipContent,\n\tTooltipProvider,\n\tTooltipTrigger,\n} from '#app/components/ui/tooltip.tsx'\nimport { useOptionalUser } from '#app/components/user.tsx'\nimport { useWorkshopConfig } from '#app/components/workshop-config.js'\nimport { cn } from '#app/utils/misc.tsx'\nimport { usePresence, type User } from '#app/utils/presence.tsx'\nimport {\n\tuseExerciseProgressClassName,\n\tuseNextExerciseRoute,\n\tuseProgressItemClassName,\n\ttype ProgressItemSearch,\n} from '../progress.tsx'\nimport { ThemeSwitch } from '../theme/index.tsx'\n\nexport async function loader({ request }: LoaderFunctionArgs) {\n\tconst timings = makeTimings('appLayoutLoader')\n\tconst { title: workshopTitle } = getWorkshopConfig()\n\tconst [exercises, playgroundAppName] = await Promise.all([\n\t\tgetExercises({ request, timings }),\n\t\tgetPlaygroundAppName(),\n\t])\n\n\tconst playground = {\n\t\tappName: playgroundAppName,\n\t\texerciseNumber: Number(\n\t\t\textractNumbersAndTypeFromAppNameOrPath(playgroundAppName ?? '')\n\t\t\t\t?.exerciseNumber,\n\t\t),\n\t}\n\n\tconst result = json(\n\t\t{\n\t\t\tworkshopTitle,\n\t\t\texercises: exercises.map((e) => ({\n\t\t\t\texerciseNumber: e.exerciseNumber,\n\t\t\t\ttitle: e.title,\n\t\t\t\tsolutions: e.solutions.map(({ stepNumber, title, name }) => ({\n\t\t\t\t\tstepNumber,\n\t\t\t\t\ttitle,\n\t\t\t\t\tname,\n\t\t\t\t})),\n\t\t\t\tproblems: e.problems.map(({ stepNumber, title, name }) => ({\n\t\t\t\t\tstepNumber,\n\t\t\t\t\ttitle,\n\t\t\t\t\tname,\n\t\t\t\t})),\n\t\t\t\tsteps: e.steps.map(({ stepNumber, problem, solution }) => ({\n\t\t\t\t\tstepNumber,\n\t\t\t\t\ttitle: problem?.title ?? solution?.title ?? 'Unknown',\n\t\t\t\t\tname: problem?.name ?? solution?.name ?? 'Unknown',\n\t\t\t\t})),\n\t\t\t})),\n\t\t\tplayground,\n\t\t},\n\t\t{\n\t\t\theaders: {\n\t\t\t\tVary: 'Cookie',\n\t\t\t\t'Server-Timing': getServerTimeHeader(timings),\n\t\t\t},\n\t\t},\n\t)\n\treturn result\n}\n\nexport const headers: HeadersFunction = ({ loaderHeaders, parentHeaders }) => {\n\tconst headers = {\n\t\t'Cache-Control': loaderHeaders.get('Cache-Control') ?? '',\n\t\tVary: 'Cookie',\n\t\t'Server-Timing': combineServerTimings(loaderHeaders, parentHeaders),\n\t}\n\treturn headers\n}\n\nconst opacities = ['opacity-70', 'opacity-80', 'opacity-90', 'opacity-100']\nconst shadows = [\n\t'shadow-[0_0_2px_0_rgba(0,0,0,0.3)]',\n\t'shadow-[0_0_4px_0_rgba(0,0,0,0.3)]',\n\t'shadow-[0_0_7px_0_rgba(0,0,0,0.3)]',\n\t'shadow-[0_0_10px_0_rgba(0,0,0,0.3)]',\n]\nfunction getScoreClassNames(score: number) {\n\tconst opacityNumber = Math.round(score * opacities.length - 1)\n\tconst shadowNumber = Math.round(score * shadows.length - 1)\n\treturn cn(\n\t\t'shadow-purple-700 hover:opacity-100 focus:opacity-100 dark:shadow-purple-200',\n\t\topacities[opacityNumber] ?? 'opacity-60',\n\t\tshadows[shadowNumber] ?? 'shadow-none',\n\t\tscore === 1 ? 'animate-pulse hover:animate-none focus:animate-none' : null,\n\t)\n}\n\nfunction FacePile({ isMenuOpened }: { isMenuOpened: boolean }) {\n\tconst loggedInUser = useOptionalUser()\n\tconst { users } = usePresence()\n\tconst {\n\t\tproduct: { displayNameShort },\n\t} = useWorkshopConfig()\n\tconst limit = isMenuOpened ? 17 : 0\n\tconst numberOverLimit = users.length - limit\n\tconst shouldShowNumberOverLimit = numberOverLimit > (isMenuOpened ? 1 : 0)\n\n\tif (!users.length) return null\n\n\tconst tiffany =\n\t\tisMenuOpened && users.length === 1 ? (\n\t\t\t<Link\n\t\t\t\ttarget=\"_blank\"\n\t\t\t\trel=\"noopener noreferrer\"\n\t\t\t\tto=\"https://www.youtube.com/watch?v=w6Q3mHyzn78\"\n\t\t\t>\n\t\t\t\t<img\n\t\t\t\t\talt=\"Tiffany Tunes\"\n\t\t\t\t\tclassName={cn(\n\t\t\t\t\t\t'h-8 w-8 rounded-full border object-cover',\n\t\t\t\t\t\tgetScoreClassNames(1),\n\t\t\t\t\t)}\n\t\t\t\t\tsrc=\"/img/tiffany.png\"\n\t\t\t\t/>\n\t\t\t</Link>\n\t\t) : null\n\tconst overLimitLabel = `${numberOverLimit}${\n\t\tisMenuOpened ? ' more ' : ' '\n\t}${displayNameShort} Dev${numberOverLimit === 1 ? '' : 's'} working now`\n\treturn (\n\t\t<div className=\"flex flex-wrap items-center gap-2\">\n\t\t\t<TooltipProvider>\n\t\t\t\t{(shouldShowNumberOverLimit ? users.slice(0, limit) : users).map(\n\t\t\t\t\t({ user, score }) => {\n\t\t\t\t\t\tconst scoreClassNames = getScoreClassNames(score)\n\t\t\t\t\t\tconst locationLabel = getLocationLabel(user.location)\n\t\t\t\t\t\treturn (\n\t\t\t\t\t\t\t<Tooltip key={user.id}>\n\t\t\t\t\t\t\t\t<TooltipTrigger asChild>\n\t\t\t\t\t\t\t\t\t{user.avatarUrl ? (\n\t\t\t\t\t\t\t\t\t\t<img\n\t\t\t\t\t\t\t\t\t\t\ttabIndex={0}\n\t\t\t\t\t\t\t\t\t\t\talt={user.name || displayNameShort}\n\t\t\t\t\t\t\t\t\t\t\tclassName={cn(\n\t\t\t\t\t\t\t\t\t\t\t\t'h-8 w-8 rounded-full border object-cover',\n\t\t\t\t\t\t\t\t\t\t\t\tscoreClassNames,\n\t\t\t\t\t\t\t\t\t\t\t)}\n\t\t\t\t\t\t\t\t\t\t\tsrc={user.avatarUrl}\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<div\n\t\t\t\t\t\t\t\t\t\t\ttabIndex={0}\n\t\t\t\t\t\t\t\t\t\t\taria-label={user.name || `${displayNameShort} Dev`}\n\t\t\t\t\t\t\t\t\t\t\tclassName={cn(\n\t\t\t\t\t\t\t\t\t\t\t\t'flex h-8 w-8 items-center justify-center rounded-full border',\n\t\t\t\t\t\t\t\t\t\t\t\tscoreClassNames,\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\t\t<Icon name=\"User\" />\n\t\t\t\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t\t\t\t)}\n\t\t\t\t\t\t\t\t</TooltipTrigger>\n\t\t\t\t\t\t\t\t<TooltipContent>\n\t\t\t\t\t\t\t\t\t<span className=\"flex flex-col items-center justify-center gap-1\">\n\t\t\t\t\t\t\t\t\t\t<span>\n\t\t\t\t\t\t\t\t\t\t\t{user.name || `${displayNameShort} Dev`}{' '}\n\t\t\t\t\t\t\t\t\t\t\t{locationLabel\n\t\t\t\t\t\t\t\t\t\t\t\t? ` is ${user.location?.origin?.includes('localhost') ? 'working' : 'learning'} ${\n\t\t\t\t\t\t\t\t\t\t\t\t\t\tscore === 1 && loggedInUser?.id !== user.id\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t? 'with you'\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} on`\n\t\t\t\t\t\t\t\t\t\t\t\t: null}\n\t\t\t\t\t\t\t\t\t\t</span>\n\t\t\t\t\t\t\t\t\t\t{locationLabel?.line1 ? (\n\t\t\t\t\t\t\t\t\t\t\t<span>{locationLabel.line1}</span>\n\t\t\t\t\t\t\t\t\t\t) : null}\n\t\t\t\t\t\t\t\t\t\t{locationLabel?.line2 ? (\n\t\t\t\t\t\t\t\t\t\t\t<span>{locationLabel.line2}</span>\n\t\t\t\t\t\t\t\t\t\t) : null}\n\t\t\t\t\t\t\t\t\t</span>\n\t\t\t\t\t\t\t\t</TooltipContent>\n\t\t\t\t\t\t\t</Tooltip>\n\t\t\t\t\t\t)\n\t\t\t\t\t},\n\t\t\t\t)}\n\t\t\t\t{tiffany}\n\t\t\t\t{shouldShowNumberOverLimit ? (\n\t\t\t\t\t<Tooltip>\n\t\t\t\t\t\t<TooltipTrigger asChild>\n\t\t\t\t\t\t\t<div\n\t\t\t\t\t\t\t\ttabIndex={0}\n\t\t\t\t\t\t\t\taria-label={overLimitLabel}\n\t\t\t\t\t\t\t\tclassName={cn(\n\t\t\t\t\t\t\t\t\t'flex items-center justify-center rounded-full border bg-accent text-xs text-accent-foreground',\n\t\t\t\t\t\t\t\t\tisMenuOpened ? 'h-8 w-8' : 'h-6 w-6',\n\t\t\t\t\t\t\t\t)}\n\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t<span\n\t\t\t\t\t\t\t\t\tclassName={cn(\n\t\t\t\t\t\t\t\t\t\t'pointer-events-none overflow-hidden text-ellipsis whitespace-nowrap text-center',\n\t\t\t\t\t\t\t\t\t\tisMenuOpened ? 'w-8' : 'w-6',\n\t\t\t\t\t\t\t\t\t)}\n\t\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t\t{isMenuOpened ? `+${numberOverLimit}` : numberOverLimit}\n\t\t\t\t\t\t\t\t</span>\n\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t</TooltipTrigger>\n\t\t\t\t\t\t<TooltipContent>{overLimitLabel}</TooltipContent>\n\t\t\t\t\t</Tooltip>\n\t\t\t\t) : null}\n\t\t\t</TooltipProvider>\n\t\t</div>\n\t)\n}\n\nconst useIsWide = makeMediaQueryStore('(min-width: 640px)', true)\n\nexport default function App() {\n\tconst user = useOptionalUser()\n\tconst isWide = useIsWide()\n\tconst isHydrated = useHydrated()\n\n\tconst [isMenuOpened, setMenuOpened] = React.useState(false)\n\tuseRevalidationWS({ watchPaths: ['./exercises/README.mdx'] })\n\n\treturn (\n\t\t<div className=\"flex flex-col\">\n\t\t\t{user ? null : <NoUserBanner />}\n\t\t\t{/*\n\t\t\t\tthis isn't placed in a conditional with isWide because the server render\n\t\t\t\tdoesn't know whether it should be around or not so we just use CSS to hide it\n\t\t\t\tif it's not supposed to show up.\n\n\t\t\t\tWe don't just use media queries for the wider screen nav because we want\n\t\t\t\tto avoid running all the logic in there unnecessarily.\n\t\t\t*/}\n\t\t\t{isHydrated && isWide ? null : (\n\t\t\t\t<MobileNavigation\n\t\t\t\t\tisMenuOpened={isMenuOpened}\n\t\t\t\t\tonMenuOpenChange={setMenuOpened}\n\t\t\t\t/>\n\t\t\t)}\n\t\t\t<div\n\t\t\t\t// this nonsense is here because we want the panels to be scrollable rather\n\t\t\t\t// than having the entire page be scrollable (at least on wider screens)\n\t\t\t\tclassName={cn('flex flex-grow flex-col sm:flex-row', {\n\t\t\t\t\t'h-[calc(100vh-128px-env(safe-area-inset-top)-env(safe-area-inset-bottom))] sm:h-[calc(100vh-64px-env(safe-area-inset-top)-env(safe-area-inset-bottom))]':\n\t\t\t\t\t\t!user,\n\t\t\t\t\t'h-[calc(100vh-64px-env(safe-area-inset-top)-env(safe-area-inset-bottom))] sm:h-[calc(100vh-env(safe-area-inset-top)-env(safe-area-inset-bottom))]':\n\t\t\t\t\t\tuser,\n\t\t\t\t\t'h-[unset]': !isWide && isMenuOpened,\n\t\t\t\t})}\n\t\t\t>\n\t\t\t\t{isWide ? (\n\t\t\t\t\t<Navigation\n\t\t\t\t\t\tisMenuOpened={isMenuOpened}\n\t\t\t\t\t\tonMenuOpenChange={setMenuOpened}\n\t\t\t\t\t/>\n\t\t\t\t) : null}\n\t\t\t\t<div\n\t\t\t\t\tclassName={cn(\n\t\t\t\t\t\t'h-full w-full max-w-full sm:max-w-[calc(100%-56px)]',\n\t\t\t\t\t\tisMenuOpened ? 'hidden md:block' : '',\n\t\t\t\t\t)}\n\t\t\t\t>\n\t\t\t\t\t<Outlet />\n\t\t\t\t</div>\n\t\t\t</div>\n\t\t</div>\n\t)\n}\n\nfunction getLocationLabel(location: User['location']) {\n\tif (!location) return null\n\n\tconst { exercise } = location\n\n\tconst exercisePortion = [\n\t\texercise\n\t\t\t? [exercise.exerciseNumber, exercise.stepNumber]\n\t\t\t\t\t.filter(Boolean)\n\t\t\t\t\t.map((s) => s.toString().padStart(2, '0'))\n\t\t\t\t\t.join('/')\n\t\t\t: null,\n\t\texercise?.type,\n\t]\n\t\t.filter(Boolean)\n\t\t.join(' - ')\n\treturn { line1: location.workshopTitle, line2: exercisePortion }\n}\n\nfunction NoUserBanner() {\n\tconst isWide = useIsWide()\n\tconst {\n\t\tproduct: { host, displayName },\n\t} = useWorkshopConfig()\n\tconst details = (\n\t\t<div>\n\t\t\t{ENV.EPICSHOP_DEPLOYED ? (\n\t\t\t\t<div>\n\t\t\t\t\t{`This is the deployed version. `}\n\t\t\t\t\t<>\n\t\t\t\t\t\t<Link\n\t\t\t\t\t\t\tclassName=\"underline\"\n\t\t\t\t\t\t\ttarget=\"_blank\"\n\t\t\t\t\t\t\trel=\"noopener noreferrer\"\n\t\t\t\t\t\t\tto={ENV.EPICSHOP_GITHUB_REPO}\n\t\t\t\t\t\t>\n\t\t\t\t\t\t\tRun locally\n\t\t\t\t\t\t</Link>\n\t\t\t\t\t\t{` for full experience.`}\n\t\t\t\t\t</>{' '}\n\t\t\t\t</div>\n\t\t\t) : (\n\t\t\t\t<div>\n\t\t\t\t\t<Link to=\"/login\" className=\"underline\">\n\t\t\t\t\t\tLogin\n\t\t\t\t\t</Link>{' '}\n\t\t\t\t\tor{' '}\n\t\t\t\t\t<a href={`https://${host}/login`} className=\"underline\">\n\t\t\t\t\t\tjoin for free\n\t\t\t\t\t</a>{' '}\n\t\t\t\t\tfor the full experience.\n\t\t\t\t</div>\n\t\t\t)}\n\t\t</div>\n\t)\n\treturn (\n\t\t<div className=\"z-10 flex h-16 items-center justify-between border-b bg-gradient-to-tr from-blue-500 to-indigo-500 pl-4 text-white\">\n\t\t\t{isWide ? (\n\t\t\t\t<>\n\t\t\t\t\t<div className=\"hidden flex-1 flex-wrap items-center gap-4 sm:flex\">\n\t\t\t\t\t\t<Logo size=\"lg\" style=\"monochrome\" />\n\t\t\t\t\t\t<div className=\"flex flex-1 flex-wrap items-center\">\n\t\t\t\t\t\t\t<p className=\"mr-2\">\n\t\t\t\t\t\t\t\tWelcome to the{' '}\n\t\t\t\t\t\t\t\t<Link\n\t\t\t\t\t\t\t\t\tto={`https://${host}`}\n\t\t\t\t\t\t\t\t\tclassName=\"underline\"\n\t\t\t\t\t\t\t\t\ttarget=\"_blank\"\n\t\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t\t{displayName}\n\t\t\t\t\t\t\t\t</Link>{' '}\n\t\t\t\t\t\t\t\tWorkshop app!\n\t\t\t\t\t\t\t</p>\n\t\t\t\t\t\t\t{details}\n\t\t\t\t\t\t</div>\n\t\t\t\t\t</div>\n\t\t\t\t\t<div className=\"hidden h-full flex-col items-center sm:flex md:flex-row\">\n\t\t\t\t\t\t<Link\n\t\t\t\t\t\t\tto={`https://${host}`}\n\t\t\t\t\t\t\ttarget=\"_blank\"\n\t\t\t\t\t\t\tclassName=\"flex h-full items-center justify-center space-x-1.5 px-5 text-sm font-semibold\"\n\t\t\t\t\t\t>\n\t\t\t\t\t\t\t<span className=\"drop-shadow-sm\">Join {displayName}</span>\n\t\t\t\t\t\t\t<span>↗︎</span>\n\t\t\t\t\t\t</Link>\n\t\t\t\t\t\t<Link\n\t\t\t\t\t\t\tto={ENV.EPICSHOP_DEPLOYED ? `https://${host}/login` : '/login'}\n\t\t\t\t\t\t\tclassName=\"flex h-full items-center justify-center space-x-1.5 bg-white/20 px-5 text-sm font-semibold shadow-md transition hover:bg-white/30\"\n\t\t\t\t\t\t>\n\t\t\t\t\t\t\t<Icon name=\"User\" size=\"lg\" />\n\t\t\t\t\t\t\t<span className=\"drop-shadow-sm\">Login</span>\n\t\t\t\t\t\t</Link>\n\t\t\t\t\t</div>\n\t\t\t\t</>\n\t\t\t) : (\n\t\t\t\t<>\n\t\t\t\t\t<div className=\"flex flex-1 flex-wrap items-center gap-4 sm:hidden\">\n\t\t\t\t\t\t<a href={`https://${host}`}>\n\t\t\t\t\t\t\t<Logo size=\"lg\" style=\"monochrome\" />\n\t\t\t\t\t\t</a>\n\t\t\t\t\t\t<Dialog>\n\t\t\t\t\t\t\t<DialogTrigger>\n\t\t\t\t\t\t\t\t<Icon name=\"Question\" size=\"lg\" className=\"animate-pulse\" />\n\t\t\t\t\t\t\t</DialogTrigger>\n\t\t\t\t\t\t\t<DialogContent>\n\t\t\t\t\t\t\t\t<DialogHeader>\n\t\t\t\t\t\t\t\t\t<Logo size=\"lg\" style=\"monochrome\" />\n\t\t\t\t\t\t\t\t\t<span className=\"text-lg font-semibold\">{displayName}</span>\n\t\t\t\t\t\t\t\t</DialogHeader>\n\t\t\t\t\t\t\t\t<DialogDescription>\n\t\t\t\t\t\t\t\t\tWelcome to the{' '}\n\t\t\t\t\t\t\t\t\t<Link to={`https://${host}`} className=\"underline\">\n\t\t\t\t\t\t\t\t\t\t{displayName}\n\t\t\t\t\t\t\t\t\t</Link>{' '}\n\t\t\t\t\t\t\t\t\tWorkshop app!\n\t\t\t\t\t\t\t\t</DialogDescription>\n\t\t\t\t\t\t\t\t{details}\n\t\t\t\t\t\t\t</DialogContent>\n\t\t\t\t\t\t</Dialog>\n\t\t\t\t\t</div>\n\t\t\t\t\t<div className=\"flex h-full items-center\">\n\t\t\t\t\t\t<Link\n\t\t\t\t\t\t\tto={`https://${host}`}\n\t\t\t\t\t\t\ttarget=\"_blank\"\n\t\t\t\t\t\t\tclassName=\"flex h-full items-center justify-center space-x-1.5 px-5 text-sm font-semibold\"\n\t\t\t\t\t\t>\n\t\t\t\t\t\t\t<span className=\"drop-shadow-sm\">Join</span>\n\t\t\t\t\t\t\t<span>↗︎</span>\n\t\t\t\t\t\t</Link>\n\t\t\t\t\t\t<Link\n\t\t\t\t\t\t\tto={ENV.EPICSHOP_DEPLOYED ? `https://${host}/login` : '/login'}\n\t\t\t\t\t\t\tclassName=\"flex h-full items-center justify-center space-x-1.5 bg-white/20 px-5 text-sm font-semibold shadow-md transition hover:bg-white/30\"\n\t\t\t\t\t\t>\n\t\t\t\t\t\t\t<Icon name=\"User\" size=\"lg\" />\n\t\t\t\t\t\t\t<span className=\"drop-shadow-sm\">Login</span>\n\t\t\t\t\t\t</Link>\n\t\t\t\t\t</div>\n\t\t\t\t</>\n\t\t\t)}\n\t\t</div>\n\t)\n}\n\nconst itemVariants = {\n\thidden: { opacity: 0, x: -20 },\n\tvisible: { opacity: 1, x: 0 },\n}\nfunction NavigationExerciseListItem({\n\texerciseNumber,\n\tchildren,\n}: {\n\texerciseNumber: number\n\tchildren: React.ReactNode\n}) {\n\tconst progressClassName = useExerciseProgressClassName(exerciseNumber)\n\treturn (\n\t\t<motion.li\n\t\t\tvariants={itemVariants}\n\t\t\t// @ts-expect-error framer-motion + latest typescript types has issues\n\t\t\tclassName={cn(\n\t\t\t\t// add gap of 3 to children, but using padding so the progress extends through the whole height\n\t\t\t\t'py-[6px] first:pt-3 last:pb-3',\n\t\t\t\tprogressClassName ? `${progressClassName} before:border-t` : null,\n\t\t\t)}\n\t\t>\n\t\t\t<span className=\"ml-2\">{children}</span>\n\t\t</motion.li>\n\t)\n}\n\nfunction NavigationExerciseStepListItem({\n\tchildren,\n\t...progressItemSearch\n}: {\n\tchildren: React.ReactNode\n} & ProgressItemSearch) {\n\tconst progressClassName = useProgressItemClassName(progressItemSearch)\n\treturn (\n\t\t<motion.li\n\t\t\tvariants={itemVariants}\n\t\t\t// @ts-expect-error framer-motion + latest typescript types has issues\n\t\t\tclassName={cn(\n\t\t\t\t// add gap of 3 to children, but using padding so the progress extends through the whole height\n\t\t\t\t'py-[6px] first:pt-3 last:pb-3',\n\t\t\t\tprogressClassName ? `${progressClassName} before:border-t` : null,\n\t\t\t)}\n\t\t>\n\t\t\t<span className=\"ml-2\">{children}</span>\n\t\t</motion.li>\n\t)\n}\n\nfunction MobileNavigation({\n\tisMenuOpened,\n\tonMenuOpenChange: setMenuOpened,\n}: {\n\tisMenuOpened: boolean\n\tonMenuOpenChange: (change: boolean) => void\n}) {\n\tconst data = useLoaderData<typeof loader>()\n\tconst user = useOptionalUser()\n\tconst nextExerciseRoute = useNextExerciseRoute()\n\tconst params = useParams()\n\tconst { users } = usePresence()\n\n\t// items\n\tconst listVariants = {\n\t\tvisible: {\n\t\t\topacity: 1,\n\t\t\ttransition: {\n\t\t\t\tduration: 0.05,\n\t\t\t\twhen: 'beforeChildren',\n\t\t\t\tstaggerChildren: 0.03,\n\t\t\t},\n\t\t},\n\t\thidden: {\n\t\t\topacity: 0,\n\t\t},\n\t}\n\n\treturn (\n\t\t<nav className=\"flex w-full border-b sm:hidden\">\n\t\t\t<div className=\"w-full\">\n\t\t\t\t<div\n\t\t\t\t\tclassName={cn('flex items-center', {\n\t\t\t\t\t\t'flex-col': isMenuOpened,\n\t\t\t\t\t\t'h-14': !isMenuOpened,\n\t\t\t\t\t})}\n\t\t\t\t>\n\t\t\t\t\t<NavToggle\n\t\t\t\t\t\ttitle={data.workshopTitle}\n\t\t\t\t\t\tisMenuOpened={isMenuOpened}\n\t\t\t\t\t\tsetMenuOpened={setMenuOpened}\n\t\t\t\t\t/>\n\t\t\t\t\t{isMenuOpened && (\n\t\t\t\t\t\t<motion.div\n\t\t\t\t\t\t\t// @ts-expect-error framer-motion + latest typescript types has issues\n\t\t\t\t\t\t\tclassName=\"flex w-full flex-grow flex-col justify-between overflow-x-auto p-6 scrollbar-thin scrollbar-thumb-scrollbar\"\n\t\t\t\t\t\t\tinitial={{ opacity: 0 }}\n\t\t\t\t\t\t\tanimate={{ opacity: 1 }}\n\t\t\t\t\t\t>\n\t\t\t\t\t\t\t<motion.ul\n\t\t\t\t\t\t\t\tvariants={listVariants}\n\t\t\t\t\t\t\t\tinitial=\"hidden\"\n\t\t\t\t\t\t\t\tanimate=\"visible\"\n\t\t\t\t\t\t\t\t// @ts-expect-error framer-motion + latest typescript types has issues\n\t\t\t\t\t\t\t\tclassName=\"flex flex-col\"\n\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t<span>\n\t\t\t\t\t\t\t\t\t<NavLink\n\t\t\t\t\t\t\t\t\t\tprefetch=\"intent\"\n\t\t\t\t\t\t\t\t\t\tto=\"/\"\n\t\t\t\t\t\t\t\t\t\tclassName={({ isActive }) =>\n\t\t\t\t\t\t\t\t\t\t\tclsx(\n\t\t\t\t\t\t\t\t\t\t\t\t'relative whitespace-nowrap px-2 py-0.5 pr-3 text-2xl font-bold outline-none hover:underline focus:underline',\n\t\t\t\t\t\t\t\t\t\t\t\t'after:absolute after:-bottom-2.5 after:-right-2.5 after:h-5 after:w-5 after:rotate-45 after:scale-75 after:bg-background after:content-[\"\"] hover:underline focus:underline',\n\t\t\t\t\t\t\t\t\t\t\t\t{ 'bg-foreground text-background': isActive },\n\t\t\t\t\t\t\t\t\t\t\t)\n\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t\t\tHome\n\t\t\t\t\t\t\t\t\t</NavLink>\n\t\t\t\t\t\t\t\t</span>\n\t\t\t\t\t\t\t\t{data.exercises.map(({ exerciseNumber, title, steps }) => {\n\t\t\t\t\t\t\t\t\tconst isActive =\n\t\t\t\t\t\t\t\t\t\tNumber(params.exerciseNumber) === exerciseNumber\n\t\t\t\t\t\t\t\t\tconst showPlayground =\n\t\t\t\t\t\t\t\t\t\t!isActive &&\n\t\t\t\t\t\t\t\t\t\tdata.playground.exerciseNumber === exerciseNumber\n\t\t\t\t\t\t\t\t\tconst exerciseNum = exerciseNumber.toString().padStart(2, '0')\n\t\t\t\t\t\t\t\t\treturn (\n\t\t\t\t\t\t\t\t\t\t<NavigationExerciseListItem\n\t\t\t\t\t\t\t\t\t\t\tkey={exerciseNumber}\n\t\t\t\t\t\t\t\t\t\t\texerciseNumber={exerciseNumber}\n\t\t\t\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t\t\t\t<Link\n\t\t\t\t\t\t\t\t\t\t\t\tprefetch=\"intent\"\n\t\t\t\t\t\t\t\t\t\t\t\tto={`/${exerciseNum}`}\n\t\t\t\t\t\t\t\t\t\t\t\tclassName={clsx(\n\t\t\t\t\t\t\t\t\t\t\t\t\t'relative whitespace-nowrap px-2 py-0.5 pr-3 text-2xl font-bold outline-none hover:underline focus:underline',\n\t\t\t\t\t\t\t\t\t\t\t\t\t'after:absolute after:-bottom-2.5 after:-right-2.5 after:h-5 after:w-5 after:rotate-45 after:scale-75 after:bg-background after:content-[\"\"] hover:underline focus:underline',\n\t\t\t\t\t\t\t\t\t\t\t\t\t{ 'bg-foreground text-background': isActive },\n\t\t\t\t\t\t\t\t\t\t\t\t)}\n\t\t\t\t\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t\t\t\t\t{title}\n\t\t\t\t\t\t\t\t\t\t\t\t{showPlayground ? ' 🛝' : null}\n\t\t\t\t\t\t\t\t\t\t\t</Link>\n\t\t\t\t\t\t\t\t\t\t\t{isActive ? (\n\t\t\t\t\t\t\t\t\t\t\t\t<motion.ul\n\t\t\t\t\t\t\t\t\t\t\t\t\tvariants={listVariants}\n\t\t\t\t\t\t\t\t\t\t\t\t\tinitial=\"hidden\"\n\t\t\t\t\t\t\t\t\t\t\t\t\tanimate=\"visible\"\n\t\t\t\t\t\t\t\t\t\t\t\t\t// @ts-expect-error framer-motion + latest typescript types has issues\n\t\t\t\t\t\t\t\t\t\t\t\t\tclassName=\"ml-4 mt-4 flex flex-col\"\n\t\t\t\t\t\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t\t\t\t\t\t<NavigationExerciseStepListItem\n\t\t\t\t\t\t\t\t\t\t\t\t\t\tkey={exerciseNumber}\n\t\t\t\t\t\t\t\t\t\t\t\t\t\ttype=\"instructions\"\n\t\t\t\t\t\t\t\t\t\t\t\t\t\texerciseNumber={exerciseNumber}\n\t\t\t\t\t\t\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t<Link\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tto={`/${exerciseNum}`}\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tprefetch=\"intent\"\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tclassName={clsx(\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t'relative whitespace-nowrap px-2 py-0.5 pr-3 text-xl font-medium outline-none after:absolute after:-bottom-2.5 after:-right-2.5 after:h-5 after:w-5 after:rotate-45 after:scale-75 after:bg-background after:content-[\"\"] hover:underline focus:underline',\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t'bg-foreground text-background':\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t!params.stepNumber,\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t)}\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tIntro\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t</Link>\n\t\t\t\t\t\t\t\t\t\t\t\t\t</NavigationExerciseStepListItem>\n\t\t\t\t\t\t\t\t\t\t\t\t\t{steps\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t.filter(Boolean)\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t.map(({ name, stepNumber, title }) => {\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tconst isActive =\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tNumber(params.stepNumber) === stepNumber\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tconst step = stepNumber\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t.toString()\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t.padStart(2, '0')\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tconst isPlayground =\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tname === data.playground.appName\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\treturn (\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<NavigationExerciseStepListItem\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tkey={stepNumber}\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\ttype=\"step\"\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tstepNumber={stepNumber}\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\texerciseNumber={exerciseNumber}\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<Link\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tto={`/${exerciseNum}/${step}`}\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tprefetch=\"intent\"\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tclassName={clsx(\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t'relative whitespace-nowrap px-2 py-0.5 pr-3 text-xl font-medium outline-none after:absolute after:-bottom-2.5 after:-right-2.5 after:h-5 after:w-5 after:rotate-45 after:scale-75 after:bg-background after:content-[\"\"] hover:underline focus:underline',\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t'bg-foreground text-background':\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tisActive,\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t)}\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t{isPlayground\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t? `${step}. ${title} 🛝`\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t: `${step}. ${title}`}\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</Link>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</NavigationExerciseStepListItem>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t)\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t})}\n\t\t\t\t\t\t\t\t\t\t\t\t\t<NavigationExerciseStepListItem\n\t\t\t\t\t\t\t\t\t\t\t\t\t\ttype=\"finished\"\n\t\t\t\t\t\t\t\t\t\t\t\t\t\texerciseNumber={exerciseNumber}\n\t\t\t\t\t\t\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t<NavLink\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tto={`/${exerciseNum}/finished`}\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tprefetch=\"intent\"\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tclassName={({ isActive }) =>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tclsx(\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t'relative whitespace-nowrap px-2 py-0.5 pr-3 text-base font-medium outline-none after:absolute after:-bottom-2.5 after:-right-2.5 after:h-5 after:w-5 after:rotate-45 after:scale-75 after:bg-background after:content-[\"\"] hover:underline focus:underline',\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t'bg-foreground text-background': isActive,\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t)\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t📝 Elaboration\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t</NavLink>\n\t\t\t\t\t\t\t\t\t\t\t\t\t</NavigationExerciseStepListItem>\n\t\t\t\t\t\t\t\t\t\t\t\t</motion.ul>\n\t\t\t\t\t\t\t\t\t\t\t) : null}\n\t\t\t\t\t\t\t\t\t\t</NavigationExerciseListItem>\n\t\t\t\t\t\t\t\t\t)\n\t\t\t\t\t\t\t\t})}\n\t\t\t\t\t\t\t</motion.ul>\n\t\t\t\t\t\t\t<div className=\"mt-6\">\n\t\t\t\t\t\t\t\t<NavLink\n\t\t\t\t\t\t\t\t\tto=\"/finished\"\n\t\t\t\t\t\t\t\t\tclassName={({ isActive }) =>\n\t\t\t\t\t\t\t\t\t\tclsx(\n\t\t\t\t\t\t\t\t\t\t\t'relative whitespace-nowrap text-lg font-bold outline-none hover:underline focus:underline',\n\t\t\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t\t\t'bg-black text-white after:absolute after:-bottom-2.5 after:-right-2.5 after:h-5 after:w-5 after:rotate-45 after:scale-75 after:bg-background after:content-[\"\"]':\n\t\t\t\t\t\t\t\t\t\t\t\t\tisActive,\n\t\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\t)\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t\t📝 Workshop Feedback\n\t\t\t\t\t\t\t\t</NavLink>\n\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t</motion.div>\n\t\t\t\t\t)}\n\t\t\t\t\t<div className=\"flex-grow\" />\n\t\t\t\t\t<div\n\t\t\t\t\t\tclassName={cn(\n\t\t\t\t\t\t\t'flex items-center justify-start p-4',\n\t\t\t\t\t\t\tisMenuOpened && users.length > 4 ? 'min-h-14' : 'h-14',\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t'w-full border-t': isMenuOpened,\n\t\t\t\t\t\t\t\t// left border is covered by the menu\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t)}\n\t\t\t\t\t>\n\t\t\t\t\t\t<FacePile isMenuOpened={isMenuOpened} />\n\t\t\t\t\t</div>\n\t\t\t\t\t{ENV.EPICSHOP_DEPLOYED ? null : user ? (\n\t\t\t\t\t\t<SimpleTooltip content={isMenuOpened ? null : 'Your account'}>\n\t\t\t\t\t\t\t<Link\n\t\t\t\t\t\t\t\tclassName={cn(\n\t\t\t\t\t\t\t\t\t'flex h-14 flex-shrink-0 items-center justify-start space-x-3 px-4 py-4 text-center no-underline hover:underline',\n\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t'border-l': !isMenuOpened,\n\t\t\t\t\t\t\t\t\t\t'w-full border-t': isMenuOpened,\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\tto=\"/account\"\n\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t{user.avatarUrl ? (\n\t\t\t\t\t\t\t\t\t<img\n\t\t\t\t\t\t\t\t\t\talt={user.name ?? user.email}\n\t\t\t\t\t\t\t\t\t\tsrc={user.avatarUrl}\n\t\t\t\t\t\t\t\t\t\tclassName=\"h-full rounded-full\"\n\t\t\t\t\t\t\t\t\t/>\n\t\t\t\t\t\t\t\t) : (\n\t\t\t\t\t\t\t\t\t<Icon name=\"User\" className=\"flex-shrink-0\" size=\"lg\" />\n\t\t\t\t\t\t\t\t)}\n\t\t\t\t\t\t\t\t{isMenuOpened ? (\n\t\t\t\t\t\t\t\t\t<motion.div\n\t\t\t\t\t\t\t\t\t\t// @ts-expect-error framer-motion + latest typescript types has issues\n\t\t\t\t\t\t\t\t\t\tclassName=\"flex items-center whitespace-nowrap\"\n\t\t\t\t\t\t\t\t\t\tinitial={{ opacity: 0 }}\n\t\t\t\t\t\t\t\t\t\tanimate={{ opacity: 1 }}\n\t\t\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t\t\tYour Account\n\t\t\t\t\t\t\t\t\t</motion.div>\n\t\t\t\t\t\t\t\t) : (\n\t\t\t\t\t\t\t\t\t<span className=\"sr-only\">Your account</span>\n\t\t\t\t\t\t\t\t)}\n\t\t\t\t\t\t\t</Link>\n\t\t\t\t\t\t</SimpleTooltip>\n\t\t\t\t\t) : null}\n\t\t\t\t\t{ENV.EPICSHOP_DEPLOYED ? null : user && nextExerciseRoute ? (\n\t\t\t\t\t\t<SimpleTooltip\n\t\t\t\t\t\t\tcontent={isMenuOpened ? null : 'Continue to next lesson'}\n\t\t\t\t\t\t>\n\t\t\t\t\t\t\t<Link\n\t\t\t\t\t\t\t\tto={nextExerciseRoute}\n\t\t\t\t\t\t\t\tprefetch=\"intent\"\n\t\t\t\t\t\t\t\tclassName={clsx(\n\t\t\t\t\t\t\t\t\t'flex h-14 w-full items-center space-x-3 border-l px-4 py-4 pl-[18px] no-underline hover:underline',\n\t\t\t\t\t\t\t\t)}\n\t\t\t\t\t\t\t\tstate={{ from: 'continue next lesson button' }}\n\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t<Icon name=\"FastForward\" className=\"flex-shrink-0\" size=\"md\" />\n\t\t\t\t\t\t\t\t{isMenuOpened ? (\n\t\t\t\t\t\t\t\t\t<motion.div\n\t\t\t\t\t\t\t\t\t\t// @ts-expect-error framer-motion + latest typescript types has issues\n\t\t\t\t\t\t\t\t\t\tclassName=\"flex items-center whitespace-nowrap\"\n\t\t\t\t\t\t\t\t\t\tinitial={{ opacity: 0 }}\n\t\t\t\t\t\t\t\t\t\tanimate={{ opacity: 1 }}\n\t\t\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t\t\tContinue to next lesson\n\t\t\t\t\t\t\t\t\t</motion.div>\n\t\t\t\t\t\t\t\t) : (\n\t\t\t\t\t\t\t\t\t<span className=\"sr-only\">Continue to next lesson</span>\n\t\t\t\t\t\t\t\t)}\n\t\t\t\t\t\t\t</Link>\n\t\t\t\t\t\t</SimpleTooltip>\n\t\t\t\t\t) : null}\n\t\t\t\t\t<div\n\t\t\t\t\t\tclassName={cn(\n\t\t\t\t\t\t\t'flex h-14 w-14 items-center justify-center self-start p-4 sm:mb-4 sm:w-full',\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t'w-full border-t': isMenuOpened,\n\t\t\t\t\t\t\t\t'border-l': !isMenuOpened,\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t)}\n\t\t\t\t\t>\n\t\t\t\t\t\t<ThemeSwitch />\n\t\t\t\t\t</div>\n\t\t\t\t</div>\n\t\t\t</div>\n\t\t</nav>\n\t)\n}\n\nconst OPENED_MENU_WIDTH = 400\n\nfunction Navigation({\n\tisMenuOpened,\n\tonMenuOpenChange: setMenuOpened,\n}: {\n\tisMenuOpened: boolean\n\tonMenuOpenChange: (change: boolean) => void\n}) {\n\tconst data = useLoaderData<typeof loader>()\n\tconst user = useOptionalUser()\n\tconst nextExerciseRoute = useNextExerciseRoute()\n\tconst params = useParams()\n\tconst { users } = usePresence()\n\n\tconst exercise = data.exercises.find(\n\t\t(e) => e.exerciseNumber === Number(params.exerciseNumber),\n\t)\n\tconst app =\n\t\tparams.type === 'solution'\n\t\t\t? exercise?.solutions.find(\n\t\t\t\t\t(s) => s.stepNumber === Number(params.stepNumber),\n\t\t\t\t)\n\t\t\t: params.type === 'problem'\n\t\t\t\t? exercise?.problems.find(\n\t\t\t\t\t\t(p) => p.stepNumber === Number(params.stepNumber),\n\t\t\t\t\t)\n\t\t\t\t: null\n\n\t// container\n\tconst menuControls = useAnimationControls()\n\tconst menuVariants = {\n\t\tclose: { width: 56 },\n\t\topen: { width: OPENED_MENU_WIDTH },\n\t}\n\n\t// items\n\tconst listVariants = {\n\t\tvisible: {\n\t\t\topacity: 1,\n\t\t\ttransition: {\n\t\t\t\tduration: 0.05,\n\t\t\t\twhen: 'beforeChildren',\n\t\t\t\tstaggerChildren: 0.03,\n\t\t\t},\n\t\t},\n\t\thidden: {\n\t\t\topacity: 0,\n\t\t},\n\t}\n\tconst exNum = Number(params.exerciseNumber).toString().padStart(2, '0')\n\n\treturn (\n\t\t<nav className=\"hidden border-r sm:flex\">\n\t\t\t<motion.div\n\t\t\t\tinitial={isMenuOpened ? 'open' : 'close'}\n\t\t\t\tvariants={menuVariants}\n\t\t\t\tanimate={menuControls}\n\t\t\t>\n\t\t\t\t<div className=\"flex h-full flex-col items-center justify-between\">\n\t\t\t\t\t<NavToggle\n\t\t\t\t\t\ttitle={data.workshopTitle}\n\t\t\t\t\t\tmenuControls={menuControls}\n\t\t\t\t\t\tisMenuOpened={isMenuOpened}\n\t\t\t\t\t\tsetMenuOpened={setMenuOpened}\n\t\t\t\t\t/>\n\t\t\t\t\t{isMenuOpened && (\n\t\t\t\t\t\t<motion.div\n\t\t\t\t\t\t\tstyle={{ width: OPENED_MENU_WIDTH }}\n\t\t\t\t\t\t\t// @ts-expect-error framer-motion + latest typescript types has issues\n\t\t\t\t\t\t\tclassName=\"flex flex-grow flex-col justify-between overflow-y-auto p-6 scrollbar-thin scrollbar-thumb-scrollbar\"\n\t\t\t\t\t\t\tinitial={{ opacity: 0 }}\n\t\t\t\t\t\t\tanimate={{ opacity: 1 }}\n\t\t\t\t\t\t>\n\t\t\t\t\t\t\t<motion.ul\n\t\t\t\t\t\t\t\tvariants={listVariants}\n\t\t\t\t\t\t\t\tinitial=\"hidden\"\n\t\t\t\t\t\t\t\tanimate=\"visible\"\n\t\t\t\t\t\t\t\t// @ts-expect-error framer-motion + latest typescript types has issues\n\t\t\t\t\t\t\t\tclassName=\"flex flex-col\"\n\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t<span>\n\t\t\t\t\t\t\t\t\t<NavLink\n\t\t\t\t\t\t\t\t\t\tprefetch=\"intent\"\n\t\t\t\t\t\t\t\t\t\tto=\"/\"\n\t\t\t\t\t\t\t\t\t\tclassName={({ isActive }) =>\n\t\t\t\t\t\t\t\t\t\t\tclsx(\n\t\t\t\t\t\t\t\t\t\t\t\t'relative whitespace-nowrap px-2 py-0.5 pr-3 text-2xl font-bold outline-none hover:underline focus:underline',\n\t\t\t\t\t\t\t\t\t\t\t\t'after:absolute after:-bottom-2.5 after:-right-2.5 after:h-5 after:w-5 after:rotate-45 after:scale-75 after:bg-background after:content-[\"\"] hover:underline focus:underline',\n\t\t\t\t\t\t\t\t\t\t\t\t{ 'bg-foreground text-background': isActive },\n\t\t\t\t\t\t\t\t\t\t\t)\n\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t\t\tHome\n\t\t\t\t\t\t\t\t\t</NavLink>\n\t\t\t\t\t\t\t\t</span>\n\t\t\t\t\t\t\t\t{data.exercises.map(({ exerciseNumber, title, steps }) => {\n\t\t\t\t\t\t\t\t\tconst isActive =\n\t\t\t\t\t\t\t\t\t\tNumber(params.exerciseNumber) === exerciseNumber\n\t\t\t\t\t\t\t\t\tconst showPlayground =\n\t\t\t\t\t\t\t\t\t\t!isActive &&\n\t\t\t\t\t\t\t\t\t\tdata.playground.exerciseNumber === exerciseNumber\n\t\t\t\t\t\t\t\t\tconst exerciseNum = exerciseNumber.toString().padStart(2, '0')\n\t\t\t\t\t\t\t\t\treturn (\n\t\t\t\t\t\t\t\t\t\t<NavigationExerciseListItem\n\t\t\t\t\t\t\t\t\t\t\tkey={exerciseNumber}\n\t\t\t\t\t\t\t\t\t\t\texerciseNumber={exerciseNumber}\n\t\t\t\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t\t\t\t<Link\n\t\t\t\t\t\t\t\t\t\t\t\tprefetch=\"intent\"\n\t\t\t\t\t\t\t\t\t\t\t\tto={`/${exerciseNum}`}\n\t\t\t\t\t\t\t\t\t\t\t\tclassName={clsx(\n\t\t\t\t\t\t\t\t\t\t\t\t\t'relative whitespace-nowrap px-2 py-0.5 pr-3 text-2xl font-bold outline-none hover:underline focus:underline',\n\t\t\t\t\t\t\t\t\t\t\t\t\t'after:absolute after:-bottom-2.5 after:-right-2.5 after:h-5 after:w-5 after:rotate-45 after:scale-75 after:bg-background after:content-[\"\"] hover:underline focus:underline',\n\t\t\t\t\t\t\t\t\t\t\t\t\t{ 'bg-foreground text-background': isActive },\n\t\t\t\t\t\t\t\t\t\t\t\t)}\n\t\t\t\t\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t\t\t\t\t{title}\n\t\t\t\t\t\t\t\t\t\t\t\t{showPlayground ? ' 🛝' : null}\n\t\t\t\t\t\t\t\t\t\t\t</Link>\n\t\t\t\t\t\t\t\t\t\t\t{isActive ? (\n\t\t\t\t\t\t\t\t\t\t\t\t<motion.ul\n\t\t\t\t\t\t\t\t\t\t\t\t\tvariants={listVariants}\n\t\t\t\t\t\t\t\t\t\t\t\t\tinitial=\"hidden\"\n\t\t\t\t\t\t\t\t\t\t\t\t\tanimate=\"visible\"\n\t\t\t\t\t\t\t\t\t\t\t\t\t// @ts-expect-error framer-motion + latest typescript types has issues\n\t\t\t\t\t\t\t\t\t\t\t\t\tclassName=\"ml-4 mt-4 flex flex-col\"\n\t\t\t\t\t\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t\t\t\t\t\t<NavigationExerciseStepListItem\n\t\t\t\t\t\t\t\t\t\t\t\t\t\tkey={exerciseNumber}\n\t\t\t\t\t\t\t\t\t\t\t\t\t\ttype=\"instructions\"\n\t\t\t\t\t\t\t\t\t\t\t\t\t\texerciseNumber={exerciseNumber}\n\t\t\t\t\t\t\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t<Link\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tto={`/${exerciseNum}`}\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tprefetch=\"intent\"\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tclassName={clsx(\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t'relative whitespace-nowrap px-2 py-0.5 pr-3 text-xl font-medium outline-none after:absolute after:-bottom-2.5 after:-right-2.5 after:h-5 after:w-5 after:rotate-45 after:scale-75 after:bg-background after:content-[\"\"] hover:underline focus:underline',\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t'bg-foreground text-background':\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t!params.stepNumber,\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t)}\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tIntro\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t</Link>\n\t\t\t\t\t\t\t\t\t\t\t\t\t</NavigationExerciseStepListItem>\n\t\t\t\t\t\t\t\t\t\t\t\t\t{steps\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t.filter(Boolean)\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t.map(({ name, stepNumber, title }) => {\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tconst isActive =\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tNumber(params.stepNumber) === stepNumber\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tconst step = stepNumber\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t.toString()\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t.padStart(2, '0')\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tconst isPlayground =\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tname === data.playground.appName\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\treturn (\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<NavigationExerciseStepListItem\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tkey={stepNumber}\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\ttype=\"step\"\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tstepNumber={stepNumber}\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\texerciseNumber={exerciseNumber}\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<Link\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tto={`/${exerciseNum}/${step}`}\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tprefetch=\"intent\"\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tclassName={clsx(\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t'relative whitespace-nowrap px-2 py-0.5 pr-3 text-xl font-medium outline-none after:absolute after:-bottom-2.5 after:-right-2.5 after:h-5 after:w-5 after:rotate-45 after:scale-75 after:bg-background after:content-[\"\"] hover:underline focus:underline',\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t'bg-foreground text-background':\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tisActive,\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t)}\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t{isPlayground\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t? `${step}. ${title} 🛝`\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t: `${step}. ${title}`}\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</Link>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</NavigationExerciseStepListItem>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t)\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t})}\n\t\t\t\t\t\t\t\t\t\t\t\t\t<NavigationExerciseStepListItem\n\t\t\t\t\t\t\t\t\t\t\t\t\t\ttype=\"finished\"\n\t\t\t\t\t\t\t\t\t\t\t\t\t\texerciseNumber={exerciseNumber}\n\t\t\t\t\t\t\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t<NavLink\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tto={`/${exerciseNum}/finished`}\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tprefetch=\"intent\"\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tclassName={({ isActive }) =>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tclsx(\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t'relative whitespace-nowrap px-2 py-0.5 pr-3 text-base font-medium outline-none after:absolute after:-bottom-2.5 after:-right-2.5 after:h-5 after:w-5 after:rotate-45 after:scale-75 after:bg-background after:content-[\"\"] hover:underline focus:underline',\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t'bg-foreground text-background': isActive,\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t)\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t📝 Elaboration\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t</NavLink>\n\t\t\t\t\t\t\t\t\t\t\t\t\t</NavigationExerciseStepListItem>\n\t\t\t\t\t\t\t\t\t\t\t\t</motion.ul>\n\t\t\t\t\t\t\t\t\t\t\t) : null}\n\t\t\t\t\t\t\t\t\t\t</NavigationExerciseListItem>\n\t\t\t\t\t\t\t\t\t)\n\t\t\t\t\t\t\t\t})}\n\t\t\t\t\t\t\t</motion.ul>\n\t\t\t\t\t\t\t<div className=\"mt-6\">\n\t\t\t\t\t\t\t\t<NavLink\n\t\t\t\t\t\t\t\t\tto=\"/finished\"\n\t\t\t\t\t\t\t\t\tclassName={({ isActive }) =>\n\t\t\t\t\t\t\t\t\t\tclsx(\n\t\t\t\t\t\t\t\t\t\t\t'relative whitespace-nowrap text-lg font-bold outline-none hover:underline focus:underline',\n\t\t\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t\t\t'bg-black text-white after:absolute after:-bottom-2.5 after:-right-2.5 after:h-5 after:w-5 after:rotate-45 after:scale-75 after:bg-background after:content-[\"\"]':\n\t\t\t\t\t\t\t\t\t\t\t\t\tisActive,\n\t\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\t)\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t\t📝 Workshop Feedback\n\t\t\t\t\t\t\t\t</NavLink>\n\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t</motion.div>\n\t\t\t\t\t)}\n\t\t\t\t\t{!isMenuOpened && (\n\t\t\t\t\t\t<div className=\"flex flex-grow flex-col justify-center\">\n\t\t\t\t\t\t\t<div className=\"orientation-sideways w-full font-mono text-sm font-medium uppercase leading-none\">\n\t\t\t\t\t\t\t\t{exercise?.title ? (\n\t\t\t\t\t\t\t\t\t<Link to={`/${exNum}`}>{exercise.title}</Link>\n\t\t\t\t\t\t\t\t) : null}\n\t\t\t\t\t\t\t\t{exercise?.title && app?.title ? ' — ' : null}\n\t\t\t\t\t\t\t\t{app?.title ? (\n\t\t\t\t\t\t\t\t\t<Link\n\t\t\t\t\t\t\t\t\t\tto={`/${exNum}/${app.stepNumber\n\t\t\t\t\t\t\t\t\t\t\t.toString()\n\t\t\t\t\t\t\t\t\t\t\t.padStart(2, '0')}`}\n\t\t\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t\t\t{app.title}\n\t\t\t\t\t\t\t\t\t</Link>\n\t\t\t\t\t\t\t\t) : null}\n\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t</div>\n\t\t\t\t\t)}\n\t\t\t\t\t<div\n\t\t\t\t\t\tclassName={cn(\n\t\t\t\t\t\t\t'flex w-full items-center justify-start border-t p-4 transition-[height]',\n\t\t\t\t\t\t\tisMenuOpened && users.length > 4 ? 'h-28' : 'h-14',\n\t\t\t\t\t\t)}\n\t\t\t\t\t\tstyle={isMenuOpened ? { width: OPENED_MENU_WIDTH } : {}}\n\t\t\t\t\t>\n\t\t\t\t\t\t<FacePile isMenuOpened={isMenuOpened} />\n\t\t\t\t\t</div>\n\t\t\t\t\t{ENV.EPICSHOP_DEPLOYED ? null : user ? (\n\t\t\t\t\t\t<SimpleTooltip content={isMenuOpened ? null : 'Your account'}>\n\t\t\t\t\t\t\t<Link\n\t\t\t\t\t\t\t\tclassName=\"flex h-14 w-full flex-shrink-0 items-center justify-start space-x-3 border-t px-4 py-4 text-center no-underline hover:underline\"\n\t\t\t\t\t\t\t\tto=\"/account\"\n\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t{user.avatarUrl ? (\n\t\t\t\t\t\t\t\t\t<img\n\t\t\t\t\t\t\t\t\t\talt={user.name ?? user.email}\n\t\t\t\t\t\t\t\t\t\tsrc={user.avatarUrl}\n\t\t\t\t\t\t\t\t\t\tclassName=\"h-full rounded-full\"\n\t\t\t\t\t\t\t\t\t/>\n\t\t\t\t\t\t\t\t) : (\n\t\t\t\t\t\t\t\t\t<Icon name=\"User\" className=\"flex-shrink-0\" size=\"lg\" />\n\t\t\t\t\t\t\t\t)}\n\t\t\t\t\t\t\t\t{isMenuOpened ? (\n\t\t\t\t\t\t\t\t\t<motion.div\n\t\t\t\t\t\t\t\t\t\t// @ts-expect-error framer-motion + latest typescript types has issues\n\t\t\t\t\t\t\t\t\t\tclassName=\"flex items-center whitespace-nowrap\"\n\t\t\t\t\t\t\t\t\t\tinitial={{ opacity: 0 }}\n\t\t\t\t\t\t\t\t\t\tanimate={{ opacity: 1 }}\n\t\t\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t\t\tYour Account\n\t\t\t\t\t\t\t\t\t</motion.div>\n\t\t\t\t\t\t\t\t) : (\n\t\t\t\t\t\t\t\t\t<span className=\"sr-only\">Your account</span>\n\t\t\t\t\t\t\t\t)}\n\t\t\t\t\t\t\t</Link>\n\t\t\t\t\t\t</SimpleTooltip>\n\t\t\t\t\t) : null}\n\t\t\t\t\t{ENV.EPICSHOP_DEPLOYED ? null : user && nextExerciseRoute ? (\n\t\t\t\t\t\t<SimpleTooltip\n\t\t\t\t\t\t\tcontent={isMenuOpened ? null : 'Continue to next lesson'}\n\t\t\t\t\t\t>\n\t\t\t\t\t\t\t<Link\n\t\t\t\t\t\t\t\tto={nextExerciseRoute}\n\t\t\t\t\t\t\t\tprefetch=\"intent\"\n\t\t\t\t\t\t\t\tclassName={clsx(\n\t\t\t\t\t\t\t\t\t'flex h-14 w-full items-center space-x-3 border-t px-4 py-4 pl-[18px] no-underline hover:underline',\n\t\t\t\t\t\t\t\t)}\n\t\t\t\t\t\t\t\tstate={{ from: 'continue next lesson button' }}\n\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t<Icon name=\"FastForward\" className=\"flex-shrink-0\" size=\"md\" />\n\t\t\t\t\t\t\t\t{isMenuOpened ? (\n\t\t\t\t\t\t\t\t\t<motion.div\n\t\t\t\t\t\t\t\t\t\t// @ts-expect-error framer-motion + latest typescript types has issues\n\t\t\t\t\t\t\t\t\t\tclassName=\"flex items-center whitespace-nowrap\"\n\t\t\t\t\t\t\t\t\t\tinitial={{ opacity: 0 }}\n\t\t\t\t\t\t\t\t\t\tanimate={{ opacity: 1 }}\n\t\t\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t\t\tContinue to next lesson\n\t\t\t\t\t\t\t\t\t</motion.div>\n\t\t\t\t\t\t\t\t) : (\n\t\t\t\t\t\t\t\t\t<span className=\"sr-only\">Continue to next lesson</span>\n\t\t\t\t\t\t\t\t)}\n\t\t\t\t\t\t\t</Link>\n\t\t\t\t\t\t</SimpleTooltip>\n\t\t\t\t\t) : null}\n\t\t\t\t\t<div className=\"mb-4 w-full self-start border-t pl-3 pt-[15px]\">\n\t\t\t\t\t\t<ThemeSwitch />\n\t\t\t\t\t</div>\n\t\t\t\t</div>\n\t\t\t</motion.div>\n\t\t</nav>\n\t)\n}\n\nfunction NavToggle({\n\ttitle,\n\tisMenuOpened,\n\tsetMenuOpened,\n\tmenuControls,\n}: {\n\ttitle: string\n\tisMenuOpened: boolean\n\tsetMenuOpened: (value: boolean) => void\n\tmenuControls?: AnimationControls\n}) {\n\tconst menuButtonRef = React.useRef<HTMLButtonElement>(null)\n\tconst path01Variants = {\n\t\topen: { d: 'M3.06061 2.99999L21.0606 21' },\n\t\tclosed: { d: 'M0 9.5L24 9.5' },\n\t}\n\tconst path02Variants = {\n\t\topen: { d: 'M3.00006 21.0607L21 3.06064' },\n\t\tmoving: { d: 'M0 14.5L24 14.5' },\n\t\tclosed: { d: 'M0 14.5L15 14.5' },\n\t}\n\tconst path01Controls = useAnimationControls()\n\tconst path02Controls = useAnimationControls()\n\n\tasync function toggleMenu() {\n\t\tvoid menuControls?.start(isMenuOpened ? 'close' : 'open')\n\t\tsetMenuOpened(!isMenuOpened)\n\t\tif (isMenuOpened) {\n\t\t\tvoid path01Controls.start(path01Variants.closed)\n\t\t\tawait path02Controls.start(path02Variants.moving)\n\t\t\tvoid path02Controls.start(path02Variants.closed)\n\t\t} else {\n\t\t\tawait path02Controls.start(path02Variants.moving)\n\t\t\tvoid path01Controls.start(path01Variants.open)\n\t\t\tvoid path02Controls.start(path02Variants.open)\n\t\t}\n\t}\n\n\tReact.useEffect(() => {\n\t\tif (!isMenuOpened) return\n\n\t\tfunction handleKeyUp(event: KeyboardEvent) {\n\t\t\tif (event.key === 'Escape') {\n\t\t\t\tmenuButtonRef.current?.click()\n\t\t\t}\n\t\t}\n\t\tdocument.addEventListener('keyup', handleKeyUp)\n\t\treturn () => document.removeEventListener('keyup', handleKeyUp)\n\t}, [isMenuOpened])\n\n\treturn (\n\t\t<div\n\t\t\tclassName={cn(\n\t\t\t\t'relative inline-flex h-14 flex-shrink-0 items-center justify-between overflow-hidden border-r sm:w-full sm:border-b sm:border-r-0',\n\t\t\t\t{\n\t\t\t\t\t'w-full': isMenuOpened,\n\t\t\t\t},\n\t\t\t)}\n\t\t>\n\t\t\t<button\n\t\t\t\tref={menuButtonRef}\n\t\t\t\tclassName=\"flex h-14 w-14 items-center justify-center\"\n\t\t\t\taria-label=\"Open Navigation menu\"\n\t\t\t\tonClick={toggleMenu}\n\t\t\t>\n\t\t\t\t<svg width=\"24\" height=\"24\" viewBox=\"0 0 24 24\">\n\t\t\t\t\t<motion.path\n\t\t\t\t\t\t{...path01Variants.closed}\n\t\t\t\t\t\tanimate={path01Controls}\n\t\t\t\t\t\ttransition={{ duration: 0.2 }}\n\t\t\t\t\t\tstroke=\"currentColor\"\n\t\t\t\t\t\tstrokeWidth={1.5}\n\t\t\t\t\t/>\n\t\t\t\t\t<motion.path\n\t\t\t\t\t\t{...path02Variants.closed}\n\t\t\t\t\t\tanimate={path02Controls}\n\t\t\t\t\t\ttransition={{ duration: 0.2 }}\n\t\t\t\t\t\tstroke=\"currentColor\"\n\t\t\t\t\t\tstrokeWidth={1.5}\n\t\t\t\t\t/>\n\t\t\t\t</svg>\n\t\t\t</button>\n\t\t\t{isMenuOpened && (\n\t\t\t\t<motion.p\n\t\t\t\t\ttransition={{ delay: 0.2 }}\n\t\t\t\t\tinitial={{ opacity: 0, y: 5 }}\n\t\t\t\t\tanimate={{ opacity: 1, y: 0 }}\n\t\t\t\t\t// @ts-expect-error framer-motion + latest typescript types has issues\n\t\t\t\t\tclassName=\"absolute right-5 whitespace-nowrap font-mono text-sm uppercase\"\n\t\t\t\t>\n\t\t\t\t\t<Link to=\"/\">{title}</Link>\n\t\t\t\t</motion.p>\n\t\t\t)}\n\t\t</div>\n\t)\n}\n"],"names":["stopAnimation","visualElement","value","setVariants","variantLabels","key","variant","setTarget","child","setValues","definition","animationControls","subscribers","controls","transitionOverride","animations","animateVisualElement","useAnimationControls","useConstant","useIsomorphicLayoutEffect","makeMediaQueryStore","mediaQuery","serverSnapshot","getSnapshot","subscribe","callback","mediaQueryList","useSyncExternalStore","DIALOG_NAME","createDialogContext","createDialogScope","createContextScope","DialogProvider","useDialogContext","Dialog","props","__scopeDialog","children","openProp","defaultOpen","onOpenChange","modal","triggerRef","React.useRef","contentRef","open","setOpen","useControllableState","jsx","useId","React.useCallback","prevOpen","TRIGGER_NAME","DialogTrigger","React.forwardRef","forwardedRef","triggerProps","context","composedTriggerRef","useComposedRefs","Primitive","getState","composeEventHandlers","PORTAL_NAME","PortalProvider","usePortalContext","DialogPortal","forceMount","container","React.Children","Presence","PortalPrimitive","OVERLAY_NAME","DialogOverlay","portalContext","overlayProps","DialogOverlayImpl","RemoveScroll","Slot","CONTENT_NAME","DialogContent","contentProps","DialogContentModal","DialogContentNonModal","composedRefs","React.useEffect","content","hideOthers","DialogContentImpl","event","_a","originalEvent","ctrlLeftClick","hasInteractedOutsideRef","hasPointerDownOutsideRef","_b","target","trapFocus","onOpenAutoFocus","onCloseAutoFocus","useFocusGuards","jsxs","Fragment","FocusScope","DismissableLayer","TitleWarning","DescriptionWarning","TITLE_NAME","DialogTitle","titleProps","DESCRIPTION_NAME","DialogDescription","descriptionProps","CLOSE_NAME","DialogClose","closeProps","TITLE_WARNING_NAME","WarningProvider","useWarningContext","createContext","titleId","titleWarningContext","MESSAGE","DESCRIPTION_WARNING_NAME","descriptionId","describedById","Root","Trigger","Portal","Overlay","Content","Title","Description","Close","DialogPrimitive.Root","DialogPrimitive.Trigger","DialogPrimitive.Portal","className","ref","DialogPrimitive.Overlay","cn","DialogPrimitive.Content","DialogPrimitive.Close","Icon","DialogHeader","DialogPrimitive.Title","DialogPrimitive.Description","opacities","shadows","getScoreClassNames","score","opacityNumber","Math","round","length","shadowNumber","FacePile","isMenuOpened","loggedInUser","useOptionalUser","users","usePresence","product","displayNameShort","useWorkshopConfig","limit","numberOverLimit","shouldShowNumberOverLimit","tiffany","Link","rel","to","alt","src","overLimitLabel","TooltipProvider","slice","map","user","scoreClassNames","locationLabel","getLocationLabel","location","Tooltip","TooltipTrigger","asChild","avatarUrl","tabIndex","name","TooltipContent","origin","includes","id","line1","line2","useIsWide","App","isWide","isHydrated","useHydrated","setMenuOpened","React","useRevalidationWS","watchPaths","NoUserBanner","MobileNavigation","onMenuOpenChange","Navigation","Outlet","exercise","exercisePortion","exerciseNumber","stepNumber","filter","Boolean","s","toString","padStart","join","type","workshopTitle","host","displayName","details","ENV","EPICSHOP_DEPLOYED","EPICSHOP_GITHUB_REPO","href","Logo","size","style","itemVariants","hidden","opacity","x","visible","NavigationExerciseListItem","progressClassName","useExerciseProgressClassName","motion","li","variants","NavigationExerciseStepListItem","progressItemSearch","useProgressItemClassName","data","useLoaderData","nextExerciseRoute","useNextExerciseRoute","params","useParams","listVariants","transition","duration","when","staggerChildren","NavToggle","title","div","initial","animate","ul","NavLink","prefetch","isActive","clsx","exercises","steps","Number","showPlayground","playground","exerciseNum","step","isPlayground","appName","SimpleTooltip","email","state","from","ThemeSwitch","OPENED_MENU_WIDTH","find","e","app","solutions","problems","p","menuControls","menuVariants","close","width","exNum","menuButtonRef","path01Variants","d","closed","path02Variants","moving","path01Controls","path02Controls","toggleMenu","start","handleKeyUp","current","click","document","addEventListener","removeEventListener","onClick","height","viewBox","path","stroke","strokeWidth","delay","y"],"mappings":"k0BAIA,SAASA,GAAcC,EAAe,CAClCA,EAAc,OAAO,QAASC,GAAUA,EAAM,KAAI,CAAE,CACxD,CACA,SAASC,EAAYF,EAAeG,EAAe,CACxB,CAAC,GAAGA,CAAa,EAAE,QAAO,EAClC,QAASC,GAAQ,CAC5B,MAAMC,EAAUL,EAAc,WAAWI,CAAG,EAC5CC,GAAWC,GAAUN,EAAeK,CAAO,EACvCL,EAAc,iBACdA,EAAc,gBAAgB,QAASO,GAAU,CAC7CL,EAAYK,EAAOJ,CAAa,CAChD,CAAa,CAEb,CAAK,CACL,CACA,SAASK,GAAUR,EAAeS,EAAY,CAC1C,GAAI,MAAM,QAAQA,CAAU,EACxB,OAAOP,EAAYF,EAAeS,CAAU,EAE3C,GAAI,OAAOA,GAAe,SAC3B,OAAOP,EAAYF,EAAe,CAACS,CAAU,CAAC,EAG9CH,GAAUN,EAAeS,CAAU,CAE3C,CAIA,SAASC,IAAoB,CAQzB,MAAMC,EAAc,IAAI,IAClBC,EAAW,CACb,UAAUZ,EAAe,CACrB,OAAAW,EAAY,IAAIX,CAAa,EACtB,IAAM,KAAKW,EAAY,OAAOX,CAAa,CACrD,EACD,MAAMS,EAAYI,EAAoB,CAElC,MAAMC,EAAa,CAAA,EACnB,OAAAH,EAAY,QAASX,GAAkB,CACnCc,EAAW,KAAKC,GAAqBf,EAAeS,EAAY,CAC5D,mBAAAI,CACH,CAAA,CAAC,CAClB,CAAa,EACM,QAAQ,IAAIC,CAAU,CAChC,EACD,IAAIL,EAAY,CAEZ,OAAOE,EAAY,QAASX,GAAkB,CAC1CQ,GAAUR,EAAeS,CAAU,CACnD,CAAa,CACJ,EACD,MAAO,CACHE,EAAY,QAASX,GAAkB,CACnCD,GAAcC,CAAa,CAC3C,CAAa,CACJ,EACD,OAAQ,CAEJ,MAAO,IAAM,CAETY,EAAS,KAAI,CAC7B,CACS,CACT,EACI,OAAOA,CACX,CC5CA,SAASI,GAAuB,CAC5B,MAAMJ,EAAWK,GAAYP,EAAiB,EAC9C,OAAAQ,GAA0BN,EAAS,MAAO,CAAA,CAAE,EACrCA,CACX,CCnCgB,SAAAO,GACfC,EACAC,EACC,CACD,SAASC,GAAc,CACf,OAAA,OAAO,WAAWF,CAAU,EAAE,OACtC,CAEA,SAASG,EAAUC,EAAsB,CAClC,MAAAC,EAAiB,OAAO,WAAWL,CAAU,EACpC,OAAAK,EAAA,iBAAiB,SAAUD,CAAQ,EAC3C,IAAM,CACGC,EAAA,oBAAoB,SAAUD,CAAQ,CAAA,CAEvD,CAEA,OAAO,UAAyB,CAC/B,OAAOE,EAAqB,qBAAAH,EAAWD,EAAa,IAAMD,CAAc,CAAA,CAE1E,CCFA,IAAIM,EAAc,SACd,CAACC,GAAqBC,EAAiB,EAAIC,GAAmBH,CAAW,EACzE,CAACI,GAAgBC,CAAgB,EAAIJ,GAAoBD,CAAW,EACpEM,GAAUC,GAAU,CACtB,KAAM,CACJ,cAAAC,EACA,SAAAC,EACA,KAAMC,EACN,YAAAC,EACA,aAAAC,EACA,MAAAC,EAAQ,EACT,EAAGN,EACEO,EAAaC,SAAa,IAAI,EAC9BC,EAAaD,SAAa,IAAI,EAC9B,CAACE,EAAO,GAAOC,CAAO,EAAIC,GAAqB,CACnD,KAAMT,EACN,YAAaC,EACb,SAAUC,CACd,CAAG,EACD,OAAuBQ,EAAG,IACxBhB,GACA,CACE,MAAOI,EACP,WAAAM,EACA,WAAAE,EACA,UAAWK,EAAO,EAClB,QAASA,EAAO,EAChB,cAAeA,EAAO,EACtB,KAAAJ,EACA,aAAcC,EACd,aAAcI,EAAAA,YAAkB,IAAMJ,EAASK,GAAa,CAACA,CAAQ,EAAG,CAACL,CAAO,CAAC,EACjF,MAAAL,EACA,SAAAJ,CACD,CACL,CACA,EACAH,GAAO,YAAcN,EACrB,IAAIwB,GAAe,gBACfC,GAAgBC,EAAgB,WAClC,CAACnB,EAAOoB,IAAiB,CACvB,KAAM,CAAE,cAAAnB,EAAe,GAAGoB,CAAY,EAAKrB,EACrCsB,EAAUxB,EAAiBmB,GAAchB,CAAa,EACtDsB,EAAqBC,EAAgBJ,EAAcE,EAAQ,UAAU,EAC3E,OAAuBT,EAAG,IACxBY,EAAU,OACV,CACE,KAAM,SACN,gBAAiB,SACjB,gBAAiBH,EAAQ,KACzB,gBAAiBA,EAAQ,UACzB,aAAcI,EAASJ,EAAQ,IAAI,EACnC,GAAGD,EACH,IAAKE,EACL,QAASI,EAAqB3B,EAAM,QAASsB,EAAQ,YAAY,CAClE,CACP,CACG,CACH,EACAJ,GAAc,YAAcD,GAC5B,IAAIW,EAAc,eACd,CAACC,GAAgBC,EAAgB,EAAIpC,GAAoBkC,EAAa,CACxE,WAAY,MACd,CAAC,EACGG,GAAgB/B,GAAU,CAC5B,KAAM,CAAE,cAAAC,EAAe,WAAA+B,EAAY,SAAA9B,EAAU,UAAA+B,CAAS,EAAKjC,EACrDsB,EAAUxB,EAAiB8B,EAAa3B,CAAa,EAC3D,OAAuBY,EAAG,IAACgB,GAAgB,CAAE,MAAO5B,EAAe,WAAA+B,EAAY,SAAUE,EAAAA,SAAe,IAAIhC,EAAW7B,GAA0BwC,EAAG,IAACsB,EAAU,CAAE,QAASH,GAAcV,EAAQ,KAAM,SAA0BT,EAAAA,IAAIuB,GAAiB,CAAE,QAAS,GAAM,UAAAH,EAAW,SAAU5D,CAAK,CAAE,CAAC,CAAE,CAAC,CAAG,CAAA,CAC3S,EACA0D,GAAa,YAAcH,EAC3B,IAAIS,EAAe,gBACfC,GAAgBnB,EAAgB,WAClC,CAACnB,EAAOoB,IAAiB,CACvB,MAAMmB,EAAgBT,GAAiBO,EAAcrC,EAAM,aAAa,EAClE,CAAE,WAAAgC,EAAaO,EAAc,WAAY,GAAGC,CAAc,EAAGxC,EAC7DsB,EAAUxB,EAAiBuC,EAAcrC,EAAM,aAAa,EAClE,OAAOsB,EAAQ,MAAwBT,MAAIsB,EAAU,CAAE,QAASH,GAAcV,EAAQ,KAAM,SAA0BT,MAAI4B,GAAmB,CAAE,GAAGD,EAAc,IAAKpB,CAAc,CAAA,EAAG,EAAI,IAC3L,CACH,EACAkB,GAAc,YAAcD,EAC5B,IAAII,GAAoBtB,EAAgB,WACtC,CAACnB,EAAOoB,IAAiB,CACvB,KAAM,CAAE,cAAAnB,EAAe,GAAGuC,CAAY,EAAKxC,EACrCsB,EAAUxB,EAAiBuC,EAAcpC,CAAa,EAC5D,OAGkBY,EAAAA,IAAI6B,GAAc,CAAE,GAAIC,GAAM,eAAgB,GAAM,OAAQ,CAACrB,EAAQ,UAAU,EAAG,SAA0BT,EAAG,IAC7HY,EAAU,IACV,CACE,aAAcC,EAASJ,EAAQ,IAAI,EACnC,GAAGkB,EACH,IAAKpB,EACL,MAAO,CAAE,cAAe,OAAQ,GAAGoB,EAAa,KAAO,CACxD,CACT,EAAS,CAEN,CACH,EACII,EAAe,gBACfC,GAAgB1B,EAAgB,WAClC,CAACnB,EAAOoB,IAAiB,CACvB,MAAMmB,EAAgBT,GAAiBc,EAAc5C,EAAM,aAAa,EAClE,CAAE,WAAAgC,EAAaO,EAAc,WAAY,GAAGO,CAAc,EAAG9C,EAC7DsB,EAAUxB,EAAiB8C,EAAc5C,EAAM,aAAa,EAClE,OAAuBa,MAAIsB,EAAU,CAAE,QAASH,GAAcV,EAAQ,KAAM,SAAUA,EAAQ,MAAwBT,EAAG,IAACkC,GAAoB,CAAE,GAAGD,EAAc,IAAK1B,CAAc,CAAA,EAAoBP,EAAAA,IAAImC,GAAuB,CAAE,GAAGF,EAAc,IAAK1B,CAAc,CAAA,CAAG,CAAA,CAC7Q,CACH,EACAyB,GAAc,YAAcD,EAC5B,IAAIG,GAAqB5B,EAAgB,WACvC,CAACnB,EAAOoB,IAAiB,CACvB,MAAME,EAAUxB,EAAiB8C,EAAc5C,EAAM,aAAa,EAC5DS,EAAaD,SAAa,IAAI,EAC9ByC,EAAezB,EAAgBJ,EAAcE,EAAQ,WAAYb,CAAU,EACjFyC,OAAAA,EAAAA,UAAgB,IAAM,CACpB,MAAMC,EAAU1C,EAAW,QAC3B,GAAI0C,EAAS,OAAOC,GAAWD,CAAO,CACvC,EAAE,CAAE,CAAA,EACkBtC,EAAG,IACxBwC,GACA,CACE,GAAGrD,EACH,IAAKiD,EACL,UAAW3B,EAAQ,KACnB,4BAA6B,GAC7B,iBAAkBK,EAAqB3B,EAAM,iBAAmBsD,GAAU,OACxEA,EAAM,eAAc,GACpBC,EAAAjC,EAAQ,WAAW,UAAnB,MAAAiC,EAA4B,OACtC,CAAS,EACD,qBAAsB5B,EAAqB3B,EAAM,qBAAuBsD,GAAU,CAChF,MAAME,EAAgBF,EAAM,OAAO,cAC7BG,EAAgBD,EAAc,SAAW,GAAKA,EAAc,UAAY,IACzDA,EAAc,SAAW,GAAKC,IACjCH,EAAM,gBAClC,CAAS,EACD,eAAgB3B,EACd3B,EAAM,eACLsD,GAAUA,EAAM,eAAgB,CAClC,CACF,CACP,CACG,CACH,EACIN,GAAwB7B,EAAgB,WAC1C,CAACnB,EAAOoB,IAAiB,CACvB,MAAME,EAAUxB,EAAiB8C,EAAc5C,EAAM,aAAa,EAC5D0D,EAA0BlD,SAAa,EAAK,EAC5CmD,EAA2BnD,SAAa,EAAK,EACnD,OAAuBK,EAAG,IACxBwC,GACA,CACE,GAAGrD,EACH,IAAKoB,EACL,UAAW,GACX,4BAA6B,GAC7B,iBAAmBkC,GAAU,UAC3BC,EAAAvD,EAAM,mBAAN,MAAAuD,EAAA,KAAAvD,EAAyBsD,GACpBA,EAAM,mBACJI,EAAwB,UAASE,EAAAtC,EAAQ,WAAW,UAAnB,MAAAsC,EAA4B,QAClEN,EAAM,eAAc,GAEtBI,EAAwB,QAAU,GAClCC,EAAyB,QAAU,EACpC,EACD,kBAAoBL,GAAU,UAC5BC,EAAAvD,EAAM,oBAAN,MAAAuD,EAAA,KAAAvD,EAA0BsD,GACrBA,EAAM,mBACTI,EAAwB,QAAU,GAC9BJ,EAAM,OAAO,cAAc,OAAS,gBACtCK,EAAyB,QAAU,KAGvC,MAAME,EAASP,EAAM,SACGM,EAAAtC,EAAQ,WAAW,UAAnB,YAAAsC,EAA4B,SAASC,KACxCP,EAAM,iBACvBA,EAAM,OAAO,cAAc,OAAS,WAAaK,EAAyB,SAC5EL,EAAM,eAAc,CAEvB,CACF,CACP,CACG,CACH,EACID,GAAoBlC,EAAgB,WACtC,CAACnB,EAAOoB,IAAiB,CACvB,KAAM,CAAE,cAAAnB,EAAe,UAAA6D,EAAW,gBAAAC,EAAiB,iBAAAC,EAAkB,GAAGlB,CAAc,EAAG9C,EACnFsB,EAAUxB,EAAiB8C,EAAc3C,CAAa,EACtDQ,EAAaD,SAAa,IAAI,EAC9ByC,EAAezB,EAAgBJ,EAAcX,CAAU,EAC7D,OAAAwD,KACuBC,EAAI,KAACC,WAAU,CAAE,SAAU,CAChCtD,EAAG,IACjBuD,GACA,CACE,QAAS,GACT,KAAM,GACN,QAASN,EACT,iBAAkBC,EAClB,mBAAoBC,EACpB,SAA0BnD,EAAG,IAC3BwD,GACA,CACE,KAAM,SACN,GAAI/C,EAAQ,UACZ,mBAAoBA,EAAQ,cAC5B,kBAAmBA,EAAQ,QAC3B,aAAcI,EAASJ,EAAQ,IAAI,EACnC,GAAGwB,EACH,IAAKG,EACL,UAAW,IAAM3B,EAAQ,aAAa,EAAK,CAC5C,CACF,CACF,CACF,EACe4C,OAAKC,EAAAA,SAAU,CAAE,SAAU,CACzBtD,EAAAA,IAAIyD,GAAc,CAAE,QAAShD,EAAQ,OAAO,CAAE,EAC9CT,EAAG,IAAC0D,GAAoB,CAAE,WAAA9D,EAAY,cAAea,EAAQ,cAAe,CACpG,EAAS,CACJ,CAAA,CAAE,CACJ,CACH,EACIkD,EAAa,cACbC,GAActD,EAAgB,WAChC,CAACnB,EAAOoB,IAAiB,CACvB,KAAM,CAAE,cAAAnB,EAAe,GAAGyE,CAAU,EAAK1E,EACnCsB,EAAUxB,EAAiB0E,EAAYvE,CAAa,EAC1D,OAAuBY,MAAIY,EAAU,GAAI,CAAE,GAAIH,EAAQ,QAAS,GAAGoD,EAAY,IAAKtD,CAAc,CAAA,CACnG,CACH,EACAqD,GAAY,YAAcD,EAC1B,IAAIG,GAAmB,oBACnBC,GAAoBzD,EAAgB,WACtC,CAACnB,EAAOoB,IAAiB,CACvB,KAAM,CAAE,cAAAnB,EAAe,GAAG4E,CAAgB,EAAK7E,EACzCsB,EAAUxB,EAAiB6E,GAAkB1E,CAAa,EAChE,OAAuBY,MAAIY,EAAU,EAAG,CAAE,GAAIH,EAAQ,cAAe,GAAGuD,EAAkB,IAAKzD,CAAc,CAAA,CAC9G,CACH,EACAwD,GAAkB,YAAcD,GAChC,IAAIG,GAAa,cACbC,GAAc5D,EAAgB,WAChC,CAACnB,EAAOoB,IAAiB,CACvB,KAAM,CAAE,cAAAnB,EAAe,GAAG+E,CAAU,EAAKhF,EACnCsB,EAAUxB,EAAiBgF,GAAY7E,CAAa,EAC1D,OAAuBY,EAAG,IACxBY,EAAU,OACV,CACE,KAAM,SACN,GAAGuD,EACH,IAAK5D,EACL,QAASO,EAAqB3B,EAAM,QAAS,IAAMsB,EAAQ,aAAa,EAAK,CAAC,CAC/E,CACP,CACG,CACH,EACAyD,GAAY,YAAcD,GAC1B,SAASpD,EAAShB,EAAM,CACtB,OAAOA,EAAO,OAAS,QACzB,CACA,IAAIuE,GAAqB,qBACrB,CAACC,GAAiBC,EAAiB,EAAIC,GAAcH,GAAoB,CAC3E,YAAarC,EACb,UAAW4B,EACX,SAAU,QACZ,CAAC,EACGF,GAAe,CAAC,CAAE,QAAAe,KAAc,CAClC,MAAMC,EAAsBH,GAAkBF,EAAkB,EAC1DM,EAAU,KAAKD,EAAoB,WAAW,mBAAmBA,EAAoB,SAAS;AAAA;AAAA,4BAE1EA,EAAoB,SAAS;AAAA;AAAA,4EAEmBA,EAAoB,QAAQ,GACtGpC,OAAAA,EAAAA,UAAgB,IAAM,CAChBmC,IACe,SAAS,eAAeA,CAAO,GACjC,QAAQ,MAAME,CAAO,EAE1C,EAAK,CAACA,EAASF,CAAO,CAAC,EACd,IACT,EACIG,GAA2B,2BAC3BjB,GAAqB,CAAC,CAAE,WAAA9D,EAAY,cAAAgF,KAAoB,CAE1D,MAAMF,EAAU,6EADkBJ,GAAkBK,EAAwB,EAC2C,WAAW,KAClItC,OAAAA,EAAAA,UAAgB,IAAM,OACpB,MAAMwC,GAAgBnC,EAAA9C,EAAW,UAAX,YAAA8C,EAAoB,aAAa,oBACnDkC,GAAiBC,IACI,SAAS,eAAeD,CAAa,GACvC,QAAQ,KAAKF,CAAO,EAE5C,EAAE,CAACA,EAAS9E,EAAYgF,CAAa,CAAC,EAChC,IACT,EACIE,GAAO5F,GACP6F,GAAU1E,GACV2E,GAAS9D,GACT+D,GAAUxD,GACVyD,GAAUlD,GACVmD,GAAQvB,GACRwB,GAAcrB,GACdsB,GAAQnB,GCzTZ,MAAMhF,GAASoG,GAETjF,GAAgBkF,GAEhBrE,GAAesE,GAIrB,SAAS/D,GAAc,CACtB,UAAAgE,EACA,IAAAC,EACA,GAAGvG,CACJ,EAAyD,CAEvD,OAAAa,EAAA,IAAC2F,GAAA,CACA,IAAAD,EACA,UAAWE,EACV,+KACAH,CACD,EACC,GAAGtG,CAAA,CAAA,CAGP,CACAsC,GAAc,YAAckE,GAAwB,YAEpD,SAAS3D,GAAc,CACtB,UAAAyD,EACA,SAAApG,EACA,IAAAqG,EACA,GAAGvG,CACJ,EAAyD,CACxD,cACE+B,GACA,CAAA,SAAA,CAAAlB,EAAA,IAACyB,GAAc,EAAA,EACf4B,EAAA,KAACwC,GAAA,CACA,IAAAH,EACA,UAAWE,EACV,wgBACAH,CACD,EACC,GAAGtG,EAEH,SAAA,CAAAE,EACAgE,EAAAA,KAAAyC,GAAA,CAAsB,UAAU,gRAChC,SAAA,CAAC9F,EAAAA,IAAA+F,EAAA,CAAK,KAAK,OAAQ,CAAA,EAClB/F,EAAA,IAAA,OAAA,CAAK,UAAU,UAAU,SAAK,QAAA,CAAA,EAChC,CAAA,CAAA,CACD,CACD,CAAA,CAAA,CAEF,CACAgC,GAAc,YAAc6D,GAAwB,YAEpD,SAASG,GAAa,CACrB,UAAAP,EACA,GAAGtG,CACJ,EAAyC,CAEvC,OAAAa,EAAA,IAAC,MAAA,CACA,UAAW4F,EACV,qDACAH,CACD,EACC,GAAGtG,CAAA,CAAA,CAGP,CACA6G,GAAa,YAAc,eAkCDC,GAAsB,YAEhD,SAASlC,GAAkB,CAC1B,UAAA0B,EACA,IAAAC,EACA,GAAGvG,CACJ,EAA6D,CAE3D,OAAAa,EAAA,IAACkG,GAAA,CACA,IAAAR,EACA,UAAWE,EAAG,gCAAiCH,CAAS,EACvD,GAAGtG,CAAA,CAAA,CAGP,CACA4E,GAAkB,YAAcmC,GAA4B,YCF5D,MAAMC,GAAY,CAAC,aAAc,aAAc,aAAc,aAAa,EACpEC,GAAU,CACf,qCACA,qCACA,qCACA,qCAAA,EAED,SAASC,GAAmBC,EAAe,CAC1C,MAAMC,EAAgBC,KAAKC,MAAMH,EAAQH,GAAUO,OAAS,CAAC,EACvDC,EAAeH,KAAKC,MAAMH,EAAQF,GAAQM,OAAS,CAAC,EACnD,OAAAd,EACN,+EACAO,GAAUI,CAAa,GAAK,aAC5BH,GAAQO,CAAY,GAAK,cACzBL,IAAU,EAAI,sDAAwD,IACvE,CACD,CAEA,SAASM,GAAS,CAAEC,aAAAA,CAAa,EAA8B,CAC9D,MAAMC,EAAeC,IACf,CAAEC,MAAAA,CAAM,EAAIC,EAAY,EACxB,CACLC,QAAS,CAAEC,iBAAAA,CAAiB,GACzBC,GAAkB,EAChBC,EAAQR,EAAe,GAAK,EAC5BS,EAAkBN,EAAMN,OAASW,EACjCE,EAA4BD,GAAmBT,EAAe,EAAI,GAEpE,GAAA,CAACG,EAAMN,OAAe,OAAA,KAE1B,MAAMc,EACLX,GAAgBG,EAAMN,SAAW,EAChC1G,EAAA,IAACyH,EAAA,CACAzE,OAAO,SACP0E,IAAI,sBACJC,GAAG,8CAEHtI,SAAAW,EAAA,IAAC,MAAA,CACA4H,IAAI,gBACJnC,UAAWG,EACV,2CACAS,GAAmB,CAAC,CACrB,EACAwB,IAAI,mBACL,CACD,CAAA,EACG,KACCC,EAAiB,GAAGR,CAAe,GACxCT,EAAe,SAAW,GAC3B,GAAGM,CAAgB,OAAOG,IAAoB,EAAI,GAAK,GAAG,eAC1D,OACEtH,EAAAA,IAAA,MAAA,CAAIyF,UAAU,oCACdpG,gBAAC0I,GACE,CAAA1I,SAAA,EAAAkI,EAA4BP,EAAMgB,MAAM,EAAGX,CAAK,EAAIL,GAAOiB,IAC5D,CAAC,CAAEC,KAAAA,EAAM5B,MAAAA,CAAM,IAAM,SACd,MAAA6B,EAAkB9B,GAAmBC,CAAK,EAC1C8B,EAAgBC,GAAiBH,EAAKI,QAAQ,EACpD,cACEC,EACA,CAAAlJ,SAAA,CAAAW,EAAA,IAACwI,EAAe,CAAAC,QAAO,GACrBpJ,SAAA6I,EAAKQ,UACL1I,EAAAA,IAAC,MAAA,CACA2I,SAAU,EACVf,IAAKM,EAAKU,MAAQzB,EAClB1B,UAAWG,EACV,2CACAuC,CACD,EACAN,IAAKK,EAAKQ,SAAA,CACX,EAEA1I,EAAA,IAAC,MAAA,CACA2I,SAAU,EACV,aAAYT,EAAKU,MAAQ,GAAGzB,CAAgB,OAC5C1B,UAAWG,EACV,+DACAuC,CACD,EAEA9I,SAAAW,EAAA,IAAC+F,EAAK,CAAA6C,KAAK,OAAO,EACnB,CAEF,CAAA,EACC5I,EAAA,IAAA6I,EAAA,CACAxJ,SAACgE,EAAA,KAAA,OAAA,CAAKoC,UAAU,kDACfpG,SAAA,CAAAgE,EAAA,KAAC,OACC,CAAAhE,SAAA,CAAK6I,EAAAU,MAAQ,GAAGzB,CAAgB,OAAQ,IACxCiB,EACE,QAAOF,GAAAA,EAAAA,EAAKI,WAALJ,YAAAA,EAAeY,SAAfZ,MAAAA,EAAuBa,SAAS,aAAe,UAAY,UAAU,IAC5EzC,IAAU,IAAKQ,GAAAA,YAAAA,EAAckC,MAAOd,EAAKc,GACtC,WACA,EACJ,MACC,IAAA,CACJ,CAAA,EACCZ,GAAAA,MAAAA,EAAea,MACfjJ,EAAAA,IAAC,OAAM,CAAAX,SAAA+I,EAAca,KAAM,CAAA,EACxB,KACHb,GAAAA,MAAAA,EAAec,MACflJ,EAAAA,IAAC,OAAM,CAAAX,SAAA+I,EAAcc,KAAM,CAAA,EACxB,IAAA,EACL,CACD,CAAA,CAAA,CAAA,EA5CahB,EAAKc,EA6CnB,CAGH,CAAA,EACCxB,EACAD,SACCgB,EACA,CAAAlJ,SAAA,CAACW,EAAA,IAAAwI,EAAA,CAAeC,QAAO,GACtBpJ,SAAAW,EAAA,IAAC,MAAA,CACA2I,SAAU,EACV,aAAYb,EACZrC,UAAWG,EACV,gGACAiB,EAAe,UAAY,SAC5B,EAEAxH,SAAAW,EAAA,IAAC,OAAA,CACAyF,UAAWG,EACV,kFACAiB,EAAe,MAAQ,KACxB,EAECxH,SAAAwH,EAAe,IAAIS,CAAe,GAAKA,EACzC,EACD,CACD,CAAA,EACAtH,EAAA,IAAC6I,GAAgBxJ,SAAeyI,CAAA,CAAA,CAAA,CACjC,CAAA,EACG,IAAA,EACL,CACD,CAAA,CAEF,CAEA,MAAMqB,GAAY/K,GAAoB,qBAAsB,EAAI,EAEhE,SAAwBgL,IAAM,CAC7B,MAAMlB,EAAOnB,IACPsC,EAASF,KACTG,EAAaC,KAEb,CAAC1C,EAAc2C,CAAa,EAAIC,WAAe,EAAK,EAC1DC,OAAAA,GAAkB,CAAEC,WAAY,CAAC,wBAAwB,CAAE,CAAC,EAG3DtG,EAAAA,KAAC,MAAI,CAAAoC,UAAU,gBACbpG,SAAA,CAAO6I,EAAA,WAAQ0B,GAAa,EAAA,EAS5BN,GAAcD,EAAS,KACvBrJ,EAAAA,IAAC6J,GAAA,CACAhD,aAAAA,EACAiD,iBAAkBN,CAAA,CACnB,EAEDnG,EAAA,KAAC,MAAA,CAGAoC,UAAWG,EAAG,sCAAuC,CACpD,0JACC,CAACsC,EACF,oJACCA,EACD,YAAa,CAACmB,GAAUxC,CACzB,CAAC,EAEAxH,SAAA,CACAgK,EAAArJ,EAAA,IAAC+J,GAAA,CACAlD,aAAAA,EACAiD,iBAAkBN,EACnB,EACG,KACJxJ,EAAA,IAAC,MAAA,CACAyF,UAAWG,EACV,sDACAiB,EAAe,kBAAoB,EACpC,EAEAxH,eAAC2K,GAAO,EAAA,CAAA,CACT,CAAA,CAAA,CACD,CAAA,CACD,CAAA,CAEF,CAEA,SAAS3B,GAAiBC,EAA4B,CACjD,GAAA,CAACA,EAAiB,OAAA,KAEhB,KAAA,CAAE2B,SAAAA,CAAa,EAAA3B,EAEf4B,EAAkB,CACvBD,EACG,CAACA,EAASE,eAAgBF,EAASG,UAAU,EAC5CC,OAAOC,OAAO,EACdrC,IAAKsC,GAAMA,EAAEC,SAAS,EAAEC,SAAS,EAAG,GAAG,CAAC,EACxCC,KAAK,GAAG,EACT,KACHT,GAAAA,YAAAA,EAAUU,IAAA,EAETN,OAAOC,OAAO,EACdI,KAAK,KAAK,EACZ,MAAO,CAAEzB,MAAOX,EAASsC,cAAe1B,MAAOgB,EAChD,CAEA,SAASN,IAAe,CACvB,MAAMP,EAASF,KACT,CACLjC,QAAS,CAAE2D,KAAAA,EAAMC,YAAAA,CAAY,GAC1B1D,GAAkB,EAChB2D,EACJ/K,EAAA,IAAA,MAAA,CACCX,SAAI2L,IAAAC,yBACH,MACC,CAAA5L,SAAA,CAAA,iCAEAgE,EAAAA,KAAAC,EAAAA,SAAA,CAAAjE,SAAA,CAAAW,EAAA,IAACyH,EAAA,CACAhC,UAAU,YACVzC,OAAO,SACP0E,IAAI,sBACJC,GAAIqD,IAAIE,qBACR7L,SAAA,cAED,EACC,uBAAA,CACF,CAAA,EAAI,GAAA,CACL,CAAA,SAEC,MACA,CAAAA,SAAA,CAAAW,EAAA,IAACyH,EAAK,CAAAE,GAAG,SAASlC,UAAU,YAAYpG,SAExC,OAAA,CAAA,EAAQ,IAAI,KACT,IACHW,EAAAA,IAAC,KAAEmL,KAAM,WAAWN,CAAI,SAAUpF,UAAU,YAAYpG,SAExD,eAAA,CAAA,EAAK,IAAI,0BAAA,EAEV,CAEF,CAAA,EAED,OACEW,EAAAA,IAAA,MAAA,CAAIyF,UAAU,qHACbpG,WAECgE,EAAA,KAAAC,WAAA,CAAAjE,SAAA,CAACgE,EAAA,KAAA,MAAA,CAAIoC,UAAU,qDACdpG,SAAA,CAAAW,EAAA,IAACoL,EAAK,CAAAC,KAAK,KAAKC,MAAM,YAAa,CAAA,EACnCjI,EAAA,KAAC,MAAI,CAAAoC,UAAU,qCACdpG,SAAA,CAACgE,EAAA,KAAA,IAAA,CAAEoC,UAAU,OAAOpG,SAAA,CAAA,iBACJ,IACfW,EAAAA,IAACyH,EAAA,CACAE,GAAI,WAAWkD,CAAI,GACnBpF,UAAU,YACVzC,OAAO,SAEN3D,SAAAyL,CAAA,CACF,EAAQ,IAAI,eAAA,CAEb,CAAA,EACCC,CAAA,CACF,CAAA,CAAA,CACD,CAAA,EACA1H,EAAA,KAAC,MAAI,CAAAoC,UAAU,0DACdpG,SAAA,CAAAgE,EAAA,KAACoE,EAAA,CACAE,GAAI,WAAWkD,CAAI,GACnB7H,OAAO,SACPyC,UAAU,iFAEVpG,SAAA,CAACgE,EAAA,KAAA,OAAA,CAAKoC,UAAU,iBAAiBpG,SAAA,CAAA,QAAMyL,CAAA,CAAY,CAAA,EACnD9K,EAAA,IAAC,QAAKX,SAAE,IAAA,CAAA,CAAA,CAAA,CACT,EACAgE,EAAA,KAACoE,EAAA,CACAE,GAAIqD,IAAIC,kBAAoB,WAAWJ,CAAI,SAAW,SACtDpF,UAAU,oIAEVpG,SAAA,CAAAW,EAAA,IAAC+F,EAAK,CAAA6C,KAAK,OAAOyC,KAAK,IAAK,CAAA,EAC3BrL,EAAA,IAAA,OAAA,CAAKyF,UAAU,iBAAiBpG,SAAK,OAAA,CAAA,CAAA,CAAA,CACvC,CAAA,CACD,CAAA,CAAA,CAAA,CACD,EAGCgE,EAAA,KAAAC,WAAA,CAAAjE,SAAA,CAACgE,EAAA,KAAA,MAAA,CAAIoC,UAAU,qDACdpG,SAAA,CAACW,EAAA,IAAA,IAAA,CAAEmL,KAAM,WAAWN,CAAI,GACvBxL,SAACW,EAAA,IAAAoL,EAAA,CAAKC,KAAK,KAAKC,MAAM,aAAa,CACpC,CAAA,SACCpM,GACA,CAAAG,SAAA,CAACW,EAAA,IAAAK,GAAA,CACAhB,eAAC0G,EAAK,CAAA6C,KAAK,WAAWyC,KAAK,KAAK5F,UAAU,gBAAgB,CAC3D,CAAA,SACCzD,GACA,CAAA3C,SAAA,CAAAgE,EAAA,KAAC2C,GACA,CAAA3G,SAAA,CAAAW,EAAA,IAACoL,EAAK,CAAAC,KAAK,KAAKC,MAAM,YAAa,CAAA,EAClCtL,EAAA,IAAA,OAAA,CAAKyF,UAAU,wBAAyBpG,SAAYyL,CAAA,CAAA,CAAA,CACtD,CAAA,SACC/G,GAAkB,CAAA1E,SAAA,CAAA,iBACH,IACfW,EAAAA,IAACyH,GAAKE,GAAI,WAAWkD,CAAI,GAAIpF,UAAU,YACrCpG,SACFyL,CAAA,CAAA,EAAQ,IAAI,eAAA,CAEb,CAAA,EACCC,CAAA,CACF,CAAA,CAAA,CACD,CAAA,CAAA,CACD,CAAA,EACA1H,EAAA,KAAC,MAAI,CAAAoC,UAAU,2BACdpG,SAAA,CAAAgE,EAAA,KAACoE,EAAA,CACAE,GAAI,WAAWkD,CAAI,GACnB7H,OAAO,SACPyC,UAAU,iFAEVpG,SAAA,CAACW,EAAA,IAAA,OAAA,CAAKyF,UAAU,iBAAiBpG,SAAI,MAAA,CAAA,EACrCW,EAAA,IAAC,QAAKX,SAAE,IAAA,CAAA,CAAA,CAAA,CACT,EACAgE,EAAA,KAACoE,EAAA,CACAE,GAAIqD,IAAIC,kBAAoB,WAAWJ,CAAI,SAAW,SACtDpF,UAAU,oIAEVpG,SAAA,CAAAW,EAAA,IAAC+F,EAAK,CAAA6C,KAAK,OAAOyC,KAAK,IAAK,CAAA,EAC3BrL,EAAA,IAAA,OAAA,CAAKyF,UAAU,iBAAiBpG,SAAK,OAAA,CAAA,CAAA,CAAA,CACvC,CAAA,CACD,CAAA,CAAA,EACD,CAEF,CAAA,CAEF,CAEA,MAAMkM,GAAe,CACpBC,OAAQ,CAAEC,QAAS,EAAGC,EAAG,GAAI,EAC7BC,QAAS,CAAEF,QAAS,EAAGC,EAAG,CAAE,CAC7B,EACA,SAASE,GAA2B,CACnCzB,eAAAA,EACA9K,SAAAA,CACD,EAGG,CACI,MAAAwM,EAAoBC,GAA6B3B,CAAc,EAEpE,OAAAnK,EAAA,IAAC+L,EAAOC,GAAP,CACAC,SAAUV,GAEV9F,UAAWG,EAEV,gCACAiG,EAAoB,GAAGA,CAAiB,mBAAqB,IAC9D,EAEAxM,SAACW,EAAA,IAAA,OAAA,CAAKyF,UAAU,OAAQpG,SAAAA,EAAS,CAAA,CAClC,CAEF,CAEA,SAAS6M,EAA+B,CACvC7M,SAAAA,EACA,GAAG8M,CACJ,EAEwB,CACjB,MAAAN,EAAoBO,GAAyBD,CAAkB,EAEpE,OAAAnM,EAAA,IAAC+L,EAAOC,GAAP,CACAC,SAAUV,GAEV9F,UAAWG,EAEV,gCACAiG,EAAoB,GAAGA,CAAiB,mBAAqB,IAC9D,EAEAxM,SAACW,EAAA,IAAA,OAAA,CAAKyF,UAAU,OAAQpG,SAAAA,EAAS,CAAA,CAClC,CAEF,CAEA,SAASwK,GAAiB,CACzBhD,aAAAA,EACAiD,iBAAkBN,CACnB,EAGG,CACF,MAAM6C,EAAOC,KACPpE,EAAOnB,IACPwF,EAAoBC,KACpBC,EAASC,KACT,CAAE1F,MAAAA,CAAM,EAAIC,EAAY,EAGxB0F,EAAe,CACpBhB,QAAS,CACRF,QAAS,EACTmB,WAAY,CACXC,SAAU,IACVC,KAAM,iBACNC,gBAAiB,GAClB,CACD,EACAvB,OAAQ,CACPC,QAAS,CACV,GAGD,aACE,MAAI,CAAAhG,UAAU,iCACdpG,SAACW,EAAA,IAAA,MAAA,CAAIyF,UAAU,SACdpG,SAAAgE,EAAA,KAAC,MAAA,CACAoC,UAAWG,EAAG,oBAAqB,CAClC,WAAYiB,EACZ,OAAQ,CAACA,CACV,CAAC,EAEDxH,SAAA,CAAAW,EAAA,IAACgN,GAAA,CACAC,MAAOZ,EAAKzB,cACZ/D,aAAAA,EACA2C,cAAAA,CACD,CAAA,EACC3C,GACAxD,OAAC0I,EAAOmB,IAAP,CAEAzH,UAAU,8GACV0H,QAAS,CAAE1B,QAAS,CAAE,EACtB2B,QAAS,CAAE3B,QAAS,CAAE,EAEtBpM,SAAA,CAAAgE,EAAAA,KAAC0I,EAAOsB,GAAP,CACApB,SAAUU,EACVQ,QAAQ,SACRC,QAAQ,UAER3H,UAAU,gBAEVpG,SAAA,CAAAW,EAAA,IAAC,OACA,CAAAX,SAAAW,EAAA,IAACsN,EAAA,CACAC,SAAS,SACT5F,GAAG,IACHlC,UAAWA,CAAC,CAAE+H,SAAAA,CAAS,IACtBC,EACC,8GACA,8KACA,CAAE,gCAAiCD,CAAS,CAC7C,EAEDnO,SAAA,OAED,CACD,CAAA,EACCgN,EAAKqB,UAAUzF,IAAI,CAAC,CAAEkC,eAAAA,EAAgB8C,MAAAA,EAAOU,MAAAA,CAAM,IAAM,CACzD,MAAMH,EACLI,OAAOnB,EAAOtC,cAAc,IAAMA,EAC7B0D,EACL,CAACL,GACDnB,EAAKyB,WAAW3D,iBAAmBA,EAC9B4D,EAAc5D,EAAeK,SAAA,EAAWC,SAAS,EAAG,GAAG,EAE5D,OAAApH,EAAAA,KAACuI,GAAA,CAEAzB,eAAAA,EAEA9K,SAAA,CAAAgE,EAAA,KAACoE,EAAA,CACA8F,SAAS,SACT5F,GAAI,IAAIoG,CAAW,GACnBtI,UAAWgI,EACV,8GACA,8KACA,CAAE,gCAAiCD,CAAS,CAC7C,EAECnO,SAAA,CAAA4N,EACAY,EAAiB,MAAQ,IAAA,CAC3B,CAAA,EACCL,EACAnK,OAAC0I,EAAOsB,GAAP,CACApB,SAAUU,EACVQ,QAAQ,SACRC,QAAQ,UAER3H,UAAU,0BAEVpG,SAAA,CAAAW,EAAA,IAACkM,EAAA,CAEAvB,KAAK,eACLR,eAAAA,EAEA9K,SAAAW,EAAA,IAACyH,EAAA,CACAE,GAAI,IAAIoG,CAAW,GACnBR,SAAS,SACT9H,UAAWgI,EACV,2PACA,CACC,gCACC,CAAChB,EAAOrC,UACV,CACD,EACA/K,SAAA,QAED,CAAA,EAhBK8K,CAiBN,EACCwD,EACCtD,OAAOC,OAAO,EACdrC,IAAI,CAAC,CAAEW,KAAAA,EAAMwB,WAAAA,EAAY6C,MAAAA,CAAM,IAAM,CACrC,MAAMO,EACLI,OAAOnB,EAAOrC,UAAU,IAAMA,EACzB4D,EAAO5D,EACXI,SAAA,EACAC,SAAS,EAAG,GAAG,EACXwD,EACLrF,IAASyD,EAAKyB,WAAWI,QAEzB,OAAAlO,EAAAA,IAACkM,EAAA,CAEAvB,KAAK,OACLP,WAAAA,EACAD,eAAAA,EAEA9K,SAAAW,EAAA,IAACyH,EAAA,CACAE,GAAI,IAAIoG,CAAW,IAAIC,CAAI,GAC3BT,SAAS,SACT9H,UAAWgI,EACV,2PACA,CACC,gCACCD,CACF,CACD,EAECnO,SAAA4O,EACE,GAAGD,CAAI,KAAKf,CAAK,MACjB,GAAGe,CAAI,KAAKf,CAAK,GACrB,CAAA,EAnBK7C,CAoBN,CAEF,CAAC,EACFpK,EAAA,IAACkM,EAAA,CACAvB,KAAK,WACLR,eAAAA,EAEA9K,SAAAW,EAAA,IAACsN,EAAA,CACA3F,GAAI,IAAIoG,CAAW,YACnBR,SAAS,SACT9H,UAAWA,CAAC,CAAE+H,SAAAA,CAAS,IACtBC,EACC,6PACA,CACC,gCAAiCD,CAClC,CACD,EAEDnO,SAAA,iBAED,CAAA,CACD,CAAA,CACD,CAAA,EACG,IAAA,CAAA,EAjGC8K,CAkGN,CAEF,CAAC,CAAA,CAAA,CACF,EACAnK,EAAA,IAAC,MAAI,CAAAyF,UAAU,OACdpG,SAAAW,EAAA,IAACsN,EAAA,CACA3F,GAAG,YACHlC,UAAWA,CAAC,CAAE+H,SAAAA,CAAS,IACtBC,EACC,4FACA,CACC,kKACCD,CACF,CACD,EAEDnO,SAAA,uBAED,CACD,CAAA,CAAA,CAAA,CACD,EAEDW,EAAA,IAAC,MAAI,CAAAyF,UAAU,WAAY,CAAA,EAC3BzF,EAAA,IAAC,MAAA,CACAyF,UAAWG,EACV,sCACAiB,GAAgBG,EAAMN,OAAS,EAAI,WAAa,OAChD,CACC,kBAAmBG,CAEpB,CACD,EAEAxH,SAAAW,EAAA,IAAC4G,IAASC,aAAAA,EAA4B,CAAA,CACvC,EACCmE,IAAIC,kBAAoB,KAAO/C,QAC9BiG,EAAc,CAAA7L,QAASuE,EAAe,KAAO,eAC7CxH,SAAAgE,EAAA,KAACoE,EAAA,CACAhC,UAAWG,EACV,kHACA,CACC,WAAY,CAACiB,EACb,kBAAmBA,CACpB,CACD,EACAc,GAAG,WAEFtI,SAAA,CAAA6I,EAAKQ,UACL1I,EAAAA,IAAC,MAAA,CACA4H,IAAKM,EAAKU,MAAQV,EAAKkG,MACvBvG,IAAKK,EAAKQ,UACVjD,UAAU,qBAAA,CACX,QAECM,EAAK,CAAA6C,KAAK,OAAOnD,UAAU,gBAAgB4F,KAAK,IAAK,CAAA,EAEtDxE,EACA7G,MAAC+L,EAAOmB,IAAP,CAEAzH,UAAU,sCACV0H,QAAS,CAAE1B,QAAS,CAAE,EACtB2B,QAAS,CAAE3B,QAAS,CAAE,EACtBpM,SAAA,cAAA,CAED,EAEAW,EAAA,IAAC,OAAK,CAAAyF,UAAU,UAAUpG,SAAY,cAAA,CAAA,CAAA,EAExC,EACD,EACG,KACH2L,IAAIC,kBAAoB,KAAO/C,GAAQqE,EACvCvM,EAAA,IAACmO,EAAA,CACA7L,QAASuE,EAAe,KAAO,0BAE/BxH,SAAAgE,EAAA,KAACoE,EAAA,CACAE,GAAI4E,EACJgB,SAAS,SACT9H,UAAWgI,EACV,mGACD,EACAY,MAAO,CAAEC,KAAM,6BAA8B,EAE7CjP,SAAA,CAAAW,EAAA,IAAC+F,GAAK6C,KAAK,cAAcnD,UAAU,gBAAgB4F,KAAK,IAAK,CAAA,EAC5DxE,EACA7G,MAAC+L,EAAOmB,IAAP,CAEAzH,UAAU,sCACV0H,QAAS,CAAE1B,QAAS,CAAE,EACtB2B,QAAS,CAAE3B,QAAS,CAAE,EACtBpM,SAAA,yBAAA,CAED,EAEAW,EAAA,IAAC,OAAK,CAAAyF,UAAU,UAAUpG,SAAuB,yBAAA,CAAA,CAAA,EAEnD,EACD,EACG,KACJW,EAAA,IAAC,MAAA,CACAyF,UAAWG,EACV,8EACA,CACC,kBAAmBiB,EACnB,WAAY,CAACA,CACd,CACD,EAEAxH,eAACkP,GAAY,EAAA,CAAA,CACd,CAAA,EACD,EACD,CACD,CAAA,CAEF,CAEA,MAAMC,EAAoB,IAE1B,SAASzE,GAAW,CACnBlD,aAAAA,EACAiD,iBAAkBN,CACnB,EAGG,CACF,MAAM6C,EAAOC,KACPpE,EAAOnB,IACPwF,EAAoBC,KACpBC,EAASC,KACT,CAAE1F,MAAAA,CAAM,EAAIC,EAAY,EAExBgD,EAAWoC,EAAKqB,UAAUe,KAC9BC,GAAMA,EAAEvE,iBAAmByD,OAAOnB,EAAOtC,cAAc,CACzD,EACMwE,EACLlC,EAAO9B,OAAS,WACbV,GAAAA,YAAAA,EAAU2E,UAAUH,KACnBlE,GAAMA,EAAEH,aAAewD,OAAOnB,EAAOrC,UAAU,GAEhDqC,EAAO9B,OAAS,UACfV,GAAAA,YAAAA,EAAU4E,SAASJ,KAClBK,GAAMA,EAAE1E,aAAewD,OAAOnB,EAAOrC,UAAU,GAEhD,KAGC2E,EAAe9Q,IACf+Q,EAAe,CACpBC,MAAO,CAAEC,MAAO,EAAG,EACnBrP,KAAM,CAAEqP,MAAOV,CAAkB,GAI5B7B,EAAe,CACpBhB,QAAS,CACRF,QAAS,EACTmB,WAAY,CACXC,SAAU,IACVC,KAAM,iBACNC,gBAAiB,GAClB,CACD,EACAvB,OAAQ,CACPC,QAAS,CACV,GAEK0D,EAAQvB,OAAOnB,EAAOtC,cAAc,EAAEK,SAAS,EAAEC,SAAS,EAAG,GAAG,EAGrE,OAAAzK,EAAAA,IAAC,MAAI,CAAAyF,UAAU,0BACdpG,SAAAW,EAAAA,IAAC+L,EAAOmB,IAAP,CACAC,QAAStG,EAAe,OAAS,QACjCoF,SAAU+C,EACV5B,QAAS2B,EAET1P,SAAAgE,EAAA,KAAC,MAAI,CAAAoC,UAAU,oDACdpG,SAAA,CAAAW,EAAA,IAACgN,GAAA,CACAC,MAAOZ,EAAKzB,cACZmE,aAAAA,EACAlI,aAAAA,EACA2C,cAAAA,CACD,CAAA,EACC3C,GACAxD,OAAC0I,EAAOmB,IAAP,CACA5B,MAAO,CAAE4D,MAAOV,CAAkB,EAElC/I,UAAU,uGACV0H,QAAS,CAAE1B,QAAS,CAAE,EACtB2B,QAAS,CAAE3B,QAAS,CAAE,EAEtBpM,SAAA,CAAAgE,EAAAA,KAAC0I,EAAOsB,GAAP,CACApB,SAAUU,EACVQ,QAAQ,SACRC,QAAQ,UAER3H,UAAU,gBAEVpG,SAAA,CAAAW,EAAA,IAAC,OACA,CAAAX,SAAAW,EAAA,IAACsN,EAAA,CACAC,SAAS,SACT5F,GAAG,IACHlC,UAAWA,CAAC,CAAE+H,SAAAA,CAAS,IACtBC,EACC,8GACA,8KACA,CAAE,gCAAiCD,CAAS,CAC7C,EAEDnO,SAAA,OAED,CACD,CAAA,EACCgN,EAAKqB,UAAUzF,IAAI,CAAC,CAAEkC,eAAAA,EAAgB8C,MAAAA,EAAOU,MAAAA,CAAM,IAAM,CACzD,MAAMH,EACLI,OAAOnB,EAAOtC,cAAc,IAAMA,EAC7B0D,EACL,CAACL,GACDnB,EAAKyB,WAAW3D,iBAAmBA,EAC9B4D,EAAc5D,EAAeK,SAAA,EAAWC,SAAS,EAAG,GAAG,EAE5D,OAAApH,EAAAA,KAACuI,GAAA,CAEAzB,eAAAA,EAEA9K,SAAA,CAAAgE,EAAA,KAACoE,EAAA,CACA8F,SAAS,SACT5F,GAAI,IAAIoG,CAAW,GACnBtI,UAAWgI,EACV,8GACA,8KACA,CAAE,gCAAiCD,CAAS,CAC7C,EAECnO,SAAA,CAAA4N,EACAY,EAAiB,MAAQ,IAAA,CAC3B,CAAA,EACCL,EACAnK,OAAC0I,EAAOsB,GAAP,CACApB,SAAUU,EACVQ,QAAQ,SACRC,QAAQ,UAER3H,UAAU,0BAEVpG,SAAA,CAAAW,EAAA,IAACkM,EAAA,CAEAvB,KAAK,eACLR,eAAAA,EAEA9K,SAAAW,EAAA,IAACyH,EAAA,CACAE,GAAI,IAAIoG,CAAW,GACnBR,SAAS,SACT9H,UAAWgI,EACV,2PACA,CACC,gCACC,CAAChB,EAAOrC,UACV,CACD,EACA/K,SAAA,QAED,CAAA,EAhBK8K,CAiBN,EACCwD,EACCtD,OAAOC,OAAO,EACdrC,IAAI,CAAC,CAAEW,KAAAA,EAAMwB,WAAAA,EAAY6C,MAAAA,CAAM,IAAM,CACrC,MAAMO,GACLI,OAAOnB,EAAOrC,UAAU,IAAMA,EACzB4D,EAAO5D,EACXI,SAAA,EACAC,SAAS,EAAG,GAAG,EACXwD,GACLrF,IAASyD,EAAKyB,WAAWI,QAEzB,OAAAlO,EAAAA,IAACkM,EAAA,CAEAvB,KAAK,OACLP,WAAAA,EACAD,eAAAA,EAEA9K,SAAAW,EAAA,IAACyH,EAAA,CACAE,GAAI,IAAIoG,CAAW,IAAIC,CAAI,GAC3BT,SAAS,SACT9H,UAAWgI,EACV,2PACA,CACC,gCACCD,EACF,CACD,EAECnO,SAAA4O,GACE,GAAGD,CAAI,KAAKf,CAAK,MACjB,GAAGe,CAAI,KAAKf,CAAK,GACrB,CAAA,EAnBK7C,CAoBN,CAEF,CAAC,EACFpK,EAAA,IAACkM,EAAA,CACAvB,KAAK,WACLR,eAAAA,EAEA9K,SAAAW,EAAA,IAACsN,EAAA,CACA3F,GAAI,IAAIoG,CAAW,YACnBR,SAAS,SACT9H,UAAWA,CAAC,CAAE+H,SAAAA,CAAS,IACtBC,EACC,6PACA,CACC,gCAAiCD,CAClC,CACD,EAEDnO,SAAA,iBAED,CAAA,CACD,CAAA,CACD,CAAA,EACG,IAAA,CAAA,EAjGC8K,CAkGN,CAEF,CAAC,CAAA,CAAA,CACF,EACAnK,EAAA,IAAC,MAAI,CAAAyF,UAAU,OACdpG,SAAAW,EAAA,IAACsN,EAAA,CACA3F,GAAG,YACHlC,UAAWA,CAAC,CAAE+H,SAAAA,CAAS,IACtBC,EACC,4FACA,CACC,kKACCD,CACF,CACD,EAEDnO,SAAA,uBAED,CACD,CAAA,CAAA,CACD,CAAA,EAEA,CAACwH,GACA7G,EAAA,IAAA,MAAA,CAAIyF,UAAU,yCACdpG,SAAAgE,EAAA,KAAC,MAAI,CAAAoC,UAAU,mFACbpG,SAAA,CAAU4K,GAAAA,MAAAA,EAAAgD,YACTxF,EAAK,CAAAE,GAAI,IAAIwH,CAAK,GAAK9P,SAAS4K,EAAAgD,KAAM,CAAA,EACpC,KACHhD,GAAAA,MAAAA,EAAUgD,QAAS0B,GAAAA,MAAAA,EAAK1B,OAAQ,MAAQ,KACxC0B,GAAAA,MAAAA,EAAK1B,MACLjN,EAAAA,IAACyH,EAAA,CACAE,GAAI,IAAIwH,CAAK,IAAIR,EAAIvE,WACnBI,SACA,EAAAC,SAAS,EAAG,GAAG,CAAC,GAEjBpL,SAAIsP,EAAA1B,KACN,CAAA,EACG,IAAA,EACL,CACD,CAAA,EAEDjN,EAAA,IAAC,MAAA,CACAyF,UAAWG,EACV,0EACAiB,GAAgBG,EAAMN,OAAS,EAAI,OAAS,MAC7C,EACA4E,MAAOzE,EAAe,CAAEqI,MAAOV,GAAsB,CAAC,EAEtDnP,SAAAW,EAAA,IAAC4G,IAASC,aAAAA,EAA4B,CAAA,CACvC,EACCmE,IAAIC,kBAAoB,KAAO/C,QAC9BiG,EAAc,CAAA7L,QAASuE,EAAe,KAAO,eAC7CxH,SAAAgE,EAAA,KAACoE,EAAA,CACAhC,UAAU,kIACVkC,GAAG,WAEFtI,SAAA,CAAA6I,EAAKQ,UACL1I,EAAAA,IAAC,MAAA,CACA4H,IAAKM,EAAKU,MAAQV,EAAKkG,MACvBvG,IAAKK,EAAKQ,UACVjD,UAAU,qBAAA,CACX,QAECM,EAAK,CAAA6C,KAAK,OAAOnD,UAAU,gBAAgB4F,KAAK,IAAK,CAAA,EAEtDxE,EACA7G,MAAC+L,EAAOmB,IAAP,CAEAzH,UAAU,sCACV0H,QAAS,CAAE1B,QAAS,CAAE,EACtB2B,QAAS,CAAE3B,QAAS,CAAE,EACtBpM,SAAA,cAAA,CAED,EAEAW,EAAA,IAAC,OAAK,CAAAyF,UAAU,UAAUpG,SAAY,cAAA,CAAA,CAAA,EAExC,EACD,EACG,KACH2L,IAAIC,kBAAoB,KAAO/C,GAAQqE,EACvCvM,EAAA,IAACmO,EAAA,CACA7L,QAASuE,EAAe,KAAO,0BAE/BxH,SAAAgE,EAAA,KAACoE,EAAA,CACAE,GAAI4E,EACJgB,SAAS,SACT9H,UAAWgI,EACV,mGACD,EACAY,MAAO,CAAEC,KAAM,6BAA8B,EAE7CjP,SAAA,CAAAW,EAAA,IAAC+F,GAAK6C,KAAK,cAAcnD,UAAU,gBAAgB4F,KAAK,IAAK,CAAA,EAC5DxE,EACA7G,MAAC+L,EAAOmB,IAAP,CAEAzH,UAAU,sCACV0H,QAAS,CAAE1B,QAAS,CAAE,EACtB2B,QAAS,CAAE3B,QAAS,CAAE,EACtBpM,SAAA,yBAAA,CAED,EAEAW,EAAA,IAAC,OAAK,CAAAyF,UAAU,UAAUpG,SAAuB,yBAAA,CAAA,CAAA,EAEnD,EACD,EACG,WACH,MAAI,CAAAoG,UAAU,iDACdpG,SAAAW,EAAAA,IAACuO,KAAY,CACd,CAAA,CAAA,EACD,EACD,CACD,CAAA,CAEF,CAEA,SAASvB,GAAU,CAClBC,MAAAA,EACApG,aAAAA,EACA2C,cAAAA,EACAuF,aAAAA,CACD,EAKG,CACI,MAAAK,EAAgB3F,SAAgC,IAAI,EACpD4F,EAAiB,CACtBxP,KAAM,CAAEyP,EAAG,6BAA8B,EACzCC,OAAQ,CAAED,EAAG,eAAgB,GAExBE,EAAiB,CACtB3P,KAAM,CAAEyP,EAAG,6BAA8B,EACzCG,OAAQ,CAAEH,EAAG,iBAAkB,EAC/BC,OAAQ,CAAED,EAAG,iBAAkB,GAE1BI,EAAiBzR,IACjB0R,EAAiB1R,IAEvB,eAAe2R,GAAa,CACtBb,GAAAA,MAAAA,EAAcc,MAAMhJ,EAAe,QAAU,QAClD2C,EAAc,CAAC3C,CAAY,EACvBA,GACE6I,EAAeG,MAAMR,EAAeE,MAAM,EACzC,MAAAI,EAAeE,MAAML,EAAeC,MAAM,EAC3CE,EAAeE,MAAML,EAAeD,MAAM,IAEzC,MAAAI,EAAeE,MAAML,EAAeC,MAAM,EAC3CC,EAAeG,MAAMR,EAAexP,IAAI,EACxC8P,EAAeE,MAAML,EAAe3P,IAAI,EAE/C,CAEA4J,OAAAA,EAAAA,UAAgB,IAAM,CACrB,GAAI,CAAC5C,EAAc,OAEnB,SAASiJ,EAAYrN,EAAsB,OACtCA,EAAMpF,MAAQ,YACjB+R,EAAAA,EAAcW,UAAdX,MAAAA,EAAuBY,QAEzB,CACSC,gBAAAC,iBAAiB,QAASJ,CAAW,EACvC,IAAMG,SAASE,oBAAoB,QAASL,CAAW,CAC/D,EAAG,CAACjJ,CAAY,CAAC,EAGhBxD,EAAAA,KAAC,MAAA,CACAoC,UAAWG,EACV,oIACA,CACC,SAAUiB,CACX,CACD,EAEAxH,SAAA,CAAAW,EAAA,IAAC,SAAA,CACA0F,IAAK0J,EACL3J,UAAU,6CACV,aAAW,uBACX2K,QAASR,EAETvQ,gBAAC,MAAI,CAAA6P,MAAM,KAAKmB,OAAO,KAAKC,QAAQ,YACnCjR,SAAA,CAAAW,EAAAA,IAAC+L,EAAOwE,KAAP,CACC,GAAGlB,EAAeE,OACnBnC,QAASsC,EACT9C,WAAY,CAAEC,SAAU,EAAI,EAC5B2D,OAAO,eACPC,YAAa,IACd,EACAzQ,EAAAA,IAAC+L,EAAOwE,KAAP,CACC,GAAGf,EAAeD,OACnBnC,QAASuC,EACT/C,WAAY,CAAEC,SAAU,EAAI,EAC5B2D,OAAO,eACPC,YAAa,GAAA,CACd,CAAA,EACD,CACD,CAAA,EACC5J,GACA7G,MAAC+L,EAAO+C,EAAP,CACAlC,WAAY,CAAE8D,MAAO,EAAI,EACzBvD,QAAS,CAAE1B,QAAS,EAAGkF,EAAG,CAAE,EAC5BvD,QAAS,CAAE3B,QAAS,EAAGkF,EAAG,CAAE,EAE5BlL,UAAU,iEAEVpG,SAACW,EAAA,IAAAyH,EAAA,CAAKE,GAAG,IAAKtI,SAAM4N,EAAA,CAAA,CACrB,CAAA,CAAA,CAEF,CAEF","x_google_ignoreList":[0,1,3]}
|
|
@@ -1,2 +0,0 @@
|
|
|
1
|
-
import{j as e}from"./index-BFGhCX_U.js";import{B as a}from"./button-DQ001ob0.js";import{I as i}from"./misc-BJtHv_Jh.js";import{S as o}from"./tooltip-BgynKV2c.js";import{u as m,a as u}from"./user-BBryXlM_.js";import{u as x}from"./presence-CdyMdOKk.js";import{u as h,a as p,L as r,F as c}from"./components-9EGYHTc_.js";import"./request-info-DCIQLE6H.js";const D={getSitemapEntries:()=>null};function O(){const l=h(),d=p(),t=m(),s=u(),n=x();return e.jsxs("main",{className:"container flex h-full w-full max-w-3xl flex-grow flex-col items-center justify-center gap-4",children:[e.jsx("img",{className:"h-36 w-36 rounded-full",alt:(s==null?void 0:s.displayName)??t.name??t.email,src:t.avatarUrl}),e.jsx("h1",{className:"mb-1 text-2xl",children:"Your Account"}),e.jsx("p",{className:"text-center text-gray-700 dark:text-gray-300",children:t.name?`Hi ${(s==null?void 0:s.displayName)??t.name}, your device is logged in with ${t.email}.`:`Your device is logged in with ${t.email}.`}),s?e.jsxs(e.Fragment,{children:[e.jsxs("p",{className:"text-center text-gray-700 dark:text-gray-300",children:["And you are connected to discord as ",s.displayName," (",s.id,")."]}),e.jsxs("div",{className:"flex justify-center gap-2",children:[e.jsx(d.Form,{method:"post",children:e.jsx(a,{varient:"mono",name:"intent",value:"disconnect-discord",children:"Disconnect Discord"})}),e.jsx(o,{content:"Your discord connection gives you access to the exclusive Discord channels for Epic Web",children:e.jsx(i,{name:"Question",tabIndex:0})})]})]}):e.jsxs("div",{className:"flex items-center gap-2",children:[e.jsxs(r,{to:l.discordAuthUrl,className:"inline-flex items-center gap-2 underline",children:[e.jsx(i,{name:"Discord",size:"lg"}),"Connect Discord"]}),e.jsx(o,{content:"This will give you access to the exclusive Discord channels for Epic Web",children:e.jsx(i,{name:"Question",tabIndex:0})})]}),e.jsxs("div",{className:"flex items-center gap-2",children:[e.jsxs(c,{method:"POST",children:[e.jsx("input",{name:"optOut",type:"hidden",value:n!=null&&n.optOut?"false":"true"}),e.jsxs(a,{varient:"mono",name:"intent",value:"presence-opt-out",children:[n!=null&&n.optOut?"Opt in to":"Opt out of"," presence"]})]}),e.jsx(o,{content:"This controls whether your name and avatar are displayed in the pile of faces in navigation",children:e.jsx(i,{name:"Question",tabIndex:0})})]}),e.jsxs("div",{className:"flex items-center gap-2",children:[e.jsx(c,{method:"post",children:e.jsx(a,{varient:"mono",name:"intent",value:"logout",children:"Log device out"})}),e.jsx(o,{content:e.jsxs("div",{children:["Note: it is your ",e.jsx("i",{className:"italic",children:"device"})," that's logged in, not your browser.",e.jsx("br",{}),"So all browsers on this device will be logged in with the same account on this device."]}),children:e.jsx(i,{name:"Question",tabIndex:0})})]}),e.jsxs("p",{children:["Check"," ",e.jsx(r,{to:"/onboarding",className:"underline",children:"/onboarding"})," ","if you'd like to review onboarding again."]}),e.jsxs("p",{children:["Check"," ",e.jsx(r,{to:"/support",className:"underline",children:"/support"})," ","if you need support."]})]})}export{O as default,D as handle};
|
|
2
|
-
//# sourceMappingURL=account-CPFwPYf1.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"account-CPFwPYf1.js","sources":["../../../app/routes/_app+/account.tsx"],"sourcesContent":["import { deleteCache } from '@epic-web/workshop-utils/cache.server'\nimport {\n\tdeleteDb,\n\tdeleteDiscordInfo,\n\trequireAuthInfo,\n\tsetPresencePreferences,\n} from '@epic-web/workshop-utils/db.server'\nimport { type SEOHandle } from '@nasa-gcn/remix-seo'\nimport { json, redirect, type LoaderFunctionArgs } from '@remix-run/node'\nimport { Form, Link, useFetcher, useLoaderData } from '@remix-run/react'\nimport { Button } from '#app/components/button.tsx'\nimport { Icon } from '#app/components/icons.tsx'\nimport { SimpleTooltip } from '#app/components/ui/tooltip.js'\nimport { useOptionalDiscordMember, useUser } from '#app/components/user.tsx'\nimport { ensureUndeployed } from '#app/utils/misc.tsx'\nimport { usePresencePreferences } from '#app/utils/presence.tsx'\nimport { redirectWithToast } from '#app/utils/toast.server.ts'\nimport { getDiscordAuthURL } from '../discord.callback.ts'\n\nexport const handle: SEOHandle = {\n\tgetSitemapEntries: () => null,\n}\n\nexport async function loader({ request }: LoaderFunctionArgs) {\n\tensureUndeployed()\n\tawait requireAuthInfo({ request })\n\treturn json({ discordAuthUrl: getDiscordAuthURL() })\n}\n\nexport async function action({ request }: { request: Request }) {\n\tensureUndeployed()\n\tconst formData = await request.formData()\n\tconst intent = formData.get('intent')\n\tif (intent === 'disconnect-discord') {\n\t\tawait deleteDiscordInfo()\n\t\treturn redirectWithToast('/account', {\n\t\t\ttype: 'success',\n\t\t\ttitle: 'Disconnected',\n\t\t\tdescription: 'Local discord data has been deleted.',\n\t\t})\n\t} else if (intent === 'logout') {\n\t\tawait deleteDb()\n\t\tawait deleteCache()\n\t\treturn redirectWithToast('/login', {\n\t\t\ttype: 'success',\n\t\t\ttitle: 'Logged out',\n\t\t\tdescription: 'Goodbye! Come back soon!',\n\t\t})\n\t} else if (intent === 'presence-opt-out') {\n\t\tconst optOut = formData.get('optOut') === 'true'\n\t\tawait setPresencePreferences({ optOut })\n\t\treturn redirectWithToast('/account', {\n\t\t\ttitle: optOut ? 'Opted out' : 'Opted in',\n\t\t\tdescription: `You are now ${optOut ? 'invisible' : 'visible'}.`,\n\t\t\ttype: 'success',\n\t\t})\n\t}\n\n\treturn redirect('/account')\n}\n\nexport default function Account() {\n\tconst data = useLoaderData<typeof loader>()\n\tconst disconnectFetcher = useFetcher()\n\tconst user = useUser()\n\tconst discordMember = useOptionalDiscordMember()\n\tconst presencePreferences = usePresencePreferences()\n\treturn (\n\t\t<main className=\"container flex h-full w-full max-w-3xl flex-grow flex-col items-center justify-center gap-4\">\n\t\t\t<img\n\t\t\t\tclassName=\"h-36 w-36 rounded-full\"\n\t\t\t\talt={discordMember?.displayName ?? user.name ?? user.email}\n\t\t\t\tsrc={user.avatarUrl}\n\t\t\t/>\n\t\t\t<h1 className=\"mb-1 text-2xl\">Your Account</h1>\n\t\t\t<p className=\"text-center text-gray-700 dark:text-gray-300\">\n\t\t\t\t{user.name\n\t\t\t\t\t? `Hi ${\n\t\t\t\t\t\t\tdiscordMember?.displayName ?? user.name\n\t\t\t\t\t\t}, your device is logged in with ${user.email}.`\n\t\t\t\t\t: `Your device is logged in with ${user.email}.`}\n\t\t\t</p>\n\t\t\t{discordMember ? (\n\t\t\t\t<>\n\t\t\t\t\t<p className=\"text-center text-gray-700 dark:text-gray-300\">\n\t\t\t\t\t\tAnd you are connected to discord as {discordMember.displayName} (\n\t\t\t\t\t\t{discordMember.id}).\n\t\t\t\t\t</p>\n\t\t\t\t\t<div className=\"flex justify-center gap-2\">\n\t\t\t\t\t\t<disconnectFetcher.Form method=\"post\">\n\t\t\t\t\t\t\t<Button varient=\"mono\" name=\"intent\" value=\"disconnect-discord\">\n\t\t\t\t\t\t\t\tDisconnect Discord\n\t\t\t\t\t\t\t</Button>\n\t\t\t\t\t\t</disconnectFetcher.Form>\n\t\t\t\t\t\t<SimpleTooltip content=\"Your discord connection gives you access to the exclusive Discord channels for Epic Web\">\n\t\t\t\t\t\t\t<Icon name=\"Question\" tabIndex={0} />\n\t\t\t\t\t\t</SimpleTooltip>\n\t\t\t\t\t</div>\n\t\t\t\t</>\n\t\t\t) : (\n\t\t\t\t<div className=\"flex items-center gap-2\">\n\t\t\t\t\t<Link\n\t\t\t\t\t\tto={data.discordAuthUrl}\n\t\t\t\t\t\tclassName=\"inline-flex items-center gap-2 underline\"\n\t\t\t\t\t>\n\t\t\t\t\t\t<Icon name=\"Discord\" size=\"lg\" />\n\t\t\t\t\t\tConnect Discord\n\t\t\t\t\t</Link>\n\t\t\t\t\t<SimpleTooltip content=\"This will give you access to the exclusive Discord channels for Epic Web\">\n\t\t\t\t\t\t<Icon name=\"Question\" tabIndex={0} />\n\t\t\t\t\t</SimpleTooltip>\n\t\t\t\t</div>\n\t\t\t)}\n\t\t\t<div className=\"flex items-center gap-2\">\n\t\t\t\t<Form method=\"POST\">\n\t\t\t\t\t<input\n\t\t\t\t\t\tname=\"optOut\"\n\t\t\t\t\t\ttype=\"hidden\"\n\t\t\t\t\t\tvalue={presencePreferences?.optOut ? 'false' : 'true'}\n\t\t\t\t\t/>\n\t\t\t\t\t<Button varient=\"mono\" name=\"intent\" value=\"presence-opt-out\">\n\t\t\t\t\t\t{presencePreferences?.optOut ? 'Opt in to' : 'Opt out of'} presence\n\t\t\t\t\t</Button>\n\t\t\t\t</Form>\n\t\t\t\t<SimpleTooltip content=\"This controls whether your name and avatar are displayed in the pile of faces in navigation\">\n\t\t\t\t\t<Icon name=\"Question\" tabIndex={0} />\n\t\t\t\t</SimpleTooltip>\n\t\t\t</div>\n\t\t\t<div className=\"flex items-center gap-2\">\n\t\t\t\t<Form method=\"post\">\n\t\t\t\t\t<Button varient=\"mono\" name=\"intent\" value=\"logout\">\n\t\t\t\t\t\tLog device out\n\t\t\t\t\t</Button>\n\t\t\t\t</Form>\n\t\t\t\t<SimpleTooltip\n\t\t\t\t\tcontent={\n\t\t\t\t\t\t<div>\n\t\t\t\t\t\t\tNote: it is your <i className=\"italic\">device</i> that's logged\n\t\t\t\t\t\t\tin, not your browser.\n\t\t\t\t\t\t\t<br />\n\t\t\t\t\t\t\tSo all browsers on this device will be logged in with the same\n\t\t\t\t\t\t\taccount on this device.\n\t\t\t\t\t\t</div>\n\t\t\t\t\t}\n\t\t\t\t>\n\t\t\t\t\t<Icon name=\"Question\" tabIndex={0} />\n\t\t\t\t</SimpleTooltip>\n\t\t\t</div>\n\t\t\t<p>\n\t\t\t\tCheck{' '}\n\t\t\t\t<Link to=\"/onboarding\" className=\"underline\">\n\t\t\t\t\t/onboarding\n\t\t\t\t</Link>{' '}\n\t\t\t\tif you'd like to review onboarding again.\n\t\t\t</p>\n\t\t\t<p>\n\t\t\t\tCheck{' '}\n\t\t\t\t<Link to=\"/support\" className=\"underline\">\n\t\t\t\t\t/support\n\t\t\t\t</Link>{' '}\n\t\t\t\tif you need support.\n\t\t\t</p>\n\t\t</main>\n\t)\n}\n"],"names":["handle","getSitemapEntries","Account","data","useLoaderData","disconnectFetcher","useFetcher","user","useUser","discordMember","useOptionalDiscordMember","presencePreferences","usePresencePreferences","jsxs","className","children","jsx","alt","displayName","name","email","src","avatarUrl","Fragment","id","Form","method","Button","varient","value","SimpleTooltip","content","Icon","tabIndex","Link","to","discordAuthUrl","size","type","optOut"],"mappings":"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"}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"diff-jlCv3hv0.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 { makeTimings } from '@epic-web/workshop-utils/timing.server'\nimport { defer, type LoaderFunctionArgs } from '@remix-run/node'\nimport { useLoaderData, useNavigation, useSearchParams } from '@remix-run/react'\nimport { useSpinDelay } from 'spin-delay'\nimport { Diff } from '#app/components/diff.tsx'\nimport { NavChevrons } from '#app/components/nav-chevrons.tsx'\nimport { getDiffCode } from '#app/utils/diff.server.ts'\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 defer({\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":["DiffViewer","data","useLoaderData","params","useSearchParams","URLSearchParams","set","navigation","useNavigation","isNavigating","useSpinDelay","state","delay","minDuration","jsxs","className","cn","children","jsx","Diff","diff","allApps","NavChevrons","prev","prevLink","next","nextLink"],"mappings":"wpBAyGA,SAAwBA,GAAa,CACpC,MAAMC,EAAOC,IACP,CAACC,CAAM,EAAIC,IACe,IAAIC,gBAAgBF,CAAM,EAClCG,IAAI,aAAc,MAAM,EAChD,MAAMC,EAAaC,IACbC,EAAeC,EAAA,aAAaH,EAAWI,QAAU,OAAQ,CAC9DC,MAAO,IACPC,YAAa,GACd,CAAC,EAGA,OAAAC,EAAAA,KAAC,MAAA,CACAC,UAAWC,EAAG,mCAAoC,CACjD,yBAA0BP,CAC3B,CAAC,EAEDQ,SAAA,CAACC,EAAA,IAAA,MAAA,CAAIH,UAAU,kBACdE,SAACC,EAAA,IAAAC,EAAA,CAAKC,KAAMnB,EAAKmB,KAAMC,QAASpB,EAAKoB,QAAS,CAC/C,CAAA,EACCH,EAAA,IAAA,MAAA,CAAIH,UAAU,8CACdE,SAACC,EAAA,IAAAI,EAAA,CAAYC,KAAMtB,EAAKuB,SAAUC,KAAMxB,EAAKyB,SAAU,CACxD,CAAA,CAAA,CAAA,CACD,CAEF"}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"discord-CHsbqaqM.js","sources":["../../../app/routes/_app+/discord.tsx"],"sourcesContent":["import { type SEOHandle } from '@nasa-gcn/remix-seo'\nimport { json } from '@remix-run/node'\nimport { Link, useLoaderData } from '@remix-run/react'\nimport { Icon } from '#app/components/icons.tsx'\nimport {\n\tuseOptionalDiscordMember,\n\tuseOptionalUser,\n} from '#app/components/user.tsx'\nimport { getDiscordAuthURL } from '../discord.callback.ts'\n\nexport const handle: SEOHandle = {\n\tgetSitemapEntries: () => null,\n}\n\nexport async function loader() {\n\treturn json({ discordAuthUrl: getDiscordAuthURL() })\n}\n\nexport function useDiscordCTALink({\n\tdiscordAuthUrl,\n}: {\n\tdiscordAuthUrl: string\n}) {\n\tconst user = useOptionalUser()\n\tconst discordMember = useOptionalDiscordMember()\n\n\tif (!user) {\n\t\treturn '/login'\n\t}\n\tif (!discordMember) {\n\t\treturn discordAuthUrl\n\t}\n\n\treturn 'https://discord.com/channels/715220730605731931/1161045224907341972'\n}\n\nexport function DiscordCTA({ discordAuthUrl }: { discordAuthUrl: string }) {\n\tconst user = useOptionalUser()\n\tconst discordMember = useOptionalDiscordMember()\n\n\tif (!user) {\n\t\treturn (\n\t\t\t<div className=\"flex flex-wrap items-center justify-center gap-2 text-xl\">\n\t\t\t\t<Link to=\"/login\" className=\"inline-flex items-center gap-2 underline\">\n\t\t\t\t\t<Icon name=\"Discord\" size=\"2xl\" />\n\t\t\t\t\tLogin\n\t\t\t\t</Link>{' '}\n\t\t\t\t<span>\n\t\t\t\t\tto get access to the exclusive{' '}\n\t\t\t\t\t<Link to=\"/discord\" className=\"underline\">\n\t\t\t\t\t\tdiscord channel\n\t\t\t\t\t</Link>\n\t\t\t\t\t.\n\t\t\t\t</span>\n\t\t\t</div>\n\t\t)\n\t}\n\tif (!discordMember) {\n\t\treturn (\n\t\t\t<div className=\"flex flex-wrap items-center justify-center gap-2 text-xl\">\n\t\t\t\t<Link to={discordAuthUrl} className=\"flex items-center gap-2 underline\">\n\t\t\t\t\t<Icon name=\"Discord\" size=\"2xl\" />\n\t\t\t\t\tConnect Discord\n\t\t\t\t</Link>{' '}\n\t\t\t\t<span>\n\t\t\t\t\tto get access to the exclusive{' '}\n\t\t\t\t\t<Link to=\"/discord\" className=\"underline\">\n\t\t\t\t\t\tdiscord channel\n\t\t\t\t\t</Link>\n\t\t\t\t\t.\n\t\t\t\t</span>\n\t\t\t</div>\n\t\t)\n\t}\n\n\treturn (\n\t\t<div className=\"flex items-center justify-center gap-2 text-xl underline\">\n\t\t\t<Link to=\"discord://discord.com/channels/715220730605731931/1161045224907341972\">\n\t\t\t\t<Icon name=\"Discord\" size=\"2xl\" />\n\t\t\t</Link>\n\t\t\t<Link\n\t\t\t\tto=\"https://discord.com/channels/715220730605731931/1161045224907341972\"\n\t\t\t\ttarget=\"_blank\"\n\t\t\t\trel=\"noreferrer noopener\"\n\t\t\t>\n\t\t\t\tOpen Discord\n\t\t\t</Link>\n\t\t</div>\n\t)\n}\n\nexport default function DiscordRoute() {\n\tconst data = useLoaderData<typeof loader>()\n\n\treturn (\n\t\t<div className=\"container flex h-full max-w-3xl flex-col items-center justify-center gap-4 p-12\">\n\t\t\t<DiscordCTA discordAuthUrl={data.discordAuthUrl} />\n\t\t\t<p>\n\t\t\t\tThe{' '}\n\t\t\t\t<Link\n\t\t\t\t\ttarget=\"_blank\"\n\t\t\t\t\trel=\"noreferrer noopener\"\n\t\t\t\t\tclassName=\"underline\"\n\t\t\t\t\tto=\"https://kentcdodds.com/discord\"\n\t\t\t\t>\n\t\t\t\t\tEpic Web Community on Discord\n\t\t\t\t</Link>{' '}\n\t\t\t\tis a great place to hang out with other developers who are working\n\t\t\t\tthrough this workshop. You can ask questions, get help, and solidify\n\t\t\t\twhat you're learning by helping others.\n\t\t\t</p>\n\t\t\t<p>\n\t\t\t\t<small className=\"text-sm\">\n\t\t\t\t\tIf you've not joined the Epic Web Community on Discord yet, you'll be\n\t\t\t\t\trequired to go through a short onboarding process first. A friendly\n\t\t\t\t\tbot will explain the process when you{' '}\n\t\t\t\t\t<Link\n\t\t\t\t\t\tto=\"https://kcd.im/discord\"\n\t\t\t\t\t\ttarget=\"_blank\"\n\t\t\t\t\t\trel=\"noreferrer noopener\"\n\t\t\t\t\t\tclassName=\"underline\"\n\t\t\t\t\t>\n\t\t\t\t\t\tjoin\n\t\t\t\t\t</Link>\n\t\t\t\t\t.\n\t\t\t\t</small>\n\t\t\t</p>\n\t\t</div>\n\t)\n}\n"],"names":["handle","getSitemapEntries","useDiscordCTALink","discordAuthUrl","user","useOptionalUser","discordMember","useOptionalDiscordMember","DiscordCTA","jsxs","className","children","jsx","Link","to","Icon","name","size","target","rel","DiscordRoute","data","useLoaderData"],"mappings":"iLAUO,MAAMA,EAAoB,CAChCC,kBAAmBA,IAAM,IAC1B,EAMO,SAASC,EAAkB,CACjCC,eAAAA,CACD,EAEG,CACF,MAAMC,EAAOC,IACPC,EAAgBC,IAEtB,OAAKH,EAGAE,EAIE,sEAHCH,EAHA,QAOT,CAEgB,SAAAK,EAAW,CAAEL,eAAAA,CAAe,EAA+B,CAC1E,MAAMC,EAAOC,IACPC,EAAgBC,IAEtB,OAAKH,EAiBAE,EAmBJG,EAAAA,KAAC,MAAI,CAAAC,UAAU,2DACdC,SAAA,CAACC,EAAA,IAAAC,EAAA,CAAKC,GAAG,wEACRH,SAAAC,EAAA,IAACG,GAAKC,KAAK,UAAUC,KAAK,MAAM,CACjC,CAAA,EACAL,EAAA,IAACC,EAAA,CACAC,GAAG,sEACHI,OAAO,SACPC,IAAI,sBACJR,SAAA,cAAA,CAED,CAAA,CACD,CAAA,EA5BCF,EAAAA,KAAC,MAAI,CAAAC,UAAU,2DACdC,SAAA,CAAAF,EAAA,KAACI,EAAK,CAAAC,GAAIX,EAAgBO,UAAU,oCACnCC,SAAA,CAAAC,EAAA,IAACG,EAAK,CAAAC,KAAK,UAAUC,KAAK,KAAM,CAAA,EAAE,iBAAA,EAEnC,EAAQ,WACP,OAAK,CAAAN,SAAA,CAAA,iCAC0B,UAC9BE,EAAK,CAAAC,GAAG,WAAWJ,UAAU,YAAYC,SAE1C,iBAAA,CAAA,EAAO,GAAA,CAER,CAAA,CAAA,CACD,CAAA,EA7BAF,EAAAA,KAAC,MAAI,CAAAC,UAAU,2DACdC,SAAA,CAAAF,EAAA,KAACI,EAAK,CAAAC,GAAG,SAASJ,UAAU,2CAC3BC,SAAA,CAAAC,EAAA,IAACG,EAAK,CAAAC,KAAK,UAAUC,KAAK,KAAM,CAAA,EAAE,OAAA,EAEnC,EAAQ,WACP,OAAK,CAAAN,SAAA,CAAA,iCAC0B,UAC9BE,EAAK,CAAAC,GAAG,WAAWJ,UAAU,YAAYC,SAE1C,iBAAA,CAAA,EAAO,GAAA,CAER,CAAA,CAAA,CACD,CAAA,CAmCH,CAEA,SAAwBS,GAAe,CACtC,MAAMC,EAAOC,IAGZ,OAAAb,EAAAA,KAAC,MAAI,CAAAC,UAAU,kFACdC,SAAA,CAACC,EAAA,IAAAJ,EAAA,CAAWL,eAAgBkB,EAAKlB,cAAgB,CAAA,SAChD,IAAE,CAAAQ,SAAA,CAAA,MACE,IACJC,EAAAA,IAACC,EAAA,CACAK,OAAO,SACPC,IAAI,sBACJT,UAAU,YACVI,GAAG,iCACHH,SAAA,+BAAA,CAED,EAAQ,IAAI,iLAAA,CAIb,CAAA,EACCC,EAAA,IAAA,IAAA,CACAD,SAACF,EAAA,KAAA,QAAA,CAAMC,UAAU,UAAUC,SAAA,CAAA,kLAGY,IACtCC,EAAAA,IAACC,EAAA,CACAC,GAAG,yBACHI,OAAO,SACPC,IAAI,sBACJT,UAAU,YACVC,SAAA,MAED,CAAA,EAAO,GAAA,EAER,CACD,CAAA,CAAA,CACD,CAAA,CAEF"}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"discord-DoeazikD.js","sources":[],"sourcesContent":[],"names":[],"mappings":""}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"finished-DVV0zwmP.js","sources":["../../../app/routes/_app+/finished.tsx"],"sourcesContent":["import { ElementScrollRestoration } from '@epic-web/restore-scroll'\nimport {\n\tgetExercises,\n\tgetWorkshopFinished,\n} from '@epic-web/workshop-utils/apps.server'\nimport { getWorkshopConfig } from '@epic-web/workshop-utils/config.server'\nimport {\n\tcombineServerTimings,\n\tgetServerTimeHeader,\n\tmakeTimings,\n\ttime,\n} from '@epic-web/workshop-utils/timing.server'\nimport { type SEOHandle } from '@nasa-gcn/remix-seo'\nimport {\n\tdefer,\n\ttype HeadersFunction,\n\ttype LoaderFunctionArgs,\n\ttype MetaFunction,\n} from '@remix-run/node'\nimport { Link, useLoaderData } from '@remix-run/react'\nimport slugify from '@sindresorhus/slugify'\nimport * as React from 'react'\nimport { EpicVideoInfoProvider } from '#app/components/epic-video.tsx'\nimport { Loading } from '#app/components/loading.tsx'\nimport { NavChevrons } from '#app/components/nav-chevrons.tsx'\nimport { useRevalidationWS } from '#app/components/revalidation-ws.js'\nimport { type loader as rootLoader } from '#app/root.tsx'\nimport { getEpicVideoInfos } from '#app/utils/epic-api.ts'\nimport { Mdx } from '#app/utils/mdx.tsx'\nimport { cn } from '#app/utils/misc.tsx'\nimport { getSeoMetaTags } from '#app/utils/seo.js'\nimport { EditFileOnGitHub } from '../launch-editor.tsx'\nimport { ProgressToggle } from '../progress.tsx'\n\nexport const handle: SEOHandle = {\n\tgetSitemapEntries: () => [{ route: '/finished' }],\n}\n\nexport const meta: MetaFunction<typeof loader, { root: typeof rootLoader }> = ({\n\tmatches,\n}) => {\n\tconst rootData = matches.find((m) => m.id === 'root')?.data\n\tif (!rootData) return []\n\n\treturn getSeoMetaTags({\n\t\ttitle: `🎉 ${rootData?.workshopTitle}`,\n\t\tdescription: `Elaboration for ${rootData?.workshopTitle}`,\n\t\togTitle: `Finished ${rootData?.workshopTitle}`,\n\t\togDescription: `You finished! Time to submit feedback.`,\n\t\tinstructor: rootData.instructor,\n\t\trequestInfo: rootData.requestInfo,\n\t})\n}\n\nexport async function loader({ request }: LoaderFunctionArgs) {\n\tconst timings = makeTimings('finishedLoader')\n\tconst exercises = await getExercises({ request, timings })\n\tconst compiledFinished = await time(() => getWorkshopFinished({ request }), {\n\t\ttimings,\n\t\ttype: 'compileMdx',\n\t\tdesc: 'compileMdx in finished',\n\t})\n\n\tconst lastExercises = exercises[exercises.length - 1]\n\tconst workshopConfig = getWorkshopConfig()\n\tconst workshopTitle = workshopConfig.title\n\tconst workshopFormTemplate = workshopConfig.forms.workshop\n\tconst workshopFormEmbedUrl = workshopFormTemplate.replace(\n\t\t'{workshopTitle}',\n\t\tencodeURIComponent(workshopTitle),\n\t)\n\treturn defer(\n\t\t{\n\t\t\tarticleId: `workshop-${slugify(workshopTitle)}-finished`,\n\t\t\tworkshopTitle,\n\t\t\tworkshopFormEmbedUrl,\n\t\t\tfinishedCode:\n\t\t\t\tcompiledFinished.compiled.status === 'success'\n\t\t\t\t\t? compiledFinished.compiled.code\n\t\t\t\t\t: null,\n\t\t\tepicVideoInfosPromise:\n\t\t\t\tcompiledFinished.compiled.status === 'success'\n\t\t\t\t\t? getEpicVideoInfos(compiledFinished.compiled.epicVideoEmbeds, {\n\t\t\t\t\t\t\trequest,\n\t\t\t\t\t\t})\n\t\t\t\t\t: null,\n\t\t\tworkshopFinished: {\n\t\t\t\tstatus: compiledFinished.compiled.status,\n\t\t\t\tfile: compiledFinished.file,\n\t\t\t\trelativePath: compiledFinished.relativePath,\n\t\t\t},\n\t\t\tprevStepLink: lastExercises\n\t\t\t\t? {\n\t\t\t\t\t\tto: `/${lastExercises.exerciseNumber}/finished`,\n\t\t\t\t\t}\n\t\t\t\t: null,\n\t\t},\n\t\t{\n\t\t\theaders: {\n\t\t\t\t'Server-Timing': getServerTimeHeader(timings),\n\t\t\t},\n\t\t},\n\t)\n}\n\nexport const headers: HeadersFunction = ({ loaderHeaders, parentHeaders }) => {\n\tconst headers = {\n\t\t'Cache-Control': loaderHeaders.get('Cache-Control') ?? '',\n\t\t'Server-Timing': combineServerTimings(loaderHeaders, parentHeaders),\n\t}\n\treturn headers\n}\n\nconst mdxComponents = { h1: () => null }\n\nexport default function ExerciseFinished() {\n\tconst data = useLoaderData<typeof loader>()\n\tuseRevalidationWS({ watchPaths: ['./exercises/FINISHED.mdx'] })\n\treturn (\n\t\t<div className=\"flex h-full flex-grow flex-col\">\n\t\t\t<main className=\"grid h-full flex-grow grid-cols-1 grid-rows-2 lg:grid-cols-2 lg:grid-rows-1\">\n\t\t\t\t<div className=\"relative col-span-1 row-span-1 flex h-full flex-col lg:border-r\">\n\t\t\t\t\t<h1 className=\"h-14 border-b pl-10 pr-5 text-sm font-medium uppercase leading-none\">\n\t\t\t\t\t\t<div className=\"flex h-14 flex-wrap items-center justify-between gap-x-2 py-2\">\n\t\t\t\t\t\t\t<div className=\"flex items-center justify-start gap-x-2\">\n\t\t\t\t\t\t\t\t<Link to=\"/\" className=\"hover:underline\">\n\t\t\t\t\t\t\t\t\t{data.workshopTitle}\n\t\t\t\t\t\t\t\t</Link>\n\t\t\t\t\t\t\t\t<span>/</span>\n\t\t\t\t\t\t\t\t<span>Elaboration</span>\n\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t</div>\n\t\t\t\t\t</h1>\n\t\t\t\t\t<article\n\t\t\t\t\t\tclassName=\"shadow-on-scrollbox 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\"\n\t\t\t\t\t\tid={data.articleId}\n\t\t\t\t\t>\n\t\t\t\t\t\t{data.finishedCode ? (\n\t\t\t\t\t\t\t<EpicVideoInfoProvider\n\t\t\t\t\t\t\t\tepicVideoInfosPromise={data.epicVideoInfosPromise}\n\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t<div className=\"prose dark:prose-invert sm:prose-lg\">\n\t\t\t\t\t\t\t\t\t<Mdx code={data.finishedCode} components={mdxComponents} />\n\t\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t\t</EpicVideoInfoProvider>\n\t\t\t\t\t\t) : (\n\t\t\t\t\t\t\t// TODO: render a random dad joke...\n\t\t\t\t\t\t\t'No finished instructions yet...'\n\t\t\t\t\t\t)}\n\t\t\t\t\t</article>\n\t\t\t\t\t<ElementScrollRestoration elementQuery={`#${data.articleId}`} />\n\t\t\t\t\t<ProgressToggle\n\t\t\t\t\t\ttype=\"workshop-finished\"\n\t\t\t\t\t\tclassName=\"h-14 border-t px-6\"\n\t\t\t\t\t/>\n\t\t\t\t\t<div className=\"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{data.workshopFinished.status === 'success' ? (\n\t\t\t\t\t\t\t<EditFileOnGitHub\n\t\t\t\t\t\t\t\tfile={data.workshopFinished.file}\n\t\t\t\t\t\t\t\trelativePath={data.workshopFinished.relativePath}\n\t\t\t\t\t\t\t/>\n\t\t\t\t\t\t) : null}\n\t\t\t\t\t\t<NavChevrons prev={data.prevStepLink} next={{ to: '/' }} />\n\t\t\t\t\t</div>\n\t\t\t\t</div>\n\t\t\t\t<Survey\n\t\t\t\t\tworkshopTitle={data.workshopTitle}\n\t\t\t\t\tworkshopFormEmbedUrl={data.workshopFormEmbedUrl}\n\t\t\t\t/>\n\t\t\t</main>\n\t\t</div>\n\t)\n}\n\nfunction Survey({\n\tworkshopTitle,\n\tworkshopFormEmbedUrl,\n}: {\n\tworkshopTitle: string\n\tworkshopFormEmbedUrl: string\n}) {\n\tconst [iframeLoaded, setIframeLoaded] = React.useState(false)\n\treturn (\n\t\t<div className=\"relative flex-shrink-0\">\n\t\t\t{!iframeLoaded ? (\n\t\t\t\t<div className=\"absolute inset-0 z-10 flex items-center justify-center\">\n\t\t\t\t\t<Loading>\n\t\t\t\t\t\t<span>Loading {workshopTitle} Elaboration form</span>\n\t\t\t\t\t</Loading>\n\t\t\t\t</div>\n\t\t\t) : null}\n\t\t\t<iframe\n\t\t\t\tonLoad={() => setIframeLoaded(true)}\n\t\t\t\t// show what would have shown if there is an error\n\t\t\t\tonError={() => setIframeLoaded(true)}\n\t\t\t\ttitle=\"Elaboration\"\n\t\t\t\tsrc={workshopFormEmbedUrl}\n\t\t\t\tclassName={cn(\n\t\t\t\t\t'absolute inset-0 flex h-full w-full transition-opacity duration-300',\n\t\t\t\t\tiframeLoaded ? 'opacity-100' : 'opacity-0',\n\t\t\t\t)}\n\t\t\t/>\n\t\t</div>\n\t)\n}\n"],"names":["handle","getSitemapEntries","route","meta","matches","rootData","find","m","id","data","getSeoMetaTags","title","workshopTitle","description","ogTitle","ogDescription","instructor","requestInfo","mdxComponents","h1","ExerciseFinished","useLoaderData","useRevalidationWS","watchPaths","className","children","jsxs","jsx","Link","to","articleId","finishedCode","EpicVideoInfoProvider","epicVideoInfosPromise","Mdx","code","components","ElementScrollRestoration","elementQuery","ProgressToggle","type","workshopFinished","status","EditFileOnGitHub","file","relativePath","NavChevrons","prev","prevStepLink","next","Survey","workshopFormEmbedUrl","iframeLoaded","setIframeLoaded","React","Loading","onLoad","onError","src","cn"],"mappings":"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"}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"index-DJF1fiZI.js","sources":["../../../../../node_modules/@radix-ui/react-roving-focus/node_modules/@radix-ui/react-context/dist/index.mjs","../../../../../node_modules/@radix-ui/react-roving-focus/dist/index.mjs","../../../../../node_modules/@radix-ui/react-tabs/dist/index.mjs","../../../app/routes/_app+/exercise+/$exerciseNumber_.$stepNumber.$type+/__shared/discord.tsx","../../../app/routes/_app+/exercise+/$exerciseNumber_.$stepNumber.$type+/__shared/playground.tsx","../../../app/routes/_app+/exercise+/$exerciseNumber_.$stepNumber.$type+/index.tsx"],"sourcesContent":["// packages/react/context/src/createContext.tsx\nimport * as React from \"react\";\nimport { jsx } from \"react/jsx-runtime\";\nfunction createContext2(rootComponentName, defaultContext) {\n const Context = React.createContext(defaultContext);\n function Provider(props) {\n const { children, ...context } = props;\n const value = React.useMemo(() => context, Object.values(context));\n return /* @__PURE__ */ jsx(Context.Provider, { value, children });\n }\n function useContext2(consumerName) {\n const context = React.useContext(Context);\n if (context) return context;\n if (defaultContext !== void 0) return defaultContext;\n throw new Error(`\\`${consumerName}\\` must be used within \\`${rootComponentName}\\``);\n }\n Provider.displayName = rootComponentName + \"Provider\";\n return [Provider, useContext2];\n}\nfunction createContextScope(scopeName, createContextScopeDeps = []) {\n let defaultContexts = [];\n function createContext3(rootComponentName, defaultContext) {\n const BaseContext = React.createContext(defaultContext);\n const index = defaultContexts.length;\n defaultContexts = [...defaultContexts, defaultContext];\n function Provider(props) {\n const { scope, children, ...context } = props;\n const Context = scope?.[scopeName][index] || BaseContext;\n const value = React.useMemo(() => context, Object.values(context));\n return /* @__PURE__ */ jsx(Context.Provider, { value, children });\n }\n function useContext2(consumerName, scope) {\n const Context = scope?.[scopeName][index] || BaseContext;\n const context = React.useContext(Context);\n if (context) return context;\n if (defaultContext !== void 0) return defaultContext;\n throw new Error(`\\`${consumerName}\\` must be used within \\`${rootComponentName}\\``);\n }\n Provider.displayName = rootComponentName + \"Provider\";\n return [Provider, useContext2];\n }\n const createScope = () => {\n const scopeContexts = defaultContexts.map((defaultContext) => {\n return React.createContext(defaultContext);\n });\n return function useScope(scope) {\n const contexts = scope?.[scopeName] || scopeContexts;\n return React.useMemo(\n () => ({ [`__scope${scopeName}`]: { ...scope, [scopeName]: contexts } }),\n [scope, contexts]\n );\n };\n };\n createScope.scopeName = scopeName;\n return [createContext3, composeContextScopes(createScope, ...createContextScopeDeps)];\n}\nfunction composeContextScopes(...scopes) {\n const baseScope = scopes[0];\n if (scopes.length === 1) return baseScope;\n const createScope = () => {\n const scopeHooks = scopes.map((createScope2) => ({\n useScope: createScope2(),\n scopeName: createScope2.scopeName\n }));\n return function useComposedScopes(overrideScopes) {\n const nextScopes = scopeHooks.reduce((nextScopes2, { useScope, scopeName }) => {\n const scopeProps = useScope(overrideScopes);\n const currentScope = scopeProps[`__scope${scopeName}`];\n return { ...nextScopes2, ...currentScope };\n }, {});\n return React.useMemo(() => ({ [`__scope${baseScope.scopeName}`]: nextScopes }), [nextScopes]);\n };\n };\n createScope.scopeName = baseScope.scopeName;\n return createScope;\n}\nexport {\n createContext2 as createContext,\n createContextScope\n};\n//# sourceMappingURL=index.mjs.map\n","\"use client\";\n\n// packages/react/roving-focus/src/RovingFocusGroup.tsx\nimport * as React from \"react\";\nimport { composeEventHandlers } from \"@radix-ui/primitive\";\nimport { createCollection } from \"@radix-ui/react-collection\";\nimport { useComposedRefs } from \"@radix-ui/react-compose-refs\";\nimport { createContextScope } from \"@radix-ui/react-context\";\nimport { useId } from \"@radix-ui/react-id\";\nimport { Primitive } from \"@radix-ui/react-primitive\";\nimport { useCallbackRef } from \"@radix-ui/react-use-callback-ref\";\nimport { useControllableState } from \"@radix-ui/react-use-controllable-state\";\nimport { useDirection } from \"@radix-ui/react-direction\";\nimport { jsx } from \"react/jsx-runtime\";\nvar ENTRY_FOCUS = \"rovingFocusGroup.onEntryFocus\";\nvar EVENT_OPTIONS = { bubbles: false, cancelable: true };\nvar GROUP_NAME = \"RovingFocusGroup\";\nvar [Collection, useCollection, createCollectionScope] = createCollection(GROUP_NAME);\nvar [createRovingFocusGroupContext, createRovingFocusGroupScope] = createContextScope(\n GROUP_NAME,\n [createCollectionScope]\n);\nvar [RovingFocusProvider, useRovingFocusContext] = createRovingFocusGroupContext(GROUP_NAME);\nvar RovingFocusGroup = React.forwardRef(\n (props, forwardedRef) => {\n return /* @__PURE__ */ jsx(Collection.Provider, { scope: props.__scopeRovingFocusGroup, children: /* @__PURE__ */ jsx(Collection.Slot, { scope: props.__scopeRovingFocusGroup, children: /* @__PURE__ */ jsx(RovingFocusGroupImpl, { ...props, ref: forwardedRef }) }) });\n }\n);\nRovingFocusGroup.displayName = GROUP_NAME;\nvar RovingFocusGroupImpl = React.forwardRef((props, forwardedRef) => {\n const {\n __scopeRovingFocusGroup,\n orientation,\n loop = false,\n dir,\n currentTabStopId: currentTabStopIdProp,\n defaultCurrentTabStopId,\n onCurrentTabStopIdChange,\n onEntryFocus,\n preventScrollOnEntryFocus = false,\n ...groupProps\n } = props;\n const ref = React.useRef(null);\n const composedRefs = useComposedRefs(forwardedRef, ref);\n const direction = useDirection(dir);\n const [currentTabStopId = null, setCurrentTabStopId] = useControllableState({\n prop: currentTabStopIdProp,\n defaultProp: defaultCurrentTabStopId,\n onChange: onCurrentTabStopIdChange\n });\n const [isTabbingBackOut, setIsTabbingBackOut] = React.useState(false);\n const handleEntryFocus = useCallbackRef(onEntryFocus);\n const getItems = useCollection(__scopeRovingFocusGroup);\n const isClickFocusRef = React.useRef(false);\n const [focusableItemsCount, setFocusableItemsCount] = React.useState(0);\n React.useEffect(() => {\n const node = ref.current;\n if (node) {\n node.addEventListener(ENTRY_FOCUS, handleEntryFocus);\n return () => node.removeEventListener(ENTRY_FOCUS, handleEntryFocus);\n }\n }, [handleEntryFocus]);\n return /* @__PURE__ */ jsx(\n RovingFocusProvider,\n {\n scope: __scopeRovingFocusGroup,\n orientation,\n dir: direction,\n loop,\n currentTabStopId,\n onItemFocus: React.useCallback(\n (tabStopId) => setCurrentTabStopId(tabStopId),\n [setCurrentTabStopId]\n ),\n onItemShiftTab: React.useCallback(() => setIsTabbingBackOut(true), []),\n onFocusableItemAdd: React.useCallback(\n () => setFocusableItemsCount((prevCount) => prevCount + 1),\n []\n ),\n onFocusableItemRemove: React.useCallback(\n () => setFocusableItemsCount((prevCount) => prevCount - 1),\n []\n ),\n children: /* @__PURE__ */ jsx(\n Primitive.div,\n {\n tabIndex: isTabbingBackOut || focusableItemsCount === 0 ? -1 : 0,\n \"data-orientation\": orientation,\n ...groupProps,\n ref: composedRefs,\n style: { outline: \"none\", ...props.style },\n onMouseDown: composeEventHandlers(props.onMouseDown, () => {\n isClickFocusRef.current = true;\n }),\n onFocus: composeEventHandlers(props.onFocus, (event) => {\n const isKeyboardFocus = !isClickFocusRef.current;\n if (event.target === event.currentTarget && isKeyboardFocus && !isTabbingBackOut) {\n const entryFocusEvent = new CustomEvent(ENTRY_FOCUS, EVENT_OPTIONS);\n event.currentTarget.dispatchEvent(entryFocusEvent);\n if (!entryFocusEvent.defaultPrevented) {\n const items = getItems().filter((item) => item.focusable);\n const activeItem = items.find((item) => item.active);\n const currentItem = items.find((item) => item.id === currentTabStopId);\n const candidateItems = [activeItem, currentItem, ...items].filter(\n Boolean\n );\n const candidateNodes = candidateItems.map((item) => item.ref.current);\n focusFirst(candidateNodes, preventScrollOnEntryFocus);\n }\n }\n isClickFocusRef.current = false;\n }),\n onBlur: composeEventHandlers(props.onBlur, () => setIsTabbingBackOut(false))\n }\n )\n }\n );\n});\nvar ITEM_NAME = \"RovingFocusGroupItem\";\nvar RovingFocusGroupItem = React.forwardRef(\n (props, forwardedRef) => {\n const {\n __scopeRovingFocusGroup,\n focusable = true,\n active = false,\n tabStopId,\n ...itemProps\n } = props;\n const autoId = useId();\n const id = tabStopId || autoId;\n const context = useRovingFocusContext(ITEM_NAME, __scopeRovingFocusGroup);\n const isCurrentTabStop = context.currentTabStopId === id;\n const getItems = useCollection(__scopeRovingFocusGroup);\n const { onFocusableItemAdd, onFocusableItemRemove } = context;\n React.useEffect(() => {\n if (focusable) {\n onFocusableItemAdd();\n return () => onFocusableItemRemove();\n }\n }, [focusable, onFocusableItemAdd, onFocusableItemRemove]);\n return /* @__PURE__ */ jsx(\n Collection.ItemSlot,\n {\n scope: __scopeRovingFocusGroup,\n id,\n focusable,\n active,\n children: /* @__PURE__ */ jsx(\n Primitive.span,\n {\n tabIndex: isCurrentTabStop ? 0 : -1,\n \"data-orientation\": context.orientation,\n ...itemProps,\n ref: forwardedRef,\n onMouseDown: composeEventHandlers(props.onMouseDown, (event) => {\n if (!focusable) event.preventDefault();\n else context.onItemFocus(id);\n }),\n onFocus: composeEventHandlers(props.onFocus, () => context.onItemFocus(id)),\n onKeyDown: composeEventHandlers(props.onKeyDown, (event) => {\n if (event.key === \"Tab\" && event.shiftKey) {\n context.onItemShiftTab();\n return;\n }\n if (event.target !== event.currentTarget) return;\n const focusIntent = getFocusIntent(event, context.orientation, context.dir);\n if (focusIntent !== void 0) {\n if (event.metaKey || event.ctrlKey || event.altKey || event.shiftKey) return;\n event.preventDefault();\n const items = getItems().filter((item) => item.focusable);\n let candidateNodes = items.map((item) => item.ref.current);\n if (focusIntent === \"last\") candidateNodes.reverse();\n else if (focusIntent === \"prev\" || focusIntent === \"next\") {\n if (focusIntent === \"prev\") candidateNodes.reverse();\n const currentIndex = candidateNodes.indexOf(event.currentTarget);\n candidateNodes = context.loop ? wrapArray(candidateNodes, currentIndex + 1) : candidateNodes.slice(currentIndex + 1);\n }\n setTimeout(() => focusFirst(candidateNodes));\n }\n })\n }\n )\n }\n );\n }\n);\nRovingFocusGroupItem.displayName = ITEM_NAME;\nvar MAP_KEY_TO_FOCUS_INTENT = {\n ArrowLeft: \"prev\",\n ArrowUp: \"prev\",\n ArrowRight: \"next\",\n ArrowDown: \"next\",\n PageUp: \"first\",\n Home: \"first\",\n PageDown: \"last\",\n End: \"last\"\n};\nfunction getDirectionAwareKey(key, dir) {\n if (dir !== \"rtl\") return key;\n return key === \"ArrowLeft\" ? \"ArrowRight\" : key === \"ArrowRight\" ? \"ArrowLeft\" : key;\n}\nfunction getFocusIntent(event, orientation, dir) {\n const key = getDirectionAwareKey(event.key, dir);\n if (orientation === \"vertical\" && [\"ArrowLeft\", \"ArrowRight\"].includes(key)) return void 0;\n if (orientation === \"horizontal\" && [\"ArrowUp\", \"ArrowDown\"].includes(key)) return void 0;\n return MAP_KEY_TO_FOCUS_INTENT[key];\n}\nfunction focusFirst(candidates, preventScroll = false) {\n const PREVIOUSLY_FOCUSED_ELEMENT = document.activeElement;\n for (const candidate of candidates) {\n if (candidate === PREVIOUSLY_FOCUSED_ELEMENT) return;\n candidate.focus({ preventScroll });\n if (document.activeElement !== PREVIOUSLY_FOCUSED_ELEMENT) return;\n }\n}\nfunction wrapArray(array, startIndex) {\n return array.map((_, index) => array[(startIndex + index) % array.length]);\n}\nvar Root = RovingFocusGroup;\nvar Item = RovingFocusGroupItem;\nexport {\n Item,\n Root,\n RovingFocusGroup,\n RovingFocusGroupItem,\n createRovingFocusGroupScope\n};\n//# sourceMappingURL=index.mjs.map\n","\"use client\";\n\n// packages/react/tabs/src/Tabs.tsx\nimport * as React from \"react\";\nimport { composeEventHandlers } from \"@radix-ui/primitive\";\nimport { createContextScope } from \"@radix-ui/react-context\";\nimport { createRovingFocusGroupScope } from \"@radix-ui/react-roving-focus\";\nimport { Presence } from \"@radix-ui/react-presence\";\nimport { Primitive } from \"@radix-ui/react-primitive\";\nimport * as RovingFocusGroup from \"@radix-ui/react-roving-focus\";\nimport { useDirection } from \"@radix-ui/react-direction\";\nimport { useControllableState } from \"@radix-ui/react-use-controllable-state\";\nimport { useId } from \"@radix-ui/react-id\";\nimport { jsx } from \"react/jsx-runtime\";\nvar TABS_NAME = \"Tabs\";\nvar [createTabsContext, createTabsScope] = createContextScope(TABS_NAME, [\n createRovingFocusGroupScope\n]);\nvar useRovingFocusGroupScope = createRovingFocusGroupScope();\nvar [TabsProvider, useTabsContext] = createTabsContext(TABS_NAME);\nvar Tabs = React.forwardRef(\n (props, forwardedRef) => {\n const {\n __scopeTabs,\n value: valueProp,\n onValueChange,\n defaultValue,\n orientation = \"horizontal\",\n dir,\n activationMode = \"automatic\",\n ...tabsProps\n } = props;\n const direction = useDirection(dir);\n const [value, setValue] = useControllableState({\n prop: valueProp,\n onChange: onValueChange,\n defaultProp: defaultValue\n });\n return /* @__PURE__ */ jsx(\n TabsProvider,\n {\n scope: __scopeTabs,\n baseId: useId(),\n value,\n onValueChange: setValue,\n orientation,\n dir: direction,\n activationMode,\n children: /* @__PURE__ */ jsx(\n Primitive.div,\n {\n dir: direction,\n \"data-orientation\": orientation,\n ...tabsProps,\n ref: forwardedRef\n }\n )\n }\n );\n }\n);\nTabs.displayName = TABS_NAME;\nvar TAB_LIST_NAME = \"TabsList\";\nvar TabsList = React.forwardRef(\n (props, forwardedRef) => {\n const { __scopeTabs, loop = true, ...listProps } = props;\n const context = useTabsContext(TAB_LIST_NAME, __scopeTabs);\n const rovingFocusGroupScope = useRovingFocusGroupScope(__scopeTabs);\n return /* @__PURE__ */ jsx(\n RovingFocusGroup.Root,\n {\n asChild: true,\n ...rovingFocusGroupScope,\n orientation: context.orientation,\n dir: context.dir,\n loop,\n children: /* @__PURE__ */ jsx(\n Primitive.div,\n {\n role: \"tablist\",\n \"aria-orientation\": context.orientation,\n ...listProps,\n ref: forwardedRef\n }\n )\n }\n );\n }\n);\nTabsList.displayName = TAB_LIST_NAME;\nvar TRIGGER_NAME = \"TabsTrigger\";\nvar TabsTrigger = React.forwardRef(\n (props, forwardedRef) => {\n const { __scopeTabs, value, disabled = false, ...triggerProps } = props;\n const context = useTabsContext(TRIGGER_NAME, __scopeTabs);\n const rovingFocusGroupScope = useRovingFocusGroupScope(__scopeTabs);\n const triggerId = makeTriggerId(context.baseId, value);\n const contentId = makeContentId(context.baseId, value);\n const isSelected = value === context.value;\n return /* @__PURE__ */ jsx(\n RovingFocusGroup.Item,\n {\n asChild: true,\n ...rovingFocusGroupScope,\n focusable: !disabled,\n active: isSelected,\n children: /* @__PURE__ */ jsx(\n Primitive.button,\n {\n type: \"button\",\n role: \"tab\",\n \"aria-selected\": isSelected,\n \"aria-controls\": contentId,\n \"data-state\": isSelected ? \"active\" : \"inactive\",\n \"data-disabled\": disabled ? \"\" : void 0,\n disabled,\n id: triggerId,\n ...triggerProps,\n ref: forwardedRef,\n onMouseDown: composeEventHandlers(props.onMouseDown, (event) => {\n if (!disabled && event.button === 0 && event.ctrlKey === false) {\n context.onValueChange(value);\n } else {\n event.preventDefault();\n }\n }),\n onKeyDown: composeEventHandlers(props.onKeyDown, (event) => {\n if ([\" \", \"Enter\"].includes(event.key)) context.onValueChange(value);\n }),\n onFocus: composeEventHandlers(props.onFocus, () => {\n const isAutomaticActivation = context.activationMode !== \"manual\";\n if (!isSelected && !disabled && isAutomaticActivation) {\n context.onValueChange(value);\n }\n })\n }\n )\n }\n );\n }\n);\nTabsTrigger.displayName = TRIGGER_NAME;\nvar CONTENT_NAME = \"TabsContent\";\nvar TabsContent = React.forwardRef(\n (props, forwardedRef) => {\n const { __scopeTabs, value, forceMount, children, ...contentProps } = props;\n const context = useTabsContext(CONTENT_NAME, __scopeTabs);\n const triggerId = makeTriggerId(context.baseId, value);\n const contentId = makeContentId(context.baseId, value);\n const isSelected = value === context.value;\n const isMountAnimationPreventedRef = React.useRef(isSelected);\n React.useEffect(() => {\n const rAF = requestAnimationFrame(() => isMountAnimationPreventedRef.current = false);\n return () => cancelAnimationFrame(rAF);\n }, []);\n return /* @__PURE__ */ jsx(Presence, { present: forceMount || isSelected, children: ({ present }) => /* @__PURE__ */ jsx(\n Primitive.div,\n {\n \"data-state\": isSelected ? \"active\" : \"inactive\",\n \"data-orientation\": context.orientation,\n role: \"tabpanel\",\n \"aria-labelledby\": triggerId,\n hidden: !present,\n id: contentId,\n tabIndex: 0,\n ...contentProps,\n ref: forwardedRef,\n style: {\n ...props.style,\n animationDuration: isMountAnimationPreventedRef.current ? \"0s\" : void 0\n },\n children: present && children\n }\n ) });\n }\n);\nTabsContent.displayName = CONTENT_NAME;\nfunction makeTriggerId(baseId, value) {\n return `${baseId}-trigger-${value}`;\n}\nfunction makeContentId(baseId, value) {\n return `${baseId}-content-${value}`;\n}\nvar Root2 = Tabs;\nvar List = TabsList;\nvar Trigger = TabsTrigger;\nvar Content = TabsContent;\nexport {\n Content,\n List,\n Root2 as Root,\n Tabs,\n TabsContent,\n TabsList,\n TabsTrigger,\n Trigger,\n createTabsScope\n};\n//# sourceMappingURL=index.mjs.map\n","import { type SerializeFrom } from '@remix-run/node'\nimport { Await, Link, useLoaderData } from '@remix-run/react'\nimport * as React from 'react'\nimport { Icon } from '#app/components/icons.tsx'\nimport { Loading } from '#app/components/loading.tsx'\nimport { useAltDown } from '#app/utils/misc.tsx'\nimport { DiscordCTA, useDiscordCTALink } from '../../../discord.tsx'\nimport { type loader } from '../index.tsx'\n\nexport function DiscordChat() {\n\tconst data = useLoaderData<typeof loader>()\n\treturn (\n\t\t<div className=\"flex h-full w-full flex-col gap-4 pt-4\">\n\t\t\t<div className=\"text-center\">\n\t\t\t\t<DiscordCTA discordAuthUrl={data.discordAuthUrl} />\n\t\t\t</div>\n\t\t\t<div className=\"flex-1 overflow-y-scroll bg-accent pb-4 scrollbar-thin scrollbar-thumb-scrollbar\">\n\t\t\t\t<DiscordPosts />\n\t\t\t</div>\n\t\t</div>\n\t)\n}\n\nfunction DiscordPosts() {\n\tconst data = useLoaderData<typeof loader>()\n\tconst ctaLink = useDiscordCTALink({ discordAuthUrl: data.discordAuthUrl })\n\tconst altDown = useAltDown()\n\treturn (\n\t\t<div className=\"flex h-full flex-col items-center justify-between\">\n\t\t\t<React.Suspense\n\t\t\t\tfallback={\n\t\t\t\t\t<div className=\"flex h-full w-full flex-col items-center justify-center\">\n\t\t\t\t\t\t<Loading>Loading Discord Posts</Loading>\n\t\t\t\t\t</div>\n\t\t\t\t}\n\t\t\t>\n\t\t\t\t<Await\n\t\t\t\t\tresolve={data.discordPostsPromise}\n\t\t\t\t\terrorElement={\n\t\t\t\t\t\t<div className=\"text-red-500\">\n\t\t\t\t\t\t\tThere was a problem loading the discord posts\n\t\t\t\t\t\t</div>\n\t\t\t\t\t}\n\t\t\t\t>\n\t\t\t\t\t{(posts) => (\n\t\t\t\t\t\t<ul className=\"flex w-full flex-col gap-4 p-3 xl:p-12\">\n\t\t\t\t\t\t\t{posts.map((post) => (\n\t\t\t\t\t\t\t\t<li\n\t\t\t\t\t\t\t\t\tkey={post.id}\n\t\t\t\t\t\t\t\t\tclassName=\"rounded-xl border bg-background transition-all duration-200 focus-within:-translate-y-1 focus-within:shadow-lg hover:-translate-y-1 hover:shadow-lg\"\n\t\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t\t<DiscordPost thread={post} />\n\t\t\t\t\t\t\t\t</li>\n\t\t\t\t\t\t\t))}\n\t\t\t\t\t\t</ul>\n\t\t\t\t\t)}\n\t\t\t\t</Await>\n\t\t\t</React.Suspense>\n\t\t\t<div>\n\t\t\t\t<Link\n\t\t\t\t\tto={\n\t\t\t\t\t\taltDown && !ctaLink.includes('oauth')\n\t\t\t\t\t\t\t? ctaLink.replace(/^https/, 'discord')\n\t\t\t\t\t\t\t: ctaLink\n\t\t\t\t\t}\n\t\t\t\t\ttarget={ctaLink.includes('oauth') ? undefined : '_blank'}\n\t\t\t\t\trel=\"noreferrer noopener\"\n\t\t\t\t\tonClick={\n\t\t\t\t\t\taltDown\n\t\t\t\t\t\t\t? (e) => {\n\t\t\t\t\t\t\t\t\te.preventDefault()\n\t\t\t\t\t\t\t\t\twindow.open(\n\t\t\t\t\t\t\t\t\t\te.currentTarget.href,\n\t\t\t\t\t\t\t\t\t\t'_blank',\n\t\t\t\t\t\t\t\t\t\t'noreferrer noopener',\n\t\t\t\t\t\t\t\t\t)\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t: undefined\n\t\t\t\t\t}\n\t\t\t\t\tclassName=\"flex items-center gap-2 p-2 text-xl hover:underline\"\n\t\t\t\t>\n\t\t\t\t\tCreate Post <Icon name=\"ExternalLink\" />\n\t\t\t\t</Link>\n\t\t\t</div>\n\t\t</div>\n\t)\n}\n\nfunction DiscordPost({\n\tthread,\n}: {\n\tthread: Awaited<SerializeFrom<typeof loader>['discordPostsPromise']>[number]\n}) {\n\tconst reactionsWithCounts = thread.reactions.filter((r) => r.count)\n\n\treturn (\n\t\t<div>\n\t\t\t<div className=\"flex flex-col gap-2 p-4\">\n\t\t\t\t<div className=\"flex gap-4\">\n\t\t\t\t\t<div className=\"flex flex-col gap-1\">\n\t\t\t\t\t\t{thread.tags.length ? (\n\t\t\t\t\t\t\t<div className=\"flex gap-2\">\n\t\t\t\t\t\t\t\t{thread.tags.map((t) => (\n\t\t\t\t\t\t\t\t\t<div\n\t\t\t\t\t\t\t\t\t\tkey={t.name}\n\t\t\t\t\t\t\t\t\t\tclassName=\"flex items-center justify-center gap-1 rounded-full bg-accent px-2 py-1 text-sm\"\n\t\t\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t\t\t<span className=\"h-3 w-3 leading-3\">\n\t\t\t\t\t\t\t\t\t\t\t{/* not sure how to fix this one... */}\n\t\t\t\t\t\t\t\t\t\t\t{/* @ts-expect-error */}\n\t\t\t\t\t\t\t\t\t\t\t<Emoji name={t.emojiName} url={t.emojiUrl} />\n\t\t\t\t\t\t\t\t\t\t</span>\n\t\t\t\t\t\t\t\t\t\t<span>{t.name}</span>\n\t\t\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t\t\t))}\n\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t) : null}\n\t\t\t\t\t\t<strong className=\"text-xl font-bold\">{thread.name}</strong>\n\t\t\t\t\t\t<div className=\"flex items-start gap-1\">\n\t\t\t\t\t\t\t<div className=\"flex items-center gap-1\">\n\t\t\t\t\t\t\t\t{thread.authorAvatarUrl ? (\n\t\t\t\t\t\t\t\t\t<img\n\t\t\t\t\t\t\t\t\t\tsrc={thread.authorAvatarUrl}\n\t\t\t\t\t\t\t\t\t\talt=\"\"\n\t\t\t\t\t\t\t\t\t\tclassName=\"h-6 w-6 rounded-full\"\n\t\t\t\t\t\t\t\t\t/>\n\t\t\t\t\t\t\t\t) : null}\n\t\t\t\t\t\t\t\t<span>\n\t\t\t\t\t\t\t\t\t<span\n\t\t\t\t\t\t\t\t\t\tclassName=\"font-bold\"\n\t\t\t\t\t\t\t\t\t\tstyle={\n\t\t\t\t\t\t\t\t\t\t\tthread.authorHexAccentColor\n\t\t\t\t\t\t\t\t\t\t\t\t? { color: thread.authorHexAccentColor }\n\t\t\t\t\t\t\t\t\t\t\t\t: {}\n\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t\t\t{thread.authorDisplayName}\n\t\t\t\t\t\t\t\t\t</span>\n\t\t\t\t\t\t\t\t\t:{' '}\n\t\t\t\t\t\t\t\t</span>\n\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t\t<span className=\"flex-1 overflow-ellipsis text-muted-foreground\">\n\t\t\t\t\t\t\t\t{thread.messagePreview}\n\t\t\t\t\t\t\t</span>\n\t\t\t\t\t\t</div>\n\t\t\t\t\t</div>\n\t\t\t\t\t{thread.previewImageUrl ? (\n\t\t\t\t\t\t<img\n\t\t\t\t\t\t\tsrc={thread.previewImageUrl}\n\t\t\t\t\t\t\talt=\"\"\n\t\t\t\t\t\t\tclassName=\"h-28 w-28 rounded-lg object-cover\"\n\t\t\t\t\t\t/>\n\t\t\t\t\t) : null}\n\t\t\t\t</div>\n\n\t\t\t\t<div className=\"flex justify-between\">\n\t\t\t\t\t<div className=\"flex items-center gap-3\">\n\t\t\t\t\t\t<span>\n\t\t\t\t\t\t\t{reactionsWithCounts.length ? (\n\t\t\t\t\t\t\t\t<ul className=\"flex items-center gap-2\">\n\t\t\t\t\t\t\t\t\t{reactionsWithCounts.map((r, i) => (\n\t\t\t\t\t\t\t\t\t\t<li\n\t\t\t\t\t\t\t\t\t\t\tkey={i}\n\t\t\t\t\t\t\t\t\t\t\tclassName=\"flex items-center gap-1 rounded-md border border-blue-600 bg-blue-500/20 px-[5px] py-[0.5px] text-sm\"\n\t\t\t\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t\t\t\t<span className=\"h-3 w-3 leading-3\">\n\t\t\t\t\t\t\t\t\t\t\t\t{/* not sure how to fix this one... */}\n\t\t\t\t\t\t\t\t\t\t\t\t{/* @ts-expect-error */}\n\t\t\t\t\t\t\t\t\t\t\t\t<Emoji name={r.emojiName} url={r.emojiUrl} />\n\t\t\t\t\t\t\t\t\t\t\t</span>\n\t\t\t\t\t\t\t\t\t\t\t<span>{r.count}</span>\n\t\t\t\t\t\t\t\t\t\t</li>\n\t\t\t\t\t\t\t\t\t))}\n\t\t\t\t\t\t\t\t</ul>\n\t\t\t\t\t\t\t) : null}\n\t\t\t\t\t\t</span>\n\t\t\t\t\t\t<span className=\"flex items-center gap-1\">\n\t\t\t\t\t\t\t<span className=\"inline-flex items-center gap-1\">\n\t\t\t\t\t\t\t\t<Icon name=\"Chat\" /> {thread.messageCount}\n\t\t\t\t\t\t\t</span>\n\t\t\t\t\t\t\t{` · ${thread.lastUpdatedDisplay}`}\n\t\t\t\t\t\t</span>\n\t\t\t\t\t</div>\n\t\t\t\t\t<span className=\"flex items-center gap-4\">\n\t\t\t\t\t\t<a href={thread.link.replace(/^https/, 'discord')}>\n\t\t\t\t\t\t\t<Icon name=\"Discord\" />\n\t\t\t\t\t\t</a>\n\t\t\t\t\t\t<a href={thread.link} target=\"_blank\" rel=\"noreferrer noopener\">\n\t\t\t\t\t\t\t<Icon name=\"ExternalLink\" />\n\t\t\t\t\t\t</a>\n\t\t\t\t\t</span>\n\t\t\t\t</div>\n\t\t\t</div>\n\t\t</div>\n\t)\n}\n\nfunction Emoji({ name, url }: { name?: string; url?: string }) {\n\treturn url ? (\n\t\t<img src={url} alt={name} className=\"h-full w-full\" />\n\t) : name ? (\n\t\tname\n\t) : null\n}\n","import { toast as showToast } from 'sonner'\nimport { type InBrowserBrowserRef } from '#app/components/in-browser-browser'\nimport { SimpleTooltip } from '#app/components/ui/tooltip'\nimport { SetAppToPlayground } from '#app/routes/set-playground'\nimport { PlaygroundWindow } from './playground-window'\nimport { Preview } from './preview'\n\nexport function Playground({\n\tappInfo: playgroundAppInfo,\n\tinBrowserBrowserRef,\n\tproblemAppName,\n\tallApps,\n\tisUpToDate,\n}: {\n\tappInfo: Parameters<typeof Preview>['0']['appInfo'] | null\n\tinBrowserBrowserRef: React.RefObject<InBrowserBrowserRef | null>\n\tproblemAppName?: string\n\tallApps: Array<{ name: string; displayName: string }>\n\tisUpToDate: boolean\n}) {\n\treturn (\n\t\t<PlaygroundWindow\n\t\t\tplaygroundAppName={playgroundAppInfo?.appName}\n\t\t\tproblemAppName={problemAppName}\n\t\t\tallApps={allApps}\n\t\t\tisUpToDate={isUpToDate}\n\t\t>\n\t\t\t{playgroundAppInfo?.dev.type === 'none' ? (\n\t\t\t\t<div>\n\t\t\t\t\t<div className=\"text-foreground-secondary flex h-full items-center justify-center text-2xl\">\n\t\t\t\t\t\tNon-UI playground\n\t\t\t\t\t</div>\n\t\t\t\t\t<div>\n\t\t\t\t\t\t<div className=\"text-foreground-secondary flex flex-wrap gap-1 text-center\">\n\t\t\t\t\t\t\tNavigate to{' '}\n\t\t\t\t\t\t\t<SimpleTooltip content={playgroundAppInfo.fullPath}>\n\t\t\t\t\t\t\t\t<span\n\t\t\t\t\t\t\t\t\tclassName=\"underline\"\n\t\t\t\t\t\t\t\t\tonClick={() => {\n\t\t\t\t\t\t\t\t\t\tvoid navigator.clipboard.writeText(\n\t\t\t\t\t\t\t\t\t\t\tplaygroundAppInfo.fullPath,\n\t\t\t\t\t\t\t\t\t\t)\n\t\t\t\t\t\t\t\t\t\tshowToast.success('Copied playground path to clipboard')\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\tthe playground directory\n\t\t\t\t\t\t\t\t</span>\n\t\t\t\t\t\t\t</SimpleTooltip>{' '}\n\t\t\t\t\t\t\tin your editor and terminal to work on this exercise!\n\t\t\t\t\t\t</div>\n\t\t\t\t\t</div>\n\t\t\t\t</div>\n\t\t\t) : playgroundAppInfo ? (\n\t\t\t\t<Preview\n\t\t\t\t\tid={playgroundAppInfo.appName}\n\t\t\t\t\tappInfo={playgroundAppInfo}\n\t\t\t\t\tinBrowserBrowserRef={inBrowserBrowserRef}\n\t\t\t\t/>\n\t\t\t) : (\n\t\t\t\t<div className=\"flex flex-col justify-center gap-2\">\n\t\t\t\t\t<p>Please set the playground first</p>\n\t\t\t\t\t{problemAppName ? (\n\t\t\t\t\t\t<SetAppToPlayground appName={problemAppName} />\n\t\t\t\t\t) : null}\n\t\t\t\t</div>\n\t\t\t)}\n\t\t</PlaygroundWindow>\n\t)\n}\n","import {\n\tgetAppByName,\n\tgetAppDisplayName,\n\tgetApps,\n\tgetExerciseApp,\n\tisExerciseStepApp,\n\tisPlaygroundApp,\n\trequireExerciseApp,\n\ttype App,\n\ttype ExerciseStepApp,\n} from '@epic-web/workshop-utils/apps.server'\nimport { compileMarkdownString } from '@epic-web/workshop-utils/compile-mdx.server'\nimport {\n\tcombineServerTimings,\n\tgetServerTimeHeader,\n\tmakeTimings,\n} from '@epic-web/workshop-utils/timing.server'\nimport * as Tabs from '@radix-ui/react-tabs'\nimport {\n\tdefer,\n\tredirect,\n\ttype HeadersFunction,\n\ttype LoaderFunctionArgs,\n} from '@remix-run/node'\nimport {\n\tLink,\n\tuseLoaderData,\n\tuseNavigate,\n\tuseSearchParams,\n} from '@remix-run/react'\nimport { clsx } from 'clsx'\nimport * as React from 'react'\nimport { useRef } from 'react'\nimport { Diff } from '#app/components/diff.tsx'\nimport { GeneralErrorBoundary } from '#app/components/error-boundary.tsx'\nimport { type InBrowserBrowserRef } from '#app/components/in-browser-browser.tsx'\nimport { getDiscordAuthURL } from '#app/routes/discord.callback.ts'\nimport { getDiffCode } from '#app/utils/diff.server.ts'\nimport { userHasAccessToWorkshop } from '#app/utils/epic-api.js'\nimport { useAltDown } from '#app/utils/misc.tsx'\nimport { fetchDiscordPosts } from './__shared/discord.server.ts'\nimport { DiscordChat } from './__shared/discord.tsx'\nimport { Playground } from './__shared/playground.tsx'\nimport { Preview } from './__shared/preview.tsx'\nimport { Tests } from './__shared/tests.tsx'\nimport { getAppRunningState } from './__shared/utils.tsx'\n\nexport async function loader({ request, params }: LoaderFunctionArgs) {\n\tconst timings = makeTimings('exerciseStepTypeIndexLoader')\n\tconst userHasAccess = await userHasAccessToWorkshop({\n\t\trequest,\n\t\ttimings,\n\t})\n\tconst searchParams = new URL(request.url).searchParams\n\tconst cacheOptions = { request, timings }\n\tconst exerciseStepApp = await requireExerciseApp(params, cacheOptions)\n\tconst reqUrl = new URL(request.url)\n\n\tconst pathnameParam = reqUrl.searchParams.get('pathname')\n\tif (pathnameParam === '' || pathnameParam === '/') {\n\t\treqUrl.searchParams.delete('pathname')\n\t\tthrow redirect(reqUrl.toString())\n\t}\n\n\tconst problemApp = await getExerciseApp(\n\t\t{ ...params, type: 'problem' },\n\t\tcacheOptions,\n\t)\n\tconst solutionApp = await getExerciseApp(\n\t\t{ ...params, type: 'solution' },\n\t\tcacheOptions,\n\t)\n\n\tif (!problemApp && !solutionApp) {\n\t\tthrow new Response('Not found', { status: 404 })\n\t}\n\n\tconst allAppsFull = await getApps(cacheOptions)\n\tconst playgroundApp = allAppsFull.find(isPlaygroundApp)\n\n\tconst app1Name = reqUrl.searchParams.get('app1')\n\tconst app2Name = reqUrl.searchParams.get('app2')\n\tconst app1 = app1Name\n\t\t? await getAppByName(app1Name)\n\t\t: playgroundApp || problemApp\n\tconst app2 = app2Name ? await getAppByName(app2Name) : solutionApp\n\n\tfunction getStepId(a: ExerciseStepApp) {\n\t\treturn (\n\t\t\ta.exerciseNumber * 1000 +\n\t\t\ta.stepNumber * 10 +\n\t\t\t(a.type === 'problem' ? 0 : 1)\n\t\t)\n\t}\n\n\tfunction getStepNameAndId(a: App) {\n\t\tif (isExerciseStepApp(a)) {\n\t\t\tconst exerciseNumberStr = String(a.exerciseNumber).padStart(2, '0')\n\t\t\tconst stepNumberStr = String(a.stepNumber).padStart(2, '0')\n\n\t\t\treturn {\n\t\t\t\tstepName: `${exerciseNumberStr}/${stepNumberStr}.${a.type}`,\n\t\t\t\tstepId: getStepId(a),\n\t\t\t}\n\t\t}\n\t\treturn { stepName: '', stepId: -1 }\n\t}\n\n\tconst allApps = allAppsFull\n\t\t.filter((a, i, ar) => ar.findIndex((b) => a.name === b.name) === i)\n\t\t.map((a) => ({\n\t\t\tdisplayName: getAppDisplayName(a, allAppsFull),\n\t\t\tname: a.name,\n\t\t\ttitle: a.title,\n\t\t\ttype: a.type,\n\t\t\t...getStepNameAndId(a),\n\t\t}))\n\n\tallApps.sort((a, b) => {\n\t\t// order them by their stepId\n\t\tif (a.stepId > 0 && b.stepId > 0) return a.stepId - b.stepId\n\n\t\t// non-step apps should come after step apps\n\t\tif (a.stepId > 0) return -1\n\t\tif (b.stepId > 0) return 1\n\n\t\treturn 0\n\t})\n\n\tasync function getDiffProp() {\n\t\tif (!app1 || !app2) {\n\t\t\treturn {\n\t\t\t\tapp1: app1?.name,\n\t\t\t\tapp2: app2?.name,\n\t\t\t\tdiffCode: null,\n\t\t\t}\n\t\t}\n\t\tif (!userHasAccess) {\n\t\t\treturn {\n\t\t\t\tapp1: app1?.name,\n\t\t\t\tapp2: app2?.name,\n\t\t\t\tdiffCode: await compileMarkdownString(\n\t\t\t\t\t`<h1>Access Denied</h1><p>You must login or register for the workshop to view the diff</p>`,\n\t\t\t\t),\n\t\t\t}\n\t\t}\n\t\tconst diffCode = await getDiffCode(app1, app2, {\n\t\t\t...cacheOptions,\n\t\t\tforceFresh: searchParams.get('forceFresh') === 'diff',\n\t\t}).catch((e) => {\n\t\t\tconsole.error(e)\n\t\t\treturn null\n\t\t})\n\t\treturn {\n\t\t\tapp1: app1.name,\n\t\t\tapp2: app2.name,\n\t\t\tdiffCode,\n\t\t}\n\t}\n\n\treturn defer(\n\t\t{\n\t\t\ttype: params.type as 'problem' | 'solution',\n\t\t\texerciseStepApp,\n\t\t\tallApps,\n\t\t\tdiscordAuthUrl: getDiscordAuthURL(),\n\t\t\t// defer this promise so that we don't block the response from being sent\n\t\t\tdiscordPostsPromise: fetchDiscordPosts({ request }),\n\t\t\tplayground: playgroundApp\n\t\t\t\t? ({\n\t\t\t\t\t\ttype: 'playground',\n\t\t\t\t\t\tfullPath: playgroundApp.fullPath,\n\t\t\t\t\t\tdev: playgroundApp.dev,\n\t\t\t\t\t\ttest: playgroundApp.test,\n\t\t\t\t\t\ttitle: playgroundApp.title,\n\t\t\t\t\t\tname: playgroundApp.name,\n\t\t\t\t\t\tappName: playgroundApp.appName,\n\t\t\t\t\t\tisUpToDate: playgroundApp.isUpToDate,\n\t\t\t\t\t\tstackBlitzUrl: playgroundApp.stackBlitzUrl,\n\t\t\t\t\t\t...(await getAppRunningState(playgroundApp)),\n\t\t\t\t\t} as const)\n\t\t\t\t: null,\n\t\t\tproblem: problemApp\n\t\t\t\t? ({\n\t\t\t\t\t\ttype: 'problem',\n\t\t\t\t\t\tfullPath: problemApp.fullPath,\n\t\t\t\t\t\tdev: problemApp.dev,\n\t\t\t\t\t\ttest: problemApp.test,\n\t\t\t\t\t\ttitle: problemApp.title,\n\t\t\t\t\t\tname: problemApp.name,\n\t\t\t\t\t\tstackBlitzUrl: problemApp.stackBlitzUrl,\n\t\t\t\t\t\t...(await getAppRunningState(problemApp)),\n\t\t\t\t\t} as const)\n\t\t\t\t: null,\n\t\t\tsolution: solutionApp\n\t\t\t\t? ({\n\t\t\t\t\t\ttype: 'solution',\n\t\t\t\t\t\tfullPath: solutionApp.fullPath,\n\t\t\t\t\t\tdev: solutionApp.dev,\n\t\t\t\t\t\ttest: solutionApp.test,\n\t\t\t\t\t\ttitle: solutionApp.title,\n\t\t\t\t\t\tname: solutionApp.name,\n\t\t\t\t\t\tstackBlitzUrl: solutionApp.stackBlitzUrl,\n\t\t\t\t\t\t...(await getAppRunningState(solutionApp)),\n\t\t\t\t\t} as const)\n\t\t\t\t: null,\n\t\t\tdiff: getDiffProp(),\n\t\t} as const,\n\t\t{\n\t\t\theaders: {\n\t\t\t\t'Server-Timing': getServerTimeHeader(timings),\n\t\t\t},\n\t\t},\n\t)\n}\n\nexport const headers: HeadersFunction = ({ loaderHeaders, parentHeaders }) => {\n\tconst headers = {\n\t\t'Server-Timing': combineServerTimings(loaderHeaders, parentHeaders),\n\t}\n\treturn headers\n}\n\nconst tabs = [\n\t'playground',\n\t'problem',\n\t'solution',\n\t'tests',\n\t'diff',\n\t'chat',\n] as const\nconst isValidPreview = (s: string | null): s is (typeof tabs)[number] =>\n\tBoolean(s && tabs.includes(s as (typeof tabs)[number]))\n\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\nexport default function ExercisePartRoute() {\n\tconst data = useLoaderData<typeof loader>()\n\tconst [searchParams] = useSearchParams()\n\n\tconst preview = searchParams.get('preview')\n\tconst inBrowserBrowserRef = useRef<InBrowserBrowserRef>(null)\n\n\tconst altDown = useAltDown()\n\tconst navigate = useNavigate()\n\n\tfunction shouldHideTab(tab: (typeof tabs)[number]) {\n\t\tif (tab === 'tests') {\n\t\t\treturn (\n\t\t\t\tENV.EPICSHOP_DEPLOYED ||\n\t\t\t\t!data.playground ||\n\t\t\t\tdata.playground.test.type === 'none'\n\t\t\t)\n\t\t}\n\t\tif (tab === 'problem' || tab === 'solution') {\n\t\t\tif (data[tab]?.dev.type === 'none') return true\n\t\t\tif (ENV.EPICSHOP_DEPLOYED) {\n\t\t\t\treturn data[tab]?.dev.type !== 'browser' && !data[tab]?.stackBlitzUrl\n\t\t\t}\n\t\t}\n\t\tif (tab === 'playground' && ENV.EPICSHOP_DEPLOYED) return true\n\t\treturn false\n\t}\n\n\tconst activeTab = isValidPreview(preview)\n\t\t? preview\n\t\t: tabs.find((t) => !shouldHideTab(t))\n\n\t// when alt is held down, the diff tab should open to the full-page diff view\n\t// between the problem and solution (this is more for the instructor than the student)\n\tconst altDiffUrl = `/diff?${new URLSearchParams({\n\t\tapp1: data.problem?.name ?? '',\n\t\tapp2: data.solution?.name ?? '',\n\t})}`\n\n\tfunction handleDiffTabClick(event: React.MouseEvent<HTMLAnchorElement>) {\n\t\tif (event.altKey && !event.ctrlKey && !event.shiftKey && !event.metaKey) {\n\t\t\tevent.preventDefault()\n\t\t\tnavigate(altDiffUrl)\n\t\t}\n\t}\n\n\treturn (\n\t\t<Tabs.Root\n\t\t\tclassName=\"relative flex flex-col overflow-y-auto sm:col-span-1 sm:row-span-1\"\n\t\t\tvalue={activeTab}\n\t\t\t// intentionally no onValueChange here because the Link will trigger the\n\t\t\t// change.\n\t\t>\n\t\t\t<Tabs.List className=\"h-14 min-h-14 overflow-x-hidden border-b scrollbar-thin scrollbar-thumb-scrollbar\">\n\t\t\t\t{tabs.map((tab) => {\n\t\t\t\t\tconst hidden = shouldHideTab(tab)\n\t\t\t\t\treturn (\n\t\t\t\t\t\t<Tabs.Trigger key={tab} value={tab} hidden={hidden} asChild>\n\t\t\t\t\t\t\t<Link\n\t\t\t\t\t\t\t\tid={`${tab}-tab`}\n\t\t\t\t\t\t\t\tclassName={clsx(\n\t\t\t\t\t\t\t\t\t'clip-path-button relative h-full px-6 py-4 font-mono text-sm uppercase outline-none radix-state-active:z-10 radix-state-active:bg-foreground radix-state-active:text-background radix-state-active:hover:bg-foreground/80 radix-state-active:hover:text-background/80 radix-state-inactive:hover:bg-foreground/20 radix-state-inactive:hover:text-foreground/80 focus:bg-foreground/80 focus:text-background/80',\n\t\t\t\t\t\t\t\t\thidden ? 'hidden' : 'inline-block',\n\t\t\t\t\t\t\t\t)}\n\t\t\t\t\t\t\t\tpreventScrollReset\n\t\t\t\t\t\t\t\tprefetch=\"intent\"\n\t\t\t\t\t\t\t\tonClick={handleDiffTabClick}\n\t\t\t\t\t\t\t\tto={\n\t\t\t\t\t\t\t\t\ttab === 'diff' && altDown\n\t\t\t\t\t\t\t\t\t\t? altDiffUrl\n\t\t\t\t\t\t\t\t\t\t: `?${withParam(\n\t\t\t\t\t\t\t\t\t\t\t\tsearchParams,\n\t\t\t\t\t\t\t\t\t\t\t\t'preview',\n\t\t\t\t\t\t\t\t\t\t\t\ttab === 'playground' ? null : tab,\n\t\t\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>\n\t\t\t\t\t\t\t\t{tab}\n\t\t\t\t\t\t\t</Link>\n\t\t\t\t\t\t</Tabs.Trigger>\n\t\t\t\t\t)\n\t\t\t\t})}\n\t\t\t</Tabs.List>\n\t\t\t<div className=\"relative z-10 flex min-h-96 flex-grow flex-col overflow-y-auto\">\n\t\t\t\t<Tabs.Content\n\t\t\t\t\tvalue=\"playground\"\n\t\t\t\t\tclassName=\"flex w-full flex-grow items-center justify-center self-start radix-state-inactive:hidden\"\n\t\t\t\t>\n\t\t\t\t\t<Playground\n\t\t\t\t\t\tappInfo={data.playground}\n\t\t\t\t\t\tproblemAppName={data.problem?.name}\n\t\t\t\t\t\tinBrowserBrowserRef={inBrowserBrowserRef}\n\t\t\t\t\t\tallApps={data.allApps}\n\t\t\t\t\t\tisUpToDate={data.playground?.isUpToDate ?? false}\n\t\t\t\t\t/>\n\t\t\t\t</Tabs.Content>\n\t\t\t\t<Tabs.Content\n\t\t\t\t\tvalue=\"problem\"\n\t\t\t\t\tclassName=\"flex w-full flex-grow items-center justify-center self-start radix-state-inactive:hidden\"\n\t\t\t\t>\n\t\t\t\t\t<Preview\n\t\t\t\t\t\tappInfo={data.problem}\n\t\t\t\t\t\tinBrowserBrowserRef={inBrowserBrowserRef}\n\t\t\t\t\t/>\n\t\t\t\t</Tabs.Content>\n\t\t\t\t<Tabs.Content\n\t\t\t\t\tvalue=\"solution\"\n\t\t\t\t\tclassName=\"flex w-full flex-grow items-center justify-center self-start radix-state-inactive:hidden\"\n\t\t\t\t>\n\t\t\t\t\t<Preview\n\t\t\t\t\t\tappInfo={data.solution}\n\t\t\t\t\t\tinBrowserBrowserRef={inBrowserBrowserRef}\n\t\t\t\t\t/>\n\t\t\t\t</Tabs.Content>\n\t\t\t\t<Tabs.Content\n\t\t\t\t\tvalue=\"tests\"\n\t\t\t\t\tclassName=\"flex w-full flex-grow items-start justify-center self-start overflow-hidden radix-state-inactive:hidden\"\n\t\t\t\t>\n\t\t\t\t\t<Tests\n\t\t\t\t\t\tappInfo={data.playground}\n\t\t\t\t\t\tproblemAppName={data.problem?.name}\n\t\t\t\t\t\tallApps={data.allApps}\n\t\t\t\t\t\tisUpToDate={data.playground?.isUpToDate ?? false}\n\t\t\t\t\t/>\n\t\t\t\t</Tabs.Content>\n\t\t\t\t<Tabs.Content\n\t\t\t\t\tvalue=\"diff\"\n\t\t\t\t\tclassName=\"flex h-full w-full flex-grow items-start justify-center self-start radix-state-inactive:hidden\"\n\t\t\t\t>\n\t\t\t\t\t<Diff diff={data.diff} allApps={data.allApps} />\n\t\t\t\t</Tabs.Content>\n\t\t\t\t<Tabs.Content\n\t\t\t\t\tvalue=\"chat\"\n\t\t\t\t\tclassName=\"flex h-full w-full flex-grow items-start justify-center self-start radix-state-inactive:hidden\"\n\t\t\t\t>\n\t\t\t\t\t<DiscordChat />\n\t\t\t\t</Tabs.Content>\n\t\t\t</div>\n\t\t</Tabs.Root>\n\t)\n}\n\nexport function ErrorBoundary() {\n\treturn (\n\t\t<GeneralErrorBoundary\n\t\t\tstatusHandlers={{\n\t\t\t\t404: () => <p>Sorry, we couldn't find an app here.</p>,\n\t\t\t}}\n\t\t/>\n\t)\n}\n"],"names":["createContextScope","scopeName","createContextScopeDeps","defaultContexts","createContext3","rootComponentName","defaultContext","BaseContext","React.createContext","index","Provider","props","scope","children","context","Context","value","React.useMemo","jsx","useContext2","consumerName","React.useContext","createScope","scopeContexts","contexts","composeContextScopes","scopes","baseScope","scopeHooks","createScope2","overrideScopes","nextScopes","nextScopes2","useScope","currentScope","ENTRY_FOCUS","EVENT_OPTIONS","GROUP_NAME","Collection","useCollection","createCollectionScope","createCollection","createRovingFocusGroupContext","createRovingFocusGroupScope","RovingFocusProvider","useRovingFocusContext","RovingFocusGroup","React.forwardRef","forwardedRef","RovingFocusGroupImpl","__scopeRovingFocusGroup","orientation","loop","dir","currentTabStopIdProp","defaultCurrentTabStopId","onCurrentTabStopIdChange","onEntryFocus","preventScrollOnEntryFocus","groupProps","ref","React.useRef","composedRefs","useComposedRefs","direction","useDirection","currentTabStopId","setCurrentTabStopId","useControllableState","isTabbingBackOut","setIsTabbingBackOut","React.useState","handleEntryFocus","useCallbackRef","getItems","isClickFocusRef","focusableItemsCount","setFocusableItemsCount","React.useEffect","node","React.useCallback","tabStopId","prevCount","Primitive","composeEventHandlers","event","isKeyboardFocus","entryFocusEvent","items","item","activeItem","currentItem","candidateNodes","focusFirst","ITEM_NAME","RovingFocusGroupItem","focusable","active","itemProps","autoId","useId","id","isCurrentTabStop","onFocusableItemAdd","onFocusableItemRemove","focusIntent","getFocusIntent","currentIndex","wrapArray","MAP_KEY_TO_FOCUS_INTENT","getDirectionAwareKey","key","candidates","preventScroll","PREVIOUSLY_FOCUSED_ELEMENT","candidate","array","startIndex","_","Root","Item","TABS_NAME","createTabsContext","createTabsScope","useRovingFocusGroupScope","TabsProvider","useTabsContext","Tabs","__scopeTabs","valueProp","onValueChange","defaultValue","activationMode","tabsProps","setValue","TAB_LIST_NAME","TabsList","listProps","rovingFocusGroupScope","RovingFocusGroup.Root","TRIGGER_NAME","TabsTrigger","disabled","triggerProps","triggerId","makeTriggerId","contentId","makeContentId","isSelected","RovingFocusGroup.Item","isAutomaticActivation","CONTENT_NAME","TabsContent","forceMount","contentProps","isMountAnimationPreventedRef","rAF","Presence","present","baseId","Root2","List","Trigger","Content","DiscordChat","data","useLoaderData","jsxs","DiscordCTA","DiscordPosts","ctaLink","useDiscordCTALink","altDown","useAltDown","React.Suspense","Loading","Await","posts","post","DiscordPost","Link","e","Icon","thread","reactionsWithCounts","t","Emoji","i","name","url","Playground","playgroundAppInfo","inBrowserBrowserRef","problemAppName","allApps","isUpToDate","PlaygroundWindow","SimpleTooltip","showToast","Preview","SetAppToPlayground","tabs","isValidPreview","s","Boolean","includes","withParam","searchParams","newSearchParams","URLSearchParams","delete","set","ExercisePartRoute","useSearchParams","preview","get","useRef","navigate","useNavigate","shouldHideTab","tab","ENV","EPICSHOP_DEPLOYED","playground","test","type","dev","stackBlitzUrl","activeTab","find","altDiffUrl","app1","problem","app2","solution","handleDiffTabClick","altKey","ctrlKey","shiftKey","metaKey","preventDefault","className","map","hidden","asChild","clsx","preventScrollReset","prefetch","onClick","to","appInfo","Tests","Diff","diff","ErrorBoundary","GeneralErrorBoundary","statusHandlers"],"mappings":"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","x_google_ignoreList":[0,1,2]}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"index-KgMLc41c.js","sources":["../../../app/routes/_app+/index.tsx"],"sourcesContent":["import { ElementScrollRestoration } from '@epic-web/restore-scroll'\nimport {\n\tgetExercises,\n\tgetWorkshopInstructions,\n} from '@epic-web/workshop-utils/apps.server'\nimport { getWorkshopConfig } from '@epic-web/workshop-utils/config.server'\nimport {\n\tcombineServerTimings,\n\tgetServerTimeHeader,\n\tmakeTimings,\n\ttime,\n} from '@epic-web/workshop-utils/timing.server'\nimport {\n\tdefer,\n\ttype HeadersFunction,\n\ttype LoaderFunctionArgs,\n\ttype SerializeFrom,\n} from '@remix-run/node'\nimport { Link, useLoaderData } from '@remix-run/react'\nimport slugify from '@sindresorhus/slugify'\nimport { EpicVideoInfoProvider } from '#app/components/epic-video.tsx'\nimport { GeneralErrorBoundary } from '#app/components/error-boundary.tsx'\nimport { EditFileOnGitHub } from '#app/routes/launch-editor.tsx'\nimport { getEpicVideoInfos } from '#app/utils/epic-api.ts'\nimport { Mdx } from '#app/utils/mdx.tsx'\nimport { cn } from '#app/utils/misc.tsx'\nimport { ProgressToggle, useExerciseProgressClassName } from '../progress.tsx'\n\nexport async function loader({ request }: LoaderFunctionArgs) {\n\tconst timings = makeTimings('indexLoader')\n\tconst { title } = getWorkshopConfig()\n\tconst [exercises, workshopReadme] = await Promise.all([\n\t\ttime(() => getExercises({ request, timings }), {\n\t\t\ttimings,\n\t\t\ttype: 'getExercises',\n\t\t\tdesc: 'getExercises in index',\n\t\t}),\n\t\ttime(() => getWorkshopInstructions({ request }), {\n\t\t\ttimings,\n\t\t\ttype: 'compileMdx',\n\t\t\tdesc: 'compileMdx in index',\n\t\t}),\n\t])\n\n\treturn defer(\n\t\t{\n\t\t\tarticleId: `workshop-${slugify(title)}-instructions`,\n\t\t\ttitle:\n\t\t\t\tworkshopReadme.compiled.status === 'success'\n\t\t\t\t\t? workshopReadme.compiled.title\n\t\t\t\t\t: title,\n\t\t\texercises: exercises.map((e) => ({\n\t\t\t\texerciseNumber: e.exerciseNumber,\n\t\t\t\ttitle: e.title,\n\t\t\t})),\n\t\t\tworkshopReadme,\n\t\t\tepicVideoInfosPromise:\n\t\t\t\tworkshopReadme.compiled.status === 'success'\n\t\t\t\t\t? getEpicVideoInfos(workshopReadme.compiled.epicVideoEmbeds, {\n\t\t\t\t\t\t\trequest,\n\t\t\t\t\t\t})\n\t\t\t\t\t: null,\n\t\t},\n\t\t{\n\t\t\theaders: {\n\t\t\t\t'Server-Timing': getServerTimeHeader(timings),\n\t\t\t},\n\t\t},\n\t)\n}\n\nexport const headers: HeadersFunction = ({ loaderHeaders, parentHeaders }) => {\n\tconst headers = {\n\t\t'Cache-Control': loaderHeaders.get('Cache-Control') ?? '',\n\t\t'Server-Timing': combineServerTimings(loaderHeaders, parentHeaders),\n\t}\n\treturn headers\n}\n\nfunction ExerciseListItem({\n\texercise,\n}: {\n\texercise: SerializeFrom<typeof loader>['exercises'][number]\n}) {\n\tconst progressClassName = useExerciseProgressClassName(\n\t\texercise.exerciseNumber,\n\t)\n\treturn (\n\t\t<li key={exercise.exerciseNumber}>\n\t\t\t<Link\n\t\t\t\tclassName={cn(\n\t\t\t\t\t\"relative flex items-center gap-4 px-4 py-3 text-lg font-semibold transition after:absolute after:right-10 after:-translate-x-2 after:opacity-0 after:transition after:content-['→'] hover:bg-gray-50 hover:after:translate-x-0 hover:after:opacity-100 dark:hover:bg-white/5\",\n\t\t\t\t\tprogressClassName,\n\t\t\t\t)}\n\t\t\t\tto={`${exercise.exerciseNumber.toString().padStart(2, '0')}`}\n\t\t\t>\n\t\t\t\t<span className=\"text-xs font-normal tabular-nums opacity-50\">\n\t\t\t\t\t{exercise.exerciseNumber}\n\t\t\t\t</span>\n\t\t\t\t<span>{exercise.title}</span>\n\t\t\t</Link>\n\t\t</li>\n\t)\n}\n\nconst mdxComponents = { h1: () => null }\n\nexport default function Index() {\n\tconst data = useLoaderData<typeof loader>()\n\n\tconst exerciseLinks = (\n\t\t<ul className=\"flex flex-col divide-y divide-border dark:divide-border/50\">\n\t\t\t<strong className=\"px-10 pb-3 font-mono text-xs uppercase\">\n\t\t\t\tExercises\n\t\t\t</strong>\n\t\t\t{data.exercises.map((exercise) => (\n\t\t\t\t<ExerciseListItem key={exercise.exerciseNumber} exercise={exercise} />\n\t\t\t))}\n\t\t</ul>\n\t)\n\treturn (\n\t\t<main className=\"relative flex h-full w-full max-w-5xl flex-col justify-between border-r md:w-3/4 xl:w-2/3\">\n\t\t\t<article\n\t\t\t\tid={data.articleId}\n\t\t\t\tclassName=\"shadow-on-scrollbox flex w-full flex-1 flex-col gap-12 overflow-y-scroll px-3 py-4 pt-6 scrollbar-thin scrollbar-thumb-scrollbar md:px-10 md:py-12 md:pt-16\"\n\t\t\t>\n\t\t\t\t<div>\n\t\t\t\t\t<h1 className=\"px-10 text-[clamp(3rem,6vw,7.5rem)] font-extrabold leading-none\">\n\t\t\t\t\t\t{data.title}\n\t\t\t\t\t</h1>\n\t\t\t\t</div>\n\t\t\t\t<div className=\"w-full max-w-none scroll-pt-6 border-t px-3 pt-3 md:px-10 md:pt-8\">\n\t\t\t\t\t<h2 className=\"pb-5 font-mono text-xs font-semibold uppercase\">\n\t\t\t\t\t\tIntro\n\t\t\t\t\t</h2>\n\t\t\t\t\t{data.workshopReadme.compiled.status === 'success' &&\n\t\t\t\t\tdata.workshopReadme.compiled.code ? (\n\t\t\t\t\t\t<EpicVideoInfoProvider\n\t\t\t\t\t\t\tepicVideoInfosPromise={data.epicVideoInfosPromise}\n\t\t\t\t\t\t>\n\t\t\t\t\t\t\t<div className=\"prose dark:prose-invert sm:prose-lg\">\n\t\t\t\t\t\t\t\t<Mdx\n\t\t\t\t\t\t\t\t\tcode={data.workshopReadme.compiled.code}\n\t\t\t\t\t\t\t\t\tcomponents={mdxComponents}\n\t\t\t\t\t\t\t\t/>\n\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t</EpicVideoInfoProvider>\n\t\t\t\t\t) : data.workshopReadme.compiled.status === 'error' ? (\n\t\t\t\t\t\t<div className=\"text-red-500\">\n\t\t\t\t\t\t\tThere was an error:\n\t\t\t\t\t\t\t<pre>{data.workshopReadme.compiled.error}</pre>\n\t\t\t\t\t\t</div>\n\t\t\t\t\t) : (\n\t\t\t\t\t\t'No instructions yet...'\n\t\t\t\t\t)}\n\t\t\t\t</div>\n\t\t\t\t<div className=\"pb-5 pt-10\">\n\t\t\t\t\t{data.workshopReadme.compiled.status === 'success' &&\n\t\t\t\t\tdata.workshopReadme.compiled.code &&\n\t\t\t\t\tdata.workshopReadme.compiled.code.length > 500\n\t\t\t\t\t\t? exerciseLinks\n\t\t\t\t\t\t: null}\n\t\t\t\t</div>\n\t\t\t</article>\n\t\t\t<ElementScrollRestoration elementQuery={`#${data.articleId}`} />\n\t\t\t<ProgressToggle\n\t\t\t\ttype=\"workshop-instructions\"\n\t\t\t\tclassName=\"h-14 border-t px-6\"\n\t\t\t/>\n\t\t\t<div className=\"flex h-16 justify-center border-t\">\n\t\t\t\t<EditFileOnGitHub\n\t\t\t\t\tfile={data.workshopReadme.file}\n\t\t\t\t\trelativePath={data.workshopReadme.relativePath}\n\t\t\t\t/>\n\t\t\t</div>\n\t\t</main>\n\t)\n}\n\nexport function ErrorBoundary() {\n\treturn <GeneralErrorBoundary />\n}\n"],"names":["ExerciseListItem","exercise","progressClassName","useExerciseProgressClassName","exerciseNumber","children","jsxs","Link","className","cn","to","toString","padStart","jsx","title","mdxComponents","h1","Index","data","useLoaderData","exerciseLinks","exercises","map","id","articleId","workshopReadme","compiled","status","code","EpicVideoInfoProvider","epicVideoInfosPromise","Mdx","components","error","length","ElementScrollRestoration","elementQuery","ProgressToggle","type","EditFileOnGitHub","file","relativePath","ErrorBoundary","GeneralErrorBoundary"],"mappings":"gmBA+EA,SAASA,EAAiB,CACzBC,SAAAA,CACD,EAEG,CACF,MAAMC,EAAoBC,EACzBF,EAASG,cACV,EACA,aACE,KACA,CAAAC,SAAAC,EAAA,KAACC,EAAA,CACAC,UAAWC,EACV,+QACAP,CACD,EACAQ,GAAI,GAAGT,EAASG,eAAeO,SAAW,EAAAC,SAAS,EAAG,GAAG,CAAC,GAE1DP,SAAA,CAAAQ,EAAA,IAAC,OAAK,CAAAL,UAAU,8CACdH,SAAAJ,EAASG,cACX,CAAA,EACAS,EAAA,IAAC,OAAM,CAAAR,SAAAJ,EAASa,KAAM,CAAA,CAAA,EACvB,CAAA,EAZQb,EAASG,cAalB,CAEF,CAEA,MAAMW,EAAgB,CAAEC,GAAIA,IAAM,IAAK,EAEvC,SAAwBC,GAAQ,CAC/B,MAAMC,EAAOC,IAEPC,EACLd,EAAA,KAAC,KAAG,CAAAE,UAAU,6DACbH,SAAA,CAACQ,EAAA,IAAA,SAAA,CAAOL,UAAU,yCAAyCH,SAE3D,WAAA,CAAA,EACCa,EAAKG,UAAUC,IAAKrB,SACnBD,EAA+C,CAAAC,SAAAA,CAAA,EAAzBA,EAASG,cAAoC,CACpE,CAAA,CACF,CAAA,EAGA,OAAAE,EAAAA,KAAC,OAAK,CAAAE,UAAU,4FACfH,SAAA,CAAAC,EAAA,KAAC,UAAA,CACAiB,GAAIL,EAAKM,UACThB,UAAU,8JAEVH,SAAA,CAAAQ,EAAA,IAAC,OACAR,SAACQ,EAAA,IAAA,KAAA,CAAGL,UAAU,kEACZH,SAAAa,EAAKJ,MACP,CACD,CAAA,EACAR,EAAA,KAAC,MAAI,CAAAE,UAAU,oEACdH,SAAA,CAACQ,EAAA,IAAA,KAAA,CAAGL,UAAU,iDAAiDH,SAE/D,OAAA,CAAA,EACCa,EAAKO,eAAeC,SAASC,SAAW,WACzCT,EAAKO,eAAeC,SAASE,KAC5Bf,EAAAA,IAACgB,EAAA,CACAC,sBAAuBZ,EAAKY,sBAE5BzB,SAAAQ,EAAA,IAAC,MAAI,CAAAL,UAAU,sCACdH,SAAAQ,EAAA,IAACkB,EAAA,CACAH,KAAMV,EAAKO,eAAeC,SAASE,KACnCI,WAAYjB,EACb,EACD,CAAA,CACD,EACGG,EAAKO,eAAeC,SAASC,SAAW,QAC3CrB,EAAA,KAAC,MAAI,CAAAE,UAAU,eAAeH,SAAA,CAAA,sBAE5BQ,EAAA,IAAA,MAAA,CAAKR,SAAKa,EAAAO,eAAeC,SAASO,KAAM,CAAA,CAAA,CAC1C,CAAA,EAEA,wBAAA,CAEF,CAAA,EACApB,EAAA,IAAC,OAAIL,UAAU,aACbH,WAAKoB,eAAeC,SAASC,SAAW,WACzCT,EAAKO,eAAeC,SAASE,MAC7BV,EAAKO,eAAeC,SAASE,KAAKM,OAAS,IACxCd,EACA,IACJ,CAAA,CAAA,CAAA,CACD,QACCe,EAAyB,CAAAC,aAAc,IAAIlB,EAAKM,SAAS,EAAI,CAAA,EAC9DX,EAAA,IAACwB,EAAA,CACAC,KAAK,wBACL9B,UAAU,oBAAA,CACX,EACAK,EAAA,IAAC,MAAI,CAAAL,UAAU,oCACdH,SAAAQ,EAAA,IAAC0B,EAAA,CACAC,KAAMtB,EAAKO,eAAee,KAC1BC,aAAcvB,EAAKO,eAAegB,aACnC,CACD,CAAA,CAAA,CACD,CAAA,CAEF,CAEO,SAASC,GAAgB,CAC/B,aAAQC,EAAqB,CAAA,CAAA,CAC9B"}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"onboarding-DCuSqnkZ.js","sources":["../../../app/routes/onboarding.tsx"],"sourcesContent":["import { invariantResponse } from '@epic-web/invariant'\nimport { getWorkshopConfig } from '@epic-web/workshop-utils/config.server'\nimport {\n\tgetAuthInfo,\n\tmarkOnboardingVideoWatched,\n} from '@epic-web/workshop-utils/db.server'\nimport { makeTimings } from '@epic-web/workshop-utils/timing.server'\nimport { type SEOHandle } from '@nasa-gcn/remix-seo'\nimport {\n\tdefer,\n\tredirect,\n\ttype ActionFunctionArgs,\n\ttype HeadersFunction,\n\ttype LoaderFunctionArgs,\n} from '@remix-run/node'\nimport { Form, useLoaderData } from '@remix-run/react'\nimport { Button } from '#app/components/button.tsx'\nimport {\n\tDeferredEpicVideo,\n\tEpicVideoInfoProvider,\n} from '#app/components/epic-video.tsx'\nimport { getEpicVideoInfos } from '#app/utils/epic-api.ts'\n\nexport const handle: SEOHandle = {\n\tgetSitemapEntries: () => null,\n}\n\nexport async function loader({ request }: LoaderFunctionArgs) {\n\tconst timings = makeTimings('onboarding')\n\n\tconst { onboardingVideo } = getWorkshopConfig()\n\tconst videoInfos = getEpicVideoInfos([onboardingVideo], { request, timings })\n\treturn defer(\n\t\t{ onboardingVideo, videoInfos },\n\t\t{ headers: { 'Server-Timing': timings.toString() } },\n\t)\n}\n\nexport const headers: HeadersFunction = ({ loaderHeaders }) => {\n\tconst headers = {\n\t\t'Server-Timing': loaderHeaders.get('Server-Timing') ?? '',\n\t}\n\treturn headers\n}\n\nexport async function action({ request }: ActionFunctionArgs) {\n\tconst data = await request.formData()\n\tconst authInfo = await getAuthInfo()\n\tconst intent = data.get('intent')\n\tinvariantResponse(intent === 'complete', 'Invalid intent')\n\tconst { onboardingVideo } = getWorkshopConfig()\n\tawait markOnboardingVideoWatched(onboardingVideo)\n\n\tif (authInfo) throw redirect('/')\n\telse throw redirect('/login')\n}\n\nexport default function Onboarding() {\n\tconst data = useLoaderData<typeof loader>()\n\treturn (\n\t\t<main className=\"flex h-full w-full flex-col items-center justify-between gap-4\">\n\t\t\t<div className=\"container flex h-full w-full max-w-5xl flex-1 flex-col items-center gap-4 overflow-y-scroll py-12 scrollbar-thin scrollbar-thumb-scrollbar\">\n\t\t\t\t<h1 className=\"text-5xl\">Onboarding</h1>\n\t\t\t\t<p className=\"text-xl\">Welcome to EpicWeb.dev!</p>\n\t\t\t\t<p className=\"text-lg\">\n\t\t\t\t\tBefore you get started, <strong>you must watch the tour video</strong>\n\t\t\t\t\t! You're going to be spending a lot of time in here, so it's important\n\t\t\t\t\tyou understand how to work effectively in this workshop\n\t\t\t\t</p>\n\t\t\t\t<div className=\"w-[780px] max-w-full\">\n\t\t\t\t\t<EpicVideoInfoProvider epicVideoInfosPromise={data.videoInfos}>\n\t\t\t\t\t\t<DeferredEpicVideo url={data.onboardingVideo} />\n\t\t\t\t\t</EpicVideoInfoProvider>\n\t\t\t\t</div>\n\t\t\t</div>\n\t\t\t<Form method=\"post\" className=\"pb-4\">\n\t\t\t\t<Button name=\"intent\" value=\"complete\" varient=\"primary\">\n\t\t\t\t\tI've watched it. Let's go!\n\t\t\t\t</Button>\n\t\t\t</Form>\n\t\t</main>\n\t)\n}\n"],"names":["handle","getSitemapEntries","Onboarding","data","useLoaderData","jsxs","className","children","jsx","EpicVideoInfoProvider","epicVideoInfosPromise","videoInfos","DeferredEpicVideo","url","onboardingVideo","Form","method","Button","name","value","varient"],"mappings":"yaAuBO,MAAMA,EAAoB,CAChCC,kBAAmBA,IAAM,IAC1B,EAgCA,SAAwBC,GAAa,CACpC,MAAMC,EAAOC,IAEZ,OAAAC,EAAAA,KAAC,OAAK,CAAAC,UAAU,iEACfC,SAAA,CAACF,EAAA,KAAA,MAAA,CAAIC,UAAU,6IACdC,SAAA,CAACC,EAAA,IAAA,KAAA,CAAGF,UAAU,WAAWC,SAAU,YAAA,CAAA,EAClCC,EAAA,IAAA,IAAA,CAAEF,UAAU,UAAUC,SAAuB,yBAAA,CAAA,EAC9CF,EAAA,KAAC,IAAE,CAAAC,UAAU,UAAUC,SAAA,CAAA,2BACEC,EAAA,IAAC,UAAOD,SAA6B,+BAAA,CAAA,EAAS,gIAAA,CAGvE,CAAA,EACCC,EAAA,IAAA,MAAA,CAAIF,UAAU,uBACdC,eAACE,EAAsB,CAAAC,sBAAuBP,EAAKQ,WAClDJ,eAACK,EAAkB,CAAAC,IAAKV,EAAKW,gBAAiB,EAC/C,CACD,CAAA,CAAA,CACD,CAAA,EACCN,EAAA,IAAAO,EAAA,CAAKC,OAAO,OAAOV,UAAU,OAC7BC,SAAAC,EAAA,IAACS,EAAO,CAAAC,KAAK,SAASC,MAAM,WAAWC,QAAQ,UAAUb,sCAEzD,CACD,CAAA,CAAA,CACD,CAAA,CAEF"}
|