import { SidebarLeft, TriangleRightMini, XMark } from "@medusajs/icons" import { IconButton, clx } from "@medusajs/ui" import { AnimatePresence } from "motion/react" import { Dialog as RadixDialog } from "radix-ui" import { PropsWithChildren, ReactNode, useEffect, useState } from "react" import { useTranslation } from "react-i18next" import { Link, Outlet, UIMatch, useMatches, useNavigation, } from "react-router-dom" import { DocumentTitle } from "../../../hooks/use-document-title" import { KeybindProvider } from "../../../providers/keybind-provider" import { useGlobalShortcuts } from "../../../providers/keybind-provider/hooks" import { useSidebar } from "../../../providers/sidebar-provider" import { ProgressBar } from "../../common/progress-bar" import { LayoutCustomizerHostProvider, LayoutCustomizerSlot, } from "../../../providers/customizer-host-provider/customizer-host-provider" import { Notifications } from "../notifications" import { CustomizerMenu, LayoutComposer } from "../../layout-composer" import { CUSTOMIZE_IDS, LAYOUT_CONTROLS_LOCATION, } from "../../layout-composer/constants" import { CORE_LAYOUT_IDS } from "@medusajs/admin-shared" export const Shell = ({ children }: PropsWithChildren) => { const globalShortcuts = useGlobalShortcuts() const navigation = useNavigation() const loading = navigation.state === "loading" return (
{children} {children}
) } const NavigationBar = ({ loading }: { loading: boolean }) => { const [showBar, setShowBar] = useState(false) /** * If the loading state is true, we want to show the bar after a short delay. * The delay is used to prevent the bar from flashing on quick navigations. */ useEffect(() => { let timeout: ReturnType if (loading) { timeout = setTimeout(() => { setShowBar(true) }, 200) } else { setShowBar(false) } return () => { clearTimeout(timeout) } }, [loading]) return (
{showBar ? : null}
) } const Gutter = ({ children }: PropsWithChildren) => { return (
{children}
) } const Breadcrumbs = () => { const matches = useMatches() as unknown as UIMatch< unknown, { breadcrumb?: (match?: UIMatch) => string | ReactNode } >[] const crumbs = matches .filter((match) => match.handle?.breadcrumb) .map((match) => { const handle = match.handle let label: string | ReactNode | undefined = undefined try { label = handle.breadcrumb?.(match) } catch (error) { // noop } if (!label) { return null } return { label: label, path: match.pathname, } }) .filter(Boolean) as { label: string | ReactNode; path: string }[] return (
    {crumbs.map((crumb, index) => { const isLast = index === crumbs.length - 1 const isSingle = crumbs.length === 1 return (
  1. {!isLast ? ( {crumb.label} ) : (
    {!isSingle && ...} {crumb.label}
    )} {!isLast && ( )}
  2. ) })}
) } const ToggleSidebar = () => { const { toggle } = useSidebar() return (
toggle("desktop")} size="small" > toggle("mobile")} size="small" >
) } const Topbar = () => { return (
{/* Single trigger for every host; while editing, the active composer's controls portal into the adjacent slot in its place. */} ), }} hasOutlet={false} customizeId={CUSTOMIZE_IDS.TOPBAR} controlSize="xsmall" />
) } const DesktopSidebarContainer = ({ children }: PropsWithChildren) => { const { desktop } = useSidebar() return (
{children}
) } const MobileSidebarContainer = ({ children }: PropsWithChildren) => { const { t } = useTranslation() const { mobile, toggle } = useSidebar() return ( toggle("mobile")}>
{t("app.nav.accessibility.title")} {t("app.nav.accessibility.description")}
{children}
) }